From f099d2c6b90f6cdd9a413afac3ae268871a71429 Mon Sep 17 00:00:00 2001 From: Messerbill Date: Mon, 8 Jun 2015 20:46:04 +0200 Subject: [PATCH] tablesorter submodule added --- .gitattributes | 23 + .gitignore | 165 + CONTRIBUTING.md | 45 + Gruntfile.js | 399 + README.md | 189 + addons/pager/icons/first.png | Bin 0 -> 720 bytes addons/pager/icons/last.png | Bin 0 -> 737 bytes addons/pager/icons/loading.gif | Bin 0 -> 416 bytes addons/pager/icons/next.png | Bin 0 -> 736 bytes addons/pager/icons/prev.png | Bin 0 -> 745 bytes addons/pager/jquery.tablesorter.pager.css | 42 + addons/pager/jquery.tablesorter.pager.js | 1090 +++ .../example-pager-custom-controls.html | 1200 +++ .../example-widget-column-reorder.html | 192 + beta-testing/pager-custom-controls.js | 102 + beta-testing/widget-reorder.js | 182 + bower.json | 10 + changelog.txt | 2 + css/bootstrap.less | 322 + css/dragtable.mod.css | 64 + css/filter.formatter.css | 183 + css/images/black-asc.gif | Bin 0 -> 48 bytes css/images/black-desc.gif | Bin 0 -> 49 bytes css/images/black-unsorted.gif | Bin 0 -> 54 bytes css/images/bootstrap-black-unsorted.png | Bin 0 -> 284 bytes css/images/bootstrap-white-unsorted.png | Bin 0 -> 223 bytes css/images/dragtable-handle.png | Bin 0 -> 103 bytes css/images/dragtable-handle.svg | 7 + css/images/dropbox-asc-hovered.png | Bin 0 -> 275 bytes css/images/dropbox-asc.png | Bin 0 -> 278 bytes css/images/dropbox-desc-hovered.png | Bin 0 -> 273 bytes css/images/dropbox-desc.png | Bin 0 -> 277 bytes css/images/green-asc.gif | Bin 0 -> 283 bytes css/images/green-desc.gif | Bin 0 -> 283 bytes css/images/green-header.gif | Bin 0 -> 513 bytes css/images/green-unsorted.gif | Bin 0 -> 520 bytes css/images/ice-asc.gif | Bin 0 -> 285 bytes css/images/ice-desc.gif | Bin 0 -> 285 bytes css/images/ice-unsorted.gif | Bin 0 -> 180 bytes css/images/metro-black-asc.png | Bin 0 -> 213 bytes css/images/metro-black-desc.png | Bin 0 -> 232 bytes css/images/metro-loading.gif | Bin 0 -> 673 bytes css/images/metro-unsorted.png | Bin 0 -> 181 bytes css/images/metro-white-asc.png | Bin 0 -> 209 bytes css/images/metro-white-desc.png | Bin 0 -> 224 bytes css/images/white-asc.gif | Bin 0 -> 48 bytes css/images/white-desc.gif | Bin 0 -> 49 bytes css/images/white-unsorted.gif | Bin 0 -> 54 bytes css/metro.less | 357 + css/psd/green-asc.psd | Bin 0 -> 32673 bytes css/psd/green-desc.psd | Bin 0 -> 27807 bytes css/psd/green-unsorted.psd | Bin 0 -> 32412 bytes css/psd/metro-style.psd | Bin 0 -> 30446 bytes css/theme.black-ice.css | 192 + css/theme.blue.css | 229 + css/theme.bootstrap.css | 158 + css/theme.bootstrap_2.css | 157 + css/theme.dark.css | 193 + css/theme.default.css | 194 + css/theme.dropbox.css | 216 + css/theme.green.css | 212 + css/theme.grey.css | 252 + css/theme.ice.css | 212 + css/theme.jui.css | 164 + css/theme.less | 329 + css/theme.metro-dark.css | 197 + dist/css/dragtable.mod.min.css | 1 + dist/css/filter.formatter.min.css | 1 + dist/css/images/black-asc.gif | Bin 0 -> 48 bytes dist/css/images/black-desc.gif | Bin 0 -> 49 bytes dist/css/images/black-unsorted.gif | Bin 0 -> 54 bytes dist/css/images/bootstrap-black-unsorted.png | Bin 0 -> 284 bytes dist/css/images/bootstrap-white-unsorted.png | Bin 0 -> 223 bytes dist/css/images/dragtable-handle.png | Bin 0 -> 103 bytes dist/css/images/dragtable-handle.svg | 7 + dist/css/images/dropbox-asc-hovered.png | Bin 0 -> 275 bytes dist/css/images/dropbox-asc.png | Bin 0 -> 278 bytes dist/css/images/dropbox-desc-hovered.png | Bin 0 -> 273 bytes dist/css/images/dropbox-desc.png | Bin 0 -> 277 bytes dist/css/images/first.png | Bin 0 -> 720 bytes dist/css/images/green-asc.gif | Bin 0 -> 283 bytes dist/css/images/green-desc.gif | Bin 0 -> 283 bytes dist/css/images/green-header.gif | Bin 0 -> 513 bytes dist/css/images/green-unsorted.gif | Bin 0 -> 520 bytes dist/css/images/ice-asc.gif | Bin 0 -> 285 bytes dist/css/images/ice-desc.gif | Bin 0 -> 285 bytes dist/css/images/ice-unsorted.gif | Bin 0 -> 180 bytes dist/css/images/last.png | Bin 0 -> 737 bytes dist/css/images/loading.gif | Bin 0 -> 416 bytes dist/css/images/metro-black-asc.png | Bin 0 -> 213 bytes dist/css/images/metro-black-desc.png | Bin 0 -> 232 bytes dist/css/images/metro-loading.gif | Bin 0 -> 673 bytes dist/css/images/metro-unsorted.png | Bin 0 -> 181 bytes dist/css/images/metro-white-asc.png | Bin 0 -> 209 bytes dist/css/images/metro-white-desc.png | Bin 0 -> 224 bytes dist/css/images/next.png | Bin 0 -> 736 bytes dist/css/images/prev.png | Bin 0 -> 745 bytes dist/css/images/white-asc.gif | Bin 0 -> 48 bytes dist/css/images/white-desc.gif | Bin 0 -> 49 bytes dist/css/images/white-unsorted.gif | Bin 0 -> 54 bytes dist/css/jquery.tablesorter.pager.min.css | 1 + dist/css/less/bootstrap.less | 322 + dist/css/less/metro.less | 357 + dist/css/less/theme.less | 329 + dist/css/theme.blackice.min.css | 1 + dist/css/theme.blue.min.css | 1 + dist/css/theme.bootstrap.min.css | 1 + dist/css/theme.bootstrap_2.min.css | 1 + dist/css/theme.dark.min.css | 1 + dist/css/theme.default.min.css | 1 + dist/css/theme.dropbox.min.css | 1 + dist/css/theme.green.min.css | 1 + dist/css/theme.grey.min.css | 1 + dist/css/theme.ice.min.css | 1 + dist/css/theme.jui.min.css | 1 + dist/css/theme.metro-dark.min.css | 1 + dist/js/extras/jquery.dragtable.mod.min.js | 3 + dist/js/extras/jquery.metadata.min.js | 1 + dist/js/extras/jquery.quicksearch.min.js | 1 + .../js/extras/jquery.tablesorter.pager.min.js | 5 + dist/js/extras/semver-mod.min.js | 2 + dist/js/jquery.tablesorter.combined.js | 4809 +++++++++++ dist/js/jquery.tablesorter.combined.min.js | 4 + dist/js/jquery.tablesorter.js | 2190 +++++ dist/js/jquery.tablesorter.min.js | 2 + dist/js/jquery.tablesorter.widgets.js | 2631 ++++++ dist/js/jquery.tablesorter.widgets.min.js | 3 + dist/js/parsers/parser-date-extract.min.js | 6 + dist/js/parsers/parser-date-iso8601.min.js | 2 + dist/js/parsers/parser-date-month.min.js | 2 + dist/js/parsers/parser-date-range.min.js | 5 + .../parsers/parser-date-two-digit-year.min.js | 2 + dist/js/parsers/parser-date-weekday.min.js | 2 + dist/js/parsers/parser-date.min.js | 4 + dist/js/parsers/parser-duration.min.js | 3 + .../parsers/parser-feet-inch-fraction.min.js | 2 + dist/js/parsers/parser-file-type.min.js | 2 + dist/js/parsers/parser-globalize.min.js | 4 + dist/js/parsers/parser-ignore-articles.min.js | 2 + dist/js/parsers/parser-image.min.js | 2 + dist/js/parsers/parser-input-select.min.js | 2 + dist/js/parsers/parser-metric.min.js | 2 + dist/js/parsers/parser-named-numbers.min.js | 2 + dist/js/parsers/parser-network.min.js | 5 + dist/js/parsers/parser-roman.min.js | 2 + dist/js/widgets/widget-alignChar.min.js | 2 + dist/js/widgets/widget-build-table.min.js | 2 + dist/js/widgets/widget-chart.min.js | 1 + dist/js/widgets/widget-columnSelector.min.js | 1 + dist/js/widgets/widget-columns.min.js | 2 + .../js/widgets/widget-cssStickyHeaders.min.js | 2 + dist/js/widgets/widget-editable.min.js | 2 + .../widget-filter-formatter-html5.min.js | 2 + .../widget-filter-formatter-jui.min.js | 2 + .../widget-filter-formatter-select2.min.js | 2 + .../widget-filter-type-insideRange.min.js | 2 + dist/js/widgets/widget-filter.min.js | 2 + dist/js/widgets/widget-formatter.min.js | 2 + dist/js/widgets/widget-grouping.min.js | 2 + dist/js/widgets/widget-headerTitles.min.js | 2 + dist/js/widgets/widget-math.min.js | 9 + dist/js/widgets/widget-output.min.js | 2 + dist/js/widgets/widget-pager.min.js | 2 + dist/js/widgets/widget-print.min.js | 1 + dist/js/widgets/widget-reflow.min.js | 1 + dist/js/widgets/widget-repeatheaders.min.js | 2 + dist/js/widgets/widget-resizable.min.js | 2 + dist/js/widgets/widget-saveSort.min.js | 2 + dist/js/widgets/widget-scroller.min.js | 2 + dist/js/widgets/widget-staticRow.min.js | 2 + dist/js/widgets/widget-stickyHeaders.min.js | 2 + dist/js/widgets/widget-storage.min.js | 2 + dist/js/widgets/widget-uitheme.min.js | 2 + docs/assets/City0.json | 159 + docs/assets/City1.json | 159 + docs/assets/City2.json | 159 + docs/assets/City3.json | 39 + docs/assets/ajax-content.html | 40 + docs/assets/build.json | 37 + docs/assets/build.txt | 9 + docs/assets/theme_switcher.json | 303 + docs/css/bootstrap-v2.min.css | 9 + docs/css/bootstrap.min.css | 5 + .../css/images/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes docs/css/images/glyphicons-halflings.png | Bin 0 -> 12799 bytes .../ui-bg_diagonals-thick_90_eeeeee_40x40.png | Bin 0 -> 312 bytes .../images/ui-bg_flat_15_cd0a0a_40x100.png | Bin 0 -> 206 bytes .../images/ui-bg_glass_100_e4f1fb_1x400.png | Bin 0 -> 350 bytes .../images/ui-bg_glass_50_3baae3_1x400.png | Bin 0 -> 336 bytes .../images/ui-bg_glass_80_d7ebf9_1x400.png | Bin 0 -> 346 bytes .../ui-bg_highlight-hard_100_f2f5f7_1x100.png | Bin 0 -> 332 bytes .../ui-bg_highlight-hard_70_000000_1x100.png | Bin 0 -> 249 bytes .../ui-bg_highlight-soft_100_deedf7_1x100.png | Bin 0 -> 387 bytes .../ui-bg_highlight-soft_25_ffef8f_1x100.png | Bin 0 -> 309 bytes docs/css/images/ui-icons_2694e8_256x240.png | Bin 0 -> 4549 bytes docs/css/images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4549 bytes docs/css/images/ui-icons_3d80b3_256x240.png | Bin 0 -> 4549 bytes docs/css/images/ui-icons_72a7cf_256x240.png | Bin 0 -> 4549 bytes docs/css/images/ui-icons_ffffff_256x240.png | Bin 0 -> 6299 bytes docs/css/jq.css | 106 + docs/css/jquery-ui.min.css | 7 + docs/css/magnific-popup.css | 405 + docs/css/menu.css | 72 + docs/css/prettify.css | 55 + docs/css/rangeslider.css | 87 + docs/css/select2-3.4.6.min.css | 1 + docs/css/select2-spinner.gif | Bin 0 -> 1849 bytes docs/css/select2.png | Bin 0 -> 613 bytes docs/css/select2x2.png | Bin 0 -> 845 bytes docs/css/tipsy.css | 16 + docs/example-add-rows.html | 144 + docs/example-ajax.html | 138 + docs/example-apply-widget.html | 131 + docs/example-child-rows-filtered.html | 634 ++ docs/example-child-rows.html | 448 ++ docs/example-css-highlighting.html | 361 + docs/example-dragtable.html | 245 + docs/example-empty-table.html | 97 + docs/example-extending-defaults.html | 117 + docs/example-extractors-parsers.html | 125 + docs/example-header-column-span.html | 100 + docs/example-locale-sort.html | 170 + docs/example-meta-headers.html | 129 + docs/example-meta-parsers.html | 121 + docs/example-meta-sort-list.html | 123 + docs/example-method-sortreset.html | 156 + docs/example-multiple-tbodies.html | 109 + docs/example-option-custom-sort.html | 150 + docs/example-option-date-format.html | 176 + docs/example-option-debug.html | 119 + docs/example-option-delay-init.html | 3365 ++++++++ docs/example-option-digits.html | 153 + docs/example-option-render-header.html | 161 + docs/example-option-render-template.html | 149 + docs/example-option-selectorsort.html | 151 + docs/example-option-show-processing.html | 1138 +++ docs/example-option-sort-append.html | 126 + docs/example-option-sort-empty.html | 198 + docs/example-option-sort-force.html | 128 + docs/example-option-sort-key.html | 119 + docs/example-option-sort-list.html | 176 + docs/example-option-sort-order.html | 113 + .../example-option-sortreset-sortrestart.html | 137 + docs/example-option-text-extraction.html | 142 + docs/example-option-textsorter-semver.html | 125 + docs/example-option-theme-metro-style.html | 194 + ...xample-options-headers-digits-strings.html | 225 + docs/example-options-headers-locked.html | 132 + docs/example-options-headers-order.html | 135 + docs/example-options-headers-parser.html | 108 + docs/example-options-headers.html | 140 + docs/example-pager-ajax.html | 472 ++ docs/example-pager-filtered.html | 468 ++ docs/example-pager.html | 454 ++ docs/example-parsers-advanced.html | 154 + docs/example-parsers-class-name.html | 131 + docs/example-parsers-date-range.html | 127 + docs/example-parsers-dates.html | 175 + docs/example-parsers-duration.html | 164 + docs/example-parsers-feet-inch-fraction.html | 128 + docs/example-parsers-file-type.html | 190 + docs/example-parsers-ignore-articles.html | 434 + docs/example-parsers-ip-address.html | 137 + docs/example-parsers-jquery-data.html | 125 + docs/example-parsers-metric.html | 123 + docs/example-parsers-named-numbers.html | 157 + docs/example-parsers-roman.html | 239 + docs/example-parsers.html | 171 + docs/example-trigger-sort.html | 230 + docs/example-triggers.html | 1111 +++ docs/example-update-all.html | 114 + docs/example-update-cell.html | 138 + docs/example-widget-align-character.html | 455 ++ docs/example-widget-bootstrap-theme-v2.html | 295 + docs/example-widget-bootstrap-theme.html | 329 + docs/example-widget-build-table.html | 873 ++ docs/example-widget-chart.html | 704 ++ docs/example-widget-column-selector.html | 611 ++ docs/example-widget-columns.html | 227 + docs/example-widget-css-sticky-header.html | 537 ++ docs/example-widget-editable.html | 579 ++ docs/example-widget-filter-any-match.html | 207 + docs/example-widget-filter-custom-search.html | 298 + .../example-widget-filter-custom-search2.html | 157 + docs/example-widget-filter-custom.html | 486 ++ ...example-widget-filter-external-inputs.html | 180 + docs/example-widget-filter-formatter-1.html | 638 ++ docs/example-widget-filter-formatter-2.html | 352 + ...ample-widget-filter-formatter-select2.html | 231 + docs/example-widget-filter.html | 842 ++ docs/example-widget-formatter.html | 241 + ...mple-widget-grouping-filter-childrows.html | 194 + docs/example-widget-grouping.html | 597 ++ docs/example-widget-header-titles.html | 321 + docs/example-widget-math.html | 646 ++ docs/example-widget-output.html | 1035 +++ docs/example-widget-pager-ajax.html | 378 + docs/example-widget-pager.html | 468 ++ docs/example-widget-print.html | 324 + docs/example-widget-reflow.html | 719 ++ docs/example-widget-reflow1.html | 104 + docs/example-widget-reflow2.html | 250 + docs/example-widget-reflow3.html | 125 + docs/example-widget-resizable.html | 373 + docs/example-widget-savesort.html | 196 + docs/example-widget-scroller.html | 698 ++ docs/example-widget-static-row.html | 283 + docs/example-widget-sticky-header.html | 719 ++ docs/example-widget-ui-theme.html | 236 + docs/example-widget-zebra.html | 146 + docs/example-widgets.html | 252 + docs/fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes docs/fonts/glyphicons-halflings-regular.svg | 288 + docs/fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes docs/fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes docs/fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes docs/img/external.png | Bin 0 -> 165 bytes docs/img/link.png | Bin 0 -> 704 bytes docs/img/screens-blue.png | Bin 0 -> 474 bytes docs/img/screens.png | Bin 0 -> 495 bytes docs/index.html | 7121 +++++++++++++++++ docs/js/bootstrap.min.js | 7 + docs/js/chili/jquery.chili-2.2.js | 704 ++ docs/js/chili/recipes.js | 229 + docs/js/demo-build-table.js | 175 + docs/js/docs.js | 224 + docs/js/jquery-1.2.6.min.js | 32 + docs/js/jquery-1.4.4.min.js | 167 + docs/js/jquery-latest.min.js | 4 + docs/js/jquery-ui.min.js | 13 + docs/js/jquery.jui_theme_switch.min.js | 11 + docs/js/jquery.magnific-popup.min.js | 4 + docs/js/jquery.tipsy.min.js | 7 + docs/js/prettify.js | 28 + docs/js/rangeslider.min.js | 2 + docs/js/search-ie.js | 28 + docs/js/search.js | 160 + docs/js/select2-3.4.6.min.js | 22 + docs/js/sugar.min.js | 132 + docs/themes.html | 253 + example.json | 6 + index.html | 62 + js/extras/jquery.dragtable.mod.js | 602 ++ js/extras/jquery.metadata.js | 117 + js/extras/jquery.quicksearch.js | 195 + js/extras/semver-mod.js | 1217 +++ js/extras/semver.js | 1202 +++ js/jquery.tablesorter.combined.js | 4815 +++++++++++ js/jquery.tablesorter.js | 2177 +++++ js/jquery.tablesorter.widgets.js | 2637 ++++++ js/parsers/parser-date-extract.js | 98 + js/parsers/parser-date-iso8601.js | 35 + js/parsers/parser-date-month.js | 38 + js/parsers/parser-date-range.js | 90 + js/parsers/parser-date-two-digit-year.js | 80 + js/parsers/parser-date-weekday.js | 38 + js/parsers/parser-date.js | 35 + js/parsers/parser-duration.js | 67 + js/parsers/parser-feet-inch-fraction.js | 63 + js/parsers/parser-file-type.js | 73 + js/parsers/parser-globalize.js | 46 + js/parsers/parser-ignore-articles.js | 61 + js/parsers/parser-image.js | 19 + js/parsers/parser-input-select.js | 183 + js/parsers/parser-metric.js | 77 + js/parsers/parser-named-numbers.js | 122 + js/parsers/parser-network.js | 137 + js/parsers/parser-roman.js | 117 + js/widgets/widget-alignChar.js | 146 + js/widgets/widget-build-table.js | 454 ++ js/widgets/widget-chart.js | 275 + js/widgets/widget-columnSelector.js | 366 + js/widgets/widget-columns.js | 78 + js/widgets/widget-cssStickyHeaders.js | 154 + js/widgets/widget-editable.js | 282 + js/widgets/widget-filter-formatter-html5.js | 429 + js/widgets/widget-filter-formatter-jui.js | 764 ++ js/widgets/widget-filter-formatter-select2.js | 149 + js/widgets/widget-filter-type-insideRange.js | 39 + js/widgets/widget-filter.js | 1567 ++++ js/widgets/widget-formatter.js | 72 + js/widgets/widget-grouping.js | 250 + js/widgets/widget-headerTitles.js | 91 + js/widgets/widget-math.js | 425 + js/widgets/widget-output.js | 337 + js/widgets/widget-pager.js | 1149 +++ js/widgets/widget-print.js | 123 + js/widgets/widget-reflow.js | 180 + js/widgets/widget-repeatheaders.js | 52 + js/widgets/widget-resizable.js | 335 + js/widgets/widget-saveSort.js | 68 + js/widgets/widget-scroller.js | 915 +++ js/widgets/widget-staticRow.js | 121 + js/widgets/widget-stickyHeaders.js | 288 + js/widgets/widget-storage.js | 89 + js/widgets/widget-uitheme.js | 185 + package.json | 80 + tablesorter.jquery.json | 47 + test.html | 131 + testing/qunit-1.16.0.css | 264 + testing/qunit-1.16.0.js | 2819 +++++++ testing/testing-ipv6.js | 594 ++ testing/testing-widgets.js | 283 + testing/testing.css | 10 + testing/testing.js | 777 ++ 405 files changed, 91002 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CONTRIBUTING.md create mode 100644 Gruntfile.js create mode 100644 README.md create mode 100644 addons/pager/icons/first.png create mode 100644 addons/pager/icons/last.png create mode 100644 addons/pager/icons/loading.gif create mode 100644 addons/pager/icons/next.png create mode 100644 addons/pager/icons/prev.png create mode 100644 addons/pager/jquery.tablesorter.pager.css create mode 100644 addons/pager/jquery.tablesorter.pager.js create mode 100644 beta-testing/example-pager-custom-controls.html create mode 100644 beta-testing/example-widget-column-reorder.html create mode 100644 beta-testing/pager-custom-controls.js create mode 100644 beta-testing/widget-reorder.js create mode 100644 bower.json create mode 100644 changelog.txt create mode 100644 css/bootstrap.less create mode 100644 css/dragtable.mod.css create mode 100644 css/filter.formatter.css create mode 100644 css/images/black-asc.gif create mode 100644 css/images/black-desc.gif create mode 100644 css/images/black-unsorted.gif create mode 100644 css/images/bootstrap-black-unsorted.png create mode 100644 css/images/bootstrap-white-unsorted.png create mode 100644 css/images/dragtable-handle.png create mode 100644 css/images/dragtable-handle.svg create mode 100644 css/images/dropbox-asc-hovered.png create mode 100644 css/images/dropbox-asc.png create mode 100644 css/images/dropbox-desc-hovered.png create mode 100644 css/images/dropbox-desc.png create mode 100644 css/images/green-asc.gif create mode 100644 css/images/green-desc.gif create mode 100644 css/images/green-header.gif create mode 100644 css/images/green-unsorted.gif create mode 100644 css/images/ice-asc.gif create mode 100644 css/images/ice-desc.gif create mode 100644 css/images/ice-unsorted.gif create mode 100644 css/images/metro-black-asc.png create mode 100644 css/images/metro-black-desc.png create mode 100644 css/images/metro-loading.gif create mode 100644 css/images/metro-unsorted.png create mode 100644 css/images/metro-white-asc.png create mode 100644 css/images/metro-white-desc.png create mode 100644 css/images/white-asc.gif create mode 100644 css/images/white-desc.gif create mode 100644 css/images/white-unsorted.gif create mode 100644 css/metro.less create mode 100644 css/psd/green-asc.psd create mode 100644 css/psd/green-desc.psd create mode 100644 css/psd/green-unsorted.psd create mode 100644 css/psd/metro-style.psd create mode 100644 css/theme.black-ice.css create mode 100644 css/theme.blue.css create mode 100644 css/theme.bootstrap.css create mode 100644 css/theme.bootstrap_2.css create mode 100644 css/theme.dark.css create mode 100644 css/theme.default.css create mode 100644 css/theme.dropbox.css create mode 100644 css/theme.green.css create mode 100644 css/theme.grey.css create mode 100644 css/theme.ice.css create mode 100644 css/theme.jui.css create mode 100644 css/theme.less create mode 100644 css/theme.metro-dark.css create mode 100644 dist/css/dragtable.mod.min.css create mode 100644 dist/css/filter.formatter.min.css create mode 100644 dist/css/images/black-asc.gif create mode 100644 dist/css/images/black-desc.gif create mode 100644 dist/css/images/black-unsorted.gif create mode 100644 dist/css/images/bootstrap-black-unsorted.png create mode 100644 dist/css/images/bootstrap-white-unsorted.png create mode 100644 dist/css/images/dragtable-handle.png create mode 100644 dist/css/images/dragtable-handle.svg create mode 100644 dist/css/images/dropbox-asc-hovered.png create mode 100644 dist/css/images/dropbox-asc.png create mode 100644 dist/css/images/dropbox-desc-hovered.png create mode 100644 dist/css/images/dropbox-desc.png create mode 100644 dist/css/images/first.png create mode 100644 dist/css/images/green-asc.gif create mode 100644 dist/css/images/green-desc.gif create mode 100644 dist/css/images/green-header.gif create mode 100644 dist/css/images/green-unsorted.gif create mode 100644 dist/css/images/ice-asc.gif create mode 100644 dist/css/images/ice-desc.gif create mode 100644 dist/css/images/ice-unsorted.gif create mode 100644 dist/css/images/last.png create mode 100644 dist/css/images/loading.gif create mode 100644 dist/css/images/metro-black-asc.png create mode 100644 dist/css/images/metro-black-desc.png create mode 100644 dist/css/images/metro-loading.gif create mode 100644 dist/css/images/metro-unsorted.png create mode 100644 dist/css/images/metro-white-asc.png create mode 100644 dist/css/images/metro-white-desc.png create mode 100644 dist/css/images/next.png create mode 100644 dist/css/images/prev.png create mode 100644 dist/css/images/white-asc.gif create mode 100644 dist/css/images/white-desc.gif create mode 100644 dist/css/images/white-unsorted.gif create mode 100644 dist/css/jquery.tablesorter.pager.min.css create mode 100644 dist/css/less/bootstrap.less create mode 100644 dist/css/less/metro.less create mode 100644 dist/css/less/theme.less create mode 100644 dist/css/theme.blackice.min.css create mode 100644 dist/css/theme.blue.min.css create mode 100644 dist/css/theme.bootstrap.min.css create mode 100644 dist/css/theme.bootstrap_2.min.css create mode 100644 dist/css/theme.dark.min.css create mode 100644 dist/css/theme.default.min.css create mode 100644 dist/css/theme.dropbox.min.css create mode 100644 dist/css/theme.green.min.css create mode 100644 dist/css/theme.grey.min.css create mode 100644 dist/css/theme.ice.min.css create mode 100644 dist/css/theme.jui.min.css create mode 100644 dist/css/theme.metro-dark.min.css create mode 100644 dist/js/extras/jquery.dragtable.mod.min.js create mode 100644 dist/js/extras/jquery.metadata.min.js create mode 100644 dist/js/extras/jquery.quicksearch.min.js create mode 100644 dist/js/extras/jquery.tablesorter.pager.min.js create mode 100644 dist/js/extras/semver-mod.min.js create mode 100644 dist/js/jquery.tablesorter.combined.js create mode 100644 dist/js/jquery.tablesorter.combined.min.js create mode 100644 dist/js/jquery.tablesorter.js create mode 100644 dist/js/jquery.tablesorter.min.js create mode 100644 dist/js/jquery.tablesorter.widgets.js create mode 100644 dist/js/jquery.tablesorter.widgets.min.js create mode 100644 dist/js/parsers/parser-date-extract.min.js create mode 100644 dist/js/parsers/parser-date-iso8601.min.js create mode 100644 dist/js/parsers/parser-date-month.min.js create mode 100644 dist/js/parsers/parser-date-range.min.js create mode 100644 dist/js/parsers/parser-date-two-digit-year.min.js create mode 100644 dist/js/parsers/parser-date-weekday.min.js create mode 100644 dist/js/parsers/parser-date.min.js create mode 100644 dist/js/parsers/parser-duration.min.js create mode 100644 dist/js/parsers/parser-feet-inch-fraction.min.js create mode 100644 dist/js/parsers/parser-file-type.min.js create mode 100644 dist/js/parsers/parser-globalize.min.js create mode 100644 dist/js/parsers/parser-ignore-articles.min.js create mode 100644 dist/js/parsers/parser-image.min.js create mode 100644 dist/js/parsers/parser-input-select.min.js create mode 100644 dist/js/parsers/parser-metric.min.js create mode 100644 dist/js/parsers/parser-named-numbers.min.js create mode 100644 dist/js/parsers/parser-network.min.js create mode 100644 dist/js/parsers/parser-roman.min.js create mode 100644 dist/js/widgets/widget-alignChar.min.js create mode 100644 dist/js/widgets/widget-build-table.min.js create mode 100644 dist/js/widgets/widget-chart.min.js create mode 100644 dist/js/widgets/widget-columnSelector.min.js create mode 100644 dist/js/widgets/widget-columns.min.js create mode 100644 dist/js/widgets/widget-cssStickyHeaders.min.js create mode 100644 dist/js/widgets/widget-editable.min.js create mode 100644 dist/js/widgets/widget-filter-formatter-html5.min.js create mode 100644 dist/js/widgets/widget-filter-formatter-jui.min.js create mode 100644 dist/js/widgets/widget-filter-formatter-select2.min.js create mode 100644 dist/js/widgets/widget-filter-type-insideRange.min.js create mode 100644 dist/js/widgets/widget-filter.min.js create mode 100644 dist/js/widgets/widget-formatter.min.js create mode 100644 dist/js/widgets/widget-grouping.min.js create mode 100644 dist/js/widgets/widget-headerTitles.min.js create mode 100644 dist/js/widgets/widget-math.min.js create mode 100644 dist/js/widgets/widget-output.min.js create mode 100644 dist/js/widgets/widget-pager.min.js create mode 100644 dist/js/widgets/widget-print.min.js create mode 100644 dist/js/widgets/widget-reflow.min.js create mode 100644 dist/js/widgets/widget-repeatheaders.min.js create mode 100644 dist/js/widgets/widget-resizable.min.js create mode 100644 dist/js/widgets/widget-saveSort.min.js create mode 100644 dist/js/widgets/widget-scroller.min.js create mode 100644 dist/js/widgets/widget-staticRow.min.js create mode 100644 dist/js/widgets/widget-stickyHeaders.min.js create mode 100644 dist/js/widgets/widget-storage.min.js create mode 100644 dist/js/widgets/widget-uitheme.min.js create mode 100644 docs/assets/City0.json create mode 100644 docs/assets/City1.json create mode 100644 docs/assets/City2.json create mode 100644 docs/assets/City3.json create mode 100644 docs/assets/ajax-content.html create mode 100644 docs/assets/build.json create mode 100644 docs/assets/build.txt create mode 100644 docs/assets/theme_switcher.json create mode 100644 docs/css/bootstrap-v2.min.css create mode 100644 docs/css/bootstrap.min.css create mode 100644 docs/css/images/glyphicons-halflings-white.png create mode 100644 docs/css/images/glyphicons-halflings.png create mode 100644 docs/css/images/ui-bg_diagonals-thick_90_eeeeee_40x40.png create mode 100644 docs/css/images/ui-bg_flat_15_cd0a0a_40x100.png create mode 100644 docs/css/images/ui-bg_glass_100_e4f1fb_1x400.png create mode 100644 docs/css/images/ui-bg_glass_50_3baae3_1x400.png create mode 100644 docs/css/images/ui-bg_glass_80_d7ebf9_1x400.png create mode 100644 docs/css/images/ui-bg_highlight-hard_100_f2f5f7_1x100.png create mode 100644 docs/css/images/ui-bg_highlight-hard_70_000000_1x100.png create mode 100644 docs/css/images/ui-bg_highlight-soft_100_deedf7_1x100.png create mode 100644 docs/css/images/ui-bg_highlight-soft_25_ffef8f_1x100.png create mode 100644 docs/css/images/ui-icons_2694e8_256x240.png create mode 100644 docs/css/images/ui-icons_2e83ff_256x240.png create mode 100644 docs/css/images/ui-icons_3d80b3_256x240.png create mode 100644 docs/css/images/ui-icons_72a7cf_256x240.png create mode 100644 docs/css/images/ui-icons_ffffff_256x240.png create mode 100644 docs/css/jq.css create mode 100644 docs/css/jquery-ui.min.css create mode 100644 docs/css/magnific-popup.css create mode 100644 docs/css/menu.css create mode 100644 docs/css/prettify.css create mode 100644 docs/css/rangeslider.css create mode 100644 docs/css/select2-3.4.6.min.css create mode 100644 docs/css/select2-spinner.gif create mode 100644 docs/css/select2.png create mode 100644 docs/css/select2x2.png create mode 100644 docs/css/tipsy.css create mode 100644 docs/example-add-rows.html create mode 100644 docs/example-ajax.html create mode 100644 docs/example-apply-widget.html create mode 100644 docs/example-child-rows-filtered.html create mode 100644 docs/example-child-rows.html create mode 100644 docs/example-css-highlighting.html create mode 100644 docs/example-dragtable.html create mode 100644 docs/example-empty-table.html create mode 100644 docs/example-extending-defaults.html create mode 100644 docs/example-extractors-parsers.html create mode 100644 docs/example-header-column-span.html create mode 100644 docs/example-locale-sort.html create mode 100644 docs/example-meta-headers.html create mode 100644 docs/example-meta-parsers.html create mode 100644 docs/example-meta-sort-list.html create mode 100644 docs/example-method-sortreset.html create mode 100644 docs/example-multiple-tbodies.html create mode 100644 docs/example-option-custom-sort.html create mode 100644 docs/example-option-date-format.html create mode 100644 docs/example-option-debug.html create mode 100644 docs/example-option-delay-init.html create mode 100644 docs/example-option-digits.html create mode 100644 docs/example-option-render-header.html create mode 100644 docs/example-option-render-template.html create mode 100644 docs/example-option-selectorsort.html create mode 100644 docs/example-option-show-processing.html create mode 100644 docs/example-option-sort-append.html create mode 100644 docs/example-option-sort-empty.html create mode 100644 docs/example-option-sort-force.html create mode 100644 docs/example-option-sort-key.html create mode 100644 docs/example-option-sort-list.html create mode 100644 docs/example-option-sort-order.html create mode 100644 docs/example-option-sortreset-sortrestart.html create mode 100644 docs/example-option-text-extraction.html create mode 100644 docs/example-option-textsorter-semver.html create mode 100644 docs/example-option-theme-metro-style.html create mode 100644 docs/example-options-headers-digits-strings.html create mode 100644 docs/example-options-headers-locked.html create mode 100644 docs/example-options-headers-order.html create mode 100644 docs/example-options-headers-parser.html create mode 100644 docs/example-options-headers.html create mode 100644 docs/example-pager-ajax.html create mode 100644 docs/example-pager-filtered.html create mode 100644 docs/example-pager.html create mode 100644 docs/example-parsers-advanced.html create mode 100644 docs/example-parsers-class-name.html create mode 100644 docs/example-parsers-date-range.html create mode 100644 docs/example-parsers-dates.html create mode 100644 docs/example-parsers-duration.html create mode 100644 docs/example-parsers-feet-inch-fraction.html create mode 100644 docs/example-parsers-file-type.html create mode 100644 docs/example-parsers-ignore-articles.html create mode 100644 docs/example-parsers-ip-address.html create mode 100644 docs/example-parsers-jquery-data.html create mode 100644 docs/example-parsers-metric.html create mode 100644 docs/example-parsers-named-numbers.html create mode 100644 docs/example-parsers-roman.html create mode 100644 docs/example-parsers.html create mode 100644 docs/example-trigger-sort.html create mode 100644 docs/example-triggers.html create mode 100644 docs/example-update-all.html create mode 100644 docs/example-update-cell.html create mode 100644 docs/example-widget-align-character.html create mode 100644 docs/example-widget-bootstrap-theme-v2.html create mode 100644 docs/example-widget-bootstrap-theme.html create mode 100644 docs/example-widget-build-table.html create mode 100644 docs/example-widget-chart.html create mode 100644 docs/example-widget-column-selector.html create mode 100644 docs/example-widget-columns.html create mode 100644 docs/example-widget-css-sticky-header.html create mode 100644 docs/example-widget-editable.html create mode 100644 docs/example-widget-filter-any-match.html create mode 100644 docs/example-widget-filter-custom-search.html create mode 100644 docs/example-widget-filter-custom-search2.html create mode 100644 docs/example-widget-filter-custom.html create mode 100644 docs/example-widget-filter-external-inputs.html create mode 100644 docs/example-widget-filter-formatter-1.html create mode 100644 docs/example-widget-filter-formatter-2.html create mode 100644 docs/example-widget-filter-formatter-select2.html create mode 100644 docs/example-widget-filter.html create mode 100644 docs/example-widget-formatter.html create mode 100644 docs/example-widget-grouping-filter-childrows.html create mode 100644 docs/example-widget-grouping.html create mode 100644 docs/example-widget-header-titles.html create mode 100644 docs/example-widget-math.html create mode 100644 docs/example-widget-output.html create mode 100644 docs/example-widget-pager-ajax.html create mode 100644 docs/example-widget-pager.html create mode 100644 docs/example-widget-print.html create mode 100644 docs/example-widget-reflow.html create mode 100644 docs/example-widget-reflow1.html create mode 100644 docs/example-widget-reflow2.html create mode 100644 docs/example-widget-reflow3.html create mode 100644 docs/example-widget-resizable.html create mode 100644 docs/example-widget-savesort.html create mode 100644 docs/example-widget-scroller.html create mode 100644 docs/example-widget-static-row.html create mode 100644 docs/example-widget-sticky-header.html create mode 100644 docs/example-widget-ui-theme.html create mode 100644 docs/example-widget-zebra.html create mode 100644 docs/example-widgets.html create mode 100644 docs/fonts/glyphicons-halflings-regular.eot create mode 100644 docs/fonts/glyphicons-halflings-regular.svg create mode 100644 docs/fonts/glyphicons-halflings-regular.ttf create mode 100644 docs/fonts/glyphicons-halflings-regular.woff create mode 100644 docs/fonts/glyphicons-halflings-regular.woff2 create mode 100644 docs/img/external.png create mode 100644 docs/img/link.png create mode 100644 docs/img/screens-blue.png create mode 100644 docs/img/screens.png create mode 100644 docs/index.html create mode 100644 docs/js/bootstrap.min.js create mode 100644 docs/js/chili/jquery.chili-2.2.js create mode 100644 docs/js/chili/recipes.js create mode 100644 docs/js/demo-build-table.js create mode 100644 docs/js/docs.js create mode 100644 docs/js/jquery-1.2.6.min.js create mode 100644 docs/js/jquery-1.4.4.min.js create mode 100644 docs/js/jquery-latest.min.js create mode 100644 docs/js/jquery-ui.min.js create mode 100644 docs/js/jquery.jui_theme_switch.min.js create mode 100644 docs/js/jquery.magnific-popup.min.js create mode 100644 docs/js/jquery.tipsy.min.js create mode 100644 docs/js/prettify.js create mode 100644 docs/js/rangeslider.min.js create mode 100644 docs/js/search-ie.js create mode 100644 docs/js/search.js create mode 100644 docs/js/select2-3.4.6.min.js create mode 100644 docs/js/sugar.min.js create mode 100644 docs/themes.html create mode 100644 example.json create mode 100644 index.html create mode 100644 js/extras/jquery.dragtable.mod.js create mode 100644 js/extras/jquery.metadata.js create mode 100644 js/extras/jquery.quicksearch.js create mode 100644 js/extras/semver-mod.js create mode 100644 js/extras/semver.js create mode 100644 js/jquery.tablesorter.combined.js create mode 100644 js/jquery.tablesorter.js create mode 100644 js/jquery.tablesorter.widgets.js create mode 100644 js/parsers/parser-date-extract.js create mode 100644 js/parsers/parser-date-iso8601.js create mode 100644 js/parsers/parser-date-month.js create mode 100644 js/parsers/parser-date-range.js create mode 100644 js/parsers/parser-date-two-digit-year.js create mode 100644 js/parsers/parser-date-weekday.js create mode 100644 js/parsers/parser-date.js create mode 100644 js/parsers/parser-duration.js create mode 100644 js/parsers/parser-feet-inch-fraction.js create mode 100644 js/parsers/parser-file-type.js create mode 100644 js/parsers/parser-globalize.js create mode 100644 js/parsers/parser-ignore-articles.js create mode 100644 js/parsers/parser-image.js create mode 100644 js/parsers/parser-input-select.js create mode 100644 js/parsers/parser-metric.js create mode 100644 js/parsers/parser-named-numbers.js create mode 100644 js/parsers/parser-network.js create mode 100644 js/parsers/parser-roman.js create mode 100644 js/widgets/widget-alignChar.js create mode 100644 js/widgets/widget-build-table.js create mode 100644 js/widgets/widget-chart.js create mode 100644 js/widgets/widget-columnSelector.js create mode 100644 js/widgets/widget-columns.js create mode 100644 js/widgets/widget-cssStickyHeaders.js create mode 100644 js/widgets/widget-editable.js create mode 100644 js/widgets/widget-filter-formatter-html5.js create mode 100644 js/widgets/widget-filter-formatter-jui.js create mode 100644 js/widgets/widget-filter-formatter-select2.js create mode 100644 js/widgets/widget-filter-type-insideRange.js create mode 100644 js/widgets/widget-filter.js create mode 100644 js/widgets/widget-formatter.js create mode 100644 js/widgets/widget-grouping.js create mode 100644 js/widgets/widget-headerTitles.js create mode 100644 js/widgets/widget-math.js create mode 100644 js/widgets/widget-output.js create mode 100644 js/widgets/widget-pager.js create mode 100644 js/widgets/widget-print.js create mode 100644 js/widgets/widget-reflow.js create mode 100644 js/widgets/widget-repeatheaders.js create mode 100644 js/widgets/widget-resizable.js create mode 100644 js/widgets/widget-saveSort.js create mode 100644 js/widgets/widget-scroller.js create mode 100644 js/widgets/widget-staticRow.js create mode 100644 js/widgets/widget-stickyHeaders.js create mode 100644 js/widgets/widget-storage.js create mode 100644 js/widgets/widget-uitheme.js create mode 100644 package.json create mode 100644 tablesorter.jquery.json create mode 100644 test.html create mode 100644 testing/qunit-1.16.0.css create mode 100644 testing/qunit-1.16.0.js create mode 100644 testing/testing-ipv6.js create mode 100644 testing/testing-widgets.js create mode 100644 testing/testing.css create mode 100644 testing/testing.js diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..14d6746 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain +*.md diss=astextplain \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fa9ca0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,165 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*_test*.* +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +node_modules/ +*_i.c +*_p.c +*.ilk +*.log +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +.builds +*.dotCover + +## TODO: If you have NuGet Package Restore enabled, uncomment this +#packages/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Others +[Bb]in +[Oo]bj +sql +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +# Mac crap +.DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1b04f9a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,45 @@ +# Contributing to tablesorter (FORK) + +1. [Getting Involved](#getting-involved) +2. [How To Report issues](#how-to-report-issues) +3. [Contributing Code](#contributing-code) + +## Getting Involved + +There are a number of ways to get involved with the development of this fork of Tablesorter. Even if you've never contributed to an Open Source project before, we're always looking for help identifying issues. + +## How to Report issues, or make requests. + +* First off make sure it's a new issue. Search the [FAQ](https://github.com/Mottie/tablesorter/wiki/FAQ), [documents](http://mottie.github.io/tablesorter/docs/) and the [issues](https://github.com/Mottie/tablesorter/issues). +* If it's an existing issue or feature request, and you want to show that it is also a concern for you. Add a comment! +* If it turns out to not be an issue, but a question instead: + * Please don't open a new issue. + * Jump on out freenode.net IRC channel: `#tablesorter`. + * Ask the question on [Stackoverflow](https://stackoverflow.com/questions/tagged/tablesorter) (tablesorter or jQuery tag). +* If you do open a new issue: + * If the issue only occurs in a particular browser or version of jQuery, that would be awesome to know! + * Please include any *relevant* code (posting the entire page usually isn't that helpful). + * Add if there are any errors showing in the console (press F12 in the browser and go to the console tab). + * Include screenshots, animated gifs, videos (check out [screenr](https://www.screenr.com/)) or funny cat pictures. You never know what might help! + +## Contributing Code + +* Installation: + * Please see the [Customize](https://github.com/Mottie/tablesorter/wiki/Customize) wiki page for specifics on how to install the necessary modules & create a custom build. + * If you aren't comfortable using grunt or making a build file, you can go ahead and just share the changes. +* Style Guide: + * We're not too strict, just try to follow the style that is already being used in the code. + * When naming variables: + * Use names that describe it's contents. I'm guilty of naming things `t` and `i`, but I'm slowly trying to rename them to make reading code and finding the variable in the code easier. + * Name jQuery objects with a leading `$`, e.g. `var $table = $('table');` + * We like semicolons! Jshint will yell at you if you don't use them. + * We like single quotes! It's OCD man! + * We like tabs! + * We like pizza! +* Pull request: + * Before opening a pull request, please make sure that your code is on a *fork* of the master. This is really for your own convenience: it's easy for us to accept your pull request from your master branch, but it's problematic for your fork when you want to pull the changes back and your master branch has diverged from upstream's master branch. + * Add unit tests - tablesorter is still missing a lot of unit tests, so adding tests for your contribution would be a tremendous help! + * Also, make sure to test your changes! + * Use `grunt test` ([ref](https://github.com/Mottie/tablesorter/wiki/Customize#testing-a-build)) + * If you aren't comfortable with using grunt, copy, then paste your code into [jsHint](http://jshint.com/) to help find any problems with the changes. + * There is no need to open an issue, then create a pull request. Just create the pull request and add any comments about your changes there. diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..ccff1a2 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,399 @@ +/*global module:false*/ +module.exports = function( grunt ) { + 'use strict'; + + var pkg = grunt.file.readJSON( 'package.json' ), + tasks, + widgetFilePrefix, + widgetFileSuffix, + + defaults = { + dependencies : { + widgets: { + 'saveSort resizable pager filter columnSelector' : 'storage', + 'filter-formatter-html5 filter-formatter-jui filter-formatter-select2' : 'filter' + // 'stickyHeaders' : 'addResizeEvent' // included with stickyHeaders widget (for now) + } + }, + standardWidgets: [ + 'storage', // req by saveSort; optional in others + 'uitheme', + 'columns', + 'filter', + 'stickyHeaders', + 'resizable', + 'saveSort' + // 'addResizeEvent', // included with stickyHeaders widget + // 'zebra' // included in core + ], + standardWidgetFileName: 'jquery.tablesorter.widgets.js', + wrappers : { + widgetPrefix: 'js/widgets/widget-', + widgetSuffix: '.js', + parserPrefix: 'js/parsers/parser-', + parserSuffix: '.js' + }, + wrapperUMD: { + // tablesorter core + coreBanner: '(function(factory) {\n' + + " if (typeof define === 'function' && define.amd) {\n" + + " define(['jquery'], factory);\n" + + " } else if (typeof module === 'object' && typeof module.exports === 'object') {\n" + + " module.exports = factory(require('jquery'));\n" + + ' } else {\n' + + ' factory(jQuery);\n' + + ' }\n' + + '}(function($) {\n\n', + // widgets wrapper & combined wrapper - may need a separate entry when this wrapper is redefined to make + // widgets a dependency of the core (see https://github.com/Mottie/tablesorter/issues/855) + banner: '<%= pkg.banner %>/* Includes widgets ( <%= pkg.selectedWidgets %> <%= pkg.selectedParsers %>) */\n' + + '(function(factory) {\n' + + " if (typeof define === 'function' && define.amd) {\n" + + " define(['jquery'], factory);\n" + + " } else if (typeof module === 'object' && typeof module.exports === 'object') {\n" + + " module.exports = factory(require('jquery'));\n" + + ' } else {\n' + + ' factory(jQuery);\n' + + ' }\n' + + '}(function($) {\n\n', + footer: '\nreturn $.tablesorter;\n}));\n' + }, + noModBanner: '/*** This file is dynamically generated ***\n' + + '█████▄ ▄████▄ █████▄ ▄████▄ ██████ ███████▄ ▄████▄ █████▄ ██ ██████ ██ ██\n' + + '██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██\n' + + '██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██\n' + + '█████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀\n*/\n' + }, + + // example widgets = [ 'pager', 'column', 'filter', 'stickyHeaders' ]; + addWidgetDependencies = function( widgets ) { + var indx, dep, + maxDeps = 40, // just in case (there are currently 27 widgets) + len = widgets.length, + deps = defaults.dependencies.widgets; + for ( dep in deps ) { + if ( typeof dep === 'string' ) { + for ( indx = 0; indx < len; indx++ ) { + // make sure indexOf is not matching 'column' instead of 'columnSelector' with surrounding spaces + if ( ( ' ' + dep + ' ' ).indexOf( ' ' + widgets[indx] + ' ' ) >= 0 && widgets.indexOf( deps[ dep ] ) < 0 ) { + widgets.push( deps[ dep ] ); + // keep checking newly added widgets, in case 'filter' is added and 'storage' hasn't been + if ( len < maxDeps ) { len++; } + continue; + } + } + } + } + return widgets; + }, + formFileNames = function() { + var wrap = defaults.wrappers; + // add widget path & file extension + pkg.processedWidgets = ( wrap.widgetPrefix + + pkg.selectedWidgets.join( wrap.widgetSuffix + ',' + wrap.widgetPrefix ) + + wrap.widgetSuffix ).split( ',' ); + console.info( 'Creating a widgets file with: ' + pkg.selectedWidgets.join(', ') ); + + if ( pkg.selectedParsers ) { + // parser path & file extension + pkg.processedParsers = ( wrap.parserPrefix + + pkg.selectedParsers.join( wrap.parserSuffix + ',' + wrap.parserPrefix ) + + wrap.parserSuffix ).split( ',' ); + console.info( 'Creating a combined file with selected widgets & these parsers: ' + pkg.selectedParsers.join(', ') ); + // make this look nice for the banner + pkg.selectedParsers = ') & parsers ( ' + pkg.selectedParsers + ' '; + } + console.info( pkg.processedParsers ); + }; + + // minified banner template - updated ##/##/20## (v2.##.##) + pkg.banner = '/*! <%= pkg.name %> (FORK) - updated ' + + '<%= grunt.template.today("mm-dd-yyyy") %> (v<%= pkg.version %>)*/\n'; + + pkg.buildWidget = defaults.standardWidgetFileName; + pkg.buildCombined = 'jquery.tablesorter.combined.js'; + pkg.processedParsers = '!js/parsers/*.js'; + + // Project configuration. + grunt.initConfig({ + pkg: pkg, + + clean: { + build: { + src: [ 'dist/**/**/**/*', 'dist/**/**/*', 'dist/**/*', 'dist' ] + }, + css: { + src: [ 'dist/css/*.css', '!dist/css/*.min.css' ] + } + }, + + copy: { + css: { + files : [{ + expand: true, + dot: true, + flatten: true, + src: [ 'css/*.css', 'addons/pager/*.css' ], + dest: 'dist/css/', + rename: function( dest, src ) { + if ( /black-ice/.test( src ) ) { + src = src.replace( /-/, '' ); + } + return dest + src; + } + }] + }, + less: { + expand: true, + flatten: true, + src: 'css/*.less', + dest: 'dist/css/less/' + }, + images: { + expand: true, + flatten: true, + src: [ 'addons/pager/icons/*', 'css/images/*' ], + dest: 'dist/css/images/' + } + }, + + concat: { + main: { + options: { + banner: defaults.wrapperUMD.coreBanner, + footer: defaults.wrapperUMD.footer + }, + src: [ 'js/jquery.tablesorter.js' ], + dest: 'dist/js/jquery.tablesorter.js' + }, + widgets: { + options: { + banner: defaults.wrapperUMD.banner, + footer: defaults.wrapperUMD.footer + }, + src: [ + '<%= pkg.processedWidgets %>', + '!js/widgets/_test-*.js', + '!js/widgets/*.min.js' + ], + dest: 'dist/js/<%= pkg.buildWidget %>' + }, + everything: { + options: { + banner: defaults.wrapperUMD.banner, + footer: defaults.wrapperUMD.footer + }, + src: [ + 'js/jquery.tablesorter.js', + '<%= pkg.processedWidgets %>', + '<%= pkg.processedParsers %>', + '!js/widgets/_test-*.js', + '!js/widgets/*.min.js' + ], + dest: 'dist/js/<%= pkg.buildCombined %>' + }, + // keep all the existing jsFiddle demos from breaking + copybackWidgets: { + options: { + banner: defaults.noModBanner + }, + src : ['dist/js/<%= pkg.buildWidget %>'], + dest: 'js/<%= pkg.buildWidget %>' + }, + copybackCombined: { + options: { + banner: defaults.noModBanner + }, + src : ['dist/js/<%= pkg.buildCombined %>'], + dest: 'js/<%= pkg.buildCombined %>' + } + }, + + jshint: { + files: { + src: [ + 'addons/pager/*.js', + '!addons/pager/*.min.js', + 'js/jquery.*.js', + 'js/**/*.js', + '!js/_test-*.js', + '!js/**/_test-*.js', + '!js/*.min.js', + '!js/**/semver*.js' + ] + }, + options: { + globals: { + 'localStorage': false, + 'navigator': false, + 'console': false, + 'alert': false + }, + 'loopfunc': true, + 'jquery': true, + 'browser': true + } + }, + + uglify: { + options: { + preserveComments: 'some', + report: 'gzip' + }, + allFiles: { + files: [{ + expand: true, + cwd: './js/', // Src matches are relative to this path. + src: [ + '**/*.js', + '!jquery.tablesorter.js', + '!_test-*.js', + '!**/_test-*.js', + '!*.min.js', + '!**/semver.js' + ], + dest: 'dist/js/', + ext: '.min.js', // Dist files will have this extension. + extDot: 'last' // Extensions in filenames begin after this dot + }] + }, + // jquery.tablesorter.min.js is being minified from js/jquery.tablesorter.js + // so it doesn't include the UMD wrapper! Point to the dist/js/ version + main: { + files : [{ + expand: true, + cwd: './dist/js/', + src: [ 'jquery.tablesorter.js' ], + dest: 'dist/js/', + ext: '.min.js', // Dist files will have this extension. + extDot: 'last' // Extensions in filenames begin after this dot + }] + }, + pageraddon: { + files: { + 'dist/js/extras/jquery.tablesorter.pager.min.js': [ 'addons/pager/*.js' ] + } + } + }, + + cssmin: { + target: { + files: [{ + expand: true, + flatten: true, + cwd: 'dist/css', + src: ['*.css', '!_test-*.css'], + dest: 'dist/css', + ext: '.min.css', + extDot: 'last' + }] + } + }, + + qunit: { + files: [ 'test.html' ] + }, + + watch: { + scripts: { + files: [ + 'js/*.js', + 'js/**/*.js', + '!js/_test-*.js', + '!js/*.min.js' + ], + tasks: [ 'build' ] + } + } + + }); + + grunt.loadNpmTasks( 'grunt-contrib-clean' ); + grunt.loadNpmTasks( 'grunt-contrib-jshint' ); + grunt.loadNpmTasks( 'grunt-contrib-qunit' ); + grunt.loadNpmTasks( 'grunt-contrib-concat' ); + grunt.loadNpmTasks( 'grunt-contrib-uglify' ); + grunt.loadNpmTasks( 'grunt-contrib-copy' ); + grunt.loadNpmTasks( 'grunt-contrib-watch' ); + grunt.loadNpmTasks( 'grunt-contrib-cssmin' ); + + grunt.registerTask( 'test', [ 'jshint', 'qunit' ] ); + + tasks = [ + 'clean:build', + 'copy', + 'concat', + 'uglify', + 'cssmin', + 'clean:css', + 'updateManifest' + ]; + + // basic = same as before: core, widgets, filterformatter all separate + grunt.registerTask( 'default', 'Default build', function() { + pkg.selectedWidgets = addWidgetDependencies( defaults.standardWidgets ); + formFileNames(); + grunt.task.run(tasks); + }); + + // quick build to just minify files for pushes between updates + grunt.registerTask( 'quick', [ 'copy', 'uglify', 'clean:css' ] ); + + // enter 'grunt custom:{filename}' (not including the '.json') + // to load in a custom json file + // the expected JSON format is (with custom widgets in a string): + // { "widgets" : "columnHighlight filter resizable saveSort stickyHeaders uitheme" } + grunt.registerTask( 'custom', 'Custom build', function(file) { + var temp, widgets, + parsers = '', + deps = true; + + /* Allow developer to set up a custom widget build (json file will have settings)*/ + try { + temp = grunt.file.readJSON( file ); + if ( temp ) { + parsers = temp.parsers; + // include dependencies? + deps = ('includeDependencies' in temp) ? temp.includeDependencies : true; + // custom file name? + pkg.buildWidget = ('destFileName' in temp) ? temp.destFileName : 'jquery.tablesorter.custom-widgets.js'; + // widgets to include + widgets = (temp.widgets || ''); + if (widgets.replace(/\s+/g,'') === '') { + grunt.log.error('No widgets found in custom build file.'); + console.info('Continuing build with default widgets...'); + temp = defaults.standardWidgets; + pkg.buildWidget = defaults.standardWidgetFileName; + } else { + temp = widgets.split(/\s+/); + } + } + } catch (err) { + grunt.log.error('Custom build json not found - Use "grunt custom:{filename}"'); + console.info('Continuing build with default settings'); + temp = defaults.standardWidgets; + } + // add dependencies + pkg.selectedWidgets = deps ? addWidgetDependencies( temp ) : temp; + pkg.selectedParsers = parsers.split( /\s+/ ); + formFileNames(); + grunt.task.run(tasks); + }); + + // update bower.json & tablesorter.jquery.json file version numbers to match the package.json version + grunt.registerTask( 'updateManifest', function() { + var i, project, + projectFile = [ 'tablesorter.jquery.json', 'bower.json' ], + len = projectFile.length; + for ( i = 0; i < len; i++ ) { + if ( !grunt.file.exists( projectFile[ i ] ) ) { + grunt.log.error( 'file ' + projectFile[ i ] + ' not found' ); + return true; // return false to abort the execution + } + project = grunt.file.readJSON( projectFile[ i ] ); // get file as json object + project.version = pkg.version; + grunt.file.write( projectFile[i], JSON.stringify( project, null, 2 ) ); // serialize it back to file + } + }); + +}; diff --git a/README.md b/README.md new file mode 100644 index 0000000..dd4f8dd --- /dev/null +++ b/README.md @@ -0,0 +1,189 @@ +tablesorter (FORK) is a jQuery plugin for turning a standard HTML table with THEAD and TBODY tags into a sortable table without page refreshes. +tablesorter can successfully parse and sort many types of data including linked data in a cell. This forked version adds lots of new enhancements including: alphanumeric sorting, pager callback functons, multiple widgets providing column styling, ui theme application, sticky headers, column filters and resizer, as well as extended documentation with a lot more demos. + +### Notice! + +* Because of the change to the internal cache, the tablesorter v2.16+ core, filter widget and pager (both plugin & widget) will only work with the same version or newer files. + +### [Documentation](//mottie.github.io/tablesorter/docs/) + +* See the [full documentation](//mottie.github.io/tablesorter/docs/). +* All of the [original document pages](//tablesorter.com/docs/) have been included. +* Information from my blog post on [undocumented options](//wowmotty.blogspot.com/2011/06/jquery-tablesorter-missing-docs.html) and lots of new demos have also been included. +* Change log moved from included text file into the [wiki documentation](//github.com/Mottie/tablesorter/wiki/Changes). + +### Demos + +* [Basic alpha-numeric sort Demo](//mottie.github.com/tablesorter/). +* Links to demo pages can be found within the main [documentation](//mottie.github.io/tablesorter/docs/). +* More demos & playgrounds - updated in the [wiki pages](//github.com/Mottie/tablesorter/wiki). + +### Features + +* Multi-column alphanumeric sorting and filtering. +* Multi-tbody sorting - see the [options](//mottie.github.io/tablesorter/docs/index.html#options) table on the main document page. +* Supports [Bootstrap v2 and 3](//mottie.github.io/tablesorter/docs/example-widget-bootstrap-theme.html) +* Parsers for sorting text, alphanumeric text, URIs, integers, currency, floats, IP addresses, dates (ISO, long and short formats) & time. [Add your own easily](//mottie.github.io/tablesorter/docs/example-parsers.html). +* Inline editing - see [demo](//mottie.github.io/tablesorter/docs/example-widget-editable.html) +* Support for ROWSPAN and COLSPAN on TH elements. +* Support secondary "hidden" sorting (e.g., maintain alphabetical sort when sorting on other criteria). +* Extensibility via [widget system](//mottie.github.io/tablesorter/docs/example-widgets.html). +* Cross-browser: IE 6.0+, FF 2+, Safari 2.0+, Opera 9.0+, Chrome 5.0+. +* Small code size, starting at 25K minified +* Works with jQuery 1.2.6+ (jQuery 1.4.1+ needed with some widgets). +* Works with jQuery 1.9+ ($.browser.msie was removed; needed in the original version). + +### Licensing + +* Copyright (c) 2007 Christian Bach. +* Original examples and docs at: [http://tablesorter.com](//tablesorter.com). +* Dual licensed under the [MIT](//www.opensource.org/licenses/mit-license.php) and [GPL](//www.gnu.org/licenses/gpl.html) licenses. + +### Download + +* Get [all files](https://github.com/Mottie/tablesorter/archive/master.zip) +* Use [bower](http://bower.io/): `bower install jquery.tablesorter` +* Use [node.js](http://nodejs.org/): `npm install tablesorter` +* CDNJS: [https://cdnjs.com/libraries/jquery.tablesorter](https://cdnjs.com/libraries/jquery.tablesorter) + +### Related Projects + +* [Plugin for Rails](//github.com/themilkman/jquery-tablesorter-rails). Maintained by [themilkman](//github.com/themilkman). +* [Bootsole](//alexweissman.github.io/bootsole/) (OOP templating engine using tablesorter) by [alexweissman](//github.com/alexweissman). + +### Contributing + +If you would like to contribute, please... + +1. Fork. +2. Make changes in a branch & add unit tests. +3. Run `grunt test` (if qunit fails, run it again - it's fickle). +4. Create a pull request. + +### Special Thanks + +* Big shout-out to [Nick Craver](//github.com/NickCraver) for getting rid of the `eval()` function that was previously needed for multi-column sorting. +* Big thanks to [thezoggy](//github.com/thezoggy) for helping with code, themes and providing valuable feedback. +* Big thanks to [ThsSin-](//github.com/TheSin-) for taking over for a while and also providing valuable feedback. +* Thanks to [prijutme4ty](https://github.com/prijutme4ty) for numerous contributions! +* Also extra thanks to [christhomas](//github.com/christhomas) and [Lynesth](//github.com/Lynesth) for help with code. +* And, of course thanks to everyone else that has contributed, and continues to contribute to this forked project! + +### Questions? + +* Check the [FAQ](//github.com/Mottie/tablesorter/wiki/FAQ) page. +* Search the [main documentation](//mottie.github.io/tablesorter/docs/) (click the menu button in the upper left corner). +* Search the [issues](//github.com/Mottie/tablesorter/issues) to see if the question or problem has been brought up before, and hopefully resolved. +* If someone is available, ask your question in the `#tablesorter` IRC channel at freenode.net. +* Ask your question at [Stackoverflow](//stackoverflow.com/questions/tagged/tablesorter) using a tablesorter tag. +* Please don't open a [new issue](//github.com/Mottie/tablesorter/issues) unless it really is an issue with the plugin, or a feature request. Thanks! + +### Recent Changes + +View the [complete change log here](//github.com/Mottie/tablesorter/wiki/Changes). + +#### Version 2.22.1 (5/17/2015) + +* Filter: fix issue with searches always looking for parsed content in numeric columns. + +#### Version 2.22.0 (5/17/2015) + +* Docs + * Lots of minor version updates, spelling corrections & clarifications in wording. + * Update box-sizing styles ([ref](http://www.paulirish.com/2012/box-sizing-border-box-ftw/)). + * Update `characterEquivalents` cross-reference to correctly match the code of the plugin. + * Add Build table widget example resulting HTML for the json example. +* Grunt build + * `package.json` files now points to the entire "dist" folder. See [issue #881](https://github.com/Mottie/tablesorter/issues/881). + * Add `grunt quick` build to only update widget & parser files; it skips updating the dates in the widgets & combined files. +* Core + * The `isDigit` function now reports `false` on empty strings. See [issue #865](https://github.com/Mottie/tablesorter/issues/865). + * Add pointer events options (`pointerClick`, `pointerDown` and `pointerUp`). Fixes [issue #885](https://github.com/Mottie/tablesorter/issues/885). + * Prevent js error when using the `computeColumnIndex` function on empty tables (used by the math widget). Fixes [issue #889](https://github.com/Mottie/tablesorter/issues/889). + * Prevent js error when `sortList` includes an out-of-bounds column. Fixes [issue #908](https://github.com/Mottie/tablesorter/issues/908). + * Centralize extractor & parser code; this code is used by the main build cache loop and the "addRows" & "updateCell" methods. + * Child row content is now properly stored in row data as an array of arrays. + * Add "o" to `sortLocaleCompare` replacement table & update docs. + * Replace all instances of using jQuery each with plain javascript. Fixes [issue #827](https://github.com/Mottie/tablesorter/issues/827). +* Editable + * Modify `trimContent` option & use HTML to modify text. Fixes [issue #886](https://github.com/Mottie/tablesorter/issues/886). + * Fix `selectAll` & change `tbody` mouseleave to complete editing to `thead` mouseenter. Fixes [issue #848](https://github.com/Mottie/tablesorter/issues/848). + * Only make table cell child div/span contenteditable. See [issue #900](https://github.com/Mottie/tablesorter/issues/900). + * Add remove widget code & allow dynamic updating if the "no-edit" class changes. Fixes [issue #900](https://github.com/Mottie/tablesorter/issues/900). +* Filter + * Regex filter searches now cache the created regex object for each query to optimize speed & a regex search now properly uses case-sensitive content + * Add `data` parameter to `filter_functions`. This is the same data used by the filter search type functions. See [issue #891](https://github.com/Mottie/tablesorter/issues/891). + * Any match searches which target specific columns will no longer save each filter to its respective column; see ["AnyMatch Searches"](http://mottie.github.io/tablesorter/docs/example-widget-filter-any-match.html#anymatch_searches) documentation. + * Operator filter searchs now ignore empty strings (because `"" < 10` is `true`). + * Clean up `parseFilter` function. + * Add `filter_childByColumn` option. + * Setting this to `true` allows searching through the child rows by column. + * When `false`, the search behaves as before and all child row content is included in the search of every column. + * See a [demo here](http://mottie.github.io/tablesorter/docs/example-child-rows-filtered.html#child-by-column). + * Fixes issues [#396](https://github.com/Mottie/tablesorter/issues/396) & [#574](https://github.com/Mottie/tablesorter/issues/574). + * Code cleanup - added a bunch of whitespace & forced line wraps at around 120. + * Prevent setFilter function from setting the same filters after an update. Fixes issues [#903](https://github.com/Mottie/tablesorter/issues/903) & [#733](https://github.com/Mottie/tablesorter/issues/733). +* Grouping + * Add keyboard accessibility to group headers. See [issue #260](https://github.com/Mottie/tablesorter/issues/260). +* Math + * Fix issues with `isNaN('') // false`. See [issue #873](https://github.com/Mottie/tablesorter/issues/873). + * Reapply column indexing after updates & prevent js error on empty tables. Fixes [issue #889](https://github.com/Mottie/tablesorter/issues/889). + * Reduce update time to 20ms. See [issue #898](https://github.com/Mottie/tablesorter/issues/898). + * Exclude ignored cells even if `math_ignore` is empty. Fixes [issue #896](https://github.com/Mottie/tablesorter/issues/896). +* Output + * Add BOM back to downloaded file. Fixes [issue #862](https://github.com/Mottie/tablesorter/issues/862). + * Add `output_hiddenColumns` option. Fixes [issue #869](https://github.com/Mottie/tablesorter/issues/869). + * Add known issues section about downloading in Safari. +* Pager (addon & widget) + * Replace all instances of using jQuery each with plain javascript. Fixes [issue #827](https://github.com/Mottie/tablesorter/issues/827). +* Resizable + * Refreshing the widget will now preserve the storage. See [issue #874](https://github.com/Mottie/tablesorter/issues/874). +* Scroller + * Set `overflow-x` auto & apply border-box to scroller. See [issue #135](https://github.com/Mottie/tablesorter/issues/135). + * Remove `pointer-events: none` from fixed column. See [issue #878](https://github.com/Mottie/tablesorter/issues/878). + * Hide fixed column scrollbar in IE9 & older. See [issue #135](https://github.com/Mottie/tablesorter/issues/135). + * Update `pointer-events` and tabbing accessibility. See [issue #135](https://github.com/Mottie/tablesorter/issues/135). + * `setFixedColumnSize` now properly updates with no set size. + * Add `scroller_addFixedOverlay` + * When `true`, a fixed column overlay is added for additional styling. See [issue #887](https://github.com/Mottie/tablesorter/issues/887). + * It includes css [`pointer-events`](http://caniuse.com/#search=pointer-events) set to `none` to allow interaction with elements underneath; make sure your browser supports it! + * Fix selector issue in the remove function. + * Properly refresh column size after an update. Fixes the third part of [issue #906](https://github.com/Mottie/tablesorter/issues/906). +* Parsers + * Add "inputs-numeric" parser. Fixes [issue #888](https://github.com/Mottie/tablesorter/issues/888). + * Add [jQuery Globalize](https://github.com/jquery/globalize) [date](http://jsfiddle.net/Mottie/0j18Lw8r/) & [number](http://jsfiddle.net/Mottie/0j18Lw8r/) parsers. + * "namedNumbers" parser: ignores adjacent puncutation. Fixes [issue #890](https://github.com/Mottie/tablesorter/issues/890). + * input-select parsers: + * Clean up & add event namespaces. + * Now return an empty string if the value is empty; previously, it would return the cell text when the value was empty. + * Network "MAC" parser: + * Return the original string if the address is grossly invalid. Fixes [issue #895](https://github.com/Mottie/tablesorter/issues/895). + * No longer auto-detect as iPv6. See [issue #895](https://github.com/Mottie/tablesorter/issues/895). +* Themes + * Declare font-weight separately. Thanks [nikolas](https://github.com/nikolas) ([pull #866](https://github.com/Mottie/tablesorter/pull/868))! + * Update Boostrap v2.x theme, and add a [Bootstrap v2.x demo](http://mottie.github.io/tablesorter/docs/example-widget-bootstrap-theme-v2.html). + +#### Version 2.21.5 (4/8/2015) + +* Filter + * Cache main loop variables - speed enhancement. + * Allow setting `filter_selectSource` along with `filter_functions` ([demo](http://jsfiddle.net/Mottie/856bzzeL/117/)). +* Resizable + * Integrate with columnSelector. See [issue #859](https://github.com/Mottie/tablesorter/issues/859). + * Prevent javascript error. + * Resizable handles now properly align when the table is within a layout with margins. Fixes [issue #864](https://github.com/Mottie/tablesorter/issues/864). +* Scroller + * Apply on initialization. Fixes [issue #860](https://github.com/Mottie/tablesorter/issues/860). + +#### Version 2.21.4 (3/28/2015) + +* Core + * Add a utility [`$.tablesorter.getColumnText()` function](http://mottie.github.io/tablesorter/docs/#function-getcolumntext). + * This function will provide a centralized method of obtaining column data (raw & parsed text from cells) and allow processing cells. + * I plan to update all widgets that need to interact or obtain column data to use this function in v2.22.0. +* Build + * The build process now includes selected parsers (added `parsers` option to build json). + * A new `jquery.tablesorter.combined.js` file is created which will contain the core plugin along with all selected widgets & parsers; a default build does not have any selected parsers. + * This will work around, but not resolve, [issue #855](https://github.com/Mottie/tablesorter/issues/855). +* Extras + * Update `semver.js` & `semver-mod.js` to v4.3.3. diff --git a/addons/pager/icons/first.png b/addons/pager/icons/first.png new file mode 100644 index 0000000000000000000000000000000000000000..6f11fcb086b1bfa51bc5070ca45fac0a988c624c GIT binary patch literal 720 zcmV;>0x$iEP)ITpohD^Ctgf=H~o==W*|y0)VM;-LQd9lR=YF)677| z!Jh8V_;KSkP5LJrlF9S+j0qkk+2iPm7~x{#{$ZSbvzK9J-4zqYVC)27V7~717pTZd znit9v$VwYJS3ROyLxp^?0)a!0U)oMn7(0Xv0eUoZ@gH)t)d5_J+J%bT22oSJ)g^nf zqQZVCEIYOm2+rB;rB+cID%~N1o%g50=A<=fWgC_GFUb) z%s4&22M=t~3G+RMgR^pz#KbcfK)ZtsdJ$j@d{400GnQJeAz+sPu#&f$`6hKh0J%~V zq(%oWs|qZyzh}{lfSK@dRK#JSxg@DDP3^*cD+kP0j(npKkSQvp3bk_uYtD5My##O+ z;RpcDs9R5c#9;NFP5{z^GN_^r%PX%(0OOZ~7+aNFP*XZk{E2|i#E`vI`YjCrsfz|V zndEsDXoqvug2CxaF}ZvhdOaY6!{9q~KO+jO!o5Vk0qt%NcD}`cvVR;6QTNzYGWq-= zUX+?7V0e7VLW2m6_>T!vT6W8eRsOC$*+0hNMWWwDsLfA)S*X-WV71;M{bCzza-4I45g$8m^55K?|L?r+odSTVNnJ96LXt|7TGI4L>d~Fz z&-h8>1xd<>>vgSt=Y;X^$Jv9(As-4y`R%SPp?5wYYBW2LD^|g`7v>f>k`%^{A!C3N&EeR0q1EmI9?j zT<^fuCti3LD9UEdoCoe2BcvKUvD7KhHa~-21gL%Aj#%s&OGVR_$6iSuSoaqp%eN%J z76DWmU8pyEP^yWrwDz7wF9N262N52Jg#ie_jHv7Leqfv#&`?`&#}Fpfom5)T>7B!> zWsOHK0qlpu1b_k9E1Iu8-65F`u4B0T$PKrdAs|z3NmX=VY5BDbP=DEtvNfR%4Y5Zu z5VMpOD@qkb3GkT!aIm-Gn* z`85iZ>7zVE#RF?u>-GjXzTT2IfyTsX6XN-%yiPPHr0n_^E8Hzpe7MH(L!#e?D90zS zP^g}fN@{04Qcb!flJ%iEo~?q;Y!zl{=dXt}`IHwd0cyqO;QYY^WD0dM6YM#f=E3C+ z!2-R=&FDY;{gfv^)4f+|?c7Tj^US!+(gqX%T+i_HIx{<~voklC*uOv1|9t14Z-oeY T=@u`q-Vg)2ozNO$->CRz{H>f zQUKDzz~ne3e?i0B-7(yb4yr4bTs^i%F{Yz&j)hfn`=;ZaUeQxez2`bzvG#r5dd{19 z!Vll38%c$&oiKTOjaT|fg-sl?YN@OUQ`v#0ax(x)CXo=iMcq4Y^)WQ;^jy2>Pi|c0 z+yEr&d4XeL8If(~h1x7UMZQw|C0j$G*0IR9p-%D344shFF)_f@iA-r&*1q$O4~JHlrS=Ys z_3vtDAiIzOXf4!*A_|%9C!fc)bZLneovQiVkU1UVLRM%mejW= OqdvS&mB_TF$F*h9sL-j zNpc$weSXQZ6Gag%5kOy9HfA1@g zVA*&|VjFHeVhIV!`DzQM7F-a@NRTNvNlYYp4z%6NAQuJno^MeOJ!7dzy8e(=;etr6 z4q2h83Vb36o=G4!6u79$u)6u4LoN!;_)kItHmh9g5CP1HxVh+sSiS*Mlqx_uVfwL~ z+}p|}Y*;r1{g* z9DE4_W&SW~qUN5hWN@-RUJ#q3Ngxr&iJp;+4aEd;HM{A>I)B?7>yL4`Nc6h^we^ve z3YC6fwXTqAQWr8=Cd?emR={YnNptkhuSFVP{Q?6Lt^ zqF4A?)Arx1JpP&Pyh<4sUhXnam)AJ@xmkE-VuVGbg_|=vm|INb-=FD!zVlDxJ_uiv SXLQ>D0000yhD literal 0 HcmV?d00001 diff --git a/addons/pager/icons/prev.png b/addons/pager/icons/prev.png new file mode 100644 index 0000000000000000000000000000000000000000..15d1584bdbb2c26a9fc4c8269aa54615a58a4657 GIT binary patch literal 745 zcmV1hlor z)=Ec^h7>5J3?Bj(D6|X+0|UcQj&m*_Qg!D|-c07sd7pF6opXl(U}#WhWg0W$d_xV%ATb~UcS*dC+@kfS*m{?64KBH-eM78JQAu#&2c z7TM!?0X98;&a@msh@1ehFDx4~_smCS0rm@Z$dv@5Y^ec>Jl}_`uDh5!i#cpZh5&_) z{y|~cgJzZ1d%`?CxkdJIg%by0u(~PqB0%Zdj?maMmYO=M!=;B#0>~5_5YO>&?w*4H z@LRbi!eNPrxg`gUUIeK8JG(3%R{o~|7so$K+8_qZe0Iz($pKd%d&oOhA&AGYXkKE` zO8~w=kN^smCS05H!-WT*2mpbXAJK6B{s*`+;U?8|s%XO8{Hs1d`DH6am$(L0coEX9 z)c+Ho)WS9-4?6~g4NrO@c2FaKCYmmR!DQ~YpfIn+s8pr^?KThtmU&}3Kr*7R^y^Rk z5Xsb_*=oc3w-9KI@B4=+yK6a8uQ@#oTkf1PnlL+NjAm=Zh)+xqld|idFEF=^(avw| z4U*w)Kx6;tnV0ZXQD@SHtHr7{`Y12 bpX>Y!%!CO%>C8GV00000NkvXXu0mjfJYGkQ literal 0 HcmV?d00001 diff --git a/addons/pager/jquery.tablesorter.pager.css b/addons/pager/jquery.tablesorter.pager.css new file mode 100644 index 0000000..e77cd88 --- /dev/null +++ b/addons/pager/jquery.tablesorter.pager.css @@ -0,0 +1,42 @@ +/* pager wrapper, div */ +.tablesorter-pager { + padding: 5px; +} +/* pager wrapper, in thead/tfoot */ +td.tablesorter-pager { + background-color: #e6eeee; + margin: 0; /* needed for bootstrap .pager gets a 18px bottom margin */ +} +/* pager navigation arrows */ +.tablesorter-pager img { + vertical-align: middle; + margin-right: 2px; + cursor: pointer; +} + +/* pager output text */ +.tablesorter-pager .pagedisplay { + padding: 0 5px 0 5px; + width: auto; + white-space: nowrap; + text-align: center; +} + +/* pager element reset (needed for bootstrap) */ +.tablesorter-pager select { + margin: 0; + padding: 0; +} + +/*** css used when "updateArrows" option is true ***/ +/* the pager itself gets a disabled class when the number of rows is less than the size */ +.tablesorter-pager.disabled { + display: none; +} +/* hide or fade out pager arrows when the first or last row is visible */ +.tablesorter-pager .disabled { + /* visibility: hidden */ + opacity: 0.5; + filter: alpha(opacity=50); + cursor: default; +} \ No newline at end of file diff --git a/addons/pager/jquery.tablesorter.pager.js b/addons/pager/jquery.tablesorter.pager.js new file mode 100644 index 0000000..bdcc50b --- /dev/null +++ b/addons/pager/jquery.tablesorter.pager.js @@ -0,0 +1,1090 @@ +/*! + * tablesorter (FORK) pager plugin + * updated 5/17/2015 (v2.22.0) + */ +/*jshint browser:true, jquery:true, unused:false */ +;(function($) { + "use strict"; + /*jshint supernew:true */ + var ts = $.tablesorter; + + $.extend({ tablesorterPager: new function() { + + this.defaults = { + // target the pager markup + container: null, + + // use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}" + // where {page} is replaced by the page number, {size} is replaced by the number of records to show, + // {sortList:col} adds the sortList to the url into a "col" array, and {filterList:fcol} adds + // the filterList to the url into an "fcol" array. + // So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url + // and a filterList = [[2,Blue],[3,13]] becomes "&fcol[2]=Blue&fcol[3]=13" in the url + ajaxUrl: null, + + // modify the url after all processing has been applied + customAjaxUrl: function(table, url) { return url; }, + + // modify the $.ajax object to allow complete control over your ajax requests + ajaxObject: { + dataType: 'json' + }, + + // set this to false if you want to block ajax loading on init + processAjaxOnInit: true, + + // process ajax so that the following information is returned: + // [ total_rows (number), rows (array of arrays), headers (array; optional) ] + // example: + // [ + // 100, // total rows + // [ + // [ "row1cell1", "row1cell2", ... "row1cellN" ], + // [ "row2cell1", "row2cell2", ... "row2cellN" ], + // ... + // [ "rowNcell1", "rowNcell2", ... "rowNcellN" ] + // ], + // [ "header1", "header2", ... "headerN" ] // optional + // ] + ajaxProcessing: function(ajax){ return [ 0, [], null ]; }, + + // output default: '{page}/{totalPages}' + // possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + output: '{startRow} to {endRow} of {totalRows} rows', // '{page}/{totalPages}' + + // apply disabled classname to the pager arrows when the rows at either extreme is visible + updateArrows: true, + + // starting page of the pager (zero based index) + page: 0, + + // reset pager after filtering; set to desired page # + // set to false to not change page at filter start + pageReset: 0, + + // Number of visible rows + size: 10, + + // Number of options to include in the pager number selector + maxOptionSize: 20, + + // Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js) + savePages: true, + + // defines custom storage key + storageKey: 'tablesorter-pager', + + // if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty + // table row set to a height to compensate; default is false + fixedHeight: false, + + // count child rows towards the set page size? (set true if it is a visible table row within the pager) + // if true, child row(s) may not appear to be attached to its parent row, may be split across pages or + // may distort the table if rowspan or cellspans are included. + countChildRows: false, + + // remove rows from the table to speed up the sort of large tables. + // setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled. + removeRows: false, // removing rows in larger tables speeds up the sort + + // css class names of pager arrows + cssFirst: '.first', // go to first page arrow + cssPrev: '.prev', // previous page arrow + cssNext: '.next', // next page arrow + cssLast: '.last', // go to last page arrow + cssGoto: '.gotoPage', // go to page selector - select dropdown that sets the current page + cssPageDisplay: '.pagedisplay', // location of where the "output" is displayed + cssPageSize: '.pagesize', // page size selector - select dropdown that sets the "size" option + cssErrorRow: 'tablesorter-errorRow', // error information row + + // class added to arrows when at the extremes (i.e. prev/first arrows are "disabled" when on the first page) + cssDisabled: 'disabled', // Note there is no period "." in front of this class name + + // stuff not set by the user + totalRows: 0, + totalPages: 0, + filteredRows: 0, + filteredPages: 0, + ajaxCounter: 0, + currentFilters: [], + startRow: 0, + endRow: 0, + $size: null, + last: {} + + }; + + var pagerEvents = 'filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete ' + + 'pageSize pageSet pageAndSize pagerUpdate refreshComplete ', + + $this = this, + + // hide arrows at extremes + pagerArrows = function(p, disable) { + var a = 'addClass', + r = 'removeClass', + d = p.cssDisabled, + dis = !!disable, + first = ( dis || p.page === 0 ), + tp = Math.min( p.totalPages, p.filteredPages ), + last = ( dis || (p.page === tp - 1) || tp === 0 ); + if ( p.updateArrows ) { + p.$container.find(p.cssFirst + ',' + p.cssPrev)[ first ? a : r ](d).attr('aria-disabled', first); + p.$container.find(p.cssNext + ',' + p.cssLast)[ last ? a : r ](d).attr('aria-disabled', last); + } + }, + + calcFilters = function(table, p) { + var normalized, indx, len, + c = table.config, + hasFilters = c.$table.hasClass('hasFilters'); + if (hasFilters && !p.ajaxUrl) { + if ($.isEmptyObject(c.cache)) { + // delayInit: true so nothing is in the cache + p.filteredRows = p.totalRows = c.$tbodies.eq(0).children('tr').not( p.countChildRows ? '' : '.' + c.cssChildRow ).length; + } else { + p.filteredRows = 0; + normalized = c.cache[0].normalized; + len = normalized.length; + for (indx = 0; indx < len; indx++) { + p.filteredRows += p.regexRows.test(normalized[indx][c.columns].$row[0].className) ? 0 : 1; + } + } + } else if (!hasFilters) { + p.filteredRows = p.totalRows; + } + }, + + updatePageDisplay = function(table, p, completed) { + if ( p.initializing ) { return; } + var s, t, $out, indx, len, options, + c = table.config, + sz = p.size || p.settings.size || 10; // don't allow dividing by zero + if (p.countChildRows) { t.push(c.cssChildRow); } + p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method + c.totalRows = p.totalRows; + calcFilters(table, p); + c.filteredRows = p.filteredRows; + p.filteredPages = Math.ceil( p.filteredRows / sz ) || 0; + if ( Math.min( p.totalPages, p.filteredPages ) >= 0 ) { + t = (p.size * p.page > p.filteredRows) && completed; + p.page = (t) ? p.pageReset || 0 : p.page; + p.startRow = (t) ? p.size * p.page + 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1); + p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) ); + $out = p.$container.find(p.cssPageDisplay); + // form the output string (can now get a new output string from the server) + s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || p.output : p.output ) + // {page} = one-based index; {page+#} = zero based index +/- value + .replace(/\{page([\-+]\d+)?\}/gi, function(m,n){ + return p.totalPages ? p.page + (n ? parseInt(n, 10) : 1) : 0; + }) + // {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object) + .replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){ + var len, indx, + str = m.replace(/[{}\s]/g,''), + extra = str.split(':'), + data = p.ajaxData, + // return zero for default page/row numbers + deflt = /(rows?|pages?)$/i.test(str) ? 0 : ''; + if (/(startRow|page)/.test(extra[0]) && extra[1] === 'input') { + len = ('' + (extra[0] === 'page' ? p.totalPages : p.totalRows)).length; + indx = extra[0] === 'page' ? p.page + 1 : p.startRow; + return ''; + } + return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt; + }); + if ( p.$goto.length ) { + t = ''; + options = buildPageSelect(p); + len = options.length; + for (indx = 0; indx < len; indx++) { + t += ''; + } + // innerHTML doesn't work in IE9 - http://support2.microsoft.com/kb/276228 + p.$goto.html(t).val( p.page + 1 ); + } + if ($out.length) { + $out[ ($out[0].nodeName === 'INPUT') ? 'val' : 'html' ](s); + // rebind startRow/page inputs + $out.find('.ts-startRow, .ts-page').unbind('change.pager').bind('change.pager', function(){ + var v = $(this).val(), + pg = $(this).hasClass('ts-startRow') ? Math.floor( v/p.size ) + 1 : v; + c.$table.trigger('pageSet.pager', [ pg ]); + }); + } + } + pagerArrows(p); + fixHeight(table, p); + if (p.initialized && completed !== false) { + if (c.debug) { + ts.log('Pager: Triggering pagerComplete'); + } + c.$table.trigger('pagerComplete', p); + // save pager info to storage + if (p.savePages && ts.storage) { + ts.storage(table, p.storageKey, { + page : p.page, + size : p.size + }); + } + } + }, + + buildPageSelect = function(p) { + // Filter the options page number link array if it's larger than 'maxOptionSize' + // as large page set links will slow the browser on large dom inserts + var i, central_focus_size, focus_option_pages, insert_index, option_length, focus_length, + pg = Math.min( p.totalPages, p.filteredPages ) || 1, + // make skip set size multiples of 5 + skip_set_size = Math.ceil( ( pg / p.maxOptionSize ) / 5 ) * 5, + large_collection = pg > p.maxOptionSize, + current_page = p.page + 1, + start_page = skip_set_size, + end_page = pg - skip_set_size, + option_pages = [1], + // construct default options pages array + option_pages_start_page = (large_collection) ? skip_set_size : 1; + + for ( i = option_pages_start_page; i <= pg; ) { + option_pages.push(i); + i = i + ( large_collection ? skip_set_size : 1 ); + } + option_pages.push(pg); + if (large_collection) { + focus_option_pages = []; + // don't allow central focus size to be > 5 on either side of current page + central_focus_size = Math.max( Math.floor( p.maxOptionSize / skip_set_size ) - 1, 5 ); + + start_page = current_page - central_focus_size; + if (start_page < 1) { start_page = 1; } + end_page = current_page + central_focus_size; + if (end_page > pg) { end_page = pg; } + // construct an array to get a focus set around the current page + for (i = start_page; i <= end_page ; i++) { + focus_option_pages.push(i); + } + + // keep unique values + option_pages = $.grep(option_pages, function(value, indx) { + return $.inArray(value, option_pages) === indx; + }); + + option_length = option_pages.length; + focus_length = focus_option_pages.length; + + // make sure at all option_pages aren't replaced + if (option_length - focus_length > skip_set_size / 2 && option_length + focus_length > p.maxOptionSize ) { + insert_index = Math.floor(option_length / 2) - Math.floor(focus_length / 2); + Array.prototype.splice.apply(option_pages, [ insert_index, focus_length ]); + } + option_pages = option_pages.concat(focus_option_pages); + + } + + // keep unique values again + option_pages = $.grep(option_pages, function(value, indx) { + return $.inArray(value, option_pages) === indx; + }) + .sort(function(a,b) { return a - b; }); + + return option_pages; + }, + + fixHeight = function(table, p) { + var d, h, + c = table.config, + $b = c.$tbodies.eq(0); + $b.find('tr.pagerSavedHeightSpacer').remove(); + if (p.fixedHeight && !p.isDisabled) { + h = $.data(table, 'pagerSavedHeight'); + if (h) { + d = h - $b.height(); + if ( d > 5 && $.data(table, 'pagerLastSize') === p.size && $b.children('tr:visible').length < p.size ) { + $b.append(''); + } + } + } + }, + + changeHeight = function(table, p) { + var h, + c = table.config, + $b = c.$tbodies.eq(0); + $b.find('tr.pagerSavedHeightSpacer').remove(); + if (!$b.children('tr:visible').length) { + $b.append(' '); + } + h = $b.children('tr').eq(0).height() * p.size; + $.data(table, 'pagerSavedHeight', h); + fixHeight(table, p); + $.data(table, 'pagerLastSize', p.size); + }, + + hideRows = function(table, p){ + if (!p.ajaxUrl) { + var i, + lastIndex = 0, + c = table.config, + rows = c.$tbodies.eq(0).children('tr'), + l = rows.length, + s = ( p.page * p.size ), + e = s + p.size, + f = c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered', + last = 0, // for cache indexing + j = 0; // size counter + p.cacheIndex = []; + for ( i = 0; i < l; i++ ){ + if ( !rows[i].className.match(f) ) { + if (j === s && rows[i].className.match(c.cssChildRow)) { + // hide child rows @ start of pager (if already visible) + rows[i].style.display = 'none'; + } else { + rows[i].style.display = ( j >= s && j < e ) ? '' : 'none'; + if (last !== j && j >= s && j < e) { + p.cacheIndex.push(i); + last = j; + } + // don't count child rows + j += rows[i].className.match(c.cssChildRow + '|' + c.selectorRemove.slice(1)) && !p.countChildRows ? 0 : 1; + if ( j === e && rows[i].style.display !== 'none' && rows[i].className.match(ts.css.cssHasChild) ) { + lastIndex = i; + } + } + } + } + // add any attached child rows to last row of pager. Fixes part of issue #396 + if ( lastIndex > 0 && rows[lastIndex].className.match(ts.css.cssHasChild) ) { + while ( ++lastIndex < l && rows[lastIndex].className.match(c.cssChildRow) ) { + rows[lastIndex].style.display = ''; + } + } + } + }, + + hideRowsSetup = function(table, p){ + p.size = parseInt( p.$size.val(), 10 ) || p.size || p.settings.size || 10; + $.data(table, 'pagerLastSize', p.size); + pagerArrows(p); + if ( !p.removeRows ) { + hideRows(table, p); + $(table).bind('sortEnd.pager filterEnd.pager', function(){ + hideRows(table, p); + }); + } + }, + + renderAjax = function(data, table, p, xhr, exception){ + // process data + if ( typeof(p.ajaxProcessing) === "function" ) { + // ajaxProcessing result: [ total, rows, headers ] + var i, j, t, hsh, $f, $sh, $headers, $h, icon, th, d, l, rr_count, len, + c = table.config, + $table = c.$table, + tds = '', + result = p.ajaxProcessing(data, table, xhr) || [ 0, [] ], + hl = $table.find('thead th').length; + + // Clean up any previous error. + ts.showError(table); + + if ( exception ) { + if (c.debug) { + ts.log('Pager: >> Ajax Error', xhr, exception); + } + ts.showError(table, + xhr.status === 0 ? 'Not connected, verify Network' : + xhr.status === 404 ? 'Requested page not found [404]' : + xhr.status === 500 ? 'Internal Server Error [500]' : + exception === 'parsererror' ? 'Requested JSON parse failed' : + exception === 'timeout' ? 'Time out error' : + exception === 'abort' ? 'Ajax Request aborted' : + 'Uncaught error: ' + xhr.statusText + ' [' + xhr.status + ']' ); + c.$tbodies.eq(0).children('tr').detach(); + p.totalRows = 0; + } else { + // process ajax object + if (!$.isArray(result)) { + p.ajaxData = result; + c.totalRows = p.totalRows = result.total; + c.filteredRows = p.filteredRows = typeof result.filteredRows !== 'undefined' ? result.filteredRows : result.total; + th = result.headers; + d = result.rows; + } else { + // allow [ total, rows, headers ] or [ rows, total, headers ] + t = isNaN(result[0]) && !isNaN(result[1]); + // ensure a zero returned row count doesn't fail the logical || + rr_count = result[t ? 1 : 0]; + p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count; + // can't set filtered rows when returning an array + c.totalRows = c.filteredRows = p.filteredRows = p.totalRows; + d = p.totalRows === 0 ? [""] : result[t ? 0 : 1] || []; // row data + th = result[2]; // headers + } + l = d && d.length; + if (d instanceof jQuery) { + if (p.processAjaxOnInit) { + // append jQuery object + c.$tbodies.eq(0).children('tr').detach(); + c.$tbodies.eq(0).append(d); + } + } else if (l) { + // build table from array + for ( i = 0; i < l; i++ ) { + tds += ''; + for ( j = 0; j < d[i].length; j++ ) { + // build tbody cells; watch for data containing HTML markup - see #434 + tds += /^\s*' + d[i][j] + ''; + } + tds += ''; + } + // add rows to first tbody + if (p.processAjaxOnInit) { + c.$tbodies.eq(0).html( tds ); + } + } + p.processAjaxOnInit = true; + // only add new header text if the length matches + if ( th && th.length === hl ) { + hsh = $table.hasClass('hasStickyHeaders'); + $sh = hsh ? c.widgetOptions.$sticky.children('thead:first').children('tr').children() : ''; + $f = $table.find('tfoot tr:first').children(); + // don't change td headers (may contain pager) + $headers = c.$headers.filter( 'th ' ); + len = $headers.length; + for ( j = 0; j < len; j++ ) { + $h = $headers.eq( j ); + // add new test within the first span it finds, or just in the header + if ( $h.find('.' + ts.css.icon).length ) { + icon = $h.find('.' + ts.css.icon).clone(true); + $h.find('.tablesorter-header-inner').html( th[j] ).append(icon); + if ( hsh && $sh.length ) { + icon = $sh.eq(j).find('.' + ts.css.icon).clone(true); + $sh.eq(j).find('.tablesorter-header-inner').html( th[j] ).append(icon); + } + } else { + $h.find('.tablesorter-header-inner').html( th[j] ); + if (hsh && $sh.length) { + $sh.eq(j).find('.tablesorter-header-inner').html( th[j] ); + } + } + $f.eq(j).html( th[j] ); + } + } + } + if (c.showProcessing) { + ts.isProcessing(table); // remove loading icon + } + // make sure last pager settings are saved, prevents multiple server side calls with + // the same parameters + p.totalPages = Math.ceil( p.totalRows / ( p.size || p.settings.size || 10 ) ); + p.last.totalRows = p.totalRows; + p.last.currentFilters = p.currentFilters; + p.last.sortList = (c.sortList || []).join(','); + updatePageDisplay(table, p, false); + $table.trigger('updateCache', [function(){ + if (p.initialized) { + // apply widgets after table has rendered & after a delay to prevent + // multiple applyWidget blocking code from blocking this trigger + setTimeout(function(){ + if (c.debug) { + ts.log('Pager: Triggering pagerChange'); + } + $table + .trigger('applyWidgets') + .trigger('pagerChange', p); + updatePageDisplay(table, p, true); + }, 0); + } + }]); + + } + if (!p.initialized) { + p.initialized = true; + p.initializing = false; + if (table.config.debug) { + ts.log('Pager: Triggering pagerInitialized'); + } + $(table) + .trigger('applyWidgets') + .trigger('pagerInitialized', p); + updatePageDisplay(table, p); + } + }, + + getAjax = function(table, p){ + var url = getAjaxUrl(table, p), + $doc = $(document), + counter, + c = table.config; + if ( url !== '' ) { + if (c.showProcessing) { + ts.isProcessing(table, true); // show loading icon + } + $doc.bind('ajaxError.pager', function(e, xhr, settings, exception) { + renderAjax(null, table, p, xhr, exception); + $doc.unbind('ajaxError.pager'); + }); + + counter = ++p.ajaxCounter; + + p.last.ajaxUrl = url; // remember processed url + p.ajaxObject.url = url; // from the ajaxUrl option and modified by customAjaxUrl + p.ajaxObject.success = function(data, status, jqxhr) { + // Refuse to process old ajax commands that were overwritten by new ones - see #443 + if (counter < p.ajaxCounter){ + return; + } + renderAjax(data, table, p, jqxhr); + $doc.unbind('ajaxError.pager'); + if (typeof p.oldAjaxSuccess === 'function') { + p.oldAjaxSuccess(data); + } + }; + if (c.debug) { + ts.log('Pager: Ajax initialized', p.ajaxObject); + } + $.ajax(p.ajaxObject); + } + }, + + getAjaxUrl = function(table, p) { + var indx, len, + c = table.config, + url = (p.ajaxUrl) ? p.ajaxUrl + // allow using "{page+1}" in the url string to switch to a non-zero based index + .replace(/\{page([\-+]\d+)?\}/, function(s,n){ return p.page + (n ? parseInt(n, 10) : 0); }) + .replace(/\{size\}/g, p.size) : '', + sortList = c.sortList, + filterList = p.currentFilters || $(table).data('lastSearch') || [], + sortCol = url.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/), + filterCol = url.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/), + arry = []; + if (sortCol) { + sortCol = sortCol[1]; + len = sortList.length; + for (indx = 0; indx < len; indx++) { + arry.push(sortCol + '[' + sortList[indx][0] + ']=' + sortList[indx][1]); + } + // if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col" + url = url.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : sortCol ); + arry = []; + } + if (filterCol) { + filterCol = filterCol[1]; + len = filterList.length; + for (indx = 0; indx < len; indx++) { + if (filterList[indx]) { + arry.push(filterCol + '[' + indx + ']=' + encodeURIComponent(filterList[indx])); + } + } + // if the arry is empty, just add the fcol parameter... "&{filterList:fcol}" becomes "&fcol" + url = url.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : filterCol ); + p.currentFilters = filterList; + } + if ( typeof(p.customAjaxUrl) === "function" ) { + url = p.customAjaxUrl(table, url); + } + if (c.debug) { + ts.log('Pager: Ajax url = ' + url); + } + return url; + }, + + renderTable = function(table, rows, p) { + var $tb, index, count, added, + $t = $(table), + c = table.config, + f = c.$table.hasClass('hasFilters'), + l = rows && rows.length || 0, // rows may be undefined + s = ( p.page * p.size ), + e = p.size; + if ( l < 1 ) { + if (c.debug) { + ts.log('Pager: >> No rows for pager to render'); + } + // empty table, abort! + return; + } + if ( p.page >= p.totalPages ) { + // lets not render the table more than once + moveToLastPage(table, p); + } + p.cacheIndex = []; + p.isDisabled = false; // needed because sorting will change the page and re-enable the pager + if (p.initialized) { + if (c.debug) { + ts.log('Pager: Triggering pagerChange'); + } + $t.trigger('pagerChange', p); + } + + if ( !p.removeRows ) { + hideRows(table, p); + } else { + ts.clearTableBody(table); + $tb = ts.processTbody(table, c.$tbodies.eq(0), true); + // not filtered, start from the calculated starting point (s) + // if filtered, start from zero + index = f ? 0 : s; + count = f ? 0 : s; + added = 0; + while (added < e && index < rows.length) { + if (!f || !/filtered/.test(rows[index][0].className)){ + count++; + if (count > s && added <= e) { + added++; + p.cacheIndex.push(index); + $tb.append(rows[index]); + } + } + index++; + } + ts.processTbody(table, $tb, false); + } + updatePageDisplay(table, p); + if (table.isUpdating) { + if (c.debug) { + ts.log('Pager: Triggering updateComplete'); + } + $t.trigger('updateComplete', [ table, true ]); + } + }, + + showAllRows = function(table, p){ + var index, $controls, len; + if ( p.ajax ) { + pagerArrows(p, true); + } else { + p.isDisabled = true; + $.data(table, 'pagerLastPage', p.page); + $.data(table, 'pagerLastSize', p.size); + p.page = 0; + p.size = p.totalRows; + p.totalPages = 1; + $(table) + .addClass('pagerDisabled') + .removeAttr('aria-describedby') + .find('tr.pagerSavedHeightSpacer').remove(); + renderTable(table, table.config.rowsCopy, p); + $(table).trigger('applyWidgets'); + if (table.config.debug) { + ts.log('Pager: Disabled'); + } + } + // disable size selector + $controls = p.$size + .add( p.$goto ) + .add( p.$container.find( '.ts-startRow, .ts-page' ) ); + len = $controls.length; + for ( index = 0; index < len; index++ ) { + $controls.eq( index ) + .attr( 'aria-disabled', 'true' ) + .addClass( p.cssDisabled )[0].disabled = true; + } + }, + + // updateCache if delayInit: true + updateCache = function(table) { + var c = table.config, + p = c.pager; + c.$table.trigger('updateCache', [ function(){ + var i, + rows = [], + n = table.config.cache[0].normalized; + p.totalRows = n.length; + for (i = 0; i < p.totalRows; i++) { + rows.push(n[i][c.columns].$row); + } + c.rowsCopy = rows; + moveToPage(table, p, true); + } ]); + }, + + moveToPage = function(table, p, pageMoved) { + if ( p.isDisabled ) { return; } + var pg, c = table.config, + $t = $(table), + l = p.last; + if ( pageMoved !== false && p.initialized && $.isEmptyObject(c.cache)) { + return updateCache(table); + } + // abort page move if the table has filters and has not been initialized + if (p.ajax && ts.hasWidget(table, 'filter') && !c.widgetOptions.filter_initialized) { return; } + calcFilters(table, p); + pg = Math.min( p.totalPages, p.filteredPages ); + if ( p.page < 0 ) { p.page = 0; } + if ( p.page > ( pg - 1 ) && pg !== 0 ) { p.page = pg - 1; } + // fixes issue where one currentFilter is [] and the other is ['','',''], + // making the next if comparison think the filters are different (joined by commas). Fixes #202. + l.currentFilters = (l.currentFilters || []).join('') === '' ? [] : l.currentFilters; + p.currentFilters = (p.currentFilters || []).join('') === '' ? [] : p.currentFilters; + // don't allow rendering multiple times on the same page/size/totalRows/filters/sorts + if ( l.page === p.page && l.size === p.size && l.totalRows === p.totalRows && + (l.currentFilters || []).join(',') === (p.currentFilters || []).join(',') && + // check for ajax url changes see #730 + (l.ajaxUrl || '') === (p.ajaxObject.url || '') && + // & ajax url option changes (dynamically add/remove/rename sort & filter parameters) + (l.optAjaxUrl || '') === (p.ajaxUrl || '') && + l.sortList === (c.sortList || []).join(',') ) { return; } + if (c.debug) { + ts.log('Pager: Changing to page ' + p.page); + } + p.last = { + page : p.page, + size : p.size, + // fixes #408; modify sortList otherwise it auto-updates + sortList : (c.sortList || []).join(','), + totalRows : p.totalRows, + currentFilters : p.currentFilters || [], + ajaxUrl : p.ajaxObject.url || '', + optAjaxUrl : p.ajaxUrl || '' + }; + if (p.ajax) { + getAjax(table, p); + } else if (!p.ajax) { + renderTable(table, c.rowsCopy, p); + } + $.data(table, 'pagerLastPage', p.page); + if (p.initialized && pageMoved !== false) { + if (c.debug) { + ts.log('Pager: Triggering pageMoved'); + } + $t + .trigger('pageMoved', p) + .trigger('applyWidgets'); + if (table.isUpdating) { + if (c.debug) { + ts.log('Pager: Triggering updateComplete'); + } + $t.trigger('updateComplete', [ table, true ]); + } + } + }, + + setPageSize = function(table, size, p) { + p.size = size || p.size || p.settings.size || 10; + p.$size.val(p.size); + $.data(table, 'pagerLastPage', p.page); + $.data(table, 'pagerLastSize', p.size); + p.totalPages = Math.ceil( p.totalRows / p.size ); + p.filteredPages = Math.ceil( p.filteredRows / p.size ); + moveToPage(table, p); + }, + + moveToFirstPage = function(table, p) { + p.page = 0; + moveToPage(table, p); + }, + + moveToLastPage = function(table, p) { + p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 ); + moveToPage(table, p); + }, + + moveToNextPage = function(table, p) { + p.page++; + if ( p.page >= ( Math.min( p.totalPages, p.filteredPages ) - 1 ) ) { + p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 ); + } + moveToPage(table, p); + }, + + moveToPrevPage = function(table, p) { + p.page--; + if ( p.page <= 0 ) { + p.page = 0; + } + moveToPage(table, p); + }, + + destroyPager = function(table, p){ + showAllRows(table, p); + p.$container.hide(); // hide pager + table.config.appender = null; // remove pager appender function + p.initialized = false; + delete table.config.rowsCopy; + $(table).unbind( pagerEvents.split(' ').join('.pager ').replace(/\s+/g, ' ') ); + if (ts.storage) { + ts.storage(table, p.storageKey, ''); + } + }, + + enablePager = function(table, p, triggered){ + var info, + c = table.config; + p.$size.add(p.$goto).add(p.$container.find('.ts-startRow, .ts-page')) + .removeClass(p.cssDisabled) + .removeAttr('disabled') + .attr('aria-disabled', 'false'); + p.isDisabled = false; + p.page = $.data(table, 'pagerLastPage') || p.page || 0; + p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || p.settings.size || 10; + p.$size.val(p.size); // set page size + p.totalPages = Math.ceil( Math.min( p.totalRows, p.filteredRows ) / p.size ); + // if table id exists, include page display with aria info + if ( table.id ) { + info = table.id + '_pager_info'; + p.$container.find(p.cssPageDisplay).attr('id', info); + c.$table.attr('aria-describedby', info); + } + changeHeight(table, p); + if ( triggered ) { + c.$table.trigger('updateRows'); + setPageSize(table, p.size, p); + hideRowsSetup(table, p); + if (c.debug) { + ts.log('Pager: Enabled'); + } + } + }; + + $this.appender = function(table, rows) { + var c = table.config, + p = c.pager; + if ( !p.ajax ) { + c.rowsCopy = rows; + p.totalRows = p.countChildRows ? c.$tbodies.eq(0).children('tr').length : rows.length; + p.size = $.data(table, 'pagerLastSize') || p.size || p.settings.size || 10; + p.totalPages = Math.ceil( p.totalRows / p.size ); + renderTable(table, rows, p); + // update display here in case all rows are removed + updatePageDisplay(table, p, false); + } + }; + + $this.construct = function(settings) { + return this.each(function() { + // check if tablesorter has initialized + if (!(this.config && this.hasInitialized)) { return; } + var t, ctrls, fxn, + table = this, + c = table.config, + wo = c.widgetOptions, + p = c.pager = $.extend( true, {}, $.tablesorterPager.defaults, settings ), + $t = c.$table, + // added in case the pager is reinitialized after being destroyed. + pager = p.$container = $(p.container).addClass('tablesorter-pager').show(); + // save a copy of the original settings + p.settings = $.extend( true, {}, $.tablesorterPager.defaults, settings ); + if (c.debug) { + ts.log('Pager: Initializing'); + } + p.oldAjaxSuccess = p.oldAjaxSuccess || p.ajaxObject.success; + c.appender = $this.appender; + p.initializing = true; + if (p.savePages && ts.storage) { + t = ts.storage(table, p.storageKey) || {}; // fixes #387 + p.page = isNaN(t.page) ? p.page : t.page; + p.size = ( isNaN(t.size) ? p.size : t.size ) || p.settings.size || 10; + $.data(table, 'pagerLastSize', p.size); + } + + // skipped rows + p.regexRows = new RegExp('(' + (wo.filter_filteredRow || 'filtered') + '|' + c.selectorRemove.slice(1) + '|' + c.cssChildRow + ')'); + + $t + .unbind( pagerEvents.split(' ').join('.pager ').replace(/\s+/g, ' ') ) + .bind('filterInit.pager filterStart.pager', function(e, filters) { + p.currentFilters = $.isArray(filters) ? filters : c.$table.data('lastSearch'); + // don't change page if filters are the same (pager updating, etc) + if (e.type === 'filterStart' && p.pageReset !== false && (c.lastCombinedFilter || '') !== (p.currentFilters || []).join('')) { + p.page = p.pageReset; // fixes #456 & #565 + } + }) + // update pager after filter widget completes + .bind('filterEnd.pager sortEnd.pager', function() { + p.currentFilters = c.$table.data('lastSearch'); + if (p.initialized || p.initializing) { + if (c.delayInit && c.rowsCopy && c.rowsCopy.length === 0) { + // make sure we have a copy of all table rows once the cache has been built + updateCache(table); + } + updatePageDisplay(table, p, false); + moveToPage(table, p, false); + c.$table.trigger('applyWidgets'); + } + }) + .bind('disable.pager', function(e){ + e.stopPropagation(); + showAllRows(table, p); + }) + .bind('enable.pager', function(e){ + e.stopPropagation(); + enablePager(table, p, true); + }) + .bind('destroy.pager', function(e){ + e.stopPropagation(); + destroyPager(table, p); + }) + .bind('updateComplete.pager', function(e, table, triggered){ + e.stopPropagation(); + // table can be unintentionally undefined in tablesorter v2.17.7 and earlier + // don't recalculate total rows/pages if using ajax + if ( !table || triggered || p.ajax ) { return; } + var $rows = c.$tbodies.eq(0).children('tr').not(c.selectorRemove); + p.totalRows = $rows.length - ( p.countChildRows ? 0 : $rows.filter('.' + c.cssChildRow).length ); + p.totalPages = Math.ceil( p.totalRows / p.size ); + if ($rows.length && c.rowsCopy && c.rowsCopy.length === 0) { + // make a copy of all table rows once the cache has been built + updateCache(table); + } + if ( p.page >= p.totalPages ) { + moveToLastPage(table, p); + } + hideRows(table, p); + changeHeight(table, p); + updatePageDisplay(table, p, true); + }) + .bind('pageSize.pager refreshComplete.pager', function(e,v){ + e.stopPropagation(); + setPageSize(table, parseInt(v, 10) || p.settings.size || 10, p); + hideRows(table, p); + updatePageDisplay(table, p, false); + }) + .bind('pageSet.pager pagerUpdate.pager', function(e,v){ + e.stopPropagation(); + // force pager refresh + if (e.type === 'pagerUpdate') { + v = typeof v === 'undefined' ? p.page + 1 : v; + p.last.page = true; + } + p.page = (parseInt(v, 10) || 1) - 1; + moveToPage(table, p, true); + updatePageDisplay(table, p, false); + }) + .bind('pageAndSize.pager', function(e, page, size){ + e.stopPropagation(); + p.page = (parseInt(page, 10) || 1) - 1; + setPageSize(table, parseInt(size, 10) || p.settings.size || 10, p); + moveToPage(table, p, true); + hideRows(table, p); + updatePageDisplay(table, p, false); + }); + + // clicked controls + ctrls = [ p.cssFirst, p.cssPrev, p.cssNext, p.cssLast ]; + fxn = [ moveToFirstPage, moveToPrevPage, moveToNextPage, moveToLastPage ]; + if (c.debug && !pager.length) { + ts.log('Pager: >> Container not found'); + } + pager.find(ctrls.join(',')) + .attr("tabindex", 0) + .unbind('click.pager') + .bind('click.pager', function(e){ + e.stopPropagation(); + var i, $t = $(this), l = ctrls.length; + if ( !$t.hasClass(p.cssDisabled) ) { + for (i = 0; i < l; i++) { + if ($t.is(ctrls[i])) { + fxn[i](table, p); + break; + } + } + } + }); + + // goto selector + p.$goto = pager.find(p.cssGoto); + if ( p.$goto.length ) { + p.$goto + .unbind('change.pager') + .bind('change.pager', function(){ + p.page = $(this).val() - 1; + moveToPage(table, p, true); + updatePageDisplay(table, p, false); + }); + } else if (c.debug) { + ts.log('Pager: >> Goto selector not found'); + } + // page size selector + p.$size = pager.find(p.cssPageSize); + if ( p.$size.length ) { + // setting an option as selected appears to cause issues with initial page size + p.$size.find('option').removeAttr('selected'); + p.$size.unbind('change.pager').bind('change.pager', function() { + p.$size.val( $(this).val() ); // in case there are more than one pagers + if ( !$(this).hasClass(p.cssDisabled) ) { + setPageSize(table, parseInt( $(this).val(), 10 ), p); + changeHeight(table, p); + } + return false; + }); + } else if (c.debug) { + ts.log('Pager: >> Size selector not found'); + } + + // clear initialized flag + p.initialized = false; + // before initialization event + $t.trigger('pagerBeforeInitialized', p); + + enablePager(table, p, false); + if ( typeof(p.ajaxUrl) === 'string' ) { + // ajax pager; interact with database + p.ajax = true; + //When filtering with ajax, allow only custom filtering function, disable default filtering since it will be done server side. + c.widgetOptions.filter_serversideFiltering = true; + c.serverSideSorting = true; + moveToPage(table, p); + } else { + p.ajax = false; + // Regular pager; all rows stored in memory + $(this).trigger("appendCache", true); + hideRowsSetup(table, p); + } + + // pager initialized + if (!p.ajax && !p.initialized) { + p.initializing = false; + p.initialized = true; + moveToPage(table, p); + if (c.debug) { + ts.log('Pager: Triggering pagerInitialized'); + } + c.$table.trigger('pagerInitialized', p); + if ( !( c.widgetOptions.filter_initialized && ts.hasWidget(table, 'filter') ) ) { + updatePageDisplay(table, p, false); + } + } + + // make the hasWidget function think that the pager widget is being used + c.widgetInit.pager = true; + }); + }; + + }() }); + + // see #486 + ts.showError = function(table, message) { + var index, $row, c, errorRow, + $table = $( table ), + len = $table.length; + for ( index = 0; index < len; index++ ) { + c = $table[ index ].config; + if ( c ) { + errorRow = c.pager && c.pager.cssErrorRow || c.widgetOptions.pager_css && c.widgetOptions.pager_css.errorRow || 'tablesorter-errorRow'; + if ( typeof message === 'undefined' ) { + c.$table.find('thead').find(c.selectorRemove).remove(); + } else { + $row = ( /tr\>/.test(message) ? $(message) : $('' + message + '') ) + .click(function(){ + $(this).remove(); + }) + // add error row to thead instead of tbody, or clicking on the header will result in a parser error + .appendTo( c.$table.find('thead:first') ) + .addClass( errorRow + ' ' + c.selectorRemove.slice(1) ) + .attr({ + role : 'alert', + 'aria-live' : 'assertive' + }); + } + } + } + }; + +// extend plugin scope +$.fn.extend({ + tablesorterPager: $.tablesorterPager.construct +}); + +})(jQuery); diff --git a/beta-testing/example-pager-custom-controls.html b/beta-testing/example-pager-custom-controls.html new file mode 100644 index 0000000..c044b3f --- /dev/null +++ b/beta-testing/example-pager-custom-controls.html @@ -0,0 +1,1200 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Pager plugin, Custom Pagination + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

+ NOTE! +

    +
  • Modified in v2.17.1 to properly work with either the pager addon or pager widget.
  • +
  • In v2.16.4, code was updated to correctly count process pages.
  • +
+

+ +

Demo

+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameMajorSexEnglishJapaneseCalculusGeometry
NameMajorSexEnglishJapaneseCalculusGeometry
+
+ # per page: + 10 | + 25 | + 50 | + 100 + + + + Prev  + + +  Next + + + +
+
Student01Languagesmale80707580
Student02Mathematicsmale908810090
Student03Languagesfemale85958085
Student04Languagesmale6055100100
Student05Languagesfemale68809580
Student06Mathematicsmale1009910090
Student07Mathematicsmale85689090
Student08Languagesmale100909085
Student09Mathematicsmale80506575
Student10Languagesmale8510010090
Student11Languagesmale8685100100
Student12Mathematicsfemale100757085
Student13Languagesfemale1008010090
Student14Languagesfemale50455590
Student15Languagesmale953510090
Student16Languagesfemale100503070
Student17Languagesfemale801005565
Student18Mathematicsmale30495575
Student19Languagesmale68908870
Student20Mathematicsmale40454080
Student21Languagesmale5045100100
Student22Mathematicsmale1009910090
Student23Languagesfemale85808080
student24Languagesfemale100911382
student25Mathematicsmale22968253
student26Languagesfemale37295659
student27Mathematicsmale86826923
student28Languagesfemale4425431
student29Mathematicsmale77472238
student30Languagesfemale19352310
student31Mathematicsmale90271750
student32Languagesfemale60753338
student33Mathematicsmale4313715
student34Languagesfemale77978144
student35Mathematicsmale5815195
student36Languagesfemale70617094
student37Mathematicsmale6036184
student38Languagesfemale6339011
student39Mathematicsmale50463238
student40Languagesfemale5175253
student41Mathematicsmale43342878
student42Languagesfemale11896095
student43Mathematicsmale48921888
student44Languagesfemale8225973
student45Mathematicsmale91733739
student46Languagesfemale481210
student47Mathematicsmale8910611
student48Languagesfemale90322118
student49Mathematicsmale42494972
student50Languagesfemale56376754
student51Mathematicsmale48315563
student52Languagesfemale38917174
student53Mathematicsmale26385100
student54Languagesfemale75811623
student55Mathematicsmale65521553
student56Languagesfemale23527994
student57Mathematicsmale80226112
student58Languagesfemale5357979
student59Mathematicsmale96323517
student60Languagesfemale16766527
student61Mathematicsmale20572223
student62Languagesfemale19838778
student63Mathematicsmale258330
student64Languagesfemale021993
student65Mathematicsmale20861396
student66Languagesfemale28358757
student67Mathematicsmale36502910
student68Languagesfemale6090966
student69Mathematicsmale34614398
student70Languagesfemale13379183
student71Mathematicsmale47805782
student72Languagesfemale69433737
student73Mathematicsmale54609421
student74Languagesfemale71143446
student75Mathematicsmale89963117
student76Languagesfemale28482994
student77Mathematicsmale100652024
student78Languagesfemale11969033
student79Mathematicsmale53559339
student80Languagesfemale11008444
student81Mathematicsmale63789643
student82Languagesfemale41698235
student83Mathematicsmale9498139
student84Languagesfemale94729177
student85Mathematicsmale71324525
student86Languagesfemale9896437
student87Mathematicsmale8917367
student88Languagesfemale43416879
student89Mathematicsmale7382237
student90Languagesfemale94839337
student91Mathematicsmale8284261
student92Languagesfemale46413069
student93Mathematicsmale47198583
student94Languagesfemale39146462
student95Mathematicsmale71314628
student96Languagesfemale90944540
student97Mathematicsmale468925
student98Languagesfemale41434799
student99Mathematicsmale71908973
student100Languagesfemale31641856
student101Mathematicsmale52136999
student102Languagesfemale86398318
student103Mathematicsmale23659880
student104Languagesfemale781005766
student105Mathematicsmale69214397
student106Languagesfemale2727838
student107Mathematicsmale86964634
student108Languagesfemale13846664
student109Mathematicsmale35959881
student110Languagesfemale30286254
student111Mathematicsmale60313585
student112Languagesfemale19811969
student113Mathematicsmale6659854
student114Languagesfemale38804016
student115Mathematicsmale5849697
student116Languagesfemale59976954
student117Mathematicsmale0347949
student118Languagesfemale1871285
student119Mathematicsmale9387759
student120Languagesfemale42232690
student121Mathematicsmale17396689
student122Languagesfemale26759018
student123Mathematicsmale34237780
student124Languagesfemale5267742
student125Mathematicsmale5628581
student126Languagesfemale51356744
student127Mathematicsmale64644434
student128Languagesfemale67917982
student129Mathematicsmale4261579
student130Languagesfemale7210369
student131Mathematicsmale9477511
student132Languagesfemale27958548
student133Mathematicsmale92114061
student134Languagesfemale4185660
student135Mathematicsmale8422652
student136Languagesfemale7604721
student137Mathematicsmale51813090
student138Languagesfemale5861673
student139Mathematicsmale48383731
student140Languagesfemale33265660
student141Mathematicsmale84842975
student142Languagesfemale7235654
student143Mathematicsmale31427082
student144Languagesfemale94875035
student145Mathematicsmale91528026
student146Languagesfemale78657979
student147Mathematicsmale50905971
student148Languagesfemale15686633
student149Mathematicsmale17363413
student150Languagesfemale30956973
student151Mathematicsmale20534958
student152Languagesfemale19896060
student153Mathematicsmale5282203
student154Languagesfemale66985366
student155Mathematicsmale5852258
student156Languagesfemale3443688
student157Mathematicsmale4309114
student158Languagesfemale34186731
student159Mathematicsmale79733452
student160Languagesfemale15613727
student161Mathematicsmale74771545
student162Languagesfemale52621958
student163Mathematicsmale77602795
student164Languagesfemale9619357
student165Mathematicsmale51637519
student166Languagesfemale32447299
student167Mathematicsmale82845763
student168Languagesfemale53128567
student169Mathematicsmale4916846
student170Languagesfemale39341665
student171Mathematicsmale10068884
student172Languagesfemale14256352
student173Mathematicsmale74261560
student174Languagesfemale1158892
student175Mathematicsmale6247231
student176Languagesfemale65263242
student177Mathematicsmale83786924
student178Languagesfemale14100743
student179Mathematicsmale2835897
student180Languagesfemale1483962
student181Mathematicsmale1442469
student182Languagesfemale6452722
student183Mathematicsmale15262785
student184Languagesfemale9149407
student185Mathematicsmale87894287
student186Languagesfemale75766188
student187Mathematicsmale11486630
student188Languagesfemale7379272
student189Mathematicsmale98365815
student190Languagesfemale8028656
student191Mathematicsmale3633974
student192Languagesfemale5923390
student193Mathematicsmale9461933
student194Languagesfemale82497242
student195Mathematicsmale8059830
student196Languagesfemale89179027
student197Mathematicsmale4622667
student198Languagesfemale65757377
student199Mathematicsmale77975413
student200Languagesfemale78195796
student201Mathematicsmale92211180
student202Languagesfemale45499340
student203Mathematicsmale74258753
student204Languagesfemale1571234
student205Mathematicsmale82979573
student206Languagesfemale82605898
student207Mathematicsmale266411100
student208Languagesfemale6496045
student209Mathematicsmale96819663
student210Languagesfemale2439069
student211Mathematicsmale8664710
student212Languagesfemale764507
student213Mathematicsmale59122677
student214Languagesfemale21259382
student215Mathematicsmale22186451
student216Languagesfemale92419828
student217Mathematicsmale32481417
student218Languagesfemale62368556
student219Mathematicsmale33379087
student220Languagesfemale24436084
student221Mathematicsmale6593751
student222Languagesfemale9197576
student223Mathematicsmale86293227
student224Languagesfemale63596891
student225Mathematicsmale57739568
student226Languagesfemale38545987
student227Mathematicsmale53627264
student228Languagesfemale62847273
student229Mathematicsmale1308358
student230Languagesfemale35658087
student231Mathematicsmale76202850
student232Languagesfemale9176633
student233Mathematicsmale9229961
student234Languagesfemale47699839
student235Mathematicsmale21443882
student236Languagesfemale19865178
student237Mathematicsmale28454936
student238Languagesfemale78194981
student239Mathematicsmale72694720
student240Languagesfemale17436656
student241Mathematicsmale901944
student242Languagesfemale618251
student243Mathematicsmale1377213
student244Languagesfemale8005854
student245Mathematicsmale8331859
student246Languagesfemale90992912
student247Mathematicsmale89238159
student248Languagesfemale7226283
student249Mathematicsmale28105047
student250Languagesfemale8914894
student251Mathematicsmale15233769
student252Languagesfemale27821036
student253Mathematicsmale49456423
student254Languagesfemale79756374
student255Mathematicsmale2566475
student256Languagesfemale36262958
student257Mathematicsmale17226673
student258Languagesfemale70919745
student259Mathematicsmale34307830
student260Languagesfemale77578677
student261Mathematicsmale1259687
student262Languagesfemale11609771
student263Mathematicsmale12303558
student264Languagesfemale46152340
student265Mathematicsmale4481926
student266Languagesfemale15683215
student267Mathematicsmale5585098
student268Languagesfemale42303224
student269Mathematicsmale781009957
student270Languagesfemale55338725
student271Mathematicsmale25972993
student272Languagesfemale39351843
student273Mathematicsmale35179958
student274Languagesfemale86522724
student275Mathematicsmale97387376
student276Languagesfemale206198
student277Mathematicsmale9336947
student278Languagesfemale423152
student279Mathematicsmale6118962
student280Languagesfemale99898794
student281Mathematicsmale4895900
student282Languagesfemale60473130
student283Mathematicsmale64241076
student284Languagesfemale9937468
student285Mathematicsmale0986869
student286Languagesfemale66824959
student287Mathematicsmale86143717
student288Languagesfemale27489327
student289Mathematicsmale8489668
student290Languagesfemale9902057
student291Mathematicsmale50967242
student292Languagesfemale9822792
student293Mathematicsmale1994287
student294Languagesfemale9897922
student295Mathematicsmale75307764
student296Languagesfemale5198553
student297Mathematicsmale25958672
student298Languagesfemale20753735
student299Mathematicsmale4924111
student300Languagesfemale2832891
student301Mathematicsmale4163425
student302Languagesfemale29167790
student303Mathematicsmale89415182
student304Languagesfemale40912434
student305Mathematicsmale7474978
student306Languagesfemale6375562
student307Mathematicsmale30733490
student308Languagesfemale82919593
student309Mathematicsmale6247382
student310Languagesfemale39101257
student311Mathematicsmale89642067
student312Languagesfemale56369241
student313Mathematicsmale99809974
student314Languagesfemale31796493
student315Mathematicsmale5327055
student316Languagesfemale35152960
student317Mathematicsmale31476960
student318Languagesfemale88281366
student319Mathematicsmale65121640
student320Languagesfemale28171940
student321Mathematicsmale241004470
student322Languagesfemale20598352
student323Mathematicsmale17608291
student324Languagesfemale95994337
student325Mathematicsmale30189931
student326Languagesfemale3478386
student327Mathematicsmale9863435
student328Languagesfemale54239846
student329Mathematicsmale97934518
student330Languagesfemale2774077
student331Mathematicsmale9704137
student332Languagesfemale52377620
student333Mathematicsmale74186819
student334Languagesfemale77100339
student335Mathematicsmale38537718
student336Languagesfemale18132610
student337Mathematicsmale90478770
student338Languagesfemale38493674
student339Mathematicsmale100641372
student340Languagesfemale74254152
student341Mathematicsmale37131613
student342Languagesfemale24341583
student343Mathematicsmale2056728
student344Languagesfemale4522572
student345Mathematicsmale19117535
student346Languagesfemale6583115
student347Mathematicsmale16663611
student348Languagesfemale1239540
student349Mathematicsmale752742
student350Languagesfemale88926055
student351Mathematicsmale92709145
student352Languagesfemale74765944
student353Mathematicsmale63696094
student354Languagesfemale3685548
student355Mathematicsmale39962148
student356Languagesfemale4134275
student357Mathematicsmale6434733
student358Languagesfemale95146355
student359Mathematicsmale701001382
student360Languagesfemale522410021
student361Mathematicsmale040869
student362Languagesfemale024932
student363Mathematicsmale23108694
student364Languagesfemale1538649
student365Mathematicsmale7623310
student366Languagesfemale35357894
student367Mathematicsmale294243100
student368Languagesfemale668510
student369Mathematicsmale74155683
student370Languagesfemale7543908
student371Mathematicsmale4060470
student372Languagesfemale62421749
student373Mathematicsmale31464454
student374Languagesfemale30344787
student375Mathematicsmale9694152
student376Languagesfemale85432992
student377Mathematicsmale7904025
student378Languagesfemale36407285
student379Mathematicsmale5368882
student380Languagesfemale87783879
student381Mathematicsmale89978338
student382Languagesfemale21194910
student383Mathematicsmale47126850
student384Languagesfemale37124995
student385Mathematicsmale8408851
student386Languagesfemale89612748
student387Mathematicsmale10478761
student388Languagesfemale1692656
student389Mathematicsmale57331347
student390Languagesfemale90357775
student391Mathematicsmale31474753
student392Languagesfemale942412
student393Mathematicsmale6119817
student394Languagesfemale457577
student395Mathematicsmale6729212
student396Languagesfemale516456
student397Mathematicsmale93147714
student398Languagesfemale1893427
student399Mathematicsmale93775791
student400Languagesfemale67778032
student401Mathematicsmale5889417
student402Languagesfemale3056053
student403Mathematicsmale28253259
student404Languagesfemale62348164
student405Mathematicsmale29842623
student406Languagesfemale7086377
student407Mathematicsmale8654799
student408Languagesfemale9381089
student409Mathematicsmale84214658
student410Languagesfemale21841849
student411Mathematicsmale2796340
student412Languagesfemale9301991
student413Mathematicsmale31928743
student414Languagesfemale53259843
student415Mathematicsmale36758089
student416Languagesfemale37681254
student417Mathematicsmale25891253
student418Languagesfemale922846
student419Mathematicsmale11286058
student420Languagesfemale1373517
student421Mathematicsmale67303885
student422Languagesfemale68793441
student423Mathematicsmale72459341
student424Languagesfemale56464538
student425Mathematicsmale8621840
student426Languagesfemale99854119
student427Mathematicsmale7135389
student428Languagesfemale22911216
student429Mathematicsmale1532693
student430Languagesfemale35463474
student431Mathematicsmale33839720
student432Languagesfemale9920326
student433Mathematicsmale48428318
student434Languagesfemale4442530
student435Mathematicsmale78486045
student436Languagesfemale4757890
student437Mathematicsmale881210053
student438Languagesfemale4805160
student439Mathematicsmale70898516
student440Languagesfemale71943433
student441Mathematicsmale68137218
student442Languagesfemale7539721
student443Mathematicsmale65366087
student444Languagesfemale43212434
student445Mathematicsmale85776528
student446Languagesfemale61907891
student447Mathematicsmale9207812
student448Languagesfemale33306290
student449Mathematicsmale8616745
student450Languagesfemale100862423
student451Mathematicsmale1425645
student452Languagesfemale86399888
student453Mathematicsmale72687719
student454Languagesfemale94523100
student455Mathematicsmale34678979
student456Languagesfemale9204745
student457Mathematicsmale64582698
student458Languagesfemale439359100
student459Mathematicsmale82359781
student460Languagesfemale183524100
student461Mathematicsmale79804351
student462Languagesfemale56101767
student463Mathematicsmale36441485
student464Languagesfemale2640692
student465Mathematicsmale59934378
student466Languagesfemale7884883
student467Mathematicsmale41378060
student468Languagesfemale44279777
student469Mathematicsmale29196482
student470Languagesfemale50962746
student471Mathematicsmale49155145
student472Languagesfemale38353178
student473Mathematicsmale1802365
student474Languagesfemale91172376
student475Mathematicsmale57393563
student476Languagesfemale33736214
student477Mathematicsmale96168840
student478Languagesfemale30631613
student479Mathematicsmale74393787
student480Languagesfemale26369479
student481Mathematicsmale19586512
student482Languagesfemale73362248
student483Mathematicsmale7894757
student484Languagesfemale5951935
student485Mathematicsmale677110085
student486Languagesfemale33301546
student487Mathematicsmale12191637
student488Languagesfemale80982914
student489Mathematicsmale70511431
student490Languagesfemale95381592
student491Mathematicsmale60317412
student492Languagesfemale62569068
student493Mathematicsmale63112991
student494Languagesfemale4112520
student495Mathematicsmale6053144
student496Languagesfemale1135528
student497Mathematicsmale11964237
student498Languagesfemale16727974
student499Mathematicsmale9212266
student500Languagesfemale34226434
student501Mathematicsmale50938661
student502Languagesfemale50224044
student503Mathematicsmale383917
student504Languagesfemale98169355
student505Mathematicsmale86893628
student506Languagesfemale16531350
student507Mathematicsmale5757338
student508Languagesfemale34796977
student509Mathematicsmale241659
student510Languagesfemale606299100
student511Mathematicsmale65525295
student512Languagesfemale5873941
student513Mathematicsmale39752876
student514Languagesfemale4666478
student515Mathematicsmale5160998
student516Languagesfemale17201297
student517Mathematicsmale72179673
student518Languagesfemale92216227
student519Mathematicsmale5042433
student520Languagesfemale5237157
student521Mathematicsmale58403554
student522Languagesfemale9385753
student523Mathematicsmale79201818
student524Languagesfemale149427
student525Mathematicsmale95412998
student526Languagesfemale3459921
student527Mathematicsmale39664129
student528Languagesfemale328125
student529Mathematicsmale33443785
student530Languagesfemale69255979
student531Mathematicsmale13504952
student532Languagesfemale54834531
student533Mathematicsmale15249751
student534Languagesfemale7516963
student535Mathematicsmale9183856
student536Languagesfemale50137480
student537Mathematicsmale54757410
student538Languagesfemale76397046
student539Mathematicsmale84723940
student540Languagesfemale10047214
student541Mathematicsmale426111
student542Languagesfemale57716561
student543Mathematicsmale7854134
student544Languagesfemale14763647
student545Mathematicsmale15196396
student546Languagesfemale27823356
student547Mathematicsmale70239690
student548Languagesfemale612278
student549Mathematicsmale22376436
student550Languagesfemale75969440
student551Mathematicsmale4382921
student552Languagesfemale7968718
student553Mathematicsmale65765244
student554Languagesfemale41627354
student555Mathematicsmale25982140
student556Languagesfemale17709682
student557Mathematicsmale43912743
student558Languagesfemale33372433
student559Mathematicsmale87871031
student560Languagesfemale48409774
student561Mathematicsmale63759155
student562Languagesfemale66825995
student563Mathematicsmale21955838
student564Languagesfemale9299745
student565Mathematicsmale5979420
student566Languagesfemale64952412
student567Mathematicsmale70463674
student568Languagesfemale16259149
student569Mathematicsmale73332488
student570Languagesfemale9619527
student571Mathematicsmale18127646
student572Languagesfemale61714963
student573Mathematicsmale46328517
student574Languagesfemale42421137
student575Mathematicsmale49764120
student576Languagesfemale22278012
student577Mathematicsmale76341866
student578Languagesfemale96772917
student579Mathematicsmale62516772
student580Languagesfemale96672254
student581Mathematicsmale77112388
student582Languagesfemale6282433
student583Mathematicsmale392312100
student584Languagesfemale10212071
student585Mathematicsmale11277100
student586Languagesfemale40349778
student587Mathematicsmale2518319
student588Languagesfemale18763025
student589Mathematicsmale24574681
student590Languagesfemale2103194
student591Mathematicsmale91847513
student592Languagesfemale79449710
student593Mathematicsmale42606730
student594Languagesfemale61577535
student595Mathematicsmale42468171
student596Languagesfemale92637574
student597Mathematicsmale86374051
student598Languagesfemale5210473
student599Mathematicsmale100281476
student600Languagesfemale31762043
student601Mathematicsmale402766
student602Languagesfemale587921
student603Mathematicsmale754691
student604Languagesfemale2830153
student605Mathematicsmale38939892
student606Languagesfemale43968991
student607Mathematicsmale43491483
student608Languagesfemale50617298
student609Mathematicsmale4499983
student610Languagesfemale5367382
student611Mathematicsmale40849954
student612Languagesfemale29966569
student613Mathematicsmale1276599
student614Languagesfemale4783494
student615Mathematicsmale3727224
student616Languagesfemale94394924
student617Mathematicsmale0752141
student618Languagesfemale5936418
student619Mathematicsmale2266133
student620Languagesfemale4387448
student621Mathematicsmale100155152
student622Languagesfemale63719917
student623Mathematicsmale143444100
student624Languagesfemale2385727
student625Mathematicsmale23143240
student626Languagesfemale34497254
student627Mathematicsmale21168126
student628Languagesfemale54693434
student629Mathematicsmale72116331
student630Languagesfemale8798947
student631Mathematicsmale43525358
student632Languagesfemale5014420
student633Mathematicsmale89836787
student634Languagesfemale079916
student635Mathematicsmale59178458
student636Languagesfemale94953660
student637Mathematicsmale39426346
student638Languagesfemale019610
student639Mathematicsmale50164171
student640Languagesfemale8604613
student641Mathematicsmale45855936
student642Languagesfemale8335057
student643Mathematicsmale8306014
student644Languagesfemale76807338
student645Mathematicsmale2614582
student646Languagesfemale9316422
student647Mathematicsmale85947616
student648Languagesfemale57453216
student649Mathematicsmale16169013
student650Languagesfemale4331887
student651Mathematicsmale16243244
student652Languagesfemale5998334
student653Mathematicsmale73184783
student654Languagesfemale992510093
student655Mathematicsmale0739784
student656Languagesfemale0289475
student657Mathematicsmale65905863
student658Languagesfemale84358641
student659Mathematicsmale4539599
student660Languagesfemale32103162
student661Mathematicsmale61285461
student662Languagesfemale70961454
student663Mathematicsmale6392298
student664Languagesfemale41104623
student665Mathematicsmale81918021
student666Languagesfemale79716568
student667Mathematicsmale47691890
student668Languagesfemale2616700
student669Mathematicsmale66109335
student670Languagesfemale66682713
student671Mathematicsmale86792645
student672Languagesfemale50532574
student673Mathematicsmale9753914
student674Languagesfemale28796942
student675Mathematicsmale607259
student676Languagesfemale53213943
student677Mathematicsmale37654591
student678Languagesfemale76806027
student679Mathematicsmale85273455
student680Languagesfemale66114117
student681Mathematicsmale27618982
student682Languagesfemale402613
student683Mathematicsmale2516695
student684Languagesfemale63448563
student685Mathematicsmale97957883
student686Languagesfemale5121387
student687Mathematicsmale63928723
student688Languagesfemale22965959
student689Mathematicsmale33801523
student690Languagesfemale34751924
student691Mathematicsmale36684854
student692Languagesfemale32362012
student693Mathematicsmale68917450
student694Languagesfemale87919637
student695Mathematicsmale239144
student696Languagesfemale9462977
student697Mathematicsmale1474575
student698Languagesfemale73921990
student699Mathematicsmale8207978
student700Languagesfemale763510039
student701Mathematicsmale27518949
student702Languagesfemale0647237
student703Mathematicsmale93469487
student704Languagesfemale6922172
student705Mathematicsmale1752113
student706Languagesfemale1325219
student707Mathematicsmale75617273
student708Languagesfemale8437736
student709Mathematicsmale81194514
student710Languagesfemale62173927
student711Mathematicsmale8869681
student712Languagesfemale53825929
student713Mathematicsmale83347134
student714Languagesfemale9552614
student715Mathematicsmale6715313
student716Languagesfemale8297825
student717Mathematicsmale65503146
student718Languagesfemale27462537
student719Mathematicsmale98423544
student720Languagesfemale9014444
student721Mathematicsmale3168293
student722Languagesfemale3434370
student723Mathematicsmale59771421
student724Languagesfemale16535759
student725Mathematicsmale7914416
student726Languagesfemale108199
student727Mathematicsmale89487916
student728Languagesfemale8872387
student729Mathematicsmale17539584
student730Languagesfemale65523961
student731Mathematicsmale44309672
student732Languagesfemale70793233
student733Mathematicsmale30474611
student734Languagesfemale761001649
student735Mathematicsmale39369089
student736Languagesfemale1941929
student737Mathematicsmale23737887
student738Languagesfemale87714464
student739Mathematicsmale22198220
student740Languagesfemale94526739
student741Mathematicsmale14175187
student742Languagesfemale5663983
student743Mathematicsmale99924698
student744Languagesfemale19768388
student745Mathematicsmale15776881
student746Languagesfemale48814838
student747Mathematicsmale2913861
student748Languagesfemale7163030
student749Mathematicsmale19683053
student750Languagesfemale91182762
student751Mathematicsmale73333836
student752Languagesfemale99387550
student753Mathematicsmale55713490
student754Languagesfemale52409883
student755Mathematicsmale1463611
student756Languagesfemale1319496
student757Mathematicsmale49665592
student758Languagesfemale0198082
student759Mathematicsmale2635873
student760Languagesfemale8287639
student761Mathematicsmale52118357
student762Languagesfemale83688425
student763Mathematicsmale1725670
student764Languagesfemale1758084
student765Mathematicsmale7564785
student766Languagesfemale76329339
student767Mathematicsmale20758465
student768Languagesfemale25471289
student769Mathematicsmale86947945
student770Languagesfemale65815535
student771Mathematicsmale62414143
student772Languagesfemale1446243
student773Mathematicsmale17557278
student774Languagesfemale9546356
student775Mathematicsmale7205648
student776Languagesfemale30881956
student777Mathematicsmale42448856
student778Languagesfemale42695663
student779Mathematicsmale7857783
student780Languagesfemale15862498
student781Mathematicsmale4684369
student782Languagesfemale67981552
student783Mathematicsmale33326357
student784Languagesfemale35951653
student785Mathematicsmale78545482
student786Languagesfemale8185914
student787Mathematicsmale42412314
student788Languagesfemale591008636
student789Mathematicsmale1926012
student790Languagesfemale10034570
student791Mathematicsmale381217
student792Languagesfemale3155193
student793Mathematicsmale11339877
student794Languagesfemale461786
student795Mathematicsmale5786727
student796Languagesfemale5746236
student797Mathematicsmale57676661
student798Languagesfemale93888725
student799Mathematicsmale59966441
student800Languagesfemale6276923
student801Mathematicsmale35833255
student802Languagesfemale42581583
student803Mathematicsmale41904012
student804Languagesfemale8143837
student805Mathematicsmale87773320
student806Languagesfemale53873037
student807Mathematicsmale13358516
student808Languagesfemale20829034
student809Mathematicsmale5821614
student810Languagesfemale14282356
student811Mathematicsmale4997368
student812Languagesfemale31461163
student813Mathematicsmale7497643
student814Languagesfemale42839575
student815Mathematicsmale2654529
student816Languagesfemale79596988
student817Mathematicsmale68182684
student818Languagesfemale39139915
student819Mathematicsmale2248716
student820Languagesfemale12538811
student821Mathematicsmale33908029
student822Languagesfemale3795486
student823Mathematicsmale9178851
student824Languagesfemale31586731
student825Mathematicsmale22305098
student826Languagesfemale55585610
student827Mathematicsmale56765753
student828Languagesfemale1129881
student829Mathematicsmale67926671
student830Languagesfemale30614449
student831Mathematicsmale0414461
student832Languagesfemale72524585
student833Mathematicsmale60991294
student834Languagesfemale83587542
student835Mathematicsmale9505377
student836Languagesfemale33287062
student837Mathematicsmale3982755
student838Languagesfemale411004547
student839Mathematicsmale81692729
student840Languagesfemale9012649
student841Mathematicsmale45382034
student842Languagesfemale325311
student843Mathematicsmale55778649
student844Languagesfemale61609176
student845Mathematicsmale8085749
student846Languagesfemale63897371
student847Mathematicsmale79159742
student848Languagesfemale99187343
student849Mathematicsmale30523856
student850Languagesfemale65866734
student851Mathematicsmale7343655
student852Languagesfemale42435173
student853Mathematicsmale870980
student854Languagesfemale29411245
student855Mathematicsmale5739090
student856Languagesfemale80529654
student857Mathematicsmale43838246
student858Languagesfemale7917131
student859Mathematicsmale6813707
student860Languagesfemale51441552
student861Mathematicsmale9170178
student862Languagesfemale4116578
student863Mathematicsmale20635585
student864Languagesfemale5938726
student865Mathematicsmale4894432
student866Languagesfemale26679839
student867Mathematicsmale48793866
student868Languagesfemale1632153
student869Mathematicsmale13205085
student870Languagesfemale4922039
student871Mathematicsmale8262353
student872Languagesfemale6607464
student873Mathematicsmale66483914
student874Languagesfemale43833100
student875Mathematicsmale214990
student876Languagesfemale79807180
student877Mathematicsmale84252688
student878Languagesfemale38466660
student879Mathematicsmale35279851
student880Languagesfemale5759267
student881Mathematicsmale7687788
student882Languagesfemale2140817
student883Mathematicsmale5046866
student884Languagesfemale83863092
student885Mathematicsmale63466694
student886Languagesfemale7671262
student887Mathematicsmale7418686
student888Languagesfemale65774488
student889Mathematicsmale67326119
student890Languagesfemale85968541
student891Mathematicsmale1487705
student892Languagesfemale81284528
student893Mathematicsmale9191883
student894Languagesfemale407024
student895Mathematicsmale18195189
student896Languagesfemale70352512
student897Mathematicsmale7290741
student898Languagesfemale8417186
student899Mathematicsmale1423886
student900Languagesfemale7837601
student901Mathematicsmale66953168
student902Languagesfemale23608065
student903Mathematicsmale76896396
student904Languagesfemale3469070
student905Mathematicsmale65449679
student906Languagesfemale6877865
student907Mathematicsmale86619943
student908Languagesfemale88953213
student909Mathematicsmale531005982
student910Languagesfemale3579535
student911Mathematicsmale230177
student912Languagesfemale9687263
student913Mathematicsmale23923996
student914Languagesfemale9497658
student915Mathematicsmale49312971
student916Languagesfemale21577957
student917Mathematicsmale03510089
student918Languagesfemale64827552
student919Mathematicsmale16666968
student920Languagesfemale92951127
student921Mathematicsmale16888590
student922Languagesfemale56152698
student923Mathematicsmale78274017
student924Languagesfemale95104432
student925Mathematicsmale99855218
student926Languagesfemale73317149
student927Mathematicsmale21791063
student928Languagesfemale92718012
student929Mathematicsmale23293388
student930Languagesfemale4189884
student931Mathematicsmale97177921
student932Languagesfemale72409392
student933Mathematicsmale7558326
student934Languagesfemale15982728
student935Mathematicsmale7688806
student936Languagesfemale84234292
student937Mathematicsmale71568671
student938Languagesfemale7395822
student939Mathematicsmale1555460
student940Languagesfemale2031308
student941Mathematicsmale97544181
student942Languagesfemale83418664
student943Mathematicsmale7195327
student944Languagesfemale0273091
student945Mathematicsmale99751722
student946Languagesfemale92531090
student947Mathematicsmale4449432
student948Languagesfemale0974879
student949Mathematicsmale97557974
student950Languagesfemale6598932
student951Mathematicsmale56733881
student952Languagesfemale84946150
student953Mathematicsmale4820770
student954Languagesfemale39981420
student955Mathematicsmale4152465
student956Languagesfemale78229231
student957Mathematicsmale28382654
student958Languagesfemale49613554
student959Mathematicsmale81152817
student960Languagesfemale5480582
student961Mathematicsmale7523537
student962Languagesfemale5565120
student963Mathematicsmale86427036
student964Languagesfemale54455480
student965Mathematicsmale38186992
student966Languagesfemale33894683
student967Mathematicsmale4395576
student968Languagesfemale13261286
student969Mathematicsmale94228559
student970Languagesfemale9358610
student971Mathematicsmale35728536
student972Languagesfemale37519693
student973Mathematicsmale71107959
student974Languagesfemale71317393
student975Mathematicsmale80268697
student976Languagesfemale69216769
student977Mathematicsmale38861039
student978Languagesfemale48903981
student979Mathematicsmale9083342
student980Languagesfemale1919184
student981Mathematicsmale98255046
student982Languagesfemale38882116
student983Mathematicsmale71481843
student984Languagesfemale79851816
student985Mathematicsmale51669068
student986Languagesfemale100956591
student987Mathematicsmale6742424
student988Languagesfemale93809435
student989Mathematicsmale65785794
student990Languagesfemale27922191
student991Mathematicsmale77152676
student992Languagesfemale28845167
student993Mathematicsmale3786250
student994Languagesfemale59772074
student995Mathematicsmale6266875
student996Languagesfemale88703343
student997Mathematicsmale73334253
student998Languagesfemale6410231
student999Mathematicsmale91931635
student1000Mathematicsmale8277079
+ +

Javascript

+
+

+	
+

HTML

+
+
<table class="tablesorter">
+	<thead>
+		<tr><th>Name</th><th>Major</th><th>Sex</th><th>English</th><th>Japanese</th><th>Calculus</th><th>Geometry</th></tr>
+	</thead>
+	<tfoot>
+		<tr><th>Name</th><th>Major</th><th>Sex</th><th>English</th><th>Japanese</th><th>Calculus</th><th>Geometry</th></tr>
+		<tr>
+			<td colspan="7">
+				<div class="pager">
+					<nav class="left">
+						# per page:
+						<a href="#" class="current">10</a> |
+						<a href="#">25</a> |
+						<a href="#">50</a> |
+						<a href="#">100</a>
+					</nav>
+					<nav class="right">
+						<span class="prev">
+							<img src="icons/prev.png" /> Prev&nbsp;
+						</span>
+						<span class="pagecount"></span>
+						&nbsp;<span class="next">Next
+							<img src="icons/next.png" />
+						</span>
+					</nav>
+				</div>
+			</td>
+		</tr>
+	</tfoot>
+	<tbody>
+		<tr><td>Student01</td><td>Languages</td><td>male</td><td>80</td><td>70</td><td>75</td><td>80</td></tr>
+		<tr><td>Student02</td><td>Mathematics</td><td>male</td><td>90</td><td>88</td><td>100</td><td>90</td></tr>
+		<tr><td>Student03</td><td>Languages</td><td>female</td><td>85</td><td>95</td><td>80</td><td>85</td></tr>
+		<tr><td>Student04</td><td>Languages</td><td>male</td><td>60</td><td>55</td><td>100</td><td>100</td></tr>
+		<tr><td>Student05</td><td>Languages</td><td>female</td><td>68</td><td>80</td><td>95</td><td>80</td></tr>
+		<tr><td>Student06</td><td>Mathematics</td><td>male</td><td>100</td><td>99</td><td>100</td><td>90</td></tr>
+		<tr><td>Student07</td><td>Mathematics</td><td>male</td><td>85</td><td>68</td><td>90</td><td>90</td></tr>
+		<tr><td>Student08</td><td>Languages</td><td>male</td><td>100</td><td>90</td><td>90</td><td>85</td></tr>
+		<tr><td>Student09</td><td>Mathematics</td><td>male</td><td>80</td><td>50</td><td>65</td><td>75</td></tr>
+		<tr><td>Student10</td><td>Languages</td><td>male</td><td>85</td><td>100</td><td>100</td><td>90</td></tr>
+		<!-- ... -->
+		<tr><td>student999</td><td>Mathematics</td><td>male</td><td>91</td><td>93</td><td>16</td><td>35</td></tr>
+	</tbody>
+</table>
+
+ +
+ + + + diff --git a/beta-testing/example-widget-column-reorder.html b/beta-testing/example-widget-column-reorder.html new file mode 100644 index 0000000..feedc1e --- /dev/null +++ b/beta-testing/example-widget-column-reorder.html @@ -0,0 +1,192 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Column reorder Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

+ NOTE! +

    +
  • Column reorder - beta testing.
  • +
  • Does not yet work properly with sticky headers - reorder second table while top table sticky header is active, then scroll...
  • +
+

+ +

Javascript

+
+

+	
+ +

CSS

+
+

+	
+ +

Demo

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Student Grades
Name (0)Major (1)Sex (2)English (3)Japanese (4)Calculus (5)Geometry (6)
NameMajorSexEnglishJapaneseCalculusGeometry
Student01 (0)Languages (1)male (2)80 (3)70 (4)75 (5)80 (6)
Student02Mathematicsmale908810090
Student03Languagesfemale85958085
Student04Languagesmale6055100100
Student05Languagesfemale68809580
Student06Mathematicsmale1009910090
Student07Mathematicsmale85689090
Student08Languagesmale100909085
Student09Mathematicsmale80506575
Student10Languagesmale8510010090
Student11Languagesmale8685100100
Student12Mathematicsfemale100757085
Student13Languagesfemale1008010090
Student14Languagesfemale50455590
Student15Languagesmale953510090
Student16Languagesfemale100503070
Student17Languagesfemale801005565
Student18Mathematicsmale30495575
Student19Languagesmale68908870
Student20Mathematicsmale40454080
Student21Languagesmale5045100100
Student22Mathematicsmale1009910090
Student23Languagesfemale85808080
+ +
+ + + + + + + + + + + + + + + + + + + + + +
Account #First NameLast NameAgeTotalDiscountDiff
A43PeterParker289.9920.3%+3
A255JohnHood3319.9925.1%-7
A33ClarkKent1815.4944.2%-13
A11BruceAlmighty45153.1944%+19
A102BruceEvans56153.1923%+9
A23MikePeters225.6920.3%+2
A55LeslieKent3315.9925.1%-3
A3FrankMint4412.5944.2%-12
A21JoeThomas4515.2544%+12
A12TessEvans6613.5923%+4
A21PeterDunn122.9921.1%+2
A33HarryJones1319.4922.2%-6
A13JohnJames1613.8942.1%-13
A71NickParker4513.8944%+29
A21CharlesDunn1915.4922%+3
+
+ +
+ + +
+ + + + diff --git a/beta-testing/pager-custom-controls.js b/beta-testing/pager-custom-controls.js new file mode 100644 index 0000000..07d6beb --- /dev/null +++ b/beta-testing/pager-custom-controls.js @@ -0,0 +1,102 @@ +/*! + * custom pager controls (beta) for TableSorter 9/15/2014 (v2.17.8) - updated 3/26/2015 (v2.21.3) + initialize custom pager script BEFORE initializing tablesorter/tablesorter pager + custom pager looks like this: + 1 | 2 … 5 | 6 | 7 … 99 | 100 + _ _ _ _ adjacentSpacer + _ _ distanceSpacer + _____ ________ ends (2 default) + _________ aroundCurrent (1 default) + + */ +/*jshint browser:true, jquery:true, unused:false, loopfunc:true */ +/*global jQuery: false */ + +;(function($){ +"use strict"; + +$.tablesorter = $.tablesorter || {}; + +$.tablesorter.customPagerControls = function(settings) { + var defaults = { + table : 'table', + pager : '.pager', + pageSize : '.left a', + currentPage : '.right a', + ends : 2, // number of pages to show of either end + aroundCurrent : 1, // number of pages surrounding the current page + link : '{page}', // page element; use {page} to include the page number + currentClass : 'current', // current page class name + adjacentSpacer : ' | ', // spacer for page numbers next to each other + distanceSpacer : ' … ', // spacer for page numbers away from each other (ellipsis) + addKeyboard : true // add left/right keyboard arrows to change current page + }, + options = $.extend({}, defaults, settings), + $table = $(options.table), + $pager = $(options.pager); + + $table + .on('pagerInitialized pagerComplete', function (e, c) { + var indx, + p = c.pager ? c.pager : c, // using widget + pages = $('
'), + pageArray = [], + cur = p.page + 1, + start = cur > 1 ? (p.filteredPages - cur < options.aroundCurrent ? -(options.aroundCurrent + 1) + (p.filteredPages - cur) : -options.aroundCurrent) : 0, + end = cur < options.aroundCurrent + 1 ? options.aroundCurrent + 3 - cur : options.aroundCurrent + 1; + for (indx = start; indx < end; indx++) { + if (cur + indx >= 1 && cur + indx < p.filteredPages) { pageArray.push( cur + indx ); } + } + if (pageArray.length) { + // include first and last pages (ends) in the pagination + for (indx = 0; indx < options.ends; indx++){ + if ($.inArray(indx + 1, pageArray) === -1) { pageArray.push(indx + 1); } + if ($.inArray(p.filteredPages - indx, pageArray) === -1) { pageArray.push(p.filteredPages - indx); } + } + // sort the list + pageArray = pageArray.sort(function(a, b){ return a - b; }); + // make links and spacers + $.each(pageArray, function(indx, value){ + pages + .append( $(options.link.replace(/\{page\}/g, value)).toggleClass(options.currentClass, value === cur).attr('data-page', value) ) + .append( '' + (indx < pageArray.length - 1 && ( pageArray[ indx + 1 ] - 1 !== value ) ? options.distanceSpacer : + ( indx >= pageArray.length - 1 ? '' : options.adjacentSpacer )) + '' ); + }); + } + $pager.find('.pagecount').html(pages.html()); + }); + + // set up pager controls + $pager.find(options.pageSize).on('click', function () { + $(this) + .addClass(options.currentClass) + .siblings() + .removeClass(options.currentClass); + $table.trigger('pageSize', $(this).html()); + return false; + }).end() + .on('click', options.currentPage, function(){ + $(this) + .addClass(options.currentClass) + .siblings() + .removeClass(options.currentClass); + $table.trigger('pageSet', $(this).attr('data-page')); + return false; + }); + + // make right/left arrow keys work + if (options.addKeyboard) { + $(document).on('keydown', function(events){ + // ignore arrows inside form elements + if (/input|select|textarea/i.test(events.target.nodeName)) { return; } + if (events.which === 37) { + // left + $pager.find(options.currentPage).filter('.' + options.currentClass).prevAll(':not(span):first').click(); + } else if (events.which === 39) { + // right + $pager.find(options.currentPage).filter('.' + options.currentClass).nextAll(':not(span):first').click(); + } + }); + } +}; +})(jQuery); \ No newline at end of file diff --git a/beta-testing/widget-reorder.js b/beta-testing/widget-reorder.js new file mode 100644 index 0000000..616fae4 --- /dev/null +++ b/beta-testing/widget-reorder.js @@ -0,0 +1,182 @@ +/*! tablesorter column reorder - beta testing +* Requires tablesorter v2.8+ and jQuery 1.7+ +* by Rob Garrison +*/ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ + "use strict"; + +$.tablesorter.addWidget({ + id: 'reorder', + priority: 70, + options : { + reorder_axis : 'xy', // x or xy + reorder_delay : 300, + reorder_helperClass : 'tablesorter-reorder-helper', + reorder_helperBar : 'tablesorter-reorder-helper-bar', + reorder_noReorder : 'reorder-false', + reorder_blocked : 'reorder-block-left reorder-block-end', + reorder_complete : null // callback + }, + init: function(table, thisWidget, c, wo) { + var i, timer, $helper, $bar, clickOffset, + lastIndx = -1, + ts = $.tablesorter, + endIndex = -1, + startIndex = -1, + t = wo.reorder_blocked.split(' '), + noReorderLeft = t[0] || 'reorder-block-left', + noReorderLast = t[1] || 'reorder-block-end', + lastOffset = c.$headers.not('.' + noReorderLeft).first(), + offsets = c.$headers.map(function(i){ + var s, $t = $(this); + if ($t.hasClass(noReorderLeft)) { + s = lastOffset; + $t = s; + //lastOffset = $t; + } + lastOffset = $t; + return $t.offset().left; + }).get(), + len = offsets.length, + startReorder = function(e, $th){ + var p = $th.position(), + r = $th.parent().position(), + i = startIndex = $th.index(); + clickOffset = [ e.pageX - p.left, e.pageY - r.top ]; + $helper = c.$table.clone(); + $helper.find('> thead > tr:first').children('[data-column!=' + i + ']').remove(); + $helper.find('thead tr:gt(0), caption, colgroup, tbody, tfoot').remove(); + $helper + .css({ + position: 'absolute', + zIndex : 1, + left: p.left - clickOffset[0], + top: r.top - clickOffset[1], + width: $th.outerWidth() + }) + .appendTo('body') + .find('th, td').addClass(wo.reorder_helperClass); + $bar = $('
') + .css({ + position : 'absolute', + top : c.$table.find('thead').offset().top, + height : $th.closest('thead').outerHeight() + c.$table.find('tbody').height() + }) + .appendTo('body'); + positionBar(e); + lastIndx = endIndex; + }, + positionBar = function(e){ + for (i = 0; i <= len; i++) { + if ( i > 0 && e.pageX < offsets[i-1] + (offsets[i] - offsets[i-1])/2 && !c.$headers.eq(i).hasClass(noReorderLeft) ) { + endIndex = i - 1; + // endIndex = offsets.lastIndexOf( offsets[i-1] ); // lastIndexOf not supported by IE8 and older + if (endIndex >= 0 && lastIndx === endIndex) { return false; } + lastIndx = endIndex; + if (c.debug) { + ts.log( endIndex === 0 ? 'target before column 0' : endIndex === len ? 'target after last column' : 'target between columns ' + startIndex + ' and ' + endIndex); + } + $bar.css('left', offsets[i-1]); + return false; + } + } + if (endIndex < 0) { + endIndex = len; + $bar.css('left', offsets[len]); + } + }, + finishReorder = function(){ + $helper.remove(); + $bar.remove(); + // finish reorder + var adj, s = startIndex, + rows = c.$table.find('tr'), + cols; + startIndex = -1; // stop mousemove updates + if ( s > -1 && endIndex > -1 && s != endIndex && s + 1 !== endIndex ) { + adj = endIndex !== 0; + if (c.debug) { + ts.log( 'Inserting column ' + s + (adj ? ' after' : ' before') + ' column ' + (endIndex - adj ? 1 : 0) ); + } + rows.each(function() { + cols = $(this).children(); + cols.eq(s)[ adj ? 'insertAfter' : 'insertBefore' ]( cols.eq( endIndex - (adj ? 1 : 0) ) ); + }); + cols = []; + // stored header info needs to be modified too! + for (i = 0; i < len; i++) { + if (i === s) { continue; } + if (i === endIndex - (adj ? 1 : 0)) { + if (!adj) { cols.push(c.headerContent[s]); } + cols.push(c.headerContent[i]); + if (adj) { cols.push(c.headerContent[s]); } + } else { + cols.push(c.headerContent[i]); + } + } + c.headerContent = cols; + // cols = c.headerContent.splice(s, 1); + // c.headerContent.splice(endIndex - (adj ? 1 : 0), 0, cols); + c.$table.trigger('updateAll', [ true, wo.reorder_complete ]); + } + endIndex = -1; + }, + mdown = function(e, el){ + var $t = $(el), evt = e; + if ($t.hasClass(wo.reorder_noReorder)) { return; } + timer = setTimeout(function(){ + $t.addClass('tablesorter-reorder'); + startReorder(evt, $t); + }, wo.reorder_delay); + }; + + console.log( c.$headers.last().hasClass(noReorderLast) ); + + if ( c.$headers.last().hasClass(noReorderLast) ) { + offsets.push( offsets[ offsets.length - 1 ] ); + } else { + offsets.push( c.$table.offset().left + c.$table.outerWidth() ); + } + + c.$headers.not('.' + wo.reorder_noReorder).bind('mousedown.reorder', function(e){ + mdown(e, this); + }); + + $(document) + .bind('mousemove.reorder', function(e){ + if (startIndex !== -1){ + var c = { left : e.pageX - clickOffset[0] }; + endIndex = -1; + if (/y/.test(wo.reorder_axis)) { + c.top = e.pageY - clickOffset[1]; + } + $helper.css(c); + positionBar(e); + } + }) + .add( c.$headers ) + .bind('mouseup.reorder', function(){ + clearTimeout(timer); + if (startIndex !== -1 && endIndex !== -1){ + finishReorder(); + } else { + startIndex = -1; + } + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + wo.$sticky.find('thead').children().not('.' + wo.reorder_noReorder).bind('mousedown.reorder', function(e){ + mdown(e, this); + }); + }); + + } +}); + +// add mouse coordinates +$x = $('#main h1:last'); $(document).mousemove(function(e){ $x.html( e.pageX ); }); + +})(jQuery); \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..fdf5e12 --- /dev/null +++ b/bower.json @@ -0,0 +1,10 @@ +{ + "name": "tablesorter", + "version": "2.22.1", + "dependencies": { + "jquery": ">=1.2.6" + }, + "main": [ + "dist/js/jquery.tablesorter.combined.js" + ] +} \ No newline at end of file diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..f8f1cf0 --- /dev/null +++ b/changelog.txt @@ -0,0 +1,2 @@ +Change log moved to the wiki documentation pages: +https://github.com/Mottie/tablesorter/wiki/Changes \ No newline at end of file diff --git a/css/bootstrap.less b/css/bootstrap.less new file mode 100644 index 0000000..1d712ca --- /dev/null +++ b/css/bootstrap.less @@ -0,0 +1,322 @@ +/* Tablesorter Custom Bootstrap LESS Theme by Rob Garrison + +To create your own theme, modify the code below and run it through +a LESS compiler, like this one: http://leafo.net/lessphp/editor.html +or download less.js from http://lesscss.org/ + +Test out these custom less files live + Basic Theme : http://codepen.io/Mottie/pen/eqBbn + Bootstrap : http://codepen.io/Mottie/pen/Ltzpi + Metro Style : http://codepen.io/Mottie/pen/gCslk + +*/ + +/*** theme ***/ +@theme : tablesorter-bootstrap; + +/*** fonts ***/ +@tableHeaderFont : 14px bold Arial, Sans-serif; +@tableBodyFont : 14px "Helvetica Neue", Helvetica, Arial, sans-serif; + +/*** color definitions ***/ +/* for best results, only change the hue (240), + leave the saturation (60%) and luminosity (80%) alone + pick the color from here: http://hslpicker.com/#99E699 */ +@headerBackground : hsl(240, 60%, 80%); +@borderAndBackground : #cdcdcd; +@overallBorder : @borderAndBackground 1px solid; +@headerTextColor : #000; + +@bodyBackground : #fff; +@bodyTextColor : #000; + +@headerAsc : darken(spin(@headerBackground, 5), 10%); /* darken(@headerBackground, 10%); */ +@headerDesc : lighten(spin(@headerBackground, -5), 10%); /* desaturate(@headerAsc, 5%); */ + +@captionBackground : #fff; /* it might be best to match the document body background color here */ +@errorBackground : #e6bf99; /* ajax error message (added to thead) */ + +@filterCellBackground : #eee; +@filterElementTextColor: #333; +@filterElementBkgd : #fff; +@filterElementBorder : 1px solid #bbb; +@filterTransitionTime : 0.1s; +@filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */ + +@overallPadding : 4px; +/* 20px should be slightly wider than the icon width to avoid overlap */ +@headerPadding : 4px 20px 4px 4px; +@headerMargin : 0 0 18px; + +/* url(icons/loading.gif); */ +@processingIcon : url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs='); + +/* zebra striping */ +.allRows { + background-color: @bodyBackground; + color: @bodyTextColor; +} +.evenRows { + background-color: lighten(@headerBackground, 35%); +} +.oddRows { + background-color: lighten(@headerBackground, 18%); +} + +/* hovered rows */ +.oddHovered { + background-color: desaturate(@headerBackground, 60%); +} +.evenHovered { + background-color: lighten( desaturate(@headerBackground, 60%), 10% ); +} + +/* Columns widget */ +@primaryOdd : spin(@headerBackground, 10); /* saturate( darken( desaturate(@headerBackground, 10%), 10% ), 30%); */ +@primaryEven : lighten( @primaryOdd, 10% ); +@secondaryOdd : @primaryEven; +@secondaryEven : lighten( @primaryEven, 5% ); +@tertiaryOdd : @secondaryEven; +@tertiaryEven : lighten( @secondaryEven, 5% ); + +/* Filter widget transition */ +.filterWidgetTransition { + -webkit-transition: line-height @filterTransitionTime ease; + -moz-transition: line-height @filterTransitionTime ease; + -o-transition: line-height @filterTransitionTime ease; + transition: line-height @filterTransitionTime ease; +} + +/*** icon block ***/ +.iconPosition { + font-size: 11px; + position: absolute; + right: 2px; + top: 50%; + margin-top: -7px; /* half the icon height; older IE doesn't like this */ + width: 14px; + height: 14px; + background-repeat: no-repeat; + line-height: 14px; +} + +/* black */ +@unsortedBlack : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAMAAADOvxanAAAAVFBMVEUAAABCQkJZWVkZGRnJyckgICAZGRkZGRn8/PweHh4dHR0aGhoaGhpUVFQbGxvQ0NDc3NxMTExSUlIbGxvr6+s4ODhKSkogICAtLS00NDQzMzMnJydSEPrQAAAAGHRSTlMA1ssZRLgdAQbDyisqsZo8QdXUq0r9xPepSRwiAAAAX0lEQVQI13XHSQKAIAwEwQAKxn13Ev7/T2Pu9qmarJKPXIicI4PH4hxaKNrhm2S8bJK5h4YzKHrzJNtK6yYT/TdXzpS5zuYg4MSQYF6i4IHExdw1UVRi05HPrrvT53a+qyMFC9t04gcAAAAASUVORK5CYII=); + +/* white */ +@unsortedWhite : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOBAMAAAALT/umAAAAKlBMVEUAAAD///////////////////////////////////////////////////+Gu8ovAAAADXRSTlMA4EXKBtQqvR0+sxmalc142gAAAFdJREFUCNdjYGDoamAAAjZbMxCVfvd6AgMDd+3du9UMDKx3hWSvMjBwXZww8RYDGuC53NB8h4GB8a617UUGBs7Yu3cjGRhYVO9eVQFKOskKOQApFmUgBwBZ+xXRTttNdAAAAABJRU5ErkJggg==); + +/* automatically choose the correct arrow/text color */ +.headerText (@a) when (lightness(@a) >= 50%) { + color: @headerTextColor; +} +.headerText (@a) when (lightness(@a) < 50%) { + color: lighten(@headerTextColor, 90%); +} +.unsorted (@a) when (lightness(@a) >= 50%) { + background-image: @unsortedBlack; + color: @headerTextColor; +} +.unsorted (@a) when (lightness(@a) < 50%) { + background-image: @unsortedWhite; + color: lighten(@headerTextColor, 90%); +} + +/* variable theme name - requires less.js 1.3+; + or just replace (!".@{theme}") with the contents of @theme +*/ +.@{theme} { + font: @tableBodyFont; + background-color: @borderAndBackground; + width: 100%; + + /* style th's outside of the thead */ + th, thead td { + font: @tableHeaderFont; + font-weight: bold; + background-color: @headerBackground; + .headerText(@headerBackground); + border-collapse: collapse; + margin: @headerMargin; + padding: @overallPadding; + } + + tbody td, tfoot th, tfoot td { + padding: @overallPadding; + vertical-align: top; + } + + /* style header */ + .tablesorter-header { + cursor: pointer; + } + + .tablesorter-header-inner { + position: relative; + padding: @headerPadding; + } + + /* bootstrap uses for icons */ + .tablesorter-header-inner i.tablesorter-icon { + .iconPosition + } + + .tablesorter-header.sorter-false { + background-image: none; + cursor: default; + + } + + .tablesorter-headerAsc { + background-color: @headerAsc; + } + + .tablesorter-headerDesc { + background-color: @headerDesc; + } + + .bootstrap-icon-unsorted { + .unsorted(@headerBackground); + } + + + /* tfoot */ + tfoot .tablesorter-headerAsc, + tfoot .tablesorter-headerDesc { + /* remove sort arrows from footer */ + background-image: none; + } + + /* optional disabled input styling */ + .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; + } + + /* body */ + tbody { + + td { + .allRows; + padding: @overallPadding; + vertical-align: top; + } + + /* Zebra Widget - row alternating colors */ + tr.odd > td { + .oddRows; + } + tr.even > td { + .evenRows; + } + + } + + /* hovered row colors + you'll need to add additional lines for + rows with more than 2 child rows + */ + tbody > tr.hover > td, + tbody > tr:hover > td, + tbody > tr:hover + tr.tablesorter-childRow > td, + tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td, + tbody > tr.even.hover > td, + tbody > tr.even:hover > td, + tbody > tr.even:hover + tr.tablesorter-childRow > td, + tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .evenHovered; + } + tbody > tr.odd.hover > td, + tbody > tr.odd:hover > td, + tbody > tr.odd:hover + tr.tablesorter-childRow > td, + tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .oddHovered; + } + + /* table processing indicator - indeterminate spinner */ + .tablesorter-processing { + background-image: @processingIcon; + background-position: center center; + background-repeat: no-repeat; + } + + /* Column Widget - column sort colors */ + tr.odd td.primary { + background-color: @primaryOdd; + } + td.primary, tr.even td.primary { + background-color: @primaryEven; + } + tr.odd td.secondary { + background-color: @secondaryOdd; + } + td.secondary, tr.even td.secondary { + background-color: @secondaryEven; + } + tr.odd td.tertiary { + background-color: @tertiaryOdd; + } + td.tertiary, tr.even td.tertiary { + background-color: @tertiaryEven; + } + + /* caption (non-theme matching) */ + caption { + background-color: @captionBackground ; + } + + /* filter widget */ + .tablesorter-filter-row input, + .tablesorter-filter-row select{ + width: 98%; + margin: 0; + padding: @overallPadding; + color: @filterElementTextColor; + background-color: @filterElementBkgd; + border: @filterElementBorder; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + .filterWidgetTransition; + } + .tablesorter-filter-row { + background-color: @filterCellBackground; + } + .tablesorter-filter-row td { + text-align: center; + background-color: @filterCellBackground; + line-height: normal; + text-align: center; /* center the input */ + .filterWidgetTransition; + } + /* hidden filter row */ + .tablesorter-filter-row.hideme td { + padding: @filterRowHiddenHeight / 2; + margin: 0; + line-height: 0; + cursor: pointer; + } + .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); + } + /* rows hidden by filtering (needed for child rows) */ + .filtered { + display: none; + } + + /* ajax error row */ + .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: @errorBackground; + } + +} diff --git a/css/dragtable.mod.css b/css/dragtable.mod.css new file mode 100644 index 0000000..e8b59d3 --- /dev/null +++ b/css/dragtable.mod.css @@ -0,0 +1,64 @@ +/* + * dragtable + * @Version 2.0.14 MOD + * default css + */ +.dragtable-sortable { + list-style-type: none; + margin: 0; + padding: 0; + -moz-user-select: none; + z-index: 10; +} +.dragtable-sortable li { + margin: 0; + padding: 0; + float: left; + font-size: 1em; +} +.dragtable-sortable table { + margin-top: 0; +} +.dragtable-sortable th, .dragtable-sortable td { + border-left: 0px; +} +.dragtable-sortable li:first-child th, .dragtable-sortable li:first-child td { + border-left: 1px solid #CCC; +} +.dragtable-handle-selected { + /* table-handle class while actively dragging a column */ +} +.ui-sortable-helper { + opacity: 0.7; + filter: alpha(opacity=70); +} +.ui-sortable-placeholder { + -moz-box-shadow: 4px 5px 4px rgba(0,0,0,0.2) inset; + -webkit-box-shadow: 4px 5px 4px rgba(0,0,0,0.2) inset; + box-shadow: 4px 5px 4px rgba(0,0,0,0.2) inset; + border-bottom: 1px solid rgba(0,0,0,0.2); + border-top: 1px solid rgba(0,0,0,0.2); + visibility: visible !important; + /* change the background color here to match the tablesorter theme */ + background: #EFEFEF; +} +.ui-sortable-placeholder * { + opacity: 0.0; + visibility: hidden; +} +.table-handle, .table-handle-disabled { + /* background-image: url(images/dragtable-handle.png); */ + /* background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAANAQMAAAC5Li2yAAAABlBMVEUAAAAzMzPI8eYgAAAAAnRSTlMAzORBQ6MAAAAOSURBVAjXYwABByyYAQAQWgFBLN2RnwAAAABJRU5ErkJggg=='); */ + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyIiBoZWlnaHQ9IjEzIj48cmVjdCBzdHlsZT0iZmlsbDojMzMzO2ZpbGwtb3BhY2l0eTouODsiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHg9IjEiIHk9IjIiLz4JPHJlY3Qgc3R5bGU9ImZpbGw6IzMzMztmaWxsLW9wYWNpdHk6Ljg7IiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4PSIxIiB5PSI0Ii8+CTxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iNiIvPjxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iOCIvPjxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iMTAiLz48L3N2Zz4=); + background-repeat: repeat-x; + height: 13px; + margin: 0 1px; + cursor: move; +} +.table-handle-disabled { + opacity: 0; + cursor: not-allowed; +} +.dragtable-sortable table { + margin-bottom: 0; +} diff --git a/css/filter.formatter.css b/css/filter.formatter.css new file mode 100644 index 0000000..cb5dde1 --- /dev/null +++ b/css/filter.formatter.css @@ -0,0 +1,183 @@ +/**** Filter Formatter Elements ****/ +.tablesorter .tablesorter-filter-row td { + text-align: center; + font-size: 0.9em; + font-weight: normal; +} + +/**** Sliders ****/ +/* shrink the sliders to look nicer inside of a table cell */ +.tablesorter .ui-slider, .tablesorter input.range { + width: 90%; + margin: 2px auto 2px auto; /* add enough top margin so the tooltips will fit */ + font-size: 0.8em; +} +.tablesorter .ui-slider { + top: 12px; +} +.tablesorter .ui-slider .ui-slider-handle { + width: 0.9em; + height: 0.9em; +} +.tablesorter .ui-datepicker { + font-size: 0.8em; +} +.tablesorter .ui-slider-horizontal { + height: 0.5em; +} +/* Add tooltips to slider handles */ +.tablesorter .value-popup:after { + content : attr(data-value); + position: absolute; + bottom: 14px; + left: -7px; + min-width: 18px; + height: 12px; + background-color: #444; + background-image: -webkit-gradient(linear, left top, left bottom, from(#444444), to(#999999)); + background-image: -webkit-linear-gradient(top, #444, #999); + background-image: -moz-linear-gradient(top, #444, #999); + background-image: -o-linear-gradient(top, #444, #999); + background-image: linear-gradient(to bottom, #444, #999); + -webkit-border-radius: 3px; + border-radius: 3px; + -webkit-background-clip: padding-box; background-clip: padding-box; + -webkit-box-shadow: 0px 0px 4px 0px #777; + box-shadow: 0px 0px 4px 0px #777; + border: #444 1px solid; + color: #fff; + font: 1em/1.1em Arial, Sans-Serif; + padding: 1px; + text-align: center; +} +.tablesorter .value-popup:before { + content: ""; + position: absolute; + width: 0; + height: 0; + border-top: 8px solid #777; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + top: -8px; + left: 50%; + margin-left: -8px; + margin-top: -1px; +} + +/**** Date Picker ****/ +.tablesorter .dateFrom, .tablesorter .dateTo { + width: 80px; + margin: 2px 5px; +} + +/**** Color Picker/HTML5Number Toggle button ****/ +.tablesorter .button { + width: 14px; + height: 14px; + background: #fcfff4; + background: -webkit-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: -moz-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: -o-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: -ms-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfff4', endColorstr='#b3bead', GradientType=0 ); + margin: 1px 5px 1px 1px; + -webkit-border-radius: 25px; + -moz-border-radius: 25px; + border-radius: 25px; + -webkit-box-shadow: inset 0px 1px 1px white, 0px 1px 3px rgba(0,0,0,0.5); + -moz-box-shadow: inset 0px 1px 1px white, 0px 1px 3px rgba(0,0,0,0.5); + box-shadow: inset 0px 1px 1px white, 0px 1px 3px rgba(0,0,0,0.5); + position: relative; + top: 3px; + display: inline-block; +} + +.tablesorter .button label { + cursor: pointer; + position: absolute; + width: 10px; + height: 10px; + -webkit-border-radius: 25px; + -moz-border-radius: 25px; + border-radius: 25px; + left: 2px; + top: 2px; + -webkit-box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,1); + -moz-box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,1); + box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,1); + background: #45484d; + background: -webkit-linear-gradient(top, #222 0%, #45484d 100%); + background: -moz-linear-gradient(top, #222 0%, #45484d 100%); + background: -o-linear-gradient(top, #222 0%, #45484d 100%); + background: -ms-linear-gradient(top, #222 0%, #45484d 100%); + background: linear-gradient(top, #222 0%, #45484d 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#222', endColorstr='#45484d', GradientType=0 ); +} + +.tablesorter .button label:after { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + opacity: 0; + content: ''; + position: absolute; + width: 8px; + height: 8px; + background: #55f; + background: -webkit-linear-gradient(top, #aaf 0%, #55f 100%); + background: -moz-linear-gradient(top, #aaf 0%, #55f 100%); + background: -o-linear-gradient(top, #aaf 0%, #55f 100%); + background: -ms-linear-gradient(top, #aaf 0%, #55f 100%); + background: linear-gradient(top, #aaf 0%, #55f 100%); + -webkit-border-radius: 25px; + -moz-border-radius: 25px; + border-radius: 25px; + top: 1px; + left: 1px; + -webkit-box-shadow: inset 0px 1px 1px #fff, 0px 1px 3px rgba(0,0,0,0.5); + -moz-box-shadow: inset 0px 1px 1px #fff, 0px 1px 3px rgba(0,0,0,0.5); + box-shadow: inset 0px 1px 1px #fff, 0px 1px 3px rgba(0,0,0,0.5); +} + +.tablesorter .button label:hover::after { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; + filter: alpha(opacity=30); + opacity: 0.3; +} + +.tablesorter .button input[type=checkbox] { + visibility: hidden; +} + +.tablesorter .button input[type=checkbox]:checked + label:after { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + filter: alpha(opacity=100); + opacity: 1; +} + +.tablesorter .colorpicker { + width: 30px; + height: 18px; +} +.tablesorter .ui-spinner-input { + width: 100px; + height: 18px; +} +.tablesorter .currentColor, .tablesorter .ui-spinner { + position: relative; +} +.tablesorter input.number { + position: relative; +} + +/* hide filter row */ +.tablesorter .tablesorter-filter-row.hideme td * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} diff --git a/css/images/black-asc.gif b/css/images/black-asc.gif new file mode 100644 index 0000000000000000000000000000000000000000..730533fa3570dd4805cec70fe2630e85a2e1b863 GIT binary patch literal 48 zcmZ?wbhEHbWM^PuXkcJa);0M5|G(l-7DfgJMg|=QAOOiQFtPU}a;`qj$IW0300PSi A(EtDd literal 0 HcmV?d00001 diff --git a/css/images/black-desc.gif b/css/images/black-desc.gif new file mode 100644 index 0000000000000000000000000000000000000000..4c3b61020bb4d707e41e94fbf2b6ebe5d0c87f6b GIT binary patch literal 49 zcmZ?wbhEHbWM^PuXkcJa);0M5|G(l-7DfgJMg|=QAOOiQFmbf-H%eylMrtrv0{{qN B3331c literal 0 HcmV?d00001 diff --git a/css/images/black-unsorted.gif b/css/images/black-unsorted.gif new file mode 100644 index 0000000000000000000000000000000000000000..5647f658329230706ec09c5e3c24fae39d225a04 GIT binary patch literal 54 zcmZ?wbhEHbWM|-HXkcJa);0M5|G(l-7DfgJMg|=QAOOiQF!A;za;`qjH@QXcLR*>^ GgEatAw+#UR literal 0 HcmV?d00001 diff --git a/css/images/bootstrap-black-unsorted.png b/css/images/bootstrap-black-unsorted.png new file mode 100644 index 0000000000000000000000000000000000000000..4e161a65ec0d89596124ebd5eeb18014e900fc5f GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^+(697!3-qN?H5}Pq(TCGLR^8glao_qWTd2|7*RL%sEWEtDfVy;b zbxll6jE#-e)zyOpeq8{XD^U{U7tC<&w4}=pSw^+cIEHXsFFo$b)S$q_a*%=RSZ%q`zyJQp@4l^^wPsR(OvfDM=HriKqBL$joSm{K zXVT90He-#d&nmaQUaJZJH4i^GW#_qP3J;DgTe~DWM4fZ4GGK literal 0 HcmV?d00001 diff --git a/css/images/bootstrap-white-unsorted.png b/css/images/bootstrap-white-unsorted.png new file mode 100644 index 0000000000000000000000000000000000000000..fb227a150ec672948d40c0989ab4654957d4074c GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^+(697!VF^h|6T^9v;urWT!Hj|;y~N(Q~E&Fyd^?&UREc$ gEEzP#QWe-4B7cis^t&#$e5Qt)Q)VVuxK2V0i)78&qol`;+0PtZJpa1{> literal 0 HcmV?d00001 diff --git a/css/images/dragtable-handle.svg b/css/images/dragtable-handle.svg new file mode 100644 index 0000000..041ec1d --- /dev/null +++ b/css/images/dragtable-handle.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/css/images/dropbox-asc-hovered.png b/css/images/dropbox-asc-hovered.png new file mode 100644 index 0000000000000000000000000000000000000000..bc45223f1dec5faab874457b501249849a5ad67a GIT binary patch literal 275 zcmV+u0qp*XP)N!0YroNDAvUkG#GGj^Q5tJa56A6voL^Y5FaECSH#ZAHJO8p z2Pn@9bO0j*hz9XN;vjkEyC0cUxcLQpK-MrZGeaB-RLI1{#PIL`Ke-j_w=ZQRCY%5Q Z3;^4XF8Gf^mEZsX002ovPDHLkV1l>1alZfn literal 0 HcmV?d00001 diff --git a/css/images/dropbox-asc.png b/css/images/dropbox-asc.png new file mode 100644 index 0000000000000000000000000000000000000000..0d6ee15054013562d87105ebf9a5915b093b745a GIT binary patch literal 278 zcmV+x0qOpUP)c1cZKk`S9+`+ZU=! zioM^Vn8eP-+rq^!EX2hx!~mi}d=%^AChRcaJ^%m!07*qoM6N<$f|sClJ^%m! literal 0 HcmV?d00001 diff --git a/css/images/dropbox-desc-hovered.png b/css/images/dropbox-desc-hovered.png new file mode 100644 index 0000000000000000000000000000000000000000..4930942048212f647f27b8c8f06ec2737a7ee016 GIT binary patch literal 273 zcmV+s0q*{ZP)o985veE zvmi|S`{ysi@Ba*GAT}e+O=VNoUSVeZrwuXEnMIi9w^M{(hzka;~ zs$c-oAU;eEu4qcM&O4wR>i_=v1#(M0h!6K2vTwe9d^_vk-@kG{zI>R)z@PvZXCx+^ b00ImE*WX@&i7{I-00000NkvXXu0mjf>Ct&J literal 0 HcmV?d00001 diff --git a/css/images/green-asc.gif b/css/images/green-asc.gif new file mode 100644 index 0000000000000000000000000000000000000000..4cfba09507af83ef6db36d4eb1adcc75e2fa3954 GIT binary patch literal 283 zcmZ?wbhEHb6krfwxXQr5=gT7y!8hS*-@He2=HH*IutrK|hPYrXpFlXT@*Y{GZ8Ea6 zB&7Srq|Ns9CGysY}Sr{1@lo@nDW`q31z-Dn^Vu6Q_RR4)3 zMJIjoW+}V79ogbzu%PkNAq^J`MW&$784_ZXj<_d$31JXmQ7TxVVRd0o-FbO7Mh0sD Dr2|2x literal 0 HcmV?d00001 diff --git a/css/images/green-desc.gif b/css/images/green-desc.gif new file mode 100644 index 0000000000000000000000000000000000000000..4f8817650dc07236f0f884cb826413ceeba2e1e6 GIT binary patch literal 283 zcmZ?wbhEHb6krfwxXQo~IxW~F#F*EGOR7th$B9dMkF3HfDVZtaqWOX%nF5NNWaO7g zNi>LXTXJgeQ#CxGt+QN1d!f4NAp^5R2DV2moQ~RRR;ziRaI=|X5pc>o=#+2pY5&mE z0deOdORpBT-fGI6k{(+YqvWFCp6vSn|9=K*1I3>#j0_Aa3_2i#L4IOjvv8PH;GrYc ze_~0|NtGs{wyw0pFDvXAk~<7EJT#{Buvumqi1d59ND9cv2rT2+m@!G`+n&1f?re+< F)&TJsK)V0{ literal 0 HcmV?d00001 diff --git a/css/images/green-header.gif b/css/images/green-header.gif new file mode 100644 index 0000000000000000000000000000000000000000..cc746b70a390d3c1e60dd0839aafaefdb56ffa5c GIT binary patch literal 513 zcmd7P%Sr-a7zW^93c{#X1sxV;wFw=D$Ppmun&SRq#z*(T68O2gBur(hZ)a0 zI!B!uXPm=7(#q7@)D`rtU*6}1FB}PZymuyW4_E+*I)P(2ga(G;49n6CL(w!zQB9JB z2GpUh>6)skimG&#uH2O+SrR)UFYsK8({)YLRE}dwve{@51W~Wms?};GlS!x3D2jdv zJkPh=?N+PB4N`0&pU>ksmdoX`*=*(~)$8>P!+;R#-*u|0D2go0k|cFH9Z?ho;ZF_A zFbqx86h)B(xH+Ilc733a_)4W*E|*HBVzF2#6mT5>4Wg-3Dw$07`+e{a&hj~K0^kPN zhFgX|0TZ_mR;vv`?2c!1?A+A!jB9J#y|cVxSzYr7f(P>p$BRp$@afrD wG=BLW--tyo&etR1lcU4ne!%bB^X$5}T+U6$OXBqjaX4LWZ!i?Qx_$({FRQBh`v3p{ literal 0 HcmV?d00001 diff --git a/css/images/green-unsorted.gif b/css/images/green-unsorted.gif new file mode 100644 index 0000000000000000000000000000000000000000..0afe2c021cc7dccbb3af311f09496b51864737ca GIT binary patch literal 520 zcmZ?wbhEHb6krfwc*elM=gT7y!52C$*d)Yw!qvWckLJw3KbO~qOJR+a%nWgXc) zK7nvv9w#p4J+eyMWE56O$QVTsmjzy=%5g&1Q~8z$x#bQ@+8c{X>D9u@ zYh|ssn)>hdWKKzsEsIfdQE*Ro{r~?z!;k`sKUo+V7+e{2K&}SG2?Kj-gKJZBOKV$` zetWy9jzd?AvYeU?Yrm_iFo%?Z9b1>KmHq)$ literal 0 HcmV?d00001 diff --git a/css/images/ice-asc.gif b/css/images/ice-asc.gif new file mode 100644 index 0000000000000000000000000000000000000000..0961d9aafb17fa754d4ce5048c638cfb4db3b40d GIT binary patch literal 285 zcmZ?wbhEHbjG ze=B$H7M`M=JO$f%3b*s*Z{sc5&0D;aw{XXQhW`vy1&Tje7#SE;8FWCVg8an5W_4iF z1{Eo(cIAK<7GG+tB)KLZ*_oj=x#Q#Jg8@4IZOsRDX3rEjc`?91@5CYJhLs*uIGBu; N3@oNIq&hNK0{}6xMqB^@ literal 0 HcmV?d00001 diff --git a/css/images/ice-desc.gif b/css/images/ice-desc.gif new file mode 100644 index 0000000000000000000000000000000000000000..0330fccaabc2e17a7e67f4962aa4f89c8557ba4f GIT binary patch literal 285 zcmZ?wbhEHb)%wYAO#uhf0Eoc^7;0*Tg1?=JT*+b^AM=xTJT*wiGf)f^f3h$#FlaL9 zfJ_4UiGj`Pz!Za0DXI2l=U-U3bOy=t3%f|=8669F*)h{#e}bBO^1=|6PPRi8jV^NB W%#AMt3|Lq{BnogWXNY%Xum%8lS4B$z literal 0 HcmV?d00001 diff --git a/css/images/ice-unsorted.gif b/css/images/ice-unsorted.gif new file mode 100644 index 0000000000000000000000000000000000000000..c1afde558ea67f6f47148bb4e25f39abafd87799 GIT binary patch literal 180 zcmV;l089TzNk%w1VGIBa0K@xc>nEA^8LW0018VEC2ui01N;O000Fs;3t0EXpUQkoug-cRK;f37(J%e iole94K-NTZIuJ|{#s~pmEfk+Z0GKccf}g=J1OPj7d^(%} literal 0 HcmV?d00001 diff --git a/css/images/metro-black-asc.png b/css/images/metro-black-asc.png new file mode 100644 index 0000000000000000000000000000000000000000..f7a781be17147df66dfad715f1a977b148fd1153 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!VDxY_&1vXDa8Pv5LY0LALL&2I0#h1RTAVE z%wWu|6?cDuf+*XOEM^0sXr!l$V+hA}-7~sE4h$l$4~-?Rm@@@l>{N*qQH@MuUvp6C zPs?_%_h)|`vVF@G*#BDZenOR(_Zq8cwyV-krlwQVQ$FtbV`gaCncnKA!t6Kk+IbhR dGl35-$=XTsix@`i@H_)@oTsaw%Q~loCIIowIb;9; literal 0 HcmV?d00001 diff --git a/css/images/metro-black-desc.png b/css/images/metro-black-desc.png new file mode 100644 index 0000000000000000000000000000000000000000..ef5f48e07e52c6608e913fda2aa724c3eda3cecd GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!VDxY_&1vXDct~{5LX~gJUF;O!w#sLuO!GX zn88R#j+05)@57y~)3P!xeeTBsWnw&C978y+CnqE%cqcG0x(f=NT%{qxuw(`+D{n){ zq6G^in3=m31S||#8Z|=MoCQ?RFtGl<$9OQiO+#Sol*ZJ1yUX=uB_wq2?agNMGTK|c loFORWyUdzt-x-*h87{7oXg6#sMkxrPKgI|jHK z=@~FHGB7YG{*!VpN=+O)ufdp~4Hg(Gr$-m$6$)@UVMj zKlcFIf@zKk$Q-{OMFr^=p4}Usb-5He1%@OTN-8AyxJFB@sFB%PdjD;r1bc(Rb%{r9 z&XSu{RkVb#8Dz$>%Sc)Kl;epBXQqVdv$ZD6@O_c=`{?PEIAe8z%m=PBoA=5bTcOPq z`BwZ7WAkBtqm?OA^Y^o0GYaUpBvtKGMr{+{%n6Hc?Ow*&s>s7)=+d4jBe=?~X~RW% z=A@w5&$jXg7CKV>Czcdh`e5~&5y!3~b#1TbDIy;vKKnHCsFfW~h)D{W(%Q09E+f)O z^ZY3X0cN?EHu8tnz~%%^!fFiAISPj+Sc*R`dA{e?JOjz&G7l8>oVLw96~1PXArBk3 zNO9us4W{3xGBz4);OyKzKUdQWt2sdD-1+x`Q}E`T(AZgw?`{gpL$+T8S zx1$Ck6B1@`W8`Hy^>n-v5k z3^p`qu(vq~sGeeA43P7%jc8xIK*3{w=Yj>s6O!06nI)M`Sh55ef+w))8BS!k1Dea= M>FVdQ&MBb@0IrQR`v3p{ literal 0 HcmV?d00001 diff --git a/css/images/metro-white-asc.png b/css/images/metro-white-asc.png new file mode 100644 index 0000000000000000000000000000000000000000..63327188b8fc240895c3e02d2e02e64e49e297c4 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!VDxY_&1vXDY*cj5LY1m4mYstac=>t;4BI9 z3uZ9p)Dn$*y+GkdYyN(qV5FyuV+hA}-7{#x{0(+XRRizpY<|VNa8}!`%^RxY>Xy%Fx>D?*J&AFu$MbY0 f)wDB(7a8Qwbqb|%)xLTMw1mOa)z4*}Q$iB}B+^)A literal 0 HcmV?d00001 diff --git a/css/images/metro-white-desc.png b/css/images/metro-white-desc.png new file mode 100644 index 0000000000000000000000000000000000000000..ca7c363e34009bdf9f61bfea526e410a9ecddc49 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!VDxY_&1vXDfIxK5LY1mjtC&A#&`*+l&2)f zFPOndM~;(8IMeUNw4Hf3%JYHZF`h1tAsp9}6A}`<6BroX1qDv7(hy--GJ}iShLSD9Mo*f5ZF4kG4X`v&>jX)S3j3^P6zuy4FF$-3-15` literal 0 HcmV?d00001 diff --git a/css/images/white-unsorted.gif b/css/images/white-unsorted.gif new file mode 100644 index 0000000000000000000000000000000000000000..9bfc3459c766d019f057f0557b0abf21319ff46e GIT binary patch literal 54 zcmZ?wbhEHbWM|-HXkcLY4+e@qSr{1@7#VaJfB+=Jz{J~=$hrD7-{cm(3vFpy4Aua( COb>nl literal 0 HcmV?d00001 diff --git a/css/metro.less b/css/metro.less new file mode 100644 index 0000000..62b9292 --- /dev/null +++ b/css/metro.less @@ -0,0 +1,357 @@ +/* Tablesorter Custom Metro LESS Theme by Rob Garrison + +To create your own theme, modify the code below and run it through +a LESS compiler, like this one: http://leafo.net/lessphp/editor.html +or download less.js from http://lesscss.org/ + +Test out these custom less files live + Basic Theme : http://codepen.io/Mottie/pen/eqBbn + Bootstrap : http://codepen.io/Mottie/pen/Ltzpi + Metro Style : http://codepen.io/Mottie/pen/gCslk + +*/ + +/*** theme ***/ +@theme : tablesorter-metro; + +/*** fonts ***/ +@tableHeaderFont : 14px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif; +@tableBodyFont : 14px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif; + +/*** color definitions ***/ +/* for best results, only change the hue (120), + leave the saturation (60%) and luminosity (75%) alone + pick the color from here: http://hslpicker.com/#825a2b + + Inspired by http://www.jtable.org/ metro themes: + Blue: hsl(212, 86%, 35%) + Brown hsl(32, 50%, 30%) + Crimson hsl(0, 100%, 38%) + Dark Grey hsl(0, 0%, 27%) + Dark Orange hsl(13, 70%, 51%) + Green hsl(120, 100%, 32%) + Light Gray hsl(0, 0%, 44%) + Pink hsl(297, 100%, 33%) + Purple hsl(257, 51%, 48%) + Red hsl(5, 100%, 40%) + + */ +@headerBackground : hsl(32, 50%, 30%); +@borderAndBackground : #cdcdcd; +@headerTextColor : #eee; + +@bodyBackground : #fff; +@bodyTextColor : #000; + +@captionBackground : #fff; /* it might be best to match the document body background color here */ +@errorBackground : #e6bf99; /* ajax error message (added to thead) */ + +@filterCellBackground : #eee; +@filterElementTextColor: #333; +@filterElementBkgd : #fff; +@filterElementBorder : 1px solid #bbb; +@filterTransitionTime : 0.1s; +@filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */ + +@overallPadding : 4px; +/* 20px should be slightly wider than the icon width to avoid overlap */ +@headerPadding : 4px 20px 4px 4px; + +/* url(icons/loading.gif); */ +@processingIcon : url('data:image/gif;base64,R0lGODlhEAAQAPIAAP///1VVVdbW1oCAgFVVVZaWlqurq7a2tiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=='); + +/* zebra striping */ +.allRows { + background-color: @bodyBackground; + color: @bodyTextColor; +} +.evenRows { + background-color: lighten( desaturate(@headerBackground, 80%), 70%); + color: @bodyTextColor; +} +.oddRows { + background-color: lighten( desaturate(@headerBackground, 80%), 50%); +} + +/* hovered rows */ +.oddHovered { + background-color: lighten( desaturate(@headerBackground, 50%), 40%); + color: @bodyTextColor; +} +.evenHovered { + background-color: lighten( desaturate(@headerBackground, 50%), 30%); + color: @bodyTextColor; +} + +/* Columns widget */ +@primaryOdd : lighten( spin(@headerBackground, 10), 40%); +@primaryEven : lighten( @primaryOdd, 8% ); +@secondaryOdd : @primaryEven; +@secondaryEven : lighten( @primaryEven, 8% ); +@tertiaryOdd : @secondaryEven; +@tertiaryEven : lighten( @secondaryEven, 8% ); + +/* Filter widget transition */ +.filterWidgetTransition { + -webkit-transition: line-height @filterTransitionTime ease; + -moz-transition: line-height @filterTransitionTime ease; + -o-transition: line-height @filterTransitionTime ease; + transition: line-height @filterTransitionTime ease; +} + +/*** Arrows ***/ +@arrowPosition : right 5px center; + +/* black */ +@unsortedBlack : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt0UjBAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC); +@sortAscBlack : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt0UjBAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC); +@sortDescBlack : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAALVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBoCg+AAAADnRSTlMAMiweCQITTvDctZZqaTlM310AAABcSURBVAjXY2BgYEtgAAFHERDJqigUAKSYBQUNgFSioKAYAwOLIBA4MASBKFUGQxAlzAAF+94BwWuGKBC1lIFl3rt3Lx0YGCzevWsGSjK9e6cAUlT3HKyW9wADAwDRrBiDy6bKzwAAAABJRU5ErkJggg==); + +/* white */ +@unsortedWhite : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAElBMVEUAAADu7u7u7u7u7u7u7u7u7u7yb344AAAABnRSTlMAMhIHKyAHBrhHAAAATElEQVQI12NgYGBSYAABQ2Ew5SgCIlkFBQOAlKKgoBADA7MgEBgwsIAoB4ZAECXKAAFQHkg9WIejoCBIv4mgoDOQYgZpAxkDNARqEQBTkAYuMZEHPgAAAABJRU5ErkJggg==); +@sortAscWhite : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAHlBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u4+jEeEAAAACXRSTlMAMwkqFV7roCD4hW+/AAAAWUlEQVQI1y3MrQ5AABSG4Xd+Rj0jiDabjKZxB6qqaarGNRh27tY5myd8b/uAeML1l2+wPqUlUd0ss+oNoZqG2rOwe15+p5iC1HNAK5IBlUjnZyIlZsxx0QAfzokSZgp96u4AAAAASUVORK5CYII=); +@sortDescWhite : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAJ1BMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u4RJgHSAAAADHRSTlMAMiweCQITaU7olrlu2HdvAAAAXElEQVQI12NgYGBLYAABRxEQyaooFACkmAUFDYBUoqCgGAMDiyAQODAEgShVBkMQJcwABWvOAMEphmgQtZWBZc6ZMycdGBhszpw5DJRkOnNGAaSo5wRYLXsBAwMAi4YWQHRX4F0AAAAASUVORK5CYII=); + +/* automatically choose the correct arrow/text color */ +.headerText (@a) when (lightness(@a) >= 50%) { + color: @headerTextColor; +} +.headerText (@a) when (lightness(@a) < 50%) { + color: lighten(@headerTextColor, 90%); +} +.unsorted (@a) when (lightness(@a) >= 50%) { + background-image: @unsortedBlack; +} +.unsorted (@a) when (lightness(@a) < 50%) { + background-image: @unsortedWhite; +} +.sortAsc (@a) when (lightness(@a) >= 50%) { + background-image: @sortAscBlack; +} +.sortAsc (@a) when (lightness(@a) < 50%) { + background-image: @sortAscWhite; +} +.sortDesc (@a) when (lightness(@a) >= 50%) { + background-image: @sortDescBlack; +} +.sortDesc (@a) when (lightness(@a) < 50%) { + background-image: @sortDescWhite; +} + +/* variable theme name - requires less.js 1.3+; + or just replace (!".@{theme}") with the contents of @theme +*/ +.@{theme} { + font: @tableBodyFont; + background-color: @borderAndBackground; + margin: 10px 0 15px; + width: 100%; + text-align: left; + border-spacing: 0; + border: 0; + + th, td { + border: 0; + } + + /* style th's outside of the thead */ + th, thead td { + font: @tableHeaderFont; + font-weight: bold; + background-color: @headerBackground; + color: @headerTextColor; + .headerText(@headerBackground); + border-collapse: collapse; + padding: @overallPadding; + } + + .dark-row th, .dark-row td, caption.dark-row { + background-color: darken( @headerBackground, 10% ); + } + + tbody td, tfoot th, tfoot td { + padding: @overallPadding; + vertical-align: top; + } + + /* style header */ + .tablesorter-header { + .unsorted(@headerBackground); + background-repeat: no-repeat; + background-position: @arrowPosition; + cursor: pointer; + white-space: normal; + } + + .tablesorter-header-inner { + padding: @headerPadding; + } + + .tablesorter-header.sorter-false { + background-image: none; + cursor: default; + padding: @overallPadding; + } + + .tablesorter-headerAsc { + .sortAsc(@headerBackground); + } + + .tablesorter-headerDesc { + .sortDesc(@headerBackground); + } + + /* tfoot */ + tfoot .tablesorter-headerAsc, + tfoot .tablesorter-headerDesc { + /* remove sort arrows from footer */ + background-image: none; + } + + /* optional disabled input styling */ + .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; + } + + /* body */ + tbody { + + td { + .allRows; + padding: @overallPadding; + vertical-align: top; + } + + /* Zebra Widget - row alternating colors */ + tr.odd > td { + .oddRows; + } + tr.even > td { + .evenRows; + } + + } + + /* hovered row colors + you'll need to add additional lines for + rows with more than 2 child rows + */ + tbody > tr.hover > td, + tbody > tr:hover > td, + tbody > tr:hover + tr.tablesorter-childRow > td, + tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td, + tbody > tr.even.hover > td, + tbody > tr.even:hover > td, + tbody > tr.even:hover + tr.tablesorter-childRow > td, + tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .evenHovered; + } + tbody > tr.odd.hover > td, + tbody > tr.odd:hover > td, + tbody > tr.odd:hover + tr.tablesorter-childRow > td, + tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .oddHovered; + } + + /* table processing indicator - indeterminate spinner */ + .tablesorter-processing { + background-image: @processingIcon; + background-position: center center; + background-repeat: no-repeat; + } + + /* pager */ + div.tablesorter-pager { + button { + background-color: lighten( @headerBackground, 7% ); + color: @headerTextColor; + border: lighten( @headerBackground, 15% ) 1px solid; + cursor: pointer; + } + button:hover { + background-color: lighten( @headerBackground, 15% ); + } + } + + /* Column Widget - column sort colors */ + tr.odd td.primary { + background-color: @primaryOdd; + } + td.primary, tr.even td.primary { + background-color: @primaryEven; + } + tr.odd td.secondary { + background-color: @secondaryOdd; + } + td.secondary, tr.even td.secondary { + background-color: @secondaryEven; + } + tr.odd td.tertiary { + background-color: @tertiaryOdd; + } + td.tertiary, tr.even td.tertiary { + background-color: @tertiaryEven; + } + + /* caption (non-theme matching) */ + caption { + background-color: @captionBackground ; + } + + /* filter widget */ + .tablesorter-filter-row input, + .tablesorter-filter-row select{ + width: 98%; + height: auto; + margin: 0; + padding: @overallPadding; + color: @filterElementTextColor; + background-color: @filterElementBkgd; + border: @filterElementBorder; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + .filterWidgetTransition; + } + .tablesorter-filter-row { + background-color: @filterCellBackground; + } + .tablesorter-filter-row td { + text-align: center; + background-color: @filterCellBackground; + line-height: normal; + text-align: center; /* center the input */ + .filterWidgetTransition; + } + /* hidden filter row */ + .tablesorter-filter-row.hideme td { + padding: @filterRowHiddenHeight / 2; + margin: 0; + line-height: 0; + cursor: pointer; + } + .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); + } + /* rows hidden by filtering (needed for child rows) */ + .filtered { + display: none; + } + + /* ajax error row */ + .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: @errorBackground; + } + +} diff --git a/css/psd/green-asc.psd b/css/psd/green-asc.psd new file mode 100644 index 0000000000000000000000000000000000000000..f492677501b08d4b691cd412b108c3eabd492513 GIT binary patch literal 32673 zcmeHQ34Bw<)}NcC>6Y%LYz0DTS?!W^FSN8xS7>QzOIbuAO>WcBBRjO(As&sYK@GQS!O&LvkqnMrW6EgCj8du%HFO5h zm>nM_B_ihf%%~h3Asts*E>##=NaYE#g!lw`yi6V| zOU+1>XCx#@ZAVm=A5gNPl zEJ(zfni;dQDV8zy3|c%4F$SEu%Ixnuf)< z7k1?C&_m}b&2$!^Bacl;1Zb+{08MH}Qc`R}GGOGSgp+Kiqtu|*);2qI$Yil{d6g_Z zBMCrGi%m%3bvQ}3*8#PuR+^P=X>pdd=@}M}A$EeC)F(!(9sl>LLapL!!f0W2q{7vz zcv?s6X~t}V+K{={hFXMti*si+70r*;ezJ@W#8i z5g*;rnfRy-g+XUvp@!(J#9{HBv7M^S5nZfMl(U9ft&YwzRTSn*i}MvJvhedVPFn?apM*Z-6FgYvL}D*;AUTnvHaP1#L1|SQVY$08Zd& z=eE{ZTAESJn9NE>MHlB~fjMzntvVwqKTV#Jnj%X`PfX62%VfFv3F&$Hi3y2G3CZ%j zObV5eXHZ$N-`Uivv08aSYC)gqY5xoGo0JWA34ZeLx%M9eKPgt8 zSS6EXB&TM`lkLy6{|oRP9;>QTG8$T)6>oP|JL4}^Un!pY`b*VU`hU5;(lTWHn9(atc!N^Ab~1ZZ|Z$o97odCrk7^zwE=kyKY}O2?=sVT7fK2k)KG0 z(#eS_>B*_71&Il=q~sKszx=WKN{f}rs$}wvr1XsB1W$eaY4!E{GpavSU!8wn@t1yn zaie_KS(bfb*lt$V`8OvV7rqLEZ{gzkui-jO8u%I2pGmau^8ZZTye>~BJQVH_9=O~= ziI?%f#Y5o^;epE?lz15rTs#!+5FWVPL5Y{~z{Nx14&i~z9h7((4_rJH?hqch+(C(# z@xaAH;SS+}%N>+>84p}M6z&inxZFXBm+`>GL*WkLfy*6~co`2|JQVH_9=O~=iI?%f z#Y5o^;epE?lz15rTs#!+5FWVPL5Y{~z{Nx14&i~z9h7((4_rJH?hqch+(C(#@xaAH z;SS+}%N>+>84p}M6z&inxZFXBm+`>GL*WkLfy*6~co`2|JQVH_9=O~=iI?%f#Y5o^ z;epE?lz15rTs#!+5FWVPL5Y{~z{Nx14sl1g{2Uuw&WLIci5O&nQ;JGaIg+DflmN5|(TGJ_xSAkTPG|<12^VpD zc?`u$sZDTk*d6L*cNy8w!UXZ5SW;m$Gj>zJ)Ebr#RA@}4d_ci63P*r3I|3y&Iujo= zN@H%|1NnMg9v=WS9IA6w^_sGpDJsaHz=jZPJfMIO*}9}cEtRSbmYQrs3$VDOkYzgX za&;Z$a#?lN7{*-CuR@1wh(B_5YH4Tu3X{%E_~lKy>jtyV%Iq^39>$s`;CSE#HGvAswvX$r*306yHCguA#oozhflz|asUB>s?ukwgV>cJv3*R@(VPxT%h&iS;@y zL))Hf_B@D2-0wNJupT%lEQAZ!N8lir8_v-eX-Kb#`^8x3Ax+Rb+FA=1b2{w36lUR+ z_;fj(1?&->7fK9!N-=7atAkXi%rZzux(56Rv0+Ly;YW>gIM-~@+rq?*3Qe6o9*4yy z*wKhK*=Fi z#ziVnMMFBe$y{tIswyq94-0(kY!_kQIs-c`N2k>=w!#N-g)g$Rq2%6bx>ji+!xY~J znl*PKUTtT)iu>1S$W~8I;D&Jea|`(hNPu>A*~k{W{< z9I6A~AF92sy*O!O1FTiUOsn+_IJf}YY*g#jnBEKY z;|&(<_`(vP=QL>PMxc)Z9j&wIwLs(1N4TC=LO&?Nm_?guRUOa?Kug%F3K&g_hQT9S zqH&^YoMvrP!-gu=|>Y zmBRR2MN4DbJMkY*=wz0Y9rskwwKN{*)6#12GA*Nl>Sokh{6v*%8JA7moHYEwWKJ3| z$@w)9VXJPT@JVqf_)s_!{&)b1!u*kN;>!?2@%2{XTMZLcgvRzc%lSRf5Kpcy7r}f8 z3QSt^SU`%3DyhoCHgF;$eDi|&K@bW@-BEAU4-JH8v>c_Pp(q>WqYo>7j93dVcP8Ao4$BUcYTid zob|ck8|)k7o8epLtM+a7o$tHKcZcsG-!r~9{6hQ&_+|Q4`AzYA*l&^F2EToNC;fi$ z_xF$TPxl|~ul1klzsUb}{}236`CpTSN(M_5l8F+F0{RDJ2TTYs z2Rs$9HegS{Hvv}z!vf<1iv!hxGXj?cZV5aRcrnN~C?+T;=>DK-K?{T43_28aA=o## zf3PB08T?T2lHl#ZCxS1BgoVgL%0l!ZPll`u`7q>MsCQ`p(ELz!=_ zg(<>RVUL8Z3fmWUCR`joAiOwyO8C6+e}o?lZ|xG=C8XDy1dh+B|;d{KcYB7 z7coC#Q^fIz>s@DIGbb~n1)+-@7Y9qV?zyR>_L_xkS7bl=+j z>mH&WgL{nb(b(hV9{YM+=o#K~Xirtoxji@a{4!DyIXJQ+a(d*-$ODm=d-d*B*vr`K z#a?@QUFaRrJG=Lk-p}=ZxA*xzVSTdtX!|_ZXJ?;(OS?#Oq&n#$>0W7T-^jj2eJy>L z_dVG6M$~|)F;TOkHb#Bj&#zxvzuJD!_1oRAHM&o9Y4iip>!ZJn@r_A~sf&3bW`E3; z{sa1t?f+Q+t^Lmp=r*8uz_bDD2b>%jFmU+5sRLIGJUU1`C~Z*vpqB=HI#@6`d2rp} zC4&zQ5e!Kgq8;+mki++Q-IIO~bI*!`A)6)JA^TZASgw*UksnPANGwR4k+?1KQqqtlI_c%4&y&NF zOOqc<-kp3Cc3@;vHl&HKt4m$B zyoyE^JyUd|xL2{Ncx`d(h}01ej@Ua=GO}{y;*sB$3@%|yc9aTAN0dHWdU90EC}z~w zGE`Pv_H5bLKNr z_ch)3;r%`C*WLflq@YR4NpDW}nml&$y2)+IGUW>8<(lG}r8TW8h3W;>59)07bL#VS zCcS_@Tbo(Cp!S?5Q}e9meBJQ6g>@IS3hiR;r71;IUYT;GzN~&ty;V0>w^8q-pRC`` zgfjKaUPEs~li{#&h;fdwWopLM=cl%^BiYp^%5ic?QwJ;qEst7GHDom`X}H>0 z-S}oxNE6d^pm}if6U}F*6-@j4bkTIx^xY5iec<5-PCc0O;PQv4hiV?$J)_@@*)z_} zES&l3!+sCfKm5t8gjow_{rbq*M|RBaHGAgl(~lNDx_(aJ9Cpr$$A&)k%HyKPwT~Zs zBJqhApSU$wJ@=z|3G)`tYkN}lK5MgJ8GSBh6Qto(je^{V}UPy74Y z)jd|vTYYm4v!>jmpA>(9S7@wHF?k@t^n8)7#s-x#rR-s|Xf z%j^GsWAYovH;vr1`^~gBH~cf^pG!A~ZJxV@+S0tGb!*+$mTlv=9o{}-`|ce>cWizu z?yWU%_kDZGJ6+zH|E}M=v){GuoVN4wF5|8X?`hsUy?fH`ul9`Fb9C?My$AP=-1ouz z1@G_KpR<4G2bmwd{b9z3+doSCXzRx*A8$F3d|>k@$)9XKm~wE-q0~d$K2860$Khdz z-#s$?$a|mVefIv*;-eoQ8+GjP@iE6gKQZw{%jfFP&wZi$;?kE5U*7m?=1H%UbH5J$ zdf_*b->mr8pnq*_NojfKRNkor-&TJ6)oIn~AHFkv*LG(1_W|E8Jlp5&+H>-AZ=WwX z|LMQ){r8z4j6dACFz3gRAD3Pnc=4YtnB)tf06gA5kEC*K-ok@0pX>=PI5# ziDym%4dM?@F8*LL$k6%l%t<_R63?8(Gbi!PNj!5B&z!_FC;8u)lURR567ttAlN6;e z)3}HNNeHQD!pMZOeuZWuiI0zuuaCsnR}$jy=O5A~NFoX9(k(2kOITR95D7VKH!jfr zN(K1)2LuKL2L=X*2L=X)<4a&Tmn6g;1=d|C#0REE!9pqu2|_4g2xa{m-Yinqz0`29 z(hI)wgu^zJ5+X_<@)CRd`1<+7@)Orc3JHYv$Y4Z?D4{?k@bVV>cnKwm5E&vA^$nGI z<&0K_MNNHJE)IWY`5U?YqPtYQSCg2;&N{5{j#*IIdg_wOlpL{Q(3U?$xAf0%&ffEx<@7HF1D;#;=s%y|d-S_s|Gs(Ou``#eYa8Y)T)pM} zYkf&&jln*K>n#Z7AT_KNtAPbQcuiOx&}KMIgffCe*zZV4VZB);tT4mVXfn@^0uoVi zrKM;v5I)G83MEr&ydnuvJ>Z*oEQ(MK)sv^EPy=l;0*I8s+dYIL;bbW}q4C`PsmHYB zr8Z8x3eHcFU)z@m!RjB|{SJSGgz&!`Wx#(x$mQ_5i~DCHP=SQYD2Hv!1ib#>WkLsy z1>q1=@FhFkDg6H5Q4XrNqa0L!=W+-ryACQ&;LuH!!3ExK5*)}KBNwy`M^TY_C8I5_ zD5wCMd{dFb0P31rdeqs)}ym97(?8?yip0PTWKcCL8S=RSCM$e z#6p}%r)*|PxLK>lVK{?uSf#7c;V_08hqX*?lP#Wv>zR6kb696G*1CjMI;@|s2du+X zr^k8l?LuWSk+;^sOM=r;*FN}9;PBsu0T&zK3s%xBUXg^|Hs`4C>Nhrhzm?cg+r%1e zY2oHL@LD}v2(LK^Mqal=oz&2M*gg(>Y_k70xM1u^D}+1#PBF+<8n^31!qtZiUIH88 zg*%6PZIc{eA*~5mjxyWZ8SX_;a(Wt?6fTCkgH;dnf>_s8@&wTt69Ed#<8i2Vs(k2qN5Va0B7%>xhP3CyKt%H27h;4H2*(zCzH8|Ni z3Wuv$<~BG(3@$Bc!nbp6_mTL|wBdH`VkAQkQ&k-do$Ep-}QslAEV`<6--iyIh%IEAZGo%SJy7NQAXct>~Q@y_GK z1I=Z2!?P=P@##(K#tzn$>dg3QfgsKeYj{;a*sXEq*{yNrf#y!FscC>^g0K!5%VHYe zD{FI0Y~f0KTrMox!@P1`eht1`G&&96&+C*9|H-}|M{`GsQm3~2mD7@CWMVZHJT&9& z(qMqj!g750eS?n^zd@JhWQYmJ6f;sOzGMG)t-#7UqXHs`S2^{a(TMxRLm!HNtAhJb z3-rAv6p!*?5K;?+5ew1*A9G5eKW2c7e|nJV62h4x1=}FC4Jh09qHMX@o;&tw-2aj! zwhQ)WXP&F=icV5H|FXoM+KCsaWXxKnPOCH(>I^1Fo2;xg+Zt38sX1HzJ{A*QS*JA8 zWGOQ+{eXd2idtAZ3y(Q;@HB^x{7DcX>)%y+(rI~PEzrubh#GtfLWyt+xF;1*crZqu zT5u-^megBxQbg^vvuq=`yGw4+=y2|M%IC-(wXMM)E(7>GTn0g=&O9xbYRK=Uf+9L6 ztDze(hPY!FkRnnu0fw0b2AmCFNZW5QK#o5|J9m=7BKIo|o(%*}1^=Fi$HP%@l3$VF zu^vMGqTk-$3)X|| zKVrJcpC)LQZit2rB z)>~GepQ|$qN0wFId+a83sD4*QM9Z>@O3Evh-`=tYS+A9Z^oWsX1EXrnMQbN+0Ga$o zGWli836jaLudUf|l4Npu)shvjZahOWx%~Je&o5oEcGCrt$yH{8Va~#rR<7IpGtT6? zc4+ZL_K6o>TD5-rmD^-uD~WnFSCYwP6&tydOvc9VS89KQb) zSCZgv{Sq?sp$2Pzbjbu=A|LE3*KDqGop+TR4p(V&a+RBQSD{*CZ`oW$2(Dt&g*E;U Dg0Bj~ literal 0 HcmV?d00001 diff --git a/css/psd/green-desc.psd b/css/psd/green-desc.psd new file mode 100644 index 0000000000000000000000000000000000000000..bc9ffacd16a2d4f55ad381f96a997c23c85528ae GIT binary patch literal 27807 zcmeHQ349aP*1waaN%x(yLnwu^bxHRYTH2;fTWD!%%c=rtGEGC1Nth&EaA6TaK}AuK zO<6@2A1FRnL3Yt6qM(3^`ieXRT#!XTX(8Xacallc7R*z>-}m|Z<@T4EbI(2Z+;ji; z+-2s@Ow)49DiDRZAc9jc`FSHD#~ME&Ew`vdgi{de*^L^HgkAd-v^fh95}cWYh-@Ds z8@zX=?Q)^Y}>d2v4zC#)^8uUgzZB|Mf^g70r(U2LbR2!=344^SP zE>cQF%(a=3IXFQ&wxmodH?XucIW|5<6`v9>O_9aQ5|dI>QwK>C;$`u1@dg(%c>l0%QtR_yDo}P}?BqYRu zM2xACF)JHl7*lUfiCs?~ZBnsXqgiWUq*$-A%3v{PMn>X-_+YD--pCikm|{sCV^s!y zT!YdWCyR}b<26IZA%IDSoTZg!16ye@=(4z)m(>`|22+i}D3wUr+$Xr`Pt;(o2uzICAOKCLfv??WT@VGigZEHrOyd{Tzopfj-0LUdN*khu2PPEF=WE|Sa3SVOf|M`xMJ3v#7J`SKK5dP+)6LafYL zjg#D8U3qZvl9Ki-Ztp*OeO!C}&ScK7gDz?7;x3TcbDAm}jdWZ&Z8BI`6`fxPPT=V0 zw%%A$l2OE%%t}T@7v*JvIk8%;IwMJumXMN~B8yK?OwLb`$#V1K)ARBZ;}etOlN0ii zb4j;y&FX|OsZ>UuL1n>yXH%=jY7-Qxid0#CN^)9WzDy=dPfE#8ON&oQOwUhG%+E=- zt98oSMr|ppg;7|kbCSVU|2OK}QPHNDLahnLs78BNjz(&`~`E?kFMt+Q#{X|&%(m(%T(_1^mHYiQ5Ec3LNeR%uR{p_{*3!gDyWK{gp)PA>^;r&Fk_M!b9N>;epE?lz15r zTs#!+5FWVPL5Y{~z{Nx14&i~z9h7((4_rJH?hqch+(C(#@xaAH;SS+}%N>+>84p}M z6z&inxZFXBm+`>GL*WkLfy*6~co`2|JQVH_9=O~=iI?%f#Y5o^;epE?lz15rTs#!+ z5FWVPL5Y{~z{Nx14&i~z9h7((4_rJH?hqch+(C(#@xaAH;SS+}%N>+>84p}M6z&in zxZFXBm+`>GL*WkLfy*6~co`2|JQVH_9=O~=iI?%f#Y5o^;epE?lz15rTs#!+5FWVP zL5Y{~z{Nx14&i~z9h7((4_rJH?hyBd%h&N@FwMZ*!1eIjFL`e`gS=C`5svu%WbS=s zKO?JU%%v8y(P9QBc}2O*WUi=!mtcuR5o4xl#-hi0F^$i19gE{ZByWYb0ZZg+%{UKE z=5*5R2&JB`%pY3`tgc9ol!!qF_(@R-Dnkh<8N~x_LNsEL7LF!}l@XdjX2M0>yU>HN zQfdnv9Cn8~*u43cI0)|o!#mTqwk^|? zne1(gX)Fn6Y&I&Ut2s5Timil~q1!9ALZ##QWvnWD9M-_Kp719^2BSj32!MvNpNU8I zC24`=NDf1%+j3nd(E$HSR>_#)%|)6~HFDn2fu!_+V*siIcfoFDLPj{V;4}kecFjB$Idu9HFt=q;@B%q$^-6h1W>j7fa$`^U45Tst2h{XV_Q(}{nkoqKIt^n7+ ztQo_40@O}oO zVmV`Wa+e^D&QPV)!C0lLEr$2AN9&5oSPE72sZp9r3>X^Xgv1|`Fp@|CzqbBB`bsN* z2shQxG_hW%WoX-MXD@?j#G|2e59@-X!Xh|uV+4+JrQs5Nk%o+wc(jZ`YBKdYOIIF9q;pG$BSuqU)%EirtngHfAYU8G!PmO(Z$IN+(phAPp7ry%EeuGyfs#fcf^ zni_jLj*Ct3r3l(&1BP-b$BU$a5MCijNTevwNw-A98Z1T^me@dE=(o*}{`nPHJNJe@ z=m=0+%!UG*!JUv+0|VhV>utimoG|9#lp?)G3a9_=`U~OH8n)$@tx@oR;mRp7Y3xff zPDZTMnJbkV7pXuM4f*H>bCIdAvZUC)T=2HDU4(sV4D8e#omRuxDj&pEzR=EwnoHDl zwbDYCFFtiNYi>t;w4LoL?pLKDpU`juH-yulTfiqk7Bs@ZV61)21|#%z6K!`4oaU98_mQ*P4k{H2PJ*4>a9-Jm}gf_W(ikr7SjVUaXN}bZ&AwyI~ z78Z$A83-q;;afRC&jMOkZ#H5+wmQ737Sm)t3TMGUpgUo{hNA}&8II1zv|7)AgA1_D zMzvmz=|ez2S!cnHFDwRncAb{42l_LhqjVO%7HGWw2-nj}7zsrfvnVsIssTD4Xn(e{ z99Eg4AuwtCYnhz_97qtQ|u4W;$?PI6fjK`S7~}yyU$Jr}AQPdHiQ*q=;x|SJQa?PfJIGmuVRdG&iHx;yG2SWn4av zYjNzSi<2wQU(g-?t{!5@bs;ZH}AD9jHDAAA*3D8Ai_eMZ9tEJ9;?Uf}#5 zXh2%o%Qjt)ZMs59z;dZT_YODCXIG#F*0d^8M| z!gbF$Gy$%3YLFgg@_O_Lnt^7cdFVOx5?X?mqcvzf+Jv^C?PxdJkKRKcqEFCCbOtq{ z^XLb31>Ho=6h%p>04j{?O!cJtPy?w1Dvipb@~L8~oEk?>qBImkS*S;-$EkVL0%{4h zl3Gu_MeU^aQy);rsV}Ir)FtW~bz2}5_zS`X-35IGae_2Kj$pW;Qt*&KBbXwXDwrjB zRniA7-|sVGJ?SX3w)B~po|h#nI?Em|U4C)y@DB>GfzR&+&l*DJuQ zo7X_E46h=uv0fUldav1D3%%BQZS^|rb<*p+*G;il93hStr-}>3m_omEIh7VIi`R(hz;f(;*u|J_xxODhcfynjfkTofWz| z^kC?@Fkx8lFnO3N?D4QQVTZ%chl|6b!;8WvhtCWDNBFVuD;+{RBy||wp`pXl4tqK@ zMF=DMMifQpBIZYIi8vK;yJPo`IUVVaPj%eX@kGa4ow|0)?nHN*+i7#BlbvpNmUhnX zT-*8i&f7bG-9^-8K$nqS>btz!<#3lDyM}ii+*Q?eZr3eczw9RHHlSO1w}-o}?sl}> zjqW|V7j!pvU)=p*_aA#i^vLcpxyOq=-tBRzXIRgyp4y%-_T1a^dua!0j#MXIBt0a( z(yLpq!d{kMD|;R5)f^ceIVy5ys{UZ#oh;cUy14&RTA|`)W)bU`}p)p z>r>O`r zKN%nxkUXGfz|sL94-^bc8K@oj%E04;yauHYVg{`mbUMaACMTvYW@F6R*ofHT*qO20 zV=u==#f^`9KJG}|-T35qUHqE(GqOGR~U3MeB>M3`-sM=&(b>{fAc!Uo!mL;sM2M@vag<$*__a zO1>J=X9P21dnqa{Dt)2!>$2#wDP`}B6pt($xpd@r<+Ace%8yipRZOhdP;s*|w{m{v znNj^lSw!I-A8abq7H`{B4QnV_4nXJXJq<;1rqc}*HKX~U!zWvOzN@;e3Pn$LE{Pcq9>t^`QsGafA%=noLX8!W{n8$a`>OO1wtaDEkJh5?h;B0pG={bYv zEPqn;r1r^UPbEIJ_^G>d)pP$fFMi&_c`Z+?p8nS}vS$`OV|}*z*<8m%r@$vgPHbMa7GDERI_I+~Src zHA_w|&0V^AS+`|RExYxK`jr!}X1}^=dH3b>mfv2XUGe$Kf|c7=^hIQ! zUUTHNwAa?J?Xq^>+B>f^uQ#nLUw3GI>iYE?x^0-hQLxdn@zNU)zVXRF^8T@7Q_QB7 zn>6%(_zp2cYWWT^{#dA)V(+M8Tb9TU$g(*fr$ss92|S_vqK{f z9XmYy@cZv6-aB|C=g8joGvD9+LBj%CT)9r+&QS zlk`t^9UpT1-4jDk?Ef_H)Av3r`s~A#BTgPaHR{yoryo4s^tt-;i(lxzxcX(?m(6FU zf93Vn+^>VbUieM7Z&v-g|Gzgkr8Mn1n|Jo;w-w)>Ij1`J!+%WwX*oaZyMXT&Ug&vY z{l$cfyDup&ee(SS-=F`%_(SuLvwsTtY1!p|m;d>5_RmMJjJ?dj{CufP6F z(k};Yl->B|rv7I0t+~H;{&n4NX}=x0J?8d>=K2;%%c48|@9ere{O(s)z12#tHNwei z051lDNF1-Akzghq@OmQH_Jg&w5c8{1Cq!94xBi6u$%iW^%1a=A83mFUQcnjV%6bOP zLjK;~-ag*`K0f{-e!hMo9fJJ*gF18y3+oUT)+xlF1lx&=v_4V+etrRg0l|TR!Qp{{ zf#LWN7|vx0aYuo59}4k?3Iq$ONF)fMgdvpmYq4I0z9X5P69u z-afv5aP!zTkwOBYJuw(jB1$L_3A`j?Z!e*LA|!?gMZH30UO6L`VUbg2B#6VGU-?#U z@2C#t`>PU@*qO)Wl0FM6uAIH9G9^c>+VXhcyca6f`3F{;Q#zg)^(}qv?O6vuwVb=I zh<8S7EFl@^GcZUd^omXfBEq%iBVN&*_jLE6&+Njq^o_z*Z@i20|QP4Bxc&&-*lh!`xp$efCQ zru9!eefZNkSI6BxmU%?da>4oq@y1@HaYn(Bv{Vqvf!jz1R0X$^@E%SL&}R6V2xSDZ zu-}o8!v0VN>!)03%wHW>jV z%HXOSp>FVFsRTmfKK1MzExFl*^R9v4C&;(uON8LQyzP9S55FS(HP;N8EF&QSEfGISZ@&Wx)yIqb2?e(T_Xu_Im&XS}l*WUEcT z-)jeZx~)BA1mEh01c1Y?&rw%<|H7juYPDl~^s6aH@MsyRSDIiqOfj~iUTap>*zf+L z3WGxHa!;LbAOk7Jd7BNDz;?HNUm5R);nGGx=f&qzqsq2D?bs*Ae0Zin>Z-oo4fLGp z)1IA#;tL5wTh5}ODApPCbScW|AJOAs)KDicrpOX zVj7<-s&k8N@d|rdE^MJ;UYRbx3ZE?+orWLhbxMc-WKY1!TqsuR)ONpedWZm-SWP(( z%{aR>7@)JT93P%T@^<3a>GGTmG2xUVMk>W;?EkI}SW#n?Ljv(Cr?E2%aer|zhT><+ z@EB@=vDbv+P#!Eks$mggK|0`LPBDzf3~=!yLYXcxTqu&WbyC|xvh^s+mYMCPW1q(3 zFUev%V1IVzx!NvoC%5wxVD{Wjyg(&m)+%*crKvz?Fgf~UMYY-1p&Cfb*~<5}nCOZc zrI98N7XZ^278Ry({Kpjl|Mr7HP^dFc%jFvQd%2*B z&e^KyI*cJ6*af7D)O3JhI)MQf!&j1j-U}pcL9}--StN2#OWC>jjB~+P;_*5-5`N^l zF1*G=sCU%vo!#LH4ZJ+G)0}*r-c$?BHSi-7$X|YqF>cmj)b0JhkyM69}1O?AK>Ui+(6 z@C-t5T|Vcw6)nDt?jZD9i>mHvL)QkjOH~BQ9YcMF_ zfcsUM(u}7eLMuwhnBmV|_hByV4Lkc~2wZ~(!ZoDLo;LpaXVYRTD@N>DjA96EALqESS52vY~dXo5#O#G zRxzpUo% z+jiJ0c7UtbTMDis6OPz&!u%{CXh&8zz#bHqor literal 0 HcmV?d00001 diff --git a/css/psd/green-unsorted.psd b/css/psd/green-unsorted.psd new file mode 100644 index 0000000000000000000000000000000000000000..5f6a8701eec903919de6fc05b4357f8f1d65f28d GIT binary patch literal 32412 zcmeHQ349aP*1waaY14gU-$E&r#V+aILJMu$w1t+IwyesMCet)DnS@Ew1yK+YpTH9Z zL^hF45Kt6-tPf>XM0o2-Reo;E9`b$T6RO0Ua^P^t|TbUM(O z9UCDfBIfFhh%6i-9aB^yl^a-EniLZkt%^&IlP1ezWC@8WDJc(0#?&Un7+6iLEG;b!tBH?~ z28n1>J!4kZMKh*eoD#d99NMH}wMMhnz(}!PWre|F&WMP>8S#g$TzVs)5o3xWWsFf7 z^s#kHW2`JDE|%8}2?qft>2j7dR)1cVa z!j9Y>dgvUbna%`s;-ljd0Gjf6fF>n9F)=zW2{3X}!b!H$QDjhSE9)IPWU}b^_;OiV zdSXg?TvBvgGOxo)vb7GVO|{ajbW4k~tWD3LSPZcfjgfT2C`(6V!&xwKmkM^hyJ(SDG`GMx#!vQsN4atzp!*YBbvGWl*d`^v|}M&xAML zr5W+j_ckUzDqU{S8Ca+xIx}HVY+G!nDsw~^$mJ!hp;D`(Gfky=+0uesd9o}mIXOB$ zM&_)>N$$@sJT&p5qP7ce?>~BdY+L=#WX`RDE@|uHE|A$%n#${qbZjYYGFVs@om&Hq zz|qfby|Jh$y?`;9m5hom$jJnAVzgRydSXs$d~!;%EG{h}DK}mw%g&8U%gIfMOGu1M ziqA>PCf&+4sT0DaQ0X}al?Asun_4wi8?Q)Fq{woUlTveXWinY>VsdV3YFu(cT5eiG zZdQ_Aty9u_)E2W^7=@KOCmC$@f1%9=k2e$sC>?cWD} zVsv~$xlERxl#(6~_ap9}_P+tXqs6MKl#GT}XU5tatDW(es;^{Eef^c{OO}|WNY2ek zNKU@rt>cgMFXA&Mqw8`G2NvUY92m9tw8|4_xk`#LIZ#;-PSd@WAB`O1z8*E*=VZ z2oGHDpv22~;Nqchhw#AV4obX?2QD58cL)z$?x4iWc;MopaEI`~$( zT<)O6%Xr}8p>T)rz~v4~yo?7f9tw8|4_xk`#LIZ#;-PSd@WAB`O1z8*E*=VZ2oGHD zpv22~;Nqchhw#AV4obX?2QD58cL)z$?x4iWc;MopaEI`~$(T<)O6 z%Xr}8p>T)rz~v4~yo?7f9tw8|4_xk`#LIZ#;-PSd@WAB`O1z8*E*=VZ2oGHDpv22~ z;Nqchhj<`dzK##?X$HQwuZ7R*$#?nbX7ClajX?&IISR4)_Y0I>ASRz|%#%XXgr;}!fEA@1F?wE35bwP5Z zL<};(Pl}3A35rKaC=O^7q7jR%y-IbshWH~} zreS!gs2QlWaAj$eo*Xt!Dkg^-%!bR>~* z2%Mp^?uqS2Vo6uPRtm3@urHRxhpklx@KW7LSvt9fh1W<}Le6mFa*o0+7$IMrFF6Dx zhwFsSN3oTa5Tk>$m~bc?XZ6x$JSQGvC^Qbvb{Sk63Pn3OMCUCCBf!OGHD|lyEc_lv zJHpP?ABiJaVAZf$2qL8u!M-7IaMp78#}ST@qHOhnZO0NAm0+U5hj48DT`&Zc!Ow<# zGN#b0@Uz9^AY;+t!H1+9#hMtMfzd#i;7l{h3VXMez*v?|!|n~VlY|d2vntIr>%>E4 zMwPP`U%i$oh7C=$=6ahHu5n+zvd)!@>j!1)m?E2$Hz`j7<_d6|y4PlCSqQbVSyIWu z=vii_jjp4Lt(X{6ToRhaJA&A93J0d2nq~}Ose>&TgJp@jQv9Vn9)>c3#T_EER!_U1 z1x|FIEPT`!Fa|!!cUxNrsAdJ!#lJOLZD5+AKiVPSU(g;a=NW@4Y1^n)952U}eY7gP2Dw-zN>$D7Q zyW`pOAR6(AXuE-vaAzD8j)0S`=ixBP4d)n$G-SNQBW5(RkTKK%9DL(dL%e-_!fEV> zGY{*)KbON9A)Hgt(5d^>UuXPXUrTbP(ps;RQa zu0388J zi`kGzGq^L-7(9e`v9JmIa>AH{V+!;dDO~>BHa6GGRw;PkaOD)4G}*$YzX}c6uEq)65Kez~9v=Zo&~O8Tv6h$(M(FV-+TJj5oUaZV(mh=N z3WFIM)IEGZsP?MX;-q)=#mbOB`~-s=3C-Qvf(SbwqVfy1j6nd6Q4fA1-X&+u*l|+t zkKwK;fgTABU8yn|i^>$(Jw~vDjudaD!)YRCsFNF~xqkR*bbg6c>J;Y=8KN?>;4o4p zAe^9veW`$+1+=c#Y{YzQb$CTJrpbLNoCO1c?uhvsj(&*9aP$yNtMv>tZ~?a2sMf17 zeF*5k)mU)D7Zw6NyGBdb0(}zbNS#Hm1seMz;d)vLBccdn7HOtcRY1o9?a!8%g2yQu z1UGMgjT2qrM4O=nf-I67jP;~Wq&X!f$5D(27ExS z%s3Say=R*u!sbp7jC7KF5Q*!Si@!F4)EU+OsDtN7>EIdGfHwnvpYS;cuVN`eJDx(Q z;};HIBwSokhd~cO%8JCTyoHYE- zWKJ3|$+c@B!q(kI;S*y}@Ud_t{OKqXh4~@jBP$_>;_IzYG727M5gOg&JFeXW4e{jc zauUpkpunUhw*@3GEtje+Yz-$O!WS=iS_nens1xdrdZE5>w~j|CXdoJba?wy!49`Gg z(FAzvsX}_Vf7haE=m|6%%|*|l7tk{FGFpc=qAlnxv;*xy`_cR8BXk^{LT6C}x`=*2 zjpzny0zcfF3ZTNMPE-%7H#LBYr&6g*DwisxN~y8bBuYaul!cl`JxR@_7EsHm)zn66 zE47Q-PaUC7P@hxhsY}#V>W)At@E3#&x(WISVg;#!EWt2AxnR6NBbXwXDwrjBR21h#nWs6DGfzUeqYM>lNVD)oXxP zx>teM7%z=it=DX?#a`>Zwt2nhb;|3a*A1~)++G|dP7&ve$BHM59~I9Nza)M`yia^W zd_jEO+uOU7_W#-I8OHi;^ba5Z@@@4Bv9!$-YncF7e&s`=0MP z-)nw;ei43Yek1&}elz@*_`T`(f!}$*+y0^c{r%h6o=?T=7nquITG@HsCQ_e(A-dU=&aDSp$9`R zgbBlXg~`KIVNZsw3wtl@Vz@XwD!d?ka`@cv*TX*!Z)_LZF0tLHc6IHRw|l2uLwjNS zKJ5$I>)Ow6|5p3c?eBEx)*-6{-Qk%ITRMEw;bzA!9fx$JJI?9&M#obf?{t!O%I#F$ z>G@7OI(^w$)VY7>5uIy0uk8F@=O4R-cNy44)n!hXx4L}MRnWD6*V3+!c3s=`XxHoA zx_8U#X6&}K+re%>c5mN(NcYLz7j=KP`=uUXJu-V}do1d)x5s5^J870wCtV^vByH^3 zwP$`$OV8CkKknHS5fw2qVrIk}5nuN5?UmZAve%+s2YNL|_J}NsoEEt`@{8V*-l@H- zdcWBFaPOOaqWX;P^K_pbeZG(C7*!B8HEMIzxxN8?2lt)QcTL}u{lxuJ`&IXQso(Mb zg8oVUtNJhRe{6tYK=J_XfR_fGc*yIaw1=37);x43+CMrgx+Z#a^!b?fF@-TRV|K*+ z92*%sF82A@!?AbclHzo6>*CJJLS;i`GiAGFSL6G~tKyf(pG*iyP$W!G*qLx8aX=!S zxH9pxq_Cu-q^FY(B(=aUa%}RJHHaRxZqS8{hzw=M>Wqd=Y38KNRhbQgdk$6(UNiWcA-#sE zhpZp+T~@!W$yu*u{hS?_&1P@Qz9~sJNhbVeywGQ6*DK{y9QCqGZJK5#N@|N~e_`E(5qxOzjiRX1Aq zhTca%NxzE;WvZD&hVF(s!wKU6<7{KYl=LYtOlf3?vFlBgX}oEtIUJm+qn5swr!41d zGHaIC+^QW_`*vMO9aDF-zJL8Q_1{fZOnv21(W9zI4@~Ph?TKmUAIo}d_2bmz6^|d7 z-fQ}-=@)0@&3N?*-zTb{_}9$1nG0tA`sC;*chBlJYsRb#Pvt$ed3NAzcJ`U42R{As z-$Z}Y{_W#u5}sN5%-uQaIUmlAo4a^!^E}nO5C1Ov`;xy~pRIiMa_MtRo0nBB zJGDG}`5P;`u6Sm}&6m_KeX?@M$}KN*=?Ky>;O2)VH_%qxU~nYzx~qXFIjMetYANsvQkG$L>6_Yv`^6 zy9e&x_RpAqZrIav&+>QLy)*w^-*;!dYu!6_@AZAgeLwEk?7whe;(@aV#~eI)XvCq9 z-y8Pc2k$H1KX^Fn@ZJwHKG<_4{m8BlQ$O7CQSwLIk0u@6_OGOWZTmR+%j_o|2 zc6|4VK_}k*Wbh~ZKh62{{gVYJKRPx1)QQt0Pk(mikuwdSsXzPvbKU1xzNq=4>FkVi zUgzd~8T{qqueyG<=Ief6ztND~@Xq<1^GCla`{wKg)rBAaZTfff#aZ75e7pF&9^Y;J zKK}bXmlT(dUw-)V#UG46H2paHr;wjk{M`5FfBZ7!m!pki8ZTa9uUN0nyVmL2hF=qZ zJ#f9``d2sfH=1tFxz*{`tG82cAHFmC&Ua0<&ECyRTKcu@zB}yhIji1kCC?h+#2diQ z05>;=J!m9Y4JYhR1lxY#OXIm_!BeOsqO6};e?tCblh}#!A_)JC0!av|XMhl8J&R@` ze;*$oiI2ZT;veGY>le~4$lpJxUB|Gnc41*1L;T5MyKsTlXDYzYFCZ`=I503cJTNdY z9G?Qixg;U(D6sBBAwE!mU?CNO1R<0#gtC4K&;OM55H%RA^a95O4lo!WLPQBfUSe+_ ziLW0_B)djZNFcOF1|v#D2?Zj7m$%r*OX!~fks(4+&rq3H)(B--#FQuE#o^Dd-kRMj zvR&!^iiAXV<_WoX?*(Oz=dY+tN$uCX^<0M?3# zP2OU!Bw|8OS*Qpsm=Y1@75~KZ;n;%xr6(E_A}h|bGZ)Cq+Nn&5S9*)F0p5L*4txSe ztnHxA9hq#Vzu`@|zXeea6Rck#e<8^;1Pw+%-?=&Rqg9VB6ff89I{0;U$8Syxo3;pV zAG`CEYOUtq^oY0nZ#eU)c#CP6{OMmNXD&E==fcxxHVQZWI&Jw!W6+Uj&rZ?~WEScjd@?VFzTb>p1a(YsFX{r1h1EnjV$*idHu zoO>efNh)t7oJmavp)8nSGN1~WXu|6~RY05JXCjml#KL|ZpBR9~Bn03v1ZRE|(r__0(xp>dyk_GvAd zjKXQx!S6WoZTDkEG7rfT{glGk1n|UaM-4vu|+6LQRY0Wf)s24)8=HGODd2e6Kz%BsJ_Np6l{); zn|R|^929IGKv@a=RSPQ=IZ)h0SYmjHldhJ8}GSt zF{dFGOE_OCbP!gmro*rG6?JA>37N?AGX@ZdmuWg}h!p|n9$|hya#${t*ziTTz zib8XMnHqBR<<`z{st5nP3zhXWD^0+9bQT6g|1aI?)iDOtaAQO{|_j>@X@bD6}qf?t}vgNH)&Pai|EE#_em+ zc-0K&HXJ%Hz7`u*wxw*xnlk3Y`v+22^=&S;XU&-Y>?ACY5Wm>2ncmQM5@Ep_oo%r_ z16c(P950Vm=v*~p4#bf)I=kVdoBtle^H`bV7f*L_d@*c1AgOy9C@so0fK-& zTrZW{=GVR9o@ar3B)(JXc}ayGI7p?yTsgeCfv@=01Tv7mi9_50pxFmffol;V2Io%d z#!YA^4*M0Y;`H*+g56XD$K#=$(7W^beH_ne+8$RROwb}U(!>&b3sq+OQY#TIQXB2z z_&;pxfM$`ffv9yfgP}8!*CdX|+uG0Prr0Luo~`~Xum&evhvRTL%iITNh{2^LH_-bv zZTFG*&$Quw?P4o*dbo`<8Xb9=1BiXf8JI;5=ki0_D#y%1hLz%LX$|XmJ0?q~A&Z)% zN35X8w{jcRiYF*FcO_{2AKCm!E;oOqzQ*lzfc(tUh-le+dE zYl?JcBNl)-H>}}R0b#esnP<1gnFpHNw5Fm4mi6Eb0xXMZd@ZZYF0_Tq>~Yz!#D;k# zy4(tUwPLswhD!)%isWpK)aFRG9!1#_vpsj*rt$bolGskTJv;MUZI`!^+WBoU zduk_Mppr3bl{&4`l&3S89DTB^(roKcb)@EO`TJN*bXk?sNRyWkfawbiys~Ry?JVLC zz}*}M@_8UY-ds`X$)M$pwLmY&B5G(;5K4fbfV)!xg`F^R*MciKu%zCilOk%bon`ab z{#bH@Mu&69k9v;WQS%1;$7KNjf`>tnsWVT@r5f;Csi26?$tvg?j3FM_1*C}741i$< zfdOa37m|NB3?yxbXzyO)Byw+7*}3?NQ^9|1zmjPpZ<)oXvb~T^@BaA^_3!=(-kA{xl-tk&zGoX?U>eAT)zAI`LOa$ z;_vV0i*Wq^X+M9!wlc#t2`Pu&&)?gWfRDJnjZj0b2fp_PqX+x>6}Ze!e*R8K6OLPs zO_c<$|FNI%&pmg^V3F2{{VjsK$KUt(`yPKECYe0`zHMxAd0!12OOL-#fU$enPA->Y z&cNgEd;EQmzt0aKHs`|Q?*kBj5r5xwekD3R87385T`9updi?A?R|*9_w;N5Hf2Q@7 z_?6teKAsi!cbV6hAt}6_W`HkI>WSR_{eH6c^ncv%uUOykX`6okzKEmbfJZ*~?&U#$ zSF8{Ib3;Szl?VR)MKt_z9R4aAe4$VH!y1AwtkifT!BuD;lC8In3J!LMCw(fq@s3q^ zJ0GFDh|0d*Y^9n<+(ocFH?G-=#TshFwg+=RScPA_wXhFQ6%1Ky^-7uz*53j?pmqKku4bHrGWR@ zc6R}LGzY5T2s~)RGk4uBt6(?&9!+>7feOM%;{%UhB}y}%<|DMCh|J0ObL(oD3-9J) zKsiGK;E6p1{siy~hA(b#3n2CXC&lA}`oY%(0ysOhuPfFjtKjytC+=9At)iy+%E@0h zSzD~)mIdP`DA~)+KzlDP8~yNvibt=tSnpaTFBO)Q0c(R4qyl?)JmFqTd-SN(WGY}54 zwlrM4bos}he*Wdk)oab1&9@$_nf>C%*WcRt&i*4eiOuIqMro%nT)JxgmP^FuqeDke zp0Q}z>I=l?U3p`4Pb~U^*t{lxto}n{^Spws#O9VgHk)tHJFDmrF0S07ponC3mSLA^nn&NJ2sqswiCUHp!7|?A;{+8z7>BN)eHw zQbZ8(1sg?dfG8G3L7Mdi5dlREVgRMw_ss0I9Px;s_`bZq-|c00=PC2d%zvIKJDb_` zg34+{A@<H9ECiQEpPw4cd~a3|&2Sc#V2$qdG$qm762UYRPQToAk6rC2P^^4Cc(1 z>?oDSSW9O@7_;S3GNNK>%#O;(0@;}IN}1Bg(6ZEoN2Yei|xq)l^xY!v6wRD^5*8|gy!S~BU3L= z%*e>VW|ETPK_lKg#b8mj#2d_gStAZRg|u1CXiXNa(ICTiRkcQ|B|9n#C*(Zr<Kq_qh8*kGRYGY6mq9!h?oVKWGWe2Wic`}Mx!o=EqP^w(PA_=7)>%|b(*Z- zXstnGY&Q4Ll6$JV(sx;+3sn|62k=RWSER%z4X(lXBxR;5;uWcx3Wb{yR@1{qIn;$l zWl?ox1>z^WTWP23X~(G1)=lY@6_=*nMwT3d>;^iiQH+-d|3;OeQ9J9xWMy=u$~9^^ zt)um{!D5E`NNisp8g*u!k#hcV4HQ%tnHiZ&aqjG8WL0vueC(a+ z$WDS*tH~@*Nl#8IDo9C5RTdQ`Cnn~n<>wct5@G0%V0owG~5e zH>&}&`H70+Q76=S9`^4U=i=-vAP))J0GYA{o!#(tNh#ytbA$&$C@y0YaNO?!Q% z-56cgwp-Lcx8K}A8@%-_tSO@P=SIxNI!m*Pq4Vp(4{p@qu@>7$@ifi$7CP-ePyuFD z)8B*t#%<~b#21gW!%hwtAIDts)sFKA|8NvCw*{v$HznJgUbUD z@1zed@A!B~eQK)jPaxV+=zA@#xK0f=|f2bXtzJfuFjJOJ@d z`rz`8kB8I;mj@u;NgrI^@$r!Q;PL>(JL!YVJ3by#A6y=Qcqe^udB?{?>VwMz5bvZ9 zF7NnwNPTd50OFnW!Q~wv52+6>4?w(=KDfN&<019Iv;_^ugsF9}lSyE)PJwlV0JHxVA6S2H3OM44V_l?#4{KyODYnE_nANyHnE7 z#Apqc3aiCrwE$BHCsOK|YT97cJHq%5|G%%q_u+b(tfpv84Fsc+5~+{@8R3+nQgjWFTA#S1rgah<4IOR0ljAaAYV6Dd3lits+!vu+WY)aTxQ4GA0?mmzxT7wXk&% zhXYA|tFC62NMdqo14Ut0fzD#E7fD)c)#@x-12G9AG0|3* zj~#|c%?!c%oOrmnY9_?3W-7?OOf$&4U`?gTVsI23YO9uU5>@r)awnl=3`!Sau(*h_ zTAkS`8D4K`auP*)U7?eJig1}OP&d}wfgr_m`UKftTcwf7G)8M}p7AKoAvuOJhU<6* zy6g1{7){McgQd7{l@9x$^C-}1WF7IV%sLC|HhLNG2=m zE6onK!eOiocjC%rbRBEPBiS0*l-g0U)oLBfuVmDDW1YzcsTrebG;ABI#4Sl{sCU2@ zfCW{MrvjtJV$|!5hI)G>sY8OZ;KuiN@T;`-4ekOzhXC^C)W@E~{h62yLM3pg;Ag)R zuZktI0DGcv%bf*Z)%mhrpg8Od6~@+|S}-3t$JhL1Xr4^J+^X$VfJELveZ| zFg?5(6}Y?}r+}(lPK~oBFvIR++B`~EhMOhTE*(CR0XqavAt6c&-O>`)Ge)ba9ZO&& zJ7gU_Zc#P1&Te@H8~!S*#W<8U&N1)PKYE<>@v;x#L#G_j*rRI{F@-j!~CvvdcDT^D7%+!3Hw%#!| z1+s-Naj>D}LJeJ~vXahN+(a{$4%A0E*zMK*YU{~fK{s%NS^EV;odSr0h8qnSYq7;> zg2{)OcJJ*ZI_MU!<4S8uH+mi4530SvQ=PQRemEf*wZWZpTS=I0S%HKNJ*BjyOlvT5 zz&Z6W(%~(NW5$k?3HO5gi=owlqpQ?rQ+ahUp6(#nz9_@{7+Fi?3UzYf5ZfPq9$!)^ zlex({6AV_H7#Q-XN>EPLz!w-GJQKpYW{U~)ajwH^8*!L}n_L(J8H8|G9Ij`>gNP0r z&ck7i-T)5H!Fe`m^co!A1>uL9tl06nWe}d#q@|l7d;r4HI;&m_Vch42>1h=-Mjpm2 z+Cr-vAgq9}l&PtLF_V{tkVsnZ7Or&*TfhTB7b%UVDWpzh{nY(s@cD^!Sqa^&qb-*B zO8BaViqXI~FZ3prVG2TQnQ<%>a@`(L!e%dCg>HJ@g1By3`S}r~&ZvkzE}ko8~hSV1-lybLBp zP~8TNmV8-6YiPF%*v-QKGn$(P9Ay0(0->v~p|A-FDCpBL#Qk{>;)VJl?)YawLOJWL zOgsu^^azdaeUkNi2!otl+g&(wf#jIAWLQATsv4Qv$~3VmJbdFL2?|7Es2l2q`l5a? zpGiW4(GZk}ir}%R0@a|g=uV_Y4M-1^-}3{wjs-L zP*&=0>V9etwSZbmt)$jbFH^5mJE#w-ebg7!G3qq+EA^@9^ozJJDU9eAZT+k*I3cCph3bTb3LY2@WoF!Z$d{Ow0aKG?`@RG<+)LWD! zDi)0s8ALNgi$pJo-WKf_ofKUb2Z>|Enc@nuMm$A4SG-!hP5i0&g!r-~SQ016mefcl zNv2B{OEyT}lYA{X@8{aOMV~t9rOEL8X_GaRZ7Q8t@>0Bs?X2RCr7H zvhcUUk4A7KVk1f;bP;nSUWqsq@kf`QUGlroT^{bTq09a*7rXZ8n%9-?I=kz}t_QpR z(M{H^s9R&V`Q5g3`=&du`+)8vx;J-!ru%!{&-4iEF{FpO$Lt=j^!PH86FDHVD)O$# zXCwDSw)O1Qb7)Uf&m}$I?RlnGM6bMFlX@-e^>(k*y+eEF^w#!X*!!K{Kgz;o`7)hs zv22&DwNGT9l0McxEBoy2b2%z5YGl-msEtwI^p*5Y?_1Y*Vc(s7TcdkNmq*_ny*~QO z7;#K`Ohe3*F}q_f#>T~tj(sq8OYEt*u5qPtQ{&dhecjK$Uv9t2{Z{om&|lC$y? zr~7|4fHNR{w6y5k;;7>K z;`PO?LsN&|HFSFkzhqd+{F1|^JxkT4>q=X18+_Y6x9u7x9acST>9Ft029z;n+sZlR zx0OF${`K&f;fCQ`Do{mf#p4y0G}Uzm7BRiRp?YO5`+eX6!q ztyDj${z;RkS*STpXVVMllXcm33+hhQXV*Vof4U*JVNt^wtx~&Gdu~$6q~((?HdZvQ zZM5k|>o)2|`ic724Izd`!!BblV~cU0X`pGA>FDIl$xlpfWri_p%#`^K^Hxh3Os4i& z`&l2b9&5^JTGn)_c~tYOEx|2@mOWDjOnG?9$*ILtpSz29m-?=qclWt_`rXIw$-igi zz0|$6_wKx}?|n1xJ27qOwCATwrZ-OiWQJnKf*HTvKl=V{GkeaQHuLxcLmyZ_D_|Bg z>+pj^9$fwq?;-6&dmm1Ic*(=pW@~1DG)FOK(VQ!fs2}<0(Zoj=KWcld?yoT@t-y z-jXXz8-y6#j(_p9e--{~ z>xTFZD>p`LobwWT$@duQr9ZQD)T&+Mq*aeU{5onO5> z=G_CkM(o=A-mv#Rc)$4lcX#LSe&>Vi58nJR^TXFaO8;of$7vsL-jlj#(f=9sZ~p$uiJ3q6 z|FGy}@006JC7pWnbn)rWe!Tt16F-@Lx_oBV&%r-Gb++Hx*M7D}!Kp-D5oJ4K`x!~e=g=l7%YiaoR!JRQ++m3=oka;PWib9-ViW^MXzJcd|%C?KjgT3URm&VGyEt6qm!}@Pz^qpDRrUVKA51CnS-dKSC86HFWO-^BE>{AM37F4$$JEu0MMyz_}{@B9DYcxeWpS7fQ*+23-`qx)yzWcfL z`1#_vg{vQU?TK9nzW?pHP468%(Kf2CY1X1Oo8Le5!-c^^N7pw$_~hCxyAPkd7>qa^ z$SsfLNhsi_k}UK|4BMRFIM;n(!fT~14`t5~9+_}qZpHbG zZ@!;1$B=xa=*5X<-h#XXva4%0PH0~J?_rO=F|_xa3zplyV4r9E5a>t3mBP*zi1LvJ z7O88=DtjeNI*qVUZG^RM95R7M=nXXRI({`u!v@(Dq9BNG%cB#c|kya%;pDGA424d-V_a%CDqu+nJ1 zd;M4-!e0Q)RHWb!BjPUr;txfE3$CDCd0WA8+Lx~2I>Wdv;zK~e)E4d(USo5WgX-lf z2NmmH4i4q8K_zfpwuv#gz?uTVf!uLF5V(SfF6mVUZE008UaUTY`T2%Iyy&$DPMjB9 zemLxlZ#YLNzqs0cO#~G)rG^fd${ewX4bURXWJA{W$9)e1BONcWIbxB=mtu3fl{843 zabK=R#pYthkv3k0b677^8r<@T%T;A0%ZDPIHa-XjD@ia?U&p{Y1F3trGCRsHJA;sH zJ7QO+Nd$t76!B~}APWeqfM^#G8wJ?50ls8t1BV0%VQqpO{qV|gXHH?6Y6{KB60sef z)qwMceNu?Z;I-Bi@`^}?*MNxJU}iwZ)2XH~gr1_+U>Z&irq#My9j0+5U|MUaYq84- z-Dqeuy3;zdsjeNZ)?xeYa5FdPaT+CXl9hI~)lAk`fKGwag`o(4ToixM5^KUKhFsE2 zjaEsTn2qE;8+nTfA68{+0@e&YYC=G0vl^p>Ylh3x z|6!y*8PHjzaScil|Ihr}b`9ir;4)ymlUXmn1U&4eBK-CP?!j>S+x@1~bs#B(rAC>G zVT{cruT6S$BiLCDC+T}|Z}=yN(?dIuvpwnc0x~M0X{>X)-@&iu*}0x~A|a+g;(jM} z%K8g-KnW@&uW{8#2CbGMzS2x|TrHIN!7blHKPkJJepBC(-#Ffw0dDx+-e2|`alX@S z{v&=v>U|oyBJ4Nhz<0{si*T3cq=^JG+UW!7;WuKK0-0e&&dqD=IxfHA;W)Rx-_&;2 zZwM^*@$|+$dnBvg`JP=g(qJ|+?AtXrv`KG;M#4XWn4uqM$iIVVh}?xVpU`a2jeA8h z%9vDUJV#<{?msJjmC7X}p}@S){RNbb7qB&kB9xCG=tT z*==XXOY)x&w|>93?q>RpZ@ipl@0sj(w;mk(O=reSe;nu5_nS95>o+VQop=($|EfdD z;DV1%&%(uI7LJF^4rV8=S*>H#B)QhP#!Rx#sJo@c%)K`qS?qeZ)H9~=))+It?<~@P zY0UIJW0DrkwzR+Yj4Arx==(0+OuuoCneKBf-!mpzN$l*HDgK}Eo4wM``VHHFIy+|m z^=C}H0>KWM?yZ!4#&kT<+eb{&Q@h4XiCfQoYdmA_?d2U+csJzz*JktngLRS{SqN|Q z`nx48us(%XeQs2mzmLb+Hm|=<g&V$)S7j4ucfQb9@ z?>5fMTx3I(-~P)s?tXatd<{{N$FJI`1q%a0P=YIcT#Tlw5@%T7K1rR$K+N z(VdrVXu>sI2mRZi4%*Io_2_O!?Eo0r$u9t;nUi*p8j`Ty_X|9>?VPtpJY literal 0 HcmV?d00001 diff --git a/css/theme.black-ice.css b/css/theme.black-ice.css new file mode 100644 index 0000000..1bf253d --- /dev/null +++ b/css/theme.black-ice.css @@ -0,0 +1,192 @@ +/************* + Black Ice Theme (by thezoggy) + *************/ +/* overall */ +.tablesorter-blackice { + width: 100%; + margin-right: auto; + margin-left: auto; + font: 11px/18px Arial, Sans-serif; + text-align: left; + background-color: #000; + border-collapse: collapse; + border-spacing: 0; +} + +/* header */ +.tablesorter-blackice th, +.tablesorter-blackice thead td { + padding: 4px; + font: 13px/20px Arial, Sans-serif; + font-weight: bold; + color: #e5e5e5; + text-align: left; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7); + background-color: #111; + border: 1px solid #232323; +} +.tablesorter-blackice .header, +.tablesorter-blackice .tablesorter-header { + padding: 4px 20px 4px 4px; + cursor: pointer; + background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); + background-position: center right; + background-repeat: no-repeat; +} +.tablesorter-blackice .headerSortUp, +.tablesorter-blackice .tablesorter-headerSortUp, +.tablesorter-blackice .tablesorter-headerAsc { + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); + color: #fff; +} +.tablesorter-blackice .headerSortDown, +.tablesorter-blackice .tablesorter-headerSortDown, +.tablesorter-blackice .tablesorter-headerDesc { + color: #fff; + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); +} +.tablesorter-blackice thead .sorter-false { + background-image: none; + cursor: default; + padding: 4px; +} + +/* tfoot */ +.tablesorter-blackice tfoot .tablesorter-headerSortUp, +.tablesorter-blackice tfoot .tablesorter-headerSortDown, +.tablesorter-blackice tfoot .tablesorter-headerAsc, +.tablesorter-blackice tfoot .tablesorter-headerDesc { + /* remove sort arrows from footer */ + background-image: none; +} + +/* tbody */ +.tablesorter-blackice td { + padding: 4px; + color: #ccc; + vertical-align: top; + background-color: #333; + border: 1px solid #232323; +} + +/* hovered row colors */ +.tablesorter-blackice tbody > tr.hover > td, +.tablesorter-blackice tbody > tr:hover > td, +.tablesorter-blackice tbody > tr.even:hover > td, +.tablesorter-blackice tbody > tr.odd:hover > td { + background-color: #000; +} + +/* table processing indicator */ +.tablesorter-blackice .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-blackice tr.odd > td { + background-color: #333; +} +.tablesorter-blackice tr.even > td { + background-color: #393939; +} + +/* Column Widget - column sort colors */ +.tablesorter-blackice td.primary, +.tablesorter-blackice tr.odd td.primary { + background-color: #2f3a40; +} +.tablesorter-blackice tr.even td.primary { + background-color: #3f4a50; +} +.tablesorter-blackice td.secondary, +.tablesorter-blackice tr.odd td.secondary { + background-color: #3f4a50; +} +.tablesorter-blackice tr.even td.secondary { + background-color: #4f5a60; +} +.tablesorter-blackice td.tertiary, +.tablesorter-blackice tr.odd td.tertiary { + background-color: #4f5a60; +} +.tablesorter-blackice tr.even td.tertiary { + background-color: #5a646b; +} + +/* caption */ +caption { + background-color: #fff; +} + +/* filter widget */ +.tablesorter-blackice .tablesorter-filter-row { + background-color: #222; +} +.tablesorter-blackice .tablesorter-filter-row td { + background-color: #222; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-blackice .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} +/* hidden filter row */ +.tablesorter-blackice .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-blackice .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* filters */ +.tablesorter-blackice input.tablesorter-filter, +.tablesorter-blackice select.tablesorter-filter { + width: 98%; + height: auto; + margin: 0; + padding: 4px; + background-color: #fff; + border: 1px solid #bbb; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.blue.css b/css/theme.blue.css new file mode 100644 index 0000000..66d6e58 --- /dev/null +++ b/css/theme.blue.css @@ -0,0 +1,229 @@ +/************* + Blue Theme + *************/ +/* overall */ +.tablesorter-blue { + width: 100%; + background-color: #fff; + margin: 10px 0 15px; + text-align: left; + border-spacing: 0; + border: #cdcdcd 1px solid; + border-width: 1px 0 0 1px; +} +.tablesorter-blue th, +.tablesorter-blue td { + border: #cdcdcd 1px solid; + border-width: 0 1px 1px 0; +} + +/* header */ +.tablesorter-blue th, +.tablesorter-blue thead td { + font: 12px/18px Arial, Sans-serif; + font-weight: bold; + color: #000; + background-color: #99bfe6; + border-collapse: collapse; + padding: 4px; + text-shadow: 0 1px 0 rgba(204, 204, 204, 0.7); +} +.tablesorter-blue tbody td, +.tablesorter-blue tfoot th, +.tablesorter-blue tfoot td { + padding: 4px; + vertical-align: top; +} +.tablesorter-blue .header, +.tablesorter-blue .tablesorter-header { + /* black (unsorted) double arrow */ + background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); + /* white (unsorted) double arrow */ + /* background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); */ + /* image */ + /* background-image: url(images/black-unsorted.gif); */ + background-repeat: no-repeat; + background-position: center right; + padding: 4px 18px 4px 4px; + white-space: normal; + cursor: pointer; +} +.tablesorter-blue .headerSortUp, +.tablesorter-blue .tablesorter-headerSortUp, +.tablesorter-blue .tablesorter-headerAsc { + background-color: #9fbfdf; + /* black asc arrow */ + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); + /* white asc arrow */ + /* background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); */ + /* image */ + /* background-image: url(images/black-asc.gif); */ +} +.tablesorter-blue .headerSortDown, +.tablesorter-blue .tablesorter-headerSortDown, +.tablesorter-blue .tablesorter-headerDesc { + background-color: #8cb3d9; + /* black desc arrow */ + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); + /* white desc arrow */ + /* background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); */ + /* image */ + /* background-image: url(images/black-desc.gif); */ +} +.tablesorter-blue thead .sorter-false { + background-image: none; + cursor: default; + padding: 4px; +} + +/* tfoot */ +.tablesorter-blue tfoot .tablesorter-headerSortUp, +.tablesorter-blue tfoot .tablesorter-headerSortDown, +.tablesorter-blue tfoot .tablesorter-headerAsc, +.tablesorter-blue tfoot .tablesorter-headerDesc { + /* remove sort arrows from footer */ + background-image: none; +} + +/* tbody */ +.tablesorter-blue td { + color: #3d3d3d; + background-color: #fff; + padding: 4px; + vertical-align: top; +} + +/* hovered row colors + you'll need to add additional lines for + rows with more than 2 child rows + */ +.tablesorter-blue tbody > tr.hover > td, +.tablesorter-blue tbody > tr:hover > td, +.tablesorter-blue tbody > tr:hover + tr.tablesorter-childRow > td, +.tablesorter-blue tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td, +.tablesorter-blue tbody > tr.even.hover > td, +.tablesorter-blue tbody > tr.even:hover > td, +.tablesorter-blue tbody > tr.even:hover + tr.tablesorter-childRow > td, +.tablesorter-blue tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + background-color: #d9d9d9; +} +.tablesorter-blue tbody > tr.odd.hover > td, +.tablesorter-blue tbody > tr.odd:hover > td, +.tablesorter-blue tbody > tr.odd:hover + tr.tablesorter-childRow > td, +.tablesorter-blue tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + background-color: #bfbfbf; +} + +/* table processing indicator */ +.tablesorter-blue .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-blue tbody tr.odd > td { + background-color: #ebf2fa; +} +.tablesorter-blue tbody tr.even > td { + background-color: #fff; +} + +/* Column Widget - column sort colors */ +.tablesorter-blue td.primary, +.tablesorter-blue tr.odd td.primary { + background-color: #99b3e6; +} +.tablesorter-blue tr.even td.primary { + background-color: #c2d1f0; +} +.tablesorter-blue td.secondary, +.tablesorter-blue tr.odd td.secondary { + background-color: #c2d1f0; +} +.tablesorter-blue tr.even td.secondary { + background-color: #d6e0f5; +} +.tablesorter-blue td.tertiary, +.tablesorter-blue tr.odd td.tertiary { + background-color: #d6e0f5; +} +.tablesorter-blue tr.even td.tertiary { + background-color: #ebf0fa; +} + +/* caption */ +caption { + background-color: #fff; +} + +/* filter widget */ +.tablesorter-blue .tablesorter-filter-row { + background-color: #eee; +} +.tablesorter-blue .tablesorter-filter-row td { + background-color: #eee; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-blue .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} +/* hidden filter row */ +.tablesorter-blue .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-blue .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* filters */ +.tablesorter-blue input.tablesorter-filter, +.tablesorter-blue select.tablesorter-filter { + width: 98%; + height: auto; + margin: 0; + padding: 4px; + background-color: #fff; + border: 1px solid #bbb; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.bootstrap.css b/css/theme.bootstrap.css new file mode 100644 index 0000000..11a3ea7 --- /dev/null +++ b/css/theme.bootstrap.css @@ -0,0 +1,158 @@ +/************* + Bootstrap theme + *************/ +/* jQuery Bootstrap Theme */ +.tablesorter-bootstrap { + width: 100%; +} +.tablesorter-bootstrap thead th, +.tablesorter-bootstrap thead td, +.tablesorter-bootstrap tfoot th, +.tablesorter-bootstrap tfoot td { + font: 14px/20px Arial, Sans-serif; + font-weight: bold; + padding: 4px; + margin: 0 0 18px; + background-color: #eee; +} + +.tablesorter-bootstrap .tablesorter-header { + cursor: pointer; +} + +.tablesorter-bootstrap .tablesorter-header-inner { + position: relative; + padding: 4px 18px 4px 4px; +} + +/* bootstrap uses for icons */ +.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon { + font-size: 11px; + position: absolute; + right: 2px; + top: 50%; + margin-top: -7px; /* half the icon height; older IE doesn't like this */ + width: 14px; + height: 14px; + background-repeat: no-repeat; + line-height: 14px; + display: inline-block; +} + +/* black unsorted icon */ +.tablesorter-bootstrap .bootstrap-icon-unsorted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAMAAADOvxanAAAAVFBMVEUAAABCQkJZWVkZGRnJyckgICAZGRkZGRn8/PweHh4dHR0aGhoaGhpUVFQbGxvQ0NDc3NxMTExSUlIbGxvr6+s4ODhKSkogICAtLS00NDQzMzMnJydSEPrQAAAAGHRSTlMA1ssZRLgdAQbDyisqsZo8QdXUq0r9xPepSRwiAAAAX0lEQVQI13XHSQKAIAwEwQAKxn13Ev7/T2Pu9qmarJKPXIicI4PH4hxaKNrhm2S8bJK5h4YzKHrzJNtK6yYT/TdXzpS5zuYg4MSQYF6i4IHExdw1UVRi05HPrrvT53a+qyMFC9t04gcAAAAASUVORK5CYII=); +} + +/* white unsorted icon */ +.tablesorter-bootstrap .icon-white.bootstrap-icon-unsorted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOBAMAAAALT/umAAAAKlBMVEUAAAD///////////////////////////////////////////////////+Gu8ovAAAADXRSTlMA4EXKBtQqvR0+sxmalc142gAAAFdJREFUCNdjYGDoamAAAjZbMxCVfvd6AgMDd+3du9UMDKx3hWSvMjBwXZww8RYDGuC53NB8h4GB8a617UUGBs7Yu3cjGRhYVO9eVQFKOskKOQApFmUgBwBZ+xXRTttNdAAAAABJRU5ErkJggg==); +} + +/* since bootstrap (table-striped) uses nth-child(), we just use this to add a zebra stripe color */ +.tablesorter-bootstrap > tbody > tr.odd > td, +.tablesorter-bootstrap > tbody > tr.tablesorter-hasChildRow.odd:hover ~ tr.tablesorter-hasChildRow.odd ~ .tablesorter-childRow.odd > td { + background-color: #f9f9f9; +} +.tablesorter-bootstrap > tbody > tr.hover > td, +.tablesorter-bootstrap > tbody > tr.odd:hover > td, +.tablesorter-bootstrap > tbody > tr.even:hover > td, +.tablesorter-bootstrap > tbody > tr.tablesorter-hasChildRow.odd:hover ~ .tablesorter-childRow.odd > td, +.tablesorter-bootstrap > tbody > tr.tablesorter-hasChildRow.even:hover ~ .tablesorter-childRow.even > td { + background-color: #f5f5f5; +} +.tablesorter-bootstrap > tbody > tr.even > td, +.tablesorter-bootstrap > tbody > tr.tablesorter-hasChildRow.even:hover ~ tr.tablesorter-hasChildRow.even ~ .tablesorter-childRow.even > td { + background-color: #fff; +} + +/* processing icon */ +.tablesorter-bootstrap .tablesorter-processing { + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs='); + background-position: center center !important; + background-repeat: no-repeat !important; +} + +/* caption */ +.caption { + background-color: #fff; +} + +/* filter widget */ +.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter, +.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter { + width: 98%; + margin: 0; + padding: 4px 6px; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled { + background-color: #eee; + color: #555; + cursor: not-allowed; + border: 1px solid #ccc; + border-radius: 4px; + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset; + box-sizing: border-box; + transition: height 0.1s ease; +} +.tablesorter-bootstrap .tablesorter-filter-row { + background-color: #efefef; +} +.tablesorter-bootstrap .tablesorter-filter-row td { + background-color: #efefef; + line-height: normal; + text-align: center; + padding: 4px 6px; + vertical-align: middle; + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* hidden filter row */ +.tablesorter-bootstrap .tablesorter-filter-row.hideme td { + padding: 2px; /* change this to modify the thickness of the closed border row */ + margin: 0; + line-height: 0; +} +.tablesorter-bootstrap .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* pager plugin */ +.tablesorter-bootstrap .tablesorter-pager select { + padding: 4px 6px; +} +.tablesorter-bootstrap .tablesorter-pager .pagedisplay { + border: 0; +} +/* tfoot i for pager controls */ +.tablesorter-bootstrap tfoot i { + font-size: 11px; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.bootstrap_2.css b/css/theme.bootstrap_2.css new file mode 100644 index 0000000..fe0665b --- /dev/null +++ b/css/theme.bootstrap_2.css @@ -0,0 +1,157 @@ +/************* + Bootstrap 2 Theme + *************/ +/* jQuery Bootstrap 2 Theme */ +.tablesorter-bootstrap { + width: 100%; +} +.tablesorter-bootstrap .tablesorter-header, +.tablesorter-bootstrap tfoot th, +.tablesorter-bootstrap tfoot td { + font: 14px/20px Arial, Sans-serif; + font-weight: bold; + position: relative; + padding: 8px; + margin: 0 0 18px; + list-style: none; + background-color: #FBFBFB; + background-image: -moz-linear-gradient(top, white, #efefef); + background-image: -ms-linear-gradient(top, white, #efefef); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(white), to(#efefef)); + background-image: -webkit-linear-gradient(top, white, #efefef); + background-image: -o-linear-gradient(top, white, #efefef); + background-image: linear-gradient(to bottom, white, #efefef); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#efefef', GradientType=0); + background-repeat: repeat-x; + -webkit-box-shadow: inset 0 1px 0 white; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 white; +} + +.tablesorter-bootstrap .tablesorter-header { + cursor: pointer; +} + +.tablesorter-bootstrap .tablesorter-header-inner { + position: relative; + padding: 4px 18px 4px 4px; +} + +/* bootstrap uses for icons */ +.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon { + position: absolute; + right: 2px; + top: 50%; + margin-top: -7px; /* half the icon height; older IE doesn't like this */ + width: 14px; + height: 14px; + background-repeat: no-repeat; + line-height: 14px; + display: inline-block; +} + +/* black unsorted icon */ +.tablesorter-bootstrap .bootstrap-icon-unsorted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWVJREFUeNqUUL9Lw2AUTGP8mqGlpBQkNeCSRcckEBcHq1jImMElToKuDvpHFMGhU0BQcHBwLji6CE1B4uB/INQsDi4d2jQ/fPeZxo764OV6915f7lLJ81xot9tCURXqdVEUr7IsO6ffH9Q5BlEUCaLwWxWqTcbYnaIoh0Dw4gAvcWlxq1qt9hqNxg6hUGAP+uIPUrGs0qXLer2+v/pTX6QpxLtkc2U2m53ACb8sSdIDXerSEms2m6+DweAICA4d89KGbduf9MpEVdXQ9/2LVqv1CASHjjn3iq/x1xKFfxQPqGnada1W86bT6SiO42OS3qk3KPStLMvbk8nkfjwen/LLuq6blFymMB0KdUPSGhAcOualjX6/f0bCiC7NaWGPQr0BwaFjzn0gYJqmLAiCA8/zni3LmhuGkQPBoWPOPwQeaPIqD4fDruu6L6Zp5kBw6IudchmdJAkLw3DXcZwnIPjy/FuAAQCiqqWWCAFKcwAAAABJRU5ErkJggg==); +} + +/* white unsorted icon */ +.tablesorter-bootstrap .icon-white.bootstrap-icon-unsorted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOBAMAAAALT/umAAAAKlBMVEUAAAD///////////////////////////////////////////////////+Gu8ovAAAADXRSTlMA4EXKBtQqvR0+sxmalc142gAAAFdJREFUCNdjYGDoamAAAjZbMxCVfvd6AgMDd+3du9UMDKx3hWSvMjBwXZww8RYDGuC53NB8h4GB8a617UUGBs7Yu3cjGRhYVO9eVQFKOskKOQApFmUgBwBZ+xXRTttNdAAAAABJRU5ErkJggg==); +} + +/* since bootstrap (table-striped) uses nth-child(), we just use this to add a zebra stripe color */ +.tablesorter-bootstrap tr.odd > td { + background-color: #f9f9f9; +} +.tablesorter-bootstrap tbody > tr.hover > td, +.tablesorter-bootstrap tbody > .odd:hover > td, +.tablesorter-bootstrap tbody > .even:hover > td { + background-color: #f5f5f5; +} +.tablesorter-bootstrap tbody > tr.even > td { + background-color: #fff; +} + +/* processing icon */ +.tablesorter-bootstrap .tablesorter-processing { + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs='); + position: absolute; + z-index: 1000; +} + +/* caption */ +caption { + background-color: #fff; +} + +/* filter widget */ +.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter, +.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter { + height: 28px; + width: 98%; + margin: 0; + padding: 4px 6px; + background-color: #fff; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled { + background-color: #eee; + cursor: not-allowed; +} +.tablesorter-bootstrap .tablesorter-filter-row { + background-color: #ddd; +} +.tablesorter-bootstrap .tablesorter-filter-row td { + background-color: #eee; + line-height: normal; + text-align: center; + padding: 4px 6px; + vertical-align: middle; + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* hidden filter row */ +.tablesorter-bootstrap tr.tablesorter-filter-row.hideme td { + padding: 2px; /* change this to modify the thickness of the closed border row */ + margin: 0; + line-height: 0; +} +.tablesorter-bootstrap tr.tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* pager plugin */ +.tablesorter-bootstrap .tablesorter-pager select { + padding: 4px 6px; +} +.tablesorter-bootstrap .tablesorter-pager .pagedisplay { + border: 0; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} \ No newline at end of file diff --git a/css/theme.dark.css b/css/theme.dark.css new file mode 100644 index 0000000..3ddbf61 --- /dev/null +++ b/css/theme.dark.css @@ -0,0 +1,193 @@ +/************* + Dark Theme (by thezoggy) + *************/ +/* overall */ +.tablesorter-dark { + width: 100%; + font: 11px/18px Arial, Sans-serif; + color: #ccc; + text-align: left; + background-color: #000; + border-spacing: 0; +} + +/* header */ +.tablesorter-dark th, +.tablesorter-dark thead td { + padding: 4px; + font: 12px/20px Arial, Sans-serif; + font-weight: bold; + color: #fff; + background-color: #000; + border-collapse: collapse; +} +.tablesorter-dark thead th { + border-bottom: #333 2px solid; +} +.tablesorter-dark .header, +.tablesorter-dark .tablesorter-header { + padding: 4px 20px 4px 4px; + cursor: pointer; + background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); + background-position: center right; + background-repeat: no-repeat; +} +.tablesorter-dark thead .headerSortUp, +.tablesorter-dark thead .tablesorter-headerSortUp, +.tablesorter-dark thead .tablesorter-headerAsc { + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); + border-bottom: #888 1px solid; +} +.tablesorter-dark thead .headerSortDown, +.tablesorter-dark thead .tablesorter-headerSortDown, +.tablesorter-dark thead .tablesorter-headerDesc { + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); + border-bottom: #888 1px solid; +} +.tablesorter-dark thead .sorter-false { + background-image: none; + cursor: default; + padding: 4px; +} + +/* tfoot */ +.tablesorter-dark tfoot .tablesorter-headerSortUp, +.tablesorter-dark tfoot .tablesorter-headerSortDown, +.tablesorter-dark tfoot .tablesorter-headerAsc, +.tablesorter-dark tfoot .tablesorter-headerDesc { + border-top: #888 1px solid; + /* remove sort arrows from footer */ + background-image: none; +} + +/* tbody */ +.tablesorter-dark td { + padding: 4px; + background-color: #000; + border-bottom: #333 1px solid; + color: #ccc; +} + +/* hovered row colors */ +.tablesorter-dark tbody > tr.hover > td, +.tablesorter-dark tbody > tr:hover > td, +.tablesorter-dark tbody > tr.even:hover > td, +.tablesorter-dark tbody > tr.odd:hover > td { + background-color: #000; +} + +/* table processing indicator */ +.tablesorter-dark .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-dark tr.odd > td { + background-color: #202020; +} +.tablesorter-dark tr.even > td { + background-color: #101010; +} + +/* Column Widget - column sort colors */ +.tablesorter-dark td.primary, +.tablesorter-dark tr.odd td.primary { + background-color: #0a0a0a; +} +.tablesorter-dark tr.even td.primary { + background-color: #050505; +} +.tablesorter-dark td.secondary, +.tablesorter-dark tr.odd td.secondary { + background-color: #0f0f0f; +} +.tablesorter-dark tr.even td.secondary { + background-color: #0a0a0a; +} +.tablesorter-dark td.tertiary, +.tablesorter-dark tr.odd td.tertiary { + background-color: #191919; +} +.tablesorter-dark tr.even td.tertiary { + background-color: #0f0f0f; +} + +/* caption */ +caption { + background-color: #202020; +} + +/* filter widget */ +.tablesorter-dark .tablesorter-filter-row { + background-color: #202020; +} +.tablesorter-dark .tablesorter-filter-row td { + background-color: #202020; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-dark .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} + +/* hidden filter row */ +.tablesorter-dark .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-dark .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} + +/* filters */ +.tablesorter-dark input.tablesorter-filter, +.tablesorter-dark select.tablesorter-filter { + width: 98%; + height: auto; + margin: 0; + padding: 4px; + background-color: #111; + border: 1px solid #222; + color: #ddd; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.default.css b/css/theme.default.css new file mode 100644 index 0000000..6c2a346 --- /dev/null +++ b/css/theme.default.css @@ -0,0 +1,194 @@ +/************* +Default Theme +*************/ +/* overall */ +.tablesorter-default { + width: 100%; + font: 12px/18px Arial, Sans-serif; + color: #333; + background-color: #fff; + border-spacing: 0; + margin: 10px 0 15px; + text-align: left; +} + +/* header */ +.tablesorter-default th, +.tablesorter-default thead td { + font-weight: bold; + color: #000; + background-color: #fff; + border-collapse: collapse; + border-bottom: #ccc 2px solid; + padding: 0; +} +.tablesorter-default tfoot th, +.tablesorter-default tfoot td { + border: 0; +} +.tablesorter-default .header, +.tablesorter-default .tablesorter-header { + background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); + background-position: center right; + background-repeat: no-repeat; + cursor: pointer; + white-space: normal; + padding: 4px 20px 4px 4px; +} +.tablesorter-default thead .headerSortUp, +.tablesorter-default thead .tablesorter-headerSortUp, +.tablesorter-default thead .tablesorter-headerAsc { + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); + border-bottom: #000 2px solid; +} +.tablesorter-default thead .headerSortDown, +.tablesorter-default thead .tablesorter-headerSortDown, +.tablesorter-default thead .tablesorter-headerDesc { + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); + border-bottom: #000 2px solid; +} +.tablesorter-default thead .sorter-false { + background-image: none; + cursor: default; + padding: 4px; +} + +/* tfoot */ +.tablesorter-default tfoot .tablesorter-headerSortUp, +.tablesorter-default tfoot .tablesorter-headerSortDown, +.tablesorter-default tfoot .tablesorter-headerAsc, +.tablesorter-default tfoot .tablesorter-headerDesc { + border-top: #000 2px solid; +} + +/* tbody */ +.tablesorter-default td { + background-color: #fff; + border-bottom: #ccc 1px solid; + padding: 4px; + vertical-align: top; +} + +/* hovered row colors */ +.tablesorter-default tbody > tr.hover > td, +.tablesorter-default tbody > tr:hover > td, +.tablesorter-default tbody > tr.even:hover > td, +.tablesorter-default tbody > tr.odd:hover > td { + background-color: #fff; + color: #000; +} + +/* table processing indicator */ +.tablesorter-default .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-default tr.odd > td { + background-color: #dfdfdf; +} +.tablesorter-default tr.even > td { + background-color: #efefef; +} + +/* Column Widget - column sort colors */ +.tablesorter-default tr.odd td.primary { + background-color: #bfbfbf; +} +.tablesorter-default td.primary, +.tablesorter-default tr.even td.primary { + background-color: #d9d9d9; +} +.tablesorter-default tr.odd td.secondary { + background-color: #d9d9d9; +} +.tablesorter-default td.secondary, +.tablesorter-default tr.even td.secondary { + background-color: #e6e6e6; +} +.tablesorter-default tr.odd td.tertiary { + background-color: #e6e6e6; +} +.tablesorter-default td.tertiary, +.tablesorter-default tr.even td.tertiary { + background-color: #f2f2f2; +} + +/* caption */ +caption { + background-color: #fff; +} + +/* filter widget */ +.tablesorter-default .tablesorter-filter-row { + background-color: #eee; +} +.tablesorter-default .tablesorter-filter-row td { + background-color: #eee; + border-bottom: #ccc 1px solid; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-default .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} +/* hidden filter row */ +.tablesorter-default .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-default .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* filters */ +.tablesorter-default input.tablesorter-filter, +.tablesorter-default select.tablesorter-filter { + width: 95%; + height: auto; + margin: 4px auto; + padding: 4px; + background-color: #fff; + border: 1px solid #bbb; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.dropbox.css b/css/theme.dropbox.css new file mode 100644 index 0000000..c173032 --- /dev/null +++ b/css/theme.dropbox.css @@ -0,0 +1,216 @@ +/************* + Dropbox Theme (by thezoggy) + *************/ +/* overall */ +.tablesorter-dropbox { + width: 100%; + font: 13px/32px "Open Sans","lucida grande","Segoe UI",arial,verdana,"lucida sans unicode",tahoma,sans-serif; + color: #555; + text-align: left; + background-color: #fff; + border-collapse: collapse; + border-top: 1px solid #82cffa; + border-spacing: 0; +} + +/* header */ +.tablesorter-dropbox th, +.tablesorter-dropbox thead td, +.tablesorter-dropbox tfoot th, +.tablesorter-dropbox tfoot td { + background-color: #f0f9ff; + border-color: #82cffa #e7f2fb #96c4ea; + border-style: solid; + border-width: 1px; + padding: 3px 6px; + font-size: 13px; + font-weight: normal; + line-height: 29px; + color: #2281CF; + text-align: left; +} +.tablesorter-dropbox .header, +.tablesorter-dropbox thead tr, +.tablesorter-dropbox .tablesorter-headerRow { + background-color: #f0f9ff; + border-bottom: 1px solid #96c4ea; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.12), 0 0 0 #000000 inset; + white-space: normal; +} +.tablesorter-dropbox .tablesorter-headerSortUp, +.tablesorter-dropbox .tablesorter-headerSortDown, +.tablesorter-dropbox .tablesorter-headerAsc, +.tablesorter-dropbox .tablesorter-headerDesc { + font-weight: 600; +} +.tablesorter-dropbox .tablesorter-header { + cursor: pointer; +} +.tablesorter-dropbox .tablesorter-header i.tablesorter-icon { + width: 9px; + height: 9px; + padding: 0 10px 0 4px; + display: inline-block; + background-position: center right; + background-repeat: no-repeat; + content: ""; +} +.tablesorter-dropbox .tablesorter-headerSortUp i.tablesorter-icon, +.tablesorter-dropbox .tablesorter-headerAsc i.tablesorter-icon { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALhJREFUeNpi/P//PwMhwILMiexYx8bIxNTy/9+/muUVQb9g4kzIitg4edI4+YRLQTSyOCPMupjerUI8whK3OXgEhH58+fDuy9sXqkuKvd+hmMTOxdvCxS8sxMUvxACiQXwU6+Im7DDg5BNKY+fiY2BmYWMA0SA+SByuiJ2bbzIHrwAzMxsb0AGMDCAaxAeJg+SZ7wtaqfAISfQAdTIwMUM8ywhUyMTEzPD/71+5FXvPLWUkJpwAAgwAZqYvvHStbD4AAAAASUVORK5CYII='); + /* background-image: url(images/dropbox-asc.png); */ +} +.tablesorter-dropbox .tablesorter-headerSortUp:hover i.tablesorter-icon, +.tablesorter-dropbox .tablesorter-headerAsc:hover i.tablesorter-icon { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALVJREFUeNpi/P//PwMhwILMCc+qZGNkYmr5/+9fzcpp7b9g4kzIitjYOdM4uXlLQTSyOCPMuqi8OiEefsHbHFzcQj++fX335eN71WWTmt6hmMTOwdXCycMnBDSJAUSD+CjWxRQ0GHBw86Sxc3AyMDOzMIBoEB8kDlfEzsk1mYOLByjPCnQAIwOIBvFB4iB55rsfmVS4+QV7QNYwMTNDHApUyMTExPDv/z+5Feu3L2UkJpwAAgwA244u+I9CleAAAAAASUVORK5CYII='); + /* background-image: url(images/dropbox-asc-hovered.png); */ +} +.tablesorter-dropbox .tablesorter-headerSortDown i.tablesorter-icon, +.tablesorter-dropbox .tablesorter-headerDesc i.tablesorter-icon { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALdJREFUeNpi/P//PwMhwBLdtVGFhZ3zNhMzC4bkv79/GP78/K7KCDIpZ9mVw+xcfDaMTExwBf///WP4+e3TkSlROrZg7UxMLLns3HxnmFnZmGGK/v7+9ff3j2+5YHkQMSlC48Kv719m/f//D2IKkAbxQeJwRSDw4/OHmr+/fr0DqmAA0SA+TA6uaEq0zjugG+r//vkFcks9iA/3HbJvvn18O+vf379yP758mMXAoAAXZyQmnAACDADX316BiTFbMQAAAABJRU5ErkJggg=='); + /* background-image: url(images/dropbox-desc.png); */ +} +.tablesorter-dropbox .tablesorter-headerSortDown:hover i.tablesorter-icon, +.tablesorter-dropbox .tablesorter-headerDesc:hover i.tablesorter-icon { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALNJREFUeNpi/P//PwMhwBJf3uP879e3PUzMzBiS//7+ZWBi43JhBJmU2z7nIzMzEx8jIyNcAUj8799/nyZXpvCzgARYuXjTWBkZVjCzIEz7++cvw+//DGkgNiPMTWVT1l5hZvynDTINbMp/pqtdOcE6IDkmmM5fv3/5//v37z9QBQOIBvFhcnBFEwoj7/5jZFnz9+8fBhAN4sN9h+ybH9++JrGxscr/+vE1CVmckZhwAggwANvlUyq5Dd1wAAAAAElFTkSuQmCC'); + /* background-image: url(images/dropbox-desc-hovered.png); */ +} +.tablesorter-dropbox thead .sorter-false { + cursor: default; +} + +.tablesorter-dropbox thead .sorter-false i.tablesorter-icon, +.tablesorter-dropbox thead .sorter-false:hover i.tablesorter-icon { + background-image: none; + padding: 4px; +} + +/* tbody */ +.tablesorter-dropbox td { + padding: 5px 6px; + line-height: 32px; + color: #555; + text-align: left; + border-top: 1px solid #edf1f5; + border-bottom: 1px solid #edf1f5; +} + +/* hovered row colors */ +.tablesorter-dropbox tbody > tr.hover > td, +.tablesorter-dropbox tbody > tr:hover > td, +.tablesorter-dropbox tbody > tr.even:hover > td, +.tablesorter-dropbox tbody > tr.odd:hover > td { + background-color: rgba(230, 245, 255, 0.3); + border-right: 0; + border-left: 0; + border-color: #c6d8e4; + /* trick to do border-top and bottom colors */ + border-style: double; +} + +/* table processing indicator */ +.tablesorter-dropbox .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-dropbox tr.odd > td { +} +.tablesorter-dropbox tr.even > td { +} + +/* Column Widget - column sort colors */ +.tablesorter-dropbox td.primary, +.tablesorter-dropbox tr.odd td.primary { +} +.tablesorter-dropbox tr.even td.primary { +} +.tablesorter-dropbox td.secondary, +.tablesorter-dropbox tr.odd td.secondary { +} +.tablesorter-dropbox tr.even td.secondary { +} +.tablesorter-dropbox td.tertiary, +.tablesorter-dropbox tr.odd td.tertiary { +} +.tablesorter-dropbox tr.even td.tertiary { +} + +/* caption */ +caption { + background-color: #fff; +} + +/* Filter Widget */ +.tablesorter-dropbox .tablesorter-filter-row { + background-color: #fff; +} +.tablesorter-dropbox .tablesorter-filter-row td { + background-color: #fff; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-dropbox .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} + +/* hidden filter row */ +.tablesorter-dropbox .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-dropbox .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} + +/* filters */ +.tablesorter-dropbox input.tablesorter-filter, +.tablesorter-dropbox select.tablesorter-filter { + width: 98%; + height: auto; + margin: 0; + background-color: #fff; + border: 1px solid #bbb; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.green.css b/css/theme.green.css new file mode 100644 index 0000000..32a0f3c --- /dev/null +++ b/css/theme.green.css @@ -0,0 +1,212 @@ +/************* + Green Theme + *************/ +/* overall */ +.tablesorter-green { + width: 100%; + text-align: left; + border-spacing: 0; + border: #cdcdcd 1px solid; + border-width: 1px 0 0 1px; +} +.tablesorter-green th, +.tablesorter-green td { + font: 12px/18px Arial, Sans-serif; + border: #cdcdcd 1px solid; + border-width: 0 1px 1px 0; +} + +/* header */ +.tablesorter-green thead tr .tablesorter-header, +.tablesorter-green tfoot tr { + background-position: center center; + background-repeat: repeat-x; + background-image: url(data:image/gif;base64,R0lGODlhAQBkAOYAAN/e39XU1fX19tTU1eXm5uTl5ePk5OLj4+Hi4vX29fT19PP08/Lz8vHy8fDx8O/w7+7v7uzt7Orr6ufo5/T08/Pz8ufn5uLi4eDg39/f3t3d3Nzc29HR0NDQz8/Pzuvq6urp6eno6Ojn5+fm5tfW1tbV1dTT09PS0tLR0dHQ0NDPz/f39/b29vX19fT09PPz8/Ly8vHx8e/v7+7u7u3t7ezs7Ovr6+rq6unp6ejo6Ofn5+bm5uXl5eTk5OPj4+Li4uHh4eDg4N/f397e3t3d3dzc3Nvb29ra2tnZ2djY2NfX19XV1dPT09LS0tHR0dDQ0M/Pz8rKysXFxf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAFMALAAAAAABAGQAAAdegCsrLC0tLi+ILi6FCSwsCS0KkhQVDA0OMjM0NTYfICEiIzw9P0AYGUQaG0ZHSEoDTU9Qs08pTk1MSyRJR0VDQT8+PTw7Ojg3NTMyMTAvi4WOhC0vMTI1OT9GTlFSgQA7); + /* background-image: url(images/green-header.gif); */ +} +.tablesorter-green th, +.tablesorter-green thead td { + font-weight: bold; + border-right: #cdcdcd 1px solid; + border-collapse: collapse; + padding: 6px; +} +.tablesorter-green .header, +.tablesorter-green .tablesorter-header-inner { + background-position: 5px center; + background-repeat: no-repeat; + background-image: url(data:image/gif;base64,R0lGODlhEAAQAOYAAA5NDBBYDlWWUzRUM5DVjp7inJ/fnQ1ECiCsGhyYFxqKFRFdDhBXDQxCCiO8HSK2HCCqGh2aGByUFxuPFhqNFhmHFRZ2EhVvERRpEBBVDSS8HiGyHB+mGh6fGRuTFxiAFBd5Eww/Cgs5CRp7Fiu+JRx8GCy/JjHAKyynKCuhJzXCMDbCMDnDMyNuHz3EODy9N0LFPSl7JkvIRjycOFDKS1LKTVPLT1XLUFTCT17OWTBkLmbQYnDTbHXVcXnWdoXago/djGmUZ112XCJEIEdjRf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEUALAAAAAAQABAAAAdlgEWCg4SFhoIvh4cVLECKhCMeJjwFj0UlEwgaMD4Gii0WFAkRHQ47BIY6IQAZDAwBCyAPOJa1toRBGBAwNTY3OT0/AoZCDQoOKi4yNDOKRCIfGycrKZYDBxIkKLZDFxy3RTHgloEAOw==); + /* background-image: url(images/green-unsorted.gif); */ + border-collapse: collapse; + white-space: normal; + cursor: pointer; +} +.tablesorter-green thead .headerSortUp .tablesorter-header-inner, +.tablesorter-green thead .tablesorter-headerSortUp .tablesorter-header-inner, +.tablesorter-green thead .tablesorter-headerAsc .tablesorter-header-inner { + background-image: url(data:image/gif;base64,R0lGODlhEAAQANUAAA5NDBBYDpDVjp7inJ/fnSCsGhyYFxFdDhBXDSO8HSK2HB2aGBuPFhqNFhmHFRZ2EhBVDSS8Hh6fGRuTFxd5Eww/Chp7Fhx8GCy/JjnDMyNuHzy9N0LFPVTCTzBkLmbQYnDTbHnWdo/djP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACMALAAAAAAQABAAAAY4wJFwSCwaj8ikcslMbpojR0bEtEwwoIHywihEOCECUvNoGBaSxEdg9FQAEAQicKAoOtC8fs8fBgEAOw==) + /* background-image: url(images/green-asc.gif); */ +} +.tablesorter-green thead .headerSortDown .tablesorter-header-inner, +.tablesorter-green thead .tablesorter-headerSortDown .tablesorter-header-inner, +.tablesorter-green thead .tablesorter-headerDesc .tablesorter-header-inner { + background-image: url(data:image/gif;base64,R0lGODlhEAAQANUAAFWWUzRUMw1EChqKFQxCCiO8HSCqGhyUFxVvERRpECGyHB+mGhiAFAs5CSu+JTHAKyynKCuhJzXCMDbCMD3EOELFPSl7JkvIRjycOFDKS1LKTVPLT1XLUF7OWXXVcYXagmmUZ112XCJEIEdjRf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACQALAAAAAAQABAAAAY4QJJwSCwaj8ikcskkghKGimbD6Xg+AGOIMChIKJcMBjlqMBSPSUQZEBwcEKYIsWiSLPa8fs9HBgEAOw==) + /* background-image: url(images/green-desc.gif); */ +} +.tablesorter-green th.tablesorter-header .tablesorter-header-inner, +.tablesorter-green td.tablesorter-header .tablesorter-header-inner { + padding-left: 23px; +} +.tablesorter-green thead .tablesorter-header.sorter-false .tablesorter-header-inner { + background-image: none; + cursor: default; + padding-left: 6px; +} + +/* tfoot */ +.tablesorter-green tbody td, +.tablesorter-green tfoot th { + padding: 6px; + vertical-align: top; +} + +/* tbody */ +.tablesorter-green td { + color: #3d3d3d; + padding: 6px; +} + +/* hovered row colors + you'll need to add additional lines for + rows with more than 2 child rows + */ +.tablesorter-green tbody > tr.hover > td, +.tablesorter-green tbody > tr:hover > td, +.tablesorter-green tbody > tr:hover + tr.tablesorter-childRow > td, +.tablesorter-green tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td, +.tablesorter-green tbody > tr.even.hover > td, +.tablesorter-green tbody > tr.even:hover > td, +.tablesorter-green tbody > tr.even:hover + tr.tablesorter-childRow > td, +.tablesorter-green tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + background-color: #d9d9d9; +} +.tablesorter-green tbody > tr.odd.hover > td, +.tablesorter-green tbody > tr.odd:hover > td, +.tablesorter-green tbody > tr.odd:hover + tr.tablesorter-childRow > td, +.tablesorter-green tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + background-color: #bfbfbf; +} + +/* table processing indicator */ +.tablesorter-green .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-green tr.odd > td { + background-color: #ebfaeb; +} +.tablesorter-green tr.even > td { + background-color: #fff; +} + +/* Column Widget - column sort colors */ +.tablesorter-green td.primary, +.tablesorter-green tr.odd td.primary { + background-color: #99e6a6; +} +.tablesorter-green tr.even td.primary { + background-color: #c2f0c9; +} +.tablesorter-green td.secondary, +.tablesorter-green tr.odd td.secondary { + background-color: #c2f0c9; +} +.tablesorter-green tr.even td.secondary { + background-color: #d6f5db; +} +.tablesorter-green td.tertiary, +.tablesorter-green tr.odd td.tertiary { + background-color: #d6f5db; +} +.tablesorter-green tr.even td.tertiary { + background-color: #ebfaed; +} + +/* caption */ +caption { + background-color: #fff; +} + +/* filter widget */ +.tablesorter-green .tablesorter-filter-row { + background-color: #eee; +} +.tablesorter-green .tablesorter-filter-row td { + background-color: #eee; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-green .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} +/* hidden filter row */ +.tablesorter-green .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-green .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* filters */ +.tablesorter-green input.tablesorter-filter, +.tablesorter-green select.tablesorter-filter { + width: 98%; + height: auto; + margin: 0; + padding: 4px; + background-color: #fff; + border: 1px solid #bbb; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.grey.css b/css/theme.grey.css new file mode 100644 index 0000000..fdb3d9b --- /dev/null +++ b/css/theme.grey.css @@ -0,0 +1,252 @@ +/************* + Grey Theme + *************/ +/* overall */ +.tablesorter-grey { + width: 100%; + margin: 10px 0 15px; + text-align: left; + border-spacing: 0; + border-left: #555 1px solid; +} + +/* header */ +.tablesorter-grey th, +.tablesorter-grey thead td { + font: bold 12px/18px Arial, Sans-serif; + color: #c8c8c8; + background-color: #3c3c3c; + background-image: -moz-linear-gradient(top, #555, #3c3c3c); + background-image: -ms-linear-gradient(top, #555, #3c3c3c); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555), to(#3c3c3c)); + background-image: -webkit-linear-gradient(top, #555, #3c3c3c); + background-image: -o-linear-gradient(top, #555, #3c3c3c); + background-image: linear-gradient(to bottom, #555,#3c3c3c); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#555555', endColorstr='#3c3c3c',GradientType=0 ); + background-repeat: repeat-x; + border-right: #555 1px solid; + text-shadow: 0 1px 0 rgba(128, 128, 128, 0.7); + -webkit-box-shadow: inset 0 1px 0 #222; + -moz-box-shadow: inset 0 1px 0 #222; + box-shadow: inset 0 1px 0 #222; + padding: 4px; +} +.tablesorter-grey .tablesorter-header-inner, +.tablesorter-grey .tablesorter-header-inner { + position: relative; + padding: 4px 15px 4px 4px; +} +.tablesorter-grey .header, +.tablesorter-grey .tablesorter-header { + cursor: pointer; +} +.tablesorter-grey .header i, +.tablesorter-grey .tablesorter-header i.tablesorter-icon { + width: 18px; + height: 10px; + position: absolute; + right: 2px; + top: 50%; + margin-top: -10px; + /* white (unsorted) double arrow */ + background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); + background-repeat: no-repeat; + background-position: center right; + padding: 4px; + white-space: normal; +} +.tablesorter-grey th.headerSortUp, +.tablesorter-grey th.tablesorter-headerSortUp, +.tablesorter-grey th.headerSortDown, +.tablesorter-grey th.tablesorter-headerSortDown { + color: #ddd; + background-color: #135185; + background-image: -moz-linear-gradient(top, #195c93, #0e4776); + background-image: -ms-linear-gradient(top, #195c93, #0e4776); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#195c93), to(#0e4776)); + background-image: -webkit-linear-gradient(top, #195c93, #0e4776); + background-image: -o-linear-gradient(top, #195c93, #0e4776); + background-image: linear-gradient(to bottom, #195c93, #0e4776); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#195c93', endColorstr='#0e4776',GradientType=0 ); +} +.tablesorter-grey .headerSortUp i.tablesorter-icon, +.tablesorter-grey .tablesorter-headerSortUp i.tablesorter-icon, +.tablesorter-grey .tablesorter-headerAsc i.tablesorter-icon { + /* white asc arrow */ + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); +} +.tablesorter-grey .headerSortDown i.tablesorter-icon, +.tablesorter-grey .tablesorter-headerSortDown i.tablesorter-icon, +.tablesorter-grey .tablesorter-headerDesc i.tablesorter-icon { + /* white desc arrow */ + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); +} +.tablesorter-grey thead .sorter-false { + cursor: default; +} +.tablesorter-grey thead .sorter-false i.tablesorter-icon { + background-image: none; + padding: 4px; +} + +/* tfoot */ +.tablesorter-grey tbody td, +.tablesorter-grey tfoot th, +.tablesorter-grey tfoot td { + padding: 4px; + vertical-align: top; + border-right: #555 1px solid; +} +.tablesorter-grey tfoot th, +.tablesorter-grey tfoot td { + padding: 8px; +} + +/* tbody */ +.tablesorter-grey td { + color: #eee; + background-color: #6d6d6d; + padding: 4px; + vertical-align: top; +} + +/* hovered row colors + you'll need to add additional lines for + rows with more than 2 child rows + */ +.tablesorter-grey tbody > tr.hover > td, +.tablesorter-grey tbody > tr:hover > td, +.tablesorter-grey tbody > tr:hover + tr.tablesorter-childRow > td, +.tablesorter-grey tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td, +.tablesorter-grey tbody > tr.even.hover > td, +.tablesorter-grey tbody > tr.even:hover > td, +.tablesorter-grey tbody > tr.even:hover + tr.tablesorter-childRow > td, +.tablesorter-grey tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + background-color: #134b78; +} +.tablesorter-grey tbody > tr.odd.hover > td, +.tablesorter-grey tbody > tr.odd:hover > td, +.tablesorter-grey tbody > tr.odd:hover + tr.tablesorter-childRow > td, +.tablesorter-grey tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + background-color: #134b78; +} + +/* table processing indicator */ +.tablesorter-grey .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-grey tbody tr.odd > td { + background-color: #5e5e5e; +} +.tablesorter-grey tbody tr.even > td { + background-color: #6d6d6d; +} + +/* Column Widget - column sort colors */ +.tablesorter-grey td.primary, +.tablesorter-grey tr.odd td.primary { + color: #ddd; + background-color: #165388; +} +.tablesorter-grey tr.even td.primary { + color: #ddd; + background-color: #195c93; +} +.tablesorter-grey td.secondary, +.tablesorter-grey tr.odd td.secondary { + color: #ddd; + background-color: #185C9A; +} +.tablesorter-grey tr.even td.secondary { + color: #ddd; + background-color: #1D67A5; +} +.tablesorter-grey td.tertiary, +.tablesorter-grey tr.odd td.tertiary { + color: #ddd; + background-color: #1B67AD; +} +.tablesorter-grey tr.even td.tertiary { + color: #ddd; + background-color: #2073B7; +} + +/* caption */ +caption { + background-color: #fff; +} + +/* filter widget */ +.tablesorter-grey .tablesorter-filter-row { + background-color: #3c3c3c; +} +.tablesorter-grey .tablesorter-filter-row td { + background-color: #3c3c3c; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-grey .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} +/* hidden filter row */ +.tablesorter-grey .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-grey .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* filters */ +.tablesorter-grey input.tablesorter-filter, +.tablesorter-grey select.tablesorter-filter { + width: 98%; + height: auto; + margin: 0; + padding: 4px; + background-color: #6d6d6d; + border: 1px solid #555; + color: #ddd; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.ice.css b/css/theme.ice.css new file mode 100644 index 0000000..0b406de --- /dev/null +++ b/css/theme.ice.css @@ -0,0 +1,212 @@ +/************* + Ice Theme (by thezoggy) + *************/ +/* overall */ +.tablesorter-ice { + width: 100%; + background-color: #fff; + margin: 10px 0 15px; + text-align: left; + border-spacing: 0; + border: #ccc 1px solid; + border-width: 1px 0 0 1px; +} +.tablesorter-ice th, +.tablesorter-ice td { + border: #ccc 1px solid; + border-width: 0 1px 1px 0; +} + +/* header */ +.tablesorter-ice th, +.tablesorter-ice thead td { + font: 12px/18px Arial, Sans-serif; + color: #555; + background-color: #f6f8f9; + border-collapse: collapse; + padding: 4px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7); +} +.tablesorter-ice tbody td, +.tablesorter-ice tfoot th, +.tablesorter-ice tfoot td { + padding: 4px; + vertical-align: top; +} +.tablesorter-ice .header, +.tablesorter-ice .tablesorter-header { + background-color: #f6f8f9; + background-position: center right; + background-repeat: no-repeat; + background-image: url(data:image/gif;base64,R0lGODlhDAAMAMQAAAJEjAJCiwJBigJAiANFjgNGjgNEjQRIkQRHkANIkAVMlAVQmAZWnQZUnAdYoAhdpAhZoAlhqQlepQliqQppsApmrQxutgtutQtutAxwtwxwtg1yug1zugxtsw1yuP8A/yH5BAEAAB8ALAAAAAAMAAwAAAUx4Cd+3GiOW4ado2d9VMVm1xg9ptadTsP+QNZEcjoQTBDGCAFgLRSfQgCYMAiCn8EvBAA7); + /* background-image: url(images/ice-unsorted.gif) */ + padding: 4px 20px 4px 4px; + white-space: normal; + cursor: pointer; +} +.tablesorter-ice .headerSortUp, +.tablesorter-ice .tablesorter-headerSortUp, +.tablesorter-ice .tablesorter-headerAsc { + color: #333; + background-color: #ebedee; + background-position: center right; + background-repeat: no-repeat; + background-image: url(data:image/gif;base64,R0lGODlhDAAMANUAAAJCiwNHkANFjgNEjQRIkQNJkQRMlARKkwRKkgVPlwZSmgdaogdYnwhfpghcowlhqgliqglgqAlgpwljqwporwpmrQplrAtsswtqsgtrsgtqsQxttAtvtQtttAxyuQxwtwxxtwxvtg10uw1zuQ1xuP8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAMAAwAAAY6wJKwJBoahyNQ6Dj0fDoZCpPEuWgqk4jxs8FQLI+Gg8Esm5kQydFQMC7IwkOAqUiUCAIzIjA4lwBlQQA7); + /* background-image: url(images/ice-desc.gif) */ +} +.tablesorter-ice .headerSortDown, +.tablesorter-ice .tablesorter-headerSortDown, +.tablesorter-ice .tablesorter-headerDesc { + color: #333; + background-color: #ebedee; + background-position: center right; + background-repeat: no-repeat; + background-image: url(data:image/gif;base64,R0lGODlhDAAMANUAAAE/iAJBigNFjgNEjQNFjQNDiwRHkQRHjwNHjwROlgRMlQRMlARJkgRKkgZQmAVPlgZWnQZSmgZRmAdXoAdXnwdUnAdbogdZoQhbowlhqAlepglkrAliqQtstAtqsQxyugxyuQxwuAxxuAxxtwxwtgxvtQ10vA12vA10u/8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACkALAAAAAAMAAwAAAY6wJQwdRoah6bP6DhEiVIdDxNEGm4yxlDpiJkwv2AmR2OhVCSJBsJ4gUQeCwOB6VAwBAXwYRAIpwBfQQA7); + /* background-image: url(images/ice-asc.gif); */ +} +.tablesorter-ice thead .sorter-false { + background-image: none; + cursor: default; + padding: 4px; +} + +/* tfoot */ +.tablesorter-ice tfoot .tablesorter-headerSortUp, +.tablesorter-ice tfoot .tablesorter-headerSortDown, +.tablesorter-ice tfoot .tablesorter-headerAsc, +.tablesorter-ice tfoot .tablesorter-headerDesc { + background-color: #ebedee; +} + +/* tbody */ +.tablesorter-ice td { + color: #333; +} + +/* hovered row colors */ +.tablesorter-ice tbody > tr.hover > td, +.tablesorter-ice tbody > tr:hover > td, +.tablesorter-ice tbody > tr.even:hover > td, +.tablesorter-ice tbody > tr.odd:hover > td { + background-color: #ebf2fa; +} + +/* table processing indicator */ +.tablesorter-ice .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-ice tr.odd > td { + background-color: #dfdfdf; +} +.tablesorter-ice tr.even > td { + background-color: #efefef; +} + +/* Column Widget - column sort colors */ +.tablesorter-ice td.primary, +.tablesorter-ice tr.odd td.primary { + background-color: #9ae5e5; +} +.tablesorter-ice tr.even td.primary { + background-color: #c2f0f0; +} +.tablesorter-ice td.secondary, +.tablesorter-ice tr.odd td.secondary { + background-color: #c2f0f0; +} +.tablesorter-ice tr.even td.secondary { + background-color: #d5f5f5; +} +.tablesorter-ice td.tertiary, +.tablesorter-ice tr.odd td.tertiary { + background-color: #d5f5f5; +} +.tablesorter-ice tr.even td.tertiary { + background-color: #ebfafa; +} + +/* sticky headers */ +.tablesorter-ice.containsStickyHeaders thead tr:nth-child(1) th, +.tablesorter-ice.containsStickyHeaders thead tr:nth-child(1) td { + border-top: #ccc 1px solid; +} + +/* caption */ +caption { + background-color: #fff; +} + +/* filter widget */ +.tablesorter-ice .tablesorter-filter-row { + background-color: #eee; +} +.tablesorter-ice .tablesorter-filter-row td { + background-color: #eee; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-ice .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} +/* hidden filter row */ +.tablesorter-ice .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-ice .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* filters */ +.tablesorter-ice input.tablesorter-filter, +.tablesorter-ice select.tablesorter-filter { + width: 98%; + height: auto; + margin: 0; + padding: 4px; + background-color: #fff; + border: 1px solid #bbb; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.jui.css b/css/theme.jui.css new file mode 100644 index 0000000..aa1309b --- /dev/null +++ b/css/theme.jui.css @@ -0,0 +1,164 @@ +/************* + jQuery UI Theme + *************/ + /* overall */ +.tablesorter-jui { + width: 100%; + border-collapse: separate; + border-spacing: 2px; /* adjust spacing between table cells */ + margin: 10px 0 15px; + padding: 5px; + font-size: 0.8em; +} + +/* header */ +.tablesorter-jui thead th, +.tablesorter-jui thead td, +.tablesorter-jui tfoot th, +.tablesorter-jui tfoot td { + position: relative; + background-repeat: no-repeat; + background-position: right center; + /* UI hover and active states make the font normal and the table resizes, this fixes it */ + font-weight: bold !important; + border-width: 1px !important; + text-align: left; + padding: 8px; /* wider than the icon */ +} +.tablesorter-jui .header, +.tablesorter-jui .tablesorter-header { + cursor: pointer; + white-space: normal; +} +.tablesorter-jui .tablesorter-header-inner { + padding-right: 20px; +} +.tablesorter-jui thead tr th .ui-icon { + position: absolute; + right: 3px; + top: 50%; + margin-top: -8px; /* half the icon height; older IE doesn't like this */ +} + +.tablesorter-jui thead .sorter-false { + cursor: default; +} +.tablesorter-jui thead tr .sorter-false .ui-icon { + display: none; +} + +/* tfoot */ +.tablesorter-jui tfoot th, +.tablesorter-jui tfoot td { + font-weight: normal !important; + font-size: .9em; + padding: 2px; +} + +/* tbody */ +.tablesorter-jui td { + padding: 4px; + vertical-align: top; +} + +/* hovered row colors */ +.tablesorter-jui tbody > tr.hover > td, +.tablesorter-jui tbody > tr:hover > td { + opacity: 0.7; + filter: alpha(opacity=70); +} + +/* table processing indicator */ +.tablesorter-jui .tablesorter-processing .tablesorter-header-inner { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important; +} + +/* Zebra widget - This allows you to use ui-state-default as the zebra stripe color */ +.tablesorter-jui tr.ui-state-default { + background-image: none; + font-weight: normal; +} + +/* processing background color */ +.tablesorter-jui .tablesorter-processing { + background-color: #ddd; /* older browsers that don't support rgba */ + background-color: rgba(255,255,255,0.8); +} + +/* caption */ +.tablesorter-jui caption { + border: 0; +} + +/* filter widget */ +.tablesorter-jui .tablesorter-filter-row { + background-color: transparent; +} +.tablesorter-jui .tablesorter-filter-row td { + background-color: transparent; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-jui .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} +/* hidden filter row */ +.tablesorter-jui .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-jui .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* filters */ +.tablesorter-jui input.tablesorter-filter, +.tablesorter-jui select.tablesorter-filter { + width: 98%; + height: auto; + margin: 0; + padding: 4px; + background-color: #fff; + border: 1px solid #bbb; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/css/theme.less b/css/theme.less new file mode 100644 index 0000000..c0a4d79 --- /dev/null +++ b/css/theme.less @@ -0,0 +1,329 @@ +/* Tablesorter Custom LESS Theme by Rob Garrison + + To create your own theme, modify the code below and run it through + a LESS compiler, like this one: http://leafo.net/lessphp/editor.html + or download less.js from http://lesscss.org/ + +Test out these custom less files live + Basic Theme : http://codepen.io/Mottie/pen/eqBbn + Bootstrap : http://codepen.io/Mottie/pen/Ltzpi + Metro Style : http://codepen.io/Mottie/pen/gCslk + + */ + +/*** theme ***/ +@theme : tablesorter-custom; + +/*** fonts ***/ +@tableHeaderFont : 11px 'trebuchet ms', verdana, arial; +@tableBodyFont : 11px 'trebuchet ms', verdana, arial; + +/*** color definitions ***/ +/* for best results, only change the hue (120), + leave the saturation (60%) and luminosity (75%) alone + pick the color from here: http://hslpicker.com/#99E699 */ +@headerBackground : hsl(120, 60%, 75%); +@borderAndBackground : #cdcdcd; +@overallBorder : @borderAndBackground 1px solid; +@headerTextColor : #000; + +@bodyBackground : #fff; +@bodyTextColor : #000; + +@headerAsc : darken(spin(@headerBackground, 5), 10%); /* darken(@headerBackground, 10%); */ +@headerDesc : lighten(spin(@headerBackground, -5), 10%); /* desaturate(@headerAsc, 5%); */ + +@captionBackground : #fff; /* it might be best to match the document body background color here */ +@errorBackground : #e6bf99; /* ajax error message (added to thead) */ + +@filterCellBackground : #eee; +@filterElementTextColor: #333; +@filterElementBkgd : #fff; +@filterElementBorder : 1px solid #bbb; +@filterTransitionTime : 0.1s; +@filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */ + +@overallPadding : 4px; +/* 20px should be slightly wider than the icon width to avoid overlap */ +@headerPadding : 4px 20px 4px 4px; + +/* url(icons/loading.gif); */ +@processingIcon : url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs='); + +/* zebra striping */ +.allRows { + background-color: @bodyBackground; + color: @bodyTextColor; +} +.evenRows { + background-color: lighten(@headerBackground, 40%); + color: @bodyTextColor; +} +.oddRows { + background-color: lighten(@headerBackground, 20%); +} + +/* hovered rows */ +.oddHovered { + background-color: desaturate(@headerBackground, 60%); + color: @bodyTextColor; +} +.evenHovered { + background-color: lighten( desaturate(@headerBackground, 60%), 10% ); + color: @bodyTextColor; +} + +/* Columns widget */ +@primaryOdd : spin(@headerBackground, 10); /* saturate( darken( desaturate(@headerBackground, 10%), 10% ), 30%); */ +@primaryEven : lighten( @primaryOdd, 10% ); +@secondaryOdd : @primaryEven; +@secondaryEven : lighten( @primaryEven, 5% ); +@tertiaryOdd : @secondaryEven; +@tertiaryEven : lighten( @secondaryEven, 5% ); + +/* Filter widget transition */ +.filterWidgetTransition { + -webkit-transition: line-height @filterTransitionTime ease; + -moz-transition: line-height @filterTransitionTime ease; + -o-transition: line-height @filterTransitionTime ease; + transition: line-height @filterTransitionTime ease; +} + +/*** Arrows ***/ +@arrowPosition : right 5px center; + +/* black */ +@unsortedBlack : url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); +@sortAscBlack : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); +@sortDescBlack : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); + +/* white */ +@unsortedWhite : url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); +@sortAscWhite : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); +@sortDescWhite : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); + +/* automatically choose the correct arrow/text color */ +.headerText (@a) when (lightness(@a) >= 50%) { + color: @headerTextColor; +} +.headerText (@a) when (lightness(@a) < 50%) { + color: lighten(@headerTextColor, 90%); +} +.unsorted (@a) when (lightness(@a) >= 50%) { + background-image: @unsortedBlack; +} +.unsorted (@a) when (lightness(@a) < 50%) { + background-image: @unsortedWhite; +} +.sortAsc (@a) when (lightness(@a) >= 50%) { + background-image: @sortAscBlack; +} +.sortAsc (@a) when (lightness(@a) < 50%) { + background-image: @sortAscWhite; +} +.sortDesc (@a) when (lightness(@a) >= 50%) { + background-image: @sortDescBlack; +} +.sortDesc (@a) when (lightness(@a) < 50%) { + background-image: @sortDescWhite; +} + +/* variable theme name - requires less.js 1.3+; + or just replace (!".@{theme}") with the contents of @theme + */ +.@{theme} { + font: @tableBodyFont; + background-color: @borderAndBackground; + margin: 10px 0 15px; + width: 100%; + text-align: left; + border-spacing: 0; + border: @overallBorder; + border-width: 1px 0 0 1px; + + th, td { + border: @overallBorder; + border-width: 0 1px 1px 0; + } + + /* style th's outside of the thead */ + th, thead td { + font: @tableHeaderFont; + font-weight: bold; + background-color: @headerBackground; + .headerText(@headerBackground); + border-collapse: collapse; + padding: @overallPadding; + } + + tbody td, tfoot th, tfoot td { + padding: @overallPadding; + vertical-align: top; + } + + /* style header */ + .tablesorter-header { + .unsorted(@headerBackground); + background-repeat: no-repeat; + background-position: @arrowPosition; + padding: @headerPadding; + cursor: pointer; + } + + .tablesorter-header.sorter-false { + background-image: none; + cursor: default; + padding: @overallPadding; + } + + .tablesorter-headerAsc { + background-color: @headerAsc; + .sortAsc(@headerBackground); + } + + .tablesorter-headerDesc { + background-color: @headerDesc; + .sortDesc(@headerBackground); + } + + /* tfoot */ + tfoot .tablesorter-headerAsc, + tfoot .tablesorter-headerDesc { + /* remove sort arrows from footer */ + background-image: none; + } + + /* optional disabled input styling */ + .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; + } + + /* body */ + tbody { + + td { + .allRows; + padding: @overallPadding; + vertical-align: top; + } + + /* Zebra Widget - row alternating colors */ + tr.odd > td { + .oddRows; + } + tr.even > td { + .evenRows; + } + + } + + /* hovered row colors + you'll need to add additional lines for + rows with more than 2 child rows + */ + tbody > tr.hover td, + tbody > tr:hover td, + tbody > tr:hover + tr.tablesorter-childRow > td, + tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td, + tbody > tr.even.hover > td, + tbody > tr.even:hover > td, + tbody > tr.even:hover + tr.tablesorter-childRow > td, + tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .evenHovered; + } + tbody > tr.odd.hover > td, + tbody > tr.odd:hover > td, + tbody > tr.odd:hover + tr.tablesorter-childRow > td, + tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .oddHovered; + } + + /* table processing indicator - indeterminate spinner */ + .tablesorter-processing { + background-image: @processingIcon; + background-position: center center; + background-repeat: no-repeat; + } + + /* Column Widget - column sort colors */ + tr.odd td.primary { + background-color: @primaryOdd; + } + td.primary, tr.even td.primary { + background-color: @primaryEven; + } + tr.odd td.secondary { + background-color: @secondaryOdd; + } + td.secondary, tr.even td.secondary { + background-color: @secondaryEven; + } + tr.odd td.tertiary { + background-color: @tertiaryOdd; + } + td.tertiary, tr.even td.tertiary { + background-color: @tertiaryEven; + } + + /* caption (non-theme matching) */ + caption { + background-color: @captionBackground ; + } + + /* filter widget */ + .tablesorter-filter-row input, + .tablesorter-filter-row select { + width: 98%; + height: auto; + margin: 0; + padding: @overallPadding; + color: @filterElementTextColor; + background-color: @filterElementBkgd; + border: @filterElementBorder; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + .filterWidgetTransition; + } + .tablesorter-filter-row { + background-color: @filterCellBackground; + } + .tablesorter-filter-row td { + text-align: center; + background-color: @filterCellBackground; + line-height: normal; + text-align: center; /* center the input */ + .filterWidgetTransition; + } + /* hidden filter row */ + .tablesorter-filter-row.hideme td { + padding: @filterRowHiddenHeight / 2; + margin: 0; + line-height: 0; + cursor: pointer; + } + .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); + } + /* rows hidden by filtering (needed for child rows) */ + .filtered { + display: none; + } + + /* ajax error row */ + .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: @errorBackground; + } + +} diff --git a/css/theme.metro-dark.css b/css/theme.metro-dark.css new file mode 100644 index 0000000..461c2db --- /dev/null +++ b/css/theme.metro-dark.css @@ -0,0 +1,197 @@ +/************* +Metro Dark Theme +*************/ +/* overall */ +.tablesorter-metro-dark { + width: 100%; + font: 12px/18px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif; + color: #000; + background-color: #333; + border-spacing: 0; + margin: 10px 0 15px; + text-align: left; +} + +.tablesorter-metro-dark tr.dark-row th, .tablesorter-metro-dark tr.dark-row td, .tablesorter-metro-dark caption.dark-row { + background-color: #222; + color: #fff; + padding: 2px; + text-align: left; + font-size: 14px; +} + +/* header/footer */ +.tablesorter-metro-dark caption, +.tablesorter-metro-dark th, +.tablesorter-metro-dark thead td, +.tablesorter-metro-dark tfoot th, +.tablesorter-metro-dark tfoot td { + font-weight: 300; + font-size: 15px; + color: #ddd; + background-color: #333; + padding: 4px; +} + +.tablesorter-metro-dark .header, +.tablesorter-metro-dark .tablesorter-header { + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAGFBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u5jNePWAAAACHRSTlMAMxIHKwEgMWD59H4AAABSSURBVAjXY2BgYFJgAAHzYhDJ6igSAKTYBAUTgJSioKAQAwNzoaCguAFDiCAQuDIkgigxBgiA8cJAVCpQt6AgSL+JoKAzA0gjUBsQqBcBCYhFAAE/CV4zeSzxAAAAAElFTkSuQmCC); + background-position: right 5px center; + background-repeat: no-repeat; + cursor: pointer; + white-space: normal; +} +.tablesorter-metro-dark .tablesorter-header-inner { + padding: 0 18px 0 4px; +} +.tablesorter-metro-dark thead .headerSortUp, +.tablesorter-metro-dark thead .tablesorter-headerSortUp, +.tablesorter-metro-dark thead .tablesorter-headerAsc { + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u5meJAOAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC); +} +.tablesorter-metro-dark thead .headerSortDown, +.tablesorter-metro-dark thead .tablesorter-headerSortDown, +.tablesorter-metro-dark thead .tablesorter-headerDesc { + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAALVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7i0NViAAAADnRSTlMAMiweCQITTvDctZZqaTlM310AAABcSURBVAjXY2BgYEtgAAFHERDJqigUAKSYBQUNgFSioKAYAwOLIBA4MASBKFUGQxAlzAAF+94BwWuGKBC1lIFl3rt3Lx0YGCzevWsGSjK9e6cAUlT3HKyW9wADAwDRrBiDy6bKzwAAAABJRU5ErkJggg==); +} +.tablesorter-metro-dark thead .sorter-false { + background-image: none; + cursor: default; + padding: 4px; +} + +/* tbody */ +.tablesorter-metro-dark td { + background-color: #fff; + padding: 4px; + vertical-align: top; +} + +/* hovered row colors */ +.tablesorter-metro-dark tbody > tr.hover > td, +.tablesorter-metro-dark tbody > tr:hover > td, +.tablesorter-metro-dark tbody > tr.even:hover > td, +.tablesorter-metro-dark tbody > tr.odd:hover > td { + background-color: #bbb; + color: #000; +} + +/* table processing indicator */ +.tablesorter-metro-dark .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(images/loading.gif) !important; */ + background-image: url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=) !important; +} + +/* pager */ +.tablesorter-metro-dark .tablesorter-pager button { + background-color: #444; + color: #eee; + border: #555 1px solid; + cursor: pointer; +} +.tablesorter-metro-dark .tablesorter-pager button:hover { + background-color: #555; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-metro-dark tr.odd > td { + background-color: #eee; +} +.tablesorter-metro-dark tr.even > td { + background-color: #fff; +} + +/* Column Widget - column sort colors */ +.tablesorter-metro-dark tr.odd td.primary { + background-color: #bfbfbf; +} +.tablesorter-metro-dark td.primary, +.tablesorter-metro-dark tr.even td.primary { + background-color: #d9d9d9; +} +.tablesorter-metro-dark tr.odd td.secondary { + background-color: #d9d9d9; +} +.tablesorter-metro-dark td.secondary, +.tablesorter-metro-dark tr.even td.secondary { + background-color: #e6e6e6; +} +.tablesorter-metro-dark tr.odd td.tertiary { + background-color: #e6e6e6; +} +.tablesorter-metro-dark td.tertiary, +.tablesorter-metro-dark tr.even td.tertiary { + background-color: #f2f2f2; +} + +/* filter widget */ +.tablesorter-metro-dark .tablesorter-filter-row { + background-color: #eee; +} +.tablesorter-metro-dark .tablesorter-filter-row td { + background-color: #eee; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-metro-dark .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} +/* hidden filter row */ +.tablesorter-metro-dark .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-metro-dark .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* filters */ +.tablesorter-metro-dark input.tablesorter-filter, +.tablesorter-metro-dark select.tablesorter-filter { + width: 95%; + height: auto; + margin: 0; + padding: 4px; + background-color: #fff; + border: 1px solid #bbb; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/dist/css/dragtable.mod.min.css b/dist/css/dragtable.mod.min.css new file mode 100644 index 0000000..a342511 --- /dev/null +++ b/dist/css/dragtable.mod.min.css @@ -0,0 +1 @@ +.dragtable-sortable{list-style-type:none;margin:0;padding:0;-moz-user-select:none;z-index:10}.dragtable-sortable li{margin:0;padding:0;float:left;font-size:1em}.dragtable-sortable table{margin-top:0}.dragtable-sortable td,.dragtable-sortable th{border-left:0}.dragtable-sortable li:first-child td,.dragtable-sortable li:first-child th{border-left:1px solid #CCC}.ui-sortable-helper{opacity:.7;filter:alpha(opacity=70)}.ui-sortable-placeholder{-moz-box-shadow:4px 5px 4px rgba(0,0,0,.2)inset;-webkit-box-shadow:4px 5px 4px rgba(0,0,0,.2)inset;box-shadow:4px 5px 4px rgba(0,0,0,.2)inset;border-bottom:1px solid rgba(0,0,0,.2);border-top:1px solid rgba(0,0,0,.2);visibility:visible!important;background:#EFEFEF}.ui-sortable-placeholder *{opacity:0;visibility:hidden}.table-handle,.table-handle-disabled{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyIiBoZWlnaHQ9IjEzIj48cmVjdCBzdHlsZT0iZmlsbDojMzMzO2ZpbGwtb3BhY2l0eTouODsiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHg9IjEiIHk9IjIiLz4JPHJlY3Qgc3R5bGU9ImZpbGw6IzMzMztmaWxsLW9wYWNpdHk6Ljg7IiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4PSIxIiB5PSI0Ii8+CTxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iNiIvPjxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iOCIvPjxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iMTAiLz48L3N2Zz4=);background-repeat:repeat-x;height:13px;margin:0 1px;cursor:move}.table-handle-disabled{opacity:0;cursor:not-allowed}.dragtable-sortable table{margin-bottom:0} \ No newline at end of file diff --git a/dist/css/filter.formatter.min.css b/dist/css/filter.formatter.min.css new file mode 100644 index 0000000..9b08b8a --- /dev/null +++ b/dist/css/filter.formatter.min.css @@ -0,0 +1 @@ +.tablesorter .tablesorter-filter-row td{text-align:center;font-size:.9em;font-weight:400}.tablesorter .ui-slider,.tablesorter input.range{width:90%;margin:2px auto;font-size:.8em}.tablesorter .ui-slider{top:12px}.tablesorter .ui-slider .ui-slider-handle{width:.9em;height:.9em}.tablesorter .ui-datepicker{font-size:.8em}.tablesorter .ui-slider-horizontal{height:.5em}.tablesorter .value-popup:after{content:attr(data-value);position:absolute;bottom:14px;left:-7px;min-width:18px;height:12px;background-color:#444;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#999));background-image:-webkit-linear-gradient(top,#444,#999);background-image:-moz-linear-gradient(top,#444,#999);background-image:-o-linear-gradient(top,#444,#999);background-image:linear-gradient(to bottom,#444,#999);-webkit-border-radius:3px;border-radius:3px;-webkit-background-clip:padding-box;background-clip:padding-box;-webkit-box-shadow:0 0 4px 0 #777;box-shadow:0 0 4px 0 #777;border:1px solid #444;color:#fff;font:1em/1.1em Arial,Sans-Serif;padding:1px;text-align:center}.tablesorter .value-popup:before{content:"";position:absolute;width:0;height:0;border-top:8px solid #777;border-left:8px solid transparent;border-right:8px solid transparent;top:-8px;left:50%;margin-left:-8px;margin-top:-1px}.tablesorter .dateFrom,.tablesorter .dateTo{width:80px;margin:2px 5px}.tablesorter .button{width:14px;height:14px;background:#fcfff4;background:-webkit-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:-moz-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:-o-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:-ms-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfff4', endColorstr='#b3bead', GradientType=0 );margin:1px 5px 1px 1px;-webkit-border-radius:25px;-moz-border-radius:25px;border-radius:25px;-webkit-box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);-moz-box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);position:relative;top:3px;display:inline-block}.tablesorter .button label{cursor:pointer;width:10px;height:10px;border-radius:25px;left:2px;top:2px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,1);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,1);box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,1);background:#45484d;background:-webkit-linear-gradient(top,#222 0,#45484d 100%);background:-moz-linear-gradient(top,#222 0,#45484d 100%);background:-o-linear-gradient(top,#222 0,#45484d 100%);background:-ms-linear-gradient(top,#222 0,#45484d 100%);background:linear-gradient(top,#222 0,#45484d 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#222', endColorstr='#45484d', GradientType=0 )}.tablesorter .button label,.tablesorter .button label:after{position:absolute;-webkit-border-radius:25px;-moz-border-radius:25px}.tablesorter .button label:after{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);opacity:0;content:'';width:8px;height:8px;background:#55f;background:-webkit-linear-gradient(top,#aaf 0,#55f 100%);background:-moz-linear-gradient(top,#aaf 0,#55f 100%);background:-o-linear-gradient(top,#aaf 0,#55f 100%);background:-ms-linear-gradient(top,#aaf 0,#55f 100%);background:linear-gradient(top,#aaf 0,#55f 100%);border-radius:25px;top:1px;left:1px;-webkit-box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);-moz-box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5)}.tablesorter .button label:hover::after{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";filter:alpha(opacity=30);opacity:.3}.tablesorter .button input[type=checkbox]{visibility:hidden}.tablesorter .button input[type=checkbox]:checked+label:after{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);opacity:1}.tablesorter .colorpicker{width:30px;height:18px}.tablesorter .ui-spinner-input{width:100px;height:18px}.tablesorter .currentColor,.tablesorter .ui-spinner,.tablesorter input.number{position:relative}.tablesorter .tablesorter-filter-row.hideme td *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)} \ No newline at end of file diff --git a/dist/css/images/black-asc.gif b/dist/css/images/black-asc.gif new file mode 100644 index 0000000000000000000000000000000000000000..730533fa3570dd4805cec70fe2630e85a2e1b863 GIT binary patch literal 48 zcmZ?wbhEHbWM^PuXkcJa);0M5|G(l-7DfgJMg|=QAOOiQFtPU}a;`qj$IW0300PSi A(EtDd literal 0 HcmV?d00001 diff --git a/dist/css/images/black-desc.gif b/dist/css/images/black-desc.gif new file mode 100644 index 0000000000000000000000000000000000000000..4c3b61020bb4d707e41e94fbf2b6ebe5d0c87f6b GIT binary patch literal 49 zcmZ?wbhEHbWM^PuXkcJa);0M5|G(l-7DfgJMg|=QAOOiQFmbf-H%eylMrtrv0{{qN B3331c literal 0 HcmV?d00001 diff --git a/dist/css/images/black-unsorted.gif b/dist/css/images/black-unsorted.gif new file mode 100644 index 0000000000000000000000000000000000000000..5647f658329230706ec09c5e3c24fae39d225a04 GIT binary patch literal 54 zcmZ?wbhEHbWM|-HXkcJa);0M5|G(l-7DfgJMg|=QAOOiQF!A;za;`qjH@QXcLR*>^ GgEatAw+#UR literal 0 HcmV?d00001 diff --git a/dist/css/images/bootstrap-black-unsorted.png b/dist/css/images/bootstrap-black-unsorted.png new file mode 100644 index 0000000000000000000000000000000000000000..4e161a65ec0d89596124ebd5eeb18014e900fc5f GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^+(697!3-qN?H5}Pq(TCGLR^8glao_qWTd2|7*RL%sEWEtDfVy;b zbxll6jE#-e)zyOpeq8{XD^U{U7tC<&w4}=pSw^+cIEHXsFFo$b)S$q_a*%=RSZ%q`zyJQp@4l^^wPsR(OvfDM=HriKqBL$joSm{K zXVT90He-#d&nmaQUaJZJH4i^GW#_qP3J;DgTe~DWM4fZ4GGK literal 0 HcmV?d00001 diff --git a/dist/css/images/bootstrap-white-unsorted.png b/dist/css/images/bootstrap-white-unsorted.png new file mode 100644 index 0000000000000000000000000000000000000000..fb227a150ec672948d40c0989ab4654957d4074c GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^+(697!VF^h|6T^9v;urWT!Hj|;y~N(Q~E&Fyd^?&UREc$ gEEzP#QWe-4B7cis^t&#$e5Qt)Q)VVuxK2V0i)78&qol`;+0PtZJpa1{> literal 0 HcmV?d00001 diff --git a/dist/css/images/dragtable-handle.svg b/dist/css/images/dragtable-handle.svg new file mode 100644 index 0000000..041ec1d --- /dev/null +++ b/dist/css/images/dragtable-handle.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/dist/css/images/dropbox-asc-hovered.png b/dist/css/images/dropbox-asc-hovered.png new file mode 100644 index 0000000000000000000000000000000000000000..bc45223f1dec5faab874457b501249849a5ad67a GIT binary patch literal 275 zcmV+u0qp*XP)N!0YroNDAvUkG#GGj^Q5tJa56A6voL^Y5FaECSH#ZAHJO8p z2Pn@9bO0j*hz9XN;vjkEyC0cUxcLQpK-MrZGeaB-RLI1{#PIL`Ke-j_w=ZQRCY%5Q Z3;^4XF8Gf^mEZsX002ovPDHLkV1l>1alZfn literal 0 HcmV?d00001 diff --git a/dist/css/images/dropbox-asc.png b/dist/css/images/dropbox-asc.png new file mode 100644 index 0000000000000000000000000000000000000000..0d6ee15054013562d87105ebf9a5915b093b745a GIT binary patch literal 278 zcmV+x0qOpUP)c1cZKk`S9+`+ZU=! zioM^Vn8eP-+rq^!EX2hx!~mi}d=%^AChRcaJ^%m!07*qoM6N<$f|sClJ^%m! literal 0 HcmV?d00001 diff --git a/dist/css/images/dropbox-desc-hovered.png b/dist/css/images/dropbox-desc-hovered.png new file mode 100644 index 0000000000000000000000000000000000000000..4930942048212f647f27b8c8f06ec2737a7ee016 GIT binary patch literal 273 zcmV+s0q*{ZP)o985veE zvmi|S`{ysi@Ba*GAT}e+O=VNoUSVeZrwuXEnMIi9w^M{(hzka;~ zs$c-oAU;eEu4qcM&O4wR>i_=v1#(M0h!6K2vTwe9d^_vk-@kG{zI>R)z@PvZXCx+^ b00ImE*WX@&i7{I-00000NkvXXu0mjf>Ct&J literal 0 HcmV?d00001 diff --git a/dist/css/images/first.png b/dist/css/images/first.png new file mode 100644 index 0000000000000000000000000000000000000000..6f11fcb086b1bfa51bc5070ca45fac0a988c624c GIT binary patch literal 720 zcmV;>0x$iEP)ITpohD^Ctgf=H~o==W*|y0)VM;-LQd9lR=YF)677| z!Jh8V_;KSkP5LJrlF9S+j0qkk+2iPm7~x{#{$ZSbvzK9J-4zqYVC)27V7~717pTZd znit9v$VwYJS3ROyLxp^?0)a!0U)oMn7(0Xv0eUoZ@gH)t)d5_J+J%bT22oSJ)g^nf zqQZVCEIYOm2+rB;rB+cID%~N1o%g50=A<=fWgC_GFUb) z%s4&22M=t~3G+RMgR^pz#KbcfK)ZtsdJ$j@d{400GnQJeAz+sPu#&f$`6hKh0J%~V zq(%oWs|qZyzh}{lfSK@dRK#JSxg@DDP3^*cD+kP0j(npKkSQvp3bk_uYtD5My##O+ z;RpcDs9R5c#9;NFP5{z^GN_^r%PX%(0OOZ~7+aNFP*XZk{E2|i#E`vI`YjCrsfz|V zndEsDXoqvug2CxaF}ZvhdOaY6!{9q~KO+jO!o5Vk0qt%NcD}`cvVR;6QTNzYGWq-= zUX+?7V0e7VLW2m6_>T!vT6W8eRsOC$*+0hNMWWwDsLfA)S*X-WV71;M{bCz|Ns9CGysY}Sr{1@lo@nDW`q31z-Dn^Vu6Q_RR4)3 zMJIjoW+}V79ogbzu%PkNAq^J`MW&$784_ZXj<_d$31JXmQ7TxVVRd0o-FbO7Mh0sD Dr2|2x literal 0 HcmV?d00001 diff --git a/dist/css/images/green-desc.gif b/dist/css/images/green-desc.gif new file mode 100644 index 0000000000000000000000000000000000000000..4f8817650dc07236f0f884cb826413ceeba2e1e6 GIT binary patch literal 283 zcmZ?wbhEHb6krfwxXQo~IxW~F#F*EGOR7th$B9dMkF3HfDVZtaqWOX%nF5NNWaO7g zNi>LXTXJgeQ#CxGt+QN1d!f4NAp^5R2DV2moQ~RRR;ziRaI=|X5pc>o=#+2pY5&mE z0deOdORpBT-fGI6k{(+YqvWFCp6vSn|9=K*1I3>#j0_Aa3_2i#L4IOjvv8PH;GrYc ze_~0|NtGs{wyw0pFDvXAk~<7EJT#{Buvumqi1d59ND9cv2rT2+m@!G`+n&1f?re+< F)&TJsK)V0{ literal 0 HcmV?d00001 diff --git a/dist/css/images/green-header.gif b/dist/css/images/green-header.gif new file mode 100644 index 0000000000000000000000000000000000000000..cc746b70a390d3c1e60dd0839aafaefdb56ffa5c GIT binary patch literal 513 zcmd7P%Sr-a7zW^93c{#X1sxV;wFw=D$Ppmun&SRq#z*(T68O2gBur(hZ)a0 zI!B!uXPm=7(#q7@)D`rtU*6}1FB}PZymuyW4_E+*I)P(2ga(G;49n6CL(w!zQB9JB z2GpUh>6)skimG&#uH2O+SrR)UFYsK8({)YLRE}dwve{@51W~Wms?};GlS!x3D2jdv zJkPh=?N+PB4N`0&pU>ksmdoX`*=*(~)$8>P!+;R#-*u|0D2go0k|cFH9Z?ho;ZF_A zFbqx86h)B(xH+Ilc733a_)4W*E|*HBVzF2#6mT5>4Wg-3Dw$07`+e{a&hj~K0^kPN zhFgX|0TZ_mR;vv`?2c!1?A+A!jB9J#y|cVxSzYr7f(P>p$BRp$@afrD wG=BLW--tyo&etR1lcU4ne!%bB^X$5}T+U6$OXBqjaX4LWZ!i?Qx_$({FRQBh`v3p{ literal 0 HcmV?d00001 diff --git a/dist/css/images/green-unsorted.gif b/dist/css/images/green-unsorted.gif new file mode 100644 index 0000000000000000000000000000000000000000..0afe2c021cc7dccbb3af311f09496b51864737ca GIT binary patch literal 520 zcmZ?wbhEHb6krfwc*elM=gT7y!52C$*d)Yw!qvWckLJw3KbO~qOJR+a%nWgXc) zK7nvv9w#p4J+eyMWE56O$QVTsmjzy=%5g&1Q~8z$x#bQ@+8c{X>D9u@ zYh|ssn)>hdWKKzsEsIfdQE*Ro{r~?z!;k`sKUo+V7+e{2K&}SG2?Kj-gKJZBOKV$` zetWy9jzd?AvYeU?Yrm_iFo%?Z9b1>KmHq)$ literal 0 HcmV?d00001 diff --git a/dist/css/images/ice-asc.gif b/dist/css/images/ice-asc.gif new file mode 100644 index 0000000000000000000000000000000000000000..0961d9aafb17fa754d4ce5048c638cfb4db3b40d GIT binary patch literal 285 zcmZ?wbhEHbjG ze=B$H7M`M=JO$f%3b*s*Z{sc5&0D;aw{XXQhW`vy1&Tje7#SE;8FWCVg8an5W_4iF z1{Eo(cIAK<7GG+tB)KLZ*_oj=x#Q#Jg8@4IZOsRDX3rEjc`?91@5CYJhLs*uIGBu; N3@oNIq&hNK0{}6xMqB^@ literal 0 HcmV?d00001 diff --git a/dist/css/images/ice-desc.gif b/dist/css/images/ice-desc.gif new file mode 100644 index 0000000000000000000000000000000000000000..0330fccaabc2e17a7e67f4962aa4f89c8557ba4f GIT binary patch literal 285 zcmZ?wbhEHb)%wYAO#uhf0Eoc^7;0*Tg1?=JT*+b^AM=xTJT*wiGf)f^f3h$#FlaL9 zfJ_4UiGj`Pz!Za0DXI2l=U-U3bOy=t3%f|=8669F*)h{#e}bBO^1=|6PPRi8jV^NB W%#AMt3|Lq{BnogWXNY%Xum%8lS4B$z literal 0 HcmV?d00001 diff --git a/dist/css/images/ice-unsorted.gif b/dist/css/images/ice-unsorted.gif new file mode 100644 index 0000000000000000000000000000000000000000..c1afde558ea67f6f47148bb4e25f39abafd87799 GIT binary patch literal 180 zcmV;l089TzNk%w1VGIBa0K@xc>nEA^8LW0018VEC2ui01N;O000Fs;3t0EXpUQkoug-cRK;f37(J%e iole94K-NTZIuJ|{#s~pmEfk+Z0GKccf}g=J1OPj7d^(%} literal 0 HcmV?d00001 diff --git a/dist/css/images/last.png b/dist/css/images/last.png new file mode 100644 index 0000000000000000000000000000000000000000..72079357614b4254b163a5cac766093d1f99bbe7 GIT binary patch literal 737 zcmV<70v`Q|P)za-4I45g$8m^55K?|L?r+odSTVNnJ96LXt|7TGI4L>d~Fz z&-h8>1xd<>>vgSt=Y;X^$Jv9(As-4y`R%SPp?5wYYBW2LD^|g`7v>f>k`%^{A!C3N&EeR0q1EmI9?j zT<^fuCti3LD9UEdoCoe2BcvKUvD7KhHa~-21gL%Aj#%s&OGVR_$6iSuSoaqp%eN%J z76DWmU8pyEP^yWrwDz7wF9N262N52Jg#ie_jHv7Leqfv#&`?`&#}Fpfom5)T>7B!> zWsOHK0qlpu1b_k9E1Iu8-65F`u4B0T$PKrdAs|z3NmX=VY5BDbP=DEtvNfR%4Y5Zu z5VMpOD@qkb3GkT!aIm-Gn* z`85iZ>7zVE#RF?u>-GjXzTT2IfyTsX6XN-%yiPPHr0n_^E8Hzpe7MH(L!#e?D90zS zP^g}fN@{04Qcb!flJ%iEo~?q;Y!zl{=dXt}`IHwd0cyqO;QYY^WD0dM6YM#f=E3C+ z!2-R=&FDY;{gfv^)4f+|?c7Tj^US!+(gqX%T+i_HIx{<~voklC*uOv1|9t14Z-oeY T=@u`q-Vg)2ozNO$->CRz{H>f zQUKDzz~ne3e?i0B-7(yb4yr4bTs^i%F{Yz&j)hfn`=;ZaUeQxez2`bzvG#r5dd{19 z!Vll38%c$&oiKTOjaT|fg-sl?YN@OUQ`v#0ax(x)CXo=iMcq4Y^)WQ;^jy2>Pi|c0 z+yEr&d4XeL8If(~h1x7UMZQw|C0j$G*0IR9p-%D344shFF)_f@iA-r&*1q$O4~JHlrS=Ys z_3vtDAiIzOXf4!*A_|%9C!fc)bZLneovQiVkU1UVLRM%mejW= OqdvS&mB{N*qQH@MuUvp6C zPs?_%_h)|`vVF@G*#BDZenOR(_Zq8cwyV-krlwQVQ$FtbV`gaCncnKA!t6Kk+IbhR dGl35-$=XTsix@`i@H_)@oTsaw%Q~loCIIowIb;9; literal 0 HcmV?d00001 diff --git a/dist/css/images/metro-black-desc.png b/dist/css/images/metro-black-desc.png new file mode 100644 index 0000000000000000000000000000000000000000..ef5f48e07e52c6608e913fda2aa724c3eda3cecd GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!VDxY_&1vXDct~{5LX~gJUF;O!w#sLuO!GX zn88R#j+05)@57y~)3P!xeeTBsWnw&C978y+CnqE%cqcG0x(f=NT%{qxuw(`+D{n){ zq6G^in3=m31S||#8Z|=MoCQ?RFtGl<$9OQiO+#Sol*ZJ1yUX=uB_wq2?agNMGTK|c loFORWyUdzt-x-*h87{7oXg6#sMkxrPKgI|jHK z=@~FHGB7YG{*!VpN=+O)ufdp~4Hg(Gr$-m$6$)@UVMj zKlcFIf@zKk$Q-{OMFr^=p4}Usb-5He1%@OTN-8AyxJFB@sFB%PdjD;r1bc(Rb%{r9 z&XSu{RkVb#8Dz$>%Sc)Kl;epBXQqVdv$ZD6@O_c=`{?PEIAe8z%m=PBoA=5bTcOPq z`BwZ7WAkBtqm?OA^Y^o0GYaUpBvtKGMr{+{%n6Hc?Ow*&s>s7)=+d4jBe=?~X~RW% z=A@w5&$jXg7CKV>Czcdh`e5~&5y!3~b#1TbDIy;vKKnHCsFfW~h)D{W(%Q09E+f)O z^ZY3X0cN?EHu8tnz~%%^!fFiAISPj+Sc*R`dA{e?JOjz&G7l8>oVLw96~1PXArBk3 zNO9us4W{3xGBz4);OyKzKUdQWt2sdD-1+x`Q}E`T(AZgw?`{gpL$+T8S zx1$Ck6B1@`W8`Hy^>n-v5k z3^p`qu(vq~sGeeA43P7%jc8xIK*3{w=Yj>s6O!06nI)M`Sh55ef+w))8BS!k1Dea= M>FVdQ&MBb@0IrQR`v3p{ literal 0 HcmV?d00001 diff --git a/dist/css/images/metro-white-asc.png b/dist/css/images/metro-white-asc.png new file mode 100644 index 0000000000000000000000000000000000000000..63327188b8fc240895c3e02d2e02e64e49e297c4 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!VDxY_&1vXDY*cj5LY1m4mYstac=>t;4BI9 z3uZ9p)Dn$*y+GkdYyN(qV5FyuV+hA}-7{#x{0(+XRRizpY<|VNa8}!`%^RxY>Xy%Fx>D?*J&AFu$MbY0 f)wDB(7a8Qwbqb|%)xLTMw1mOa)z4*}Q$iB}B+^)A literal 0 HcmV?d00001 diff --git a/dist/css/images/metro-white-desc.png b/dist/css/images/metro-white-desc.png new file mode 100644 index 0000000000000000000000000000000000000000..ca7c363e34009bdf9f61bfea526e410a9ecddc49 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!VDxY_&1vXDfIxK5LY1mjtC&A#&`*+l&2)f zFPOndM~;(8IMeUNw4Hf3%JYHZF`h1tAsp9}6A}`<6BroX1qDv7(hy--GJ}iShLSD9Mo*f5ZF4kG4X`v&>jX)S3j3^P6_TF$F*h9sL-j zNpc$weSXQZ6Gag%5kOy9HfA1@g zVA*&|VjFHeVhIV!`DzQM7F-a@NRTNvNlYYp4z%6NAQuJno^MeOJ!7dzy8e(=;etr6 z4q2h83Vb36o=G4!6u79$u)6u4LoN!;_)kItHmh9g5CP1HxVh+sSiS*Mlqx_uVfwL~ z+}p|}Y*;r1{g* z9DE4_W&SW~qUN5hWN@-RUJ#q3Ngxr&iJp;+4aEd;HM{A>I)B?7>yL4`Nc6h^we^ve z3YC6fwXTqAQWr8=Cd?emR={YnNptkhuSFVP{Q?6Lt^ zqF4A?)Arx1JpP&Pyh<4sUhXnam)AJ@xmkE-VuVGbg_|=vm|INb-=FD!zVlDxJ_uiv SXLQ>D0000yhD literal 0 HcmV?d00001 diff --git a/dist/css/images/prev.png b/dist/css/images/prev.png new file mode 100644 index 0000000000000000000000000000000000000000..15d1584bdbb2c26a9fc4c8269aa54615a58a4657 GIT binary patch literal 745 zcmV1hlor z)=Ec^h7>5J3?Bj(D6|X+0|UcQj&m*_Qg!D|-c07sd7pF6opXl(U}#WhWg0W$d_xV%ATb~UcS*dC+@kfS*m{?64KBH-eM78JQAu#&2c z7TM!?0X98;&a@msh@1ehFDx4~_smCS0rm@Z$dv@5Y^ec>Jl}_`uDh5!i#cpZh5&_) z{y|~cgJzZ1d%`?CxkdJIg%by0u(~PqB0%Zdj?maMmYO=M!=;B#0>~5_5YO>&?w*4H z@LRbi!eNPrxg`gUUIeK8JG(3%R{o~|7so$K+8_qZe0Iz($pKd%d&oOhA&AGYXkKE` zO8~w=kN^smCS05H!-WT*2mpbXAJK6B{s*`+;U?8|s%XO8{Hs1d`DH6am$(L0coEX9 z)c+Ho)WS9-4?6~g4NrO@c2FaKCYmmR!DQ~YpfIn+s8pr^?KThtmU&}3Kr*7R^y^Rk z5Xsb_*=oc3w-9KI@B4=+yK6a8uQ@#oTkf1PnlL+NjAm=Zh)+xqld|idFEF=^(avw| z4U*w)Kx6;tnV0ZXQD@SHtHr7{`Y12 bpX>Y!%!CO%>C8GV00000NkvXXu0mjfJYGkQ literal 0 HcmV?d00001 diff --git a/dist/css/images/white-asc.gif b/dist/css/images/white-asc.gif new file mode 100644 index 0000000000000000000000000000000000000000..2173b0a0596a3faa5d8f9236c385c325fa6227ad GIT binary patch literal 48 wcmZ?wbhEHbWM^PuXkcLY4+e@qSr{1@7#VaJfB+=Jz{K8@$hrD7A2)+F09SGhP5=M^ literal 0 HcmV?d00001 diff --git a/dist/css/images/white-desc.gif b/dist/css/images/white-desc.gif new file mode 100644 index 0000000000000000000000000000000000000000..7109c3ea161794feeae8c95a0fc5aa728e371f37 GIT binary patch literal 49 xcmZ?wbhEHbWM^PuXkcLY4+e@qSr{1@7#VaJfB+=Jz{JtQ-zb^I8>zuy4FF$-3-15` literal 0 HcmV?d00001 diff --git a/dist/css/images/white-unsorted.gif b/dist/css/images/white-unsorted.gif new file mode 100644 index 0000000000000000000000000000000000000000..9bfc3459c766d019f057f0557b0abf21319ff46e GIT binary patch literal 54 zcmZ?wbhEHbWM|-HXkcLY4+e@qSr{1@7#VaJfB+=Jz{J~=$hrD7-{cm(3vFpy4Aua( COb>nl literal 0 HcmV?d00001 diff --git a/dist/css/jquery.tablesorter.pager.min.css b/dist/css/jquery.tablesorter.pager.min.css new file mode 100644 index 0000000..9d87fe3 --- /dev/null +++ b/dist/css/jquery.tablesorter.pager.min.css @@ -0,0 +1 @@ +.tablesorter-pager{padding:5px}td.tablesorter-pager{background-color:#e6eeee;margin:0}.tablesorter-pager img{vertical-align:middle;margin-right:2px;cursor:pointer}.tablesorter-pager .pagedisplay{padding:0 5px;width:auto;white-space:nowrap;text-align:center}.tablesorter-pager select{margin:0;padding:0}.tablesorter-pager.disabled{display:none}.tablesorter-pager .disabled{opacity:.5;filter:alpha(opacity=50);cursor:default} \ No newline at end of file diff --git a/dist/css/less/bootstrap.less b/dist/css/less/bootstrap.less new file mode 100644 index 0000000..1d712ca --- /dev/null +++ b/dist/css/less/bootstrap.less @@ -0,0 +1,322 @@ +/* Tablesorter Custom Bootstrap LESS Theme by Rob Garrison + +To create your own theme, modify the code below and run it through +a LESS compiler, like this one: http://leafo.net/lessphp/editor.html +or download less.js from http://lesscss.org/ + +Test out these custom less files live + Basic Theme : http://codepen.io/Mottie/pen/eqBbn + Bootstrap : http://codepen.io/Mottie/pen/Ltzpi + Metro Style : http://codepen.io/Mottie/pen/gCslk + +*/ + +/*** theme ***/ +@theme : tablesorter-bootstrap; + +/*** fonts ***/ +@tableHeaderFont : 14px bold Arial, Sans-serif; +@tableBodyFont : 14px "Helvetica Neue", Helvetica, Arial, sans-serif; + +/*** color definitions ***/ +/* for best results, only change the hue (240), + leave the saturation (60%) and luminosity (80%) alone + pick the color from here: http://hslpicker.com/#99E699 */ +@headerBackground : hsl(240, 60%, 80%); +@borderAndBackground : #cdcdcd; +@overallBorder : @borderAndBackground 1px solid; +@headerTextColor : #000; + +@bodyBackground : #fff; +@bodyTextColor : #000; + +@headerAsc : darken(spin(@headerBackground, 5), 10%); /* darken(@headerBackground, 10%); */ +@headerDesc : lighten(spin(@headerBackground, -5), 10%); /* desaturate(@headerAsc, 5%); */ + +@captionBackground : #fff; /* it might be best to match the document body background color here */ +@errorBackground : #e6bf99; /* ajax error message (added to thead) */ + +@filterCellBackground : #eee; +@filterElementTextColor: #333; +@filterElementBkgd : #fff; +@filterElementBorder : 1px solid #bbb; +@filterTransitionTime : 0.1s; +@filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */ + +@overallPadding : 4px; +/* 20px should be slightly wider than the icon width to avoid overlap */ +@headerPadding : 4px 20px 4px 4px; +@headerMargin : 0 0 18px; + +/* url(icons/loading.gif); */ +@processingIcon : url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs='); + +/* zebra striping */ +.allRows { + background-color: @bodyBackground; + color: @bodyTextColor; +} +.evenRows { + background-color: lighten(@headerBackground, 35%); +} +.oddRows { + background-color: lighten(@headerBackground, 18%); +} + +/* hovered rows */ +.oddHovered { + background-color: desaturate(@headerBackground, 60%); +} +.evenHovered { + background-color: lighten( desaturate(@headerBackground, 60%), 10% ); +} + +/* Columns widget */ +@primaryOdd : spin(@headerBackground, 10); /* saturate( darken( desaturate(@headerBackground, 10%), 10% ), 30%); */ +@primaryEven : lighten( @primaryOdd, 10% ); +@secondaryOdd : @primaryEven; +@secondaryEven : lighten( @primaryEven, 5% ); +@tertiaryOdd : @secondaryEven; +@tertiaryEven : lighten( @secondaryEven, 5% ); + +/* Filter widget transition */ +.filterWidgetTransition { + -webkit-transition: line-height @filterTransitionTime ease; + -moz-transition: line-height @filterTransitionTime ease; + -o-transition: line-height @filterTransitionTime ease; + transition: line-height @filterTransitionTime ease; +} + +/*** icon block ***/ +.iconPosition { + font-size: 11px; + position: absolute; + right: 2px; + top: 50%; + margin-top: -7px; /* half the icon height; older IE doesn't like this */ + width: 14px; + height: 14px; + background-repeat: no-repeat; + line-height: 14px; +} + +/* black */ +@unsortedBlack : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAMAAADOvxanAAAAVFBMVEUAAABCQkJZWVkZGRnJyckgICAZGRkZGRn8/PweHh4dHR0aGhoaGhpUVFQbGxvQ0NDc3NxMTExSUlIbGxvr6+s4ODhKSkogICAtLS00NDQzMzMnJydSEPrQAAAAGHRSTlMA1ssZRLgdAQbDyisqsZo8QdXUq0r9xPepSRwiAAAAX0lEQVQI13XHSQKAIAwEwQAKxn13Ev7/T2Pu9qmarJKPXIicI4PH4hxaKNrhm2S8bJK5h4YzKHrzJNtK6yYT/TdXzpS5zuYg4MSQYF6i4IHExdw1UVRi05HPrrvT53a+qyMFC9t04gcAAAAASUVORK5CYII=); + +/* white */ +@unsortedWhite : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOBAMAAAALT/umAAAAKlBMVEUAAAD///////////////////////////////////////////////////+Gu8ovAAAADXRSTlMA4EXKBtQqvR0+sxmalc142gAAAFdJREFUCNdjYGDoamAAAjZbMxCVfvd6AgMDd+3du9UMDKx3hWSvMjBwXZww8RYDGuC53NB8h4GB8a617UUGBs7Yu3cjGRhYVO9eVQFKOskKOQApFmUgBwBZ+xXRTttNdAAAAABJRU5ErkJggg==); + +/* automatically choose the correct arrow/text color */ +.headerText (@a) when (lightness(@a) >= 50%) { + color: @headerTextColor; +} +.headerText (@a) when (lightness(@a) < 50%) { + color: lighten(@headerTextColor, 90%); +} +.unsorted (@a) when (lightness(@a) >= 50%) { + background-image: @unsortedBlack; + color: @headerTextColor; +} +.unsorted (@a) when (lightness(@a) < 50%) { + background-image: @unsortedWhite; + color: lighten(@headerTextColor, 90%); +} + +/* variable theme name - requires less.js 1.3+; + or just replace (!".@{theme}") with the contents of @theme +*/ +.@{theme} { + font: @tableBodyFont; + background-color: @borderAndBackground; + width: 100%; + + /* style th's outside of the thead */ + th, thead td { + font: @tableHeaderFont; + font-weight: bold; + background-color: @headerBackground; + .headerText(@headerBackground); + border-collapse: collapse; + margin: @headerMargin; + padding: @overallPadding; + } + + tbody td, tfoot th, tfoot td { + padding: @overallPadding; + vertical-align: top; + } + + /* style header */ + .tablesorter-header { + cursor: pointer; + } + + .tablesorter-header-inner { + position: relative; + padding: @headerPadding; + } + + /* bootstrap uses for icons */ + .tablesorter-header-inner i.tablesorter-icon { + .iconPosition + } + + .tablesorter-header.sorter-false { + background-image: none; + cursor: default; + + } + + .tablesorter-headerAsc { + background-color: @headerAsc; + } + + .tablesorter-headerDesc { + background-color: @headerDesc; + } + + .bootstrap-icon-unsorted { + .unsorted(@headerBackground); + } + + + /* tfoot */ + tfoot .tablesorter-headerAsc, + tfoot .tablesorter-headerDesc { + /* remove sort arrows from footer */ + background-image: none; + } + + /* optional disabled input styling */ + .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; + } + + /* body */ + tbody { + + td { + .allRows; + padding: @overallPadding; + vertical-align: top; + } + + /* Zebra Widget - row alternating colors */ + tr.odd > td { + .oddRows; + } + tr.even > td { + .evenRows; + } + + } + + /* hovered row colors + you'll need to add additional lines for + rows with more than 2 child rows + */ + tbody > tr.hover > td, + tbody > tr:hover > td, + tbody > tr:hover + tr.tablesorter-childRow > td, + tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td, + tbody > tr.even.hover > td, + tbody > tr.even:hover > td, + tbody > tr.even:hover + tr.tablesorter-childRow > td, + tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .evenHovered; + } + tbody > tr.odd.hover > td, + tbody > tr.odd:hover > td, + tbody > tr.odd:hover + tr.tablesorter-childRow > td, + tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .oddHovered; + } + + /* table processing indicator - indeterminate spinner */ + .tablesorter-processing { + background-image: @processingIcon; + background-position: center center; + background-repeat: no-repeat; + } + + /* Column Widget - column sort colors */ + tr.odd td.primary { + background-color: @primaryOdd; + } + td.primary, tr.even td.primary { + background-color: @primaryEven; + } + tr.odd td.secondary { + background-color: @secondaryOdd; + } + td.secondary, tr.even td.secondary { + background-color: @secondaryEven; + } + tr.odd td.tertiary { + background-color: @tertiaryOdd; + } + td.tertiary, tr.even td.tertiary { + background-color: @tertiaryEven; + } + + /* caption (non-theme matching) */ + caption { + background-color: @captionBackground ; + } + + /* filter widget */ + .tablesorter-filter-row input, + .tablesorter-filter-row select{ + width: 98%; + margin: 0; + padding: @overallPadding; + color: @filterElementTextColor; + background-color: @filterElementBkgd; + border: @filterElementBorder; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + .filterWidgetTransition; + } + .tablesorter-filter-row { + background-color: @filterCellBackground; + } + .tablesorter-filter-row td { + text-align: center; + background-color: @filterCellBackground; + line-height: normal; + text-align: center; /* center the input */ + .filterWidgetTransition; + } + /* hidden filter row */ + .tablesorter-filter-row.hideme td { + padding: @filterRowHiddenHeight / 2; + margin: 0; + line-height: 0; + cursor: pointer; + } + .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); + } + /* rows hidden by filtering (needed for child rows) */ + .filtered { + display: none; + } + + /* ajax error row */ + .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: @errorBackground; + } + +} diff --git a/dist/css/less/metro.less b/dist/css/less/metro.less new file mode 100644 index 0000000..62b9292 --- /dev/null +++ b/dist/css/less/metro.less @@ -0,0 +1,357 @@ +/* Tablesorter Custom Metro LESS Theme by Rob Garrison + +To create your own theme, modify the code below and run it through +a LESS compiler, like this one: http://leafo.net/lessphp/editor.html +or download less.js from http://lesscss.org/ + +Test out these custom less files live + Basic Theme : http://codepen.io/Mottie/pen/eqBbn + Bootstrap : http://codepen.io/Mottie/pen/Ltzpi + Metro Style : http://codepen.io/Mottie/pen/gCslk + +*/ + +/*** theme ***/ +@theme : tablesorter-metro; + +/*** fonts ***/ +@tableHeaderFont : 14px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif; +@tableBodyFont : 14px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif; + +/*** color definitions ***/ +/* for best results, only change the hue (120), + leave the saturation (60%) and luminosity (75%) alone + pick the color from here: http://hslpicker.com/#825a2b + + Inspired by http://www.jtable.org/ metro themes: + Blue: hsl(212, 86%, 35%) + Brown hsl(32, 50%, 30%) + Crimson hsl(0, 100%, 38%) + Dark Grey hsl(0, 0%, 27%) + Dark Orange hsl(13, 70%, 51%) + Green hsl(120, 100%, 32%) + Light Gray hsl(0, 0%, 44%) + Pink hsl(297, 100%, 33%) + Purple hsl(257, 51%, 48%) + Red hsl(5, 100%, 40%) + + */ +@headerBackground : hsl(32, 50%, 30%); +@borderAndBackground : #cdcdcd; +@headerTextColor : #eee; + +@bodyBackground : #fff; +@bodyTextColor : #000; + +@captionBackground : #fff; /* it might be best to match the document body background color here */ +@errorBackground : #e6bf99; /* ajax error message (added to thead) */ + +@filterCellBackground : #eee; +@filterElementTextColor: #333; +@filterElementBkgd : #fff; +@filterElementBorder : 1px solid #bbb; +@filterTransitionTime : 0.1s; +@filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */ + +@overallPadding : 4px; +/* 20px should be slightly wider than the icon width to avoid overlap */ +@headerPadding : 4px 20px 4px 4px; + +/* url(icons/loading.gif); */ +@processingIcon : url('data:image/gif;base64,R0lGODlhEAAQAPIAAP///1VVVdbW1oCAgFVVVZaWlqurq7a2tiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=='); + +/* zebra striping */ +.allRows { + background-color: @bodyBackground; + color: @bodyTextColor; +} +.evenRows { + background-color: lighten( desaturate(@headerBackground, 80%), 70%); + color: @bodyTextColor; +} +.oddRows { + background-color: lighten( desaturate(@headerBackground, 80%), 50%); +} + +/* hovered rows */ +.oddHovered { + background-color: lighten( desaturate(@headerBackground, 50%), 40%); + color: @bodyTextColor; +} +.evenHovered { + background-color: lighten( desaturate(@headerBackground, 50%), 30%); + color: @bodyTextColor; +} + +/* Columns widget */ +@primaryOdd : lighten( spin(@headerBackground, 10), 40%); +@primaryEven : lighten( @primaryOdd, 8% ); +@secondaryOdd : @primaryEven; +@secondaryEven : lighten( @primaryEven, 8% ); +@tertiaryOdd : @secondaryEven; +@tertiaryEven : lighten( @secondaryEven, 8% ); + +/* Filter widget transition */ +.filterWidgetTransition { + -webkit-transition: line-height @filterTransitionTime ease; + -moz-transition: line-height @filterTransitionTime ease; + -o-transition: line-height @filterTransitionTime ease; + transition: line-height @filterTransitionTime ease; +} + +/*** Arrows ***/ +@arrowPosition : right 5px center; + +/* black */ +@unsortedBlack : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt0UjBAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC); +@sortAscBlack : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt0UjBAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC); +@sortDescBlack : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAALVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBoCg+AAAADnRSTlMAMiweCQITTvDctZZqaTlM310AAABcSURBVAjXY2BgYEtgAAFHERDJqigUAKSYBQUNgFSioKAYAwOLIBA4MASBKFUGQxAlzAAF+94BwWuGKBC1lIFl3rt3Lx0YGCzevWsGSjK9e6cAUlT3HKyW9wADAwDRrBiDy6bKzwAAAABJRU5ErkJggg==); + +/* white */ +@unsortedWhite : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAElBMVEUAAADu7u7u7u7u7u7u7u7u7u7yb344AAAABnRSTlMAMhIHKyAHBrhHAAAATElEQVQI12NgYGBSYAABQ2Ew5SgCIlkFBQOAlKKgoBADA7MgEBgwsIAoB4ZAECXKAAFQHkg9WIejoCBIv4mgoDOQYgZpAxkDNARqEQBTkAYuMZEHPgAAAABJRU5ErkJggg==); +@sortAscWhite : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAHlBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u4+jEeEAAAACXRSTlMAMwkqFV7roCD4hW+/AAAAWUlEQVQI1y3MrQ5AABSG4Xd+Rj0jiDabjKZxB6qqaarGNRh27tY5myd8b/uAeML1l2+wPqUlUd0ss+oNoZqG2rOwe15+p5iC1HNAK5IBlUjnZyIlZsxx0QAfzokSZgp96u4AAAAASUVORK5CYII=); +@sortDescWhite : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAJ1BMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u4RJgHSAAAADHRSTlMAMiweCQITaU7olrlu2HdvAAAAXElEQVQI12NgYGBLYAABRxEQyaooFACkmAUFDYBUoqCgGAMDiyAQODAEgShVBkMQJcwABWvOAMEphmgQtZWBZc6ZMycdGBhszpw5DJRkOnNGAaSo5wRYLXsBAwMAi4YWQHRX4F0AAAAASUVORK5CYII=); + +/* automatically choose the correct arrow/text color */ +.headerText (@a) when (lightness(@a) >= 50%) { + color: @headerTextColor; +} +.headerText (@a) when (lightness(@a) < 50%) { + color: lighten(@headerTextColor, 90%); +} +.unsorted (@a) when (lightness(@a) >= 50%) { + background-image: @unsortedBlack; +} +.unsorted (@a) when (lightness(@a) < 50%) { + background-image: @unsortedWhite; +} +.sortAsc (@a) when (lightness(@a) >= 50%) { + background-image: @sortAscBlack; +} +.sortAsc (@a) when (lightness(@a) < 50%) { + background-image: @sortAscWhite; +} +.sortDesc (@a) when (lightness(@a) >= 50%) { + background-image: @sortDescBlack; +} +.sortDesc (@a) when (lightness(@a) < 50%) { + background-image: @sortDescWhite; +} + +/* variable theme name - requires less.js 1.3+; + or just replace (!".@{theme}") with the contents of @theme +*/ +.@{theme} { + font: @tableBodyFont; + background-color: @borderAndBackground; + margin: 10px 0 15px; + width: 100%; + text-align: left; + border-spacing: 0; + border: 0; + + th, td { + border: 0; + } + + /* style th's outside of the thead */ + th, thead td { + font: @tableHeaderFont; + font-weight: bold; + background-color: @headerBackground; + color: @headerTextColor; + .headerText(@headerBackground); + border-collapse: collapse; + padding: @overallPadding; + } + + .dark-row th, .dark-row td, caption.dark-row { + background-color: darken( @headerBackground, 10% ); + } + + tbody td, tfoot th, tfoot td { + padding: @overallPadding; + vertical-align: top; + } + + /* style header */ + .tablesorter-header { + .unsorted(@headerBackground); + background-repeat: no-repeat; + background-position: @arrowPosition; + cursor: pointer; + white-space: normal; + } + + .tablesorter-header-inner { + padding: @headerPadding; + } + + .tablesorter-header.sorter-false { + background-image: none; + cursor: default; + padding: @overallPadding; + } + + .tablesorter-headerAsc { + .sortAsc(@headerBackground); + } + + .tablesorter-headerDesc { + .sortDesc(@headerBackground); + } + + /* tfoot */ + tfoot .tablesorter-headerAsc, + tfoot .tablesorter-headerDesc { + /* remove sort arrows from footer */ + background-image: none; + } + + /* optional disabled input styling */ + .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; + } + + /* body */ + tbody { + + td { + .allRows; + padding: @overallPadding; + vertical-align: top; + } + + /* Zebra Widget - row alternating colors */ + tr.odd > td { + .oddRows; + } + tr.even > td { + .evenRows; + } + + } + + /* hovered row colors + you'll need to add additional lines for + rows with more than 2 child rows + */ + tbody > tr.hover > td, + tbody > tr:hover > td, + tbody > tr:hover + tr.tablesorter-childRow > td, + tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td, + tbody > tr.even.hover > td, + tbody > tr.even:hover > td, + tbody > tr.even:hover + tr.tablesorter-childRow > td, + tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .evenHovered; + } + tbody > tr.odd.hover > td, + tbody > tr.odd:hover > td, + tbody > tr.odd:hover + tr.tablesorter-childRow > td, + tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .oddHovered; + } + + /* table processing indicator - indeterminate spinner */ + .tablesorter-processing { + background-image: @processingIcon; + background-position: center center; + background-repeat: no-repeat; + } + + /* pager */ + div.tablesorter-pager { + button { + background-color: lighten( @headerBackground, 7% ); + color: @headerTextColor; + border: lighten( @headerBackground, 15% ) 1px solid; + cursor: pointer; + } + button:hover { + background-color: lighten( @headerBackground, 15% ); + } + } + + /* Column Widget - column sort colors */ + tr.odd td.primary { + background-color: @primaryOdd; + } + td.primary, tr.even td.primary { + background-color: @primaryEven; + } + tr.odd td.secondary { + background-color: @secondaryOdd; + } + td.secondary, tr.even td.secondary { + background-color: @secondaryEven; + } + tr.odd td.tertiary { + background-color: @tertiaryOdd; + } + td.tertiary, tr.even td.tertiary { + background-color: @tertiaryEven; + } + + /* caption (non-theme matching) */ + caption { + background-color: @captionBackground ; + } + + /* filter widget */ + .tablesorter-filter-row input, + .tablesorter-filter-row select{ + width: 98%; + height: auto; + margin: 0; + padding: @overallPadding; + color: @filterElementTextColor; + background-color: @filterElementBkgd; + border: @filterElementBorder; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + .filterWidgetTransition; + } + .tablesorter-filter-row { + background-color: @filterCellBackground; + } + .tablesorter-filter-row td { + text-align: center; + background-color: @filterCellBackground; + line-height: normal; + text-align: center; /* center the input */ + .filterWidgetTransition; + } + /* hidden filter row */ + .tablesorter-filter-row.hideme td { + padding: @filterRowHiddenHeight / 2; + margin: 0; + line-height: 0; + cursor: pointer; + } + .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); + } + /* rows hidden by filtering (needed for child rows) */ + .filtered { + display: none; + } + + /* ajax error row */ + .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: @errorBackground; + } + +} diff --git a/dist/css/less/theme.less b/dist/css/less/theme.less new file mode 100644 index 0000000..c0a4d79 --- /dev/null +++ b/dist/css/less/theme.less @@ -0,0 +1,329 @@ +/* Tablesorter Custom LESS Theme by Rob Garrison + + To create your own theme, modify the code below and run it through + a LESS compiler, like this one: http://leafo.net/lessphp/editor.html + or download less.js from http://lesscss.org/ + +Test out these custom less files live + Basic Theme : http://codepen.io/Mottie/pen/eqBbn + Bootstrap : http://codepen.io/Mottie/pen/Ltzpi + Metro Style : http://codepen.io/Mottie/pen/gCslk + + */ + +/*** theme ***/ +@theme : tablesorter-custom; + +/*** fonts ***/ +@tableHeaderFont : 11px 'trebuchet ms', verdana, arial; +@tableBodyFont : 11px 'trebuchet ms', verdana, arial; + +/*** color definitions ***/ +/* for best results, only change the hue (120), + leave the saturation (60%) and luminosity (75%) alone + pick the color from here: http://hslpicker.com/#99E699 */ +@headerBackground : hsl(120, 60%, 75%); +@borderAndBackground : #cdcdcd; +@overallBorder : @borderAndBackground 1px solid; +@headerTextColor : #000; + +@bodyBackground : #fff; +@bodyTextColor : #000; + +@headerAsc : darken(spin(@headerBackground, 5), 10%); /* darken(@headerBackground, 10%); */ +@headerDesc : lighten(spin(@headerBackground, -5), 10%); /* desaturate(@headerAsc, 5%); */ + +@captionBackground : #fff; /* it might be best to match the document body background color here */ +@errorBackground : #e6bf99; /* ajax error message (added to thead) */ + +@filterCellBackground : #eee; +@filterElementTextColor: #333; +@filterElementBkgd : #fff; +@filterElementBorder : 1px solid #bbb; +@filterTransitionTime : 0.1s; +@filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */ + +@overallPadding : 4px; +/* 20px should be slightly wider than the icon width to avoid overlap */ +@headerPadding : 4px 20px 4px 4px; + +/* url(icons/loading.gif); */ +@processingIcon : url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs='); + +/* zebra striping */ +.allRows { + background-color: @bodyBackground; + color: @bodyTextColor; +} +.evenRows { + background-color: lighten(@headerBackground, 40%); + color: @bodyTextColor; +} +.oddRows { + background-color: lighten(@headerBackground, 20%); +} + +/* hovered rows */ +.oddHovered { + background-color: desaturate(@headerBackground, 60%); + color: @bodyTextColor; +} +.evenHovered { + background-color: lighten( desaturate(@headerBackground, 60%), 10% ); + color: @bodyTextColor; +} + +/* Columns widget */ +@primaryOdd : spin(@headerBackground, 10); /* saturate( darken( desaturate(@headerBackground, 10%), 10% ), 30%); */ +@primaryEven : lighten( @primaryOdd, 10% ); +@secondaryOdd : @primaryEven; +@secondaryEven : lighten( @primaryEven, 5% ); +@tertiaryOdd : @secondaryEven; +@tertiaryEven : lighten( @secondaryEven, 5% ); + +/* Filter widget transition */ +.filterWidgetTransition { + -webkit-transition: line-height @filterTransitionTime ease; + -moz-transition: line-height @filterTransitionTime ease; + -o-transition: line-height @filterTransitionTime ease; + transition: line-height @filterTransitionTime ease; +} + +/*** Arrows ***/ +@arrowPosition : right 5px center; + +/* black */ +@unsortedBlack : url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); +@sortAscBlack : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); +@sortDescBlack : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); + +/* white */ +@unsortedWhite : url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); +@sortAscWhite : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); +@sortDescWhite : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); + +/* automatically choose the correct arrow/text color */ +.headerText (@a) when (lightness(@a) >= 50%) { + color: @headerTextColor; +} +.headerText (@a) when (lightness(@a) < 50%) { + color: lighten(@headerTextColor, 90%); +} +.unsorted (@a) when (lightness(@a) >= 50%) { + background-image: @unsortedBlack; +} +.unsorted (@a) when (lightness(@a) < 50%) { + background-image: @unsortedWhite; +} +.sortAsc (@a) when (lightness(@a) >= 50%) { + background-image: @sortAscBlack; +} +.sortAsc (@a) when (lightness(@a) < 50%) { + background-image: @sortAscWhite; +} +.sortDesc (@a) when (lightness(@a) >= 50%) { + background-image: @sortDescBlack; +} +.sortDesc (@a) when (lightness(@a) < 50%) { + background-image: @sortDescWhite; +} + +/* variable theme name - requires less.js 1.3+; + or just replace (!".@{theme}") with the contents of @theme + */ +.@{theme} { + font: @tableBodyFont; + background-color: @borderAndBackground; + margin: 10px 0 15px; + width: 100%; + text-align: left; + border-spacing: 0; + border: @overallBorder; + border-width: 1px 0 0 1px; + + th, td { + border: @overallBorder; + border-width: 0 1px 1px 0; + } + + /* style th's outside of the thead */ + th, thead td { + font: @tableHeaderFont; + font-weight: bold; + background-color: @headerBackground; + .headerText(@headerBackground); + border-collapse: collapse; + padding: @overallPadding; + } + + tbody td, tfoot th, tfoot td { + padding: @overallPadding; + vertical-align: top; + } + + /* style header */ + .tablesorter-header { + .unsorted(@headerBackground); + background-repeat: no-repeat; + background-position: @arrowPosition; + padding: @headerPadding; + cursor: pointer; + } + + .tablesorter-header.sorter-false { + background-image: none; + cursor: default; + padding: @overallPadding; + } + + .tablesorter-headerAsc { + background-color: @headerAsc; + .sortAsc(@headerBackground); + } + + .tablesorter-headerDesc { + background-color: @headerDesc; + .sortDesc(@headerBackground); + } + + /* tfoot */ + tfoot .tablesorter-headerAsc, + tfoot .tablesorter-headerDesc { + /* remove sort arrows from footer */ + background-image: none; + } + + /* optional disabled input styling */ + .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; + } + + /* body */ + tbody { + + td { + .allRows; + padding: @overallPadding; + vertical-align: top; + } + + /* Zebra Widget - row alternating colors */ + tr.odd > td { + .oddRows; + } + tr.even > td { + .evenRows; + } + + } + + /* hovered row colors + you'll need to add additional lines for + rows with more than 2 child rows + */ + tbody > tr.hover td, + tbody > tr:hover td, + tbody > tr:hover + tr.tablesorter-childRow > td, + tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td, + tbody > tr.even.hover > td, + tbody > tr.even:hover > td, + tbody > tr.even:hover + tr.tablesorter-childRow > td, + tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .evenHovered; + } + tbody > tr.odd.hover > td, + tbody > tr.odd:hover > td, + tbody > tr.odd:hover + tr.tablesorter-childRow > td, + tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td { + .oddHovered; + } + + /* table processing indicator - indeterminate spinner */ + .tablesorter-processing { + background-image: @processingIcon; + background-position: center center; + background-repeat: no-repeat; + } + + /* Column Widget - column sort colors */ + tr.odd td.primary { + background-color: @primaryOdd; + } + td.primary, tr.even td.primary { + background-color: @primaryEven; + } + tr.odd td.secondary { + background-color: @secondaryOdd; + } + td.secondary, tr.even td.secondary { + background-color: @secondaryEven; + } + tr.odd td.tertiary { + background-color: @tertiaryOdd; + } + td.tertiary, tr.even td.tertiary { + background-color: @tertiaryEven; + } + + /* caption (non-theme matching) */ + caption { + background-color: @captionBackground ; + } + + /* filter widget */ + .tablesorter-filter-row input, + .tablesorter-filter-row select { + width: 98%; + height: auto; + margin: 0; + padding: @overallPadding; + color: @filterElementTextColor; + background-color: @filterElementBkgd; + border: @filterElementBorder; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + .filterWidgetTransition; + } + .tablesorter-filter-row { + background-color: @filterCellBackground; + } + .tablesorter-filter-row td { + text-align: center; + background-color: @filterCellBackground; + line-height: normal; + text-align: center; /* center the input */ + .filterWidgetTransition; + } + /* hidden filter row */ + .tablesorter-filter-row.hideme td { + padding: @filterRowHiddenHeight / 2; + margin: 0; + line-height: 0; + cursor: pointer; + } + .tablesorter-filter-row.hideme * { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); + } + /* rows hidden by filtering (needed for child rows) */ + .filtered { + display: none; + } + + /* ajax error row */ + .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: @errorBackground; + } + +} diff --git a/dist/css/theme.blackice.min.css b/dist/css/theme.blackice.min.css new file mode 100644 index 0000000..0d728c7 --- /dev/null +++ b/dist/css/theme.blackice.min.css @@ -0,0 +1 @@ +.tablesorter-blackice{width:100%;margin-right:auto;margin-left:auto;font:11px/18px Arial,Sans-serif;text-align:left;background-color:#000;border-collapse:collapse;border-spacing:0}.tablesorter-blackice th,.tablesorter-blackice thead td{padding:4px;font:13px/20px Arial,Sans-serif;font-weight:700;color:#e5e5e5;text-align:left;text-shadow:0 1px 0 rgba(0,0,0,.7);background-color:#111;border:1px solid #232323}.tablesorter-blackice .header,.tablesorter-blackice .tablesorter-header{padding:4px 20px 4px 4px;cursor:pointer;background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-position:center right;background-repeat:no-repeat}.tablesorter-blackice .headerSortUp,.tablesorter-blackice .tablesorter-headerAsc,.tablesorter-blackice .tablesorter-headerSortUp{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);color:#fff}.tablesorter-blackice .headerSortDown,.tablesorter-blackice .tablesorter-headerDesc,.tablesorter-blackice .tablesorter-headerSortDown{color:#fff;background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7)}.tablesorter-blackice thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-blackice tfoot .tablesorter-headerAsc,.tablesorter-blackice tfoot .tablesorter-headerDesc,.tablesorter-blackice tfoot .tablesorter-headerSortDown,.tablesorter-blackice tfoot .tablesorter-headerSortUp{background-image:none}.tablesorter-blackice td{padding:4px;color:#ccc;vertical-align:top;background-color:#333;border:1px solid #232323}.tablesorter-blackice tbody>tr.even:hover>td,.tablesorter-blackice tbody>tr.hover>td,.tablesorter-blackice tbody>tr.odd:hover>td,.tablesorter-blackice tbody>tr:hover>td{background-color:#000}.tablesorter-blackice .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-blackice tr.odd>td{background-color:#333}.tablesorter-blackice tr.even>td{background-color:#393939}.tablesorter-blackice td.primary,.tablesorter-blackice tr.odd td.primary{background-color:#2f3a40}.tablesorter-blackice td.secondary,.tablesorter-blackice tr.even td.primary,.tablesorter-blackice tr.odd td.secondary{background-color:#3f4a50}.tablesorter-blackice td.tertiary,.tablesorter-blackice tr.even td.secondary,.tablesorter-blackice tr.odd td.tertiary{background-color:#4f5a60}.tablesorter-blackice tr.even td.tertiary{background-color:#5a646b}caption{background-color:#fff}.tablesorter-blackice .tablesorter-filter-row{background-color:#222}.tablesorter-blackice .tablesorter-filter-row td{background-color:#222;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-blackice .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-blackice .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-blackice .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-blackice input.tablesorter-filter,.tablesorter-blackice select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.blue.min.css b/dist/css/theme.blue.min.css new file mode 100644 index 0000000..8276861 --- /dev/null +++ b/dist/css/theme.blue.min.css @@ -0,0 +1 @@ +.tablesorter-blue{width:100%;background-color:#fff;margin:10px 0 15px;text-align:left;border-spacing:0;border:1px solid #cdcdcd;border-width:1px 0 0 1px}.tablesorter-blue td,.tablesorter-blue th{border:1px solid #cdcdcd;border-width:0 1px 1px 0}.tablesorter-blue th,.tablesorter-blue thead td{font:12px/18px Arial,Sans-serif;font-weight:700;color:#000;background-color:#99bfe6;border-collapse:collapse;padding:4px;text-shadow:0 1px 0 rgba(204,204,204,.7)}.tablesorter-blue tbody td,.tablesorter-blue tfoot td,.tablesorter-blue tfoot th{padding:4px;vertical-align:top}.tablesorter-blue .header,.tablesorter-blue .tablesorter-header{background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-repeat:no-repeat;background-position:center right;padding:4px 18px 4px 4px;white-space:normal;cursor:pointer}.tablesorter-blue .headerSortUp,.tablesorter-blue .tablesorter-headerAsc,.tablesorter-blue .tablesorter-headerSortUp{background-color:#9fbfdf;background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7)}.tablesorter-blue .headerSortDown,.tablesorter-blue .tablesorter-headerDesc,.tablesorter-blue .tablesorter-headerSortDown{background-color:#8cb3d9;background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7)}.tablesorter-blue thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-blue tfoot .tablesorter-headerAsc,.tablesorter-blue tfoot .tablesorter-headerDesc,.tablesorter-blue tfoot .tablesorter-headerSortDown,.tablesorter-blue tfoot .tablesorter-headerSortUp{background-image:none}.tablesorter-blue td{color:#3d3d3d;background-color:#fff;padding:4px;vertical-align:top}.tablesorter-blue tbody>tr.even.hover>td,.tablesorter-blue tbody>tr.even:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr.even:hover+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr.even:hover>td,.tablesorter-blue tbody>tr.hover>td,.tablesorter-blue tbody>tr:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr:hover+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr:hover>td{background-color:#d9d9d9}.tablesorter-blue tbody>tr.odd.hover>td,.tablesorter-blue tbody>tr.odd:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr.odd:hover+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr.odd:hover>td{background-color:#bfbfbf}.tablesorter-blue .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-blue tbody tr.odd>td{background-color:#ebf2fa}.tablesorter-blue tbody tr.even>td{background-color:#fff}.tablesorter-blue td.primary,.tablesorter-blue tr.odd td.primary{background-color:#99b3e6}.tablesorter-blue td.secondary,.tablesorter-blue tr.even td.primary,.tablesorter-blue tr.odd td.secondary{background-color:#c2d1f0}.tablesorter-blue td.tertiary,.tablesorter-blue tr.even td.secondary,.tablesorter-blue tr.odd td.tertiary{background-color:#d6e0f5}.tablesorter-blue tr.even td.tertiary{background-color:#ebf0fa}caption{background-color:#fff}.tablesorter-blue .tablesorter-filter-row{background-color:#eee}.tablesorter-blue .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-blue .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-blue .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-blue .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-blue input.tablesorter-filter,.tablesorter-blue select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.bootstrap.min.css b/dist/css/theme.bootstrap.min.css new file mode 100644 index 0000000..1dedb66 --- /dev/null +++ b/dist/css/theme.bootstrap.min.css @@ -0,0 +1 @@ +.tablesorter-bootstrap{width:100%}.tablesorter-bootstrap tfoot td,.tablesorter-bootstrap tfoot th,.tablesorter-bootstrap thead td,.tablesorter-bootstrap thead th{font:14px/20px Arial,Sans-serif;font-weight:700;padding:4px;margin:0 0 18px;background-color:#eee}.tablesorter-bootstrap .tablesorter-header{cursor:pointer}.tablesorter-bootstrap .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon{font-size:11px;position:absolute;right:2px;top:50%;margin-top:-7px;width:14px;height:14px;background-repeat:no-repeat;line-height:14px;display:inline-block}.tablesorter-bootstrap .bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAMAAADOvxanAAAAVFBMVEUAAABCQkJZWVkZGRnJyckgICAZGRkZGRn8/PweHh4dHR0aGhoaGhpUVFQbGxvQ0NDc3NxMTExSUlIbGxvr6+s4ODhKSkogICAtLS00NDQzMzMnJydSEPrQAAAAGHRSTlMA1ssZRLgdAQbDyisqsZo8QdXUq0r9xPepSRwiAAAAX0lEQVQI13XHSQKAIAwEwQAKxn13Ev7/T2Pu9qmarJKPXIicI4PH4hxaKNrhm2S8bJK5h4YzKHrzJNtK6yYT/TdXzpS5zuYg4MSQYF6i4IHExdw1UVRi05HPrrvT53a+qyMFC9t04gcAAAAASUVORK5CYII=)}.tablesorter-bootstrap .icon-white.bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOBAMAAAALT/umAAAAKlBMVEUAAAD///////////////////////////////////////////////////+Gu8ovAAAADXRSTlMA4EXKBtQqvR0+sxmalc142gAAAFdJREFUCNdjYGDoamAAAjZbMxCVfvd6AgMDd+3du9UMDKx3hWSvMjBwXZww8RYDGuC53NB8h4GB8a617UUGBs7Yu3cjGRhYVO9eVQFKOskKOQApFmUgBwBZ+xXRTttNdAAAAABJRU5ErkJggg==)}.tablesorter-bootstrap>tbody>tr.odd>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~tr.tablesorter-hasChildRow.odd~.tablesorter-childRow.odd>td{background-color:#f9f9f9}.tablesorter-bootstrap>tbody>tr.even:hover>td,.tablesorter-bootstrap>tbody>tr.hover>td,.tablesorter-bootstrap>tbody>tr.odd:hover>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~.tablesorter-childRow.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~.tablesorter-childRow.odd>td{background-color:#f5f5f5}.caption,.tablesorter-bootstrap>tbody>tr.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~tr.tablesorter-hasChildRow.even~.tablesorter-childRow.even>td{background-color:#fff}.tablesorter-bootstrap .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);background-position:center center!important;background-repeat:no-repeat!important}.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter{width:98%;margin:0;padding:4px 6px;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled{background-color:#eee;color:#555;cursor:not-allowed;border:1px solid #ccc;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.075)inset;box-sizing:border-box;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row{background-color:#efefef}.tablesorter-bootstrap .tablesorter-filter-row td{background-color:#efefef;line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-bootstrap .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-bootstrap .tablesorter-pager select{padding:4px 6px}.tablesorter-bootstrap .tablesorter-pager .pagedisplay{border:0}.tablesorter-bootstrap tfoot i{font-size:11px}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.bootstrap_2.min.css b/dist/css/theme.bootstrap_2.min.css new file mode 100644 index 0000000..f855e08 --- /dev/null +++ b/dist/css/theme.bootstrap_2.min.css @@ -0,0 +1 @@ +.tablesorter-bootstrap{width:100%}.tablesorter-bootstrap .tablesorter-header,.tablesorter-bootstrap tfoot td,.tablesorter-bootstrap tfoot th{font:14px/20px Arial,Sans-serif;font-weight:700;position:relative;padding:8px;margin:0 0 18px;list-style:none;background-color:#FBFBFB;background-image:-moz-linear-gradient(top,#fff,#efefef);background-image:-ms-linear-gradient(top,#fff,#efefef);background-image:-webkit-gradient(linear,0 0,0 100%,from(white),to(#efefef));background-image:-webkit-linear-gradient(top,#fff,#efefef);background-image:-o-linear-gradient(top,#fff,#efefef);background-image:linear-gradient(to bottom,#fff,#efefef);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#efefef', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.tablesorter-bootstrap .tablesorter-header{cursor:pointer}.tablesorter-bootstrap .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon{position:absolute;right:2px;top:50%;margin-top:-7px;width:14px;height:14px;background-repeat:no-repeat;line-height:14px;display:inline-block}.tablesorter-bootstrap .bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWVJREFUeNqUUL9Lw2AUTGP8mqGlpBQkNeCSRcckEBcHq1jImMElToKuDvpHFMGhU0BQcHBwLji6CE1B4uB/INQsDi4d2jQ/fPeZxo764OV6915f7lLJ81xot9tCURXqdVEUr7IsO6ffH9Q5BlEUCaLwWxWqTcbYnaIoh0Dw4gAvcWlxq1qt9hqNxg6hUGAP+uIPUrGs0qXLer2+v/pTX6QpxLtkc2U2m53ACb8sSdIDXerSEms2m6+DweAICA4d89KGbduf9MpEVdXQ9/2LVqv1CASHjjn3iq/x1xKFfxQPqGnada1W86bT6SiO42OS3qk3KPStLMvbk8nkfjwen/LLuq6blFymMB0KdUPSGhAcOualjX6/f0bCiC7NaWGPQr0BwaFjzn0gYJqmLAiCA8/zni3LmhuGkQPBoWPOPwQeaPIqD4fDruu6L6Zp5kBw6IudchmdJAkLw3DXcZwnIPjy/FuAAQCiqqWWCAFKcwAAAABJRU5ErkJggg==)}.tablesorter-bootstrap .icon-white.bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOBAMAAAALT/umAAAAKlBMVEUAAAD///////////////////////////////////////////////////+Gu8ovAAAADXRSTlMA4EXKBtQqvR0+sxmalc142gAAAFdJREFUCNdjYGDoamAAAjZbMxCVfvd6AgMDd+3du9UMDKx3hWSvMjBwXZww8RYDGuC53NB8h4GB8a617UUGBs7Yu3cjGRhYVO9eVQFKOskKOQApFmUgBwBZ+xXRTttNdAAAAABJRU5ErkJggg==)}.tablesorter-bootstrap tr.odd>td{background-color:#f9f9f9}.tablesorter-bootstrap tbody>.even:hover>td,.tablesorter-bootstrap tbody>.odd:hover>td,.tablesorter-bootstrap tbody>tr.hover>td{background-color:#f5f5f5}.tablesorter-bootstrap tbody>tr.even>td,caption{background-color:#fff}.tablesorter-bootstrap .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);position:absolute;z-index:1000}.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter{height:28px;width:98%;margin:0;padding:4px 6px;background-color:#fff;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled{background-color:#eee;cursor:not-allowed}.tablesorter-bootstrap .tablesorter-filter-row{background-color:#ddd}.tablesorter-bootstrap .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-bootstrap tr.tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-bootstrap tr.tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-bootstrap .tablesorter-pager select{padding:4px 6px}.tablesorter-bootstrap .tablesorter-pager .pagedisplay{border:0}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.dark.min.css b/dist/css/theme.dark.min.css new file mode 100644 index 0000000..7b3801b --- /dev/null +++ b/dist/css/theme.dark.min.css @@ -0,0 +1 @@ +.tablesorter-dark,.tablesorter-dark tbody>tr.even:hover>td,.tablesorter-dark tbody>tr.hover>td,.tablesorter-dark tbody>tr.odd:hover>td,.tablesorter-dark tbody>tr:hover>td,.tablesorter-dark td{background-color:#000}.tablesorter-dark{width:100%;font:11px/18px Arial,Sans-serif;color:#ccc;text-align:left;border-spacing:0}.tablesorter-dark th,.tablesorter-dark thead td{padding:4px;font:12px/20px Arial,Sans-serif;font-weight:700;color:#fff;background-color:#000;border-collapse:collapse}.tablesorter-dark thead th{border-bottom:#333 2px solid}.tablesorter-dark .header,.tablesorter-dark .tablesorter-header{padding:4px 20px 4px 4px;cursor:pointer;background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-position:center right;background-repeat:no-repeat}.tablesorter-dark thead .headerSortUp,.tablesorter-dark thead .tablesorter-headerAsc,.tablesorter-dark thead .tablesorter-headerSortUp{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);border-bottom:#888 1px solid}.tablesorter-dark thead .headerSortDown,.tablesorter-dark thead .tablesorter-headerDesc,.tablesorter-dark thead .tablesorter-headerSortDown{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);border-bottom:#888 1px solid}.tablesorter-dark thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-dark tfoot .tablesorter-headerAsc,.tablesorter-dark tfoot .tablesorter-headerDesc,.tablesorter-dark tfoot .tablesorter-headerSortDown,.tablesorter-dark tfoot .tablesorter-headerSortUp{border-top:#888 1px solid;background-image:none}.tablesorter-dark td{padding:4px;border-bottom:#333 1px solid;color:#ccc}.tablesorter-dark .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-dark tr.odd>td{background-color:#202020}.tablesorter-dark tr.even>td{background-color:#101010}.tablesorter-dark td.primary,.tablesorter-dark tr.odd td.primary{background-color:#0a0a0a}.tablesorter-dark tr.even td.primary{background-color:#050505}.tablesorter-dark td.secondary,.tablesorter-dark tr.odd td.secondary{background-color:#0f0f0f}.tablesorter-dark tr.even td.secondary{background-color:#0a0a0a}.tablesorter-dark td.tertiary,.tablesorter-dark tr.odd td.tertiary{background-color:#191919}.tablesorter-dark tr.even td.tertiary{background-color:#0f0f0f}.tablesorter-dark .tablesorter-filter-row,caption{background-color:#202020}.tablesorter-dark .tablesorter-filter-row td{background-color:#202020;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-dark .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-dark .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-dark .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-dark input.tablesorter-filter,.tablesorter-dark select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#111;border:1px solid #222;color:#ddd;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.default.min.css b/dist/css/theme.default.min.css new file mode 100644 index 0000000..e60b049 --- /dev/null +++ b/dist/css/theme.default.min.css @@ -0,0 +1 @@ +.tablesorter-default{width:100%;font:12px/18px Arial,Sans-serif;color:#333;background-color:#fff;border-spacing:0;margin:10px 0 15px;text-align:left}.tablesorter-default th,.tablesorter-default thead td{font-weight:700;color:#000;background-color:#fff;border-collapse:collapse;border-bottom:#ccc 2px solid;padding:0}.tablesorter-default tfoot td,.tablesorter-default tfoot th{border:0}.tablesorter-default .header,.tablesorter-default .tablesorter-header{background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-position:center right;background-repeat:no-repeat;cursor:pointer;white-space:normal;padding:4px 20px 4px 4px}.tablesorter-default thead .headerSortUp,.tablesorter-default thead .tablesorter-headerAsc,.tablesorter-default thead .tablesorter-headerSortUp{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);border-bottom:#000 2px solid}.tablesorter-default thead .headerSortDown,.tablesorter-default thead .tablesorter-headerDesc,.tablesorter-default thead .tablesorter-headerSortDown{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);border-bottom:#000 2px solid}.tablesorter-default thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-default tfoot .tablesorter-headerAsc,.tablesorter-default tfoot .tablesorter-headerDesc,.tablesorter-default tfoot .tablesorter-headerSortDown,.tablesorter-default tfoot .tablesorter-headerSortUp{border-top:#000 2px solid}.tablesorter-default td{background-color:#fff;border-bottom:#ccc 1px solid;padding:4px;vertical-align:top}.tablesorter-default tbody>tr.even:hover>td,.tablesorter-default tbody>tr.hover>td,.tablesorter-default tbody>tr.odd:hover>td,.tablesorter-default tbody>tr:hover>td{background-color:#fff;color:#000}.tablesorter-default .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-default tr.odd>td{background-color:#dfdfdf}.tablesorter-default tr.even>td{background-color:#efefef}.tablesorter-default tr.odd td.primary{background-color:#bfbfbf}.tablesorter-default td.primary,.tablesorter-default tr.even td.primary,.tablesorter-default tr.odd td.secondary{background-color:#d9d9d9}.tablesorter-default td.secondary,.tablesorter-default tr.even td.secondary,.tablesorter-default tr.odd td.tertiary{background-color:#e6e6e6}.tablesorter-default td.tertiary,.tablesorter-default tr.even td.tertiary{background-color:#f2f2f2}caption{background-color:#fff}.tablesorter-default .tablesorter-filter-row{background-color:#eee}.tablesorter-default .tablesorter-filter-row td{background-color:#eee;border-bottom:#ccc 1px solid;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-default .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-default .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-default .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-default input.tablesorter-filter,.tablesorter-default select.tablesorter-filter{width:95%;height:auto;margin:4px auto;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.dropbox.min.css b/dist/css/theme.dropbox.min.css new file mode 100644 index 0000000..949f9c9 --- /dev/null +++ b/dist/css/theme.dropbox.min.css @@ -0,0 +1 @@ +.tablesorter-dropbox{width:100%;font:13px/32px "Open Sans","lucida grande","Segoe UI",arial,verdana,"lucida sans unicode",tahoma,sans-serif;color:#555;text-align:left;background-color:#fff;border-collapse:collapse;border-top:1px solid #82cffa;border-spacing:0}.tablesorter-dropbox tfoot td,.tablesorter-dropbox tfoot th,.tablesorter-dropbox th,.tablesorter-dropbox thead td{background-color:#f0f9ff;border-color:#82cffa #e7f2fb #96c4ea;border-style:solid;border-width:1px;padding:3px 6px;font-size:13px;font-weight:400;line-height:29px;color:#2281CF;text-align:left}.tablesorter-dropbox .header,.tablesorter-dropbox .tablesorter-headerRow,.tablesorter-dropbox thead tr{background-color:#f0f9ff;border-bottom:1px solid #96c4ea;box-shadow:0 1px 1px rgba(0,0,0,.12),0 0 0 #000 inset;white-space:normal}.tablesorter-dropbox .tablesorter-headerAsc,.tablesorter-dropbox .tablesorter-headerDesc,.tablesorter-dropbox .tablesorter-headerSortDown,.tablesorter-dropbox .tablesorter-headerSortUp{font-weight:600}.tablesorter-dropbox .tablesorter-header{cursor:pointer}.tablesorter-dropbox .tablesorter-header i.tablesorter-icon{width:9px;height:9px;padding:0 10px 0 4px;display:inline-block;background-position:center right;background-repeat:no-repeat;content:""}.tablesorter-dropbox .tablesorter-headerAsc i.tablesorter-icon,.tablesorter-dropbox .tablesorter-headerSortUp i.tablesorter-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALhJREFUeNpi/P//PwMhwILMiexYx8bIxNTy/9+/muUVQb9g4kzIitg4edI4+YRLQTSyOCPMupjerUI8whK3OXgEhH58+fDuy9sXqkuKvd+hmMTOxdvCxS8sxMUvxACiQXwU6+Im7DDg5BNKY+fiY2BmYWMA0SA+SByuiJ2bbzIHrwAzMxsb0AGMDCAaxAeJg+SZ7wtaqfAISfQAdTIwMUM8ywhUyMTEzPD/71+5FXvPLWUkJpwAAgwAZqYvvHStbD4AAAAASUVORK5CYII=)}.tablesorter-dropbox .tablesorter-headerAsc:hover i.tablesorter-icon,.tablesorter-dropbox .tablesorter-headerSortUp:hover i.tablesorter-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALVJREFUeNpi/P//PwMhwILMCc+qZGNkYmr5/+9fzcpp7b9g4kzIitjYOdM4uXlLQTSyOCPMuqi8OiEefsHbHFzcQj++fX335eN71WWTmt6hmMTOwdXCycMnBDSJAUSD+CjWxRQ0GHBw86Sxc3AyMDOzMIBoEB8kDlfEzsk1mYOLByjPCnQAIwOIBvFB4iB55rsfmVS4+QV7QNYwMTNDHApUyMTExPDv/z+5Feu3L2UkJpwAAgwA244u+I9CleAAAAAASUVORK5CYII=)}.tablesorter-dropbox .tablesorter-headerDesc i.tablesorter-icon,.tablesorter-dropbox .tablesorter-headerSortDown i.tablesorter-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALdJREFUeNpi/P//PwMhwBLdtVGFhZ3zNhMzC4bkv79/GP78/K7KCDIpZ9mVw+xcfDaMTExwBf///WP4+e3TkSlROrZg7UxMLLns3HxnmFnZmGGK/v7+9ff3j2+5YHkQMSlC48Kv719m/f//D2IKkAbxQeJwRSDw4/OHmr+/fr0DqmAA0SA+TA6uaEq0zjugG+r//vkFcks9iA/3HbJvvn18O+vf379yP758mMXAoAAXZyQmnAACDADX316BiTFbMQAAAABJRU5ErkJggg==)}.tablesorter-dropbox .tablesorter-headerDesc:hover i.tablesorter-icon,.tablesorter-dropbox .tablesorter-headerSortDown:hover i.tablesorter-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALNJREFUeNpi/P//PwMhwBJf3uP879e3PUzMzBiS//7+ZWBi43JhBJmU2z7nIzMzEx8jIyNcAUj8799/nyZXpvCzgARYuXjTWBkZVjCzIEz7++cvw+//DGkgNiPMTWVT1l5hZvynDTINbMp/pqtdOcE6IDkmmM5fv3/5//v37z9QBQOIBvFhcnBFEwoj7/5jZFnz9+8fBhAN4sN9h+ybH9++JrGxscr/+vE1CVmckZhwAggwANvlUyq5Dd1wAAAAAElFTkSuQmCC)}.tablesorter-dropbox thead .sorter-false{cursor:default}.tablesorter-dropbox thead .sorter-false i.tablesorter-icon,.tablesorter-dropbox thead .sorter-false:hover i.tablesorter-icon{background-image:none;padding:4px}.tablesorter-dropbox td{padding:5px 6px;line-height:32px;color:#555;text-align:left;border-top:1px solid #edf1f5;border-bottom:1px solid #edf1f5}.tablesorter-dropbox tbody>tr.even:hover>td,.tablesorter-dropbox tbody>tr.hover>td,.tablesorter-dropbox tbody>tr.odd:hover>td,.tablesorter-dropbox tbody>tr:hover>td{background-color:rgba(230,245,255,.3);border-right:0;border-left:0;border-color:#c6d8e4;border-style:double}.tablesorter-dropbox .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-dropbox .tablesorter-filter-row,caption{background-color:#fff}.tablesorter-dropbox .tablesorter-filter-row td{background-color:#fff;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-dropbox .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-dropbox .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-dropbox .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-dropbox input.tablesorter-filter,.tablesorter-dropbox select.tablesorter-filter{width:98%;height:auto;margin:0;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.green.min.css b/dist/css/theme.green.min.css new file mode 100644 index 0000000..1bcbf53 --- /dev/null +++ b/dist/css/theme.green.min.css @@ -0,0 +1 @@ +.tablesorter-green{width:100%;text-align:left;border-spacing:0;border:1px solid #cdcdcd;border-width:1px 0 0 1px}.tablesorter-green td,.tablesorter-green th{font:12px/18px Arial,Sans-serif;border:1px solid #cdcdcd;border-width:0 1px 1px 0}.tablesorter-green tfoot tr,.tablesorter-green thead tr .tablesorter-header{background-position:center center;background-repeat:repeat-x;background-image:url(data:image/gif;base64,R0lGODlhAQBkAOYAAN/e39XU1fX19tTU1eXm5uTl5ePk5OLj4+Hi4vX29fT19PP08/Lz8vHy8fDx8O/w7+7v7uzt7Orr6ufo5/T08/Pz8ufn5uLi4eDg39/f3t3d3Nzc29HR0NDQz8/Pzuvq6urp6eno6Ojn5+fm5tfW1tbV1dTT09PS0tLR0dHQ0NDPz/f39/b29vX19fT09PPz8/Ly8vHx8e/v7+7u7u3t7ezs7Ovr6+rq6unp6ejo6Ofn5+bm5uXl5eTk5OPj4+Li4uHh4eDg4N/f397e3t3d3dzc3Nvb29ra2tnZ2djY2NfX19XV1dPT09LS0tHR0dDQ0M/Pz8rKysXFxf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAFMALAAAAAABAGQAAAdegCsrLC0tLi+ILi6FCSwsCS0KkhQVDA0OMjM0NTYfICEiIzw9P0AYGUQaG0ZHSEoDTU9Qs08pTk1MSyRJR0VDQT8+PTw7Ojg3NTMyMTAvi4WOhC0vMTI1OT9GTlFSgQA7)}.tablesorter-green th,.tablesorter-green thead td{font-weight:700;border-right:#cdcdcd 1px solid;border-collapse:collapse;padding:6px}.tablesorter-green .header,.tablesorter-green .tablesorter-header-inner{background-position:5px center;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhEAAQAOYAAA5NDBBYDlWWUzRUM5DVjp7inJ/fnQ1ECiCsGhyYFxqKFRFdDhBXDQxCCiO8HSK2HCCqGh2aGByUFxuPFhqNFhmHFRZ2EhVvERRpEBBVDSS8HiGyHB+mGh6fGRuTFxiAFBd5Eww/Cgs5CRp7Fiu+JRx8GCy/JjHAKyynKCuhJzXCMDbCMDnDMyNuHz3EODy9N0LFPSl7JkvIRjycOFDKS1LKTVPLT1XLUFTCT17OWTBkLmbQYnDTbHXVcXnWdoXago/djGmUZ112XCJEIEdjRf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEUALAAAAAAQABAAAAdlgEWCg4SFhoIvh4cVLECKhCMeJjwFj0UlEwgaMD4Gii0WFAkRHQ47BIY6IQAZDAwBCyAPOJa1toRBGBAwNTY3OT0/AoZCDQoOKi4yNDOKRCIfGycrKZYDBxIkKLZDFxy3RTHgloEAOw==);border-collapse:collapse;white-space:normal;cursor:pointer}.tablesorter-green thead .headerSortUp .tablesorter-header-inner,.tablesorter-green thead .tablesorter-headerAsc .tablesorter-header-inner,.tablesorter-green thead .tablesorter-headerSortUp .tablesorter-header-inner{background-image:url(data:image/gif;base64,R0lGODlhEAAQANUAAA5NDBBYDpDVjp7inJ/fnSCsGhyYFxFdDhBXDSO8HSK2HB2aGBuPFhqNFhmHFRZ2EhBVDSS8Hh6fGRuTFxd5Eww/Chp7Fhx8GCy/JjnDMyNuHzy9N0LFPVTCTzBkLmbQYnDTbHnWdo/djP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACMALAAAAAAQABAAAAY4wJFwSCwaj8ikcslMbpojR0bEtEwwoIHywihEOCECUvNoGBaSxEdg9FQAEAQicKAoOtC8fs8fBgEAOw==)}.tablesorter-green thead .headerSortDown .tablesorter-header-inner,.tablesorter-green thead .tablesorter-headerDesc .tablesorter-header-inner,.tablesorter-green thead .tablesorter-headerSortDown .tablesorter-header-inner{background-image:url(data:image/gif;base64,R0lGODlhEAAQANUAAFWWUzRUMw1EChqKFQxCCiO8HSCqGhyUFxVvERRpECGyHB+mGhiAFAs5CSu+JTHAKyynKCuhJzXCMDbCMD3EOELFPSl7JkvIRjycOFDKS1LKTVPLT1XLUF7OWXXVcYXagmmUZ112XCJEIEdjRf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACQALAAAAAAQABAAAAY4QJJwSCwaj8ikcskkghKGimbD6Xg+AGOIMChIKJcMBjlqMBSPSUQZEBwcEKYIsWiSLPa8fs9HBgEAOw==)}.tablesorter-green td.tablesorter-header .tablesorter-header-inner,.tablesorter-green th.tablesorter-header .tablesorter-header-inner{padding-left:23px}.tablesorter-green thead .tablesorter-header.sorter-false .tablesorter-header-inner{background-image:none;cursor:default;padding-left:6px}.tablesorter-green tbody td,.tablesorter-green tfoot th{padding:6px;vertical-align:top}.tablesorter-green td{color:#3d3d3d;padding:6px}.tablesorter-green tbody>tr.even.hover>td,.tablesorter-green tbody>tr.even:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr.even:hover+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr.even:hover>td,.tablesorter-green tbody>tr.hover>td,.tablesorter-green tbody>tr:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr:hover+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr:hover>td{background-color:#d9d9d9}.tablesorter-green tbody>tr.odd.hover>td,.tablesorter-green tbody>tr.odd:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr.odd:hover+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr.odd:hover>td{background-color:#bfbfbf}.tablesorter-green .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-green tr.odd>td{background-color:#ebfaeb}.tablesorter-green tr.even>td{background-color:#fff}.tablesorter-green td.primary,.tablesorter-green tr.odd td.primary{background-color:#99e6a6}.tablesorter-green td.secondary,.tablesorter-green tr.even td.primary,.tablesorter-green tr.odd td.secondary{background-color:#c2f0c9}.tablesorter-green td.tertiary,.tablesorter-green tr.even td.secondary,.tablesorter-green tr.odd td.tertiary{background-color:#d6f5db}.tablesorter-green tr.even td.tertiary{background-color:#ebfaed}caption{background-color:#fff}.tablesorter-green .tablesorter-filter-row{background-color:#eee}.tablesorter-green .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-green .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-green .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-green .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-green input.tablesorter-filter,.tablesorter-green select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.grey.min.css b/dist/css/theme.grey.min.css new file mode 100644 index 0000000..9fb75c5 --- /dev/null +++ b/dist/css/theme.grey.min.css @@ -0,0 +1 @@ +.tablesorter-grey{width:100%;margin:10px 0 15px;text-align:left;border-spacing:0;border-left:#555 1px solid}.tablesorter-grey th,.tablesorter-grey thead td{font:700 12px/18px Arial,Sans-serif;color:#c8c8c8;background-color:#3c3c3c;background-image:-moz-linear-gradient(top,#555,#3c3c3c);background-image:-ms-linear-gradient(top,#555,#3c3c3c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#555),to(#3c3c3c));background-image:-webkit-linear-gradient(top,#555,#3c3c3c);background-image:-o-linear-gradient(top,#555,#3c3c3c);background-image:linear-gradient(to bottom,#555,#3c3c3c);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#555555', endColorstr='#3c3c3c', GradientType=0 );background-repeat:repeat-x;border-right:#555 1px solid;text-shadow:0 1px 0 rgba(128,128,128,.7);-webkit-box-shadow:inset 0 1px 0 #222;-moz-box-shadow:inset 0 1px 0 #222;box-shadow:inset 0 1px 0 #222;padding:4px}.tablesorter-grey .tablesorter-header-inner{position:relative;padding:4px 15px 4px 4px}.tablesorter-grey .header,.tablesorter-grey .tablesorter-header{cursor:pointer}.tablesorter-grey .header i,.tablesorter-grey .tablesorter-header i.tablesorter-icon{width:18px;height:10px;position:absolute;right:2px;top:50%;margin-top:-10px;background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-repeat:no-repeat;background-position:center right;padding:4px;white-space:normal}.tablesorter-grey th.headerSortDown,.tablesorter-grey th.headerSortUp,.tablesorter-grey th.tablesorter-headerSortDown,.tablesorter-grey th.tablesorter-headerSortUp{color:#ddd;background-color:#135185;background-image:-moz-linear-gradient(top,#195c93,#0e4776);background-image:-ms-linear-gradient(top,#195c93,#0e4776);background-image:-webkit-gradient(linear,0 0,0 100%,from(#195c93),to(#0e4776));background-image:-webkit-linear-gradient(top,#195c93,#0e4776);background-image:-o-linear-gradient(top,#195c93,#0e4776);background-image:linear-gradient(to bottom,#195c93,#0e4776);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#195c93', endColorstr='#0e4776', GradientType=0 )}.tablesorter-grey .headerSortUp i.tablesorter-icon,.tablesorter-grey .tablesorter-headerAsc i.tablesorter-icon,.tablesorter-grey .tablesorter-headerSortUp i.tablesorter-icon{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7)}.tablesorter-grey .headerSortDown i.tablesorter-icon,.tablesorter-grey .tablesorter-headerDesc i.tablesorter-icon,.tablesorter-grey .tablesorter-headerSortDown i.tablesorter-icon{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7)}.tablesorter-grey thead .sorter-false{cursor:default}.tablesorter-grey thead .sorter-false i.tablesorter-icon{background-image:none;padding:4px}.tablesorter-grey tbody td,.tablesorter-grey tfoot td,.tablesorter-grey tfoot th{padding:4px;vertical-align:top;border-right:#555 1px solid}.tablesorter-grey tfoot td,.tablesorter-grey tfoot th{padding:8px}.tablesorter-grey td{color:#eee;background-color:#6d6d6d;padding:4px;vertical-align:top}.tablesorter-grey tbody>tr.even.hover>td,.tablesorter-grey tbody>tr.even:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr.even:hover+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr.even:hover>td,.tablesorter-grey tbody>tr.hover>td,.tablesorter-grey tbody>tr.odd.hover>td,.tablesorter-grey tbody>tr.odd:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr.odd:hover+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr.odd:hover>td,.tablesorter-grey tbody>tr:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr:hover+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr:hover>td{background-color:#134b78}.tablesorter-grey .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-grey tbody tr.odd>td{background-color:#5e5e5e}.tablesorter-grey tbody tr.even>td{background-color:#6d6d6d}.tablesorter-grey td.primary,.tablesorter-grey tr.odd td.primary{color:#ddd;background-color:#165388}.tablesorter-grey tr.even td.primary{color:#ddd;background-color:#195c93}.tablesorter-grey td.secondary,.tablesorter-grey tr.odd td.secondary{color:#ddd;background-color:#185C9A}.tablesorter-grey tr.even td.secondary{color:#ddd;background-color:#1D67A5}.tablesorter-grey td.tertiary,.tablesorter-grey tr.odd td.tertiary{color:#ddd;background-color:#1B67AD}.tablesorter-grey tr.even td.tertiary{color:#ddd;background-color:#2073B7}caption{background-color:#fff}.tablesorter-grey .tablesorter-filter-row{background-color:#3c3c3c}.tablesorter-grey .tablesorter-filter-row td{background-color:#3c3c3c;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-grey .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-grey .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-grey .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-grey input.tablesorter-filter,.tablesorter-grey select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#6d6d6d;border:1px solid #555;color:#ddd;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.ice.min.css b/dist/css/theme.ice.min.css new file mode 100644 index 0000000..add23f6 --- /dev/null +++ b/dist/css/theme.ice.min.css @@ -0,0 +1 @@ +.tablesorter-ice{width:100%;background-color:#fff;margin:10px 0 15px;text-align:left;border-spacing:0;border:1px solid #ccc;border-width:1px 0 0 1px}.tablesorter-ice td,.tablesorter-ice th{border:1px solid #ccc;border-width:0 1px 1px 0}.tablesorter-ice th,.tablesorter-ice thead td{font:12px/18px Arial,Sans-serif;color:#555;background-color:#f6f8f9;border-collapse:collapse;padding:4px;text-shadow:0 1px 0 rgba(255,255,255,.7)}.tablesorter-ice tbody td,.tablesorter-ice tfoot td,.tablesorter-ice tfoot th{padding:4px;vertical-align:top}.tablesorter-ice .header,.tablesorter-ice .tablesorter-header{background-color:#f6f8f9;background-position:center right;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhDAAMAMQAAAJEjAJCiwJBigJAiANFjgNGjgNEjQRIkQRHkANIkAVMlAVQmAZWnQZUnAdYoAhdpAhZoAlhqQlepQliqQppsApmrQxutgtutQtutAxwtwxwtg1yug1zugxtsw1yuP8A/yH5BAEAAB8ALAAAAAAMAAwAAAUx4Cd+3GiOW4ado2d9VMVm1xg9ptadTsP+QNZEcjoQTBDGCAFgLRSfQgCYMAiCn8EvBAA7);padding:4px 20px 4px 4px;white-space:normal;cursor:pointer}.tablesorter-ice .headerSortUp,.tablesorter-ice .tablesorter-headerAsc,.tablesorter-ice .tablesorter-headerSortUp{color:#333;background-color:#ebedee;background-position:center right;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhDAAMANUAAAJCiwNHkANFjgNEjQRIkQNJkQRMlARKkwRKkgVPlwZSmgdaogdYnwhfpghcowlhqgliqglgqAlgpwljqwporwpmrQplrAtsswtqsgtrsgtqsQxttAtvtQtttAxyuQxwtwxxtwxvtg10uw1zuQ1xuP8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAMAAwAAAY6wJKwJBoahyNQ6Dj0fDoZCpPEuWgqk4jxs8FQLI+Gg8Esm5kQydFQMC7IwkOAqUiUCAIzIjA4lwBlQQA7)}.tablesorter-ice .headerSortDown,.tablesorter-ice .tablesorter-headerDesc,.tablesorter-ice .tablesorter-headerSortDown{color:#333;background-color:#ebedee;background-position:center right;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhDAAMANUAAAE/iAJBigNFjgNEjQNFjQNDiwRHkQRHjwNHjwROlgRMlQRMlARJkgRKkgZQmAVPlgZWnQZSmgZRmAdXoAdXnwdUnAdbogdZoQhbowlhqAlepglkrAliqQtstAtqsQxyugxyuQxwuAxxuAxxtwxwtgxvtQ10vA12vA10u/8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACkALAAAAAAMAAwAAAY6wJQwdRoah6bP6DhEiVIdDxNEGm4yxlDpiJkwv2AmR2OhVCSJBsJ4gUQeCwOB6VAwBAXwYRAIpwBfQQA7)}.tablesorter-ice thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-ice tfoot .tablesorter-headerAsc,.tablesorter-ice tfoot .tablesorter-headerDesc,.tablesorter-ice tfoot .tablesorter-headerSortDown,.tablesorter-ice tfoot .tablesorter-headerSortUp{background-color:#ebedee}.tablesorter-ice td{color:#333}.tablesorter-ice tbody>tr.even:hover>td,.tablesorter-ice tbody>tr.hover>td,.tablesorter-ice tbody>tr.odd:hover>td,.tablesorter-ice tbody>tr:hover>td{background-color:#ebf2fa}.tablesorter-ice .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-ice tr.odd>td{background-color:#dfdfdf}.tablesorter-ice tr.even>td{background-color:#efefef}.tablesorter-ice td.primary,.tablesorter-ice tr.odd td.primary{background-color:#9ae5e5}.tablesorter-ice td.secondary,.tablesorter-ice tr.even td.primary,.tablesorter-ice tr.odd td.secondary{background-color:#c2f0f0}.tablesorter-ice td.tertiary,.tablesorter-ice tr.even td.secondary,.tablesorter-ice tr.odd td.tertiary{background-color:#d5f5f5}.tablesorter-ice tr.even td.tertiary{background-color:#ebfafa}.tablesorter-ice.containsStickyHeaders thead tr:nth-child(1) td,.tablesorter-ice.containsStickyHeaders thead tr:nth-child(1) th{border-top:#ccc 1px solid}caption{background-color:#fff}.tablesorter-ice .tablesorter-filter-row{background-color:#eee}.tablesorter-ice .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-ice .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-ice .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-ice .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-ice input.tablesorter-filter,.tablesorter-ice select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.jui.min.css b/dist/css/theme.jui.min.css new file mode 100644 index 0000000..8b24d87 --- /dev/null +++ b/dist/css/theme.jui.min.css @@ -0,0 +1 @@ +.tablesorter .filtered,.tablesorter-jui thead tr .sorter-false .ui-icon{display:none}.tablesorter-jui{width:100%;border-collapse:separate;border-spacing:2px;margin:10px 0 15px;padding:5px;font-size:.8em}.tablesorter-jui tfoot td,.tablesorter-jui tfoot th,.tablesorter-jui thead td,.tablesorter-jui thead th{position:relative;background-repeat:no-repeat;background-position:right center;font-weight:700!important;border-width:1px!important;text-align:left;padding:8px}.tablesorter-jui .header,.tablesorter-jui .tablesorter-header{cursor:pointer;white-space:normal}.tablesorter-jui .tablesorter-header-inner{padding-right:20px}.tablesorter-jui thead tr th .ui-icon{position:absolute;right:3px;top:50%;margin-top:-8px}.tablesorter-jui thead .sorter-false{cursor:default}.tablesorter-jui tfoot td,.tablesorter-jui tfoot th{font-weight:400!important;font-size:.9em;padding:2px}.tablesorter-jui td{padding:4px;vertical-align:top}.tablesorter-jui tbody>tr.hover>td,.tablesorter-jui tbody>tr:hover>td{opacity:.7;filter:alpha(opacity=70)}.tablesorter-jui .tablesorter-processing .tablesorter-header-inner{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-jui tr.ui-state-default{background-image:none;font-weight:400}.tablesorter-jui .tablesorter-processing{background-color:#ddd;background-color:rgba(255,255,255,.8)}.tablesorter-jui caption{border:0}.tablesorter-jui .tablesorter-filter-row{background-color:transparent}.tablesorter-jui .tablesorter-filter-row td{background-color:transparent;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-jui .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-jui .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-jui .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-jui input.tablesorter-filter,.tablesorter-jui select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/css/theme.metro-dark.min.css b/dist/css/theme.metro-dark.min.css new file mode 100644 index 0000000..349f9d9 --- /dev/null +++ b/dist/css/theme.metro-dark.min.css @@ -0,0 +1 @@ +.tablesorter-metro-dark{width:100%;font:12px/18px 'Segoe UI Semilight','Open Sans',Verdana,Arial,Helvetica,sans-serif;color:#000;background-color:#333;border-spacing:0;margin:10px 0 15px;text-align:left}.tablesorter-metro-dark caption.dark-row,.tablesorter-metro-dark tr.dark-row td,.tablesorter-metro-dark tr.dark-row th{background-color:#222;color:#fff;padding:2px;text-align:left;font-size:14px}.tablesorter-metro-dark caption,.tablesorter-metro-dark tfoot td,.tablesorter-metro-dark tfoot th,.tablesorter-metro-dark th,.tablesorter-metro-dark thead td{font-weight:300;font-size:15px;color:#ddd;background-color:#333;padding:4px}.tablesorter-metro-dark .header,.tablesorter-metro-dark .tablesorter-header{background-image:url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAGFBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u5jNePWAAAACHRSTlMAMxIHKwEgMWD59H4AAABSSURBVAjXY2BgYFJgAAHzYhDJ6igSAKTYBAUTgJSioKAQAwNzoaCguAFDiCAQuDIkgigxBgiA8cJAVCpQt6AgSL+JoKAzA0gjUBsQqBcBCYhFAAE/CV4zeSzxAAAAAElFTkSuQmCC);background-position:right 5px center;background-repeat:no-repeat;cursor:pointer;white-space:normal}.tablesorter-metro-dark .tablesorter-header-inner{padding:0 18px 0 4px}.tablesorter-metro-dark thead .headerSortUp,.tablesorter-metro-dark thead .tablesorter-headerAsc,.tablesorter-metro-dark thead .tablesorter-headerSortUp{background-image:url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u5meJAOAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC)}.tablesorter-metro-dark thead .headerSortDown,.tablesorter-metro-dark thead .tablesorter-headerDesc,.tablesorter-metro-dark thead .tablesorter-headerSortDown{background-image:url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAALVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7i0NViAAAADnRSTlMAMiweCQITTvDctZZqaTlM310AAABcSURBVAjXY2BgYEtgAAFHERDJqigUAKSYBQUNgFSioKAYAwOLIBA4MASBKFUGQxAlzAAF+94BwWuGKBC1lIFl3rt3Lx0YGCzevWsGSjK9e6cAUlT3HKyW9wADAwDRrBiDy6bKzwAAAABJRU5ErkJggg==)}.tablesorter-metro-dark thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-metro-dark td{background-color:#fff;padding:4px;vertical-align:top}.tablesorter-metro-dark tbody>tr.even:hover>td,.tablesorter-metro-dark tbody>tr.hover>td,.tablesorter-metro-dark tbody>tr.odd:hover>td,.tablesorter-metro-dark tbody>tr:hover>td{background-color:#bbb;color:#000}.tablesorter-metro-dark .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-metro-dark .tablesorter-pager button{background-color:#444;color:#eee;border:1px solid #555;cursor:pointer}.tablesorter-metro-dark .tablesorter-pager button:hover{background-color:#555}.tablesorter-metro-dark tr.odd>td{background-color:#eee}.tablesorter-metro-dark tr.even>td{background-color:#fff}.tablesorter-metro-dark tr.odd td.primary{background-color:#bfbfbf}.tablesorter-metro-dark td.primary,.tablesorter-metro-dark tr.even td.primary,.tablesorter-metro-dark tr.odd td.secondary{background-color:#d9d9d9}.tablesorter-metro-dark td.secondary,.tablesorter-metro-dark tr.even td.secondary,.tablesorter-metro-dark tr.odd td.tertiary{background-color:#e6e6e6}.tablesorter-metro-dark td.tertiary,.tablesorter-metro-dark tr.even td.tertiary{background-color:#f2f2f2}.tablesorter-metro-dark .tablesorter-filter-row{background-color:#eee}.tablesorter-metro-dark .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-metro-dark .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-metro-dark .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-metro-dark .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-metro-dark input.tablesorter-filter,.tablesorter-metro-dark select.tablesorter-filter{width:95%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99} \ No newline at end of file diff --git a/dist/js/extras/jquery.dragtable.mod.min.js b/dist/js/extras/jquery.dragtable.mod.min.js new file mode 100644 index 0000000..09cec48 --- /dev/null +++ b/dist/js/extras/jquery.dragtable.mod.min.js @@ -0,0 +1,3 @@ +/*! Dragtable Mod for TableSorter - 2/7/2015 (v2.19.0) */ +!function(a){"use strict";function b(){var b=a('');a(document.head).append(b),a(document.body).attr("onselectstart","return false;").attr("unselectable","on"),window.getSelection?window.getSelection().removeAllRanges():document.selection.empty()}function c(){a("#__dragtable_disable_text_selection__").remove(),f?a(document.body).attr("onselectstart",f):a(document.body).removeAttr("onselectstart"),g?a(document.body).attr("unselectable",g):a(document.body).removeAttr("unselectable")}var d,e=a.tablesorter;e.dragtable={create:function(b){var c,d=b.originalTable.el,e=b.options.dragHandle.replace(".","");d.children("thead").children().children("th,td").each(function(){var d=a(this);d.find(b.options.dragHandle+",."+e+"-disabled").length||(c=b.options.dragaccept?d.hasClass(b.options.dragaccept.replace(".","")):!0,d.wrapInner('
').prepend('
'))})},start:function(b){b=a(b)[0],b&&b.config&&(b.config.widgetOptions.dragtableLast={search:a(b).data("lastSearch"),order:e.dragtable.getOrder(b)})},update:function(b){var c,d,f,g=b.originalTable,h=g.el[0],i=a(h),j=h.config,k=j&&j.widgetOptions,l=g.startIndex-1,m=g.endIndex-1,n=e.dragtable.getOrder(h)||[],o=e.hasWidget(i,"filter")||!1,p=k&&k.dragtableLast||{},q=[];(p.order||[]).join("")!==n.join("")&&(j.sortList.length&&(d=a.extend(!0,[],j.sortList),a.each(n,function(a,b){f=e.isValueInArray(parseInt(b,10),d),b!==p.order[a]&&f>=0&&(j.sortList[f][0]=a)})),o&&a.each(p.search||[],function(a){q[a]=p.search[n[a]]}),c=e.hasWidget(j.$table,"editable")?k.editable_columnsArray:!1,c&&(j.widgetOptions.editable_columnsArray=e.dragtable.reindexArrayItem(c,l,m)),c=e.hasWidget(j.$table,"math")?k.math_ignore:!1,c&&(j.widgetOptions.math_ignore=e.dragtable.reindexArrayItem(c,l,m)),c=e.hasWidget(j.$table,"resizable")?k.resizable_widths:!1,c&&(k.resizable_widths=e.dragtable.moveArrayItem(c,l,m)),i.trigger("updateAll",[!1,function(){o&&setTimeout(function(){j.lastCombinedFilter=null,j.$table.data("lastSearch",q),e.setFilters(i,q),a.isFunction(b.options.tablesorterComplete)&&b.options.tablesorterComplete(j.table)},10)}]))},getOrder:function(b){return a(b).children("thead").children("."+e.css.headerRow).children().map(function(){return a(this).attr("data-column")}).get()||[]},startColumnMove:function(b){var c,d=b.el[0].config,f=b.startIndex-1,g=b.endIndex-1,h=d.columns-1,i=g===h?!1:f>=g,j=d.$table.children().children("tr");d.debug&&e.log("Inserting column "+f+(i?" before":" after")+" column "+g),j.each(function(){c=a(this).children(),c.eq(f)[i?"insertBefore":"insertAfter"](c.eq(g))}),c=d.$table.children("colgroup").children(),c.eq(f)[i?"insertBefore":"insertAfter"](c.eq(g))},swapNodes:function(a,b){var c,d,e,f=a.length;for(c=0;f>c;c++)d=a[c].parentNode,e=a[c].nextSibling===b[c]?a[c]:a[c].nextSibling,b[c].parentNode.insertBefore(a[c],b[c]),d.insertBefore(b[c],e)},moveArrayItem:function(a,b,c){var e,f=a.length;if(c>=f)for(e=c-f;e--+1;)a.push(d);return a.splice(c,0,a.splice(b,1)[0]),a},reindexArrayItem:function(b,c,d){var e=a.inArray(d,b),f=a.inArray(c,b),g=(Math.max.apply(Math,b),[]);return e>=0&&f>=0?b:(a.each(b,function(a,b){c>d?b>=d?g.push(b+(c>b?1:0)):g.push(b):d>c&&(b===c?g.push(d):d>b&&b>=c?g.push(b-1):d>=b?g.push(b):b>c&&g.push(b+(d>b?0:1)))}),g.sort())}},/*! dragtable v2.0.14 Mod */ +a.widget("akottr.dragtable",{options:{revert:!1,dragHandle:".table-handle",maxMovingRows:40,excludeFooter:!1,onlyHeaderThreshold:100,dragaccept:null,persistState:null,restoreState:null,exact:!0,clickDelay:10,containment:null,cursor:"move",cursorAt:!1,distance:0,tolerance:"pointer",axis:"x",beforeStart:a.noop,beforeMoving:a.noop,beforeReorganize:a.noop,beforeStop:a.noop,tablesorterComplete:null,sortClass:".sorter"},originalTable:{el:null,selectedHandle:null,sortOrder:null,startIndex:0,endIndex:0},sortableTable:{el:a(),selectedHandle:a(),movingRow:a()},persistState:function(){var b=this;this.originalTable.el.find("th").each(function(a){""!==this.id&&(b.originalTable.sortOrder[this.id]=a)}),a.ajax({url:this.options.persistState,data:this.originalTable.sortOrder})},_restoreState:function(b){for(var c in b)c in b&&(this.originalTable.startIndex=a("#"+c).closest("th").prevAll().length+1,this.originalTable.endIndex=parseInt(b[c],10)+1,this._bubbleCols())},_bubbleCols:function(){e.dragtable.startColumnMove(this.originalTable)},_rearrangeTableBackroundProcessing:function(){var b=this;return function(){b._bubbleCols(),b.options.beforeStop(b.originalTable),b.sortableTable.el.remove(),c(),e.dragtable.update(b),a.isFunction(b.options.persistState)?b.options.persistState(b.originalTable):b.persistState()}},_rearrangeTable:function(){var a=this;return function(){a.originalTable.selectedHandle.removeClass("dragtable-handle-selected"),a.sortableTable.el.sortable("disable"),a.sortableTable.el.addClass("dragtable-disabled"),a.options.beforeReorganize(a.originalTable,a.sortableTable),a.originalTable.endIndex=a.sortableTable.movingRow.prevAll().length+1,setTimeout(a._rearrangeTableBackroundProcessing(),50)}},_generateSortable:function(c){c.cancelBubble?c.cancelBubble=!0:c.stopPropagation();for(var d=this,e=this.originalTable.el[0].attributes,f="",g=0;g',s=[],t=m.eq(0).children("th, td").length;for(g=0;t>g;g++){var u=m.children(":nth-child("+(g+1)+")");u.is(":visible")&&(q=0,s[g]='
  • "+(p?'':"")+"",m.each(function(a){s[g]+=""+u[a].outerHTML+""}),s[g]+="",u=n.children(":nth-child("+(g+1)+")"),d.options.maxMovingRows>1&&(u=u.add(n.children(":nth-child("+(g+1)+")").slice(0,d.options.maxMovingRows-1))),u.each(function(a){s[g]+=""+this.outerHTML+""}),s[g]+="",d.options.excludeFooter||(s[g]+=""+l.filter("tfoot").children("tr:visible").children()[g].outerHTML+""),s[g]+="
  • ")}r+=s.join("")+"",this.sortableTable.el=this.originalTable.el.before(r).prev(),this.sortableTable.el.find("> li > table").each(function(b){a(this).css("width",j[b]+"px")}),this.sortableTable.selectedHandle=this.sortableTable.el.find("th .dragtable-handle-selected");var v=this.options.dragaccept?"li:has("+this.options.dragaccept+")":"li";this.sortableTable.el.sortable({items:v,stop:this._rearrangeTable(),revert:this.options.revert,tolerance:this.options.tolerance,containment:this.options.containment,cursor:this.options.cursor,cursorAt:this.options.cursorAt,distance:this.options.distance,axis:this.options.axis}),this.originalTable.startIndex=a(c.target).closest("th,td").prevAll().length+1,this.options.beforeMoving(this.originalTable,this.sortableTable),this.sortableTable.movingRow=this.sortableTable.el.children("li:nth-child("+this.originalTable.startIndex+")"),b(),this.sortableTable.movingRow.trigger(a.extend(a.Event(c.type),{which:1,clientX:c.clientX,clientY:c.clientY,pageX:c.pageX,pageY:c.pageY,screenX:c.screenX,screenY:c.screenY}));var w=this.sortableTable.el.find(".ui-sortable-placeholder");w.height()>0&&w.css("height",this.sortableTable.el.find(".ui-sortable-helper").height()),w.html('
    ')},bindTo:{},_create:function(){var b=this;b.originalTable={el:b.element,selectedHandle:a(),sortOrder:{},startIndex:0,endIndex:0},e.dragtable.create(b),b.bindTo="> thead > tr > "+(b.options.dragaccept||"th, td"),b.element.find(b.bindTo).find(b.options.dragHandle).length&&(b.bindTo+=" "+b.options.dragHandle),a.isFunction(b.options.restoreState)?b.options.restoreState(b.originalTable):b._restoreState(b.options.restoreState),b.originalTable.el.on("mousedown.dragtable",b.bindTo,function(c){1===c.which&&(e.dragtable.start(b.originalTable.el),b.options.beforeStart(b.originalTable)!==!1&&(clearTimeout(b.downTimer),b.downTimer=setTimeout(function(){b.originalTable.selectedHandle=a(b),b.originalTable.selectedHandle.addClass("dragtable-handle-selected"),b._generateSortable(c)},b.options.clickDelay)))}).on("mouseup.dragtable",b.options.dragHandle,function(){clearTimeout(b.downTimer)})},redraw:function(){this.destroy(),this._create()},destroy:function(){this.originalTable.el.off("mousedown.dragtable mouseup.dragtable",this.bindTo),a.Widget.prototype.destroy.apply(this,arguments)}});var f=a(document.body).attr("onselectstart"),g=a(document.body).attr("unselectable")}(jQuery); \ No newline at end of file diff --git a/dist/js/extras/jquery.metadata.min.js b/dist/js/extras/jquery.metadata.min.js new file mode 100644 index 0000000..27450af --- /dev/null +++ b/dist/js/extras/jquery.metadata.min.js @@ -0,0 +1 @@ +!function($){$.extend({metadata:{defaults:{type:"class",name:"metadata",cre:/(\{.*\})/,single:"metadata"},setType:function(a,b){this.defaults.type=a,this.defaults.name=b},get:function(elem,opts){var data,m,e,attr,settings=$.extend({},this.defaults,opts);if(settings.single.length||(settings.single="metadata"),data=$.data(elem,settings.single))return data;if(data="{}","class"===settings.type)m=settings.cre.exec(elem.className),m&&(data=m[1]);else if("elem"===settings.type){if(!elem.getElementsByTagName)return void 0;e=elem.getElementsByTagName(settings.name),e.length&&(data=$.trim(e[0].innerHTML))}else void 0!==elem.getAttribute&&(attr=elem.getAttribute(settings.name),attr&&(data=attr));return data.indexOf("{")<0&&(data="{"+data+"}"),data=eval("("+data+")"),$.data(elem,settings.single,data),data}}}),$.fn.metadata=function(a){return $.metadata.get(this[0],a)}}(jQuery); \ No newline at end of file diff --git a/dist/js/extras/jquery.quicksearch.min.js b/dist/js/extras/jquery.quicksearch.min.js new file mode 100644 index 0000000..c091c77 --- /dev/null +++ b/dist/js/extras/jquery.quicksearch.min.js @@ -0,0 +1 @@ +!function(a,b,c,d){a.fn.quicksearch=function(c,d){var e,f,g,h,i="",j=this,k=a.extend({delay:100,selector:null,stripeRows:null,loader:null,noResults:"",childRow:"tablesorter-childRow",matchedResultsCount:0,bind:"keyup",onBefore:function(){},onAfter:function(){},show:function(){this.style.display=""},hide:function(){this.style.display="none"},prepareQuery:function(a){return a.toLowerCase().split(" ")},testQuery:function(a,b){for(var c=0;cc;c++)j||k.testQuery(h,f[c],g[c])||a(g[c]).hasClass(k.childRow)&&a(g[c>1?c-1:0]).is(":visible")?(k.show.apply(g[c]),e=!1,d++):k.hide.apply(g[c]);return e?this.results(!1):(this.results(!0),this.stripe()),this.matchedResultsCount=d,this.loader(!1),k.onAfter(),this},this.search=function(a){i=a,j.trigger()},this.currentMatchedResults=function(){return this.matchedResultsCount},this.stripe=function(){if("object"==typeof k.stripeRows&&null!==k.stripeRows){var b=k.stripeRows.join(" "),c=k.stripeRows.length;h.not(":hidden").each(function(d){a(this).removeClass(b).addClass(k.stripeRows[d%c])})}return this},this.strip_html=function(b){var c=b.replace(new RegExp("<[^<]+>","g"),"");return c=a.trim(c.toLowerCase())},this.results=function(b){return"string"==typeof k.noResults&&""!==k.noResults&&(b?a(k.noResults).hide():a(k.noResults).show()),this},this.loader=function(b){return"string"==typeof k.loader&&""!==k.loader&&(b?a(k.loader).show():a(k.loader).hide()),this},this.cache=function(){h=a(c),"string"==typeof k.noResults&&""!==k.noResults&&(h=h.not(k.noResults));var b="string"==typeof k.selector?h.find(k.selector):a(c).not(k.noResults);return f=b.map(function(){return j.strip_html(this.innerHTML)}),g=h.map(function(){return this}),i=i||this.val()||"",this.go()},this.trigger=function(){return this.loader(!0),k.onBefore(),b.clearTimeout(e),e=b.setTimeout(function(){j.go()},k.delay),this},this.cache(),this.results(!0),this.stripe(),this.loader(!1),this.each(function(){a(this).on(k.bind,function(){i=a(this).val(),j.trigger()})})}}(jQuery,this,document); \ No newline at end of file diff --git a/dist/js/extras/jquery.tablesorter.pager.min.js b/dist/js/extras/jquery.tablesorter.pager.min.js new file mode 100644 index 0000000..7742eb4 --- /dev/null +++ b/dist/js/extras/jquery.tablesorter.pager.min.js @@ -0,0 +1,5 @@ +/*! + * tablesorter (FORK) pager plugin + * updated 5/17/2015 (v2.22.0) + */ +!function(a){"use strict";var b=a.tablesorter;a.extend({tablesorterPager:new function(){this.defaults={container:null,ajaxUrl:null,customAjaxUrl:function(a,b){return b},ajaxObject:{dataType:"json"},processAjaxOnInit:!0,ajaxProcessing:function(a){return[0,[],null]},output:"{startRow} to {endRow} of {totalRows} rows",updateArrows:!0,page:0,pageReset:0,size:10,maxOptionSize:20,savePages:!0,storageKey:"tablesorter-pager",fixedHeight:!1,countChildRows:!1,removeRows:!1,cssFirst:".first",cssPrev:".prev",cssNext:".next",cssLast:".last",cssGoto:".gotoPage",cssPageDisplay:".pagedisplay",cssPageSize:".pagesize",cssErrorRow:"tablesorter-errorRow",cssDisabled:"disabled",totalRows:0,totalPages:0,filteredRows:0,filteredPages:0,ajaxCounter:0,currentFilters:[],startRow:0,endRow:0,$size:null,last:{}};var c="filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete pageSize pageSet pageAndSize pagerUpdate refreshComplete ",d=this,e=function(a,b){var c="addClass",d="removeClass",e=a.cssDisabled,f=!!b,g=f||0===a.page,h=Math.min(a.totalPages,a.filteredPages),i=f||a.page===h-1||0===h;a.updateArrows&&(a.$container.find(a.cssFirst+","+a.cssPrev)[g?c:d](e).attr("aria-disabled",g),a.$container.find(a.cssNext+","+a.cssLast)[i?c:d](e).attr("aria-disabled",i))},f=function(b,c){var d,e,f,g=b.config,h=g.$table.hasClass("hasFilters");if(h&&!c.ajaxUrl)if(a.isEmptyObject(g.cache))c.filteredRows=c.totalRows=g.$tbodies.eq(0).children("tr").not(c.countChildRows?"":"."+g.cssChildRow).length;else for(c.filteredRows=0,d=g.cache[0].normalized,f=d.length,e=0;f>e;e++)c.filteredRows+=c.regexRows.test(d[e][g.columns].$row[0].className)?0:1;else h||(c.filteredRows=c.totalRows)},g=function(c,d,g){if(!d.initializing){var j,k,l,m,n,o,p=c.config,q=d.size||d.settings.size||10;if(d.countChildRows&&k.push(p.cssChildRow),d.totalPages=Math.ceil(d.totalRows/q),p.totalRows=d.totalRows,f(c,d),p.filteredRows=d.filteredRows,d.filteredPages=Math.ceil(d.filteredRows/q)||0,Math.min(d.totalPages,d.filteredPages)>=0){if(k=d.size*d.page>d.filteredRows&&g,d.page=k?d.pageReset||0:d.page,d.startRow=k?d.size*d.page+1:0===d.filteredRows?0:d.size*d.page+1,d.endRow=Math.min(d.filteredRows,d.totalRows,d.size*(d.page+1)),l=d.$container.find(d.cssPageDisplay),j=(d.ajaxData&&d.ajaxData.output?d.ajaxData.output||d.output:d.output).replace(/\{page([\-+]\d+)?\}/gi,function(a,b){return d.totalPages?d.page+(b?parseInt(b,10):1):0}).replace(/\{\w+(\s*:\s*\w+)?\}/gi,function(a){var b,c,e=a.replace(/[{}\s]/g,""),f=e.split(":"),g=d.ajaxData,h=/(rows?|pages?)$/i.test(e)?0:"";return/(startRow|page)/.test(f[0])&&"input"===f[1]?(b=(""+("page"===f[0]?d.totalPages:d.totalRows)).length,c="page"===f[0]?d.page+1:d.startRow,''):f.length>1&&g&&g[f[0]]?g[f[0]][f[1]]:d[e]||(g?g[e]:h)||h}),d.$goto.length){for(k="",o=h(d),n=o.length,m=0;n>m;m++)k+='";d.$goto.html(k).val(d.page+1)}l.length&&(l["INPUT"===l[0].nodeName?"val":"html"](j),l.find(".ts-startRow, .ts-page").unbind("change.pager").bind("change.pager",function(){var b=a(this).val(),c=a(this).hasClass("ts-startRow")?Math.floor(b/d.size)+1:b;p.$table.trigger("pageSet.pager",[c])}))}e(d),i(c,d),d.initialized&&g!==!1&&(p.debug&&b.log("Pager: Triggering pagerComplete"),p.$table.trigger("pagerComplete",d),d.savePages&&b.storage&&b.storage(c,d.storageKey,{page:d.page,size:d.size}))}},h=function(b){var c,d,e,f,g,h,i=Math.min(b.totalPages,b.filteredPages)||1,j=5*Math.ceil(i/b.maxOptionSize/5),k=i>b.maxOptionSize,l=b.page+1,m=j,n=i-j,o=[1],p=k?j:1;for(c=p;i>=c;)o.push(c),c+=k?j:1;if(o.push(i),k){for(e=[],d=Math.max(Math.floor(b.maxOptionSize/j)-1,5),m=l-d,1>m&&(m=1),n=l+d,n>i&&(n=i),c=m;n>=c;c++)e.push(c);o=a.grep(o,function(b,c){return a.inArray(b,o)===c}),g=o.length,h=e.length,g-h>j/2&&g+h>b.maxOptionSize&&(f=Math.floor(g/2)-Math.floor(h/2),Array.prototype.splice.apply(o,[f,h])),o=o.concat(e)}return o=a.grep(o,function(b,c){return a.inArray(b,o)===c}).sort(function(a,b){return a-b})},i=function(b,c){var d,e,f=b.config,g=f.$tbodies.eq(0);g.find("tr.pagerSavedHeightSpacer").remove(),c.fixedHeight&&!c.isDisabled&&(e=a.data(b,"pagerSavedHeight"),e&&(d=e-g.height(),d>5&&a.data(b,"pagerLastSize")===c.size&&g.children("tr:visible").length')))},j=function(b,c){var d,e=b.config,f=e.$tbodies.eq(0);f.find("tr.pagerSavedHeightSpacer").remove(),f.children("tr:visible").length||f.append(' '),d=f.children("tr").eq(0).height()*c.size,a.data(b,"pagerSavedHeight",d),i(b,c),a.data(b,"pagerLastSize",c.size)},k=function(a,c){if(!c.ajaxUrl){var d,e=0,f=a.config,g=f.$tbodies.eq(0).children("tr"),h=g.length,i=c.page*c.size,j=i+c.size,k=f.widgetOptions&&f.widgetOptions.filter_filteredRow||"filtered",l=0,m=0;for(c.cacheIndex=[],d=0;h>d;d++)g[d].className.match(k)||(m===i&&g[d].className.match(f.cssChildRow)?g[d].style.display="none":(g[d].style.display=m>=i&&j>m?"":"none",l!==m&&m>=i&&j>m&&(c.cacheIndex.push(d),l=m),m+=g[d].className.match(f.cssChildRow+"|"+f.selectorRemove.slice(1))&&!c.countChildRows?0:1,m===j&&"none"!==g[d].style.display&&g[d].className.match(b.css.cssHasChild)&&(e=d)));if(e>0&&g[e].className.match(b.css.cssHasChild))for(;++e> Ajax Error",f,h),b.showError(d,0===f.status?"Not connected, verify Network":404===f.status?"Requested page not found [404]":500===f.status?"Internal Server Error [500]":"parsererror"===h?"Requested JSON parse failed":"timeout"===h?"Time out error":"abort"===h?"Ajax Request aborted":"Uncaught error: "+f.statusText+" ["+f.status+"]"),w.$tbodies.eq(0).children("tr").detach(),e.totalRows=0;else{if(a.isArray(z)?(k=isNaN(z[0])&&!isNaN(z[1]),u=z[k?1:0],e.totalRows=isNaN(u)?e.totalRows||0:u,w.totalRows=w.filteredRows=e.filteredRows=e.totalRows,s=0===e.totalRows?[""]:z[k?0:1]||[],r=z[2]):(e.ajaxData=z,w.totalRows=e.totalRows=z.total,w.filteredRows=e.filteredRows="undefined"!=typeof z.filteredRows?z.filteredRows:z.total,r=z.headers,s=z.rows),t=s&&s.length,s instanceof jQuery)e.processAjaxOnInit&&(w.$tbodies.eq(0).children("tr").detach(),w.$tbodies.eq(0).append(s));else if(t){for(i=0;t>i;i++){for(y+="",j=0;j"+s[i][j]+"";y+=""}e.processAjaxOnInit&&w.$tbodies.eq(0).html(y)}if(e.processAjaxOnInit=!0,r&&r.length===A)for(l=x.hasClass("hasStickyHeaders"),n=l?w.widgetOptions.$sticky.children("thead:first").children("tr").children():"",m=x.find("tfoot tr:first").children(),o=w.$headers.filter("th "),v=o.length,j=0;v>j;j++)p=o.eq(j),p.find("."+b.css.icon).length?(q=p.find("."+b.css.icon).clone(!0),p.find(".tablesorter-header-inner").html(r[j]).append(q),l&&n.length&&(q=n.eq(j).find("."+b.css.icon).clone(!0),n.eq(j).find(".tablesorter-header-inner").html(r[j]).append(q))):(p.find(".tablesorter-header-inner").html(r[j]),l&&n.length&&n.eq(j).find(".tablesorter-header-inner").html(r[j])),m.eq(j).html(r[j])}w.showProcessing&&b.isProcessing(d),e.totalPages=Math.ceil(e.totalRows/(e.size||e.settings.size||10)),e.last.totalRows=e.totalRows,e.last.currentFilters=e.currentFilters,e.last.sortList=(w.sortList||[]).join(","),g(d,e,!1),x.trigger("updateCache",[function(){e.initialized&&setTimeout(function(){w.debug&&b.log("Pager: Triggering pagerChange"),x.trigger("applyWidgets").trigger("pagerChange",e),g(d,e,!0)},0)}])}e.initialized||(e.initialized=!0,e.initializing=!1,d.config.debug&&b.log("Pager: Triggering pagerInitialized"),a(d).trigger("applyWidgets").trigger("pagerInitialized",e),g(d,e))},n=function(c,d){var e,f=o(c,d),g=a(document),h=c.config;""!==f&&(h.showProcessing&&b.isProcessing(c,!0),g.bind("ajaxError.pager",function(a,b,e,f){m(null,c,d,b,f),g.unbind("ajaxError.pager")}),e=++d.ajaxCounter,d.last.ajaxUrl=f,d.ajaxObject.url=f,d.ajaxObject.success=function(a,b,f){ee;e++)m.push(k+"["+i[e][0]+"]="+i[e][1]);h=h.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g,m.length?m.join("&"):k),m=[]}if(l){for(l=l[1],f=j.length,e=0;f>e;e++)j[e]&&m.push(l+"["+e+"]="+encodeURIComponent(j[e]));h=h.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g,m.length?m.join("&"):l),d.currentFilters=j}return"function"==typeof d.customAjaxUrl&&(h=d.customAjaxUrl(c,h)),g.debug&&b.log("Pager: Ajax url = "+h),h},p=function(c,d,e){var f,h,i,j,l=a(c),m=c.config,n=m.$table.hasClass("hasFilters"),o=d&&d.length||0,p=e.page*e.size,q=e.size;if(1>o)return void(m.debug&&b.log("Pager: >> No rows for pager to render"));if(e.page>=e.totalPages&&v(c,e),e.cacheIndex=[],e.isDisabled=!1,e.initialized&&(m.debug&&b.log("Pager: Triggering pagerChange"),l.trigger("pagerChange",e)),e.removeRows){for(b.clearTableBody(c),f=b.processTbody(c,m.$tbodies.eq(0),!0),h=n?0:p,i=n?0:p,j=0;q>j&&hp&&q>=j&&(j++,e.cacheIndex.push(h),f.append(d[h]))),h++;b.processTbody(c,f,!1)}else k(c,e);g(c,e),c.isUpdating&&(m.debug&&b.log("Pager: Triggering updateComplete"),l.trigger("updateComplete",[c,!0]))},q=function(c,d){var f,g,h;for(d.ajax?e(d,!0):(d.isDisabled=!0,a.data(c,"pagerLastPage",d.page),a.data(c,"pagerLastSize",d.size),d.page=0,d.size=d.totalRows,d.totalPages=1,a(c).addClass("pagerDisabled").removeAttr("aria-describedby").find("tr.pagerSavedHeightSpacer").remove(),p(c,c.config.rowsCopy,d),a(c).trigger("applyWidgets"),c.config.debug&&b.log("Pager: Disabled")),g=d.$size.add(d.$goto).add(d.$container.find(".ts-startRow, .ts-page")),h=g.length,f=0;h>f;f++)g.eq(f).attr("aria-disabled","true").addClass(d.cssDisabled)[0].disabled=!0},r=function(a){var b=a.config,c=b.pager;b.$table.trigger("updateCache",[function(){var d,e=[],f=a.config.cache[0].normalized;for(c.totalRows=f.length,d=0;dg-1&&0!==g&&(d.page=g-1),j.currentFilters=""===(j.currentFilters||[]).join("")?[]:j.currentFilters,d.currentFilters=""===(d.currentFilters||[]).join("")?[]:d.currentFilters,(j.page!==d.page||j.size!==d.size||j.totalRows!==d.totalRows||(j.currentFilters||[]).join(",")!==(d.currentFilters||[]).join(",")||(j.ajaxUrl||"")!==(d.ajaxObject.url||"")||(j.optAjaxUrl||"")!==(d.ajaxUrl||"")||j.sortList!==(h.sortList||[]).join(","))&&(h.debug&&b.log("Pager: Changing to page "+d.page),d.last={page:d.page,size:d.size,sortList:(h.sortList||[]).join(","),totalRows:d.totalRows,currentFilters:d.currentFilters||[],ajaxUrl:d.ajaxObject.url||"",optAjaxUrl:d.ajaxUrl||""},d.ajax?n(c,d):d.ajax||p(c,h.rowsCopy,d),a.data(c,"pagerLastPage",d.page),d.initialized&&e!==!1&&(h.debug&&b.log("Pager: Triggering pageMoved"),i.trigger("pageMoved",d).trigger("applyWidgets"),c.isUpdating&&(h.debug&&b.log("Pager: Triggering updateComplete"),i.trigger("updateComplete",[c,!0]))))))}},t=function(b,c,d){d.size=c||d.size||d.settings.size||10,d.$size.val(d.size),a.data(b,"pagerLastPage",d.page),a.data(b,"pagerLastSize",d.size),d.totalPages=Math.ceil(d.totalRows/d.size),d.filteredPages=Math.ceil(d.filteredRows/d.size),s(b,d)},u=function(a,b){b.page=0,s(a,b)},v=function(a,b){b.page=Math.min(b.totalPages,b.filteredPages)-1,s(a,b)},w=function(a,b){b.page++,b.page>=Math.min(b.totalPages,b.filteredPages)-1&&(b.page=Math.min(b.totalPages,b.filteredPages)-1),s(a,b)},x=function(a,b){b.page--,b.page<=0&&(b.page=0),s(a,b)},y=function(d,e){q(d,e),e.$container.hide(),d.config.appender=null,e.initialized=!1,delete d.config.rowsCopy,a(d).unbind(c.split(" ").join(".pager ").replace(/\s+/g," ")),b.storage&&b.storage(d,e.storageKey,"")},z=function(c,d,e){var f,g=c.config;d.$size.add(d.$goto).add(d.$container.find(".ts-startRow, .ts-page")).removeClass(d.cssDisabled).removeAttr("disabled").attr("aria-disabled","false"),d.isDisabled=!1,d.page=a.data(c,"pagerLastPage")||d.page||0,d.size=a.data(c,"pagerLastSize")||parseInt(d.$size.find("option[selected]").val(),10)||d.size||d.settings.size||10,d.$size.val(d.size),d.totalPages=Math.ceil(Math.min(d.totalRows,d.filteredRows)/d.size),c.id&&(f=c.id+"_pager_info",d.$container.find(d.cssPageDisplay).attr("id",f),g.$table.attr("aria-describedby",f)),j(c,d),e&&(g.$table.trigger("updateRows"),t(c,d.size,d),l(c,d),g.debug&&b.log("Pager: Enabled"))};d.appender=function(b,c){var d=b.config,e=d.pager;e.ajax||(d.rowsCopy=c,e.totalRows=e.countChildRows?d.$tbodies.eq(0).children("tr").length:c.length,e.size=a.data(b,"pagerLastSize")||e.size||e.settings.size||10,e.totalPages=Math.ceil(e.totalRows/e.size),p(b,c,e),g(b,e,!1))},d.construct=function(e){return this.each(function(){if(this.config&&this.hasInitialized){var f,h,i,m=this,n=m.config,o=n.widgetOptions,p=n.pager=a.extend(!0,{},a.tablesorterPager.defaults,e),A=n.$table,B=p.$container=a(p.container).addClass("tablesorter-pager").show();p.settings=a.extend(!0,{},a.tablesorterPager.defaults,e),n.debug&&b.log("Pager: Initializing"),p.oldAjaxSuccess=p.oldAjaxSuccess||p.ajaxObject.success,n.appender=d.appender,p.initializing=!0,p.savePages&&b.storage&&(f=b.storage(m,p.storageKey)||{},p.page=isNaN(f.page)?p.page:f.page,p.size=(isNaN(f.size)?p.size:f.size)||p.settings.size||10,a.data(m,"pagerLastSize",p.size)),p.regexRows=new RegExp("("+(o.filter_filteredRow||"filtered")+"|"+n.selectorRemove.slice(1)+"|"+n.cssChildRow+")"),A.unbind(c.split(" ").join(".pager ").replace(/\s+/g," ")).bind("filterInit.pager filterStart.pager",function(b,c){p.currentFilters=a.isArray(c)?c:n.$table.data("lastSearch"),"filterStart"===b.type&&p.pageReset!==!1&&(n.lastCombinedFilter||"")!==(p.currentFilters||[]).join("")&&(p.page=p.pageReset)}).bind("filterEnd.pager sortEnd.pager",function(){p.currentFilters=n.$table.data("lastSearch"),(p.initialized||p.initializing)&&(n.delayInit&&n.rowsCopy&&0===n.rowsCopy.length&&r(m),g(m,p,!1),s(m,p,!1),n.$table.trigger("applyWidgets"))}).bind("disable.pager",function(a){a.stopPropagation(),q(m,p)}).bind("enable.pager",function(a){a.stopPropagation(),z(m,p,!0)}).bind("destroy.pager",function(a){a.stopPropagation(),y(m,p)}).bind("updateComplete.pager",function(a,b,c){if(a.stopPropagation(),b&&!c&&!p.ajax){var d=n.$tbodies.eq(0).children("tr").not(n.selectorRemove);p.totalRows=d.length-(p.countChildRows?0:d.filter("."+n.cssChildRow).length),p.totalPages=Math.ceil(p.totalRows/p.size),d.length&&n.rowsCopy&&0===n.rowsCopy.length&&r(b),p.page>=p.totalPages&&v(b,p),k(b,p),j(b,p),g(b,p,!0)}}).bind("pageSize.pager refreshComplete.pager",function(a,b){a.stopPropagation(),t(m,parseInt(b,10)||p.settings.size||10,p),k(m,p),g(m,p,!1)}).bind("pageSet.pager pagerUpdate.pager",function(a,b){a.stopPropagation(),"pagerUpdate"===a.type&&(b="undefined"==typeof b?p.page+1:b,p.last.page=!0),p.page=(parseInt(b,10)||1)-1,s(m,p,!0),g(m,p,!1)}).bind("pageAndSize.pager",function(a,b,c){a.stopPropagation(),p.page=(parseInt(b,10)||1)-1,t(m,parseInt(c,10)||p.settings.size||10,p),s(m,p,!0),k(m,p),g(m,p,!1)}),h=[p.cssFirst,p.cssPrev,p.cssNext,p.cssLast],i=[u,x,w,v],n.debug&&!B.length&&b.log("Pager: >> Container not found"),B.find(h.join(",")).attr("tabindex",0).unbind("click.pager").bind("click.pager",function(b){b.stopPropagation();var c,d=a(this),e=h.length;if(!d.hasClass(p.cssDisabled))for(c=0;e>c;c++)if(d.is(h[c])){i[c](m,p);break}}),p.$goto=B.find(p.cssGoto),p.$goto.length?p.$goto.unbind("change.pager").bind("change.pager",function(){p.page=a(this).val()-1,s(m,p,!0),g(m,p,!1)}):n.debug&&b.log("Pager: >> Goto selector not found"),p.$size=B.find(p.cssPageSize),p.$size.length?(p.$size.find("option").removeAttr("selected"),p.$size.unbind("change.pager").bind("change.pager",function(){return p.$size.val(a(this).val()),a(this).hasClass(p.cssDisabled)||(t(m,parseInt(a(this).val(),10),p),j(m,p)),!1})):n.debug&&b.log("Pager: >> Size selector not found"),p.initialized=!1,A.trigger("pagerBeforeInitialized",p),z(m,p,!1),"string"==typeof p.ajaxUrl?(p.ajax=!0,n.widgetOptions.filter_serversideFiltering=!0,n.serverSideSorting=!0,s(m,p)):(p.ajax=!1,a(this).trigger("appendCache",!0),l(m,p)),p.ajax||p.initialized||(p.initializing=!1,p.initialized=!0,s(m,p),n.debug&&b.log("Pager: Triggering pagerInitialized"),n.$table.trigger("pagerInitialized",p),n.widgetOptions.filter_initialized&&b.hasWidget(m,"filter")||g(m,p,!1)),n.widgetInit.pager=!0}})}}}),b.showError=function(b,c){var d,e,f,g,h=a(b),i=h.length;for(d=0;i>d;d++)f=h[d].config,f&&(g=f.pager&&f.pager.cssErrorRow||f.widgetOptions.pager_css&&f.widgetOptions.pager_css.errorRow||"tablesorter-errorRow","undefined"==typeof c?f.$table.find("thead").find(f.selectorRemove).remove():e=a(/tr\>/.test(c)?c:''+c+"").click(function(){a(this).remove()}).appendTo(f.$table.find("thead:first")).addClass(g+" "+f.selectorRemove.slice(1)).attr({role:"alert","aria-live":"assertive"}))},a.fn.extend({tablesorterPager:a.tablesorterPager.construct})}(jQuery); \ No newline at end of file diff --git a/dist/js/extras/semver-mod.min.js b/dist/js/extras/semver-mod.min.js new file mode 100644 index 0000000..733fe11 --- /dev/null +++ b/dist/js/extras/semver-mod.min.js @@ -0,0 +1,2 @@ +/*! Modified semver.js for node.js (v4.3.3, 3/27/2015) */ +!function(){function a(a,b){if(a instanceof d)return a;if("string"!=typeof a)return null;if(a.length>U)return null;var c=b?W[la]:W[ia];if(!c.test(a))return null;try{return new d(a,b)}catch(e){return null}}function b(b,c){var d=a(b,c);return d?d.version:null}function c(b,c){var d=a(b.trim().replace(/^[=v]+/,""),c);return d?d.version:null}function d(a,b){if(a instanceof d){if(a.loose===b)return a;a=a.version}else if("string"!=typeof a)throw new TypeError("Invalid Version: "+a);if(a.length>U)throw new TypeError("version is longer than "+U+" characters");if(!(this instanceof d))return new d(a,b);R("SemVer",a,b),this.loose=b;var c=a.trim().match(b?W[la]:W[ia]);if(!c)throw new TypeError("Invalid Version: "+a);if(this.raw=a,this.major=+c[1],this.minor=+c[2],this.patch=+c[3],this.major>V||this.major<0)throw new TypeError("Invalid major version");if(this.minor>V||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>V||this.patch<0)throw new TypeError("Invalid patch version");c[4]?this.prerelease=c[4].split(".").map(function(a){if(/^[0-9]+$/.test(a)){var b=+a;if(b>=0&&V>b)return b}return a}):this.prerelease=[],this.build=c[5]?c[5].split("."):[],this.format()}function e(a,b,c,e){"string"==typeof c&&(e=c,c=void 0);try{return new d(a,c).inc(b,e).version}catch(f){return null}}function f(b,c){if(s(b,c))return null;var d=a(b),e=a(c);if(d.prerelease.length||e.prerelease.length){for(var f in d)if(("major"===f||"minor"===f||"patch"===f)&&d[f]!==e[f])return"pre"+f;return"prerelease"}for(var f in d)if(("major"===f||"minor"===f||"patch"===f)&&d[f]!==e[f])return f}function g(a,b){var c=La.test(a),d=La.test(b);return c&&d&&(a=+a,b=+b),c&&!d?-1:d&&!c?1:b>a?-1:a>b?1:0}function h(a,b){return g(b,a)}function i(a,b){return new d(a,b).major}function j(a,b){return new d(a,b).minor}function k(a,b){return new d(a,b).patch}function l(a,b,c){return new d(a,c).compare(b)}function m(a,b){return l(a,b,!0)}function n(a,b,c){return l(b,a,c)}function o(a,b){return a.sort(function(a,c){return T.compare(a,c,b)})}function p(a,b){return a.sort(function(a,c){return T.rcompare(a,c,b)})}function q(a,b,c){return l(a,b,c)>0}function r(a,b,c){return l(a,b,c)<0}function s(a,b,c){return 0===l(a,b,c)}function t(a,b,c){return 0!==l(a,b,c)}function u(a,b,c){return l(a,b,c)>=0}function v(a,b,c){return l(a,b,c)<=0}function w(a,b,c,d){var e;switch(b){case"===":"object"==typeof a&&(a=a.version),"object"==typeof c&&(c=c.version),e=a===c;break;case"!==":"object"==typeof a&&(a=a.version),"object"==typeof c&&(c=c.version),e=a!==c;break;case"":case"=":case"==":e=s(a,c,d);break;case"!=":e=t(a,c,d);break;case">":e=q(a,c,d);break;case">=":e=u(a,c,d);break;case"<":e=r(a,c,d);break;case"<=":e=v(a,c,d);break;default:throw new TypeError("Invalid operator: "+b)}return e}function x(a,b){if(a instanceof x){if(a.loose===b)return a;a=a.value}return this instanceof x?(R("comparator",a,b),this.loose=b,this.parse(a),this.semver===Ma?this.value="":this.value=this.operator+this.semver.version,void R("comp",this)):new x(a,b)}function y(a,b){if(a instanceof y&&a.loose===b)return a;if(!(this instanceof y))return new y(a,b);if(this.loose=b,this.raw=a,this.set=a.split(/\s*\|\|\s*/).map(function(a){return this.parseRange(a.trim())},this).filter(function(a){return a.length}),!this.set.length)throw new TypeError("Invalid SemVer Range: "+a);this.format()}function z(a,b){return new y(a,b).set.map(function(a){return a.map(function(a){return a.value}).join(" ").trim().split(" ")})}function A(a,b){return R("comp",a),a=E(a,b),R("caret",a),a=C(a,b),R("tildes",a),a=G(a,b),R("xrange",a),a=I(a,b),R("stars",a),a}function B(a){return!a||"x"===a.toLowerCase()||"*"===a}function C(a,b){return a.trim().split(/\s+/).map(function(a){return D(a,b)}).join(" ")}function D(a,b){var c=b?W[xa]:W[wa];return a.replace(c,function(b,c,d,e,f){R("tilde",a,b,c,d,e,f);var g;return B(c)?g="":B(d)?g=">="+c+".0.0 <"+(+c+1)+".0.0":B(e)?g=">="+c+"."+d+".0 <"+c+"."+(+d+1)+".0":f?(R("replaceTilde pr",f),"-"!==f.charAt(0)&&(f="-"+f),g=">="+c+"."+d+"."+e+f+" <"+c+"."+(+d+1)+".0"):g=">="+c+"."+d+"."+e+" <"+c+"."+(+d+1)+".0",R("tilde return",g),g})}function E(a,b){return a.trim().split(/\s+/).map(function(a){return F(a,b)}).join(" ")}function F(a,b){R("caret",a,b);var c=b?W[Ca]:W[Ba];return a.replace(c,function(b,c,d,e,f){R("caret",a,b,c,d,e,f);var g;return B(c)?g="":B(d)?g=">="+c+".0.0 <"+(+c+1)+".0.0":B(e)?g="0"===c?">="+c+"."+d+".0 <"+c+"."+(+d+1)+".0":">="+c+"."+d+".0 <"+(+c+1)+".0.0":f?(R("replaceCaret pr",f),"-"!==f.charAt(0)&&(f="-"+f),g="0"===c?"0"===d?">="+c+"."+d+"."+e+f+" <"+c+"."+d+"."+(+e+1):">="+c+"."+d+"."+e+f+" <"+c+"."+(+d+1)+".0":">="+c+"."+d+"."+e+f+" <"+(+c+1)+".0.0"):(R("no pr"),g="0"===c?"0"===d?">="+c+"."+d+"."+e+" <"+c+"."+d+"."+(+e+1):">="+c+"."+d+"."+e+" <"+c+"."+(+d+1)+".0":">="+c+"."+d+"."+e+" <"+(+c+1)+".0.0"),R("caret return",g),g})}function G(a,b){return R("replaceXRanges",a,b),a.split(/\s+/).map(function(a){return H(a,b)}).join(" ")}function H(a,b){a=a.trim();var c=b?W[sa]:W[ra];return a.replace(c,function(b,c,d,e,f,g){R("xRange",a,b,c,d,e,f,g);var h=B(d),i=h||B(e),j=i||B(f),k=j;return"="===c&&k&&(c=""),h?b=">"===c||"<"===c?"<0.0.0":"*":c&&k?(i&&(e=0),j&&(f=0),">"===c?(c=">=",i?(d=+d+1,e=0,f=0):j&&(e=+e+1,f=0)):"<="===c&&(c="<",i?d=+d+1:e=+e+1),b=c+d+"."+e+"."+f):i?b=">="+d+".0.0 <"+(+d+1)+".0.0":j&&(b=">="+d+"."+e+".0 <"+d+"."+(+e+1)+".0"),R("xRange return",b),b})}function I(a,b){return R("replaceStars",a,b),a.trim().replace(W[Ja],"")}function J(a,b,c,d,e,f,g,h,i,j,k,l,m){return b=B(c)?"":B(d)?">="+c+".0.0":B(e)?">="+c+"."+d+".0":">="+b,h=B(i)?"":B(j)?"<"+(+i+1)+".0.0":B(k)?"<"+i+"."+(+j+1)+".0":l?"<="+i+"."+j+"."+k+"-"+l:"<="+h,(b+" "+h).trim()}function K(a,b){for(var c=0;c0){var d=a[c].semver;if(d.major===b.major&&d.minor===b.minor&&d.patch===b.patch)return!0}}return!1}return!0}function L(a,b,c){try{b=new y(b,c)}catch(d){return!1}return b.test(a)}function M(a,b,c){return a.filter(function(a){return L(a,b,c)}).sort(function(a,b){return n(a,b,c)})[0]||null}function N(a,b){try{return new y(a,b).range||"*"}catch(c){return null}}function O(a,b,c){return Q(a,b,"<",c)}function P(a,b,c){return Q(a,b,">",c)}function Q(a,b,c,e){a=new d(a,e),b=new y(b,e);var f,g,h,i,j;switch(c){case">":f=q,g=v,h=r,i=">",j=">=";break;case"<":f=r,g=u,h=q,i="<",j="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(L(a,b,e))return!1;for(var k=0;k)?=?)";var na=Y++;X[na]=X[$]+"|x|X|\\*";var oa=Y++;X[oa]=X[Z]+"|x|X|\\*";var pa=Y++;X[pa]="[v=\\s]*("+X[oa]+")(?:\\.("+X[oa]+")(?:\\.("+X[oa]+")(?:"+X[ea]+")?"+X[ha]+"?)?)?";var qa=Y++;X[qa]="[v=\\s]*("+X[na]+")(?:\\.("+X[na]+")(?:\\.("+X[na]+")(?:"+X[fa]+")?"+X[ha]+"?)?)?";var ra=Y++;X[ra]="^"+X[ma]+"\\s*"+X[pa]+"$";var sa=Y++;X[sa]="^"+X[ma]+"\\s*"+X[qa]+"$";var ta=Y++;X[ta]="(?:~>?)";var ua=Y++;X[ua]="(\\s*)"+X[ta]+"\\s+",W[ua]=new RegExp(X[ua],"g");var va="$1~",wa=Y++;X[wa]="^"+X[ta]+X[pa]+"$";var xa=Y++;X[xa]="^"+X[ta]+X[qa]+"$";var ya=Y++;X[ya]="(?:\\^)";var za=Y++;X[za]="(\\s*)"+X[ya]+"\\s+",W[za]=new RegExp(X[za],"g");var Aa="$1^",Ba=Y++;X[Ba]="^"+X[ya]+X[pa]+"$";var Ca=Y++;X[Ca]="^"+X[ya]+X[qa]+"$";var Da=Y++;X[Da]="^"+X[ma]+"\\s*("+ka+")$|^$";var Ea=Y++;X[Ea]="^"+X[ma]+"\\s*("+ja+")$|^$";var Fa=Y++;X[Fa]="(\\s*)"+X[ma]+"\\s*("+ka+"|"+X[pa]+")",W[Fa]=new RegExp(X[Fa],"g");var Ga="$1$2$3",Ha=Y++;X[Ha]="^\\s*("+X[pa]+")\\s+-\\s+("+X[pa]+")\\s*$";var Ia=Y++;X[Ia]="^\\s*("+X[qa]+")\\s+-\\s+("+X[qa]+")\\s*$";var Ja=Y++;X[Ja]="(<|>)?=?\\s*\\*";for(var Ka=0;Y>Ka;Ka++)R(Ka,X[Ka]),W[Ka]||(W[Ka]=new RegExp(X[Ka]));T.parse=a,T.valid=b,T.clean=c,window.semver=T.SemVer=d,d.prototype.format=function(){return this.version=this.major+"."+this.minor+"."+this.patch,this.prerelease.length&&(this.version+="-"+this.prerelease.join(".")),this.version},d.prototype.inspect=function(){return''},d.prototype.toString=function(){return this.version},d.prototype.compare=function(a){return R("SemVer.compare",this.version,this.loose,a),a instanceof d||(a=new d(a,this.loose)),this.compareMain(a)||this.comparePre(a)},d.prototype.compareMain=function(a){return a instanceof d||(a=new d(a,this.loose)),g(this.major,a.major)||g(this.minor,a.minor)||g(this.patch,a.patch)},d.prototype.comparePre=function(a){if(a instanceof d||(a=new d(a,this.loose)),this.prerelease.length&&!a.prerelease.length)return-1;if(!this.prerelease.length&&a.prerelease.length)return 1;if(!this.prerelease.length&&!a.prerelease.length)return 0;var b=0;do{var c=this.prerelease[b],e=a.prerelease[b];if(R("prerelease compare",b,c,e),void 0===c&&void 0===e)return 0;if(void 0===e)return 1;if(void 0===c)return-1;if(c!==e)return g(c,e)}while(++b)},d.prototype.inc=function(a,b){switch(a){case"premajor":this.prerelease.length=0,this.patch=0,this.minor=0,this.major++,this.inc("pre",b);break;case"preminor":this.prerelease.length=0,this.patch=0,this.minor++,this.inc("pre",b);break;case"prepatch":this.prerelease.length=0,this.inc("patch",b),this.inc("pre",b);break;case"prerelease":0===this.prerelease.length&&this.inc("patch",b),this.inc("pre",b);break;case"major":(0!==this.minor||0!==this.patch||0===this.prerelease.length)&&this.major++,this.minor=0,this.patch=0,this.prerelease=[];break;case"minor":(0!==this.patch||0===this.prerelease.length)&&this.minor++,this.patch=0,this.prerelease=[];break;case"patch":0===this.prerelease.length&&this.patch++,this.prerelease=[];break;case"pre":if(0===this.prerelease.length)this.prerelease=[0];else{for(var c=this.prerelease.length;--c>=0;)"number"==typeof this.prerelease[c]&&(this.prerelease[c]++,c=-2);-1===c&&this.prerelease.push(0)}b&&(this.prerelease[0]===b?isNaN(this.prerelease[1])&&(this.prerelease=[b,0]):this.prerelease=[b,0]);break;default:throw new Error("invalid increment argument: "+a)}return this.format(),this},T.inc=e,T.diff=f,T.compareIdentifiers=g;var La=/^[0-9]+$/;T.rcompareIdentifiers=h,T.major=i,T.minor=j,T.patch=k,T.compare=l,T.compareLoose=m,T.rcompare=n,T.sort=o,T.rsort=p,T.gt=q,T.lt=r,T.eq=s,T.neq=t,T.gte=u,T.lte=v,T.cmp=w,T.Comparator=x;var Ma={};x.prototype.parse=function(a){var b=this.loose?W[Da]:W[Ea],c=a.match(b);if(!c)throw new TypeError("Invalid comparator: "+a);this.operator=c[1],"="===this.operator&&(this.operator=""),c[2]?this.semver=new d(c[2],this.loose):this.semver=Ma},x.prototype.inspect=function(){return''},x.prototype.toString=function(){return this.value},x.prototype.test=function(a){return R("Comparator.test",a,this.loose),this.semver===Ma?!0:("string"==typeof a&&(a=new d(a,this.loose)),w(a,this.operator,this.semver,this.loose))},T.Range=y,y.prototype.inspect=function(){return''},y.prototype.format=function(){return this.range=this.set.map(function(a){return a.join(" ").trim()}).join("||").trim(),this.range},y.prototype.toString=function(){return this.range},y.prototype.parseRange=function(a){var b=this.loose;a=a.trim(),R("range",a,b);var c=b?W[Ia]:W[Ha];a=a.replace(c,J),R("hyphen replace",a),a=a.replace(W[Fa],Ga),R("comparator trim",a,W[Fa]),a=a.replace(W[ua],va),a=a.replace(W[za],Aa),a=a.split(/\s+/).join(" ");var d=b?W[Da]:W[Ea],e=a.split(" ").map(function(a){return A(a,b)}).join(" ").split(/\s+/);return this.loose&&(e=e.filter(function(a){return!!a.match(d)})),e=e.map(function(a){return new x(a,b)})},T.toComparators=z,y.prototype.test=function(a){if(!a)return!1;"string"==typeof a&&(a=new d(a,this.loose));for(var b=0;b (class from cssIcon) + onRenderTemplate : null, // function(index, template){ return template; }, (template is a string) + onRenderHeader : null, // function(index){}, (nothing to return) + + // *** functionality + cancelSelection : true, // prevent text selection in the header + tabIndex : true, // add tabindex to header for keyboard accessibility + dateFormat : 'mmddyyyy', // other options: 'ddmmyyy' or 'yyyymmdd' + sortMultiSortKey : 'shiftKey', // key used to select additional columns + sortResetKey : 'ctrlKey', // key used to remove sorting on a column + usNumberFormat : true, // false for German '1.234.567,89' or French '1 234 567,89' + delayInit : false, // if false, the parsed table contents will not update until the first sort + 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. + resort : true, // default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed + + // *** sort options + headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc. + ignoreCase : true, // ignore case while sorting + sortForce : null, // column(s) first sorted; always applied + sortList : [], // Initial sort order; applied initially; updated when manually sorted + sortAppend : null, // column(s) sorted last; always applied + sortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained + + sortInitialOrder : 'asc', // sort direction on first click + sortLocaleCompare: false, // replace equivalent character (accented characters) + sortReset : false, // third click on the header will reset column to default - unsorted + sortRestart : false, // restart sort to 'sortInitialOrder' when clicking on previously unsorted columns + + emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero, emptyMax, emptyMin + stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero + textExtraction : 'basic', // text extraction method/function - function(node, table, cellIndex){} + textAttribute : 'data-text',// data-attribute that contains alternate cell text (used in default textExtraction function) + textSorter : null, // choose overall or specific column sorter function(a, b, direction, table, columnIndex) [alt: ts.sortText] + numberSorter : null, // choose overall numeric sorter function(a, b, direction, maxColumnValue) + + // *** widget options + widgets: [], // method to add widgets, e.g. widgets: ['zebra'] + widgetOptions : { + zebra : [ 'even', 'odd' ] // zebra widget alternating row class names + }, + initWidgets : true, // apply widgets on tablesorter initialization + widgetClass : 'widget-{name}', // table class name template to match to include a widget + + // *** callbacks + initialized : null, // function(table){}, + + // *** extra css class names + tableClass : '', + cssAsc : '', + cssDesc : '', + cssNone : '', + cssHeader : '', + cssHeaderRow : '', + cssProcessing : '', // processing icon applied to header during sort/filter + + cssChildRow : 'tablesorter-childRow', // class name indiciating that a row is to be attached to the its parent + cssIcon : 'tablesorter-icon', // if this class does not exist, the {icon} will not be added from the headerTemplate + cssIconNone : '', // class name added to the icon when there is no column sort + cssIconAsc : '', // class name added to the icon when the column has an ascending sort + cssIconDesc : '', // class name added to the icon when the column has a descending sort + cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!) + cssNoSort : 'tablesorter-noSort', // class name added to element inside header; clicking on it won't cause a sort + cssIgnoreRow : 'tablesorter-ignoreRow', // header row to ignore; cells within this row will not be added to c.$headers + + // *** events + pointerClick : 'click', + pointerDown : 'mousedown', + pointerUp : 'mouseup', + + // *** selectors + selectorHeaders : '> thead th, > thead td', + selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort + selectorRemove : '.remove-me', + + // *** advanced + debug : false, + + // *** Internal variables + headerList: [], + empties: {}, + strings: {}, + parsers: [] + + // removed: widgetZebra: { css: ['even', 'odd'] } + + }; + + // internal css classes - these will ALWAYS be added to + // the table and MUST only contain one class name - fixes #381 + ts.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' + }; + + // labels applied to sortable headers for accessibility (aria) support + ts.language = { + sortAsc : 'Ascending sort applied, ', + sortDesc : 'Descending sort applied, ', + sortNone : 'No sort applied, ', + nextAsc : 'activate to apply an ascending sort', + nextDesc : 'activate to apply a descending sort', + nextNone : 'activate to remove the sort' + }; + + // These methods can be applied on table.config instance + ts.instanceMethods = {}; + + /* debuging utils */ + function log() { + var a = arguments[0], + s = arguments.length > 1 ? Array.prototype.slice.call(arguments) : a; + if (typeof console !== 'undefined' && typeof console.log !== 'undefined') { + console[ /error/i.test(a) ? 'error' : /warn/i.test(a) ? 'warn' : 'log' ](s); + } else { + alert(s); + } + } + + function benchmark(s, d) { + log(s + ' (' + (new Date().getTime() - d.getTime()) + 'ms)'); + } + + ts.log = log; + ts.benchmark = benchmark; + + // $.isEmptyObject from jQuery v1.4 + function isEmptyObject(obj) { + /*jshint forin: false */ + for (var name in obj) { + return false; + } + return true; + } + + ts.getElementText = function(c, node, cellIndex) { + if (!node) { return ''; } + var te, + t = c.textExtraction || '', + // node could be a jquery object + // http://jsperf.com/jquery-vs-instanceof-jquery/2 + $node = node.jquery ? node : $(node); + if (typeof(t) === 'string') { + // check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow! + // http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/ + return $.trim( + ( t === 'basic' ? $node.attr(c.textAttribute) || node.textContent : node.textContent ) || + $node.text() + ); + } else { + if (typeof(t) === 'function') { + return $.trim( t($node[0], c.table, cellIndex) ); + } else if (typeof (te = ts.getColumnData( c.table, t, cellIndex )) === 'function') { + return $.trim( te($node[0], c.table, cellIndex) ); + } + } + // fallback + return $.trim( $node[0].textContent || $node.text() ); + }; + + function detectParserForColumn(c, rows, rowIndex, cellIndex) { + var cur, $node, + i = ts.parsers.length, + node = false, + nodeValue = '', + keepLooking = true; + while (nodeValue === '' && keepLooking) { + rowIndex++; + if (rows[rowIndex]) { + node = rows[rowIndex].cells[cellIndex]; + nodeValue = ts.getElementText(c, node, cellIndex); + $node = $(node); + if (c.debug) { + log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"'); + } + } else { + keepLooking = false; + } + } + while (--i >= 0) { + cur = ts.parsers[i]; + // ignore the default text parser because it will always be true + if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, c.table, node, $node)) { + return cur; + } + } + // nothing found, return the generic parser (text) + return ts.getParserById('text'); + } + + // centralized function to extract/parse cell contents + ts.getParsedText = function( c, cell, colIndex, txt ) { + if ( typeof txt === 'undefined' ) { + txt = ts.getElementText( c, cell, colIndex ); + } + // if no parser, make sure to return the txt + var val = '' + txt, + parser = c.parsers[ colIndex ], + extractor = c.extractors[ colIndex ]; + if ( parser ) { + // do extract before parsing, if there is one + if ( extractor && typeof extractor.format === 'function' ) { + txt = extractor.format( txt, c.table, cell, colIndex ); + } + // allow parsing if the string is empty, previously parsing would change it to zero, + // in case the parser needs to extract data from the table cell attributes + val = parser.id === 'no-parser' ? '' : + // make sure txt is a string (extractor may have converted it) + parser.format( '' + txt, c.table, cell, colIndex ); + if ( c.ignoreCase && typeof val === 'string' ) { + val = val.toLowerCase(); + } + } + return val; + } + + function buildParserCache( c, $tbodies ) { + var rows, list, l, i, h, ch, np, p, e, time, tb, len, + table = c.table, + j = 0, + parsersDebug = ''; + // update table bodies in case we start with an empty table + c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'); + tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies; + len = tb.length; + if ( len === 0) { + return c.debug ? log('Warning: *Empty table!* Not building a parser cache') : ''; + } else if (c.debug) { + time = new Date(); + log('Detecting parsers for each column'); + } + list = { + extractors: [], + parsers: [] + }; + while (j < len) { + rows = tb[j].rows; + if (rows.length) { + l = c.columns; // rows[j].cells.length; + for (i = 0; i < l; i++) { + h = c.$headerIndexed[i]; + // get column indexed table cell + ch = ts.getColumnData( table, c.headers, i ); + // get column parser/extractor + e = ts.getParserById( ts.getData(h, ch, 'extractor') ); + p = ts.getParserById( ts.getData(h, ch, 'sorter') ); + np = ts.getData(h, ch, 'parser') === 'false'; + // empty cells behaviour - keeping emptyToBottom for backwards compatibility + c.empties[i] = ( ts.getData(h, ch, 'empty') || c.emptyTo || (c.emptyToBottom ? 'bottom' : 'top' ) ).toLowerCase(); + // text strings behaviour in numerical sorts + c.strings[i] = ( ts.getData(h, ch, 'string') || c.stringTo || 'max' ).toLowerCase(); + if (np) { + p = ts.getParserById('no-parser'); + } + if (!e) { + // For now, maybe detect someday + e = false; + } + if (!p) { + p = detectParserForColumn(c, rows, -1, i); + } + if (c.debug) { + parsersDebug += 'column:' + i + '; extractor:' + e.id + '; parser:' + p.id + '; string:' + c.strings[i] + '; empty: ' + c.empties[i] + '\n'; + } + list.parsers[i] = p; + list.extractors[i] = e; + } + } + j += (list.parsers.length) ? len : 1; + } + if (c.debug) { + log(parsersDebug ? parsersDebug : 'No parsers detected'); + benchmark('Completed detecting parsers', time); + } + c.parsers = list.parsers; + c.extractors = list.extractors; + } + + /* utils */ + function buildCache(table, $tbodies) { + var cc, t, v, i, j, k, $tb, $row, cols, cacheTime, + totalRows, rowData, prevRowData, colMax, + c = table.config, + parsers = c.parsers; + // update tbody variable + c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'); + $tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies, + c.cache = {}; + c.totalRows = 0; + // if no parsers found, return - it's an empty table. + if (!parsers) { + return c.debug ? log('Warning: *Empty table!* Not building a cache') : ''; + } + if (c.debug) { + cacheTime = new Date(); + } + // processing icon + if (c.showProcessing) { + ts.isProcessing(table, true); + } + for (k = 0; k < $tb.length; k++) { + colMax = []; // column max value per tbody + cc = c.cache[k] = { + normalized: [] // array of normalized row data; last entry contains 'rowData' above + // colMax: # // added at the end + }; + + totalRows = ($tb[k] && $tb[k].rows.length) || 0; + for (i = 0; i < totalRows; ++i) { + rowData = { + // order: original row order # + // $row : jQuery Object[] + child: [], // child row text (filter widget) + raw: [] // original row text + }; + /** Add the table data to main data array */ + $row = $( $tb[ k ].rows[ i ] ); + cols = []; + // if this is a child row, add it to the last row's children and continue to the next row + // ignore child row class, if it is the first row + if ( $row.hasClass( c.cssChildRow ) && i !== 0 ) { + t = cc.normalized.length - 1; + prevRowData = cc.normalized[ t ][ c.columns ]; + prevRowData.$row = prevRowData.$row.add( $row ); + // add 'hasChild' class name to parent row + if ( !$row.prev().hasClass( c.cssChildRow ) ) { + $row.prev().addClass( ts.css.cssHasChild ); + } + // save child row content (un-parsed!) + v = $row.children( 'th, td' ); + t = prevRowData.child.length; + prevRowData.child[ t ] = []; + // child row content does not account for colspans/rowspans; so indexing may be off + for ( j = 0; j < c.columns; j++ ) { + prevRowData.child[ t ][ j ] = ts.getParsedText( c, v[ j ], j ); + } + // go to the next for loop + continue; + } + rowData.$row = $row; + rowData.order = i; // add original row position to rowCache + for ( j = 0; j < c.columns; ++j ) { + if (typeof parsers[ j ] === 'undefined') { + if ( c.debug ) { + log( 'No parser found for cell:', $row[ 0 ].cells[ j ], 'does it have a header?' ); + } + continue; + } + t = ts.getElementText( c, $row[ 0 ].cells[j], j ); + rowData.raw.push( t ); // save original row text + v = ts.getParsedText( c, $row[ 0 ].cells[ j ], j, t ); + cols.push( v ); + if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) { + // determine column max value (ignore sign) + colMax[ j ] = Math.max( Math.abs( v ) || 0, colMax[ j ] || 0 ); + } + } + // ensure rowData is always in the same location (after the last column) + cols[ c.columns ] = rowData; + cc.normalized.push( cols ); + } + cc.colMax = colMax; + // total up rows, not including child rows + c.totalRows += cc.normalized.length; + + } + if ( c.showProcessing ) { + ts.isProcessing( table ); // remove processing icon + } + if ( c.debug ) { + benchmark( 'Building cache for ' + totalRows + ' rows', cacheTime ); + } + } + + // init flag (true) used by pager plugin to prevent widget application + function appendToTable(table, init) { + var c = table.config, + wo = c.widgetOptions, + $tbodies = c.$tbodies, + rows = [], + cc = c.cache, + n, totalRows, $bk, $tb, + i, k, appendTime; + // empty table - fixes #206/#346 + if (isEmptyObject(cc)) { + // run pager appender in case the table was just emptied + return c.appender ? c.appender(table, rows) : + table.isUpdating ? c.$table.trigger('updateComplete', table) : ''; // Fixes #532 + } + if (c.debug) { + appendTime = new Date(); + } + for (k = 0; k < $tbodies.length; k++) { + $bk = $tbodies.eq(k); + if ($bk.length) { + // get tbody + $tb = ts.processTbody(table, $bk, true); + n = cc[k].normalized; + totalRows = n.length; + for (i = 0; i < totalRows; i++) { + rows.push(n[i][c.columns].$row); + // removeRows used by the pager plugin; don't render if using ajax - fixes #411 + if (!c.appender || (c.pager && (!c.pager.removeRows || !wo.pager_removeRows) && !c.pager.ajax)) { + $tb.append(n[i][c.columns].$row); + } + } + // restore tbody + ts.processTbody(table, $tb, false); + } + } + if (c.appender) { + c.appender(table, rows); + } + if (c.debug) { + benchmark('Rebuilt table', appendTime); + } + // apply table widgets; but not before ajax completes + if (!init && !c.appender) { ts.applyWidget(table); } + if (table.isUpdating) { + c.$table.trigger('updateComplete', table); + } + } + + function formatSortingOrder(v) { + // look for 'd' in 'desc' order; return true + return (/^d/i.test(v) || v === 1); + } + + function buildHeaders(table) { + var ch, $t, h, i, t, lock, time, indx, + c = table.config; + c.headerList = []; + c.headerContent = []; + if (c.debug) { + time = new Date(); + } + // children tr in tfoot - see issue #196 & #547 + c.columns = ts.computeColumnIndex( c.$table.children('thead, tfoot').children('tr') ); + // add icon if cssIcon option exists + i = c.cssIcon ? '' : ''; + // redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683 + c.$headers = $( $.map( $(table).find(c.selectorHeaders), function(elem, index) { + $t = $(elem); + // ignore cell (don't add it to c.$headers) if row has ignoreRow class + if ($t.parent().hasClass(c.cssIgnoreRow)) { return; } + // make sure to get header cell & not column indexed cell + ch = ts.getColumnData( table, c.headers, index, true ); + // save original header content + c.headerContent[index] = $t.html(); + // if headerTemplate is empty, don't reformat the header cell + if ( c.headerTemplate !== '' && !$t.find('.' + ts.css.headerIn).length ) { + // set up header template + t = c.headerTemplate.replace(/\{content\}/g, $t.html()).replace(/\{icon\}/g, $t.find('.' + ts.css.icon).length ? '' : i); + if (c.onRenderTemplate) { + h = c.onRenderTemplate.apply($t, [index, t]); + if (h && typeof h === 'string') { t = h; } // only change t if something is returned + } + $t.html('
    ' + t + '
    '); // faster than wrapInner + } + if (c.onRenderHeader) { c.onRenderHeader.apply($t, [index, c, c.$table]); } + // *** remove this.column value if no conflicts found + elem.column = parseInt( $t.attr('data-column'), 10); + elem.order = formatSortingOrder( ts.getData($t, ch, 'sortInitialOrder') || c.sortInitialOrder ) ? [1,0,2] : [0,1,2]; + elem.count = -1; // set to -1 because clicking on the header automatically adds one + elem.lockedOrder = false; + lock = ts.getData($t, ch, 'lockedOrder') || false; + if (typeof lock !== 'undefined' && lock !== false) { + elem.order = elem.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0]; + } + $t.addClass(ts.css.header + ' ' + c.cssHeader); + // add cell to headerList + c.headerList[index] = elem; + // add to parent in case there are multiple rows + $t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow).attr('role', 'row'); + // allow keyboard cursor to focus on element + if (c.tabIndex) { $t.attr('tabindex', 0); } + return elem; + })); + // cache headers per column + c.$headerIndexed = []; + for (indx = 0; indx < c.columns; indx++) { + $t = c.$headers.filter('[data-column="' + indx + '"]'); + // target sortable column cells, unless there are none, then use non-sortable cells + // .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6 + c.$headerIndexed[indx] = $t.not('.sorter-false').length ? $t.not('.sorter-false').filter(':last') : $t.filter(':last'); + } + $(table).find(c.selectorHeaders).attr({ + scope: 'col', + role : 'columnheader' + }); + // enable/disable sorting + updateHeader(table); + if (c.debug) { + benchmark('Built headers:', time); + log(c.$headers); + } + } + + function commonUpdate(table, resort, callback) { + var c = table.config; + // remove rows/elements before update + c.$table.find(c.selectorRemove).remove(); + // rebuild parsers + buildParserCache(c); + // rebuild the cache map + buildCache(table); + checkResort(c, resort, callback); + } + + function updateHeader(table) { + var index, s, $th, col, + c = table.config, + len = c.$headers.length; + for ( index = 0; index < len; index++ ) { + $th = c.$headers.eq( index ); + col = ts.getColumnData( table, c.headers, index, true ); + // add 'sorter-false' class if 'parser-false' is set + s = ts.getData( $th, col, 'sorter' ) === 'false' || ts.getData( $th, col, 'parser' ) === 'false'; + $th[0].sortDisabled = s; + $th[ s ? 'addClass' : 'removeClass' ]('sorter-false').attr('aria-disabled', '' + s); + // aria-controls - requires table ID + if (table.id) { + if (s) { + $th.removeAttr('aria-controls'); + } else { + $th.attr('aria-controls', table.id); + } + } + } + } + + function setHeadersCss(table) { + var f, h, i, j, $headers, $h, nextSort, txt, + c = table.config, + list = c.sortList, + len = list.length, + none = ts.css.sortNone + ' ' + c.cssNone, + css = [ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc], + cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ], + aria = ['ascending', 'descending'], + // find the footer + $t = $(table).find('tfoot tr').children() + .add( $( c.namespace + '_extra_headers' ) ) + .removeClass( css.join( ' ' ) ); + // remove all header information + c.$headers + .removeClass(css.join(' ')) + .addClass(none).attr('aria-sort', 'none') + .find('.' + ts.css.icon) + .removeClass(cssIcon.join(' ')) + .addClass(cssIcon[2]); + for (i = 0; i < len; i++) { + // direction = 2 means reset! + if (list[i][1] !== 2) { + // multicolumn sorting updating - choose the :last in case there are nested columns + f = c.$headers.not('.sorter-false').filter('[data-column="' + list[i][0] + '"]' + (len === 1 ? ':last' : '') ); + if (f.length) { + for (j = 0; j < f.length; j++) { + if (!f[j].sortDisabled) { + f.eq(j) + .removeClass(none) + .addClass(css[list[i][1]]) + .attr('aria-sort', aria[list[i][1]]) + .find('.' + ts.css.icon) + .removeClass(cssIcon[2]) + .addClass(cssIcon[list[i][1]]); + } + } + // add sorted class to footer & extra headers, if they exist + if ($t.length) { + $t.filter('[data-column="' + list[i][0] + '"]').removeClass(none).addClass(css[list[i][1]]); + } + } + } + } + // add verbose aria labels + len = c.$headers.length; + $headers = c.$headers.not('.sorter-false'); + for ( i = 0; i < len; i++ ) { + $h = $headers.eq( i ); + if ( $h.length ) { + h = $headers[ i ]; + nextSort = h.order[ ( h.count + 1 ) % ( c.sortReset ? 3 : 2 ) ], + txt = $.trim( $h.text() ) + ': ' + + ts.language[ $h.hasClass( ts.css.sortAsc ) ? 'sortAsc' : $h.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone' ] + + ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ]; + $h.attr( 'aria-label', txt ); + } + } + } + + function updateHeaderSortCount( table, list ) { + var col, dir, group, header, indx, primary, temp, val, + c = table.config, + sortList = list || c.sortList, + len = sortList.length; + c.sortList = []; + for (indx = 0; indx < len; indx++) { + val = sortList[indx]; + // ensure all sortList values are numeric - fixes #127 + col = parseInt(val[0], 10); + // prevents error if sorton array is wrong + if ( col < c.columns && c.$headerIndexed[col] ) { + // make sure header exists + header = c.$headerIndexed[col][0]; + // o.count = o.count + 1; + dir = ('' + val[1]).match(/^(1|d|s|o|n)/); + dir = dir ? dir[0] : ''; + // 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext + switch(dir) { + case '1': case 'd': // descending + dir = 1; + break; + case 's': // same direction (as primary column) + // if primary sort is set to 's', make it ascending + dir = primary || 0; + break; + case 'o': + temp = header.order[(primary || 0) % (c.sortReset ? 3 : 2)]; + // opposite of primary column; but resets if primary resets + dir = temp === 0 ? 1 : temp === 1 ? 0 : 2; + break; + case 'n': + header.count = header.count + 1; + dir = header.order[(header.count) % (c.sortReset ? 3 : 2)]; + break; + default: // ascending + dir = 0; + break; + } + primary = indx === 0 ? dir : primary; + group = [ col, parseInt(dir, 10) || 0 ]; + c.sortList.push(group); + dir = $.inArray(group[1], header.order); // fixes issue #167 + header.count = dir >= 0 ? dir : group[1] % (c.sortReset ? 3 : 2); + } + } + } + + function getCachedSortType(parsers, i) { + return (parsers && parsers[i]) ? parsers[i].type || '' : ''; + } + + function initSort(table, cell, event){ + if (table.isUpdating) { + // let any updates complete before initializing a sort + return setTimeout(function(){ initSort(table, cell, event); }, 50); + } + var arry, indx, i, col, order, s, $header, + c = table.config, + key = !event[c.sortMultiSortKey], + $table = c.$table, + len = c.$headers.length; + // Only call sortStart if sorting is enabled + $table.trigger('sortStart', table); + // get current column sort order + cell.count = event[c.sortResetKey] ? 2 : (cell.count + 1) % (c.sortReset ? 3 : 2); + // reset all sorts on non-current column - issue #30 + if (c.sortRestart) { + indx = cell; + for ( i = 0; i < len; i++ ) { + $header = c.$headers.eq( i ); + // only reset counts on columns that weren't just clicked on and if not included in a multisort + if ( $header[0] !== indx && ( key || !$header.is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc) ) ) { + $header[0].count = -1; + } + } + } + // get current column index + indx = parseInt( $(cell).attr('data-column'), 10 ); + // user only wants to sort on one column + if (key) { + // flush the sort list + c.sortList = []; + if (c.sortForce !== null) { + arry = c.sortForce; + for (col = 0; col < arry.length; col++) { + if (arry[col][0] !== indx) { + c.sortList.push(arry[col]); + } + } + } + // add column to sort list + order = cell.order[cell.count]; + if (order < 2) { + c.sortList.push([indx, order]); + // add other columns if header spans across multiple + if (cell.colSpan > 1) { + for (col = 1; col < cell.colSpan; col++) { + c.sortList.push([indx + col, order]); + } + } + } + // multi column sorting + } else { + // get rid of the sortAppend before adding more - fixes issue #115 & #523 + if (c.sortAppend && c.sortList.length > 1) { + for (col = 0; col < c.sortAppend.length; col++) { + s = ts.isValueInArray(c.sortAppend[col][0], c.sortList); + if (s >= 0) { + c.sortList.splice(s,1); + } + } + } + // the user has clicked on an already sorted column + if (ts.isValueInArray(indx, c.sortList) >= 0) { + // reverse the sorting direction + for (col = 0; col < c.sortList.length; col++) { + s = c.sortList[col]; + order = c.$headerIndexed[ s[0] ][0]; + if (s[0] === indx) { + // order.count seems to be incorrect when compared to cell.count + s[1] = order.order[cell.count]; + if (s[1] === 2) { + c.sortList.splice(col,1); + order.count = -1; + } + } + } + } else { + // add column to sort list array + order = cell.order[cell.count]; + if (order < 2) { + c.sortList.push([indx, order]); + // add other columns if header spans across multiple + if (cell.colSpan > 1) { + for (col = 1; col < cell.colSpan; col++) { + c.sortList.push([indx + col, order]); + } + } + } + } + } + if (c.sortAppend !== null) { + arry = c.sortAppend; + for (col = 0; col < arry.length; col++) { + if (arry[col][0] !== indx) { + c.sortList.push(arry[col]); + } + } + } + // sortBegin event triggered immediately before the sort + $table.trigger('sortBegin', table); + // setTimeout needed so the processing icon shows up + setTimeout(function(){ + // set css for headers + setHeadersCss(table); + multisort(table); + appendToTable(table); + $table.trigger('sortEnd', table); + }, 1); + } + + // sort multiple columns + function multisort(table) { /*jshint loopfunc:true */ + var i, k, num, col, sortTime, colMax, + rows, order, sort, x, y, + dir = 0, + c = table.config, + cts = c.textSorter || '', + sortList = c.sortList, + l = sortList.length, + bl = c.$tbodies.length; + if (c.serverSideSorting || isEmptyObject(c.cache)) { // empty table - fixes #206/#346 + return; + } + if (c.debug) { sortTime = new Date(); } + for (k = 0; k < bl; k++) { + colMax = c.cache[k].colMax; + rows = c.cache[k].normalized; + + rows.sort(function(a, b) { + // rows is undefined here in IE, so don't use it! + for (i = 0; i < l; i++) { + col = sortList[i][0]; + order = sortList[i][1]; + // sort direction, true = asc, false = desc + dir = order === 0; + + if (c.sortStable && a[col] === b[col] && l === 1) { + return a[c.columns].order - b[c.columns].order; + } + + // fallback to natural sort since it is more robust + num = /n/i.test(getCachedSortType(c.parsers, col)); + if (num && c.strings[col]) { + // sort strings in numerical columns + if (typeof (c.string[c.strings[col]]) === 'boolean') { + num = (dir ? 1 : -1) * (c.string[c.strings[col]] ? -1 : 1); + } else { + num = (c.strings[col]) ? c.string[c.strings[col]] || 0 : 0; + } + // fall back to built-in numeric sort + // var sort = $.tablesorter['sort' + s]( a[c], b[c], dir, colMax[c], table); + sort = c.numberSorter ? c.numberSorter(a[col], b[col], dir, colMax[col], table) : + ts[ 'sortNumeric' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], num, colMax[col], col, table); + } else { + // set a & b depending on sort direction + x = dir ? a : b; + y = dir ? b : a; + // text sort function + if (typeof(cts) === 'function') { + // custom OVERALL text sorter + sort = cts(x[col], y[col], dir, col, table); + } else if (typeof(cts) === 'object' && cts.hasOwnProperty(col)) { + // custom text sorter for a SPECIFIC COLUMN + sort = cts[col](x[col], y[col], dir, col, table); + } else { + // fall back to natural sort + sort = ts[ 'sortNatural' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], col, table, c); + } + } + if (sort) { return sort; } + } + return a[c.columns].order - b[c.columns].order; + }); + } + if (c.debug) { benchmark('Sorting on ' + sortList.toString() + ' and dir ' + order + ' time', sortTime); } + } + + function resortComplete(c, callback){ + if (c.table.isUpdating) { + c.$table.trigger('updateComplete', c.table); + } + if ($.isFunction(callback)) { + callback(c.table); + } + } + + function checkResort(c, resort, callback) { + var sl = $.isArray(resort) ? resort : c.sortList, + // if no resort parameter is passed, fallback to config.resort (true by default) + resrt = typeof resort === 'undefined' ? c.resort : resort; + // don't try to resort if the table is still processing + // this will catch spamming of the updateCell method + if (resrt !== false && !c.serverSideSorting && !c.table.isProcessing) { + if (sl.length) { + c.$table.trigger('sorton', [sl, function(){ + resortComplete(c, callback); + }, true]); + } else { + c.$table.trigger('sortReset', [function(){ + resortComplete(c, callback); + ts.applyWidget(c.table, false); + }]); + } + } else { + resortComplete(c, callback); + ts.applyWidget(c.table, false); + } + } + + function bindMethods(table){ + var c = table.config, + $table = c.$table, + events = ('sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache ' + + 'updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ').split(' ') + .join(c.namespace + ' '); + // apply easy methods that trigger bound events + $table + .unbind( events.replace(/\s+/g, ' ') ) + .bind('sortReset' + c.namespace, function(e, callback){ + e.stopPropagation(); + c.sortList = []; + setHeadersCss(table); + multisort(table); + appendToTable(table); + if ($.isFunction(callback)) { + callback(table); + } + }) + .bind('updateAll' + c.namespace, function(e, resort, callback){ + e.stopPropagation(); + table.isUpdating = true; + ts.refreshWidgets(table, true, true); + buildHeaders(table); + ts.bindEvents(table, c.$headers, true); + bindMethods(table); + commonUpdate(table, resort, callback); + }) + .bind('update' + c.namespace + ' updateRows' + c.namespace, function(e, resort, callback) { + e.stopPropagation(); + table.isUpdating = true; + // update sorting (if enabled/disabled) + updateHeader(table); + commonUpdate(table, resort, callback); + }) + .bind('updateCell' + c.namespace, function(e, cell, resort, callback) { + e.stopPropagation(); + table.isUpdating = true; + $table.find(c.selectorRemove).remove(); + // get position from the dom + var t, row, icell, cache, + $tb = c.$tbodies, + $cell = $(cell), + // update cache - format: function(s, table, cell, cellIndex) + // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr'); + tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ), + tbcache = c.cache[ tbdy ], + $row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first'); + cell = $cell[0]; // in case cell is a jQuery object + // tbody may not exist if update is initialized while tbody is removed for processing + if ($tb.length && tbdy >= 0) { + row = $tb.eq( tbdy ).find( 'tr' ).index( $row ); + cache = tbcache.normalized[ row ]; + icell = $cell.index(); + t = ts.getParsedText( c, cell, icell ); + cache[ icell ] = t; + cache[ c.columns ].$row = $row; + if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) { + // update column max value (ignore sign) + tbcache.colMax[icell] = Math.max(Math.abs(t) || 0, tbcache.colMax[icell] || 0); + } + t = resort !== 'undefined' ? resort : c.resort; + if (t !== false) { + // widgets will be reapplied + checkResort(c, t, callback); + } else { + // don't reapply widgets is resort is false, just in case it causes + // problems with element focus + if ($.isFunction(callback)) { + callback(table); + } + c.$table.trigger('updateComplete', c.table); + } + } + }) + .bind('addRows' + c.namespace, function(e, $row, resort, callback) { + e.stopPropagation(); + table.isUpdating = true; + if (isEmptyObject(c.cache)) { + // empty table, do an update instead - fixes #450 + updateHeader(table); + commonUpdate(table, resort, callback); + } else { + $row = $($row).attr('role', 'row'); // make sure we're using a jQuery object + var i, j, l, rowData, cells, + rows = $row.filter('tr').length, + tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') ); + // fixes adding rows to an empty table - see issue #179 + if (!(c.parsers && c.parsers.length)) { + buildParserCache(c); + } + // add each row + for (i = 0; i < rows; i++) { + l = $row[i].cells.length; + cells = []; + rowData = { + child: [], + $row : $row.eq(i), + order: c.cache[tbdy].normalized.length + }; + // add each cell + for (j = 0; j < l; j++) { + cells[j] = ts.getParsedText( c, $row[i].cells[j], j ); + if ((c.parsers[j].type || '').toLowerCase() === 'numeric') { + // update column max value (ignore sign) + c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0); + } + } + // add the row data to the end + cells.push(rowData); + // update cache + c.cache[tbdy].normalized.push(cells); + } + // resort using current settings + checkResort(c, resort, callback); + } + }) + .bind('updateComplete' + c.namespace, function(){ + table.isUpdating = false; + }) + .bind('sorton' + c.namespace, function(e, list, callback, init) { + var c = table.config; + e.stopPropagation(); + $table.trigger('sortStart', this); + // update header count index + updateHeaderSortCount(table, list); + // set css for headers + setHeadersCss(table); + // fixes #346 + if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } + $table.trigger('sortBegin', this); + // sort the table and append it to the dom + multisort(table); + appendToTable(table, init); + $table.trigger('sortEnd', this); + ts.applyWidget(table); + if ($.isFunction(callback)) { + callback(table); + } + }) + .bind('appendCache' + c.namespace, function(e, callback, init) { + e.stopPropagation(); + appendToTable(table, init); + if ($.isFunction(callback)) { + callback(table); + } + }) + // $tbodies variable is used by the tbody sorting widget + .bind('updateCache' + c.namespace, function(e, callback, $tbodies){ + // rebuild parsers + if (!(c.parsers && c.parsers.length)) { + buildParserCache(c, $tbodies); + } + // rebuild the cache map + buildCache(table, $tbodies); + if ($.isFunction(callback)) { + callback(table); + } + }) + .bind('applyWidgetId' + c.namespace, function(e, id) { + e.stopPropagation(); + ts.getWidgetById(id).format(table, c, c.widgetOptions); + }) + .bind('applyWidgets' + c.namespace, function(e, init) { + e.stopPropagation(); + // apply widgets + ts.applyWidget(table, init); + }) + .bind('refreshWidgets' + c.namespace, function(e, all, dontapply){ + e.stopPropagation(); + ts.refreshWidgets(table, all, dontapply); + }) + .bind('destroy' + c.namespace, function(e, c, cb){ + e.stopPropagation(); + ts.destroy(table, c, cb); + }) + .bind('resetToLoadState' + c.namespace, function(){ + // remove all widgets + ts.removeWidget(table, true, false); + // restore original settings; this clears out current settings, but does not clear + // values saved to storage. + c = $.extend(true, ts.defaults, c.originalSettings); + table.hasInitialized = false; + // setup the entire table again + ts.setup( table, c ); + }); + } + + /* public methods */ + ts.construct = function(settings) { + return this.each(function() { + var table = this, + // merge & extend config options + c = $.extend(true, {}, ts.defaults, settings, ts.instanceMethods); + // save initial settings + c.originalSettings = settings; + // create a table from data (build table widget) + if (!table.hasInitialized && ts.buildTable && this.nodeName !== 'TABLE') { + // return the table (in case the original target is the table's container) + ts.buildTable(table, c); + } else { + ts.setup(table, c); + } + }); + }; + + ts.setup = function(table, c) { + // if no thead or tbody, or tablesorter is already present, quit + if (!table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true) { + return c.debug ? log('ERROR: stopping initialization! No table, thead, tbody or tablesorter has already been initialized') : ''; + } + + var k = '', + $table = $(table), + m = $.metadata; + // initialization flag + table.hasInitialized = false; + // table is being processed flag + table.isProcessing = true; + // make sure to store the config object + table.config = c; + // save the settings where they read + $.data(table, 'tablesorter', c); + if (c.debug) { $.data( table, 'startoveralltimer', new Date()); } + + // removing this in version 3 (only supports jQuery 1.7+) + c.supportsDataObject = (function(version) { + version[0] = parseInt(version[0], 10); + return (version[0] > 1) || (version[0] === 1 && parseInt(version[1], 10) >= 4); + })($.fn.jquery.split('.')); + // digit sort text location; keeping max+/- for backwards compatibility + c.string = { 'max': 1, 'min': -1, 'emptymin': 1, 'emptymax': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false }; + // ensure case insensitivity + c.emptyTo = c.emptyTo.toLowerCase(); + c.stringTo = c.stringTo.toLowerCase(); + // add table theme class only if there isn't already one there + if (!/tablesorter\-/.test($table.attr('class'))) { + k = (c.theme !== '' ? ' tablesorter-' + c.theme : ''); + } + c.table = table; + c.$table = $table + .addClass(ts.css.table + ' ' + c.tableClass + k) + .attr('role', 'grid'); + c.$headers = $table.find(c.selectorHeaders); + + // give the table a unique id, which will be used in namespace binding + if (!c.namespace) { + c.namespace = '.tablesorter' + Math.random().toString(16).slice(2); + } else { + // make sure namespace starts with a period & doesn't have weird characters + c.namespace = '.' + c.namespace.replace(/\W/g,''); + } + + c.$table.children().children('tr').attr('role', 'row'); + c.$tbodies = $table.children('tbody:not(.' + c.cssInfoBlock + ')').attr({ + 'aria-live' : 'polite', + 'aria-relevant' : 'all' + }); + if (c.$table.children('caption').length) { + k = c.$table.children('caption')[0]; + if (!k.id) { k.id = c.namespace.slice(1) + 'caption'; } + c.$table.attr('aria-labelledby', k.id); + } + c.widgetInit = {}; // keep a list of initialized widgets + // change textExtraction via data-attribute + c.textExtraction = c.$table.attr('data-text-extraction') || c.textExtraction || 'basic'; + // build headers + buildHeaders(table); + // fixate columns if the users supplies the fixedWidth option + // do this after theme has been applied + ts.fixColumnWidth(table); + // add widget options before parsing (e.g. grouping widget has parser settings) + ts.applyWidgetOptions(table, c); + // try to auto detect column type, and store in tables config + buildParserCache(c); + // start total row count at zero + c.totalRows = 0; + // build the cache for the tbody cells + // delayInit will delay building the cache until the user starts a sort + if (!c.delayInit) { buildCache(table); } + // bind all header events and methods + ts.bindEvents(table, c.$headers, true); + bindMethods(table); + // get sort list from jQuery data or metadata + // in jQuery < 1.4, an error occurs when calling $table.data() + if (c.supportsDataObject && typeof $table.data().sortlist !== 'undefined') { + c.sortList = $table.data().sortlist; + } else if (m && ($table.metadata() && $table.metadata().sortlist)) { + c.sortList = $table.metadata().sortlist; + } + // apply widget init code + ts.applyWidget(table, true); + // if user has supplied a sort list to constructor + if (c.sortList.length > 0) { + $table.trigger('sorton', [c.sortList, {}, !c.initWidgets, true]); + } else { + setHeadersCss(table); + if (c.initWidgets) { + // apply widget format + ts.applyWidget(table, false); + } + } + + // show processesing icon + if (c.showProcessing) { + $table + .unbind('sortBegin' + c.namespace + ' sortEnd' + c.namespace) + .bind('sortBegin' + c.namespace + ' sortEnd' + c.namespace, function(e) { + clearTimeout(c.processTimer); + ts.isProcessing(table); + if (e.type === 'sortBegin') { + c.processTimer = setTimeout(function(){ + ts.isProcessing(table, true); + }, 500); + } + }); + } + + // initialized + table.hasInitialized = true; + table.isProcessing = false; + if (c.debug) { + ts.benchmark('Overall initialization time', $.data( table, 'startoveralltimer')); + } + $table.trigger('tablesorter-initialized', table); + if (typeof c.initialized === 'function') { c.initialized(table); } + }; + + // automatically add a colgroup with col elements set to a percentage width + ts.fixColumnWidth = function(table) { + table = $(table)[0]; + var overallWidth, percent, $tbodies, len, index, + c = table.config, + colgroup = c.$table.children('colgroup'); + // remove plugin-added colgroup, in case we need to refresh the widths + if (colgroup.length && colgroup.hasClass(ts.css.colgroup)) { + colgroup.remove(); + } + if (c.widthFixed && c.$table.children('colgroup').length === 0) { + colgroup = $(''); + overallWidth = c.$table.width(); + // only add col for visible columns - fixes #371 + $tbodies = c.$tbodies.find('tr:first').children(':visible'); //.each(function() + len = $tbodies.length; + for ( index = 0; index < len; index++ ) { + percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%'; + colgroup.append( $('').css('width', percent) ); + } + c.$table.prepend(colgroup); + } + }; + + ts.getColumnData = function(table, obj, indx, getCell, $headers){ + if (typeof obj === 'undefined' || obj === null) { return; } + table = $(table)[0]; + var $h, k, + c = table.config, + $cells = ( $headers || c.$headers ), + // c.$headerIndexed is not defined initially + $cell = c.$headerIndexed && c.$headerIndexed[indx] || $cells.filter('[data-column="' + indx + '"]:last'); + if (obj[indx]) { + return getCell ? obj[indx] : obj[$cells.index( $cell )]; + } + for (k in obj) { + if (typeof k === 'string') { + $h = $cell + // header cell with class/id + .filter(k) + // find elements within the header cell with cell/id + .add( $cell.find(k) ); + if ($h.length) { + return obj[k]; + } + } + } + return; + }; + + // computeTableHeaderCellIndexes from: + // http://www.javascripttoolbox.com/lib/table/examples.php + // http://www.javascripttoolbox.com/temp/table_cellindex.html + ts.computeColumnIndex = function(trs) { + var i, j, k, l, $cell, cell, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol, + matrix = [], + matrixrow = [], + lookup = {}; + for (i = 0; i < trs.length; i++) { + cells = trs[i].cells; + for (j = 0; j < cells.length; j++) { + cell = cells[j]; + $cell = $(cell); + rowIndex = cell.parentNode.rowIndex; + cellId = rowIndex + '-' + $cell.index(); + rowSpan = cell.rowSpan || 1; + colSpan = cell.colSpan || 1; + if (typeof(matrix[rowIndex]) === 'undefined') { + matrix[rowIndex] = []; + } + // Find first available column in the first row + for (k = 0; k < matrix[rowIndex].length + 1; k++) { + if (typeof(matrix[rowIndex][k]) === 'undefined') { + firstAvailCol = k; + break; + } + } + lookup[cellId] = firstAvailCol; + // add data-column + $cell.attr({ 'data-column' : firstAvailCol }); // 'data-row' : rowIndex + for (k = rowIndex; k < rowIndex + rowSpan; k++) { + if (typeof(matrix[k]) === 'undefined') { + matrix[k] = []; + } + matrixrow = matrix[k]; + for (l = firstAvailCol; l < firstAvailCol + colSpan; l++) { + matrixrow[l] = 'x'; + } + } + } + } + return matrixrow.length; + }; + + // *** Process table *** + // add processing indicator + ts.isProcessing = function(table, toggle, $ths) { + table = $(table); + var c = table[0].config, + // default to all headers + $h = $ths || table.find('.' + ts.css.header); + if (toggle) { + // don't use sortList if custom $ths used + if (typeof $ths !== 'undefined' && c.sortList.length > 0) { + // get headers from the sortList + $h = $h.filter(function(){ + // get data-column from attr to keep compatibility with jQuery 1.2.6 + return this.sortDisabled ? false : ts.isValueInArray( parseFloat($(this).attr('data-column')), c.sortList) >= 0; + }); + } + table.add($h).addClass(ts.css.processing + ' ' + c.cssProcessing); + } else { + table.add($h).removeClass(ts.css.processing + ' ' + c.cssProcessing); + } + }; + + // detach tbody but save the position + // don't use tbody because there are portions that look for a tbody index (updateCell) + ts.processTbody = function(table, $tb, getIt){ + table = $(table)[0]; + var holdr; + if (getIt) { + table.isProcessing = true; + $tb.before(''); + holdr = ($.fn.detach) ? $tb.detach() : $tb.remove(); + return holdr; + } + holdr = $(table).find('span.tablesorter-savemyplace'); + $tb.insertAfter( holdr ); + holdr.remove(); + table.isProcessing = false; + }; + + ts.clearTableBody = function(table) { + $(table)[0].config.$tbodies.children().detach(); + }; + + ts.bindEvents = function(table, $headers, core) { + table = $(table)[0]; + var t, downTarget = null, + c = table.config; + if (core !== true) { + $headers.addClass( c.namespace.slice(1) + '_extra_headers' ); + t = $.fn.closest ? $headers.closest('table')[0] : $headers.parents('table')[0]; + if (t && t.nodeName === 'TABLE' && t !== table) { + $(t).addClass( c.namespace.slice(1) + '_extra_table' ); + } + } + t = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' ) + .replace(/\s+/g, ' ') + .split(' ') + .join(c.namespace + ' '); + // apply event handling to headers and/or additional headers (stickyheaders, scroller, etc) + $headers + // http://stackoverflow.com/questions/5312849/jquery-find-self; + .find(c.selectorSort).add( $headers.filter(c.selectorSort) ) + .unbind(t) + .bind(t, function(e, external) { + var cell, temp, + $target = $(e.target), + // wrap event type in spaces, so the match doesn't trigger on inner words + type = ' ' + e.type + ' '; + // only recognize left clicks + if ( ( ( e.which || e.button ) !== 1 && !type.match( ' ' + c.pointerClick + ' | sort | keyup ' ) ) || + // allow pressing enter + ( type === ' keyup ' && e.which !== 13 ) || + // allow triggering a click event (e.which is undefined) & ignore physical clicks + ( type.match(' ' + c.pointerClick + ' ') && typeof e.which !== 'undefined' ) ) { + return; + } + // ignore mouseup if mousedown wasn't on the same target + if ( type.match(' ' + c.pointerUp + ' ') && downTarget !== e.target && external !== true ) { return; } + // set target on mousedown + if ( type.match(' ' + c.pointerDown + ' ') ) { + downTarget = e.target; + // preventDefault needed or jQuery v1.3.2 and older throws an + // "Uncaught TypeError: handler.apply is not a function" error + temp = $target.jquery.split( '.' ); + if ( temp[0] === '1' && temp[1] < 4 ) { e.preventDefault(); } + return; + } + downTarget = null; + // prevent sort being triggered on form elements + if ( /(input|select|button|textarea)/i.test(e.target.nodeName) || + // nosort class name, or elements within a nosort container + $target.hasClass(c.cssNoSort) || $target.parents('.' + c.cssNoSort).length > 0 || + // elements within a button + $target.parents('button').length > 0 ) { + return !c.cancelSelection; + } + if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } + // jQuery v1.2.6 doesn't have closest() + cell = $.fn.closest ? $(this).closest('th, td')[0] : /TH|TD/.test(this.nodeName) ? this : $(this).parents('th, td')[0]; + // reference original table headers and find the same cell + cell = c.$headers[ $headers.index( cell ) ]; + if (!cell.sortDisabled) { + initSort(table, cell, e); + } + }); + if (c.cancelSelection) { + // cancel selection + $headers + .attr('unselectable', 'on') + .bind('selectstart', false) + .css({ + 'user-select': 'none', + 'MozUserSelect': 'none' // not needed for jQuery 1.8+ + }); + } + }; + + // restore headers + ts.restoreHeaders = function(table){ + var index, $cell, + c = $(table)[0].config, + $headers = c.$table.find( c.selectorHeaders ), + len = $headers.length; + // don't use c.$headers here in case header cells were swapped + for ( index = 0; index < len; index++ ) { + // c.$table.find(c.selectorHeaders).each(function(i){ + $cell = $headers.eq( index ); + // only restore header cells if it is wrapped + // because this is also used by the updateAll method + if ( $cell.find( '.' + ts.css.headerIn ).length ) { + $cell.html( c.headerContent[ index ] ); + } + } + }; + + ts.destroy = function(table, removeClasses, callback){ + table = $(table)[0]; + if (!table.hasInitialized) { return; } + // remove all widgets + ts.removeWidget(table, true, false); + var events, + $t = $(table), + c = table.config, + $h = $t.find('thead:first'), + $r = $h.find('tr.' + ts.css.headerRow).removeClass(ts.css.headerRow + ' ' + c.cssHeaderRow), + $f = $t.find('tfoot:first > tr').children('th, td'); + if (removeClasses === false && $.inArray('uitheme', c.widgets) >= 0) { + // reapply uitheme classes, in case we want to maintain appearance + $t.trigger('applyWidgetId', ['uitheme']); + $t.trigger('applyWidgetId', ['zebra']); + } + // remove widget added rows, just in case + $h.find('tr').not($r).remove(); + // disable tablesorter + events = 'sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache ' + + 'applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState '.split(' ') + .join(c.namespace + ' '); + $t + .removeData('tablesorter') + .unbind( events.replace(/\s+/g, ' ') ); + c.$headers.add($f) + .removeClass( [ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone].join(' ') ) + .removeAttr('data-column') + .removeAttr('aria-label') + .attr('aria-disabled', 'true'); + $r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(/\s+/g, ' ') ); + ts.restoreHeaders(table); + $t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false); + // clear flag in case the plugin is initialized again + table.hasInitialized = false; + delete table.config.cache; + if (typeof callback === 'function') { + callback(table); + } + }; + + // *** sort functions *** + // regex used in natural sort + ts.regex = { + chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters + chunks: /(^\\0|\\0$)/, // replace chunks @ ends + hex: /^0x[0-9a-f]+$/i // hex + }; + + // Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed) + // this function will only accept strings, or you'll see 'TypeError: undefined is not a function' + // I could add a = a.toString(); b = b.toString(); but it'll slow down the sort overall + ts.sortNatural = function(a, b) { + if (a === b) { return 0; } + var xN, xD, yN, yD, xF, yF, i, mx, + r = ts.regex; + // first try and sort Hex codes + if (r.hex.test(b)) { + xD = parseInt(a.match(r.hex), 16); + yD = parseInt(b.match(r.hex), 16); + if ( xD < yD ) { return -1; } + if ( xD > yD ) { return 1; } + } + // chunk/tokenize + xN = a.replace(r.chunk, '\\0$1\\0').replace(r.chunks, '').split('\\0'); + yN = b.replace(r.chunk, '\\0$1\\0').replace(r.chunks, '').split('\\0'); + mx = Math.max(xN.length, yN.length); + // natural sorting through split numeric strings and default strings + for (i = 0; i < mx; i++) { + // find floats not starting with '0', string or 0 if not defined + xF = isNaN(xN[i]) ? xN[i] || 0 : parseFloat(xN[i]) || 0; + yF = isNaN(yN[i]) ? yN[i] || 0 : parseFloat(yN[i]) || 0; + // handle numeric vs string comparison - number < string - (Kyle Adams) + if (isNaN(xF) !== isNaN(yF)) { return (isNaN(xF)) ? 1 : -1; } + // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' + if (typeof xF !== typeof yF) { + xF += ''; + yF += ''; + } + if (xF < yF) { return -1; } + if (xF > yF) { return 1; } + } + return 0; + }; + + ts.sortNaturalAsc = function(a, b, col, table, c) { + if (a === b) { return 0; } + var e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + return ts.sortNatural(a, b); + }; + + ts.sortNaturalDesc = function(a, b, col, table, c) { + if (a === b) { return 0; } + var e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + return ts.sortNatural(b, a); + }; + + // basic alphabetical sort + ts.sortText = function(a, b) { + return a > b ? 1 : (a < b ? -1 : 0); + }; + + // return text string value by adding up ascii value + // so the text is somewhat sorted when using a digital sort + // this is NOT an alphanumeric sort + ts.getTextValue = function(a, num, mx) { + if (mx) { + // make sure the text value is greater than the max numerical value (mx) + var i, l = a ? a.length : 0, n = mx + num; + for (i = 0; i < l; i++) { + n += a.charCodeAt(i); + } + return num * n; + } + return 0; + }; + + ts.sortNumericAsc = function(a, b, num, mx, col, table) { + if (a === b) { return 0; } + var c = table.config, + e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } + if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } + return a - b; + }; + + ts.sortNumericDesc = function(a, b, num, mx, col, table) { + if (a === b) { return 0; } + var c = table.config, + e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } + if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } + return b - a; + }; + + ts.sortNumeric = function(a, b) { + return a - b; + }; + + // used when replacing accented characters during sorting + ts.characterEquivalents = { + 'a' : '\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5', // áàâãäąå + 'A' : '\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5', // ÁÀÂÃÄĄÅ + 'c' : '\u00e7\u0107\u010d', // çćč + 'C' : '\u00c7\u0106\u010c', // ÇĆČ + 'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę + 'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ + 'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı + 'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ + 'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō + 'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ + 'ss': '\u00df', // ß (s sharp) + 'SS': '\u1e9e', // ẞ (Capital sharp s) + 'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů + 'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ + }; + ts.replaceAccents = function(s) { + var a, acc = '[', eq = ts.characterEquivalents; + if (!ts.characterRegex) { + ts.characterRegexArray = {}; + for (a in eq) { + if (typeof a === 'string') { + acc += eq[a]; + ts.characterRegexArray[a] = new RegExp('[' + eq[a] + ']', 'g'); + } + } + ts.characterRegex = new RegExp(acc + ']'); + } + if (ts.characterRegex.test(s)) { + for (a in eq) { + if (typeof a === 'string') { + s = s.replace( ts.characterRegexArray[a], a ); + } + } + } + return s; + }; + + // *** utilities *** + ts.isValueInArray = function(column, arry) { + var indx, len = arry.length; + for (indx = 0; indx < len; indx++) { + if (arry[indx][0] === column) { + return indx; + } + } + return -1; + }; + + ts.addParser = function(parser) { + var i, l = ts.parsers.length, a = true; + for (i = 0; i < l; i++) { + if (ts.parsers[i].id.toLowerCase() === parser.id.toLowerCase()) { + a = false; + } + } + if (a) { + ts.parsers.push(parser); + } + }; + + // Use it to add a set of methods to table.config which will be available for all tables. + // This should be done before table initialization + ts.addInstanceMethods = function(methods) { + $.extend(ts.instanceMethods, methods); + }; + + ts.getParserById = function(name) { + /*jshint eqeqeq:false */ + if (name == 'false') { return false; } + var i, l = ts.parsers.length; + for (i = 0; i < l; i++) { + if (ts.parsers[i].id.toLowerCase() === (name.toString()).toLowerCase()) { + return ts.parsers[i]; + } + } + return false; + }; + + ts.addWidget = function(widget) { + ts.widgets.push(widget); + }; + + ts.hasWidget = function(table, name){ + table = $(table); + return table.length && table[0].config && table[0].config.widgetInit[name] || false; + }; + + ts.getWidgetById = function(name) { + var i, w, l = ts.widgets.length; + for (i = 0; i < l; i++) { + w = ts.widgets[i]; + if (w && w.hasOwnProperty('id') && w.id.toLowerCase() === name.toLowerCase()) { + return w; + } + } + }; + + ts.applyWidgetOptions = function( table, c ){ + var indx, widget, + len = c.widgets.length, + wo = c.widgetOptions; + if (len) { + for (indx = 0; indx < len; indx++) { + widget = ts.getWidgetById( c.widgets[indx] ); + if ( widget && 'options' in widget ) { + wo = table.config.widgetOptions = $.extend( true, {}, widget.options, wo ); + } + } + } + }; + + ts.applyWidget = function(table, init, callback) { + table = $(table)[0]; // in case this is called externally + var indx, len, name, + c = table.config, + wo = c.widgetOptions, + tableClass = ' ' + c.table.className + ' ', + widgets = [], + time, time2, w, wd; + // prevent numerous consecutive widget applications + if (init !== false && table.hasInitialized && (table.isApplyingWidgets || table.isUpdating)) { return; } + if (c.debug) { time = new Date(); } + // look for widgets to apply from in table class + // stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget + wd = new RegExp( '\\s' + c.widgetClass.replace( /\{name\}/i, '([\\w-]+)' )+ '\\s', 'g' ); + if ( tableClass.match( wd ) ) { + // extract out the widget id from the table class (widget id's can include dashes) + w = tableClass.match( wd ); + if ( w ) { + len = w.length; + for (indx = 0; indx < len; indx++) { + c.widgets.push( w[indx].replace( wd, '$1' ) ); + } + } + } + if (c.widgets.length) { + table.isApplyingWidgets = true; + // ensure unique widget ids + c.widgets = $.grep(c.widgets, function(v, k){ + return $.inArray(v, c.widgets) === k; + }); + name = c.widgets || []; + len = name.length; + // build widget array & add priority as needed + for (indx = 0; indx < len; indx++) { + wd = ts.getWidgetById(name[indx]); + if (wd && wd.id) { + // set priority to 10 if not defined + if (!wd.priority) { wd.priority = 10; } + widgets[indx] = wd; + } + } + // sort widgets by priority + widgets.sort(function(a, b){ + return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1; + }); + // add/update selected widgets + len = widgets.length; + for (indx = 0; indx < len; indx++) { + if (widgets[indx]) { + if ( init || !( c.widgetInit[ widgets[indx].id ] ) ) { + // set init flag first to prevent calling init more than once (e.g. pager) + c.widgetInit[ widgets[indx].id ] = true; + if (table.hasInitialized) { + // don't reapply widget options on tablesorter init + ts.applyWidgetOptions( table, c ); + } + if ( 'init' in widgets[indx] ) { + if (c.debug) { time2 = new Date(); } + widgets[indx].init(table, widgets[indx], c, wo); + if (c.debug) { ts.benchmark('Initializing ' + widgets[indx].id + ' widget', time2); } + } + } + if ( !init && 'format' in widgets[indx] ) { + if (c.debug) { time2 = new Date(); } + widgets[indx].format(table, c, wo, false); + if (c.debug) { ts.benchmark( ( init ? 'Initializing ' : 'Applying ' ) + widgets[indx].id + ' widget', time2); } + } + } + } + // callback executed on init only + if (!init && typeof callback === 'function') { + callback(table); + } + } + setTimeout(function(){ + table.isApplyingWidgets = false; + $.data(table, 'lastWidgetApplication', new Date()); + }, 0); + if (c.debug) { + w = c.widgets.length; + benchmark('Completed ' + (init === true ? 'initializing ' : 'applying ') + w + ' widget' + (w !== 1 ? 's' : ''), time); + } + }; + + ts.removeWidget = function(table, name, refreshing){ + table = $(table)[0]; + var i, widget, indx, len, + c = table.config; + // if name === true, add all widgets from $.tablesorter.widgets + if (name === true) { + name = []; + len = ts.widgets.length; + for (indx = 0; indx < len; indx++) { + widget = ts.widgets[indx]; + if (widget && widget.id) { + name.push( widget.id ); + } + } + } else { + // name can be either an array of widgets names, + // or a space/comma separated list of widget names + name = ( $.isArray(name) ? name.join(',') : name || '' ).toLowerCase().split( /[\s,]+/ ); + } + len = name.length; + for (i = 0; i < len; i++) { + widget = ts.getWidgetById(name[i]); + indx = $.inArray( name[i], c.widgets ); + if ( widget && 'remove' in widget ) { + if (c.debug && indx >= 0) { log( 'Removing "' + name[i] + '" widget' ); } + widget.remove(table, c, c.widgetOptions, refreshing); + c.widgetInit[ name[i] ] = false; + } + // don't remove the widget from config.widget if refreshing + if (indx >= 0 && refreshing !== true) { + c.widgets.splice( indx, 1 ); + } + } + }; + + ts.refreshWidgets = function(table, doAll, dontapply) { + table = $(table)[0]; // see issue #243 + var indx, + c = table.config, + cw = c.widgets, + widgets = ts.widgets, + len = widgets.length, + list = [], + callback = function(table){ + $(table).trigger('refreshComplete'); + }; + // remove widgets not defined in config.widgets, unless doAll is true + for (indx = 0; indx < len; indx++) { + if (widgets[indx] && widgets[indx].id && (doAll || $.inArray( widgets[indx].id, cw ) < 0)) { + list.push( widgets[indx].id ); + } + } + ts.removeWidget( table, list.join(','), true ); + if (dontapply !== true) { + // call widget init if + ts.applyWidget(table, doAll || false, callback ); + if (doAll) { + // apply widget format + ts.applyWidget(table, false, callback); + } + } else { + callback(table); + } + }; + + ts.getColumnText = function( table, column, callback ) { + table = $( table )[0]; + var tbodyIndex, rowIndex, cache, row, tbodyLen, rowLen, raw, parsed, $cell, result, + hasCallback = typeof callback === 'function', + allColumns = column === 'all', + data = { raw : [], parsed: [], $cell: [] }, + c = table.config; + if ( !isEmptyObject( c ) ) { + tbodyLen = c.$tbodies.length; + for ( tbodyIndex = 0; tbodyIndex < tbodyLen; tbodyIndex++ ) { + cache = c.cache[ tbodyIndex ].normalized; + rowLen = cache.length; + for ( rowIndex = 0; rowIndex < rowLen; rowIndex++ ) { + result = true; + row = cache[ rowIndex ]; + parsed = ( allColumns ) ? row.slice(0, c.columns) : row[ column ]; + row = row[ c.columns ]; + raw = ( allColumns ) ? row.raw : row.raw[ column ]; + $cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column ); + if ( hasCallback ) { + result = callback({ + tbodyIndex: tbodyIndex, + rowIndex: rowIndex, + parsed: parsed, + raw: raw, + $row: row.$row, + $cell: $cell + }); + } + if ( result !== false ) { + data.parsed.push( parsed ); + data.raw.push( raw ); + data.$cell.push( $cell ); + } + } + } + // return everything + return data; + } + }; + + // get sorter, string, empty, etc options for each column from + // jQuery data, metadata, header option or header class name ('sorter-false') + // priority = jQuery data > meta > headers option > header class name + ts.getData = function(h, ch, key) { + var val = '', $h = $(h), m, cl; + if (!$h.length) { return ''; } + m = $.metadata ? $h.metadata() : false; + cl = ' ' + ($h.attr('class') || ''); + if (typeof $h.data(key) !== 'undefined' || typeof $h.data(key.toLowerCase()) !== 'undefined'){ + // 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder' + // 'data-sort-initial-order' is assigned to 'sortInitialOrder' + val += $h.data(key) || $h.data(key.toLowerCase()); + } else if (m && typeof m[key] !== 'undefined') { + val += m[key]; + } else if (ch && typeof ch[key] !== 'undefined') { + val += ch[key]; + } else if (cl !== ' ' && cl.match(' ' + key + '-')) { + // include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser' + val = cl.match( new RegExp('\\s' + key + '-([\\w-]+)') )[1] || ''; + } + return $.trim(val); + }; + + ts.formatFloat = function(s, table) { + if (typeof s !== 'string' || s === '') { return s; } + // allow using formatFloat without a table; defaults to US number format + var i, + t = table && table.config ? table.config.usNumberFormat !== false : + typeof table !== 'undefined' ? table : true; + if (t) { + // US Format - 1,234,567.89 -> 1234567.89 + s = s.replace(/,/g,''); + } else { + // German Format = 1.234.567,89 -> 1234567.89 + // French Format = 1 234 567,89 -> 1234567.89 + s = s.replace(/[\s|\.]/g,'').replace(/,/g,'.'); + } + if(/^\s*\([.\d]+\)/.test(s)) { + // make (#) into a negative number -> (10) = -10 + s = s.replace(/^\s*\(([.\d]+)\)/, '-$1'); + } + i = parseFloat(s); + // return the text instead of zero + return isNaN(i) ? $.trim(s) : i; + }; + + ts.isDigit = function(s) { + // replace all unwanted chars and match + return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : s !== ''; + }; + + }() + }); + + // make shortcut + var ts = $.tablesorter; + + // extend plugin scope + $.fn.extend({ + tablesorter: ts.construct + }); + + // add default parsers + ts.addParser({ + id: 'no-parser', + is: function() { + return false; + }, + format: function() { + return ''; + }, + type: 'text' + }); + + ts.addParser({ + id: 'text', + is: function() { + return true; + }, + format: function(s, table) { + var c = table.config; + if (s) { + s = $.trim( c.ignoreCase ? s.toLocaleLowerCase() : s ); + s = c.sortLocaleCompare ? ts.replaceAccents(s) : s; + } + return s; + }, + type: 'text' + }); + + ts.addParser({ + id: 'digit', + is: function(s) { + return ts.isDigit(s); + }, + format: function(s, table) { + var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table); + return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'currency', + is: function(s) { + return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test((s || '').replace(/[+\-,. ]/g,'')); // £$€¤¥¢ + }, + format: function(s, table) { + var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table); + return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'url', + is: function(s) { + return (/^(https?|ftp|file):\/\//).test(s); + }, + format: function(s) { + return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s; + }, + parsed : true, // filter widget flag + type: 'text' + }); + + ts.addParser({ + id: 'isoDate', + is: function(s) { + return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s); + }, + format: function(s, table) { + var date = s ? new Date( s.replace(/-/g, '/') ) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'percent', + is: function(s) { + return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15; + }, + format: function(s, table) { + return s ? ts.formatFloat(s.replace(/%/g, ''), table) : s; + }, + type: 'numeric' + }); + + // added image parser to core v2.17.9 + ts.addParser({ + id: 'image', + is: function(s, table, node, $node){ + return $node.find('img').length > 0; + }, + format: function(s, table, cell) { + return $(cell).find('img').attr(table.config.imgAttr || 'alt') || s; + }, + parsed : true, // filter widget flag + type: 'text' + }); + + ts.addParser({ + id: 'usLongDate', + is: function(s) { + // two digit years are not allowed cross-browser + // Jan 01, 2013 12:34:56 PM or 01 Jan 2013 + return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) || (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s); + }, + format: function(s, table) { + var date = s ? new Date( s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd' + is: function(s) { + // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included + return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test((s || '').replace(/\s+/g,' ').replace(/[\-.,]/g, '/')); + }, + format: function(s, table, cell, cellIndex) { + if (s) { + var date, d, + c = table.config, + ci = c.$headerIndexed[ cellIndex ], + format = ci.length && ci[0].dateFormat || ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') || c.dateFormat; + d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/'); // escaped - because JSHint in Firefox was showing it as an error + if (format === 'mmddyyyy') { + d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$1/$2'); + } else if (format === 'ddmmyyyy') { + d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$2/$1'); + } else if (format === 'yyyymmdd') { + d = d.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, '$1/$2/$3'); + } + date = new Date(d); + return date instanceof Date && isFinite(date) ? date.getTime() : s; + } + return s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'time', + is: function(s) { + return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s); + }, + format: function(s, table) { + var date = s ? new Date( '2000/01/01 ' + s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'metadata', + is: function() { + return false; + }, + format: function(s, table, cell) { + var c = table.config, + p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; + return $(cell).metadata()[p]; + }, + type: 'numeric' + }); + + // add default widgets + ts.addWidget({ + id: 'zebra', + priority: 90, + format: function(table, c, wo) { + var $tv, $tr, row, even, time, k, i, len, + child = new RegExp(c.cssChildRow, 'i'), + b = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) ); + if (c.debug) { + time = new Date(); + } + for (k = 0; k < b.length; k++ ) { + // loop through the visible rows + row = 0; + $tv = b.eq( k ).children( 'tr:visible' ).not( c.selectorRemove ); + len = $tv.length; + for ( i = 0; i < len; i++ ) { + $tr = $tv.eq( i ); + // style child rows the same way the parent row was styled + if ( !child.test( $tr[0].className ) ) { row++; } + even = ( row % 2 === 0 ); + $tr + .removeClass( wo.zebra[ even ? 1 : 0 ] ) + .addClass( wo.zebra[ even ? 0 : 1 ] ); + } + } + }, + remove: function(table, c, wo, refreshing){ + if (refreshing) { return; } + var k, $tb, + b = c.$tbodies, + rmv = (wo.zebra || [ 'even', 'odd' ]).join(' '); + for (k = 0; k < b.length; k++ ){ + $tb = ts.processTbody(table, b.eq(k), true); // remove tbody + $tb.children().removeClass(rmv); + ts.processTbody(table, $tb, false); // restore tbody + } + } + }); + +})(jQuery); + +/*! Widget: storage - updated 3/26/2015 (v2.21.3) */ +;(function ($, window, document) { +'use strict'; + +var ts = $.tablesorter || {}; +// *** Store data in local storage, with a cookie fallback *** +/* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json) + if you need it, then include https://github.com/douglascrockford/JSON-js + + $.parseJSON is not available is jQuery versions older than 1.4.1, using older + versions will only allow storing information for one page at a time + + // *** Save data (JSON format only) *** + // val must be valid JSON... use http://jsonlint.com/ to ensure it is valid + var val = { "mywidget" : "data1" }; // valid JSON uses double quotes + // $.tablesorter.storage(table, key, val); + $.tablesorter.storage(table, 'tablesorter-mywidget', val); + + // *** Get data: $.tablesorter.storage(table, key); *** + v = $.tablesorter.storage(table, 'tablesorter-mywidget'); + // val may be empty, so also check for your data + val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : ''; + alert(val); // "data1" if saved, or "" if not +*/ +ts.storage = function(table, key, value, options) { + table = $(table)[0]; + var cookieIndex, cookies, date, + hasStorage = false, + values = {}, + c = table.config, + wo = c && c.widgetOptions, + storageType = ( options && options.useSessionStorage ) || ( wo && wo.storage_useSessionStorage ) ? + 'sessionStorage' : 'localStorage', + $table = $(table), + // id from (1) options ID, (2) table "data-table-group" attribute, (3) widgetOptions.storage_tableId, + // (4) table ID, then (5) table index + id = options && options.id || + $table.attr( options && options.group || wo && wo.storage_group || 'data-table-group') || + wo && wo.storage_tableId || table.id || $('.tablesorter').index( $table ), + // url from (1) options url, (2) table "data-table-page" attribute, (3) widgetOptions.storage_fixedUrl, + // (4) table.config.fixedUrl (deprecated), then (5) window location path + url = options && options.url || + $table.attr(options && options.page || wo && wo.storage_page || 'data-table-page') || + wo && wo.storage_fixedUrl || c && c.fixedUrl || window.location.pathname; + // https://gist.github.com/paulirish/5558557 + if (storageType in window) { + try { + window[storageType].setItem('_tmptest', 'temp'); + hasStorage = true; + window[storageType].removeItem('_tmptest'); + } catch(error) { + if (c && c.debug) { + ts.log( storageType + ' is not supported in this browser' ); + } + } + } + // *** get value *** + if ($.parseJSON) { + if (hasStorage) { + values = $.parseJSON( window[storageType][key] || 'null' ) || {}; + } else { + // old browser, using cookies + cookies = document.cookie.split(/[;\s|=]/); + // add one to get from the key to the value + cookieIndex = $.inArray(key, cookies) + 1; + values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {}; + } + } + // allow value to be an empty string too + if ((value || value === '') && window.JSON && JSON.hasOwnProperty('stringify')) { + // add unique identifiers = url pathname > table ID/index on page > data + if (!values[url]) { + values[url] = {}; + } + values[url][id] = value; + // *** set value *** + if (hasStorage) { + window[storageType][key] = JSON.stringify(values); + } else { + date = new Date(); + date.setTime(date.getTime() + (31536e+6)); // 365 days + document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g,'\"') + '; expires=' + date.toGMTString() + '; path=/'; + } + } else { + return values && values[url] ? values[url][id] : ''; + } +}; + +})(jQuery, window, document); + +/*! Widget: uitheme - updated 3/26/2015 (v2.21.3) */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +ts.themes = { + 'bootstrap' : { + table : 'table table-bordered table-striped', + caption : 'caption', + // header class names + header : 'bootstrap-header', // give the header a gradient background (theme.bootstrap_2.css) + sortNone : '', + sortAsc : '', + sortDesc : '', + active : '', // applied when column is sorted + hover : '', // custom css required - a defined bootstrap style may not override other classes + // icon class names + icons : '', // add "icon-white" to make them white; this icon class is added to the in the header + iconSortNone : 'bootstrap-icon-unsorted', // class name added to icon when column is not sorted + iconSortAsc : 'icon-chevron-up glyphicon glyphicon-chevron-up', // class name added to icon when column has ascending sort + iconSortDesc : 'icon-chevron-down glyphicon glyphicon-chevron-down', // class name added to icon when column has descending sort + filterRow : '', // filter row class + footerRow : '', + footerCells : '', + even : '', // even row zebra striping + odd : '' // odd row zebra striping + }, + 'jui' : { + table : 'ui-widget ui-widget-content ui-corner-all', // table classes + caption : 'ui-widget-content', + // header class names + header : 'ui-widget-header ui-corner-all ui-state-default', // header classes + sortNone : '', + sortAsc : '', + sortDesc : '', + active : 'ui-state-active', // applied when column is sorted + hover : 'ui-state-hover', // hover class + // icon class names + icons : 'ui-icon', // icon class added to the in the header + iconSortNone : 'ui-icon-carat-2-n-s', // class name added to icon when column is not sorted + iconSortAsc : 'ui-icon-carat-1-n', // class name added to icon when column has ascending sort + iconSortDesc : 'ui-icon-carat-1-s', // class name added to icon when column has descending sort + filterRow : '', + footerRow : '', + footerCells : '', + even : 'ui-widget-content', // even row zebra striping + odd : 'ui-state-default' // odd row zebra striping + } +}; + +$.extend(ts.css, { + wrapper : 'tablesorter-wrapper' // ui theme & resizable +}); + +ts.addWidget({ + id: "uitheme", + priority: 10, + format: function(table, c, wo) { + var i, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme, + themesAll = ts.themes, + $table = c.$table.add( $( c.namespace + '_extra_table' ) ), + $headers = c.$headers.add( $( c.namespace + '_extra_headers' ) ), + theme = c.theme || 'jui', + themes = themesAll[theme] || {}, + remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ), + iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) ); + if (c.debug) { time = new Date(); } + // initialization code - run once + if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) { + wo.uitheme_applied = true; + oldtheme = themesAll[c.appliedTheme] || {}; + hasOldTheme = !$.isEmptyObject(oldtheme); + oldremove = hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : ''; + oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : ''; + if (hasOldTheme) { + wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') ); + wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') ); + c.$tbodies.children().removeClass( [oldtheme.even, oldtheme.odd].join(' ') ); + } + // update zebra stripes + if (themes.even) { wo.zebra[0] += ' ' + themes.even; } + if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; } + // add caption style + $table.children('caption') + .removeClass(oldtheme.caption || '') + .addClass(themes.caption); + // add table/footer class names + $tfoot = $table + // remove other selected themes + .removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') ) + .addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name + .children('tfoot'); + c.appliedTheme = c.theme; + + if ($tfoot.length) { + $tfoot + // if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed + .children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow) + .children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells); + } + // update header classes + $headers + .removeClass( (hasOldTheme ? [oldtheme.header, oldtheme.hover, oldremove].join(' ') : '') || '' ) + .addClass(themes.header) + .not('.sorter-false') + .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') + .bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) { + // toggleClass with switch added in jQuery 1.3 + $(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || ''); + }); + + $headers.each(function(){ + var $this = $(this); + if (!$this.find('.' + ts.css.wrapper).length) { + // Firefox needs this inner div to position the icon & resizer correctly + $this.wrapInner('
    '); + } + }); + if (c.cssIcon) { + // if c.cssIcon is '', then no is added to the header + $headers + .find('.' + ts.css.icon) + .removeClass(hasOldTheme ? [oldtheme.icons, oldIconRmv].join(' ') : '') + .addClass(themes.icons || ''); + } + if ($table.hasClass('hasFilters')) { + $table.children('thead').children('.' + ts.css.filterRow) + .removeClass(hasOldTheme ? oldtheme.filterRow || '' : '') + .addClass(themes.filterRow || ''); + } + } + for (i = 0; i < c.columns; i++) { + $header = c.$headers + .add($(c.namespace + '_extra_headers')) + .not('.sorter-false') + .filter('[data-column="' + i + '"]'); + $icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $(); + $h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last'); + if ($h.length) { + $header.removeClass(remove); + $icon.removeClass(iconRmv); + if ($h[0].sortDisabled) { + // no sort arrows for disabled columns! + $icon.removeClass(themes.icons || ''); + } else { + hdr = themes.sortNone; + icon = themes.iconSortNone; + if ($h.hasClass(ts.css.sortAsc)) { + hdr = [themes.sortAsc, themes.active].join(' '); + icon = themes.iconSortAsc; + } else if ($h.hasClass(ts.css.sortDesc)) { + hdr = [themes.sortDesc, themes.active].join(' '); + icon = themes.iconSortDesc; + } + $header.addClass(hdr); + $icon.addClass(icon || ''); + } + } + } + if (c.debug) { + ts.benchmark("Applying " + theme + " theme", time); + } + }, + remove: function(table, c, wo, refreshing) { + if (!wo.uitheme_applied) { return; } + var $table = c.$table, + theme = c.appliedTheme || 'jui', + themes = ts.themes[ theme ] || ts.themes.jui, + $headers = $table.children('thead').children(), + remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc, + iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc; + $table.removeClass('tablesorter-' + theme + ' ' + themes.table); + wo.uitheme_applied = false; + if (refreshing) { return; } + $table.find(ts.css.header).removeClass(themes.header); + $headers + .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover + .removeClass(themes.hover + ' ' + remove + ' ' + themes.active) + .filter('.' + ts.css.filterRow) + .removeClass(themes.filterRow); + $headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv); + } +}); + +})(jQuery); + +/*! Widget: columns */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +ts.addWidget({ + id: "columns", + priority: 30, + options : { + columns : [ "primary", "secondary", "tertiary" ] + }, + format: function(table, c, wo) { + var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx, + $table = c.$table, + $tbodies = c.$tbodies, + sortList = c.sortList, + len = sortList.length, + // removed c.widgetColumns support + css = wo && wo.columns || [ "primary", "secondary", "tertiary" ], + last = css.length - 1; + remove = css.join(' '); + // check if there is a sort (on initialization there may not be one) + for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody + $rows = $tbody.children('tr'); + // loop through the visible rows + $rows.each(function() { + $row = $(this); + if (this.style.display !== 'none') { + // remove all columns class names + $cells = $row.children().removeClass(remove); + // add appropriate column class names + if (sortList && sortList[0]) { + // primary sort column class + $cells.eq(sortList[0][0]).addClass(css[0]); + if (len > 1) { + for (indx = 1; indx < len; indx++) { + // secondary, tertiary, etc sort column classes + $cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] ); + } + } + } + } + }); + ts.processTbody(table, $tbody, false); + } + // add classes to thead and tfoot + rows = wo.columns_thead !== false ? ['thead tr'] : []; + if (wo.columns_tfoot !== false) { + rows.push('tfoot tr'); + } + if (rows.length) { + $rows = $table.find( rows.join(',') ).children().removeClass(remove); + if (len) { + for (indx = 0; indx < len; indx++) { + // add primary. secondary, tertiary, etc sort column classes + $rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]); + } + } + } + }, + remove: function(table, c, wo) { + var tbodyIndex, $tbody, + $tbodies = c.$tbodies, + remove = (wo.columns || [ "primary", "secondary", "tertiary" ]).join(' '); + c.$headers.removeClass(remove); + c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove); + for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody + $tbody.children('tr').each(function() { + $(this).children().removeClass(remove); + }); + ts.processTbody(table, $tbody, false); // restore tbody + } + } +}); + +})(jQuery); + +/*! Widget: filter - updated 5/17/2015 (v2.22.1) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +;( function ( $ ) { +'use strict'; +var ts = $.tablesorter || {}, + tscss = ts.css; + +$.extend( tscss, { + filterRow : 'tablesorter-filter-row', + filter : 'tablesorter-filter', + filterDisabled : 'disabled', + filterRowHide : 'hideme' +}); + +ts.addWidget({ + id: 'filter', + priority: 50, + options : { + filter_childRows : false, // if true, filter includes child row content in the search + filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped + filter_columnFilters : true, // if true, a filter will be added to the top of each table column + filter_columnAnyMatch: true, // if true, allows using '#:{query}' in AnyMatch searches ( column:query ) + filter_cellFilter : '', // css class name added to the filter cell ( string or array ) + filter_cssFilter : '', // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added ) + 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. + filter_excludeFilter : {}, // filters to exclude, per column + filter_external : '', // jQuery selector string ( or jQuery object ) of external filters + filter_filteredRow : 'filtered', // class added to filtered rows; needed by pager plugin + filter_formatter : null, // add custom filter elements to the filter row + filter_functions : null, // add custom filter functions using this option + filter_hideEmpty : true, // hide filter row when table is empty + filter_hideFilters : false, // collapse filter row when mouse leaves the area + filter_ignoreCase : true, // if true, make all searches case-insensitive + filter_liveSearch : true, // if true, search column content while the user types ( with a delay ) + filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down + filter_placeholder : { search : '', select : '' }, // default placeholder text ( overridden by any header 'data-placeholder' setting ) + filter_reset : null, // jQuery selector string of an element used to reset the filters + filter_saveFilters : false, // Use the $.tablesorter.storage utility to save the most recent filters + filter_searchDelay : 300, // typing delay in milliseconds before starting a search + filter_searchFiltered: true, // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true + filter_selectSource : null, // include a function to return an array of values to be added to the column filter select + filter_startsWith : false, // if true, filter start from the beginning of the cell contents + filter_useParsedData : false, // filter all data using parsed content + filter_serversideFiltering : false, // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used. + filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value + filter_selectSourceSeparator : '|' // filter_selectSource array text left of the separator is added to the option value, right into the option text + }, + format: function( table, c, wo ) { + if ( !c.$table.hasClass( 'hasFilters' ) ) { + ts.filter.init( table, c, wo ); + } + }, + remove: function( table, c, wo, refreshing ) { + var tbodyIndex, $tbody, + $table = c.$table, + $tbodies = c.$tbodies, + events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ' + .split( ' ' ).join( c.namespace + 'filter ' ); + $table + .removeClass( 'hasFilters' ) + // add .tsfilter namespace to all BUT search + .unbind( events.replace( /\s+/g, ' ' ) ) + // remove the filter row even if refreshing, because the column might have been moved + .find( '.' + tscss.filterRow ).remove(); + if ( refreshing ) { return; } + for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody + $tbody.children().removeClass( wo.filter_filteredRow ).show(); + ts.processTbody( table, $tbody, false ); // restore tbody + } + if ( wo.filter_reset ) { + $( document ).undelegate( wo.filter_reset, 'click.tsfilter' ); + } + } +}); + +ts.filter = { + + // regex used in filter 'check' functions - not for general use and not documented + regex: { + regex : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex + child : /tablesorter-childRow/, // child row class name; this gets updated in the script + filtered : /filtered/, // filtered (hidden) row class name; updated in the script + type : /undefined|number/, // check type + exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==') + nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser) + operators : /[<>=]/g, // replace operators + query : '(q|query)' // replace filter queries + }, + // function( c, data ) { } + // c = table.config + // data.$row = jQuery object of the row currently being processed + // data.$cells = jQuery object of all cells within the current row + // data.filters = array of filters for all columns ( some may be undefined ) + // data.filter = filter for the current column + // data.iFilter = same as data.filter, except lowercase ( if wo.filter_ignoreCase is true ) + // data.exact = table cell text ( or parsed data if column parser enabled ) + // data.iExact = same as data.exact, except lowercase ( if wo.filter_ignoreCase is true ) + // data.cache = table cell text from cache, so it has been parsed ( & in all lower case if c.ignoreCase is true ) + // data.cacheArray = An array of parsed content from each table cell in the row being processed + // data.index = column index; table = table element ( DOM ) + // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class ) + types: { + // Look for regex + regex: function( c, data ) { + if ( ts.filter.regex.regex.test( data.filter ) ) { + var matches, + // cache regex per column for optimal speed + regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ), + isRegex = regex instanceof RegExp; + try { + if ( !isRegex ) { + // force case insensitive search if ignoreCase option set? + // if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; } + data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] ); + } + matches = regex.test( data.exact ); + } catch ( error ) { + matches = false; + } + return matches; + } + return null; + }, + // Look for operators >, >=, < or <= + operators: function( c, data ) { + // ignore empty strings... because '' < 10 is true + if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) { + var cachedValue, result, txt, + table = c.table, + index = data.index, + parsed = data.parsed[index], + query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ), + parser = c.parsers[index], + savedSearch = query; + // parse filter value in case we're comparing numbers ( dates ) + if ( parsed || parser.type === 'numeric' ) { + txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) ); + result = ts.filter.parseFilter( c, txt, index, true ); + query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query; + } + // iExact may be numeric - see issue #149; + // check if cached is defined, because sometimes j goes out of range? ( numeric columns ) + if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) && + typeof data.cache !== 'undefined' ) { + cachedValue = data.cache; + } else { + txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact; + cachedValue = ts.formatFloat( txt, table ); + } + if ( />/.test( data.iFilter ) ) { + result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query; + } else if ( /= 0 ); + } + } + return null; + }, + // Look for quotes or equals to get an exact match; ignore type since iExact could be numeric + exact: function( c, data ) { + /*jshint eqeqeq:false */ + if ( ts.filter.regex.exact.test( data.iFilter ) ) { + var txt = data.iFilter.replace( ts.filter.regex.exact, '' ), + filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || ''; + return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact; + } + return null; + }, + // Look for an AND or && operator ( logical and ) + and : function( c, data ) { + if ( ts.filter.regex.andTest.test( data.filter ) ) { + var index = data.index, + parsed = data.parsed[index], + query = data.iFilter.split( ts.filter.regex.andSplit ), + result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0, + indx = query.length - 1; + while ( result && indx ) { + result = result && + data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0; + indx--; + } + return result; + } + return null; + }, + // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu! + range : function( c, data ) { + if ( ts.filter.regex.toTest.test( data.iFilter ) ) { + var result, tmp, range1, range2, + table = c.table, + index = data.index, + parsed = data.parsed[index], + // make sure the dash is for a range and not indicating a negative number + query = data.iFilter.split( ts.filter.regex.toSplit ); + + tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || ''; + range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table ); + tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || ''; + range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table ); + // parse filter value in case we're comparing numbers ( dates ) + if ( parsed || c.parsers[index].type === 'numeric' ) { + result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index ); + range1 = ( result !== '' && !isNaN( result ) ) ? result : range1; + result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index ); + range2 = ( result !== '' && !isNaN( result ) ) ? result : range2; + } + if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) { + result = data.cache; + } else { + tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact; + result = ts.formatFloat( tmp, table ); + } + if ( range1 > range2 ) { + tmp = range1; range1 = range2; range2 = tmp; // swap + } + return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' ); + } + return null; + }, + // Look for wild card: ? = single, * = multiple, or | = logical OR + wild : function( c, data ) { + if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) { + var index = data.index, + parsed = data.parsed[ index ], + txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ), + query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' ); + // look for an exact match with the 'or' unless the 'filter-match' class is found + if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) { + // show all results while using filter match. Fixes #727 + if ( query[ query.length - 1 ] === '|' ) { + query += '*'; + } + query = data.anyMatch && $.isArray( data.rowArray ) ? + '(' + query + ')' : + '^(' + query + ')$'; + } + // parsing the filter may not work properly when using wildcards =/ + return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) ) + .test( data.iExact ); + } + return null; + }, + // fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license ) + fuzzy: function( c, data ) { + if ( /^~/.test( data.iFilter ) ) { + var indx, + patternIndx = 0, + len = data.iExact.length, + txt = data.iFilter.slice( 1 ), + pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || ''; + for ( indx = 0; indx < len; indx++ ) { + if ( data.iExact[ indx ] === pattern[ patternIndx ] ) { + patternIndx += 1; + } + } + if ( patternIndx === pattern.length ) { + return true; + } + return false; + } + return null; + } + }, + init: function( table, c, wo ) { + // filter language options + ts.language = $.extend( true, {}, { + to : 'to', + or : 'or', + and : 'and' + }, ts.language ); + + var options, string, txt, $header, column, filters, val, fxn, noSelect, + regex = ts.filter.regex; + c.$table.addClass( 'hasFilters' ); + + // define timers so using clearTimeout won't cause an undefined error + wo.searchTimer = null; + wo.filter_initTimer = null; + wo.filter_formatterCount = 0; + wo.filter_formatterInit = []; + wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]'; + wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]'; + + val = '\\{' + ts.filter.regex.query + '\\}'; + $.extend( regex, { + child : new RegExp( c.cssChildRow ), + filtered : new RegExp( wo.filter_filteredRow ), + alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ), + toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ), + toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ), + andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ), + andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ), + orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ), + iQuery : new RegExp( val, 'i' ), + igQuery : new RegExp( val, 'ig' ) + }); + + // don't build filter row if columnFilters is false or all columns are set to 'filter-false' + // see issue #156 + val = c.$headers.filter( '.filter-false, .parser-false' ).length; + if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) { + // build filter row + ts.filter.buildRow( table, c, wo ); + } + + txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ' + .split( ' ' ).join( c.namespace + 'filter ' ); + c.$table.bind( txt, function( event, filter ) { + val = wo.filter_hideEmpty && + $.isEmptyObject( c.cache ) && + !( c.delayInit && event.type === 'appendCache' ); + // hide filter row using the 'filtered' class name + c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450 + if ( !/(search|filter)/.test( event.type ) ) { + event.stopPropagation(); + ts.filter.buildDefault( table, true ); + } + if ( event.type === 'filterReset' ) { + c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' ); + ts.filter.searching( table, [] ); + } else if ( event.type === 'filterEnd' ) { + ts.filter.buildDefault( table, true ); + } else { + // send false argument to force a new search; otherwise if the filter hasn't changed, + // it will return + filter = event.type === 'search' ? filter : + event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : ''; + if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) { + // force a new search since content has changed + c.lastCombinedFilter = null; + c.lastSearch = []; + } + // pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first + // input ensures all inputs are updated when a search is triggered on the table + // $( 'table' ).trigger( 'search', [...] ); + ts.filter.searching( table, filter, true ); + } + return false; + }); + + // reset button/link + if ( wo.filter_reset ) { + if ( wo.filter_reset instanceof $ ) { + // reset contains a jQuery object, bind to it + wo.filter_reset.click( function() { + c.$table.trigger( 'filterReset' ); + }); + } else if ( $( wo.filter_reset ).length ) { + // reset is a jQuery selector, use event delegation + $( document ) + .undelegate( wo.filter_reset, 'click.tsfilter' ) + .delegate( wo.filter_reset, 'click.tsfilter', function() { + // trigger a reset event, so other functions ( filter_formatter ) know when to reset + c.$table.trigger( 'filterReset' ); + }); + } + } + if ( wo.filter_functions ) { + for ( column = 0; column < c.columns; column++ ) { + fxn = ts.getColumnData( table, wo.filter_functions, column ); + if ( fxn ) { + // remove 'filter-select' from header otherwise the options added here are replaced with + // all options + $header = c.$headerIndexed[ column ].removeClass( 'filter-select' ); + // don't build select if 'filter-false' or 'parser-false' set + noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) ); + options = ''; + if ( fxn === true && noSelect ) { + ts.filter.buildSelect( table, column ); + } else if ( typeof fxn === 'object' && noSelect ) { + // add custom drop down list + for ( string in fxn ) { + if ( typeof string === 'string' ) { + options += options === '' ? + '' : ''; + val = string; + txt = string; + if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) { + val = string.split( wo.filter_selectSourceSeparator ); + txt = val[1]; + val = val[0]; + } + options += ''; + } + } + c.$table + .find( 'thead' ) + .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' ) + .append( options ); + txt = wo.filter_selectSource; + fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column ); + if ( fxn ) { + // updating so the extra options are appended + ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) ); + } + } + } + } + } + // not really updating, but if the column has both the 'filter-select' class & + // filter_functions set to true, it would append the same options twice. + ts.filter.buildDefault( table, true ); + + ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true ); + if ( wo.filter_external ) { + ts.filter.bindSearch( table, wo.filter_external ); + } + + if ( wo.filter_hideFilters ) { + ts.filter.hideFilters( table, c ); + } + + // show processing icon + if ( c.showProcessing ) { + txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' ); + c.$table + .unbind( txt.replace( /\s+/g, ' ' ) ) + .bind( txt, function( event, columns ) { + // only add processing to certain columns to all columns + $header = ( columns ) ? + c.$table + .find( '.' + tscss.header ) + .filter( '[data-column]' ) + .filter( function() { + return columns[ $( this ).data( 'column' ) ] !== ''; + }) : ''; + ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' ); + }); + } + + // set filtered rows count ( intially unfiltered ) + c.filteredRows = c.totalRows; + + // add default values + txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' ); + c.$table + .unbind( txt.replace( /\s+/g, ' ' ) ) + .bind( txt, function() { + // redefine 'wo' as it does not update properly inside this callback + var wo = this.config.widgetOptions; + filters = ts.filter.setDefaults( table, c, wo ) || []; + if ( filters.length ) { + // prevent delayInit from triggering a cache build if filters are empty + if ( !( c.delayInit && filters.join( '' ) === '' ) ) { + ts.setFilters( table, filters, true ); + } + } + c.$table.trigger( 'filterFomatterUpdate' ); + // trigger init after setTimeout to prevent multiple filterStart/End/Init triggers + setTimeout( function() { + if ( !wo.filter_initialized ) { + ts.filter.filterInitComplete( c ); + } + }, 100 ); + }); + // if filter widget is added after pager has initialized; then set filter init flag + if ( c.pager && c.pager.initialized && !wo.filter_initialized ) { + c.$table.trigger( 'filterFomatterUpdate' ); + setTimeout( function() { + ts.filter.filterInitComplete( c ); + }, 100 ); + } + }, + // $cell parameter, but not the config, is passed to the filter_formatters, + // so we have to work with it instead + formatterUpdated: function( $cell, column ) { + var wo = $cell.closest( 'table' )[0].config.widgetOptions; + if ( !wo.filter_initialized ) { + // add updates by column since this function + // may be called numerous times before initialization + wo.filter_formatterInit[ column ] = 1; + } + }, + filterInitComplete: function( c ) { + var indx, len, + wo = c.widgetOptions, + count = 0, + completed = function() { + wo.filter_initialized = true; + c.$table.trigger( 'filterInit', c ); + ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] ); + }; + if ( $.isEmptyObject( wo.filter_formatter ) ) { + completed(); + } else { + len = wo.filter_formatterInit.length; + for ( indx = 0; indx < len; indx++ ) { + if ( wo.filter_formatterInit[ indx ] === 1 ) { + count++; + } + } + clearTimeout( wo.filter_initTimer ); + if ( !wo.filter_initialized && count === wo.filter_formatterCount ) { + // filter widget initialized + completed(); + } else if ( !wo.filter_initialized ) { + // fall back in case a filter_formatter doesn't call + // $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off + wo.filter_initTimer = setTimeout( function() { + completed(); + }, 500 ); + } + } + }, + + setDefaults: function( table, c, wo ) { + var isArray, saved, indx, col, $filters, + // get current ( default ) filters + filters = ts.getFilters( table ) || []; + if ( wo.filter_saveFilters && ts.storage ) { + saved = ts.storage( table, 'tablesorter-filters' ) || []; + isArray = $.isArray( saved ); + // make sure we're not just getting an empty array + if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) { + filters = saved; + } + } + // if no filters saved, then check default settings + if ( filters.join( '' ) === '' ) { + // allow adding default setting to external filters + $filters = c.$headers.add( wo.filter_$externalFilters ) + .filter( '[' + wo.filter_defaultAttrib + ']' ); + for ( indx = 0; indx <= c.columns; indx++ ) { + // include data-column='all' external filters + col = indx === c.columns ? 'all' : indx; + filters[indx] = $filters + .filter( '[data-column="' + col + '"]' ) + .attr( wo.filter_defaultAttrib ) || filters[indx] || ''; + } + } + c.$table.data( 'lastSearch', filters ); + return filters; + }, + parseFilter: function( c, filter, column, parsed ) { + return parsed ? c.parsers[column].format( filter, c.table, [], column ) : filter; + }, + buildRow: function( table, c, wo ) { + var col, column, $header, buildSelect, disabled, name, ffxn, tmp, + // c.columns defined in computeThIndexes() + cellFilter = wo.filter_cellFilter, + columns = c.columns, + arry = $.isArray( cellFilter ), + buildFilter = ''; + for ( column = 0; column < columns; column++ ) { + buildFilter += '' ).appendTo( c.$filters.eq( column ) ); + } else { + ffxn = ts.getColumnData( table, wo.filter_formatter, column ); + if ( ffxn ) { + wo.filter_formatterCount++; + buildFilter = ffxn( c.$filters.eq( column ), column ); + // no element returned, so lets go find it + if ( buildFilter && buildFilter.length === 0 ) { + buildFilter = c.$filters.eq( column ).children( 'input' ); + } + // element not in DOM, so lets attach it + if ( buildFilter && ( buildFilter.parent().length === 0 || + ( buildFilter.parent().length && buildFilter.parent()[0] !== c.$filters[column] ) ) ) { + c.$filters.eq( column ).append( buildFilter ); + } + } else { + buildFilter = $( '' ).appendTo( c.$filters.eq( column ) ); + } + if ( buildFilter ) { + tmp = $header.data( 'placeholder' ) || + $header.attr( 'data-placeholder' ) || + wo.filter_placeholder.search || ''; + buildFilter.attr( 'placeholder', tmp ); + } + } + if ( buildFilter ) { + // add filter class name + name = ( $.isArray( wo.filter_cssFilter ) ? + ( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) : + wo.filter_cssFilter ) || ''; + buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', column ); + if ( disabled ) { + buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true; + } + } + } + }, + bindSearch: function( table, $el, internal ) { + table = $( table )[0]; + $el = $( $el ); // allow passing a selector string + if ( !$el.length ) { return; } + var tmp, + c = table.config, + wo = c.widgetOptions, + namespace = c.namespace + 'filter', + $ext = wo.filter_$externalFilters; + if ( internal !== true ) { + // save anyMatch element + tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector; + wo.filter_$anyMatch = $el.filter( tmp ); + if ( $ext && $ext.length ) { + wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el ); + } else { + wo.filter_$externalFilters = $el; + } + // update values ( external filters added after table initialization ) + ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false ); + } + // unbind events + tmp = ( 'keypress keyup search change '.split( ' ' ).join( namespace + ' ' ) ); + $el + // use data attribute instead of jQuery data since the head is cloned without including + // the data/binding + .attr( 'data-lastSearchTime', new Date().getTime() ) + .unbind( tmp.replace( /\s+/g, ' ' ) ) + // include change for select - fixes #473 + .bind( 'keyup' + namespace, function( event ) { + $( this ).attr( 'data-lastSearchTime', new Date().getTime() ); + // emulate what webkit does.... escape clears the filter + if ( event.which === 27 ) { + this.value = ''; + // live search + } else if ( wo.filter_liveSearch === false ) { + return; + // don't return if the search value is empty ( all rows need to be revealed ) + } else if ( this.value !== '' && ( + // liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace + ( typeof wo.filter_liveSearch === 'number' && this.value.length < wo.filter_liveSearch ) || + // let return & backspace continue on, but ignore arrows & non-valid characters + ( event.which !== 13 && event.which !== 8 && + ( event.which < 32 || ( event.which >= 37 && event.which <= 40 ) ) ) ) ) { + return; + } + // change event = no delay; last true flag tells getFilters to skip newest timed input + ts.filter.searching( table, true, true ); + }) + .bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) { + var column = $( this ).data( 'column' ); + // don't allow 'change' event to process if the input value is the same - fixes #685 + if ( event.which === 13 || event.type === 'search' || + event.type === 'change' && this.value !== c.lastSearch[column] ) { + event.preventDefault(); + // init search with no delay + $( this ).attr( 'data-lastSearchTime', new Date().getTime() ); + ts.filter.searching( table, false, true ); + } + }); + }, + searching: function( table, filter, skipFirst ) { + var wo = table.config.widgetOptions; + clearTimeout( wo.searchTimer ); + if ( typeof filter === 'undefined' || filter === true ) { + // delay filtering + wo.searchTimer = setTimeout( function() { + ts.filter.checkFilters( table, filter, skipFirst ); + }, wo.filter_liveSearch ? wo.filter_searchDelay : 10 ); + } else { + // skip delay + ts.filter.checkFilters( table, filter, skipFirst ); + } + }, + checkFilters: function( table, filter, skipFirst ) { + var c = table.config, + wo = c.widgetOptions, + filterArray = $.isArray( filter ), + filters = ( filterArray ) ? filter : ts.getFilters( table, true ), + combinedFilters = ( filters || [] ).join( '' ); // combined filter values + // prevent errors if delay init is set + if ( $.isEmptyObject( c.cache ) ) { + // update cache if delayInit set & pager has initialized ( after user initiates a search ) + if ( c.delayInit && c.pager && c.pager.initialized ) { + c.$table.trigger( 'updateCache', [ function() { + ts.filter.checkFilters( table, false, skipFirst ); + } ] ); + } + return; + } + // add filter array back into inputs + if ( filterArray ) { + ts.setFilters( table, filters, false, skipFirst !== true ); + if ( !wo.filter_initialized ) { c.lastCombinedFilter = ''; } + } + if ( wo.filter_hideFilters ) { + // show/hide filter row as needed + c.$table + .find( '.' + tscss.filterRow ) + .trigger( combinedFilters === '' ? 'mouseleave' : 'mouseenter' ); + } + // return if the last search is the same; but filter === false when updating the search + // see example-widget-filter.html filter toggle buttons + if ( c.lastCombinedFilter === combinedFilters && filter !== false ) { + return; + } else if ( filter === false ) { + // force filter refresh + c.lastCombinedFilter = null; + c.lastSearch = []; + } + if ( wo.filter_initialized ) { + c.$table.trigger( 'filterStart', [filters] ); + } + if ( c.showProcessing ) { + // give it time for the processing icon to kick in + setTimeout( function() { + ts.filter.findRows( table, filters, combinedFilters ); + return false; + }, 30 ); + } else { + ts.filter.findRows( table, filters, combinedFilters ); + return false; + } + }, + hideFilters: function( table, c ) { + var $filterRow, $filterRow2, timer; + $( table ) + .find( '.' + tscss.filterRow ) + .addClass( tscss.filterRowHide ) + .bind( 'mouseenter mouseleave', function( e ) { + // save event object - http://bugs.jquery.com/ticket/12140 + var event = e; + $filterRow = $( this ); + clearTimeout( timer ); + timer = setTimeout( function() { + if ( /enter|over/.test( event.type ) ) { + $filterRow.removeClass( tscss.filterRowHide ); + } else { + // don't hide if input has focus + // $( ':focus' ) needs jQuery 1.6+ + if ( $( document.activeElement ).closest( 'tr' )[0] !== $filterRow[0] ) { + // don't hide row if any filter has a value + if ( c.lastCombinedFilter === '' ) { + $filterRow.addClass( tscss.filterRowHide ); + } + } + } + }, 200 ); + }) + .find( 'input, select' ).bind( 'focus blur', function( e ) { + $filterRow2 = $( this ).closest( 'tr' ); + clearTimeout( timer ); + var event = e; + timer = setTimeout( function() { + // don't hide row if any filter has a value + if ( ts.getFilters( c.$table ).join( '' ) === '' ) { + $filterRow2.toggleClass( tscss.filterRowHide, event.type === 'focus' ); + } + }, 200 ); + }); + }, + defaultFilter: function( filter, mask ) { + if ( filter === '' ) { return filter; } + var regex = ts.filter.regex.iQuery, + maskLen = mask.match( ts.filter.regex.igQuery ).length, + query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ], + len = query.length - 1, + indx = 0, + val = mask; + if ( len < 1 && maskLen > 1 ) { + // only one 'word' in query but mask has >1 slots + query[1] = query[0]; + } + // replace all {query} with query words... + // if query = 'Bob', then convert mask from '!{query}' to '!Bob' + // if query = 'Bob Joe Frank', then convert mask '{q} OR {q}' to 'Bob OR Joe OR Frank' + while ( regex.test( val ) ) { + val = val.replace( regex, query[indx++] || '' ); + if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) { + val = mask.replace( regex, val ); + } + } + return val; + }, + getLatestSearch: function( $input ) { + if ( $input ) { + return $input.sort( function( a, b ) { + return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' ); + }); + } + return $input || $(); + }, + multipleColumns: function( c, $input ) { + // look for multiple columns '1-3,4-6,8' in data-column + var temp, ranges, range, start, end, singles, i, indx, len, + wo = c.widgetOptions, + // only target 'all' column inputs on initialization + // & don't target 'all' column inputs if they don't exist + targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length, + columns = [], + val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' ); + // process column range + if ( targets && /-/.test( val ) ) { + ranges = val.match( /(\d+)\s*-\s*(\d+)/g ); + len = ranges.length; + for ( indx = 0; indx < len; indx++ ) { + range = ranges[indx].split( /\s*-\s*/ ); + start = parseInt( range[0], 10 ) || 0; + end = parseInt( range[1], 10 ) || ( c.columns - 1 ); + if ( start > end ) { + temp = start; start = end; end = temp; // swap + } + if ( end >= c.columns ) { + end = c.columns - 1; + } + for ( ; start <= end; start++ ) { + columns.push( start ); + } + // remove processed range from val + val = val.replace( ranges[ indx ], '' ); + } + } + // process single columns + if ( targets && /,/.test( val ) ) { + singles = val.split( /\s*,\s*/ ); + len = singles.length; + for ( i = 0; i < len; i++ ) { + if ( singles[ i ] !== '' ) { + indx = parseInt( singles[ i ], 10 ); + if ( indx < c.columns ) { + columns.push( indx ); + } + } + } + } + // return all columns + if ( !columns.length ) { + for ( indx = 0; indx < c.columns; indx++ ) { + columns.push( indx ); + } + } + return columns; + }, + processRow: function( c, data, vars ) { + var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, + fxn, ffxn, txt, + regex = ts.filter.regex, + wo = c.widgetOptions, + showRow = true; + data.$cells = data.$row.children(); + + if ( data.anyMatchFlag ) { + // look for multiple columns '1-3,4-6,8' + columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch ); + data.anyMatch = true; + data.rowArray = data.$cells.map( function( i ) { + if ( $.inArray( i, columnIndex ) > -1 ) { + if ( data.parsed[ i ] ) { + txt = data.cacheArray[ i ]; + } else { + txt = data.rawArray[ i ]; + txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt ); + if ( c.sortLocaleCompare ) { + txt = ts.replaceAccents( txt ); + } + } + return txt; + } + }).get(); + data.filter = data.anyMatchFilter; + data.iFilter = data.iAnyMatchFilter; + data.exact = data.rowArray.join( ' ' ); + data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact; + data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' ); + filterMatched = null; + matches = null; + for ( ffxn in ts.filter.types ) { + if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) { + matches = ts.filter.types[ffxn]( c, data ); + if ( matches !== null ) { + filterMatched = matches; + } + } + } + if ( filterMatched !== null ) { + showRow = filterMatched; + } else { + if ( wo.filter_startsWith ) { + showRow = false; + columnIndex = c.columns; + while ( !showRow && columnIndex > 0 ) { + columnIndex--; + showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0; + } + } else { + showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0; + } + } + data.anyMatch = false; + // no other filters to process + if ( data.filters.join( '' ) === data.filter ) { + return showRow; + } + } + + for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) { + data.filter = data.filters[ columnIndex ]; + data.index = columnIndex; + + // filter types to exclude, per column + excludeMatch = vars.excludeFilter[ columnIndex ]; + + // ignore if filter is empty or disabled + if ( data.filter ) { + data.cache = data.cacheArray[ columnIndex ]; + // check if column data should be from the cell or from parsed data + if ( wo.filter_useParsedData || data.parsed[ columnIndex ] ) { + data.exact = data.cache; + } else { + result = data.rawArray[ columnIndex ] || ''; + data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405 + } + data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ? + data.exact.toLowerCase() : data.exact; + result = showRow; // if showRow is true, show that row + + // in case select filter option has a different value vs text 'a - z|A through Z' + ffxn = wo.filter_columnFilters ? + c.$filters.add( c.$externalFilters ) + .filter( '[data-column="'+ columnIndex + '"]' ) + .find( 'select option:selected' ) + .attr( 'data-function-name' ) || '' : ''; + // replace accents - see #357 + if ( c.sortLocaleCompare ) { + data.filter = ts.replaceAccents( data.filter ); + } + + val = true; + if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) { + data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] ); + // val is used to indicate that a filter select is using a default filter; + // so we override the exact & partial matches + val = false; + } + // data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ), + // data.filter = case sensitive + data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter; + fxn = vars.functions[ columnIndex ]; + $cell = c.$headerIndexed[ columnIndex ]; + hasSelect = $cell.hasClass( 'filter-select' ); + filterMatched = null; + if ( fxn || ( hasSelect && val ) ) { + if ( fxn === true || hasSelect ) { + // default selector uses exact match unless 'filter-match' class is found + filterMatched = $cell.hasClass( 'filter-match' ) ? + data.iExact.search( data.iFilter ) >= 0 : + data.filter === data.exact; + } else if ( typeof fxn === 'function' ) { + // filter callback( exact cell content, parser normalized content, + // filter input value, column index, jQuery row object ) + filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data ); + } else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) { + // selector option function + txt = ffxn || data.filter; + filterMatched = + fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data ); + } + } + if ( filterMatched === null ) { + // cycle through the different filters + // filters return a boolean or null if nothing matches + matches = null; + for ( ffxn in ts.filter.types ) { + if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) { + matches = ts.filter.types[ ffxn ]( c, data ); + if ( matches !== null ) { + filterMatched = matches; + } + } + } + if ( filterMatched !== null ) { + result = filterMatched; + // Look for match, and add child row data for matching + } else { + txt = ( data.iExact + data.childRowText ) + .indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) ); + result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) ); + } + } else { + result = filterMatched; + } + showRow = ( result ) ? showRow : false; + } + } + return showRow; + }, + findRows: function( table, filters, combinedFilters ) { + if ( table.config.lastCombinedFilter === combinedFilters || + !table.config.widgetOptions.filter_initialized ) { + return; + } + var len, norm_rows, rowData, $rows, rowIndex, tbodyIndex, $tbody, columnIndex, + isChild, childRow, lastSearch, showRow, time, val, indx, + notFiltered, searchFiltered, query, injected, res, id, txt, + storedFilters = $.extend( [], filters ), + regex = ts.filter.regex, + c = table.config, + wo = c.widgetOptions, + // data object passed to filters; anyMatch is a flag for the filters + data = { + anyMatch: false, + filters: filters, + // regex filter type cache + filter_regexCache : [], + }, + vars = { + // anyMatch really screws up with these types of filters + noAnyMatch: [ 'range', 'notMatch', 'operators' ], + // cache filter variables that use ts.getColumnData in the main loop + functions : [], + excludeFilter : [], + defaultColFilter : [], + defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || '' + }; + + // parse columns after formatter, in case the class is added at that point + data.parsed = c.$headers.map( function( columnIndex ) { + return c.parsers && c.parsers[ columnIndex ] && + // force parsing if parser type is numeric + c.parsers[ columnIndex ].parsed || + // getData won't return 'parsed' if other 'filter-' class names exist + // ( e.g. ) + ts.getData && ts.getData( c.$headerIndexed[ columnIndex ], + ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' || + $( this ).hasClass( 'filter-parsed' ); + }).get(); + + for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) { + vars.functions[ columnIndex ] = + ts.getColumnData( table, wo.filter_functions, columnIndex ); + vars.defaultColFilter[ columnIndex ] = + ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || ''; + vars.excludeFilter[ columnIndex ] = + ( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ ); + } + + if ( c.debug ) { + ts.log( 'Filter: Starting filter widget search', filters ); + time = new Date(); + } + // filtered rows count + c.filteredRows = 0; + c.totalRows = 0; + // combindedFilters are undefined on init + combinedFilters = ( storedFilters || [] ).join( '' ); + + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true ); + // skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel! + // $rows = $tbody.children( 'tr' ).not( c.selectorRemove ); + columnIndex = c.columns; + // convert stored rows into a jQuery object + norm_rows = c.cache[ tbodyIndex ].normalized; + $rows = $( $.map( norm_rows, function( el ) { + return el[ columnIndex ].$row.get(); + }) ); + + if ( combinedFilters === '' || wo.filter_serversideFiltering ) { + $rows + .removeClass( wo.filter_filteredRow ) + .not( '.' + c.cssChildRow ) + .css( 'display', '' ); + } else { + // filter out child rows + $rows = $rows.not( '.' + c.cssChildRow ); + len = $rows.length; + + if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) || + typeof filters[c.columns] !== 'undefined' ) { + data.anyMatchFlag = true; + data.anyMatchFilter = '' + ( + filters[ c.columns ] || + wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() || + '' + ); + if ( wo.filter_columnAnyMatch ) { + // specific columns search + query = data.anyMatchFilter.split( regex.andSplit ); + injected = false; + for ( indx = 0; indx < query.length; indx++ ) { + res = query[ indx ].split( ':' ); + if ( res.length > 1 ) { + // make the column a one-based index ( non-developers start counting from one :P ) + id = parseInt( res[0], 10 ) - 1; + if ( id >= 0 && id < c.columns ) { // if id is an integer + filters[ id ] = res[1]; + query.splice( indx, 1 ); + indx--; + injected = true; + } + } + } + if ( injected ) { + data.anyMatchFilter = query.join( ' && ' ); + } + } + } + + // optimize searching only through already filtered rows - see #313 + searchFiltered = wo.filter_searchFiltered; + lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || []; + if ( searchFiltered ) { + // cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669 + for ( indx = 0; indx < columnIndex + 1; indx++ ) { + val = filters[indx] || ''; + // break out of loop if we've already determined not to search filtered rows + if ( !searchFiltered ) { indx = columnIndex; } + // search already filtered rows if... + searchFiltered = searchFiltered && lastSearch.length && + // there are no changes from beginning of filter + val.indexOf( lastSearch[indx] || '' ) === 0 && + // if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string + !regex.alreadyFiltered.test( val ) && + // if we are not doing exact matches, using '|' ( logical or ) or not '!' + !/[=\"\|!]/.test( val ) && + // don't search only filtered if the value is negative + // ( '> -10' => '> -100' will ignore hidden rows ) + !( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) && + // if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593 + !( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length && + !c.$headerIndexed[indx].hasClass( 'filter-match' ) ); + } + } + notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length; + // can't search when all rows are hidden - this happens when looking for exact matches + if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; } + if ( c.debug ) { + ts.log( 'Filter: Searching through ' + + ( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' ); + } + if ( data.anyMatchFlag ) { + if ( c.sortLocaleCompare ) { + // replace accents + data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter ); + } + if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) { + data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter ); + // clear search filtered flag because default filters are not saved to the last search + searchFiltered = false; + } + // make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true + // when c.ignoreCase is true, the cache contains all lower case data + data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ? + data.anyMatchFilter : + data.anyMatchFilter.toLowerCase(); + } + + // loop through the rows + for ( rowIndex = 0; rowIndex < len; rowIndex++ ) { + + txt = $rows[ rowIndex ].className; + // the first row can never be a child row + isChild = rowIndex && regex.child.test( txt ); + // skip child rows & already filtered rows + if ( isChild || ( searchFiltered && regex.filtered.test( txt ) ) ) { + continue; + } + + data.$row = $rows.eq( rowIndex ); + data.cacheArray = norm_rows[ rowIndex ]; + rowData = data.cacheArray[ c.columns ]; + data.rawArray = rowData.raw; + data.childRowText = ''; + + if ( !wo.filter_childByColumn ) { + txt = ''; + // child row cached text + childRow = rowData.child; + // so, if 'table.config.widgetOptions.filter_childRows' is true and there is + // a match anywhere in the child row, then it will make the row visible + // checked here so the option can be changed dynamically + for ( indx = 0; indx < childRow.length; indx++ ) { + txt += ' ' + childRow[indx].join( '' ) || ''; + } + data.childRowText = wo.filter_childRows ? + ( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) : + ''; + } + + showRow = ts.filter.processRow( c, data, vars ); + childRow = rowData.$row.filter( ':gt( 0 )' ); + + if ( wo.filter_childRows && childRow.length ) { + if ( wo.filter_childByColumn ) { + // cycle through each child row + for ( indx = 0; indx < childRow.length; indx++ ) { + data.$row = childRow.eq( indx ); + data.cacheArray = rowData.child[ indx ]; + data.rawArray = data.cacheArray; + // use OR comparison on child rows + showRow = showRow || ts.filter.processRow( c, data, vars ); + } + } + childRow.toggleClass( wo.filter_filteredRow, !showRow ); + } + + rowData.$row + .toggleClass( wo.filter_filteredRow, !showRow )[0] + .display = showRow ? '' : 'none'; + } + } + c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length; + c.totalRows += $rows.length; + ts.processTbody( table, $tbody, false ); + } + c.lastCombinedFilter = combinedFilters; // save last search + // don't save 'filters' directly since it may have altered ( AnyMatch column searches ) + c.lastSearch = storedFilters; + c.$table.data( 'lastSearch', storedFilters ); + if ( wo.filter_saveFilters && ts.storage ) { + ts.storage( table, 'tablesorter-filters', storedFilters ); + } + if ( c.debug ) { + ts.benchmark( 'Completed filter widget search', time ); + } + if ( wo.filter_initialized ) { + c.$table.trigger( 'filterEnd', c ); + } + setTimeout( function() { + c.$table.trigger( 'applyWidgets' ); // make sure zebra widget is applied + }, 0 ); + }, + getOptionSource: function( table, column, onlyAvail ) { + table = $( table )[0]; + var cts, txt, indx, len, + c = table.config, + wo = c.widgetOptions, + parsed = [], + arry = false, + source = wo.filter_selectSource, + last = c.$table.data( 'lastSearch' ) || [], + fxn = $.isFunction( source ) ? true : ts.getColumnData( table, source, column ); + + if ( onlyAvail && last[column] !== '' ) { + onlyAvail = false; + } + + // filter select source option + if ( fxn === true ) { + // OVERALL source + arry = source( table, column, onlyAvail ); + } else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '' ) >= 0 ) ) { + // selectSource is a jQuery object or string of options + return fxn; + } else if ( $.isArray( fxn ) ) { + arry = fxn; + } else if ( $.type( source ) === 'object' && fxn ) { + // custom select source function for a SPECIFIC COLUMN + arry = fxn( table, column, onlyAvail ); + } + if ( arry === false ) { + // fall back to original method + arry = ts.filter.getOptions( table, column, onlyAvail ); + } + + // get unique elements and sort the list + // if $.tablesorter.sortText exists ( not in the original tablesorter ), + // then natural sort the list otherwise use a basic sort + arry = $.grep( arry, function( value, indx ) { + return $.inArray( value, arry ) === indx; + }); + + if ( c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) { + // unsorted select options + return arry; + } else { + len = arry.length; + // parse select option values + for ( indx = 0; indx < len; indx++ ) { + txt = arry[ indx ]; + // parse array data using set column parser; this DOES NOT pass the original + // table cell to the parser format function + parsed.push({ + t : txt, + // check parser length - fixes #934 + p : c.parsers && c.parsers.length && c.parsers[ column ].format( txt, table, [], column ) || txt + }); + } + + // sort parsed select options + cts = c.textSorter || ''; + parsed.sort( function( a, b ) { + // sortNatural breaks if you don't pass it strings + var x = a.p.toString(), + y = b.p.toString(); + if ( $.isFunction( cts ) ) { + // custom OVERALL text sorter + return cts( x, y, true, column, table ); + } else if ( typeof( cts ) === 'object' && cts.hasOwnProperty( column ) ) { + // custom text sorter for a SPECIFIC COLUMN + return cts[column]( x, y, true, column, table ); + } else if ( ts.sortNatural ) { + // fall back to natural sort + return ts.sortNatural( x, y ); + } + // using an older version! do a basic sort + return true; + }); + // rebuild arry from sorted parsed data + arry = []; + len = parsed.length; + for ( indx = 0; indx < len; indx++ ) { + arry.push( parsed[indx].t ); + } + return arry; + } + }, + getOptions: function( table, column, onlyAvail ) { + table = $( table )[0]; + var rowIndex, tbodyIndex, len, row, cache, + c = table.config, + wo = c.widgetOptions, + arry = []; + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) { + cache = c.cache[tbodyIndex]; + len = c.cache[tbodyIndex].normalized.length; + // loop through the rows + for ( rowIndex = 0; rowIndex < len; rowIndex++ ) { + // get cached row from cache.row ( old ) or row data object + // ( new; last item in normalized array ) + row = cache.row ? + cache.row[ rowIndex ] : + cache.normalized[ rowIndex ][ c.columns ].$row[0]; + // check if has class filtered + if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) { + continue; + } + // get non-normalized cell content + if ( wo.filter_useParsedData || + c.parsers[column].parsed || + c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) { + arry.push( '' + cache.normalized[ rowIndex ][ column ] ); + } else { + // get raw cached data instead of content directly from the cells + arry.push( cache.normalized[ rowIndex ][ c.columns ].raw[ column ] ); + } + } + } + return arry; + }, + buildSelect: function( table, column, arry, updating, onlyAvail ) { + table = $( table )[0]; + column = parseInt( column, 10 ); + if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) { + return; + } + var indx, val, txt, t, $filters, $filter, + c = table.config, + wo = c.widgetOptions, + node = c.$headerIndexed[ column ], + // t.data( 'placeholder' ) won't work in jQuery older than 1.4.3 + options = '', + // Get curent filter value + currentValue = c.$table + .find( 'thead' ) + .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' ) + .val(); + // nothing included in arry ( external source ), so get the options from + // filter_selectSource or column data + if ( typeof arry === 'undefined' || arry === '' ) { + arry = ts.filter.getOptionSource( table, column, onlyAvail ); + } + + if ( $.isArray( arry ) ) { + // build option list + for ( indx = 0; indx < arry.length; indx++ ) { + txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '"' ); + val = txt; + // allow including a symbol in the selectSource array + // 'a-z|A through Z' so that 'a-z' becomes the option value + // and 'A through Z' becomes the option text + if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) { + t = txt.split( wo.filter_selectSourceSeparator ); + val = t[0]; + txt = t[1]; + } + // replace quotes - fixes #242 & ignore empty strings + // see http://stackoverflow.com/q/14990971/145346 + options += arry[indx] !== '' ? + '' : ''; + } + // clear arry so it doesn't get appended twice + arry = []; + } + + // update all selects in the same column ( clone thead in sticky headers & + // any external selects ) - fixes 473 + $filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) ) + .find( '.' + tscss.filter ); + if ( wo.filter_$externalFilters ) { + $filters = $filters && $filters.length ? + $filters.add( wo.filter_$externalFilters ) : + wo.filter_$externalFilters; + } + $filter = $filters.filter( 'select[data-column="' + column + '"]' ); + + // make sure there is a select there! + if ( $filter.length ) { + $filter[ updating ? 'html' : 'append' ]( options ); + if ( !$.isArray( arry ) ) { + // append options if arry is provided externally as a string or jQuery object + // options ( default value ) was already added + $filter.append( arry ).val( currentValue ); + } + $filter.val( currentValue ); + } + }, + buildDefault: function( table, updating ) { + var columnIndex, $header, noSelect, + c = table.config, + wo = c.widgetOptions, + columns = c.columns; + // build default select dropdown + for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) { + $header = c.$headerIndexed[columnIndex]; + noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) ); + // look for the filter-select class; build/update it if found + if ( ( $header.hasClass( 'filter-select' ) || + ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) { + ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) ); + } + } + } +}; + +ts.getFilters = function( table, getRaw, setFilters, skipFirst ) { + var i, $filters, $column, cols, + filters = false, + c = table ? $( table )[0].config : '', + wo = c ? c.widgetOptions : ''; + if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) || + // setFilters called, but last search is exactly the same as the current + // fixes issue #733 & #903 where calling update causes the input values to reset + ( $.isArray(setFilters) && setFilters.join('') === c.lastCombinedFilter ) ) { + return $( table ).data( 'lastSearch' ); + } + if ( c ) { + if ( c.$filters ) { + $filters = c.$filters.find( '.' + tscss.filter ); + } + if ( wo.filter_$externalFilters ) { + $filters = $filters && $filters.length ? + $filters.add( wo.filter_$externalFilters ) : + wo.filter_$externalFilters; + } + if ( $filters && $filters.length ) { + filters = setFilters || []; + for ( i = 0; i < c.columns + 1; i++ ) { + cols = ( i === c.columns ? + // 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' ) + wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector : + '[data-column="' + i + '"]' ); + $column = $filters.filter( cols ); + if ( $column.length ) { + // move the latest search to the first slot in the array + $column = ts.filter.getLatestSearch( $column ); + if ( $.isArray( setFilters ) ) { + // skip first ( latest input ) to maintain cursor position while typing + if ( skipFirst && $column.length > 1 ) { + $column = $column.slice( 1 ); + } + if ( i === c.columns ) { + // prevent data-column='all' from filling data-column='0,1' ( etc ) + cols = $column.filter( wo.filter_anyColumnSelector ); + $column = cols.length ? cols : $column; + } + $column + .val( setFilters[ i ] ) + .trigger( 'change.tsfilter' ); + } else { + filters[i] = $column.val() || ''; + // don't change the first... it will move the cursor + if ( i === c.columns ) { + // don't update range columns from 'all' setting + $column + .slice( 1 ) + .filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' ) + .val( filters[ i ] ); + } else { + $column + .slice( 1 ) + .val( filters[ i ] ); + } + } + // save any match input dynamically + if ( i === c.columns && $column.length ) { + wo.filter_$anyMatch = $column; + } + } + } + } + } + if ( filters.length === 0 ) { + filters = false; + } + return filters; +}; + +ts.setFilters = function( table, filter, apply, skipFirst ) { + var c = table ? $( table )[0].config : '', + valid = ts.getFilters( table, true, filter, skipFirst ); + if ( c && apply ) { + // ensure new set filters are applied, even if the search is the same + c.lastCombinedFilter = null; + c.lastSearch = []; + ts.filter.searching( c.table, filter, skipFirst ); + c.$table.trigger( 'filterFomatterUpdate' ); + } + return !!valid; +}; + +})( jQuery ); + +/*! Widget: stickyHeaders - updated 3/26/2015 (v2.21.3) *//* + * Requires tablesorter v2.8+ and jQuery 1.4.3+ + * by Rob Garrison + */ +;(function ($, window) { +'use strict'; +var ts = $.tablesorter || {}; + +$.extend(ts.css, { + sticky : 'tablesorter-stickyHeader', // stickyHeader + stickyVis : 'tablesorter-sticky-visible', + stickyHide: 'tablesorter-sticky-hidden', + stickyWrap: 'tablesorter-sticky-wrapper' +}); + +// Add a resize event to table headers +ts.addHeaderResizeEvent = function(table, disable, settings) { + table = $(table)[0]; // make sure we're using a dom element + if ( !table.config ) { return; } + var defaults = { + timer : 250 + }, + options = $.extend({}, defaults, settings), + c = table.config, + wo = c.widgetOptions, + checkSizes = function( triggerEvent ) { + var index, headers, $header, sizes, width, height, + len = c.$headers.length; + wo.resize_flag = true; + headers = []; + for ( index = 0; index < len; index++ ) { + $header = c.$headers.eq( index ); + sizes = $header.data( 'savedSizes' ) || [ 0,0 ]; // fixes #394 + width = $header[0].offsetWidth; + height = $header[0].offsetHeight; + if ( width !== sizes[0] || height !== sizes[1] ) { + $header.data( 'savedSizes', [ width, height ] ); + headers.push( $header[0] ); + } + } + if ( headers.length && triggerEvent !== false ) { + c.$table.trigger( 'resize', [ headers ] ); + } + wo.resize_flag = false; + }; + checkSizes( false ); + clearInterval(wo.resize_timer); + if (disable) { + wo.resize_flag = false; + return false; + } + wo.resize_timer = setInterval(function() { + if (wo.resize_flag) { return; } + checkSizes(); + }, options.timer); +}; + +// Sticky headers based on this awesome article: +// http://css-tricks.com/13465-persistent-headers/ +// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech +// ************************** +ts.addWidget({ + id: "stickyHeaders", + priority: 60, // sticky widget must be initialized after the filter widget! + options: { + stickyHeaders : '', // extra class name added to the sticky header row + stickyHeaders_attachTo : null, // jQuery selector or object to attach sticky header to + stickyHeaders_xScroll : null, // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window) + stickyHeaders_yScroll : null, // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window) + stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element + stickyHeaders_filteredToTop: true, // scroll table top into view after filtering + stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists + stickyHeaders_addResizeEvent : true, // trigger "resize" event on headers + stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header + stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs + }, + format: function(table, c, wo) { + // filter widget doesn't initialize on an empty table. Fixes #449 + if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) { + return; + } + var index, len, $t, + $table = c.$table, + // add position: relative to attach element, hopefully it won't cause trouble. + $attach = $(wo.stickyHeaders_attachTo), + namespace = c.namespace + 'stickyheaders ', + // element to watch for the scroll event + $yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window), + $xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window), + $thead = $table.children('thead:first'), + $header = $thead.children('tr').not('.sticky-false').children(), + $tfoot = $table.children('tfoot'), + $stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '', + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0, + // is this table nested? If so, find parent sticky header wrapper (div, not table) + $nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ? + $table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [], + nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0, + // clone table, then wrap to make sticky header + $stickyTable = wo.$sticky = $table.clone() + .addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders + ' ' + c.namespace.slice(1) + '_extra_table' ) + .wrap('
    '), + $stickyWrap = $stickyTable.parent() + .addClass(ts.css.stickyHide) + .css({ + position : $attach.length ? 'absolute' : 'fixed', + padding : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ), + top : stickyOffset + nestedStickyTop, + left : 0, + visibility : 'hidden', + zIndex : wo.stickyHeaders_zIndex || 2 + }), + $stickyThead = $stickyTable.children('thead:first'), + $stickyCells, + laststate = '', + spacing = 0, + setWidth = function($orig, $clone){ + var index, width, border, $cell, $this, + $cells = $orig.filter(':visible'), + len = $cells.length; + for ( index = 0; index < len; index++ ) { + $cell = $clone.filter(':visible').eq(index); + $this = $cells.eq(index); + // code from https://github.com/jmosbech/StickyTableHeaders + if ($this.css('box-sizing') === 'border-box') { + width = $this.outerWidth(); + } else { + if ($cell.css('border-collapse') === 'collapse') { + if (window.getComputedStyle) { + width = parseFloat( window.getComputedStyle($this[0], null).width ); + } else { + // ie8 only + border = parseFloat( $this.css('border-width') ); + width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border; + } + } else { + width = $this.width(); + } + } + $cell.css({ + 'width': width, + 'min-width': width, + 'max-width': width + }); + } + }, + resizeHeader = function() { + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0; + spacing = 0; + $stickyWrap.css({ + left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 : + $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing, + width: $table.outerWidth() + }); + setWidth( $table, $stickyTable ); + setWidth( $header, $stickyCells ); + }, + scrollSticky = function( resizing ) { + if (!$table.is(':visible')) { return; } // fixes #278 + // Detect nested tables - fixes #724 + nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0; + var offset = $table.offset(), + yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3 + xWindow = $.isWindow( $xScroll[0] ), + // scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop, + scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop, + tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)), + isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden', + cssSettings = { visibility : isVisible }; + + if ($attach.length) { + cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop(); + } + if (xWindow) { + // adjust when scrolling horizontally - fixes issue #143 + cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing; + } + if ($nestedSticky.length) { + cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop; + } + $stickyWrap + .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide ) + .addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide ) + .css(cssSettings); + if (isVisible !== laststate || resizing) { + // make sure the column widths match + resizeHeader(); + laststate = isVisible; + } + }; + // only add a position relative if a position isn't already defined + if ($attach.length && !$attach.css('position')) { + $attach.css('position', 'relative'); + } + // fix clone ID, if it exists - fixes #271 + if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; } + // clear out cloned table, except for sticky header + // include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing + $stickyTable.find('thead:gt(0), tr.sticky-false').hide(); + $stickyTable.find('tbody, tfoot').remove(); + $stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption); + // issue #172 - find td/th in sticky header + $stickyCells = $stickyThead.children().children(); + $stickyTable.css({ height:0, width:0, margin: 0 }); + // remove resizable block + $stickyCells.find('.' + ts.css.resizer).remove(); + // update sticky header class names to match real header after sorting + $table + .addClass('hasStickyHeaders') + .bind('pagerComplete' + namespace, function() { + resizeHeader(); + }); + + ts.bindEvents(table, $stickyThead.children().children('.' + ts.css.header)); + + // add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned. + $table.after( $stickyWrap ); + + // onRenderHeader is defined, we need to do something about it (fixes #641) + if (c.onRenderHeader) { + $t = $stickyThead.children('tr').children(); + len = $t.length; + for ( index = 0; index < len; index++ ) { + // send second parameter + c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] ); + } + } + + // make it sticky! + $xScroll.add($yScroll) + .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') ) + .bind('scroll resize '.split(' ').join( namespace ), function( event ) { + scrollSticky( event.type === 'resize' ); + }); + c.$table + .unbind('stickyHeadersUpdate' + namespace) + .bind('stickyHeadersUpdate' + namespace, function(){ + scrollSticky( true ); + }); + + if (wo.stickyHeaders_addResizeEvent) { + ts.addHeaderResizeEvent(table); + } + + // look for filter widget + if ($table.hasClass('hasFilters') && wo.filter_columnFilters) { + // scroll table into view after filtering, if sticky header is active - #482 + $table.bind('filterEnd' + namespace, function() { + // $(':focus') needs jQuery 1.6+ + var $td = $(document.activeElement).closest('td'), + column = $td.parent().children().index($td); + // only scroll if sticky header is active + if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) { + // scroll to original table (not sticky clone) + window.scrollTo(0, $table.position().top); + // give same input/select focus; check if c.$filters exists; fixes #594 + if (column >= 0 && c.$filters) { + c.$filters.eq(column).find('a, select, input').filter(':visible').focus(); + } + } + }); + ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) ); + // support hideFilters + if (wo.filter_hideFilters) { + ts.filter.hideFilters($stickyTable, c); + } + } + + $table.trigger('stickyHeadersInit'); + + }, + remove: function(table, c, wo) { + var namespace = c.namespace + 'stickyheaders '; + c.$table + .removeClass('hasStickyHeaders') + .unbind( ('pagerComplete filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') ) + .next('.' + ts.css.stickyWrap).remove(); + if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table + $(window) + .add(wo.stickyHeaders_xScroll) + .add(wo.stickyHeaders_yScroll) + .add(wo.stickyHeaders_attachTo) + .unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') ); + ts.addHeaderResizeEvent(table, false); + } +}); + +})(jQuery, window); + +/*! Widget: resizable - updated 5/17/2015 (v2.22.0) */ +;(function ($, window) { +'use strict'; +var ts = $.tablesorter || {}; + +$.extend(ts.css, { + resizableContainer : 'tablesorter-resizable-container', + resizableHandle : 'tablesorter-resizable-handle', + resizableNoSelect : 'tablesorter-disableSelection', + resizableStorage : 'tablesorter-resizable' +}); + +// Add extra scroller css +$(function(){ + var s = ''; + $(s).appendTo('body'); +}); + +ts.resizable = { + init : function( c, wo ) { + if ( c.$table.hasClass( 'hasResizable' ) ) { return; } + c.$table.addClass( 'hasResizable' ); + ts.resizableReset( c.table, true ); // set default widths + + // internal variables + wo.resizable_ = { + $wrap : c.$table.parent(), + mouseXPosition : 0, + $target : null, + $next : null, + overflow : c.$table.parent().css('overflow') === 'auto', + fullWidth : Math.abs(c.$table.parent().width() - c.$table.width()) < 20, + storedSizes : [] + }; + + var noResize, $header, column, storedSizes, + marginTop = parseInt( c.$table.css( 'margin-top' ), 10 ); + + wo.resizable_.storedSizes = storedSizes = ( ( ts.storage && wo.resizable !== false ) ? + ts.storage( c.table, ts.css.resizableStorage ) : + [] ) || []; + ts.resizable.setWidths( c, wo, storedSizes ); + + wo.$resizable_container = $( '
    ' ) + .css({ top : marginTop }) + .insertBefore( c.$table ); + // add container + for ( column = 0; column < c.columns; column++ ) { + $header = c.$headerIndexed[ column ]; + noResize = ts.getData( $header, ts.getColumnData( c.table, c.headers, column ), 'resizable' ) === 'false'; + if ( !noResize ) { + $( '
    ' ) + .appendTo( wo.$resizable_container ) + .attr({ + 'data-column' : column, + 'unselectable' : 'on' + }) + .data( 'header', $header ) + .bind( 'selectstart', false ); + } + } + c.$table.one('tablesorter-initialized', function() { + ts.resizable.setHandlePosition( c, wo ); + ts.resizable.bindings( this.config, this.config.widgetOptions ); + }); + }, + + setWidth : function( $el, width ) { + $el.css({ + 'width' : width, + 'min-width' : '', + 'max-width' : '' + }); + }, + + setWidths : function( c, wo, storedSizes ) { + var column, + $extra = $( c.namespace + '_extra_headers' ), + $col = c.$table.children( 'colgroup' ).children( 'col' ); + storedSizes = storedSizes || wo.resizable_.storedSizes || []; + // process only if table ID or url match + if ( storedSizes.length ) { + for ( column = 0; column < c.columns; column++ ) { + // set saved resizable widths + c.$headerIndexed[ column ].width( storedSizes[ column ] ); + if ( $extra.length ) { + // stickyHeaders needs to modify min & max width as well + ts.resizable.setWidth( $extra.eq( column ).add( $col.eq( column ) ), storedSizes[ column ] ); + } + } + if ( $( c.namespace + '_extra_table' ).length && !ts.hasWidget( c.table, 'scroller' ) ) { + ts.resizable.setWidth( $( c.namespace + '_extra_table' ), c.$table.outerWidth() ); + } + } + }, + + setHandlePosition : function( c, wo ) { + var startPosition, + hasScroller = ts.hasWidget( c.table, 'scroller' ), + tableHeight = c.$table.height(), + $handles = wo.$resizable_container.children(), + handleCenter = Math.floor( $handles.width() / 2 ); + + if ( hasScroller ) { + tableHeight = 0; + c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function(){ + var $this = $(this); + // center table has a max-height set + tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height(); + }); + } + // subtract out table left position from resizable handles. Fixes #864 + startPosition = c.$table.position().left; + $handles.each( function() { + var $this = $(this), + column = parseInt( $this.attr( 'data-column' ), 10 ), + columns = c.columns - 1, + $header = $this.data( 'header' ); + if ( !$header ) { return; } // see #859 + if ( !$header.is(':visible') ) { + $this.hide(); + } else if ( column < columns || column === columns && wo.resizable_addLastColumn ) { + $this.css({ + display: 'inline-block', + height : tableHeight, + left : $header.position().left - startPosition + $header.outerWidth() - handleCenter + }); + } + }); + }, + + // prevent text selection while dragging resize bar + toggleTextSelection : function( c, toggle ) { + var namespace = c.namespace + 'tsresize'; + c.widgetOptions.resizable_.disabled = toggle; + $( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle ); + if ( toggle ) { + $( 'body' ) + .attr( 'unselectable', 'on' ) + .bind( 'selectstart' + namespace, false ); + } else { + $( 'body' ) + .removeAttr( 'unselectable' ) + .unbind( 'selectstart' + namespace ); + } + }, + + bindings : function( c, wo ) { + var namespace = c.namespace + 'tsresize'; + wo.$resizable_container.children().bind( 'mousedown', function( event ) { + // save header cell and mouse position + var column, $this, + vars = wo.resizable_, + $extras = $( c.namespace + '_extra_headers' ), + $header = $( event.target ).data( 'header' ); + + column = parseInt( $header.attr( 'data-column' ), 10 ); + vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') ); + vars.target = column; + + // if table is not as wide as it's parent, then resize the table + vars.$next = event.shiftKey || wo.resizable_targetLast ? + $header.parent().children().not( '.resizable-false' ).filter( ':last' ) : + $header.nextAll( ':not(.resizable-false)' ).eq( 0 ); + + column = parseInt( vars.$next.attr( 'data-column' ), 10 ); + vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') ); + vars.next = column; + + vars.mouseXPosition = event.pageX; + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + ts.resizable.toggleTextSelection( c, true ); + }); + + $( document ) + .bind( 'mousemove' + namespace, function( event ) { + var vars = wo.resizable_; + // ignore mousemove if no mousedown + if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; } + if ( wo.resizable_throttle ) { + clearTimeout( vars.timer ); + vars.timer = setTimeout( function() { + ts.resizable.mouseMove( c, wo, event ); + }, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle ); + } else { + ts.resizable.mouseMove( c, wo, event ); + } + }) + .bind( 'mouseup' + namespace, function() { + if (!wo.resizable_.disabled) { return; } + ts.resizable.toggleTextSelection( c, false ); + ts.resizable.stopResize( c, wo ); + ts.resizable.setHandlePosition( c, wo ); + }); + + // resizeEnd event triggered by scroller widget + $( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }); + + // right click to reset columns to default widths + c.$table + .bind( 'columnUpdate' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }) + .find( 'thead:first' ) + .add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) ) + .bind( 'contextmenu' + namespace, function() { + // $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset + var allowClick = wo.resizable_.storedSizes.length === 0; + ts.resizableReset( c.table ); + ts.resizable.setHandlePosition( c, wo ); + wo.resizable_.storedSizes = []; + return allowClick; + }); + + }, + + mouseMove : function( c, wo, event ) { + if ( wo.resizable_.mouseXPosition === 0 || !wo.resizable_.$target ) { return; } + // resize columns + var vars = wo.resizable_, + $next = vars.$next, + leftEdge = event.pageX - vars.mouseXPosition; + if ( vars.fullWidth ) { + vars.storedSizes[ vars.target ] += leftEdge; + vars.storedSizes[ vars.next ] -= leftEdge; + ts.resizable.setWidths( c, wo ); + + } else if ( vars.overflow ) { + c.$table.add( $( c.namespace + '_extra_table' ) ).width(function(i, w){ + return w + leftEdge; + }); + if ( !$next.length ) { + // if expanding right-most column, scroll the wrapper + vars.$wrap[0].scrollLeft = c.$table.width(); + } + } else { + vars.storedSizes[ vars.target ] += leftEdge; + ts.resizable.setWidths( c, wo ); + } + vars.mouseXPosition = event.pageX; + // dynamically update sticky header widths + c.$table.trigger('stickyHeadersUpdate'); + }, + + stopResize : function( c, wo ) { + var $this, column, + vars = wo.resizable_; + vars.storedSizes = []; + if ( ts.storage ) { + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + if ( wo.resizable !== false ) { + // save all column widths + ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes ); + } + } + vars.mouseXPosition = 0; + vars.$target = vars.$next = null; + // will update stickyHeaders, just in case, see #912 + c.$table.trigger('stickyHeadersUpdate'); + } +}; + +// this widget saves the column widths if +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: "resizable", + priority: 40, + options: { + resizable : true, + resizable_addLastColumn : false, + resizable_widths : [], + resizable_throttle : false, // set to true (5ms) or any number 0-10 range + resizable_targetLast : false + }, + init: function(table, thisWidget, c, wo) { + ts.resizable.init( c, wo ); + }, + remove: function( table, c, wo, refreshing ) { + if (wo.$resizable_container) { + var namespace = c.namespace + 'tsresize'; + c.$table.add( $( c.namespace + '_extra_table' ) ) + .removeClass('hasResizable') + .children( 'thead' ).unbind( 'contextmenu' + namespace ); + + wo.$resizable_container.remove(); + ts.resizable.toggleTextSelection( c, false ); + ts.resizableReset( table, refreshing ); + $( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace ); + } + } +}); + +ts.resizableReset = function( table, refreshing ) { + $( table ).each(function(){ + var index, $t, + c = this.config, + wo = c && c.widgetOptions; + if ( table && c && c.$headerIndexed.length ) { + for ( index = 0; index < c.columns; index++ ) { + $t = c.$headerIndexed[ index ]; + if ( wo.resizable_widths && wo.resizable_widths[ index ] ) { + $t.css( 'width', wo.resizable_widths[ index ] ); + } else if ( !$t.hasClass( 'resizable-false' ) ) { + // don't clear the width of any column that is not resizable + $t.css( 'width', '' ); + } + } + // reset stickyHeader widths + c.$table.trigger( 'stickyHeadersUpdate' ); + if ( ts.storage && !refreshing ) { + ts.storage( this, ts.css.resizableStorage, {} ); + } + } + }); +}; + +})( jQuery, window ); + +/*! Widget: saveSort */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +// this widget saves the last sort only if the +// saveSort widget option is true AND the +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: 'saveSort', + priority: 20, + options: { + saveSort : true + }, + init: function(table, thisWidget, c, wo) { + // run widget format before all other widgets are applied to the table + thisWidget.format(table, c, wo, true); + }, + format: function(table, c, wo, init) { + var stored, time, + $table = c.$table, + saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true + sortList = { "sortList" : c.sortList }; + if (c.debug) { + time = new Date(); + } + if ($table.hasClass('hasSaveSort')) { + if (saveSort && table.hasInitialized && ts.storage) { + ts.storage( table, 'tablesorter-savesort', sortList ); + if (c.debug) { + ts.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time); + } + } + } else { + // set table sort on initial run of the widget + $table.addClass('hasSaveSort'); + sortList = ''; + // get data + if (ts.storage) { + stored = ts.storage( table, 'tablesorter-savesort' ); + sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : ''; + if (c.debug) { + ts.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time); + } + $table.bind('saveSortReset', function(event) { + event.stopPropagation(); + ts.storage( table, 'tablesorter-savesort', '' ); + }); + } + // init is true when widget init is run, this will run this widget before all other widgets have initialized + // this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice. + if (init && sortList && sortList.length > 0) { + c.sortList = sortList; + } else if (table.hasInitialized && sortList && sortList.length > 0) { + // update sort change + $table.trigger('sorton', [sortList]); + } + } + }, + remove: function(table, c) { + c.$table.removeClass('hasSaveSort'); + // clear storage + if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); } + } +}); + +})(jQuery); + +return $.tablesorter; +})); diff --git a/dist/js/jquery.tablesorter.combined.min.js b/dist/js/jquery.tablesorter.combined.min.js new file mode 100644 index 0000000..6436ebc --- /dev/null +++ b/dist/js/jquery.tablesorter.combined.min.js @@ -0,0 +1,4 @@ +/*! tablesorter (FORK) - updated 06-07-2015 (v2.22.1)*/ +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){return function(a){"use strict";a.extend({tablesorter:new function(){function b(){var a=arguments[0],b=arguments.length>1?Array.prototype.slice.call(arguments):a;"undefined"!=typeof console&&"undefined"!=typeof console.log?console[/error/i.test(a)?"error":/warn/i.test(a)?"warn":"log"](b):alert(b)}function c(a,c){b(a+" ("+((new Date).getTime()-c.getTime())+"ms)")}function d(a){for(var b in a)return!1;return!0}function e(c,d,e,f){for(var g,h,i=u.parsers.length,j=!1,k="",l=!0;""===k&&l;)e++,d[e]?(j=d[e].cells[f],k=u.getElementText(c,j,f),h=a(j),c.debug&&b("Checking if value was empty on row "+e+", column: "+f+': "'+k+'"')):l=!1;for(;--i>=0;)if(g=u.parsers[i],g&&"text"!==g.id&&g.is&&g.is(k,c.table,j,h))return g;return u.getParserById("text")}function f(a,d){var f,g,h,i,j,k,l,m,n,o,p,q,r=a.table,s=0,t="";if(a.$tbodies=a.$table.children("tbody:not(."+a.cssInfoBlock+")"),p="undefined"==typeof d?a.$tbodies:d,q=p.length,0===q)return a.debug?b("Warning: *Empty table!* Not building a parser cache"):"";for(a.debug&&(o=new Date,b("Detecting parsers for each column")),g={extractors:[],parsers:[]};q>s;){if(f=p[s].rows,f.length)for(h=a.columns,i=0;h>i;i++)j=a.$headerIndexed[i],k=u.getColumnData(r,a.headers,i),n=u.getParserById(u.getData(j,k,"extractor")),m=u.getParserById(u.getData(j,k,"sorter")),l="false"===u.getData(j,k,"parser"),a.empties[i]=(u.getData(j,k,"empty")||a.emptyTo||(a.emptyToBottom?"bottom":"top")).toLowerCase(),a.strings[i]=(u.getData(j,k,"string")||a.stringTo||"max").toLowerCase(),l&&(m=u.getParserById("no-parser")),n||(n=!1),m||(m=e(a,f,-1,i)),a.debug&&(t+="column:"+i+"; extractor:"+n.id+"; parser:"+m.id+"; string:"+a.strings[i]+"; empty: "+a.empties[i]+"\n"),g.parsers[i]=m,g.extractors[i]=n;s+=g.parsers.length?q:1}a.debug&&(b(t?t:"No parsers detected"),c("Completed detecting parsers",o)),a.parsers=g.parsers,a.extractors=g.extractors}function g(d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t=d.config,v=t.parsers;if(t.$tbodies=t.$table.children("tbody:not(."+t.cssInfoBlock+")"),l="undefined"==typeof e?t.$tbodies:e,t.cache={},t.totalRows=0,!v)return t.debug?b("Warning: *Empty table!* Not building a cache"):"";for(t.debug&&(o=new Date),t.showProcessing&&u.isProcessing(d,!0),k=0;ki;++i)if(q={child:[],raw:[]},m=a(l[k].rows[i]),n=[],m.hasClass(t.cssChildRow)&&0!==i)for(g=f.normalized.length-1,r=f.normalized[g][t.columns],r.$row=r.$row.add(m),m.prev().hasClass(t.cssChildRow)||m.prev().addClass(u.css.cssHasChild),h=m.children("th, td"),g=r.child.length,r.child[g]=[],j=0;ji;i++)o.push(e[i][l.columns].$row),l.appender&&(!l.pager||l.pager.removeRows&&m.pager_removeRows||l.pager.ajax)||h.append(e[i][l.columns].$row);u.processTbody(a,h,!1)}l.appender&&l.appender(a,o),l.debug&&c("Rebuilt table",k),b||l.appender||u.applyWidget(a),a.isUpdating&&l.$table.trigger("updateComplete",a)}function i(a){return/^d/i.test(a)||1===a}function j(d){var e,f,g,h,j,k,m,n,o=d.config;for(o.headerList=[],o.headerContent=[],o.debug&&(m=new Date),o.columns=u.computeColumnIndex(o.$table.children("thead, tfoot").children("tr")),h=o.cssIcon?'':"",o.$headers=a(a.map(a(d).find(o.selectorHeaders),function(b,c){return f=a(b),f.parent().hasClass(o.cssIgnoreRow)?void 0:(e=u.getColumnData(d,o.headers,c,!0),o.headerContent[c]=f.html(),""===o.headerTemplate||f.find("."+u.css.headerIn).length||(j=o.headerTemplate.replace(/\{content\}/g,f.html()).replace(/\{icon\}/g,f.find("."+u.css.icon).length?"":h),o.onRenderTemplate&&(g=o.onRenderTemplate.apply(f,[c,j]),g&&"string"==typeof g&&(j=g)),f.html('
    '+j+"
    ")),o.onRenderHeader&&o.onRenderHeader.apply(f,[c,o,o.$table]),b.column=parseInt(f.attr("data-column"),10),b.order=i(u.getData(f,e,"sortInitialOrder")||o.sortInitialOrder)?[1,0,2]:[0,1,2],b.count=-1,b.lockedOrder=!1,k=u.getData(f,e,"lockedOrder")||!1,"undefined"!=typeof k&&k!==!1&&(b.order=b.lockedOrder=i(k)?[1,1,1]:[0,0,0]),f.addClass(u.css.header+" "+o.cssHeader),o.headerList[c]=b,f.parent().addClass(u.css.headerRow+" "+o.cssHeaderRow).attr("role","row"),o.tabIndex&&f.attr("tabindex",0),b)})),o.$headerIndexed=[],n=0;nb;b++)d=f.$headers.eq(b),e=u.getColumnData(a,f.headers,b,!0),c="false"===u.getData(d,e,"sorter")||"false"===u.getData(d,e,"parser"),d[0].sortDisabled=c,d[c?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+c),a.id&&(c?d.removeAttr("aria-controls"):d.attr("aria-controls",a.id))}function m(b){var c,d,e,f,g,h,i,j,k=b.config,l=k.sortList,m=l.length,n=u.css.sortNone+" "+k.cssNone,o=[u.css.sortAsc+" "+k.cssAsc,u.css.sortDesc+" "+k.cssDesc],p=[k.cssIconAsc,k.cssIconDesc,k.cssIconNone],q=["ascending","descending"],r=a(b).find("tfoot tr").children().add(a(k.namespace+"_extra_headers")).removeClass(o.join(" "));for(k.$headers.removeClass(o.join(" ")).addClass(n).attr("aria-sort","none").find("."+u.css.icon).removeClass(p.join(" ")).addClass(p[2]),e=0;m>e;e++)if(2!==l[e][1]&&(c=k.$headers.not(".sorter-false").filter('[data-column="'+l[e][0]+'"]'+(1===m?":last":"")),c.length)){for(f=0;fe;e++)h=g.eq(e),h.length&&(d=g[e],i=d.order[(d.count+1)%(k.sortReset?3:2)],j=a.trim(h.text())+": "+u.language[h.hasClass(u.css.sortAsc)?"sortAsc":h.hasClass(u.css.sortDesc)?"sortDesc":"sortNone"]+u.language[0===i?"nextAsc":1===i?"nextDesc":"nextNone"],h.attr("aria-label",j))}function n(b,c){var d,e,f,g,h,i,j,k,l=b.config,m=c||l.sortList,n=m.length;for(l.sortList=[],h=0;n>h;h++)if(k=m[h],d=parseInt(k[0],10),d=0?e:f[1]%(l.sortReset?3:2)}}function o(a,b){return a&&a[b]?a[b].type||"":""}function p(b,c,d){if(b.isUpdating)return setTimeout(function(){p(b,c,d)},50);var e,f,g,i,j,k,l,n=b.config,o=!d[n.sortMultiSortKey],r=n.$table,s=n.$headers.length;if(r.trigger("sortStart",b),c.count=d[n.sortResetKey]?2:(c.count+1)%(n.sortReset?3:2),n.sortRestart)for(f=c,g=0;s>g;g++)l=n.$headers.eq(g),l[0]===f||!o&&l.is("."+u.css.sortDesc+",."+u.css.sortAsc)||(l[0].count=-1);if(f=parseInt(a(c).attr("data-column"),10),o){if(n.sortList=[],null!==n.sortForce)for(e=n.sortForce,i=0;ij&&(n.sortList.push([f,j]),c.colSpan>1))for(i=1;i1)for(i=0;i=0&&n.sortList.splice(k,1);if(u.isValueInArray(f,n.sortList)>=0)for(i=0;ij&&(n.sortList.push([f,j]),c.colSpan>1))for(i=1;ie;e++)i=q.cache[e].colMax,j=q.cache[e].normalized,j.sort(function(c,d){for(b=0;t>b;b++){if(g=s[b][0],k=s[b][1],p=0===k,q.sortStable&&c[g]===d[g]&&1===t)return c[q.columns].order-d[q.columns].order;if(f=/n/i.test(o(q.parsers,g)),f&&q.strings[g]?(f="boolean"==typeof q.string[q.strings[g]]?(p?1:-1)*(q.string[q.strings[g]]?-1:1):q.strings[g]?q.string[q.strings[g]]||0:0,l=q.numberSorter?q.numberSorter(c[g],d[g],p,i[g],a):u["sortNumeric"+(p?"Asc":"Desc")](c[g],d[g],f,i[g],g,a)):(m=p?c:d,n=p?d:c,l="function"==typeof r?r(m[g],n[g],p,g,a):"object"==typeof r&&r.hasOwnProperty(g)?r[g](m[g],n[g],p,g,a):u["sortNatural"+(p?"Asc":"Desc")](c[g],d[g],g,a,q)),l)return l}return c[q.columns].order-d[q.columns].order});q.debug&&c("Sorting on "+s.toString()+" and dir "+k+" time",h)}}function r(b,c){b.table.isUpdating&&b.$table.trigger("updateComplete",b.table),a.isFunction(c)&&c(b.table)}function s(b,c,d){var e=a.isArray(c)?c:b.sortList,f="undefined"==typeof c?b.resort:c;f===!1||b.serverSideSorting||b.table.isProcessing?(r(b,d),u.applyWidget(b.table,!1)):e.length?b.$table.trigger("sorton",[e,function(){r(b,d)},!0]):b.$table.trigger("sortReset",[function(){r(b,d),u.applyWidget(b.table,!1)}])}function t(b){var c=b.config,e=c.$table,i="sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(c.namespace+" ");e.unbind(i.replace(/\s+/g," ")).bind("sortReset"+c.namespace,function(d,e){d.stopPropagation(),c.sortList=[],m(b),q(b),h(b),a.isFunction(e)&&e(b)}).bind("updateAll"+c.namespace,function(a,d,e){a.stopPropagation(),b.isUpdating=!0,u.refreshWidgets(b,!0,!0),j(b),u.bindEvents(b,c.$headers,!0),t(b),k(b,d,e)}).bind("update"+c.namespace+" updateRows"+c.namespace,function(a,c,d){a.stopPropagation(),b.isUpdating=!0,l(b),k(b,c,d)}).bind("updateCell"+c.namespace,function(d,f,g,h){d.stopPropagation(),b.isUpdating=!0,e.find(c.selectorRemove).remove();var i,j,k,l,m=c.$tbodies,n=a(f),o=m.index(a.fn.closest?n.closest("tbody"):n.parents("tbody").filter(":first")),p=c.cache[o],q=a.fn.closest?n.closest("tr"):n.parents("tr").filter(":first");f=n[0],m.length&&o>=0&&(j=m.eq(o).find("tr").index(q),l=p.normalized[j],k=n.index(),i=u.getParsedText(c,f,k),l[k]=i,l[c.columns].$row=q,"numeric"===(c.parsers[k].type||"").toLowerCase()&&(p.colMax[k]=Math.max(Math.abs(i)||0,p.colMax[k]||0)),i="undefined"!==g?g:c.resort,i!==!1?s(c,i,h):(a.isFunction(h)&&h(b),c.$table.trigger("updateComplete",c.table)))}).bind("addRows"+c.namespace,function(e,g,h,i){if(e.stopPropagation(),b.isUpdating=!0,d(c.cache))l(b),k(b,h,i);else{g=a(g).attr("role","row");var j,m,n,o,p,q=g.filter("tr").length,r=c.$tbodies.index(g.parents("tbody").filter(":first"));for(c.parsers&&c.parsers.length||f(c),j=0;q>j;j++){for(n=g[j].cells.length,p=[],o={child:[],$row:g.eq(j),order:c.cache[r].normalized.length},m=0;n>m;m++)p[m]=u.getParsedText(c,g[j].cells[m],m),"numeric"===(c.parsers[m].type||"").toLowerCase()&&(c.cache[r].colMax[m]=Math.max(Math.abs(p[m])||0,c.cache[r].colMax[m]||0));p.push(o),c.cache[r].normalized.push(p)}s(c,h,i)}}).bind("updateComplete"+c.namespace,function(){b.isUpdating=!1}).bind("sorton"+c.namespace,function(c,f,i,j){var k=b.config;c.stopPropagation(),e.trigger("sortStart",this),n(b,f),m(b),k.delayInit&&d(k.cache)&&g(b),e.trigger("sortBegin",this),q(b),h(b,j),e.trigger("sortEnd",this),u.applyWidget(b),a.isFunction(i)&&i(b)}).bind("appendCache"+c.namespace,function(c,d,e){c.stopPropagation(),h(b,e),a.isFunction(d)&&d(b)}).bind("updateCache"+c.namespace,function(d,e,h){c.parsers&&c.parsers.length||f(c,h),g(b,h),a.isFunction(e)&&e(b)}).bind("applyWidgetId"+c.namespace,function(a,d){a.stopPropagation(),u.getWidgetById(d).format(b,c,c.widgetOptions)}).bind("applyWidgets"+c.namespace,function(a,c){a.stopPropagation(),u.applyWidget(b,c)}).bind("refreshWidgets"+c.namespace,function(a,c,d){a.stopPropagation(),u.refreshWidgets(b,c,d)}).bind("destroy"+c.namespace,function(a,c,d){a.stopPropagation(),u.destroy(b,c,d)}).bind("resetToLoadState"+c.namespace,function(){u.removeWidget(b,!0,!1),c=a.extend(!0,u.defaults,c.originalSettings),b.hasInitialized=!1,u.setup(b,c)})}var u=this;u.version="2.22.1",u.parsers=[],u.widgets=[],u.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",textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,widgets:[],widgetOptions:{zebra:["even","odd"]},initWidgets:!0,widgetClass:"widget-{name}",initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",cssInfoBlock:"tablesorter-infoOnly",cssNoSort:"tablesorter-noSort",cssIgnoreRow:"tablesorter-ignoreRow",pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[]},u.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"},u.language={sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"},u.instanceMethods={},u.log=b,u.benchmark=c,u.getElementText=function(b,c,d){if(!c)return"";var e,f=b.textExtraction||"",g=c.jquery?c:a(c);return"string"==typeof f?a.trim(("basic"===f?g.attr(b.textAttribute)||c.textContent:c.textContent)||g.text()):"function"==typeof f?a.trim(f(g[0],b.table,d)):"function"==typeof(e=u.getColumnData(b.table,f,d))?a.trim(e(g[0],b.table,d)):a.trim(g[0].textContent||g.text())},u.getParsedText=function(a,b,c,d){"undefined"==typeof d&&(d=u.getElementText(a,b,c));var e=""+d,f=a.parsers[c],g=a.extractors[c];return f&&(g&&"function"==typeof g.format&&(d=g.format(d,a.table,b,c)),e="no-parser"===f.id?"":f.format(""+d,a.table,b,c),a.ignoreCase&&"string"==typeof e&&(e=e.toLowerCase())),e},u.construct=function(b){return this.each(function(){var c=this,d=a.extend(!0,{},u.defaults,b,u.instanceMethods);d.originalSettings=b,!c.hasInitialized&&u.buildTable&&"TABLE"!==this.nodeName?u.buildTable(c,d):u.setup(c,d)})},u.setup=function(c,d){if(!c||!c.tHead||0===c.tBodies.length||c.hasInitialized===!0)return d.debug?b("ERROR: stopping initialization! No table, thead, tbody or tablesorter has already been initialized"):"";var e="",h=a(c),i=a.metadata;c.hasInitialized=!1,c.isProcessing=!0,c.config=d,a.data(c,"tablesorter",d),d.debug&&a.data(c,"startoveralltimer",new Date),d.supportsDataObject=function(a){return a[0]=parseInt(a[0],10),a[0]>1||1===a[0]&&parseInt(a[1],10)>=4}(a.fn.jquery.split(".")),d.string={max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1},d.emptyTo=d.emptyTo.toLowerCase(),d.stringTo=d.stringTo.toLowerCase(),/tablesorter\-/.test(h.attr("class"))||(e=""!==d.theme?" tablesorter-"+d.theme:""),d.table=c,d.$table=h.addClass(u.css.table+" "+d.tableClass+e).attr("role","grid"),d.$headers=h.find(d.selectorHeaders),d.namespace?d.namespace="."+d.namespace.replace(/\W/g,""):d.namespace=".tablesorter"+Math.random().toString(16).slice(2),d.$table.children().children("tr").attr("role","row"),d.$tbodies=h.children("tbody:not(."+d.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"}),d.$table.children("caption").length&&(e=d.$table.children("caption")[0],e.id||(e.id=d.namespace.slice(1)+"caption"),d.$table.attr("aria-labelledby",e.id)),d.widgetInit={},d.textExtraction=d.$table.attr("data-text-extraction")||d.textExtraction||"basic",j(c),u.fixColumnWidth(c),u.applyWidgetOptions(c,d),f(d),d.totalRows=0,d.delayInit||g(c),u.bindEvents(c,d.$headers,!0),t(c),d.supportsDataObject&&"undefined"!=typeof h.data().sortlist?d.sortList=h.data().sortlist:i&&h.metadata()&&h.metadata().sortlist&&(d.sortList=h.metadata().sortlist),u.applyWidget(c,!0),d.sortList.length>0?h.trigger("sorton",[d.sortList,{},!d.initWidgets,!0]):(m(c),d.initWidgets&&u.applyWidget(c,!1)),d.showProcessing&&h.unbind("sortBegin"+d.namespace+" sortEnd"+d.namespace).bind("sortBegin"+d.namespace+" sortEnd"+d.namespace,function(a){clearTimeout(d.processTimer),u.isProcessing(c),"sortBegin"===a.type&&(d.processTimer=setTimeout(function(){u.isProcessing(c,!0)},500))}),c.hasInitialized=!0,c.isProcessing=!1,d.debug&&u.benchmark("Overall initialization time",a.data(c,"startoveralltimer")),h.trigger("tablesorter-initialized",c),"function"==typeof d.initialized&&d.initialized(c)},u.fixColumnWidth=function(b){b=a(b)[0];var c,d,e,f,g,h=b.config,i=h.$table.children("colgroup");if(i.length&&i.hasClass(u.css.colgroup)&&i.remove(),h.widthFixed&&0===h.$table.children("colgroup").length){for(i=a(''),c=h.$table.width(),e=h.$tbodies.find("tr:first").children(":visible"),f=e.length,g=0;f>g;g++)d=parseInt(e.eq(g).width()/c*1e3,10)/10+"%",i.append(a("").css("width",d));h.$table.prepend(i)}},u.getColumnData=function(b,c,d,e,f){if("undefined"!=typeof c&&null!==c){b=a(b)[0];var g,h,i=b.config,j=f||i.$headers,k=i.$headerIndexed&&i.$headerIndexed[d]||j.filter('[data-column="'+d+'"]:last');if(c[d])return e?c[d]:c[j.index(k)];for(h in c)if("string"==typeof h&&(g=k.filter(h).add(k.find(h)),g.length))return c[h]}},u.computeColumnIndex=function(b){var c,d,e,f,g,h,i,j,k,l,m,n,o=[],p=[],q={};for(c=0;ce;e++)for("undefined"==typeof o[e]&&(o[e]=[]),p=o[e],f=n;n+m>f;f++)p[f]="x"}return p.length},u.isProcessing=function(b,c,d){b=a(b);var e=b[0].config,f=d||b.find("."+u.css.header);c?("undefined"!=typeof d&&e.sortList.length>0&&(f=f.filter(function(){return this.sortDisabled?!1:u.isValueInArray(parseFloat(a(this).attr("data-column")),e.sortList)>=0})),b.add(f).addClass(u.css.processing+" "+e.cssProcessing)):b.add(f).removeClass(u.css.processing+" "+e.cssProcessing)},u.processTbody=function(b,c,d){b=a(b)[0];var e;return d?(b.isProcessing=!0,c.before(''),e=a.fn.detach?c.detach():c.remove()):(e=a(b).find("span.tablesorter-savemyplace"),c.insertAfter(e),e.remove(),void(b.isProcessing=!1))},u.clearTableBody=function(b){a(b)[0].config.$tbodies.children().detach()},u.bindEvents=function(b,c,e){b=a(b)[0];var f,h=null,i=b.config;e!==!0&&(c.addClass(i.namespace.slice(1)+"_extra_headers"),f=a.fn.closest?c.closest("table")[0]:c.parents("table")[0],f&&"TABLE"===f.nodeName&&f!==b&&a(f).addClass(i.namespace.slice(1)+"_extra_table")),f=(i.pointerDown+" "+i.pointerUp+" "+i.pointerClick+" sort keyup ").replace(/\s+/g," ").split(" ").join(i.namespace+" "),c.find(i.selectorSort).add(c.filter(i.selectorSort)).unbind(f).bind(f,function(e,f){var j,k,l=a(e.target),m=" "+e.type+" ";if(!(1!==(e.which||e.button)&&!m.match(" "+i.pointerClick+" | sort | keyup ")||" keyup "===m&&13!==e.which||m.match(" "+i.pointerClick+" ")&&"undefined"!=typeof e.which||m.match(" "+i.pointerUp+" ")&&h!==e.target&&f!==!0)){if(m.match(" "+i.pointerDown+" "))return h=e.target,k=l.jquery.split("."),void("1"===k[0]&&k[1]<4&&e.preventDefault());if(h=null,/(input|select|button|textarea)/i.test(e.target.nodeName)||l.hasClass(i.cssNoSort)||l.parents("."+i.cssNoSort).length>0||l.parents("button").length>0)return!i.cancelSelection;i.delayInit&&d(i.cache)&&g(b),j=a.fn.closest?a(this).closest("th, td")[0]:/TH|TD/.test(this.nodeName)?this:a(this).parents("th, td")[0],j=i.$headers[c.index(j)],j.sortDisabled||p(b,j,e)}}),i.cancelSelection&&c.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})},u.restoreHeaders=function(b){var c,d,e=a(b)[0].config,f=e.$table.find(e.selectorHeaders),g=f.length;for(c=0;g>c;c++)d=f.eq(c),d.find("."+u.css.headerIn).length&&d.html(e.headerContent[c])},u.destroy=function(b,c,d){if(b=a(b)[0],b.hasInitialized){u.removeWidget(b,!0,!1);var e,f=a(b),g=b.config,h=f.find("thead:first"),i=h.find("tr."+u.css.headerRow).removeClass(u.css.headerRow+" "+g.cssHeaderRow),j=f.find("tfoot:first > tr").children("th, td");c===!1&&a.inArray("uitheme",g.widgets)>=0&&(f.trigger("applyWidgetId",["uitheme"]),f.trigger("applyWidgetId",["zebra"])),h.find("tr").not(i).remove(),e="sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache "+"applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState ".split(" ").join(g.namespace+" "),f.removeData("tablesorter").unbind(e.replace(/\s+/g," ")),g.$headers.add(j).removeClass([u.css.header,g.cssHeader,g.cssAsc,g.cssDesc,u.css.sortAsc,u.css.sortDesc,u.css.sortNone].join(" ")).removeAttr("data-column").removeAttr("aria-label").attr("aria-disabled","true"),i.find(g.selectorSort).unbind("mousedown mouseup keypress ".split(" ").join(g.namespace+" ").replace(/\s+/g," ")),u.restoreHeaders(b),f.toggleClass(u.css.table+" "+g.tableClass+" tablesorter-"+g.theme,c===!1),b.hasInitialized=!1,delete b.config.cache,"function"==typeof d&&d(b)}},u.regex={chunk:/(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i},u.sortNatural=function(a,b){if(a===b)return 0;var c,d,e,f,g,h,i,j,k=u.regex;if(k.hex.test(b)){if(d=parseInt(a.match(k.hex),16),f=parseInt(b.match(k.hex),16),f>d)return-1;if(d>f)return 1}for(c=a.replace(k.chunk,"\\0$1\\0").replace(k.chunks,"").split("\\0"),e=b.replace(k.chunk,"\\0$1\\0").replace(k.chunks,"").split("\\0"),j=Math.max(c.length,e.length),i=0;j>i;i++){if(g=isNaN(c[i])?c[i]||0:parseFloat(c[i])||0,h=isNaN(e[i])?e[i]||0:parseFloat(e[i])||0,isNaN(g)!==isNaN(h))return isNaN(g)?1:-1;if(typeof g!=typeof h&&(g+="",h+=""),h>g)return-1;if(g>h)return 1}return 0},u.sortNaturalAsc=function(a,b,c,d,e){if(a===b)return 0;var f=e.string[e.empties[c]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:-f||-1:""===b&&0!==f?"boolean"==typeof f?f?1:-1:f||1:u.sortNatural(a,b)},u.sortNaturalDesc=function(a,b,c,d,e){if(a===b)return 0;var f=e.string[e.empties[c]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:f||1:""===b&&0!==f?"boolean"==typeof f?f?1:-1:-f||-1:u.sortNatural(b,a)},u.sortText=function(a,b){return a>b?1:b>a?-1:0},u.getTextValue=function(a,b,c){if(c){var d,e=a?a.length:0,f=c+b;for(d=0;e>d;d++)f+=a.charCodeAt(d);return b*f}return 0},u.sortNumericAsc=function(a,b,c,d,e,f){if(a===b)return 0;var g=f.config,h=g.string[g.empties[e]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:-h||-1:""===b&&0!==h?"boolean"==typeof h?h?1:-1:h||1:(isNaN(a)&&(a=u.getTextValue(a,c,d)),isNaN(b)&&(b=u.getTextValue(b,c,d)),a-b)},u.sortNumericDesc=function(a,b,c,d,e,f){if(a===b)return 0;var g=f.config,h=g.string[g.empties[e]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:h||1:""===b&&0!==h?"boolean"==typeof h?h?1:-1:-h||-1:(isNaN(a)&&(a=u.getTextValue(a,c,d)),isNaN(b)&&(b=u.getTextValue(b,c,d)),b-a)},u.sortNumeric=function(a,b){return a-b},u.characterEquivalents={a:"áàâãäąå",A:"ÁÀÂÃÄĄÅ",c:"çćč",C:"ÇĆČ",e:"éèêëěę",E:"ÉÈÊËĚĘ",i:"íìİîïı",I:"ÍÌİÎÏ",o:"óòôõöō",O:"ÓÒÔÕÖŌ",ss:"ß",SS:"ẞ",u:"úùûüů",U:"ÚÙÛÜŮ"},u.replaceAccents=function(a){var b,c="[",d=u.characterEquivalents;if(!u.characterRegex){u.characterRegexArray={};for(b in d)"string"==typeof b&&(c+=d[b],u.characterRegexArray[b]=new RegExp("["+d[b]+"]","g"));u.characterRegex=new RegExp(c+"]")}if(u.characterRegex.test(a))for(b in d)"string"==typeof b&&(a=a.replace(u.characterRegexArray[b],b));return a},u.isValueInArray=function(a,b){var c,d=b.length;for(c=0;d>c;c++)if(b[c][0]===a)return c;return-1},u.addParser=function(a){var b,c=u.parsers.length,d=!0;for(b=0;c>b;b++)u.parsers[b].id.toLowerCase()===a.id.toLowerCase()&&(d=!1);d&&u.parsers.push(a)},u.addInstanceMethods=function(b){a.extend(u.instanceMethods,b)},u.getParserById=function(a){if("false"==a)return!1;var b,c=u.parsers.length;for(b=0;c>b;b++)if(u.parsers[b].id.toLowerCase()===a.toString().toLowerCase())return u.parsers[b];return!1},u.addWidget=function(a){u.widgets.push(a)},u.hasWidget=function(b,c){return b=a(b),b.length&&b[0].config&&b[0].config.widgetInit[c]||!1},u.getWidgetById=function(a){var b,c,d=u.widgets.length;for(b=0;d>b;b++)if(c=u.widgets[b],c&&c.hasOwnProperty("id")&&c.id.toLowerCase()===a.toLowerCase())return c},u.applyWidgetOptions=function(b,c){var d,e,f=c.widgets.length,g=c.widgetOptions;if(f)for(d=0;f>d;d++)e=u.getWidgetById(c.widgets[d]),e&&"options"in e&&(g=b.config.widgetOptions=a.extend(!0,{},e.options,g))},u.applyWidget=function(b,d,e){b=a(b)[0];var f,g,h,i,j,k,l,m=b.config,n=m.widgetOptions,o=" "+m.table.className+" ",p=[];if(d===!1||!b.hasInitialized||!b.isApplyingWidgets&&!b.isUpdating){if(m.debug&&(i=new Date),l=new RegExp("\\s"+m.widgetClass.replace(/\{name\}/i,"([\\w-]+)")+"\\s","g"),o.match(l)&&(k=o.match(l)))for(g=k.length,f=0;g>f;f++)m.widgets.push(k[f].replace(l,"$1"));if(m.widgets.length){for(b.isApplyingWidgets=!0,m.widgets=a.grep(m.widgets,function(b,c){return a.inArray(b,m.widgets)===c}),h=m.widgets||[],g=h.length,f=0;g>f;f++)l=u.getWidgetById(h[f]),l&&l.id&&(l.priority||(l.priority=10),p[f]=l);for(p.sort(function(a,b){return a.priorityf;f++)p[f]&&((d||!m.widgetInit[p[f].id])&&(m.widgetInit[p[f].id]=!0,b.hasInitialized&&u.applyWidgetOptions(b,m),"init"in p[f]&&(m.debug&&(j=new Date),p[f].init(b,p[f],m,n),m.debug&&u.benchmark("Initializing "+p[f].id+" widget",j))),!d&&"format"in p[f]&&(m.debug&&(j=new Date),p[f].format(b,m,n,!1),m.debug&&u.benchmark((d?"Initializing ":"Applying ")+p[f].id+" widget",j)));d||"function"!=typeof e||e(b)}setTimeout(function(){b.isApplyingWidgets=!1,a.data(b,"lastWidgetApplication",new Date)},0),m.debug&&(k=m.widgets.length,c("Completed "+(d===!0?"initializing ":"applying ")+k+" widget"+(1!==k?"s":""),i))}},u.removeWidget=function(c,d,e){c=a(c)[0];var f,g,h,i,j=c.config;if(d===!0)for(d=[],i=u.widgets.length,h=0;i>h;h++)g=u.widgets[h],g&&g.id&&d.push(g.id);else d=(a.isArray(d)?d.join(","):d||"").toLowerCase().split(/[\s,]+/);for(i=d.length,f=0;i>f;f++)g=u.getWidgetById(d[f]),h=a.inArray(d[f],j.widgets),g&&"remove"in g&&(j.debug&&h>=0&&b('Removing "'+d[f]+'" widget'),g.remove(c,j,j.widgetOptions,e),j.widgetInit[d[f]]=!1),h>=0&&e!==!0&&j.widgets.splice(h,1)},u.refreshWidgets=function(b,c,d){b=a(b)[0];var e,f=b.config,g=f.widgets,h=u.widgets,i=h.length,j=[],k=function(b){a(b).trigger("refreshComplete")};for(e=0;i>e;e++)h[e]&&h[e].id&&(c||a.inArray(h[e].id,g)<0)&&j.push(h[e].id);u.removeWidget(b,j.join(","),!0),d!==!0?(u.applyWidget(b,c||!1,k),c&&u.applyWidget(b,!1,k)):k(b)},u.getColumnText=function(b,c,e){b=a(b)[0];var f,g,h,i,j,k,l,m,n,o,p="function"==typeof e,q="all"===c,r={raw:[],parsed:[],$cell:[]},s=b.config;if(!d(s)){for(j=s.$tbodies.length,f=0;j>f;f++)for(h=s.cache[f].normalized,k=h.length,g=0;k>g;g++)o=!0,i=h[g],m=q?i.slice(0,s.columns):i[c],i=i[s.columns],l=q?i.raw:i.raw[c],n=q?i.$row.children():i.$row.children().eq(c),p&&(o=e({tbodyIndex:f,rowIndex:g,parsed:m,raw:l,$row:i.$row,$cell:n})),o!==!1&&(r.parsed.push(m),r.raw.push(l),r.$cell.push(n));return r}},u.getData=function(b,c,d){var e,f,g="",h=a(b);return h.length?(e=a.metadata?h.metadata():!1,f=" "+(h.attr("class")||""),"undefined"!=typeof h.data(d)||"undefined"!=typeof h.data(d.toLowerCase())?g+=h.data(d)||h.data(d.toLowerCase()):e&&"undefined"!=typeof e[d]?g+=e[d]:c&&"undefined"!=typeof c[d]?g+=c[d]:" "!==f&&f.match(" "+d+"-")&&(g=f.match(new RegExp("\\s"+d+"-([\\w-]+)"))[1]||""),a.trim(g)):""},u.formatFloat=function(b,c){if("string"!=typeof b||""===b)return b;var d,e=c&&c.config?c.config.usNumberFormat!==!1:"undefined"!=typeof c?c:!0;return b=e?b.replace(/,/g,""):b.replace(/[\s|\.]/g,"").replace(/,/g,"."),/^\s*\([.\d]+\)/.test(b)&&(b=b.replace(/^\s*\(([.\d]+)\)/,"-$1")),d=parseFloat(b),isNaN(d)?a.trim(b):d},u.isDigit=function(a){return isNaN(a)?/^[\-+(]?\d+[)]?$/.test(a.toString().replace(/[,.'"\s]/g,"")):""!==a}}});var b=a.tablesorter;a.fn.extend({tablesorter:b.construct}),b.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"}),b.addParser({id:"text",is:function(){return!0},format:function(c,d){var e=d.config;return c&&(c=a.trim(e.ignoreCase?c.toLocaleLowerCase():c),c=e.sortLocaleCompare?b.replaceAccents(c):c),c},type:"text"}),b.addParser({id:"digit",is:function(a){return b.isDigit(a)},format:function(c,d){var e=b.formatFloat((c||"").replace(/[^\w,. \-()]/g,""),d);return c&&"number"==typeof e?e:c?a.trim(c&&d.config.ignoreCase?c.toLocaleLowerCase():c):c},type:"numeric"}),b.addParser({id:"currency",is:function(a){return/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/.test((a||"").replace(/[+\-,. ]/g,""))},format:function(c,d){var e=b.formatFloat((c||"").replace(/[^\w,. \-()]/g,""),d);return c&&"number"==typeof e?e:c?a.trim(c&&d.config.ignoreCase?c.toLocaleLowerCase():c):c},type:"numeric"}),b.addParser({id:"url",is:function(a){return/^(https?|ftp|file):\/\//.test(a)},format:function(b){return b?a.trim(b.replace(/(https?|ftp|file):\/\//,"")):b},parsed:!0,type:"text"}),b.addParser({id:"isoDate",is:function(a){return/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/.test(a)},format:function(a,b){var c=a?new Date(a.replace(/-/g,"/")):a;return c instanceof Date&&isFinite(c)?c.getTime():a},type:"numeric"}),b.addParser({id:"percent",is:function(a){return/(\d\s*?%|%\s*?\d)/.test(a)&&a.length<15},format:function(a,c){return a?b.formatFloat(a.replace(/%/g,""),c):a},type:"numeric"}),b.addParser({id:"image",is:function(a,b,c,d){return d.find("img").length>0},format:function(b,c,d){return a(d).find("img").attr(c.config.imgAttr||"alt")||b},parsed:!0,type:"text"}),b.addParser({id:"usLongDate",is:function(a){return/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i.test(a)||/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i.test(a); +},format:function(a,b){var c=a?new Date(a.replace(/(\S)([AP]M)$/i,"$1 $2")):a;return c instanceof Date&&isFinite(c)?c.getTime():a},type:"numeric"}),b.addParser({id:"shortDate",is:function(a){return/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/.test((a||"").replace(/\s+/g," ").replace(/[\-.,]/g,"/"))},format:function(a,c,d,e){if(a){var f,g,h=c.config,i=h.$headerIndexed[e],j=i.length&&i[0].dateFormat||b.getData(i,b.getColumnData(c,h.headers,e),"dateFormat")||h.dateFormat;return g=a.replace(/\s+/g," ").replace(/[\-.,]/g,"/"),"mmddyyyy"===j?g=g.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$1/$2"):"ddmmyyyy"===j?g=g.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$2/$1"):"yyyymmdd"===j&&(g=g.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,"$1/$2/$3")),f=new Date(g),f instanceof Date&&isFinite(f)?f.getTime():a}return a},type:"numeric"}),b.addParser({id:"time",is:function(a){return/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i.test(a)},format:function(a,b){var c=a?new Date("2000/01/01 "+a.replace(/(\S)([AP]M)$/i,"$1 $2")):a;return c instanceof Date&&isFinite(c)?c.getTime():a},type:"numeric"}),b.addParser({id:"metadata",is:function(){return!1},format:function(b,c,d){var e=c.config,f=e.parserMetadataName?e.parserMetadataName:"sortValue";return a(d).metadata()[f]},type:"numeric"}),b.addWidget({id:"zebra",priority:90,format:function(b,c,d){var e,f,g,h,i,j,k,l,m=new RegExp(c.cssChildRow,"i"),n=c.$tbodies.add(a(c.namespace+"_extra_table").children("tbody:not(."+c.cssInfoBlock+")"));for(c.debug&&(i=new Date),j=0;jk;k++)f=e.eq(k),m.test(f[0].className)||g++,h=g%2===0,f.removeClass(d.zebra[h?1:0]).addClass(d.zebra[h?0:1])},remove:function(a,c,d,e){if(!e){var f,g,h=c.$tbodies,i=(d.zebra||["even","odd"]).join(" ");for(f=0;f
    ')}),d.cssIcon&&t.find("."+b.css.icon).removeClass(q?[n.icons,p].join(" "):"").addClass(v.icons||""),s.hasClass("hasFilters")&&s.children("thead").children("."+b.css.filterRow).removeClass(q?n.filterRow||"":"").addClass(v.filterRow||"")),f=0;f1)))for(m=1;q>m;m++)k.eq(p[m][0]).addClass(r[m]||r[s])}),b.processTbody(c,f,!1);if(i=e.columns_thead!==!1?["thead tr"]:[],e.columns_tfoot!==!1&&i.push("tfoot tr"),i.length&&(h=n.find(i.join(",")).children().removeClass(l),q))for(m=0;q>m;m++)h.filter('[data-column="'+p[m][0]+'"]').addClass(r[m]||r[s])},remove:function(c,d,e){var f,g,h=d.$tbodies,i=(e.columns||["primary","secondary","tertiary"]).join(" ");for(d.$headers.removeClass(i),d.$table.children("tfoot").children("tr").children("th, td").removeClass(i),f=0;f=]/g,query:"(q|query)"},types:{regex:function(a,c){if(b.filter.regex.regex.test(c.filter)){var d,e=c.filter_regexCache[c.index]||b.filter.regex.regex.exec(c.filter),f=e instanceof RegExp;try{f||(c.filter_regexCache[c.index]=e=new RegExp(e[1],e[2])),d=e.test(c.exact)}catch(g){d=!1}return d}return null},operators:function(c,d){if(/^[<>]=?/.test(d.iFilter)&&""!==d.iExact){var e,f,g,h=c.table,i=d.index,j=d.parsed[i],k=b.formatFloat(d.iFilter.replace(b.filter.regex.operators,""),h),l=c.parsers[i],m=k;return(j||"numeric"===l.type)&&(g=a.trim(""+d.iFilter.replace(b.filter.regex.operators,"")),f=b.filter.parseFilter(c,g,i,!0),k="number"!=typeof f||""===f||isNaN(f)?k:f),!j&&"numeric"!==l.type||isNaN(k)||"undefined"==typeof d.cache?(g=isNaN(d.iExact)?d.iExact.replace(b.filter.regex.nondigit,""):d.iExact,e=b.formatFloat(g,h)):e=d.cache,/>/.test(d.iFilter)?f=/>=/.test(d.iFilter)?e>=k:e>k:/=e:k>e),f||""!==m||(f=!0),f}return null},notMatch:function(c,d){if(/^\!/.test(d.iFilter)){var e,f=d.iFilter.replace("!",""),g=b.filter.parseFilter(c,f,d.index,d.parsed[d.index])||"";return b.filter.regex.exact.test(g)?(g=g.replace(b.filter.regex.exact,""),""===g?!0:a.trim(g)!==d.iExact):(e=d.iExact.search(a.trim(g)),""===g?!0:!(c.widgetOptions.filter_startsWith?0===e:e>=0))}return null},exact:function(c,d){if(b.filter.regex.exact.test(d.iFilter)){var e=d.iFilter.replace(b.filter.regex.exact,""),f=b.filter.parseFilter(c,e,d.index,d.parsed[d.index])||"";return d.anyMatch?a.inArray(f,d.rowArray)>=0:f==d.iExact}return null},and:function(c,d){if(b.filter.regex.andTest.test(d.filter)){for(var e=d.index,f=d.parsed[e],g=d.iFilter.split(b.filter.regex.andSplit),h=d.iExact.search(a.trim(b.filter.parseFilter(c,g[0],e,f)))>=0,i=g.length-1;h&&i;)h=h&&d.iExact.search(a.trim(b.filter.parseFilter(c,g[i],e,f)))>=0,i--;return h}return null},range:function(a,c){if(b.filter.regex.toTest.test(c.iFilter)){var d,e,f,g,h=a.table,i=c.index,j=c.parsed[i],k=c.iFilter.split(b.filter.regex.toSplit);return e=k[0].replace(b.filter.regex.nondigit,"")||"",f=b.formatFloat(b.filter.parseFilter(a,e,i,j),h),e=k[1].replace(b.filter.regex.nondigit,"")||"",g=b.formatFloat(b.filter.parseFilter(a,e,i,j),h),(j||"numeric"===a.parsers[i].type)&&(d=a.parsers[i].format(""+k[0],h,a.$headers.eq(i),i),f=""===d||isNaN(d)?f:d,d=a.parsers[i].format(""+k[1],h,a.$headers.eq(i),i),g=""===d||isNaN(d)?g:d),!j&&"numeric"!==a.parsers[i].type||isNaN(f)||isNaN(g)?(e=isNaN(c.iExact)?c.iExact.replace(b.filter.regex.nondigit,""):c.iExact,d=b.formatFloat(e,h)):d=c.cache,f>g&&(e=f,f=g,g=e),d>=f&&g>=d||""===f||""===g}return null},wild:function(c,d){if(/[\?\*\|]/.test(d.iFilter)||b.filter.regex.orReplace.test(d.filter)){var e=d.index,f=d.parsed[e],g=d.iFilter.replace(b.filter.regex.orReplace,"|"),h=""+(b.filter.parseFilter(c,g,e,f)||"");return!c.$headerIndexed[e].hasClass("filter-match")&&/\|/.test(h)&&("|"===h[h.length-1]&&(h+="*"),h=d.anyMatch&&a.isArray(d.rowArray)?"("+h+")":"^("+h+")$"),new RegExp(h.replace(/\?/g,"\\S{1}").replace(/\*/g,"\\S*")).test(d.iExact)}return null},fuzzy:function(a,c){if(/^~/.test(c.iFilter)){var d,e=0,f=c.iExact.length,g=c.iFilter.slice(1),h=b.filter.parseFilter(a,g,c.index,c.parsed[c.index])||"";for(d=0;f>d;d++)c.iExact[d]===h[e]&&(e+=1);return e===h.length?!0:!1}return null}},init:function(d,e,f){b.language=a.extend(!0,{},{to:"to",or:"or",and:"and"},b.language);var g,h,i,j,k,l,m,n,o,p=b.filter.regex;if(e.$table.addClass("hasFilters"),f.searchTimer=null,f.filter_initTimer=null,f.filter_formatterCount=0,f.filter_formatterInit=[],f.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',f.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',m="\\{"+b.filter.regex.query+"\\}",a.extend(p,{child:new RegExp(e.cssChildRow),filtered:new RegExp(f.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+b.language.or+"|-|"+b.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+b.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+b.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+b.language.and+"|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+b.language.and+"|&&)\\s+)","gi"),orReplace:new RegExp("\\s+("+b.language.or+")\\s+","gi"),iQuery:new RegExp(m,"i"),igQuery:new RegExp(m,"ig")}),m=e.$headers.filter(".filter-false, .parser-false").length,f.filter_columnFilters!==!1&&m!==e.$headers.length&&b.filter.buildRow(d,e,f),i="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(e.namespace+"filter "),e.$table.bind(i,function(g,h){return m=f.filter_hideEmpty&&a.isEmptyObject(e.cache)&&!(e.delayInit&&"appendCache"===g.type),e.$table.find("."+c.filterRow).toggleClass(f.filter_filteredRow,m),/(search|filter)/.test(g.type)||(g.stopPropagation(),b.filter.buildDefault(d,!0)),"filterReset"===g.type?(e.$table.find("."+c.filter).add(f.filter_$externalFilters).val(""),b.filter.searching(d,[])):"filterEnd"===g.type?b.filter.buildDefault(d,!0):(h="search"===g.type?h:"updateComplete"===g.type?e.$table.data("lastSearch"):"",/(update|add)/.test(g.type)&&"updateComplete"!==g.type&&(e.lastCombinedFilter=null,e.lastSearch=[]),b.filter.searching(d,h,!0)),!1}),f.filter_reset&&(f.filter_reset instanceof a?f.filter_reset.click(function(){e.$table.trigger("filterReset")}):a(f.filter_reset).length&&a(document).undelegate(f.filter_reset,"click.tsfilter").delegate(f.filter_reset,"click.tsfilter",function(){e.$table.trigger("filterReset")})),f.filter_functions)for(k=0;k'+(j.data("placeholder")||j.attr("data-placeholder")||f.filter_placeholder.select||"")+"":"",m=h,i=h,h.indexOf(f.filter_selectSourceSeparator)>=0&&(m=h.split(f.filter_selectSourceSeparator),i=m[1],m=m[0]),g+="");e.$table.find("thead").find("select."+c.filter+'[data-column="'+k+'"]').append(g),i=f.filter_selectSource,n=a.isFunction(i)?!0:b.getColumnData(d,i,k),n&&b.filter.buildSelect(e.table,k,"",!0,j.hasClass(f.filter_onlyAvail))}b.filter.buildDefault(d,!0),b.filter.bindSearch(d,e.$table.find("."+c.filter),!0),f.filter_external&&b.filter.bindSearch(d,f.filter_external),f.filter_hideFilters&&b.filter.hideFilters(d,e),e.showProcessing&&(i="filterStart filterEnd ".split(" ").join(e.namespace+"filter "),e.$table.unbind(i.replace(/\s+/g," ")).bind(i,function(f,g){j=g?e.$table.find("."+c.header).filter("[data-column]").filter(function(){return""!==g[a(this).data("column")]}):"",b.isProcessing(d,"filterStart"===f.type,g?j:"")})),e.filteredRows=e.totalRows,i="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(e.namespace+"filter "),e.$table.unbind(i.replace(/\s+/g," ")).bind(i,function(){var a=this.config.widgetOptions;l=b.filter.setDefaults(d,e,a)||[],l.length&&(e.delayInit&&""===l.join("")||b.setFilters(d,l,!0)),e.$table.trigger("filterFomatterUpdate"),setTimeout(function(){a.filter_initialized||b.filter.filterInitComplete(e)},100)}),e.pager&&e.pager.initialized&&!f.filter_initialized&&(e.$table.trigger("filterFomatterUpdate"),setTimeout(function(){b.filter.filterInitComplete(e)},100))},formatterUpdated:function(a,b){var c=a.closest("table")[0].config.widgetOptions;c.filter_initialized||(c.filter_formatterInit[b]=1)},filterInitComplete:function(c){var d,e,f=c.widgetOptions,g=0,h=function(){f.filter_initialized=!0,c.$table.trigger("filterInit",c),b.filter.findRows(c.table,c.$table.data("lastSearch")||[])};if(a.isEmptyObject(f.filter_formatter))h();else{for(e=f.filter_formatterInit.length,d=0;e>d;d++)1===f.filter_formatterInit[d]&&g++;clearTimeout(f.filter_initTimer),f.filter_initialized||g!==f.filter_formatterCount?f.filter_initialized||(f.filter_initTimer=setTimeout(function(){h()},500)):h()}},setDefaults:function(c,d,e){var f,g,h,i,j,k=b.getFilters(c)||[];if(e.filter_saveFilters&&b.storage&&(g=b.storage(c,"tablesorter-filters")||[],f=a.isArray(g),f&&""===g.join("")||!f||(k=g)),""===k.join(""))for(j=d.$headers.add(e.filter_$externalFilters).filter("["+e.filter_defaultAttrib+"]"),h=0;h<=d.columns;h++)i=h===d.columns?"all":h,k[h]=j.filter('[data-column="'+i+'"]').attr(e.filter_defaultAttrib)||k[h]||"";return d.$table.data("lastSearch",k),k},parseFilter:function(a,b,c,d){return d?a.parsers[c].format(b,a.table,[],c):b},buildRow:function(d,e,f){var g,h,i,j,k,l,m,n,o=f.filter_cellFilter,p=e.columns,q=a.isArray(o),r='';for(h=0;p>h;h++)r+="").appendTo(e.$table.children("thead").eq(0)).find("td"),h=0;p>h;h++)k=!1,i=e.$headerIndexed[h],m=b.getColumnData(d,f.filter_functions,h),j=f.filter_functions&&m&&"function"!=typeof m||i.hasClass("filter-select"),g=b.getColumnData(d,e.headers,h),k="false"===b.getData(i[0],g,"filter")||"false"===b.getData(i[0],g,"parser"),j?r=a("').appendTo(e.$filters.eq(h)),r&&(n=i.data("placeholder")||i.attr("data-placeholder")||f.filter_placeholder.search||"",r.attr("placeholder",n))),r&&(l=(a.isArray(f.filter_cssFilter)?"undefined"!=typeof f.filter_cssFilter[h]?f.filter_cssFilter[h]||"":"":f.filter_cssFilter)||"",r.addClass(c.filter+" "+l).attr("data-column",h),k&&(r.attr("placeholder","").addClass(c.filterDisabled)[0].disabled=!0))},bindSearch:function(c,d,e){if(c=a(c)[0],d=a(d),d.length){var f,g=c.config,h=g.widgetOptions,i=g.namespace+"filter",j=h.filter_$externalFilters;e!==!0&&(f=h.filter_anyColumnSelector+","+h.filter_multipleColumnSelector,h.filter_$anyMatch=d.filter(f),j&&j.length?h.filter_$externalFilters=h.filter_$externalFilters.add(d):h.filter_$externalFilters=d,b.setFilters(c,g.$table.data("lastSearch")||[],e===!1)),f="keypress keyup search change ".split(" ").join(i+" "),d.attr("data-lastSearchTime",(new Date).getTime()).unbind(f.replace(/\s+/g," ")).bind("keyup"+i,function(d){if(a(this).attr("data-lastSearchTime",(new Date).getTime()),27===d.which)this.value="";else{if(h.filter_liveSearch===!1)return;if(""!==this.value&&("number"==typeof h.filter_liveSearch&&this.value.length=37&&d.which<=40)))return}b.filter.searching(c,!0,!0)}).bind("search change keypress ".split(" ").join(i+" "),function(d){var e=a(this).data("column");(13===d.which||"search"===d.type||"change"===d.type&&this.value!==g.lastSearch[e])&&(d.preventDefault(),a(this).attr("data-lastSearchTime",(new Date).getTime()),b.filter.searching(c,!1,!0))})}},searching:function(a,c,d){var e=a.config.widgetOptions;clearTimeout(e.searchTimer),"undefined"==typeof c||c===!0?e.searchTimer=setTimeout(function(){b.filter.checkFilters(a,c,d)},e.filter_liveSearch?e.filter_searchDelay:10):b.filter.checkFilters(a,c,d)},checkFilters:function(d,e,f){var g=d.config,h=g.widgetOptions,i=a.isArray(e),j=i?e:b.getFilters(d,!0),k=(j||[]).join("");return a.isEmptyObject(g.cache)?void(g.delayInit&&g.pager&&g.pager.initialized&&g.$table.trigger("updateCache",[function(){b.filter.checkFilters(d,!1,f)}])):(i&&(b.setFilters(d,j,!1,f!==!0),h.filter_initialized||(g.lastCombinedFilter="")),h.filter_hideFilters&&g.$table.find("."+c.filterRow).trigger(""===k?"mouseleave":"mouseenter"),g.lastCombinedFilter!==k||e===!1?(e===!1&&(g.lastCombinedFilter=null,g.lastSearch=[]),h.filter_initialized&&g.$table.trigger("filterStart",[j]),g.showProcessing?void setTimeout(function(){return b.filter.findRows(d,j,k),!1},30):(b.filter.findRows(d,j,k),!1)):void 0)},hideFilters:function(d,e){var f,g,h;a(d).find("."+c.filterRow).addClass(c.filterRowHide).bind("mouseenter mouseleave",function(b){var d=b;f=a(this),clearTimeout(h),h=setTimeout(function(){/enter|over/.test(d.type)?f.removeClass(c.filterRowHide):a(document.activeElement).closest("tr")[0]!==f[0]&&""===e.lastCombinedFilter&&f.addClass(c.filterRowHide)},200)}).find("input, select").bind("focus blur",function(d){g=a(this).closest("tr"),clearTimeout(h);var f=d;h=setTimeout(function(){""===b.getFilters(e.$table).join("")&&g.toggleClass(c.filterRowHide,"focus"===f.type)},200)})},defaultFilter:function(c,d){if(""===c)return c;var e=b.filter.regex.iQuery,f=d.match(b.filter.regex.igQuery).length,g=f>1?a.trim(c).split(/\s/):[a.trim(c)],h=g.length-1,i=0,j=d;for(1>h&&f>1&&(g[1]=g[0]);e.test(j);)j=j.replace(e,g[i++]||""),e.test(j)&&h>i&&""!==(g[i]||"")&&(j=d.replace(e,j));return j},getLatestSearch:function(b){return b?b.sort(function(b,c){return a(c).attr("data-lastSearchTime")-a(b).attr("data-lastSearchTime")}):b||a()},multipleColumns:function(c,d){var e,f,g,h,i,j,k,l,m,n=c.widgetOptions,o=n.filter_initialized||!d.filter(n.filter_anyColumnSelector).length,p=[],q=a.trim(b.filter.getLatestSearch(d).attr("data-column")||"");if(o&&/-/.test(q))for(f=q.match(/(\d+)\s*-\s*(\d+)/g),m=f.length,l=0;m>l;l++){for(g=f[l].split(/\s*-\s*/),h=parseInt(g[0],10)||0,i=parseInt(g[1],10)||c.columns-1,h>i&&(e=h,h=i,i=e),i>=c.columns&&(i=c.columns-1);i>=h;h++)p.push(h);q=q.replace(f[l],"")}if(o&&/,/.test(q))for(j=q.split(/\s*,\s*/),m=j.length,k=0;m>k;k++)""!==j[k]&&(l=parseInt(j[k],10),l-1?(d.parsed[e]?p=d.cacheArray[e]:(p=d.rawArray[e],p=a.trim(r.filter_ignoreCase?p.toLowerCase():p),c.sortLocaleCompare&&(p=b.replaceAccents(p))),p):void 0}).get(),d.filter=d.anyMatchFilter,d.iFilter=d.iAnyMatchFilter,d.exact=d.rowArray.join(" "),d.iExact=r.filter_ignoreCase?d.exact.toLowerCase():d.exact,d.cache=d.cacheArray.slice(0,-1).join(" "),l=null,i=null;for(o in b.filter.types)a.inArray(o,e.noAnyMatch)<0&&null===i&&(i=b.filter.types[o](c,d),null!==i&&(l=i));if(null!==l)s=l;else if(r.filter_startsWith)for(s=!1,g=c.columns;!s&&g>0;)g--,s=s||0===d.rowArray[g].indexOf(d.iFilter);else s=(d.iExact+d.childRowText).indexOf(d.iFilter)>=0;if(d.anyMatch=!1,d.filters.join("")===d.filter)return s}for(g=0;g=0:d.filter===d.exact:"function"==typeof n?l=n(d.exact,d.cache,d.filter,g,d.$row,c,d):"function"==typeof n[o||d.filter]&&(p=o||d.filter,l=n[p](d.exact,d.cache,d.filter,g,d.$row,c,d))),null===l){i=null;for(o in b.filter.types)a.inArray(o,m)<0&&null===i&&(i=b.filter.types[o](c,d),null!==i&&(l=i));null!==l?j=l:(p=(d.iExact+d.childRowText).indexOf(b.filter.parseFilter(c,d.iFilter,g,d.parsed[g])),j=!r.filter_startsWith&&p>=0||r.filter_startsWith&&0===p)}else j=l;s=j?s:!1}return s},findRows:function(c,d,e){if(c.config.lastCombinedFilter!==e&&c.config.widgetOptions.filter_initialized){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B=a.extend([],d),C=b.filter.regex,D=c.config,E=D.widgetOptions,F={anyMatch:!1,filters:d,filter_regexCache:[]},G={noAnyMatch:["range","notMatch","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:b.getColumnData(c,E.filter_defaultFilter,D.columns,!0)||""};for(F.parsed=D.$headers.map(function(d){return D.parsers&&D.parsers[d]&&D.parsers[d].parsed||b.getData&&"parsed"===b.getData(D.$headerIndexed[d],b.getColumnData(c,D.headers,d),"filter")||a(this).hasClass("filter-parsed")}).get(),m=0;m1&&(z=parseInt(y[0],10)-1,z>=0&&zt;t++)s=d[t]||"",v||(t=m),v=!(!v||!p.length||0!==s.indexOf(p[t]||"")||C.alreadyFiltered.test(s)||/[=\"\|!]/.test(s)||/(>=?\s*-\d)/.test(s)||/(<=?\s*\d)/.test(s)||""!==s&&D.$filters&&D.$filters.eq(t).find("select").length&&!D.$headerIndexed[t].hasClass("filter-match"));for(u=i.not("."+E.filter_filteredRow).length,v&&0===u&&(v=!1),D.debug&&b.log("Filter: Searching through "+(v&&f>u?u:"all")+" rows"),F.anyMatchFlag&&(D.sortLocaleCompare&&(F.anyMatchFilter=b.replaceAccents(F.anyMatchFilter)),E.filter_defaultFilter&&C.iQuery.test(G.defaultAnyFilter)&&(F.anyMatchFilter=b.filter.defaultFilter(F.anyMatchFilter,G.defaultAnyFilter),v=!1),F.iAnyMatchFilter=E.filter_ignoreCase&&D.ignoreCase?F.anyMatchFilter.toLowerCase():F.anyMatchFilter),j=0;f>j;j++)if(A=i[j].className,n=j&&C.child.test(A),!(n||v&&C.filtered.test(A))){if(F.$row=i.eq(j),F.cacheArray=g[j],h=F.cacheArray[D.columns],F.rawArray=h.raw,F.childRowText="",!E.filter_childByColumn){for(A="",o=h.child,t=0;t")>=0)return p;a.isArray(p)?m=p:"object"===a.type(n)&&p&&(m=p(c,d,e))}if(m===!1&&(m=b.filter.getOptions(c,d,e)),m=a.grep(m,function(b,c){return a.inArray(b,m)===c}),j.$headerIndexed[d].hasClass("filter-select-nosort"))return m;for(i=m.length,h=0;i>h;h++)g=m[h],l.push({t:g,p:j.parsers&&j.parsers.length&&j.parsers[d].format(g,c,[],d)||g});for(f=j.textSorter||"",l.sort(function(e,g){var h=e.p.toString(),i=g.p.toString();return a.isFunction(f)?f(h,i,!0,d,c):"object"==typeof f&&f.hasOwnProperty(d)?f[d](h,i,!0,d,c):b.sortNatural?b.sortNatural(h,i):!0}),m=[],i=l.length,h=0;i>h;h++)m.push(l[h].t);return m},getOptions:function(b,c,d){b=a(b)[0];var e,f,g,h,i,j=b.config,k=j.widgetOptions,l=[];for(f=0;fe;e++)h=i.row?i.row[e]:i.normalized[e][j.columns].$row[0],d&&h.className.match(k.filter_filteredRow)||(k.filter_useParsedData||j.parsers[c].parsed||j.$headerIndexed[c].hasClass("filter-parsed")?l.push(""+i.normalized[e][c]):l.push(i.normalized[e][j.columns].raw[c]));return l},buildSelect:function(d,e,f,g,h){if(d=a(d)[0],e=parseInt(e,10),d.config.cache&&!a.isEmptyObject(d.config.cache)){var i,j,k,l,m,n,o=d.config,p=o.widgetOptions,q=o.$headerIndexed[e],r='",s=o.$table.find("thead").find("select."+c.filter+'[data-column="'+e+'"]').val();if(("undefined"==typeof f||""===f)&&(f=b.filter.getOptionSource(d,e,h)),a.isArray(f)){for(i=0;i=0&&(l=k.split(p.filter_selectSourceSeparator),j=l[0],k=l[1]),r+=""!==f[i]?"":"";f=[]}m=(o.$filters?o.$filters:o.$table.children("thead")).find("."+c.filter),p.filter_$externalFilters&&(m=m&&m.length?m.add(p.filter_$externalFilters):p.filter_$externalFilters), +n=m.filter('select[data-column="'+e+'"]'),n.length&&(n[g?"html":"append"](r),a.isArray(f)||n.append(f).val(s),n.val(s))}},buildDefault:function(a,c){var d,e,f,g=a.config,h=g.widgetOptions,i=g.columns;for(d=0;i>d;d++)e=g.$headerIndexed[d],f=!(e.hasClass("filter-false")||e.hasClass("parser-false")),(e.hasClass("filter-select")||b.getColumnData(a,h.filter_functions,d)===!0)&&f&&b.filter.buildSelect(a,d,"",c,e.hasClass(h.filter_onlyAvail))}},b.getFilters=function(d,e,f,g){var h,i,j,k,l=!1,m=d?a(d)[0].config:"",n=m?m.widgetOptions:"";if(e!==!0&&n&&!n.filter_columnFilters||a.isArray(f)&&f.join("")===m.lastCombinedFilter)return a(d).data("lastSearch");if(m&&(m.$filters&&(i=m.$filters.find("."+c.filter)),n.filter_$externalFilters&&(i=i&&i.length?i.add(n.filter_$externalFilters):n.filter_$externalFilters),i&&i.length))for(l=f||[],h=0;h1&&(j=j.slice(1)),h===m.columns&&(k=j.filter(n.filter_anyColumnSelector),j=k.length?k:j),j.val(f[h]).trigger("change.tsfilter")):(l[h]=j.val()||"",h===m.columns?j.slice(1).filter('[data-column*="'+j.attr("data-column")+'"]').val(l[h]):j.slice(1).val(l[h])),h===m.columns&&j.length&&(n.filter_$anyMatch=j));return 0===l.length&&(l=!1),l},b.setFilters=function(c,d,e,f){var g=c?a(c)[0].config:"",h=b.getFilters(c,!0,d,f);return g&&e&&(g.lastCombinedFilter=null,g.lastSearch=[],b.filter.searching(g.table,d,f),g.$table.trigger("filterFomatterUpdate")),!!h}}(jQuery),function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),c.addHeaderResizeEvent=function(b,c,d){if(b=a(b)[0],b.config){var e={timer:250},f=a.extend({},e,d),g=b.config,h=g.widgetOptions,i=function(a){var b,c,d,e,f,i,j=g.$headers.length;for(h.resize_flag=!0,c=[],b=0;j>b;b++)d=g.$headers.eq(b),e=d.data("savedSizes")||[0,0],f=d[0].offsetWidth,i=d[0].offsetHeight,(f!==e[0]||i!==e[1])&&(d.data("savedSizes",[f,i]),c.push(d[0]));c.length&&a!==!1&&g.$table.trigger("resize",[c]),h.resize_flag=!1};return i(!1),clearInterval(h.resize_timer),c?(h.resize_flag=!1,!1):void(h.resize_timer=setInterval(function(){h.resize_flag||i()},f.timer))}},c.addWidget({id:"stickyHeaders",priority:60,options:{stickyHeaders:"",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(d,e,f){if(!(e.$table.hasClass("hasStickyHeaders")||a.inArray("filter",e.widgets)>=0&&!e.$table.hasClass("hasFilters"))){var g,h,i,j,k=e.$table,l=a(f.stickyHeaders_attachTo),m=e.namespace+"stickyheaders ",n=a(f.stickyHeaders_yScroll||f.stickyHeaders_attachTo||b),o=a(f.stickyHeaders_xScroll||f.stickyHeaders_attachTo||b),p=k.children("thead:first"),q=p.children("tr").not(".sticky-false").children(),r=k.children("tfoot"),s=isNaN(f.stickyHeaders_offset)?a(f.stickyHeaders_offset):"",t=s.length?s.height()||0:parseInt(f.stickyHeaders_offset,10)||0,u=k.parent().closest("."+c.css.table).hasClass("hasStickyHeaders")?k.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],v=u.length?u.height():0,w=f.$sticky=k.clone().addClass("containsStickyHeaders "+c.css.sticky+" "+f.stickyHeaders+" "+e.namespace.slice(1)+"_extra_table").wrap('
    '),x=w.parent().addClass(c.css.stickyHide).css({position:l.length?"absolute":"fixed",padding:parseInt(w.parent().parent().css("padding-left"),10),top:t+v,left:0,visibility:"hidden",zIndex:f.stickyHeaders_zIndex||2}),y=w.children("thead:first"),z="",A=0,B=function(a,c){var d,e,f,g,h,i=a.filter(":visible"),j=i.length;for(d=0;j>d;d++)g=c.filter(":visible").eq(d),h=i.eq(d),"border-box"===h.css("box-sizing")?e=h.outerWidth():"collapse"===g.css("border-collapse")?b.getComputedStyle?e=parseFloat(b.getComputedStyle(h[0],null).width):(f=parseFloat(h.css("border-width")),e=h.outerWidth()-parseFloat(h.css("padding-left"))-parseFloat(h.css("padding-right"))-f):e=h.width(),g.css({width:e,"min-width":e,"max-width":e})},C=function(){t=s.length?s.height()||0:parseInt(f.stickyHeaders_offset,10)||0,A=0,x.css({left:l.length?parseInt(l.css("padding-left"),10)||0:k.offset().left-parseInt(k.css("margin-left"),10)-o.scrollLeft()-A,width:k.outerWidth()}),B(k,w),B(q,j)},D=function(b){if(k.is(":visible")){v=u.length?u.offset().top-n.scrollTop()+u.height():0;var d=k.offset(),e=a.isWindow(n[0]),f=a.isWindow(o[0]),g=(l.length?e?n.scrollTop():n.offset().top:n.scrollTop())+t+v,h=k.height()-(x.height()+(r.height()||0)),i=g>d.top&&gg;g++)e.onRenderHeader.apply(i.eq(g),[g,e,w]);o.add(n).unbind("scroll resize ".split(" ").join(m).replace(/\s+/g," ")).bind("scroll resize ".split(" ").join(m),function(a){D("resize"===a.type)}),e.$table.unbind("stickyHeadersUpdate"+m).bind("stickyHeadersUpdate"+m,function(){D(!0)}),f.stickyHeaders_addResizeEvent&&c.addHeaderResizeEvent(d),k.hasClass("hasFilters")&&f.filter_columnFilters&&(k.bind("filterEnd"+m,function(){var d=a(document.activeElement).closest("td"),g=d.parent().children().index(d);x.hasClass(c.css.stickyVis)&&f.stickyHeaders_filteredToTop&&(b.scrollTo(0,k.position().top),g>=0&&e.$filters&&e.$filters.eq(g).find("a, select, input").filter(":visible").focus())}),c.filter.bindSearch(k,j.find("."+c.css.filter)),f.filter_hideFilters&&c.filter.hideFilters(w,e)),k.trigger("stickyHeadersInit")}},remove:function(d,e,f){var g=e.namespace+"stickyheaders ";e.$table.removeClass("hasStickyHeaders").unbind("pagerComplete filterEnd stickyHeadersUpdate ".split(" ").join(g).replace(/\s+/g," ")).next("."+c.css.stickyWrap).remove(),f.$sticky&&f.$sticky.length&&f.$sticky.remove(),a(b).add(f.stickyHeaders_xScroll).add(f.stickyHeaders_yScroll).add(f.stickyHeaders_attachTo).unbind("scroll resize ".split(" ").join(g).replace(/\s+/g," ")),c.addHeaderResizeEvent(d,!1)}})}(jQuery,window),function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{resizableContainer:"tablesorter-resizable-container",resizableHandle:"tablesorter-resizable-handle",resizableNoSelect:"tablesorter-disableSelection",resizableStorage:"tablesorter-resizable"}),a(function(){var b="";a(b).appendTo("body")}),c.resizable={init:function(b,d){if(!b.$table.hasClass("hasResizable")){b.$table.addClass("hasResizable"),c.resizableReset(b.table,!0),d.resizable_={$wrap:b.$table.parent(),mouseXPosition:0,$target:null,$next:null,overflow:"auto"===b.$table.parent().css("overflow"),fullWidth:Math.abs(b.$table.parent().width()-b.$table.width())<20,storedSizes:[]};var e,f,g,h,i=parseInt(b.$table.css("margin-top"),10);for(d.resizable_.storedSizes=h=(c.storage&&d.resizable!==!1?c.storage(b.table,c.css.resizableStorage):[])||[],c.resizable.setWidths(b,d,h),d.$resizable_container=a('
    ').css({top:i}).insertBefore(b.$table),g=0;g').appendTo(d.$resizable_container).attr({"data-column":g,unselectable:"on"}).data("header",f).bind("selectstart",!1);b.$table.one("tablesorter-initialized",function(){c.resizable.setHandlePosition(b,d),c.resizable.bindings(this.config,this.config.widgetOptions)})}},setWidth:function(a,b){a.css({width:b,"min-width":"","max-width":""})},setWidths:function(b,d,e){var f,g=a(b.namespace+"_extra_headers"),h=b.$table.children("colgroup").children("col");if(e=e||d.resizable_.storedSizes||[],e.length){for(f=0;ff||f===h&&d.resizable_addLastColumn)&&c.css({display:"inline-block",height:g,left:j.position().left-e+j.outerWidth()-i}):c.hide())})},toggleTextSelection:function(b,d){var e=b.namespace+"tsresize";b.widgetOptions.resizable_.disabled=d,a("body").toggleClass(c.css.resizableNoSelect,d),d?a("body").attr("unselectable","on").bind("selectstart"+e,!1):a("body").removeAttr("unselectable").unbind("selectstart"+e)},bindings:function(d,e){var f=d.namespace+"tsresize";e.$resizable_container.children().bind("mousedown",function(b){var f,g,h=e.resizable_,i=a(d.namespace+"_extra_headers"),j=a(b.target).data("header");for(f=parseInt(j.attr("data-column"),10),h.$target=j=j.add(i.filter('[data-column="'+f+'"]')),h.target=f,h.$next=b.shiftKey||e.resizable_targetLast?j.parent().children().not(".resizable-false").filter(":last"):j.nextAll(":not(.resizable-false)").eq(0),f=parseInt(h.$next.attr("data-column"),10),h.$next=h.$next.add(i.filter('[data-column="'+f+'"]')),h.next=f,h.mouseXPosition=b.pageX,h.storedSizes=[],f=0;f0?d.sortList=k:c.hasInitialized&&k&&k.length>0&&i.trigger("sorton",[k]))},remove:function(a,c){c.$table.removeClass("hasSaveSort"),b.storage&&b.storage(a,"tablesorter-savesort","")}})}(jQuery),a.tablesorter}); \ No newline at end of file diff --git a/dist/js/jquery.tablesorter.js b/dist/js/jquery.tablesorter.js new file mode 100644 index 0000000..68a6047 --- /dev/null +++ b/dist/js/jquery.tablesorter.js @@ -0,0 +1,2190 @@ +(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($) { + +/*! TableSorter (FORK) v2.22.1 *//* +* Client-side table sorting with ease! +* @requires jQuery v1.2.6+ +* +* Copyright (c) 2007 Christian Bach +* fork maintained by Rob Garrison +* +* Examples and docs at: http://tablesorter.com +* Dual licensed under the MIT and GPL licenses: +* http://www.opensource.org/licenses/mit-license.php +* http://www.gnu.org/licenses/gpl.html +* +* @type jQuery +* @name tablesorter (FORK) +* @cat Plugins/Tablesorter +* @author Christian Bach - christian.bach@polyester.se +* @contributor Rob Garrison - https://github.com/Mottie/tablesorter +*/ +/*jshint browser:true, jquery:true, unused:false, expr: true */ +/*global console:false, alert:false, require:false, define:false, module:false */ +;(function($){ + 'use strict'; + $.extend({ + /*jshint supernew:true */ + tablesorter: new function() { + + var ts = this; + + ts.version = '2.22.1'; + + ts.parsers = []; + ts.widgets = []; + ts.defaults = { + + // *** appearance + theme : 'default', // adds tablesorter-{theme} to the table for styling + widthFixed : false, // adds colgroup to fix widths of columns + showProcessing : false, // show an indeterminate timer icon in the header when the table is sorted or filtered. + + headerTemplate : '{content}',// header layout template (HTML ok); {content} = innerHTML, {icon} = (class from cssIcon) + onRenderTemplate : null, // function(index, template){ return template; }, (template is a string) + onRenderHeader : null, // function(index){}, (nothing to return) + + // *** functionality + cancelSelection : true, // prevent text selection in the header + tabIndex : true, // add tabindex to header for keyboard accessibility + dateFormat : 'mmddyyyy', // other options: 'ddmmyyy' or 'yyyymmdd' + sortMultiSortKey : 'shiftKey', // key used to select additional columns + sortResetKey : 'ctrlKey', // key used to remove sorting on a column + usNumberFormat : true, // false for German '1.234.567,89' or French '1 234 567,89' + delayInit : false, // if false, the parsed table contents will not update until the first sort + 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. + resort : true, // default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed + + // *** sort options + headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc. + ignoreCase : true, // ignore case while sorting + sortForce : null, // column(s) first sorted; always applied + sortList : [], // Initial sort order; applied initially; updated when manually sorted + sortAppend : null, // column(s) sorted last; always applied + sortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained + + sortInitialOrder : 'asc', // sort direction on first click + sortLocaleCompare: false, // replace equivalent character (accented characters) + sortReset : false, // third click on the header will reset column to default - unsorted + sortRestart : false, // restart sort to 'sortInitialOrder' when clicking on previously unsorted columns + + emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero, emptyMax, emptyMin + stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero + textExtraction : 'basic', // text extraction method/function - function(node, table, cellIndex){} + textAttribute : 'data-text',// data-attribute that contains alternate cell text (used in default textExtraction function) + textSorter : null, // choose overall or specific column sorter function(a, b, direction, table, columnIndex) [alt: ts.sortText] + numberSorter : null, // choose overall numeric sorter function(a, b, direction, maxColumnValue) + + // *** widget options + widgets: [], // method to add widgets, e.g. widgets: ['zebra'] + widgetOptions : { + zebra : [ 'even', 'odd' ] // zebra widget alternating row class names + }, + initWidgets : true, // apply widgets on tablesorter initialization + widgetClass : 'widget-{name}', // table class name template to match to include a widget + + // *** callbacks + initialized : null, // function(table){}, + + // *** extra css class names + tableClass : '', + cssAsc : '', + cssDesc : '', + cssNone : '', + cssHeader : '', + cssHeaderRow : '', + cssProcessing : '', // processing icon applied to header during sort/filter + + cssChildRow : 'tablesorter-childRow', // class name indiciating that a row is to be attached to the its parent + cssIcon : 'tablesorter-icon', // if this class does not exist, the {icon} will not be added from the headerTemplate + cssIconNone : '', // class name added to the icon when there is no column sort + cssIconAsc : '', // class name added to the icon when the column has an ascending sort + cssIconDesc : '', // class name added to the icon when the column has a descending sort + cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!) + cssNoSort : 'tablesorter-noSort', // class name added to element inside header; clicking on it won't cause a sort + cssIgnoreRow : 'tablesorter-ignoreRow', // header row to ignore; cells within this row will not be added to c.$headers + + // *** events + pointerClick : 'click', + pointerDown : 'mousedown', + pointerUp : 'mouseup', + + // *** selectors + selectorHeaders : '> thead th, > thead td', + selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort + selectorRemove : '.remove-me', + + // *** advanced + debug : false, + + // *** Internal variables + headerList: [], + empties: {}, + strings: {}, + parsers: [] + + // removed: widgetZebra: { css: ['even', 'odd'] } + + }; + + // internal css classes - these will ALWAYS be added to + // the table and MUST only contain one class name - fixes #381 + ts.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' + }; + + // labels applied to sortable headers for accessibility (aria) support + ts.language = { + sortAsc : 'Ascending sort applied, ', + sortDesc : 'Descending sort applied, ', + sortNone : 'No sort applied, ', + nextAsc : 'activate to apply an ascending sort', + nextDesc : 'activate to apply a descending sort', + nextNone : 'activate to remove the sort' + }; + + // These methods can be applied on table.config instance + ts.instanceMethods = {}; + + /* debuging utils */ + function log() { + var a = arguments[0], + s = arguments.length > 1 ? Array.prototype.slice.call(arguments) : a; + if (typeof console !== 'undefined' && typeof console.log !== 'undefined') { + console[ /error/i.test(a) ? 'error' : /warn/i.test(a) ? 'warn' : 'log' ](s); + } else { + alert(s); + } + } + + function benchmark(s, d) { + log(s + ' (' + (new Date().getTime() - d.getTime()) + 'ms)'); + } + + ts.log = log; + ts.benchmark = benchmark; + + // $.isEmptyObject from jQuery v1.4 + function isEmptyObject(obj) { + /*jshint forin: false */ + for (var name in obj) { + return false; + } + return true; + } + + ts.getElementText = function(c, node, cellIndex) { + if (!node) { return ''; } + var te, + t = c.textExtraction || '', + // node could be a jquery object + // http://jsperf.com/jquery-vs-instanceof-jquery/2 + $node = node.jquery ? node : $(node); + if (typeof(t) === 'string') { + // check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow! + // http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/ + return $.trim( + ( t === 'basic' ? $node.attr(c.textAttribute) || node.textContent : node.textContent ) || + $node.text() + ); + } else { + if (typeof(t) === 'function') { + return $.trim( t($node[0], c.table, cellIndex) ); + } else if (typeof (te = ts.getColumnData( c.table, t, cellIndex )) === 'function') { + return $.trim( te($node[0], c.table, cellIndex) ); + } + } + // fallback + return $.trim( $node[0].textContent || $node.text() ); + }; + + function detectParserForColumn(c, rows, rowIndex, cellIndex) { + var cur, $node, + i = ts.parsers.length, + node = false, + nodeValue = '', + keepLooking = true; + while (nodeValue === '' && keepLooking) { + rowIndex++; + if (rows[rowIndex]) { + node = rows[rowIndex].cells[cellIndex]; + nodeValue = ts.getElementText(c, node, cellIndex); + $node = $(node); + if (c.debug) { + log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"'); + } + } else { + keepLooking = false; + } + } + while (--i >= 0) { + cur = ts.parsers[i]; + // ignore the default text parser because it will always be true + if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, c.table, node, $node)) { + return cur; + } + } + // nothing found, return the generic parser (text) + return ts.getParserById('text'); + } + + // centralized function to extract/parse cell contents + ts.getParsedText = function( c, cell, colIndex, txt ) { + if ( typeof txt === 'undefined' ) { + txt = ts.getElementText( c, cell, colIndex ); + } + // if no parser, make sure to return the txt + var val = '' + txt, + parser = c.parsers[ colIndex ], + extractor = c.extractors[ colIndex ]; + if ( parser ) { + // do extract before parsing, if there is one + if ( extractor && typeof extractor.format === 'function' ) { + txt = extractor.format( txt, c.table, cell, colIndex ); + } + // allow parsing if the string is empty, previously parsing would change it to zero, + // in case the parser needs to extract data from the table cell attributes + val = parser.id === 'no-parser' ? '' : + // make sure txt is a string (extractor may have converted it) + parser.format( '' + txt, c.table, cell, colIndex ); + if ( c.ignoreCase && typeof val === 'string' ) { + val = val.toLowerCase(); + } + } + return val; + } + + function buildParserCache( c, $tbodies ) { + var rows, list, l, i, h, ch, np, p, e, time, tb, len, + table = c.table, + j = 0, + parsersDebug = ''; + // update table bodies in case we start with an empty table + c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'); + tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies; + len = tb.length; + if ( len === 0) { + return c.debug ? log('Warning: *Empty table!* Not building a parser cache') : ''; + } else if (c.debug) { + time = new Date(); + log('Detecting parsers for each column'); + } + list = { + extractors: [], + parsers: [] + }; + while (j < len) { + rows = tb[j].rows; + if (rows.length) { + l = c.columns; // rows[j].cells.length; + for (i = 0; i < l; i++) { + h = c.$headerIndexed[i]; + // get column indexed table cell + ch = ts.getColumnData( table, c.headers, i ); + // get column parser/extractor + e = ts.getParserById( ts.getData(h, ch, 'extractor') ); + p = ts.getParserById( ts.getData(h, ch, 'sorter') ); + np = ts.getData(h, ch, 'parser') === 'false'; + // empty cells behaviour - keeping emptyToBottom for backwards compatibility + c.empties[i] = ( ts.getData(h, ch, 'empty') || c.emptyTo || (c.emptyToBottom ? 'bottom' : 'top' ) ).toLowerCase(); + // text strings behaviour in numerical sorts + c.strings[i] = ( ts.getData(h, ch, 'string') || c.stringTo || 'max' ).toLowerCase(); + if (np) { + p = ts.getParserById('no-parser'); + } + if (!e) { + // For now, maybe detect someday + e = false; + } + if (!p) { + p = detectParserForColumn(c, rows, -1, i); + } + if (c.debug) { + parsersDebug += 'column:' + i + '; extractor:' + e.id + '; parser:' + p.id + '; string:' + c.strings[i] + '; empty: ' + c.empties[i] + '\n'; + } + list.parsers[i] = p; + list.extractors[i] = e; + } + } + j += (list.parsers.length) ? len : 1; + } + if (c.debug) { + log(parsersDebug ? parsersDebug : 'No parsers detected'); + benchmark('Completed detecting parsers', time); + } + c.parsers = list.parsers; + c.extractors = list.extractors; + } + + /* utils */ + function buildCache(table, $tbodies) { + var cc, t, v, i, j, k, $tb, $row, cols, cacheTime, + totalRows, rowData, prevRowData, colMax, + c = table.config, + parsers = c.parsers; + // update tbody variable + c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'); + $tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies, + c.cache = {}; + c.totalRows = 0; + // if no parsers found, return - it's an empty table. + if (!parsers) { + return c.debug ? log('Warning: *Empty table!* Not building a cache') : ''; + } + if (c.debug) { + cacheTime = new Date(); + } + // processing icon + if (c.showProcessing) { + ts.isProcessing(table, true); + } + for (k = 0; k < $tb.length; k++) { + colMax = []; // column max value per tbody + cc = c.cache[k] = { + normalized: [] // array of normalized row data; last entry contains 'rowData' above + // colMax: # // added at the end + }; + + totalRows = ($tb[k] && $tb[k].rows.length) || 0; + for (i = 0; i < totalRows; ++i) { + rowData = { + // order: original row order # + // $row : jQuery Object[] + child: [], // child row text (filter widget) + raw: [] // original row text + }; + /** Add the table data to main data array */ + $row = $( $tb[ k ].rows[ i ] ); + cols = []; + // if this is a child row, add it to the last row's children and continue to the next row + // ignore child row class, if it is the first row + if ( $row.hasClass( c.cssChildRow ) && i !== 0 ) { + t = cc.normalized.length - 1; + prevRowData = cc.normalized[ t ][ c.columns ]; + prevRowData.$row = prevRowData.$row.add( $row ); + // add 'hasChild' class name to parent row + if ( !$row.prev().hasClass( c.cssChildRow ) ) { + $row.prev().addClass( ts.css.cssHasChild ); + } + // save child row content (un-parsed!) + v = $row.children( 'th, td' ); + t = prevRowData.child.length; + prevRowData.child[ t ] = []; + // child row content does not account for colspans/rowspans; so indexing may be off + for ( j = 0; j < c.columns; j++ ) { + prevRowData.child[ t ][ j ] = ts.getParsedText( c, v[ j ], j ); + } + // go to the next for loop + continue; + } + rowData.$row = $row; + rowData.order = i; // add original row position to rowCache + for ( j = 0; j < c.columns; ++j ) { + if (typeof parsers[ j ] === 'undefined') { + if ( c.debug ) { + log( 'No parser found for cell:', $row[ 0 ].cells[ j ], 'does it have a header?' ); + } + continue; + } + t = ts.getElementText( c, $row[ 0 ].cells[j], j ); + rowData.raw.push( t ); // save original row text + v = ts.getParsedText( c, $row[ 0 ].cells[ j ], j, t ); + cols.push( v ); + if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) { + // determine column max value (ignore sign) + colMax[ j ] = Math.max( Math.abs( v ) || 0, colMax[ j ] || 0 ); + } + } + // ensure rowData is always in the same location (after the last column) + cols[ c.columns ] = rowData; + cc.normalized.push( cols ); + } + cc.colMax = colMax; + // total up rows, not including child rows + c.totalRows += cc.normalized.length; + + } + if ( c.showProcessing ) { + ts.isProcessing( table ); // remove processing icon + } + if ( c.debug ) { + benchmark( 'Building cache for ' + totalRows + ' rows', cacheTime ); + } + } + + // init flag (true) used by pager plugin to prevent widget application + function appendToTable(table, init) { + var c = table.config, + wo = c.widgetOptions, + $tbodies = c.$tbodies, + rows = [], + cc = c.cache, + n, totalRows, $bk, $tb, + i, k, appendTime; + // empty table - fixes #206/#346 + if (isEmptyObject(cc)) { + // run pager appender in case the table was just emptied + return c.appender ? c.appender(table, rows) : + table.isUpdating ? c.$table.trigger('updateComplete', table) : ''; // Fixes #532 + } + if (c.debug) { + appendTime = new Date(); + } + for (k = 0; k < $tbodies.length; k++) { + $bk = $tbodies.eq(k); + if ($bk.length) { + // get tbody + $tb = ts.processTbody(table, $bk, true); + n = cc[k].normalized; + totalRows = n.length; + for (i = 0; i < totalRows; i++) { + rows.push(n[i][c.columns].$row); + // removeRows used by the pager plugin; don't render if using ajax - fixes #411 + if (!c.appender || (c.pager && (!c.pager.removeRows || !wo.pager_removeRows) && !c.pager.ajax)) { + $tb.append(n[i][c.columns].$row); + } + } + // restore tbody + ts.processTbody(table, $tb, false); + } + } + if (c.appender) { + c.appender(table, rows); + } + if (c.debug) { + benchmark('Rebuilt table', appendTime); + } + // apply table widgets; but not before ajax completes + if (!init && !c.appender) { ts.applyWidget(table); } + if (table.isUpdating) { + c.$table.trigger('updateComplete', table); + } + } + + function formatSortingOrder(v) { + // look for 'd' in 'desc' order; return true + return (/^d/i.test(v) || v === 1); + } + + function buildHeaders(table) { + var ch, $t, h, i, t, lock, time, indx, + c = table.config; + c.headerList = []; + c.headerContent = []; + if (c.debug) { + time = new Date(); + } + // children tr in tfoot - see issue #196 & #547 + c.columns = ts.computeColumnIndex( c.$table.children('thead, tfoot').children('tr') ); + // add icon if cssIcon option exists + i = c.cssIcon ? '' : ''; + // redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683 + c.$headers = $( $.map( $(table).find(c.selectorHeaders), function(elem, index) { + $t = $(elem); + // ignore cell (don't add it to c.$headers) if row has ignoreRow class + if ($t.parent().hasClass(c.cssIgnoreRow)) { return; } + // make sure to get header cell & not column indexed cell + ch = ts.getColumnData( table, c.headers, index, true ); + // save original header content + c.headerContent[index] = $t.html(); + // if headerTemplate is empty, don't reformat the header cell + if ( c.headerTemplate !== '' && !$t.find('.' + ts.css.headerIn).length ) { + // set up header template + t = c.headerTemplate.replace(/\{content\}/g, $t.html()).replace(/\{icon\}/g, $t.find('.' + ts.css.icon).length ? '' : i); + if (c.onRenderTemplate) { + h = c.onRenderTemplate.apply($t, [index, t]); + if (h && typeof h === 'string') { t = h; } // only change t if something is returned + } + $t.html('
    ' + t + '
    '); // faster than wrapInner + } + if (c.onRenderHeader) { c.onRenderHeader.apply($t, [index, c, c.$table]); } + // *** remove this.column value if no conflicts found + elem.column = parseInt( $t.attr('data-column'), 10); + elem.order = formatSortingOrder( ts.getData($t, ch, 'sortInitialOrder') || c.sortInitialOrder ) ? [1,0,2] : [0,1,2]; + elem.count = -1; // set to -1 because clicking on the header automatically adds one + elem.lockedOrder = false; + lock = ts.getData($t, ch, 'lockedOrder') || false; + if (typeof lock !== 'undefined' && lock !== false) { + elem.order = elem.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0]; + } + $t.addClass(ts.css.header + ' ' + c.cssHeader); + // add cell to headerList + c.headerList[index] = elem; + // add to parent in case there are multiple rows + $t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow).attr('role', 'row'); + // allow keyboard cursor to focus on element + if (c.tabIndex) { $t.attr('tabindex', 0); } + return elem; + })); + // cache headers per column + c.$headerIndexed = []; + for (indx = 0; indx < c.columns; indx++) { + $t = c.$headers.filter('[data-column="' + indx + '"]'); + // target sortable column cells, unless there are none, then use non-sortable cells + // .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6 + c.$headerIndexed[indx] = $t.not('.sorter-false').length ? $t.not('.sorter-false').filter(':last') : $t.filter(':last'); + } + $(table).find(c.selectorHeaders).attr({ + scope: 'col', + role : 'columnheader' + }); + // enable/disable sorting + updateHeader(table); + if (c.debug) { + benchmark('Built headers:', time); + log(c.$headers); + } + } + + function commonUpdate(table, resort, callback) { + var c = table.config; + // remove rows/elements before update + c.$table.find(c.selectorRemove).remove(); + // rebuild parsers + buildParserCache(c); + // rebuild the cache map + buildCache(table); + checkResort(c, resort, callback); + } + + function updateHeader(table) { + var index, s, $th, col, + c = table.config, + len = c.$headers.length; + for ( index = 0; index < len; index++ ) { + $th = c.$headers.eq( index ); + col = ts.getColumnData( table, c.headers, index, true ); + // add 'sorter-false' class if 'parser-false' is set + s = ts.getData( $th, col, 'sorter' ) === 'false' || ts.getData( $th, col, 'parser' ) === 'false'; + $th[0].sortDisabled = s; + $th[ s ? 'addClass' : 'removeClass' ]('sorter-false').attr('aria-disabled', '' + s); + // aria-controls - requires table ID + if (table.id) { + if (s) { + $th.removeAttr('aria-controls'); + } else { + $th.attr('aria-controls', table.id); + } + } + } + } + + function setHeadersCss(table) { + var f, h, i, j, $headers, $h, nextSort, txt, + c = table.config, + list = c.sortList, + len = list.length, + none = ts.css.sortNone + ' ' + c.cssNone, + css = [ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc], + cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ], + aria = ['ascending', 'descending'], + // find the footer + $t = $(table).find('tfoot tr').children() + .add( $( c.namespace + '_extra_headers' ) ) + .removeClass( css.join( ' ' ) ); + // remove all header information + c.$headers + .removeClass(css.join(' ')) + .addClass(none).attr('aria-sort', 'none') + .find('.' + ts.css.icon) + .removeClass(cssIcon.join(' ')) + .addClass(cssIcon[2]); + for (i = 0; i < len; i++) { + // direction = 2 means reset! + if (list[i][1] !== 2) { + // multicolumn sorting updating - choose the :last in case there are nested columns + f = c.$headers.not('.sorter-false').filter('[data-column="' + list[i][0] + '"]' + (len === 1 ? ':last' : '') ); + if (f.length) { + for (j = 0; j < f.length; j++) { + if (!f[j].sortDisabled) { + f.eq(j) + .removeClass(none) + .addClass(css[list[i][1]]) + .attr('aria-sort', aria[list[i][1]]) + .find('.' + ts.css.icon) + .removeClass(cssIcon[2]) + .addClass(cssIcon[list[i][1]]); + } + } + // add sorted class to footer & extra headers, if they exist + if ($t.length) { + $t.filter('[data-column="' + list[i][0] + '"]').removeClass(none).addClass(css[list[i][1]]); + } + } + } + } + // add verbose aria labels + len = c.$headers.length; + $headers = c.$headers.not('.sorter-false'); + for ( i = 0; i < len; i++ ) { + $h = $headers.eq( i ); + if ( $h.length ) { + h = $headers[ i ]; + nextSort = h.order[ ( h.count + 1 ) % ( c.sortReset ? 3 : 2 ) ], + txt = $.trim( $h.text() ) + ': ' + + ts.language[ $h.hasClass( ts.css.sortAsc ) ? 'sortAsc' : $h.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone' ] + + ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ]; + $h.attr( 'aria-label', txt ); + } + } + } + + function updateHeaderSortCount( table, list ) { + var col, dir, group, header, indx, primary, temp, val, + c = table.config, + sortList = list || c.sortList, + len = sortList.length; + c.sortList = []; + for (indx = 0; indx < len; indx++) { + val = sortList[indx]; + // ensure all sortList values are numeric - fixes #127 + col = parseInt(val[0], 10); + // prevents error if sorton array is wrong + if ( col < c.columns && c.$headerIndexed[col] ) { + // make sure header exists + header = c.$headerIndexed[col][0]; + // o.count = o.count + 1; + dir = ('' + val[1]).match(/^(1|d|s|o|n)/); + dir = dir ? dir[0] : ''; + // 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext + switch(dir) { + case '1': case 'd': // descending + dir = 1; + break; + case 's': // same direction (as primary column) + // if primary sort is set to 's', make it ascending + dir = primary || 0; + break; + case 'o': + temp = header.order[(primary || 0) % (c.sortReset ? 3 : 2)]; + // opposite of primary column; but resets if primary resets + dir = temp === 0 ? 1 : temp === 1 ? 0 : 2; + break; + case 'n': + header.count = header.count + 1; + dir = header.order[(header.count) % (c.sortReset ? 3 : 2)]; + break; + default: // ascending + dir = 0; + break; + } + primary = indx === 0 ? dir : primary; + group = [ col, parseInt(dir, 10) || 0 ]; + c.sortList.push(group); + dir = $.inArray(group[1], header.order); // fixes issue #167 + header.count = dir >= 0 ? dir : group[1] % (c.sortReset ? 3 : 2); + } + } + } + + function getCachedSortType(parsers, i) { + return (parsers && parsers[i]) ? parsers[i].type || '' : ''; + } + + function initSort(table, cell, event){ + if (table.isUpdating) { + // let any updates complete before initializing a sort + return setTimeout(function(){ initSort(table, cell, event); }, 50); + } + var arry, indx, i, col, order, s, $header, + c = table.config, + key = !event[c.sortMultiSortKey], + $table = c.$table, + len = c.$headers.length; + // Only call sortStart if sorting is enabled + $table.trigger('sortStart', table); + // get current column sort order + cell.count = event[c.sortResetKey] ? 2 : (cell.count + 1) % (c.sortReset ? 3 : 2); + // reset all sorts on non-current column - issue #30 + if (c.sortRestart) { + indx = cell; + for ( i = 0; i < len; i++ ) { + $header = c.$headers.eq( i ); + // only reset counts on columns that weren't just clicked on and if not included in a multisort + if ( $header[0] !== indx && ( key || !$header.is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc) ) ) { + $header[0].count = -1; + } + } + } + // get current column index + indx = parseInt( $(cell).attr('data-column'), 10 ); + // user only wants to sort on one column + if (key) { + // flush the sort list + c.sortList = []; + if (c.sortForce !== null) { + arry = c.sortForce; + for (col = 0; col < arry.length; col++) { + if (arry[col][0] !== indx) { + c.sortList.push(arry[col]); + } + } + } + // add column to sort list + order = cell.order[cell.count]; + if (order < 2) { + c.sortList.push([indx, order]); + // add other columns if header spans across multiple + if (cell.colSpan > 1) { + for (col = 1; col < cell.colSpan; col++) { + c.sortList.push([indx + col, order]); + } + } + } + // multi column sorting + } else { + // get rid of the sortAppend before adding more - fixes issue #115 & #523 + if (c.sortAppend && c.sortList.length > 1) { + for (col = 0; col < c.sortAppend.length; col++) { + s = ts.isValueInArray(c.sortAppend[col][0], c.sortList); + if (s >= 0) { + c.sortList.splice(s,1); + } + } + } + // the user has clicked on an already sorted column + if (ts.isValueInArray(indx, c.sortList) >= 0) { + // reverse the sorting direction + for (col = 0; col < c.sortList.length; col++) { + s = c.sortList[col]; + order = c.$headerIndexed[ s[0] ][0]; + if (s[0] === indx) { + // order.count seems to be incorrect when compared to cell.count + s[1] = order.order[cell.count]; + if (s[1] === 2) { + c.sortList.splice(col,1); + order.count = -1; + } + } + } + } else { + // add column to sort list array + order = cell.order[cell.count]; + if (order < 2) { + c.sortList.push([indx, order]); + // add other columns if header spans across multiple + if (cell.colSpan > 1) { + for (col = 1; col < cell.colSpan; col++) { + c.sortList.push([indx + col, order]); + } + } + } + } + } + if (c.sortAppend !== null) { + arry = c.sortAppend; + for (col = 0; col < arry.length; col++) { + if (arry[col][0] !== indx) { + c.sortList.push(arry[col]); + } + } + } + // sortBegin event triggered immediately before the sort + $table.trigger('sortBegin', table); + // setTimeout needed so the processing icon shows up + setTimeout(function(){ + // set css for headers + setHeadersCss(table); + multisort(table); + appendToTable(table); + $table.trigger('sortEnd', table); + }, 1); + } + + // sort multiple columns + function multisort(table) { /*jshint loopfunc:true */ + var i, k, num, col, sortTime, colMax, + rows, order, sort, x, y, + dir = 0, + c = table.config, + cts = c.textSorter || '', + sortList = c.sortList, + l = sortList.length, + bl = c.$tbodies.length; + if (c.serverSideSorting || isEmptyObject(c.cache)) { // empty table - fixes #206/#346 + return; + } + if (c.debug) { sortTime = new Date(); } + for (k = 0; k < bl; k++) { + colMax = c.cache[k].colMax; + rows = c.cache[k].normalized; + + rows.sort(function(a, b) { + // rows is undefined here in IE, so don't use it! + for (i = 0; i < l; i++) { + col = sortList[i][0]; + order = sortList[i][1]; + // sort direction, true = asc, false = desc + dir = order === 0; + + if (c.sortStable && a[col] === b[col] && l === 1) { + return a[c.columns].order - b[c.columns].order; + } + + // fallback to natural sort since it is more robust + num = /n/i.test(getCachedSortType(c.parsers, col)); + if (num && c.strings[col]) { + // sort strings in numerical columns + if (typeof (c.string[c.strings[col]]) === 'boolean') { + num = (dir ? 1 : -1) * (c.string[c.strings[col]] ? -1 : 1); + } else { + num = (c.strings[col]) ? c.string[c.strings[col]] || 0 : 0; + } + // fall back to built-in numeric sort + // var sort = $.tablesorter['sort' + s]( a[c], b[c], dir, colMax[c], table); + sort = c.numberSorter ? c.numberSorter(a[col], b[col], dir, colMax[col], table) : + ts[ 'sortNumeric' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], num, colMax[col], col, table); + } else { + // set a & b depending on sort direction + x = dir ? a : b; + y = dir ? b : a; + // text sort function + if (typeof(cts) === 'function') { + // custom OVERALL text sorter + sort = cts(x[col], y[col], dir, col, table); + } else if (typeof(cts) === 'object' && cts.hasOwnProperty(col)) { + // custom text sorter for a SPECIFIC COLUMN + sort = cts[col](x[col], y[col], dir, col, table); + } else { + // fall back to natural sort + sort = ts[ 'sortNatural' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], col, table, c); + } + } + if (sort) { return sort; } + } + return a[c.columns].order - b[c.columns].order; + }); + } + if (c.debug) { benchmark('Sorting on ' + sortList.toString() + ' and dir ' + order + ' time', sortTime); } + } + + function resortComplete(c, callback){ + if (c.table.isUpdating) { + c.$table.trigger('updateComplete', c.table); + } + if ($.isFunction(callback)) { + callback(c.table); + } + } + + function checkResort(c, resort, callback) { + var sl = $.isArray(resort) ? resort : c.sortList, + // if no resort parameter is passed, fallback to config.resort (true by default) + resrt = typeof resort === 'undefined' ? c.resort : resort; + // don't try to resort if the table is still processing + // this will catch spamming of the updateCell method + if (resrt !== false && !c.serverSideSorting && !c.table.isProcessing) { + if (sl.length) { + c.$table.trigger('sorton', [sl, function(){ + resortComplete(c, callback); + }, true]); + } else { + c.$table.trigger('sortReset', [function(){ + resortComplete(c, callback); + ts.applyWidget(c.table, false); + }]); + } + } else { + resortComplete(c, callback); + ts.applyWidget(c.table, false); + } + } + + function bindMethods(table){ + var c = table.config, + $table = c.$table, + events = ('sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache ' + + 'updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ').split(' ') + .join(c.namespace + ' '); + // apply easy methods that trigger bound events + $table + .unbind( events.replace(/\s+/g, ' ') ) + .bind('sortReset' + c.namespace, function(e, callback){ + e.stopPropagation(); + c.sortList = []; + setHeadersCss(table); + multisort(table); + appendToTable(table); + if ($.isFunction(callback)) { + callback(table); + } + }) + .bind('updateAll' + c.namespace, function(e, resort, callback){ + e.stopPropagation(); + table.isUpdating = true; + ts.refreshWidgets(table, true, true); + buildHeaders(table); + ts.bindEvents(table, c.$headers, true); + bindMethods(table); + commonUpdate(table, resort, callback); + }) + .bind('update' + c.namespace + ' updateRows' + c.namespace, function(e, resort, callback) { + e.stopPropagation(); + table.isUpdating = true; + // update sorting (if enabled/disabled) + updateHeader(table); + commonUpdate(table, resort, callback); + }) + .bind('updateCell' + c.namespace, function(e, cell, resort, callback) { + e.stopPropagation(); + table.isUpdating = true; + $table.find(c.selectorRemove).remove(); + // get position from the dom + var t, row, icell, cache, + $tb = c.$tbodies, + $cell = $(cell), + // update cache - format: function(s, table, cell, cellIndex) + // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr'); + tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ), + tbcache = c.cache[ tbdy ], + $row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first'); + cell = $cell[0]; // in case cell is a jQuery object + // tbody may not exist if update is initialized while tbody is removed for processing + if ($tb.length && tbdy >= 0) { + row = $tb.eq( tbdy ).find( 'tr' ).index( $row ); + cache = tbcache.normalized[ row ]; + icell = $cell.index(); + t = ts.getParsedText( c, cell, icell ); + cache[ icell ] = t; + cache[ c.columns ].$row = $row; + if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) { + // update column max value (ignore sign) + tbcache.colMax[icell] = Math.max(Math.abs(t) || 0, tbcache.colMax[icell] || 0); + } + t = resort !== 'undefined' ? resort : c.resort; + if (t !== false) { + // widgets will be reapplied + checkResort(c, t, callback); + } else { + // don't reapply widgets is resort is false, just in case it causes + // problems with element focus + if ($.isFunction(callback)) { + callback(table); + } + c.$table.trigger('updateComplete', c.table); + } + } + }) + .bind('addRows' + c.namespace, function(e, $row, resort, callback) { + e.stopPropagation(); + table.isUpdating = true; + if (isEmptyObject(c.cache)) { + // empty table, do an update instead - fixes #450 + updateHeader(table); + commonUpdate(table, resort, callback); + } else { + $row = $($row).attr('role', 'row'); // make sure we're using a jQuery object + var i, j, l, rowData, cells, + rows = $row.filter('tr').length, + tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') ); + // fixes adding rows to an empty table - see issue #179 + if (!(c.parsers && c.parsers.length)) { + buildParserCache(c); + } + // add each row + for (i = 0; i < rows; i++) { + l = $row[i].cells.length; + cells = []; + rowData = { + child: [], + $row : $row.eq(i), + order: c.cache[tbdy].normalized.length + }; + // add each cell + for (j = 0; j < l; j++) { + cells[j] = ts.getParsedText( c, $row[i].cells[j], j ); + if ((c.parsers[j].type || '').toLowerCase() === 'numeric') { + // update column max value (ignore sign) + c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0); + } + } + // add the row data to the end + cells.push(rowData); + // update cache + c.cache[tbdy].normalized.push(cells); + } + // resort using current settings + checkResort(c, resort, callback); + } + }) + .bind('updateComplete' + c.namespace, function(){ + table.isUpdating = false; + }) + .bind('sorton' + c.namespace, function(e, list, callback, init) { + var c = table.config; + e.stopPropagation(); + $table.trigger('sortStart', this); + // update header count index + updateHeaderSortCount(table, list); + // set css for headers + setHeadersCss(table); + // fixes #346 + if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } + $table.trigger('sortBegin', this); + // sort the table and append it to the dom + multisort(table); + appendToTable(table, init); + $table.trigger('sortEnd', this); + ts.applyWidget(table); + if ($.isFunction(callback)) { + callback(table); + } + }) + .bind('appendCache' + c.namespace, function(e, callback, init) { + e.stopPropagation(); + appendToTable(table, init); + if ($.isFunction(callback)) { + callback(table); + } + }) + // $tbodies variable is used by the tbody sorting widget + .bind('updateCache' + c.namespace, function(e, callback, $tbodies){ + // rebuild parsers + if (!(c.parsers && c.parsers.length)) { + buildParserCache(c, $tbodies); + } + // rebuild the cache map + buildCache(table, $tbodies); + if ($.isFunction(callback)) { + callback(table); + } + }) + .bind('applyWidgetId' + c.namespace, function(e, id) { + e.stopPropagation(); + ts.getWidgetById(id).format(table, c, c.widgetOptions); + }) + .bind('applyWidgets' + c.namespace, function(e, init) { + e.stopPropagation(); + // apply widgets + ts.applyWidget(table, init); + }) + .bind('refreshWidgets' + c.namespace, function(e, all, dontapply){ + e.stopPropagation(); + ts.refreshWidgets(table, all, dontapply); + }) + .bind('destroy' + c.namespace, function(e, c, cb){ + e.stopPropagation(); + ts.destroy(table, c, cb); + }) + .bind('resetToLoadState' + c.namespace, function(){ + // remove all widgets + ts.removeWidget(table, true, false); + // restore original settings; this clears out current settings, but does not clear + // values saved to storage. + c = $.extend(true, ts.defaults, c.originalSettings); + table.hasInitialized = false; + // setup the entire table again + ts.setup( table, c ); + }); + } + + /* public methods */ + ts.construct = function(settings) { + return this.each(function() { + var table = this, + // merge & extend config options + c = $.extend(true, {}, ts.defaults, settings, ts.instanceMethods); + // save initial settings + c.originalSettings = settings; + // create a table from data (build table widget) + if (!table.hasInitialized && ts.buildTable && this.nodeName !== 'TABLE') { + // return the table (in case the original target is the table's container) + ts.buildTable(table, c); + } else { + ts.setup(table, c); + } + }); + }; + + ts.setup = function(table, c) { + // if no thead or tbody, or tablesorter is already present, quit + if (!table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true) { + return c.debug ? log('ERROR: stopping initialization! No table, thead, tbody or tablesorter has already been initialized') : ''; + } + + var k = '', + $table = $(table), + m = $.metadata; + // initialization flag + table.hasInitialized = false; + // table is being processed flag + table.isProcessing = true; + // make sure to store the config object + table.config = c; + // save the settings where they read + $.data(table, 'tablesorter', c); + if (c.debug) { $.data( table, 'startoveralltimer', new Date()); } + + // removing this in version 3 (only supports jQuery 1.7+) + c.supportsDataObject = (function(version) { + version[0] = parseInt(version[0], 10); + return (version[0] > 1) || (version[0] === 1 && parseInt(version[1], 10) >= 4); + })($.fn.jquery.split('.')); + // digit sort text location; keeping max+/- for backwards compatibility + c.string = { 'max': 1, 'min': -1, 'emptymin': 1, 'emptymax': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false }; + // ensure case insensitivity + c.emptyTo = c.emptyTo.toLowerCase(); + c.stringTo = c.stringTo.toLowerCase(); + // add table theme class only if there isn't already one there + if (!/tablesorter\-/.test($table.attr('class'))) { + k = (c.theme !== '' ? ' tablesorter-' + c.theme : ''); + } + c.table = table; + c.$table = $table + .addClass(ts.css.table + ' ' + c.tableClass + k) + .attr('role', 'grid'); + c.$headers = $table.find(c.selectorHeaders); + + // give the table a unique id, which will be used in namespace binding + if (!c.namespace) { + c.namespace = '.tablesorter' + Math.random().toString(16).slice(2); + } else { + // make sure namespace starts with a period & doesn't have weird characters + c.namespace = '.' + c.namespace.replace(/\W/g,''); + } + + c.$table.children().children('tr').attr('role', 'row'); + c.$tbodies = $table.children('tbody:not(.' + c.cssInfoBlock + ')').attr({ + 'aria-live' : 'polite', + 'aria-relevant' : 'all' + }); + if (c.$table.children('caption').length) { + k = c.$table.children('caption')[0]; + if (!k.id) { k.id = c.namespace.slice(1) + 'caption'; } + c.$table.attr('aria-labelledby', k.id); + } + c.widgetInit = {}; // keep a list of initialized widgets + // change textExtraction via data-attribute + c.textExtraction = c.$table.attr('data-text-extraction') || c.textExtraction || 'basic'; + // build headers + buildHeaders(table); + // fixate columns if the users supplies the fixedWidth option + // do this after theme has been applied + ts.fixColumnWidth(table); + // add widget options before parsing (e.g. grouping widget has parser settings) + ts.applyWidgetOptions(table, c); + // try to auto detect column type, and store in tables config + buildParserCache(c); + // start total row count at zero + c.totalRows = 0; + // build the cache for the tbody cells + // delayInit will delay building the cache until the user starts a sort + if (!c.delayInit) { buildCache(table); } + // bind all header events and methods + ts.bindEvents(table, c.$headers, true); + bindMethods(table); + // get sort list from jQuery data or metadata + // in jQuery < 1.4, an error occurs when calling $table.data() + if (c.supportsDataObject && typeof $table.data().sortlist !== 'undefined') { + c.sortList = $table.data().sortlist; + } else if (m && ($table.metadata() && $table.metadata().sortlist)) { + c.sortList = $table.metadata().sortlist; + } + // apply widget init code + ts.applyWidget(table, true); + // if user has supplied a sort list to constructor + if (c.sortList.length > 0) { + $table.trigger('sorton', [c.sortList, {}, !c.initWidgets, true]); + } else { + setHeadersCss(table); + if (c.initWidgets) { + // apply widget format + ts.applyWidget(table, false); + } + } + + // show processesing icon + if (c.showProcessing) { + $table + .unbind('sortBegin' + c.namespace + ' sortEnd' + c.namespace) + .bind('sortBegin' + c.namespace + ' sortEnd' + c.namespace, function(e) { + clearTimeout(c.processTimer); + ts.isProcessing(table); + if (e.type === 'sortBegin') { + c.processTimer = setTimeout(function(){ + ts.isProcessing(table, true); + }, 500); + } + }); + } + + // initialized + table.hasInitialized = true; + table.isProcessing = false; + if (c.debug) { + ts.benchmark('Overall initialization time', $.data( table, 'startoveralltimer')); + } + $table.trigger('tablesorter-initialized', table); + if (typeof c.initialized === 'function') { c.initialized(table); } + }; + + // automatically add a colgroup with col elements set to a percentage width + ts.fixColumnWidth = function(table) { + table = $(table)[0]; + var overallWidth, percent, $tbodies, len, index, + c = table.config, + colgroup = c.$table.children('colgroup'); + // remove plugin-added colgroup, in case we need to refresh the widths + if (colgroup.length && colgroup.hasClass(ts.css.colgroup)) { + colgroup.remove(); + } + if (c.widthFixed && c.$table.children('colgroup').length === 0) { + colgroup = $(''); + overallWidth = c.$table.width(); + // only add col for visible columns - fixes #371 + $tbodies = c.$tbodies.find('tr:first').children(':visible'); //.each(function() + len = $tbodies.length; + for ( index = 0; index < len; index++ ) { + percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%'; + colgroup.append( $('').css('width', percent) ); + } + c.$table.prepend(colgroup); + } + }; + + ts.getColumnData = function(table, obj, indx, getCell, $headers){ + if (typeof obj === 'undefined' || obj === null) { return; } + table = $(table)[0]; + var $h, k, + c = table.config, + $cells = ( $headers || c.$headers ), + // c.$headerIndexed is not defined initially + $cell = c.$headerIndexed && c.$headerIndexed[indx] || $cells.filter('[data-column="' + indx + '"]:last'); + if (obj[indx]) { + return getCell ? obj[indx] : obj[$cells.index( $cell )]; + } + for (k in obj) { + if (typeof k === 'string') { + $h = $cell + // header cell with class/id + .filter(k) + // find elements within the header cell with cell/id + .add( $cell.find(k) ); + if ($h.length) { + return obj[k]; + } + } + } + return; + }; + + // computeTableHeaderCellIndexes from: + // http://www.javascripttoolbox.com/lib/table/examples.php + // http://www.javascripttoolbox.com/temp/table_cellindex.html + ts.computeColumnIndex = function(trs) { + var i, j, k, l, $cell, cell, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol, + matrix = [], + matrixrow = [], + lookup = {}; + for (i = 0; i < trs.length; i++) { + cells = trs[i].cells; + for (j = 0; j < cells.length; j++) { + cell = cells[j]; + $cell = $(cell); + rowIndex = cell.parentNode.rowIndex; + cellId = rowIndex + '-' + $cell.index(); + rowSpan = cell.rowSpan || 1; + colSpan = cell.colSpan || 1; + if (typeof(matrix[rowIndex]) === 'undefined') { + matrix[rowIndex] = []; + } + // Find first available column in the first row + for (k = 0; k < matrix[rowIndex].length + 1; k++) { + if (typeof(matrix[rowIndex][k]) === 'undefined') { + firstAvailCol = k; + break; + } + } + lookup[cellId] = firstAvailCol; + // add data-column + $cell.attr({ 'data-column' : firstAvailCol }); // 'data-row' : rowIndex + for (k = rowIndex; k < rowIndex + rowSpan; k++) { + if (typeof(matrix[k]) === 'undefined') { + matrix[k] = []; + } + matrixrow = matrix[k]; + for (l = firstAvailCol; l < firstAvailCol + colSpan; l++) { + matrixrow[l] = 'x'; + } + } + } + } + return matrixrow.length; + }; + + // *** Process table *** + // add processing indicator + ts.isProcessing = function(table, toggle, $ths) { + table = $(table); + var c = table[0].config, + // default to all headers + $h = $ths || table.find('.' + ts.css.header); + if (toggle) { + // don't use sortList if custom $ths used + if (typeof $ths !== 'undefined' && c.sortList.length > 0) { + // get headers from the sortList + $h = $h.filter(function(){ + // get data-column from attr to keep compatibility with jQuery 1.2.6 + return this.sortDisabled ? false : ts.isValueInArray( parseFloat($(this).attr('data-column')), c.sortList) >= 0; + }); + } + table.add($h).addClass(ts.css.processing + ' ' + c.cssProcessing); + } else { + table.add($h).removeClass(ts.css.processing + ' ' + c.cssProcessing); + } + }; + + // detach tbody but save the position + // don't use tbody because there are portions that look for a tbody index (updateCell) + ts.processTbody = function(table, $tb, getIt){ + table = $(table)[0]; + var holdr; + if (getIt) { + table.isProcessing = true; + $tb.before(''); + holdr = ($.fn.detach) ? $tb.detach() : $tb.remove(); + return holdr; + } + holdr = $(table).find('span.tablesorter-savemyplace'); + $tb.insertAfter( holdr ); + holdr.remove(); + table.isProcessing = false; + }; + + ts.clearTableBody = function(table) { + $(table)[0].config.$tbodies.children().detach(); + }; + + ts.bindEvents = function(table, $headers, core) { + table = $(table)[0]; + var t, downTarget = null, + c = table.config; + if (core !== true) { + $headers.addClass( c.namespace.slice(1) + '_extra_headers' ); + t = $.fn.closest ? $headers.closest('table')[0] : $headers.parents('table')[0]; + if (t && t.nodeName === 'TABLE' && t !== table) { + $(t).addClass( c.namespace.slice(1) + '_extra_table' ); + } + } + t = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' ) + .replace(/\s+/g, ' ') + .split(' ') + .join(c.namespace + ' '); + // apply event handling to headers and/or additional headers (stickyheaders, scroller, etc) + $headers + // http://stackoverflow.com/questions/5312849/jquery-find-self; + .find(c.selectorSort).add( $headers.filter(c.selectorSort) ) + .unbind(t) + .bind(t, function(e, external) { + var cell, temp, + $target = $(e.target), + // wrap event type in spaces, so the match doesn't trigger on inner words + type = ' ' + e.type + ' '; + // only recognize left clicks + if ( ( ( e.which || e.button ) !== 1 && !type.match( ' ' + c.pointerClick + ' | sort | keyup ' ) ) || + // allow pressing enter + ( type === ' keyup ' && e.which !== 13 ) || + // allow triggering a click event (e.which is undefined) & ignore physical clicks + ( type.match(' ' + c.pointerClick + ' ') && typeof e.which !== 'undefined' ) ) { + return; + } + // ignore mouseup if mousedown wasn't on the same target + if ( type.match(' ' + c.pointerUp + ' ') && downTarget !== e.target && external !== true ) { return; } + // set target on mousedown + if ( type.match(' ' + c.pointerDown + ' ') ) { + downTarget = e.target; + // preventDefault needed or jQuery v1.3.2 and older throws an + // "Uncaught TypeError: handler.apply is not a function" error + temp = $target.jquery.split( '.' ); + if ( temp[0] === '1' && temp[1] < 4 ) { e.preventDefault(); } + return; + } + downTarget = null; + // prevent sort being triggered on form elements + if ( /(input|select|button|textarea)/i.test(e.target.nodeName) || + // nosort class name, or elements within a nosort container + $target.hasClass(c.cssNoSort) || $target.parents('.' + c.cssNoSort).length > 0 || + // elements within a button + $target.parents('button').length > 0 ) { + return !c.cancelSelection; + } + if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } + // jQuery v1.2.6 doesn't have closest() + cell = $.fn.closest ? $(this).closest('th, td')[0] : /TH|TD/.test(this.nodeName) ? this : $(this).parents('th, td')[0]; + // reference original table headers and find the same cell + cell = c.$headers[ $headers.index( cell ) ]; + if (!cell.sortDisabled) { + initSort(table, cell, e); + } + }); + if (c.cancelSelection) { + // cancel selection + $headers + .attr('unselectable', 'on') + .bind('selectstart', false) + .css({ + 'user-select': 'none', + 'MozUserSelect': 'none' // not needed for jQuery 1.8+ + }); + } + }; + + // restore headers + ts.restoreHeaders = function(table){ + var index, $cell, + c = $(table)[0].config, + $headers = c.$table.find( c.selectorHeaders ), + len = $headers.length; + // don't use c.$headers here in case header cells were swapped + for ( index = 0; index < len; index++ ) { + // c.$table.find(c.selectorHeaders).each(function(i){ + $cell = $headers.eq( index ); + // only restore header cells if it is wrapped + // because this is also used by the updateAll method + if ( $cell.find( '.' + ts.css.headerIn ).length ) { + $cell.html( c.headerContent[ index ] ); + } + } + }; + + ts.destroy = function(table, removeClasses, callback){ + table = $(table)[0]; + if (!table.hasInitialized) { return; } + // remove all widgets + ts.removeWidget(table, true, false); + var events, + $t = $(table), + c = table.config, + $h = $t.find('thead:first'), + $r = $h.find('tr.' + ts.css.headerRow).removeClass(ts.css.headerRow + ' ' + c.cssHeaderRow), + $f = $t.find('tfoot:first > tr').children('th, td'); + if (removeClasses === false && $.inArray('uitheme', c.widgets) >= 0) { + // reapply uitheme classes, in case we want to maintain appearance + $t.trigger('applyWidgetId', ['uitheme']); + $t.trigger('applyWidgetId', ['zebra']); + } + // remove widget added rows, just in case + $h.find('tr').not($r).remove(); + // disable tablesorter + events = 'sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache ' + + 'applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState '.split(' ') + .join(c.namespace + ' '); + $t + .removeData('tablesorter') + .unbind( events.replace(/\s+/g, ' ') ); + c.$headers.add($f) + .removeClass( [ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone].join(' ') ) + .removeAttr('data-column') + .removeAttr('aria-label') + .attr('aria-disabled', 'true'); + $r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(/\s+/g, ' ') ); + ts.restoreHeaders(table); + $t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false); + // clear flag in case the plugin is initialized again + table.hasInitialized = false; + delete table.config.cache; + if (typeof callback === 'function') { + callback(table); + } + }; + + // *** sort functions *** + // regex used in natural sort + ts.regex = { + chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters + chunks: /(^\\0|\\0$)/, // replace chunks @ ends + hex: /^0x[0-9a-f]+$/i // hex + }; + + // Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed) + // this function will only accept strings, or you'll see 'TypeError: undefined is not a function' + // I could add a = a.toString(); b = b.toString(); but it'll slow down the sort overall + ts.sortNatural = function(a, b) { + if (a === b) { return 0; } + var xN, xD, yN, yD, xF, yF, i, mx, + r = ts.regex; + // first try and sort Hex codes + if (r.hex.test(b)) { + xD = parseInt(a.match(r.hex), 16); + yD = parseInt(b.match(r.hex), 16); + if ( xD < yD ) { return -1; } + if ( xD > yD ) { return 1; } + } + // chunk/tokenize + xN = a.replace(r.chunk, '\\0$1\\0').replace(r.chunks, '').split('\\0'); + yN = b.replace(r.chunk, '\\0$1\\0').replace(r.chunks, '').split('\\0'); + mx = Math.max(xN.length, yN.length); + // natural sorting through split numeric strings and default strings + for (i = 0; i < mx; i++) { + // find floats not starting with '0', string or 0 if not defined + xF = isNaN(xN[i]) ? xN[i] || 0 : parseFloat(xN[i]) || 0; + yF = isNaN(yN[i]) ? yN[i] || 0 : parseFloat(yN[i]) || 0; + // handle numeric vs string comparison - number < string - (Kyle Adams) + if (isNaN(xF) !== isNaN(yF)) { return (isNaN(xF)) ? 1 : -1; } + // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' + if (typeof xF !== typeof yF) { + xF += ''; + yF += ''; + } + if (xF < yF) { return -1; } + if (xF > yF) { return 1; } + } + return 0; + }; + + ts.sortNaturalAsc = function(a, b, col, table, c) { + if (a === b) { return 0; } + var e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + return ts.sortNatural(a, b); + }; + + ts.sortNaturalDesc = function(a, b, col, table, c) { + if (a === b) { return 0; } + var e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + return ts.sortNatural(b, a); + }; + + // basic alphabetical sort + ts.sortText = function(a, b) { + return a > b ? 1 : (a < b ? -1 : 0); + }; + + // return text string value by adding up ascii value + // so the text is somewhat sorted when using a digital sort + // this is NOT an alphanumeric sort + ts.getTextValue = function(a, num, mx) { + if (mx) { + // make sure the text value is greater than the max numerical value (mx) + var i, l = a ? a.length : 0, n = mx + num; + for (i = 0; i < l; i++) { + n += a.charCodeAt(i); + } + return num * n; + } + return 0; + }; + + ts.sortNumericAsc = function(a, b, num, mx, col, table) { + if (a === b) { return 0; } + var c = table.config, + e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } + if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } + return a - b; + }; + + ts.sortNumericDesc = function(a, b, num, mx, col, table) { + if (a === b) { return 0; } + var c = table.config, + e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } + if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } + return b - a; + }; + + ts.sortNumeric = function(a, b) { + return a - b; + }; + + // used when replacing accented characters during sorting + ts.characterEquivalents = { + 'a' : '\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5', // áàâãäąå + 'A' : '\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5', // ÁÀÂÃÄĄÅ + 'c' : '\u00e7\u0107\u010d', // çćč + 'C' : '\u00c7\u0106\u010c', // ÇĆČ + 'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę + 'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ + 'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı + 'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ + 'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō + 'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ + 'ss': '\u00df', // ß (s sharp) + 'SS': '\u1e9e', // ẞ (Capital sharp s) + 'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů + 'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ + }; + ts.replaceAccents = function(s) { + var a, acc = '[', eq = ts.characterEquivalents; + if (!ts.characterRegex) { + ts.characterRegexArray = {}; + for (a in eq) { + if (typeof a === 'string') { + acc += eq[a]; + ts.characterRegexArray[a] = new RegExp('[' + eq[a] + ']', 'g'); + } + } + ts.characterRegex = new RegExp(acc + ']'); + } + if (ts.characterRegex.test(s)) { + for (a in eq) { + if (typeof a === 'string') { + s = s.replace( ts.characterRegexArray[a], a ); + } + } + } + return s; + }; + + // *** utilities *** + ts.isValueInArray = function(column, arry) { + var indx, len = arry.length; + for (indx = 0; indx < len; indx++) { + if (arry[indx][0] === column) { + return indx; + } + } + return -1; + }; + + ts.addParser = function(parser) { + var i, l = ts.parsers.length, a = true; + for (i = 0; i < l; i++) { + if (ts.parsers[i].id.toLowerCase() === parser.id.toLowerCase()) { + a = false; + } + } + if (a) { + ts.parsers.push(parser); + } + }; + + // Use it to add a set of methods to table.config which will be available for all tables. + // This should be done before table initialization + ts.addInstanceMethods = function(methods) { + $.extend(ts.instanceMethods, methods); + }; + + ts.getParserById = function(name) { + /*jshint eqeqeq:false */ + if (name == 'false') { return false; } + var i, l = ts.parsers.length; + for (i = 0; i < l; i++) { + if (ts.parsers[i].id.toLowerCase() === (name.toString()).toLowerCase()) { + return ts.parsers[i]; + } + } + return false; + }; + + ts.addWidget = function(widget) { + ts.widgets.push(widget); + }; + + ts.hasWidget = function(table, name){ + table = $(table); + return table.length && table[0].config && table[0].config.widgetInit[name] || false; + }; + + ts.getWidgetById = function(name) { + var i, w, l = ts.widgets.length; + for (i = 0; i < l; i++) { + w = ts.widgets[i]; + if (w && w.hasOwnProperty('id') && w.id.toLowerCase() === name.toLowerCase()) { + return w; + } + } + }; + + ts.applyWidgetOptions = function( table, c ){ + var indx, widget, + len = c.widgets.length, + wo = c.widgetOptions; + if (len) { + for (indx = 0; indx < len; indx++) { + widget = ts.getWidgetById( c.widgets[indx] ); + if ( widget && 'options' in widget ) { + wo = table.config.widgetOptions = $.extend( true, {}, widget.options, wo ); + } + } + } + }; + + ts.applyWidget = function(table, init, callback) { + table = $(table)[0]; // in case this is called externally + var indx, len, name, + c = table.config, + wo = c.widgetOptions, + tableClass = ' ' + c.table.className + ' ', + widgets = [], + time, time2, w, wd; + // prevent numerous consecutive widget applications + if (init !== false && table.hasInitialized && (table.isApplyingWidgets || table.isUpdating)) { return; } + if (c.debug) { time = new Date(); } + // look for widgets to apply from in table class + // stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget + wd = new RegExp( '\\s' + c.widgetClass.replace( /\{name\}/i, '([\\w-]+)' )+ '\\s', 'g' ); + if ( tableClass.match( wd ) ) { + // extract out the widget id from the table class (widget id's can include dashes) + w = tableClass.match( wd ); + if ( w ) { + len = w.length; + for (indx = 0; indx < len; indx++) { + c.widgets.push( w[indx].replace( wd, '$1' ) ); + } + } + } + if (c.widgets.length) { + table.isApplyingWidgets = true; + // ensure unique widget ids + c.widgets = $.grep(c.widgets, function(v, k){ + return $.inArray(v, c.widgets) === k; + }); + name = c.widgets || []; + len = name.length; + // build widget array & add priority as needed + for (indx = 0; indx < len; indx++) { + wd = ts.getWidgetById(name[indx]); + if (wd && wd.id) { + // set priority to 10 if not defined + if (!wd.priority) { wd.priority = 10; } + widgets[indx] = wd; + } + } + // sort widgets by priority + widgets.sort(function(a, b){ + return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1; + }); + // add/update selected widgets + len = widgets.length; + for (indx = 0; indx < len; indx++) { + if (widgets[indx]) { + if ( init || !( c.widgetInit[ widgets[indx].id ] ) ) { + // set init flag first to prevent calling init more than once (e.g. pager) + c.widgetInit[ widgets[indx].id ] = true; + if (table.hasInitialized) { + // don't reapply widget options on tablesorter init + ts.applyWidgetOptions( table, c ); + } + if ( 'init' in widgets[indx] ) { + if (c.debug) { time2 = new Date(); } + widgets[indx].init(table, widgets[indx], c, wo); + if (c.debug) { ts.benchmark('Initializing ' + widgets[indx].id + ' widget', time2); } + } + } + if ( !init && 'format' in widgets[indx] ) { + if (c.debug) { time2 = new Date(); } + widgets[indx].format(table, c, wo, false); + if (c.debug) { ts.benchmark( ( init ? 'Initializing ' : 'Applying ' ) + widgets[indx].id + ' widget', time2); } + } + } + } + // callback executed on init only + if (!init && typeof callback === 'function') { + callback(table); + } + } + setTimeout(function(){ + table.isApplyingWidgets = false; + $.data(table, 'lastWidgetApplication', new Date()); + }, 0); + if (c.debug) { + w = c.widgets.length; + benchmark('Completed ' + (init === true ? 'initializing ' : 'applying ') + w + ' widget' + (w !== 1 ? 's' : ''), time); + } + }; + + ts.removeWidget = function(table, name, refreshing){ + table = $(table)[0]; + var i, widget, indx, len, + c = table.config; + // if name === true, add all widgets from $.tablesorter.widgets + if (name === true) { + name = []; + len = ts.widgets.length; + for (indx = 0; indx < len; indx++) { + widget = ts.widgets[indx]; + if (widget && widget.id) { + name.push( widget.id ); + } + } + } else { + // name can be either an array of widgets names, + // or a space/comma separated list of widget names + name = ( $.isArray(name) ? name.join(',') : name || '' ).toLowerCase().split( /[\s,]+/ ); + } + len = name.length; + for (i = 0; i < len; i++) { + widget = ts.getWidgetById(name[i]); + indx = $.inArray( name[i], c.widgets ); + if ( widget && 'remove' in widget ) { + if (c.debug && indx >= 0) { log( 'Removing "' + name[i] + '" widget' ); } + widget.remove(table, c, c.widgetOptions, refreshing); + c.widgetInit[ name[i] ] = false; + } + // don't remove the widget from config.widget if refreshing + if (indx >= 0 && refreshing !== true) { + c.widgets.splice( indx, 1 ); + } + } + }; + + ts.refreshWidgets = function(table, doAll, dontapply) { + table = $(table)[0]; // see issue #243 + var indx, + c = table.config, + cw = c.widgets, + widgets = ts.widgets, + len = widgets.length, + list = [], + callback = function(table){ + $(table).trigger('refreshComplete'); + }; + // remove widgets not defined in config.widgets, unless doAll is true + for (indx = 0; indx < len; indx++) { + if (widgets[indx] && widgets[indx].id && (doAll || $.inArray( widgets[indx].id, cw ) < 0)) { + list.push( widgets[indx].id ); + } + } + ts.removeWidget( table, list.join(','), true ); + if (dontapply !== true) { + // call widget init if + ts.applyWidget(table, doAll || false, callback ); + if (doAll) { + // apply widget format + ts.applyWidget(table, false, callback); + } + } else { + callback(table); + } + }; + + ts.getColumnText = function( table, column, callback ) { + table = $( table )[0]; + var tbodyIndex, rowIndex, cache, row, tbodyLen, rowLen, raw, parsed, $cell, result, + hasCallback = typeof callback === 'function', + allColumns = column === 'all', + data = { raw : [], parsed: [], $cell: [] }, + c = table.config; + if ( !isEmptyObject( c ) ) { + tbodyLen = c.$tbodies.length; + for ( tbodyIndex = 0; tbodyIndex < tbodyLen; tbodyIndex++ ) { + cache = c.cache[ tbodyIndex ].normalized; + rowLen = cache.length; + for ( rowIndex = 0; rowIndex < rowLen; rowIndex++ ) { + result = true; + row = cache[ rowIndex ]; + parsed = ( allColumns ) ? row.slice(0, c.columns) : row[ column ]; + row = row[ c.columns ]; + raw = ( allColumns ) ? row.raw : row.raw[ column ]; + $cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column ); + if ( hasCallback ) { + result = callback({ + tbodyIndex: tbodyIndex, + rowIndex: rowIndex, + parsed: parsed, + raw: raw, + $row: row.$row, + $cell: $cell + }); + } + if ( result !== false ) { + data.parsed.push( parsed ); + data.raw.push( raw ); + data.$cell.push( $cell ); + } + } + } + // return everything + return data; + } + }; + + // get sorter, string, empty, etc options for each column from + // jQuery data, metadata, header option or header class name ('sorter-false') + // priority = jQuery data > meta > headers option > header class name + ts.getData = function(h, ch, key) { + var val = '', $h = $(h), m, cl; + if (!$h.length) { return ''; } + m = $.metadata ? $h.metadata() : false; + cl = ' ' + ($h.attr('class') || ''); + if (typeof $h.data(key) !== 'undefined' || typeof $h.data(key.toLowerCase()) !== 'undefined'){ + // 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder' + // 'data-sort-initial-order' is assigned to 'sortInitialOrder' + val += $h.data(key) || $h.data(key.toLowerCase()); + } else if (m && typeof m[key] !== 'undefined') { + val += m[key]; + } else if (ch && typeof ch[key] !== 'undefined') { + val += ch[key]; + } else if (cl !== ' ' && cl.match(' ' + key + '-')) { + // include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser' + val = cl.match( new RegExp('\\s' + key + '-([\\w-]+)') )[1] || ''; + } + return $.trim(val); + }; + + ts.formatFloat = function(s, table) { + if (typeof s !== 'string' || s === '') { return s; } + // allow using formatFloat without a table; defaults to US number format + var i, + t = table && table.config ? table.config.usNumberFormat !== false : + typeof table !== 'undefined' ? table : true; + if (t) { + // US Format - 1,234,567.89 -> 1234567.89 + s = s.replace(/,/g,''); + } else { + // German Format = 1.234.567,89 -> 1234567.89 + // French Format = 1 234 567,89 -> 1234567.89 + s = s.replace(/[\s|\.]/g,'').replace(/,/g,'.'); + } + if(/^\s*\([.\d]+\)/.test(s)) { + // make (#) into a negative number -> (10) = -10 + s = s.replace(/^\s*\(([.\d]+)\)/, '-$1'); + } + i = parseFloat(s); + // return the text instead of zero + return isNaN(i) ? $.trim(s) : i; + }; + + ts.isDigit = function(s) { + // replace all unwanted chars and match + return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : s !== ''; + }; + + }() + }); + + // make shortcut + var ts = $.tablesorter; + + // extend plugin scope + $.fn.extend({ + tablesorter: ts.construct + }); + + // add default parsers + ts.addParser({ + id: 'no-parser', + is: function() { + return false; + }, + format: function() { + return ''; + }, + type: 'text' + }); + + ts.addParser({ + id: 'text', + is: function() { + return true; + }, + format: function(s, table) { + var c = table.config; + if (s) { + s = $.trim( c.ignoreCase ? s.toLocaleLowerCase() : s ); + s = c.sortLocaleCompare ? ts.replaceAccents(s) : s; + } + return s; + }, + type: 'text' + }); + + ts.addParser({ + id: 'digit', + is: function(s) { + return ts.isDigit(s); + }, + format: function(s, table) { + var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table); + return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'currency', + is: function(s) { + return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test((s || '').replace(/[+\-,. ]/g,'')); // £$€¤¥¢ + }, + format: function(s, table) { + var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table); + return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'url', + is: function(s) { + return (/^(https?|ftp|file):\/\//).test(s); + }, + format: function(s) { + return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s; + }, + parsed : true, // filter widget flag + type: 'text' + }); + + ts.addParser({ + id: 'isoDate', + is: function(s) { + return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s); + }, + format: function(s, table) { + var date = s ? new Date( s.replace(/-/g, '/') ) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'percent', + is: function(s) { + return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15; + }, + format: function(s, table) { + return s ? ts.formatFloat(s.replace(/%/g, ''), table) : s; + }, + type: 'numeric' + }); + + // added image parser to core v2.17.9 + ts.addParser({ + id: 'image', + is: function(s, table, node, $node){ + return $node.find('img').length > 0; + }, + format: function(s, table, cell) { + return $(cell).find('img').attr(table.config.imgAttr || 'alt') || s; + }, + parsed : true, // filter widget flag + type: 'text' + }); + + ts.addParser({ + id: 'usLongDate', + is: function(s) { + // two digit years are not allowed cross-browser + // Jan 01, 2013 12:34:56 PM or 01 Jan 2013 + return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) || (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s); + }, + format: function(s, table) { + var date = s ? new Date( s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd' + is: function(s) { + // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included + return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test((s || '').replace(/\s+/g,' ').replace(/[\-.,]/g, '/')); + }, + format: function(s, table, cell, cellIndex) { + if (s) { + var date, d, + c = table.config, + ci = c.$headerIndexed[ cellIndex ], + format = ci.length && ci[0].dateFormat || ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') || c.dateFormat; + d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/'); // escaped - because JSHint in Firefox was showing it as an error + if (format === 'mmddyyyy') { + d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$1/$2'); + } else if (format === 'ddmmyyyy') { + d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$2/$1'); + } else if (format === 'yyyymmdd') { + d = d.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, '$1/$2/$3'); + } + date = new Date(d); + return date instanceof Date && isFinite(date) ? date.getTime() : s; + } + return s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'time', + is: function(s) { + return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s); + }, + format: function(s, table) { + var date = s ? new Date( '2000/01/01 ' + s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'metadata', + is: function() { + return false; + }, + format: function(s, table, cell) { + var c = table.config, + p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; + return $(cell).metadata()[p]; + }, + type: 'numeric' + }); + + // add default widgets + ts.addWidget({ + id: 'zebra', + priority: 90, + format: function(table, c, wo) { + var $tv, $tr, row, even, time, k, i, len, + child = new RegExp(c.cssChildRow, 'i'), + b = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) ); + if (c.debug) { + time = new Date(); + } + for (k = 0; k < b.length; k++ ) { + // loop through the visible rows + row = 0; + $tv = b.eq( k ).children( 'tr:visible' ).not( c.selectorRemove ); + len = $tv.length; + for ( i = 0; i < len; i++ ) { + $tr = $tv.eq( i ); + // style child rows the same way the parent row was styled + if ( !child.test( $tr[0].className ) ) { row++; } + even = ( row % 2 === 0 ); + $tr + .removeClass( wo.zebra[ even ? 1 : 0 ] ) + .addClass( wo.zebra[ even ? 0 : 1 ] ); + } + } + }, + remove: function(table, c, wo, refreshing){ + if (refreshing) { return; } + var k, $tb, + b = c.$tbodies, + rmv = (wo.zebra || [ 'even', 'odd' ]).join(' '); + for (k = 0; k < b.length; k++ ){ + $tb = ts.processTbody(table, b.eq(k), true); // remove tbody + $tb.children().removeClass(rmv); + ts.processTbody(table, $tb, false); // restore tbody + } + } + }); + +})(jQuery); + +return $.tablesorter; +})); diff --git a/dist/js/jquery.tablesorter.min.js b/dist/js/jquery.tablesorter.min.js new file mode 100644 index 0000000..263a5a6 --- /dev/null +++ b/dist/js/jquery.tablesorter.min.js @@ -0,0 +1,2 @@ +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){return function(a){"use strict";a.extend({tablesorter:new function(){function b(){var a=arguments[0],b=arguments.length>1?Array.prototype.slice.call(arguments):a;"undefined"!=typeof console&&"undefined"!=typeof console.log?console[/error/i.test(a)?"error":/warn/i.test(a)?"warn":"log"](b):alert(b)}function c(a,c){b(a+" ("+((new Date).getTime()-c.getTime())+"ms)")}function d(a){for(var b in a)return!1;return!0}function e(c,d,e,f){for(var g,h,i=u.parsers.length,j=!1,k="",l=!0;""===k&&l;)e++,d[e]?(j=d[e].cells[f],k=u.getElementText(c,j,f),h=a(j),c.debug&&b("Checking if value was empty on row "+e+", column: "+f+': "'+k+'"')):l=!1;for(;--i>=0;)if(g=u.parsers[i],g&&"text"!==g.id&&g.is&&g.is(k,c.table,j,h))return g;return u.getParserById("text")}function f(a,d){var f,g,h,i,j,k,l,m,n,o,p,q,r=a.table,s=0,t="";if(a.$tbodies=a.$table.children("tbody:not(."+a.cssInfoBlock+")"),p="undefined"==typeof d?a.$tbodies:d,q=p.length,0===q)return a.debug?b("Warning: *Empty table!* Not building a parser cache"):"";for(a.debug&&(o=new Date,b("Detecting parsers for each column")),g={extractors:[],parsers:[]};q>s;){if(f=p[s].rows,f.length)for(h=a.columns,i=0;h>i;i++)j=a.$headerIndexed[i],k=u.getColumnData(r,a.headers,i),n=u.getParserById(u.getData(j,k,"extractor")),m=u.getParserById(u.getData(j,k,"sorter")),l="false"===u.getData(j,k,"parser"),a.empties[i]=(u.getData(j,k,"empty")||a.emptyTo||(a.emptyToBottom?"bottom":"top")).toLowerCase(),a.strings[i]=(u.getData(j,k,"string")||a.stringTo||"max").toLowerCase(),l&&(m=u.getParserById("no-parser")),n||(n=!1),m||(m=e(a,f,-1,i)),a.debug&&(t+="column:"+i+"; extractor:"+n.id+"; parser:"+m.id+"; string:"+a.strings[i]+"; empty: "+a.empties[i]+"\n"),g.parsers[i]=m,g.extractors[i]=n;s+=g.parsers.length?q:1}a.debug&&(b(t?t:"No parsers detected"),c("Completed detecting parsers",o)),a.parsers=g.parsers,a.extractors=g.extractors}function g(d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t=d.config,v=t.parsers;if(t.$tbodies=t.$table.children("tbody:not(."+t.cssInfoBlock+")"),l="undefined"==typeof e?t.$tbodies:e,t.cache={},t.totalRows=0,!v)return t.debug?b("Warning: *Empty table!* Not building a cache"):"";for(t.debug&&(o=new Date),t.showProcessing&&u.isProcessing(d,!0),k=0;ki;++i)if(q={child:[],raw:[]},m=a(l[k].rows[i]),n=[],m.hasClass(t.cssChildRow)&&0!==i)for(g=f.normalized.length-1,r=f.normalized[g][t.columns],r.$row=r.$row.add(m),m.prev().hasClass(t.cssChildRow)||m.prev().addClass(u.css.cssHasChild),h=m.children("th, td"),g=r.child.length,r.child[g]=[],j=0;ji;i++)o.push(e[i][l.columns].$row),l.appender&&(!l.pager||l.pager.removeRows&&m.pager_removeRows||l.pager.ajax)||h.append(e[i][l.columns].$row);u.processTbody(a,h,!1)}l.appender&&l.appender(a,o),l.debug&&c("Rebuilt table",k),b||l.appender||u.applyWidget(a),a.isUpdating&&l.$table.trigger("updateComplete",a)}function i(a){return/^d/i.test(a)||1===a}function j(d){var e,f,g,h,j,k,m,n,o=d.config;for(o.headerList=[],o.headerContent=[],o.debug&&(m=new Date),o.columns=u.computeColumnIndex(o.$table.children("thead, tfoot").children("tr")),h=o.cssIcon?'':"",o.$headers=a(a.map(a(d).find(o.selectorHeaders),function(b,c){return f=a(b),f.parent().hasClass(o.cssIgnoreRow)?void 0:(e=u.getColumnData(d,o.headers,c,!0),o.headerContent[c]=f.html(),""===o.headerTemplate||f.find("."+u.css.headerIn).length||(j=o.headerTemplate.replace(/\{content\}/g,f.html()).replace(/\{icon\}/g,f.find("."+u.css.icon).length?"":h),o.onRenderTemplate&&(g=o.onRenderTemplate.apply(f,[c,j]),g&&"string"==typeof g&&(j=g)),f.html('
    '+j+"
    ")),o.onRenderHeader&&o.onRenderHeader.apply(f,[c,o,o.$table]),b.column=parseInt(f.attr("data-column"),10),b.order=i(u.getData(f,e,"sortInitialOrder")||o.sortInitialOrder)?[1,0,2]:[0,1,2],b.count=-1,b.lockedOrder=!1,k=u.getData(f,e,"lockedOrder")||!1,"undefined"!=typeof k&&k!==!1&&(b.order=b.lockedOrder=i(k)?[1,1,1]:[0,0,0]),f.addClass(u.css.header+" "+o.cssHeader),o.headerList[c]=b,f.parent().addClass(u.css.headerRow+" "+o.cssHeaderRow).attr("role","row"),o.tabIndex&&f.attr("tabindex",0),b)})),o.$headerIndexed=[],n=0;nb;b++)d=f.$headers.eq(b),e=u.getColumnData(a,f.headers,b,!0),c="false"===u.getData(d,e,"sorter")||"false"===u.getData(d,e,"parser"),d[0].sortDisabled=c,d[c?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+c),a.id&&(c?d.removeAttr("aria-controls"):d.attr("aria-controls",a.id))}function m(b){var c,d,e,f,g,h,i,j,k=b.config,l=k.sortList,m=l.length,n=u.css.sortNone+" "+k.cssNone,o=[u.css.sortAsc+" "+k.cssAsc,u.css.sortDesc+" "+k.cssDesc],p=[k.cssIconAsc,k.cssIconDesc,k.cssIconNone],q=["ascending","descending"],r=a(b).find("tfoot tr").children().add(a(k.namespace+"_extra_headers")).removeClass(o.join(" "));for(k.$headers.removeClass(o.join(" ")).addClass(n).attr("aria-sort","none").find("."+u.css.icon).removeClass(p.join(" ")).addClass(p[2]),e=0;m>e;e++)if(2!==l[e][1]&&(c=k.$headers.not(".sorter-false").filter('[data-column="'+l[e][0]+'"]'+(1===m?":last":"")),c.length)){for(f=0;fe;e++)h=g.eq(e),h.length&&(d=g[e],i=d.order[(d.count+1)%(k.sortReset?3:2)],j=a.trim(h.text())+": "+u.language[h.hasClass(u.css.sortAsc)?"sortAsc":h.hasClass(u.css.sortDesc)?"sortDesc":"sortNone"]+u.language[0===i?"nextAsc":1===i?"nextDesc":"nextNone"],h.attr("aria-label",j))}function n(b,c){var d,e,f,g,h,i,j,k,l=b.config,m=c||l.sortList,n=m.length;for(l.sortList=[],h=0;n>h;h++)if(k=m[h],d=parseInt(k[0],10),d=0?e:f[1]%(l.sortReset?3:2)}}function o(a,b){return a&&a[b]?a[b].type||"":""}function p(b,c,d){if(b.isUpdating)return setTimeout(function(){p(b,c,d)},50);var e,f,g,i,j,k,l,n=b.config,o=!d[n.sortMultiSortKey],r=n.$table,s=n.$headers.length;if(r.trigger("sortStart",b),c.count=d[n.sortResetKey]?2:(c.count+1)%(n.sortReset?3:2),n.sortRestart)for(f=c,g=0;s>g;g++)l=n.$headers.eq(g),l[0]===f||!o&&l.is("."+u.css.sortDesc+",."+u.css.sortAsc)||(l[0].count=-1);if(f=parseInt(a(c).attr("data-column"),10),o){if(n.sortList=[],null!==n.sortForce)for(e=n.sortForce,i=0;ij&&(n.sortList.push([f,j]),c.colSpan>1))for(i=1;i1)for(i=0;i=0&&n.sortList.splice(k,1);if(u.isValueInArray(f,n.sortList)>=0)for(i=0;ij&&(n.sortList.push([f,j]),c.colSpan>1))for(i=1;ie;e++)i=q.cache[e].colMax,j=q.cache[e].normalized,j.sort(function(c,d){for(b=0;t>b;b++){if(g=s[b][0],k=s[b][1],p=0===k,q.sortStable&&c[g]===d[g]&&1===t)return c[q.columns].order-d[q.columns].order;if(f=/n/i.test(o(q.parsers,g)),f&&q.strings[g]?(f="boolean"==typeof q.string[q.strings[g]]?(p?1:-1)*(q.string[q.strings[g]]?-1:1):q.strings[g]?q.string[q.strings[g]]||0:0,l=q.numberSorter?q.numberSorter(c[g],d[g],p,i[g],a):u["sortNumeric"+(p?"Asc":"Desc")](c[g],d[g],f,i[g],g,a)):(m=p?c:d,n=p?d:c,l="function"==typeof r?r(m[g],n[g],p,g,a):"object"==typeof r&&r.hasOwnProperty(g)?r[g](m[g],n[g],p,g,a):u["sortNatural"+(p?"Asc":"Desc")](c[g],d[g],g,a,q)),l)return l}return c[q.columns].order-d[q.columns].order});q.debug&&c("Sorting on "+s.toString()+" and dir "+k+" time",h)}}function r(b,c){b.table.isUpdating&&b.$table.trigger("updateComplete",b.table),a.isFunction(c)&&c(b.table)}function s(b,c,d){var e=a.isArray(c)?c:b.sortList,f="undefined"==typeof c?b.resort:c;f===!1||b.serverSideSorting||b.table.isProcessing?(r(b,d),u.applyWidget(b.table,!1)):e.length?b.$table.trigger("sorton",[e,function(){r(b,d)},!0]):b.$table.trigger("sortReset",[function(){r(b,d),u.applyWidget(b.table,!1)}])}function t(b){var c=b.config,e=c.$table,i="sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(c.namespace+" ");e.unbind(i.replace(/\s+/g," ")).bind("sortReset"+c.namespace,function(d,e){d.stopPropagation(),c.sortList=[],m(b),q(b),h(b),a.isFunction(e)&&e(b)}).bind("updateAll"+c.namespace,function(a,d,e){a.stopPropagation(),b.isUpdating=!0,u.refreshWidgets(b,!0,!0),j(b),u.bindEvents(b,c.$headers,!0),t(b),k(b,d,e)}).bind("update"+c.namespace+" updateRows"+c.namespace,function(a,c,d){a.stopPropagation(),b.isUpdating=!0,l(b),k(b,c,d)}).bind("updateCell"+c.namespace,function(d,f,g,h){d.stopPropagation(),b.isUpdating=!0,e.find(c.selectorRemove).remove();var i,j,k,l,m=c.$tbodies,n=a(f),o=m.index(a.fn.closest?n.closest("tbody"):n.parents("tbody").filter(":first")),p=c.cache[o],q=a.fn.closest?n.closest("tr"):n.parents("tr").filter(":first");f=n[0],m.length&&o>=0&&(j=m.eq(o).find("tr").index(q),l=p.normalized[j],k=n.index(),i=u.getParsedText(c,f,k),l[k]=i,l[c.columns].$row=q,"numeric"===(c.parsers[k].type||"").toLowerCase()&&(p.colMax[k]=Math.max(Math.abs(i)||0,p.colMax[k]||0)),i="undefined"!==g?g:c.resort,i!==!1?s(c,i,h):(a.isFunction(h)&&h(b),c.$table.trigger("updateComplete",c.table)))}).bind("addRows"+c.namespace,function(e,g,h,i){if(e.stopPropagation(),b.isUpdating=!0,d(c.cache))l(b),k(b,h,i);else{g=a(g).attr("role","row");var j,m,n,o,p,q=g.filter("tr").length,r=c.$tbodies.index(g.parents("tbody").filter(":first"));for(c.parsers&&c.parsers.length||f(c),j=0;q>j;j++){for(n=g[j].cells.length,p=[],o={child:[],$row:g.eq(j),order:c.cache[r].normalized.length},m=0;n>m;m++)p[m]=u.getParsedText(c,g[j].cells[m],m),"numeric"===(c.parsers[m].type||"").toLowerCase()&&(c.cache[r].colMax[m]=Math.max(Math.abs(p[m])||0,c.cache[r].colMax[m]||0));p.push(o),c.cache[r].normalized.push(p)}s(c,h,i)}}).bind("updateComplete"+c.namespace,function(){b.isUpdating=!1}).bind("sorton"+c.namespace,function(c,f,i,j){var k=b.config;c.stopPropagation(),e.trigger("sortStart",this),n(b,f),m(b),k.delayInit&&d(k.cache)&&g(b),e.trigger("sortBegin",this),q(b),h(b,j),e.trigger("sortEnd",this),u.applyWidget(b),a.isFunction(i)&&i(b)}).bind("appendCache"+c.namespace,function(c,d,e){c.stopPropagation(),h(b,e),a.isFunction(d)&&d(b)}).bind("updateCache"+c.namespace,function(d,e,h){c.parsers&&c.parsers.length||f(c,h),g(b,h),a.isFunction(e)&&e(b)}).bind("applyWidgetId"+c.namespace,function(a,d){a.stopPropagation(),u.getWidgetById(d).format(b,c,c.widgetOptions)}).bind("applyWidgets"+c.namespace,function(a,c){a.stopPropagation(),u.applyWidget(b,c)}).bind("refreshWidgets"+c.namespace,function(a,c,d){a.stopPropagation(),u.refreshWidgets(b,c,d)}).bind("destroy"+c.namespace,function(a,c,d){a.stopPropagation(),u.destroy(b,c,d)}).bind("resetToLoadState"+c.namespace,function(){u.removeWidget(b,!0,!1),c=a.extend(!0,u.defaults,c.originalSettings),b.hasInitialized=!1,u.setup(b,c)})}var u=this;u.version="2.22.1",u.parsers=[],u.widgets=[],u.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",textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,widgets:[],widgetOptions:{zebra:["even","odd"]},initWidgets:!0,widgetClass:"widget-{name}",initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",cssInfoBlock:"tablesorter-infoOnly",cssNoSort:"tablesorter-noSort",cssIgnoreRow:"tablesorter-ignoreRow",pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[]},u.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"},u.language={sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"},u.instanceMethods={},u.log=b,u.benchmark=c,u.getElementText=function(b,c,d){if(!c)return"";var e,f=b.textExtraction||"",g=c.jquery?c:a(c);return"string"==typeof f?a.trim(("basic"===f?g.attr(b.textAttribute)||c.textContent:c.textContent)||g.text()):"function"==typeof f?a.trim(f(g[0],b.table,d)):"function"==typeof(e=u.getColumnData(b.table,f,d))?a.trim(e(g[0],b.table,d)):a.trim(g[0].textContent||g.text())},u.getParsedText=function(a,b,c,d){"undefined"==typeof d&&(d=u.getElementText(a,b,c));var e=""+d,f=a.parsers[c],g=a.extractors[c];return f&&(g&&"function"==typeof g.format&&(d=g.format(d,a.table,b,c)),e="no-parser"===f.id?"":f.format(""+d,a.table,b,c),a.ignoreCase&&"string"==typeof e&&(e=e.toLowerCase())),e},u.construct=function(b){return this.each(function(){var c=this,d=a.extend(!0,{},u.defaults,b,u.instanceMethods);d.originalSettings=b,!c.hasInitialized&&u.buildTable&&"TABLE"!==this.nodeName?u.buildTable(c,d):u.setup(c,d)})},u.setup=function(c,d){if(!c||!c.tHead||0===c.tBodies.length||c.hasInitialized===!0)return d.debug?b("ERROR: stopping initialization! No table, thead, tbody or tablesorter has already been initialized"):"";var e="",h=a(c),i=a.metadata;c.hasInitialized=!1,c.isProcessing=!0,c.config=d,a.data(c,"tablesorter",d),d.debug&&a.data(c,"startoveralltimer",new Date),d.supportsDataObject=function(a){return a[0]=parseInt(a[0],10),a[0]>1||1===a[0]&&parseInt(a[1],10)>=4}(a.fn.jquery.split(".")),d.string={max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1},d.emptyTo=d.emptyTo.toLowerCase(),d.stringTo=d.stringTo.toLowerCase(),/tablesorter\-/.test(h.attr("class"))||(e=""!==d.theme?" tablesorter-"+d.theme:""),d.table=c,d.$table=h.addClass(u.css.table+" "+d.tableClass+e).attr("role","grid"),d.$headers=h.find(d.selectorHeaders),d.namespace?d.namespace="."+d.namespace.replace(/\W/g,""):d.namespace=".tablesorter"+Math.random().toString(16).slice(2),d.$table.children().children("tr").attr("role","row"),d.$tbodies=h.children("tbody:not(."+d.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"}),d.$table.children("caption").length&&(e=d.$table.children("caption")[0],e.id||(e.id=d.namespace.slice(1)+"caption"),d.$table.attr("aria-labelledby",e.id)),d.widgetInit={},d.textExtraction=d.$table.attr("data-text-extraction")||d.textExtraction||"basic",j(c),u.fixColumnWidth(c),u.applyWidgetOptions(c,d),f(d),d.totalRows=0,d.delayInit||g(c),u.bindEvents(c,d.$headers,!0),t(c),d.supportsDataObject&&"undefined"!=typeof h.data().sortlist?d.sortList=h.data().sortlist:i&&h.metadata()&&h.metadata().sortlist&&(d.sortList=h.metadata().sortlist),u.applyWidget(c,!0),d.sortList.length>0?h.trigger("sorton",[d.sortList,{},!d.initWidgets,!0]):(m(c),d.initWidgets&&u.applyWidget(c,!1)),d.showProcessing&&h.unbind("sortBegin"+d.namespace+" sortEnd"+d.namespace).bind("sortBegin"+d.namespace+" sortEnd"+d.namespace,function(a){clearTimeout(d.processTimer),u.isProcessing(c),"sortBegin"===a.type&&(d.processTimer=setTimeout(function(){u.isProcessing(c,!0)},500))}),c.hasInitialized=!0,c.isProcessing=!1,d.debug&&u.benchmark("Overall initialization time",a.data(c,"startoveralltimer")),h.trigger("tablesorter-initialized",c),"function"==typeof d.initialized&&d.initialized(c)},u.fixColumnWidth=function(b){b=a(b)[0];var c,d,e,f,g,h=b.config,i=h.$table.children("colgroup");if(i.length&&i.hasClass(u.css.colgroup)&&i.remove(),h.widthFixed&&0===h.$table.children("colgroup").length){for(i=a(''),c=h.$table.width(),e=h.$tbodies.find("tr:first").children(":visible"),f=e.length,g=0;f>g;g++)d=parseInt(e.eq(g).width()/c*1e3,10)/10+"%",i.append(a("").css("width",d));h.$table.prepend(i)}},u.getColumnData=function(b,c,d,e,f){if("undefined"!=typeof c&&null!==c){b=a(b)[0];var g,h,i=b.config,j=f||i.$headers,k=i.$headerIndexed&&i.$headerIndexed[d]||j.filter('[data-column="'+d+'"]:last');if(c[d])return e?c[d]:c[j.index(k)];for(h in c)if("string"==typeof h&&(g=k.filter(h).add(k.find(h)),g.length))return c[h]}},u.computeColumnIndex=function(b){var c,d,e,f,g,h,i,j,k,l,m,n,o=[],p=[],q={};for(c=0;ce;e++)for("undefined"==typeof o[e]&&(o[e]=[]),p=o[e],f=n;n+m>f;f++)p[f]="x"}return p.length},u.isProcessing=function(b,c,d){b=a(b);var e=b[0].config,f=d||b.find("."+u.css.header);c?("undefined"!=typeof d&&e.sortList.length>0&&(f=f.filter(function(){return this.sortDisabled?!1:u.isValueInArray(parseFloat(a(this).attr("data-column")),e.sortList)>=0})),b.add(f).addClass(u.css.processing+" "+e.cssProcessing)):b.add(f).removeClass(u.css.processing+" "+e.cssProcessing)},u.processTbody=function(b,c,d){b=a(b)[0];var e;return d?(b.isProcessing=!0,c.before(''),e=a.fn.detach?c.detach():c.remove()):(e=a(b).find("span.tablesorter-savemyplace"),c.insertAfter(e),e.remove(),void(b.isProcessing=!1))},u.clearTableBody=function(b){a(b)[0].config.$tbodies.children().detach()},u.bindEvents=function(b,c,e){b=a(b)[0];var f,h=null,i=b.config;e!==!0&&(c.addClass(i.namespace.slice(1)+"_extra_headers"),f=a.fn.closest?c.closest("table")[0]:c.parents("table")[0],f&&"TABLE"===f.nodeName&&f!==b&&a(f).addClass(i.namespace.slice(1)+"_extra_table")),f=(i.pointerDown+" "+i.pointerUp+" "+i.pointerClick+" sort keyup ").replace(/\s+/g," ").split(" ").join(i.namespace+" "),c.find(i.selectorSort).add(c.filter(i.selectorSort)).unbind(f).bind(f,function(e,f){var j,k,l=a(e.target),m=" "+e.type+" ";if(!(1!==(e.which||e.button)&&!m.match(" "+i.pointerClick+" | sort | keyup ")||" keyup "===m&&13!==e.which||m.match(" "+i.pointerClick+" ")&&"undefined"!=typeof e.which||m.match(" "+i.pointerUp+" ")&&h!==e.target&&f!==!0)){if(m.match(" "+i.pointerDown+" "))return h=e.target,k=l.jquery.split("."),void("1"===k[0]&&k[1]<4&&e.preventDefault());if(h=null,/(input|select|button|textarea)/i.test(e.target.nodeName)||l.hasClass(i.cssNoSort)||l.parents("."+i.cssNoSort).length>0||l.parents("button").length>0)return!i.cancelSelection;i.delayInit&&d(i.cache)&&g(b),j=a.fn.closest?a(this).closest("th, td")[0]:/TH|TD/.test(this.nodeName)?this:a(this).parents("th, td")[0],j=i.$headers[c.index(j)],j.sortDisabled||p(b,j,e)}}),i.cancelSelection&&c.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})},u.restoreHeaders=function(b){var c,d,e=a(b)[0].config,f=e.$table.find(e.selectorHeaders),g=f.length;for(c=0;g>c;c++)d=f.eq(c),d.find("."+u.css.headerIn).length&&d.html(e.headerContent[c])},u.destroy=function(b,c,d){if(b=a(b)[0],b.hasInitialized){u.removeWidget(b,!0,!1);var e,f=a(b),g=b.config,h=f.find("thead:first"),i=h.find("tr."+u.css.headerRow).removeClass(u.css.headerRow+" "+g.cssHeaderRow),j=f.find("tfoot:first > tr").children("th, td");c===!1&&a.inArray("uitheme",g.widgets)>=0&&(f.trigger("applyWidgetId",["uitheme"]),f.trigger("applyWidgetId",["zebra"])),h.find("tr").not(i).remove(),e="sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache "+"applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState ".split(" ").join(g.namespace+" "),f.removeData("tablesorter").unbind(e.replace(/\s+/g," ")),g.$headers.add(j).removeClass([u.css.header,g.cssHeader,g.cssAsc,g.cssDesc,u.css.sortAsc,u.css.sortDesc,u.css.sortNone].join(" ")).removeAttr("data-column").removeAttr("aria-label").attr("aria-disabled","true"),i.find(g.selectorSort).unbind("mousedown mouseup keypress ".split(" ").join(g.namespace+" ").replace(/\s+/g," ")),u.restoreHeaders(b),f.toggleClass(u.css.table+" "+g.tableClass+" tablesorter-"+g.theme,c===!1),b.hasInitialized=!1,delete b.config.cache,"function"==typeof d&&d(b)}},u.regex={chunk:/(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i},u.sortNatural=function(a,b){if(a===b)return 0;var c,d,e,f,g,h,i,j,k=u.regex;if(k.hex.test(b)){if(d=parseInt(a.match(k.hex),16),f=parseInt(b.match(k.hex),16),f>d)return-1;if(d>f)return 1}for(c=a.replace(k.chunk,"\\0$1\\0").replace(k.chunks,"").split("\\0"),e=b.replace(k.chunk,"\\0$1\\0").replace(k.chunks,"").split("\\0"),j=Math.max(c.length,e.length),i=0;j>i;i++){if(g=isNaN(c[i])?c[i]||0:parseFloat(c[i])||0,h=isNaN(e[i])?e[i]||0:parseFloat(e[i])||0,isNaN(g)!==isNaN(h))return isNaN(g)?1:-1;if(typeof g!=typeof h&&(g+="",h+=""),h>g)return-1;if(g>h)return 1}return 0},u.sortNaturalAsc=function(a,b,c,d,e){if(a===b)return 0;var f=e.string[e.empties[c]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:-f||-1:""===b&&0!==f?"boolean"==typeof f?f?1:-1:f||1:u.sortNatural(a,b)},u.sortNaturalDesc=function(a,b,c,d,e){if(a===b)return 0;var f=e.string[e.empties[c]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:f||1:""===b&&0!==f?"boolean"==typeof f?f?1:-1:-f||-1:u.sortNatural(b,a)},u.sortText=function(a,b){return a>b?1:b>a?-1:0},u.getTextValue=function(a,b,c){if(c){var d,e=a?a.length:0,f=c+b;for(d=0;e>d;d++)f+=a.charCodeAt(d);return b*f}return 0},u.sortNumericAsc=function(a,b,c,d,e,f){if(a===b)return 0;var g=f.config,h=g.string[g.empties[e]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:-h||-1:""===b&&0!==h?"boolean"==typeof h?h?1:-1:h||1:(isNaN(a)&&(a=u.getTextValue(a,c,d)),isNaN(b)&&(b=u.getTextValue(b,c,d)),a-b)},u.sortNumericDesc=function(a,b,c,d,e,f){if(a===b)return 0;var g=f.config,h=g.string[g.empties[e]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:h||1:""===b&&0!==h?"boolean"==typeof h?h?1:-1:-h||-1:(isNaN(a)&&(a=u.getTextValue(a,c,d)),isNaN(b)&&(b=u.getTextValue(b,c,d)),b-a)},u.sortNumeric=function(a,b){return a-b},u.characterEquivalents={a:"áàâãäąå",A:"ÁÀÂÃÄĄÅ",c:"çćč",C:"ÇĆČ",e:"éèêëěę",E:"ÉÈÊËĚĘ",i:"íìİîïı",I:"ÍÌİÎÏ",o:"óòôõöō",O:"ÓÒÔÕÖŌ",ss:"ß",SS:"ẞ",u:"úùûüů",U:"ÚÙÛÜŮ"},u.replaceAccents=function(a){var b,c="[",d=u.characterEquivalents;if(!u.characterRegex){u.characterRegexArray={};for(b in d)"string"==typeof b&&(c+=d[b],u.characterRegexArray[b]=new RegExp("["+d[b]+"]","g"));u.characterRegex=new RegExp(c+"]")}if(u.characterRegex.test(a))for(b in d)"string"==typeof b&&(a=a.replace(u.characterRegexArray[b],b));return a},u.isValueInArray=function(a,b){var c,d=b.length;for(c=0;d>c;c++)if(b[c][0]===a)return c;return-1},u.addParser=function(a){var b,c=u.parsers.length,d=!0;for(b=0;c>b;b++)u.parsers[b].id.toLowerCase()===a.id.toLowerCase()&&(d=!1);d&&u.parsers.push(a)},u.addInstanceMethods=function(b){a.extend(u.instanceMethods,b)},u.getParserById=function(a){if("false"==a)return!1;var b,c=u.parsers.length;for(b=0;c>b;b++)if(u.parsers[b].id.toLowerCase()===a.toString().toLowerCase())return u.parsers[b];return!1},u.addWidget=function(a){u.widgets.push(a)},u.hasWidget=function(b,c){return b=a(b),b.length&&b[0].config&&b[0].config.widgetInit[c]||!1},u.getWidgetById=function(a){var b,c,d=u.widgets.length;for(b=0;d>b;b++)if(c=u.widgets[b],c&&c.hasOwnProperty("id")&&c.id.toLowerCase()===a.toLowerCase())return c},u.applyWidgetOptions=function(b,c){var d,e,f=c.widgets.length,g=c.widgetOptions;if(f)for(d=0;f>d;d++)e=u.getWidgetById(c.widgets[d]),e&&"options"in e&&(g=b.config.widgetOptions=a.extend(!0,{},e.options,g))},u.applyWidget=function(b,d,e){b=a(b)[0];var f,g,h,i,j,k,l,m=b.config,n=m.widgetOptions,o=" "+m.table.className+" ",p=[];if(d===!1||!b.hasInitialized||!b.isApplyingWidgets&&!b.isUpdating){if(m.debug&&(i=new Date),l=new RegExp("\\s"+m.widgetClass.replace(/\{name\}/i,"([\\w-]+)")+"\\s","g"),o.match(l)&&(k=o.match(l)))for(g=k.length,f=0;g>f;f++)m.widgets.push(k[f].replace(l,"$1"));if(m.widgets.length){for(b.isApplyingWidgets=!0,m.widgets=a.grep(m.widgets,function(b,c){return a.inArray(b,m.widgets)===c}),h=m.widgets||[],g=h.length,f=0;g>f;f++)l=u.getWidgetById(h[f]),l&&l.id&&(l.priority||(l.priority=10),p[f]=l);for(p.sort(function(a,b){return a.priorityf;f++)p[f]&&((d||!m.widgetInit[p[f].id])&&(m.widgetInit[p[f].id]=!0,b.hasInitialized&&u.applyWidgetOptions(b,m),"init"in p[f]&&(m.debug&&(j=new Date),p[f].init(b,p[f],m,n),m.debug&&u.benchmark("Initializing "+p[f].id+" widget",j))),!d&&"format"in p[f]&&(m.debug&&(j=new Date),p[f].format(b,m,n,!1),m.debug&&u.benchmark((d?"Initializing ":"Applying ")+p[f].id+" widget",j)));d||"function"!=typeof e||e(b)}setTimeout(function(){b.isApplyingWidgets=!1,a.data(b,"lastWidgetApplication",new Date)},0),m.debug&&(k=m.widgets.length,c("Completed "+(d===!0?"initializing ":"applying ")+k+" widget"+(1!==k?"s":""),i))}},u.removeWidget=function(c,d,e){c=a(c)[0];var f,g,h,i,j=c.config;if(d===!0)for(d=[],i=u.widgets.length,h=0;i>h;h++)g=u.widgets[h],g&&g.id&&d.push(g.id);else d=(a.isArray(d)?d.join(","):d||"").toLowerCase().split(/[\s,]+/);for(i=d.length,f=0;i>f;f++)g=u.getWidgetById(d[f]),h=a.inArray(d[f],j.widgets),g&&"remove"in g&&(j.debug&&h>=0&&b('Removing "'+d[f]+'" widget'),g.remove(c,j,j.widgetOptions,e),j.widgetInit[d[f]]=!1),h>=0&&e!==!0&&j.widgets.splice(h,1)},u.refreshWidgets=function(b,c,d){b=a(b)[0];var e,f=b.config,g=f.widgets,h=u.widgets,i=h.length,j=[],k=function(b){a(b).trigger("refreshComplete")};for(e=0;i>e;e++)h[e]&&h[e].id&&(c||a.inArray(h[e].id,g)<0)&&j.push(h[e].id);u.removeWidget(b,j.join(","),!0),d!==!0?(u.applyWidget(b,c||!1,k),c&&u.applyWidget(b,!1,k)):k(b)},u.getColumnText=function(b,c,e){b=a(b)[0];var f,g,h,i,j,k,l,m,n,o,p="function"==typeof e,q="all"===c,r={raw:[],parsed:[],$cell:[]},s=b.config;if(!d(s)){for(j=s.$tbodies.length,f=0;j>f;f++)for(h=s.cache[f].normalized,k=h.length,g=0;k>g;g++)o=!0,i=h[g],m=q?i.slice(0,s.columns):i[c],i=i[s.columns],l=q?i.raw:i.raw[c],n=q?i.$row.children():i.$row.children().eq(c),p&&(o=e({tbodyIndex:f,rowIndex:g,parsed:m,raw:l,$row:i.$row,$cell:n})),o!==!1&&(r.parsed.push(m),r.raw.push(l),r.$cell.push(n));return r}},u.getData=function(b,c,d){var e,f,g="",h=a(b);return h.length?(e=a.metadata?h.metadata():!1,f=" "+(h.attr("class")||""),"undefined"!=typeof h.data(d)||"undefined"!=typeof h.data(d.toLowerCase())?g+=h.data(d)||h.data(d.toLowerCase()):e&&"undefined"!=typeof e[d]?g+=e[d]:c&&"undefined"!=typeof c[d]?g+=c[d]:" "!==f&&f.match(" "+d+"-")&&(g=f.match(new RegExp("\\s"+d+"-([\\w-]+)"))[1]||""),a.trim(g)):""},u.formatFloat=function(b,c){if("string"!=typeof b||""===b)return b;var d,e=c&&c.config?c.config.usNumberFormat!==!1:"undefined"!=typeof c?c:!0;return b=e?b.replace(/,/g,""):b.replace(/[\s|\.]/g,"").replace(/,/g,"."),/^\s*\([.\d]+\)/.test(b)&&(b=b.replace(/^\s*\(([.\d]+)\)/,"-$1")),d=parseFloat(b),isNaN(d)?a.trim(b):d},u.isDigit=function(a){return isNaN(a)?/^[\-+(]?\d+[)]?$/.test(a.toString().replace(/[,.'"\s]/g,"")):""!==a}}});var b=a.tablesorter;a.fn.extend({tablesorter:b.construct}),b.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"}),b.addParser({id:"text",is:function(){return!0},format:function(c,d){var e=d.config;return c&&(c=a.trim(e.ignoreCase?c.toLocaleLowerCase():c),c=e.sortLocaleCompare?b.replaceAccents(c):c),c},type:"text"}),b.addParser({id:"digit",is:function(a){return b.isDigit(a)},format:function(c,d){var e=b.formatFloat((c||"").replace(/[^\w,. \-()]/g,""),d);return c&&"number"==typeof e?e:c?a.trim(c&&d.config.ignoreCase?c.toLocaleLowerCase():c):c},type:"numeric"}),b.addParser({id:"currency",is:function(a){return/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/.test((a||"").replace(/[+\-,. ]/g,""))},format:function(c,d){var e=b.formatFloat((c||"").replace(/[^\w,. \-()]/g,""),d);return c&&"number"==typeof e?e:c?a.trim(c&&d.config.ignoreCase?c.toLocaleLowerCase():c):c},type:"numeric"}),b.addParser({id:"url",is:function(a){return/^(https?|ftp|file):\/\//.test(a)},format:function(b){return b?a.trim(b.replace(/(https?|ftp|file):\/\//,"")):b},parsed:!0,type:"text"}),b.addParser({id:"isoDate",is:function(a){return/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/.test(a)},format:function(a,b){var c=a?new Date(a.replace(/-/g,"/")):a;return c instanceof Date&&isFinite(c)?c.getTime():a},type:"numeric"}),b.addParser({id:"percent",is:function(a){return/(\d\s*?%|%\s*?\d)/.test(a)&&a.length<15},format:function(a,c){return a?b.formatFloat(a.replace(/%/g,""),c):a},type:"numeric"}),b.addParser({id:"image",is:function(a,b,c,d){return d.find("img").length>0},format:function(b,c,d){return a(d).find("img").attr(c.config.imgAttr||"alt")||b},parsed:!0,type:"text"}),b.addParser({id:"usLongDate",is:function(a){return/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i.test(a)||/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i.test(a); +},format:function(a,b){var c=a?new Date(a.replace(/(\S)([AP]M)$/i,"$1 $2")):a;return c instanceof Date&&isFinite(c)?c.getTime():a},type:"numeric"}),b.addParser({id:"shortDate",is:function(a){return/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/.test((a||"").replace(/\s+/g," ").replace(/[\-.,]/g,"/"))},format:function(a,c,d,e){if(a){var f,g,h=c.config,i=h.$headerIndexed[e],j=i.length&&i[0].dateFormat||b.getData(i,b.getColumnData(c,h.headers,e),"dateFormat")||h.dateFormat;return g=a.replace(/\s+/g," ").replace(/[\-.,]/g,"/"),"mmddyyyy"===j?g=g.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$1/$2"):"ddmmyyyy"===j?g=g.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$2/$1"):"yyyymmdd"===j&&(g=g.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,"$1/$2/$3")),f=new Date(g),f instanceof Date&&isFinite(f)?f.getTime():a}return a},type:"numeric"}),b.addParser({id:"time",is:function(a){return/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i.test(a)},format:function(a,b){var c=a?new Date("2000/01/01 "+a.replace(/(\S)([AP]M)$/i,"$1 $2")):a;return c instanceof Date&&isFinite(c)?c.getTime():a},type:"numeric"}),b.addParser({id:"metadata",is:function(){return!1},format:function(b,c,d){var e=c.config,f=e.parserMetadataName?e.parserMetadataName:"sortValue";return a(d).metadata()[f]},type:"numeric"}),b.addWidget({id:"zebra",priority:90,format:function(b,c,d){var e,f,g,h,i,j,k,l,m=new RegExp(c.cssChildRow,"i"),n=c.$tbodies.add(a(c.namespace+"_extra_table").children("tbody:not(."+c.cssInfoBlock+")"));for(c.debug&&(i=new Date),j=0;jk;k++)f=e.eq(k),m.test(f[0].className)||g++,h=g%2===0,f.removeClass(d.zebra[h?1:0]).addClass(d.zebra[h?0:1])},remove:function(a,c,d,e){if(!e){var f,g,h=c.$tbodies,i=(d.zebra||["even","odd"]).join(" ");for(f=0;f table ID/index on page > data + if (!values[url]) { + values[url] = {}; + } + values[url][id] = value; + // *** set value *** + if (hasStorage) { + window[storageType][key] = JSON.stringify(values); + } else { + date = new Date(); + date.setTime(date.getTime() + (31536e+6)); // 365 days + document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g,'\"') + '; expires=' + date.toGMTString() + '; path=/'; + } + } else { + return values && values[url] ? values[url][id] : ''; + } +}; + +})(jQuery, window, document); + +/*! Widget: uitheme - updated 3/26/2015 (v2.21.3) */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +ts.themes = { + 'bootstrap' : { + table : 'table table-bordered table-striped', + caption : 'caption', + // header class names + header : 'bootstrap-header', // give the header a gradient background (theme.bootstrap_2.css) + sortNone : '', + sortAsc : '', + sortDesc : '', + active : '', // applied when column is sorted + hover : '', // custom css required - a defined bootstrap style may not override other classes + // icon class names + icons : '', // add "icon-white" to make them white; this icon class is added to the in the header + iconSortNone : 'bootstrap-icon-unsorted', // class name added to icon when column is not sorted + iconSortAsc : 'icon-chevron-up glyphicon glyphicon-chevron-up', // class name added to icon when column has ascending sort + iconSortDesc : 'icon-chevron-down glyphicon glyphicon-chevron-down', // class name added to icon when column has descending sort + filterRow : '', // filter row class + footerRow : '', + footerCells : '', + even : '', // even row zebra striping + odd : '' // odd row zebra striping + }, + 'jui' : { + table : 'ui-widget ui-widget-content ui-corner-all', // table classes + caption : 'ui-widget-content', + // header class names + header : 'ui-widget-header ui-corner-all ui-state-default', // header classes + sortNone : '', + sortAsc : '', + sortDesc : '', + active : 'ui-state-active', // applied when column is sorted + hover : 'ui-state-hover', // hover class + // icon class names + icons : 'ui-icon', // icon class added to the in the header + iconSortNone : 'ui-icon-carat-2-n-s', // class name added to icon when column is not sorted + iconSortAsc : 'ui-icon-carat-1-n', // class name added to icon when column has ascending sort + iconSortDesc : 'ui-icon-carat-1-s', // class name added to icon when column has descending sort + filterRow : '', + footerRow : '', + footerCells : '', + even : 'ui-widget-content', // even row zebra striping + odd : 'ui-state-default' // odd row zebra striping + } +}; + +$.extend(ts.css, { + wrapper : 'tablesorter-wrapper' // ui theme & resizable +}); + +ts.addWidget({ + id: "uitheme", + priority: 10, + format: function(table, c, wo) { + var i, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme, + themesAll = ts.themes, + $table = c.$table.add( $( c.namespace + '_extra_table' ) ), + $headers = c.$headers.add( $( c.namespace + '_extra_headers' ) ), + theme = c.theme || 'jui', + themes = themesAll[theme] || {}, + remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ), + iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) ); + if (c.debug) { time = new Date(); } + // initialization code - run once + if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) { + wo.uitheme_applied = true; + oldtheme = themesAll[c.appliedTheme] || {}; + hasOldTheme = !$.isEmptyObject(oldtheme); + oldremove = hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : ''; + oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : ''; + if (hasOldTheme) { + wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') ); + wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') ); + c.$tbodies.children().removeClass( [oldtheme.even, oldtheme.odd].join(' ') ); + } + // update zebra stripes + if (themes.even) { wo.zebra[0] += ' ' + themes.even; } + if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; } + // add caption style + $table.children('caption') + .removeClass(oldtheme.caption || '') + .addClass(themes.caption); + // add table/footer class names + $tfoot = $table + // remove other selected themes + .removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') ) + .addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name + .children('tfoot'); + c.appliedTheme = c.theme; + + if ($tfoot.length) { + $tfoot + // if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed + .children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow) + .children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells); + } + // update header classes + $headers + .removeClass( (hasOldTheme ? [oldtheme.header, oldtheme.hover, oldremove].join(' ') : '') || '' ) + .addClass(themes.header) + .not('.sorter-false') + .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') + .bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) { + // toggleClass with switch added in jQuery 1.3 + $(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || ''); + }); + + $headers.each(function(){ + var $this = $(this); + if (!$this.find('.' + ts.css.wrapper).length) { + // Firefox needs this inner div to position the icon & resizer correctly + $this.wrapInner('
    '); + } + }); + if (c.cssIcon) { + // if c.cssIcon is '', then no is added to the header + $headers + .find('.' + ts.css.icon) + .removeClass(hasOldTheme ? [oldtheme.icons, oldIconRmv].join(' ') : '') + .addClass(themes.icons || ''); + } + if ($table.hasClass('hasFilters')) { + $table.children('thead').children('.' + ts.css.filterRow) + .removeClass(hasOldTheme ? oldtheme.filterRow || '' : '') + .addClass(themes.filterRow || ''); + } + } + for (i = 0; i < c.columns; i++) { + $header = c.$headers + .add($(c.namespace + '_extra_headers')) + .not('.sorter-false') + .filter('[data-column="' + i + '"]'); + $icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $(); + $h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last'); + if ($h.length) { + $header.removeClass(remove); + $icon.removeClass(iconRmv); + if ($h[0].sortDisabled) { + // no sort arrows for disabled columns! + $icon.removeClass(themes.icons || ''); + } else { + hdr = themes.sortNone; + icon = themes.iconSortNone; + if ($h.hasClass(ts.css.sortAsc)) { + hdr = [themes.sortAsc, themes.active].join(' '); + icon = themes.iconSortAsc; + } else if ($h.hasClass(ts.css.sortDesc)) { + hdr = [themes.sortDesc, themes.active].join(' '); + icon = themes.iconSortDesc; + } + $header.addClass(hdr); + $icon.addClass(icon || ''); + } + } + } + if (c.debug) { + ts.benchmark("Applying " + theme + " theme", time); + } + }, + remove: function(table, c, wo, refreshing) { + if (!wo.uitheme_applied) { return; } + var $table = c.$table, + theme = c.appliedTheme || 'jui', + themes = ts.themes[ theme ] || ts.themes.jui, + $headers = $table.children('thead').children(), + remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc, + iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc; + $table.removeClass('tablesorter-' + theme + ' ' + themes.table); + wo.uitheme_applied = false; + if (refreshing) { return; } + $table.find(ts.css.header).removeClass(themes.header); + $headers + .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover + .removeClass(themes.hover + ' ' + remove + ' ' + themes.active) + .filter('.' + ts.css.filterRow) + .removeClass(themes.filterRow); + $headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv); + } +}); + +})(jQuery); + +/*! Widget: columns */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +ts.addWidget({ + id: "columns", + priority: 30, + options : { + columns : [ "primary", "secondary", "tertiary" ] + }, + format: function(table, c, wo) { + var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx, + $table = c.$table, + $tbodies = c.$tbodies, + sortList = c.sortList, + len = sortList.length, + // removed c.widgetColumns support + css = wo && wo.columns || [ "primary", "secondary", "tertiary" ], + last = css.length - 1; + remove = css.join(' '); + // check if there is a sort (on initialization there may not be one) + for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody + $rows = $tbody.children('tr'); + // loop through the visible rows + $rows.each(function() { + $row = $(this); + if (this.style.display !== 'none') { + // remove all columns class names + $cells = $row.children().removeClass(remove); + // add appropriate column class names + if (sortList && sortList[0]) { + // primary sort column class + $cells.eq(sortList[0][0]).addClass(css[0]); + if (len > 1) { + for (indx = 1; indx < len; indx++) { + // secondary, tertiary, etc sort column classes + $cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] ); + } + } + } + } + }); + ts.processTbody(table, $tbody, false); + } + // add classes to thead and tfoot + rows = wo.columns_thead !== false ? ['thead tr'] : []; + if (wo.columns_tfoot !== false) { + rows.push('tfoot tr'); + } + if (rows.length) { + $rows = $table.find( rows.join(',') ).children().removeClass(remove); + if (len) { + for (indx = 0; indx < len; indx++) { + // add primary. secondary, tertiary, etc sort column classes + $rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]); + } + } + } + }, + remove: function(table, c, wo) { + var tbodyIndex, $tbody, + $tbodies = c.$tbodies, + remove = (wo.columns || [ "primary", "secondary", "tertiary" ]).join(' '); + c.$headers.removeClass(remove); + c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove); + for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody + $tbody.children('tr').each(function() { + $(this).children().removeClass(remove); + }); + ts.processTbody(table, $tbody, false); // restore tbody + } + } +}); + +})(jQuery); + +/*! Widget: filter - updated 5/17/2015 (v2.22.1) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +;( function ( $ ) { +'use strict'; +var ts = $.tablesorter || {}, + tscss = ts.css; + +$.extend( tscss, { + filterRow : 'tablesorter-filter-row', + filter : 'tablesorter-filter', + filterDisabled : 'disabled', + filterRowHide : 'hideme' +}); + +ts.addWidget({ + id: 'filter', + priority: 50, + options : { + filter_childRows : false, // if true, filter includes child row content in the search + filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped + filter_columnFilters : true, // if true, a filter will be added to the top of each table column + filter_columnAnyMatch: true, // if true, allows using '#:{query}' in AnyMatch searches ( column:query ) + filter_cellFilter : '', // css class name added to the filter cell ( string or array ) + filter_cssFilter : '', // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added ) + 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. + filter_excludeFilter : {}, // filters to exclude, per column + filter_external : '', // jQuery selector string ( or jQuery object ) of external filters + filter_filteredRow : 'filtered', // class added to filtered rows; needed by pager plugin + filter_formatter : null, // add custom filter elements to the filter row + filter_functions : null, // add custom filter functions using this option + filter_hideEmpty : true, // hide filter row when table is empty + filter_hideFilters : false, // collapse filter row when mouse leaves the area + filter_ignoreCase : true, // if true, make all searches case-insensitive + filter_liveSearch : true, // if true, search column content while the user types ( with a delay ) + filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down + filter_placeholder : { search : '', select : '' }, // default placeholder text ( overridden by any header 'data-placeholder' setting ) + filter_reset : null, // jQuery selector string of an element used to reset the filters + filter_saveFilters : false, // Use the $.tablesorter.storage utility to save the most recent filters + filter_searchDelay : 300, // typing delay in milliseconds before starting a search + filter_searchFiltered: true, // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true + filter_selectSource : null, // include a function to return an array of values to be added to the column filter select + filter_startsWith : false, // if true, filter start from the beginning of the cell contents + filter_useParsedData : false, // filter all data using parsed content + filter_serversideFiltering : false, // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used. + filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value + filter_selectSourceSeparator : '|' // filter_selectSource array text left of the separator is added to the option value, right into the option text + }, + format: function( table, c, wo ) { + if ( !c.$table.hasClass( 'hasFilters' ) ) { + ts.filter.init( table, c, wo ); + } + }, + remove: function( table, c, wo, refreshing ) { + var tbodyIndex, $tbody, + $table = c.$table, + $tbodies = c.$tbodies, + events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ' + .split( ' ' ).join( c.namespace + 'filter ' ); + $table + .removeClass( 'hasFilters' ) + // add .tsfilter namespace to all BUT search + .unbind( events.replace( /\s+/g, ' ' ) ) + // remove the filter row even if refreshing, because the column might have been moved + .find( '.' + tscss.filterRow ).remove(); + if ( refreshing ) { return; } + for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody + $tbody.children().removeClass( wo.filter_filteredRow ).show(); + ts.processTbody( table, $tbody, false ); // restore tbody + } + if ( wo.filter_reset ) { + $( document ).undelegate( wo.filter_reset, 'click.tsfilter' ); + } + } +}); + +ts.filter = { + + // regex used in filter 'check' functions - not for general use and not documented + regex: { + regex : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex + child : /tablesorter-childRow/, // child row class name; this gets updated in the script + filtered : /filtered/, // filtered (hidden) row class name; updated in the script + type : /undefined|number/, // check type + exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==') + nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser) + operators : /[<>=]/g, // replace operators + query : '(q|query)' // replace filter queries + }, + // function( c, data ) { } + // c = table.config + // data.$row = jQuery object of the row currently being processed + // data.$cells = jQuery object of all cells within the current row + // data.filters = array of filters for all columns ( some may be undefined ) + // data.filter = filter for the current column + // data.iFilter = same as data.filter, except lowercase ( if wo.filter_ignoreCase is true ) + // data.exact = table cell text ( or parsed data if column parser enabled ) + // data.iExact = same as data.exact, except lowercase ( if wo.filter_ignoreCase is true ) + // data.cache = table cell text from cache, so it has been parsed ( & in all lower case if c.ignoreCase is true ) + // data.cacheArray = An array of parsed content from each table cell in the row being processed + // data.index = column index; table = table element ( DOM ) + // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class ) + types: { + // Look for regex + regex: function( c, data ) { + if ( ts.filter.regex.regex.test( data.filter ) ) { + var matches, + // cache regex per column for optimal speed + regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ), + isRegex = regex instanceof RegExp; + try { + if ( !isRegex ) { + // force case insensitive search if ignoreCase option set? + // if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; } + data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] ); + } + matches = regex.test( data.exact ); + } catch ( error ) { + matches = false; + } + return matches; + } + return null; + }, + // Look for operators >, >=, < or <= + operators: function( c, data ) { + // ignore empty strings... because '' < 10 is true + if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) { + var cachedValue, result, txt, + table = c.table, + index = data.index, + parsed = data.parsed[index], + query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ), + parser = c.parsers[index], + savedSearch = query; + // parse filter value in case we're comparing numbers ( dates ) + if ( parsed || parser.type === 'numeric' ) { + txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) ); + result = ts.filter.parseFilter( c, txt, index, true ); + query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query; + } + // iExact may be numeric - see issue #149; + // check if cached is defined, because sometimes j goes out of range? ( numeric columns ) + if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) && + typeof data.cache !== 'undefined' ) { + cachedValue = data.cache; + } else { + txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact; + cachedValue = ts.formatFloat( txt, table ); + } + if ( />/.test( data.iFilter ) ) { + result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query; + } else if ( /= 0 ); + } + } + return null; + }, + // Look for quotes or equals to get an exact match; ignore type since iExact could be numeric + exact: function( c, data ) { + /*jshint eqeqeq:false */ + if ( ts.filter.regex.exact.test( data.iFilter ) ) { + var txt = data.iFilter.replace( ts.filter.regex.exact, '' ), + filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || ''; + return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact; + } + return null; + }, + // Look for an AND or && operator ( logical and ) + and : function( c, data ) { + if ( ts.filter.regex.andTest.test( data.filter ) ) { + var index = data.index, + parsed = data.parsed[index], + query = data.iFilter.split( ts.filter.regex.andSplit ), + result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0, + indx = query.length - 1; + while ( result && indx ) { + result = result && + data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0; + indx--; + } + return result; + } + return null; + }, + // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu! + range : function( c, data ) { + if ( ts.filter.regex.toTest.test( data.iFilter ) ) { + var result, tmp, range1, range2, + table = c.table, + index = data.index, + parsed = data.parsed[index], + // make sure the dash is for a range and not indicating a negative number + query = data.iFilter.split( ts.filter.regex.toSplit ); + + tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || ''; + range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table ); + tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || ''; + range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table ); + // parse filter value in case we're comparing numbers ( dates ) + if ( parsed || c.parsers[index].type === 'numeric' ) { + result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index ); + range1 = ( result !== '' && !isNaN( result ) ) ? result : range1; + result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index ); + range2 = ( result !== '' && !isNaN( result ) ) ? result : range2; + } + if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) { + result = data.cache; + } else { + tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact; + result = ts.formatFloat( tmp, table ); + } + if ( range1 > range2 ) { + tmp = range1; range1 = range2; range2 = tmp; // swap + } + return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' ); + } + return null; + }, + // Look for wild card: ? = single, * = multiple, or | = logical OR + wild : function( c, data ) { + if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) { + var index = data.index, + parsed = data.parsed[ index ], + txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ), + query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' ); + // look for an exact match with the 'or' unless the 'filter-match' class is found + if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) { + // show all results while using filter match. Fixes #727 + if ( query[ query.length - 1 ] === '|' ) { + query += '*'; + } + query = data.anyMatch && $.isArray( data.rowArray ) ? + '(' + query + ')' : + '^(' + query + ')$'; + } + // parsing the filter may not work properly when using wildcards =/ + return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) ) + .test( data.iExact ); + } + return null; + }, + // fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license ) + fuzzy: function( c, data ) { + if ( /^~/.test( data.iFilter ) ) { + var indx, + patternIndx = 0, + len = data.iExact.length, + txt = data.iFilter.slice( 1 ), + pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || ''; + for ( indx = 0; indx < len; indx++ ) { + if ( data.iExact[ indx ] === pattern[ patternIndx ] ) { + patternIndx += 1; + } + } + if ( patternIndx === pattern.length ) { + return true; + } + return false; + } + return null; + } + }, + init: function( table, c, wo ) { + // filter language options + ts.language = $.extend( true, {}, { + to : 'to', + or : 'or', + and : 'and' + }, ts.language ); + + var options, string, txt, $header, column, filters, val, fxn, noSelect, + regex = ts.filter.regex; + c.$table.addClass( 'hasFilters' ); + + // define timers so using clearTimeout won't cause an undefined error + wo.searchTimer = null; + wo.filter_initTimer = null; + wo.filter_formatterCount = 0; + wo.filter_formatterInit = []; + wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]'; + wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]'; + + val = '\\{' + ts.filter.regex.query + '\\}'; + $.extend( regex, { + child : new RegExp( c.cssChildRow ), + filtered : new RegExp( wo.filter_filteredRow ), + alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ), + toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ), + toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ), + andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ), + andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ), + orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ), + iQuery : new RegExp( val, 'i' ), + igQuery : new RegExp( val, 'ig' ) + }); + + // don't build filter row if columnFilters is false or all columns are set to 'filter-false' + // see issue #156 + val = c.$headers.filter( '.filter-false, .parser-false' ).length; + if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) { + // build filter row + ts.filter.buildRow( table, c, wo ); + } + + txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ' + .split( ' ' ).join( c.namespace + 'filter ' ); + c.$table.bind( txt, function( event, filter ) { + val = wo.filter_hideEmpty && + $.isEmptyObject( c.cache ) && + !( c.delayInit && event.type === 'appendCache' ); + // hide filter row using the 'filtered' class name + c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450 + if ( !/(search|filter)/.test( event.type ) ) { + event.stopPropagation(); + ts.filter.buildDefault( table, true ); + } + if ( event.type === 'filterReset' ) { + c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' ); + ts.filter.searching( table, [] ); + } else if ( event.type === 'filterEnd' ) { + ts.filter.buildDefault( table, true ); + } else { + // send false argument to force a new search; otherwise if the filter hasn't changed, + // it will return + filter = event.type === 'search' ? filter : + event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : ''; + if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) { + // force a new search since content has changed + c.lastCombinedFilter = null; + c.lastSearch = []; + } + // pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first + // input ensures all inputs are updated when a search is triggered on the table + // $( 'table' ).trigger( 'search', [...] ); + ts.filter.searching( table, filter, true ); + } + return false; + }); + + // reset button/link + if ( wo.filter_reset ) { + if ( wo.filter_reset instanceof $ ) { + // reset contains a jQuery object, bind to it + wo.filter_reset.click( function() { + c.$table.trigger( 'filterReset' ); + }); + } else if ( $( wo.filter_reset ).length ) { + // reset is a jQuery selector, use event delegation + $( document ) + .undelegate( wo.filter_reset, 'click.tsfilter' ) + .delegate( wo.filter_reset, 'click.tsfilter', function() { + // trigger a reset event, so other functions ( filter_formatter ) know when to reset + c.$table.trigger( 'filterReset' ); + }); + } + } + if ( wo.filter_functions ) { + for ( column = 0; column < c.columns; column++ ) { + fxn = ts.getColumnData( table, wo.filter_functions, column ); + if ( fxn ) { + // remove 'filter-select' from header otherwise the options added here are replaced with + // all options + $header = c.$headerIndexed[ column ].removeClass( 'filter-select' ); + // don't build select if 'filter-false' or 'parser-false' set + noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) ); + options = ''; + if ( fxn === true && noSelect ) { + ts.filter.buildSelect( table, column ); + } else if ( typeof fxn === 'object' && noSelect ) { + // add custom drop down list + for ( string in fxn ) { + if ( typeof string === 'string' ) { + options += options === '' ? + '' : ''; + val = string; + txt = string; + if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) { + val = string.split( wo.filter_selectSourceSeparator ); + txt = val[1]; + val = val[0]; + } + options += ''; + } + } + c.$table + .find( 'thead' ) + .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' ) + .append( options ); + txt = wo.filter_selectSource; + fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column ); + if ( fxn ) { + // updating so the extra options are appended + ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) ); + } + } + } + } + } + // not really updating, but if the column has both the 'filter-select' class & + // filter_functions set to true, it would append the same options twice. + ts.filter.buildDefault( table, true ); + + ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true ); + if ( wo.filter_external ) { + ts.filter.bindSearch( table, wo.filter_external ); + } + + if ( wo.filter_hideFilters ) { + ts.filter.hideFilters( table, c ); + } + + // show processing icon + if ( c.showProcessing ) { + txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' ); + c.$table + .unbind( txt.replace( /\s+/g, ' ' ) ) + .bind( txt, function( event, columns ) { + // only add processing to certain columns to all columns + $header = ( columns ) ? + c.$table + .find( '.' + tscss.header ) + .filter( '[data-column]' ) + .filter( function() { + return columns[ $( this ).data( 'column' ) ] !== ''; + }) : ''; + ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' ); + }); + } + + // set filtered rows count ( intially unfiltered ) + c.filteredRows = c.totalRows; + + // add default values + txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' ); + c.$table + .unbind( txt.replace( /\s+/g, ' ' ) ) + .bind( txt, function() { + // redefine 'wo' as it does not update properly inside this callback + var wo = this.config.widgetOptions; + filters = ts.filter.setDefaults( table, c, wo ) || []; + if ( filters.length ) { + // prevent delayInit from triggering a cache build if filters are empty + if ( !( c.delayInit && filters.join( '' ) === '' ) ) { + ts.setFilters( table, filters, true ); + } + } + c.$table.trigger( 'filterFomatterUpdate' ); + // trigger init after setTimeout to prevent multiple filterStart/End/Init triggers + setTimeout( function() { + if ( !wo.filter_initialized ) { + ts.filter.filterInitComplete( c ); + } + }, 100 ); + }); + // if filter widget is added after pager has initialized; then set filter init flag + if ( c.pager && c.pager.initialized && !wo.filter_initialized ) { + c.$table.trigger( 'filterFomatterUpdate' ); + setTimeout( function() { + ts.filter.filterInitComplete( c ); + }, 100 ); + } + }, + // $cell parameter, but not the config, is passed to the filter_formatters, + // so we have to work with it instead + formatterUpdated: function( $cell, column ) { + var wo = $cell.closest( 'table' )[0].config.widgetOptions; + if ( !wo.filter_initialized ) { + // add updates by column since this function + // may be called numerous times before initialization + wo.filter_formatterInit[ column ] = 1; + } + }, + filterInitComplete: function( c ) { + var indx, len, + wo = c.widgetOptions, + count = 0, + completed = function() { + wo.filter_initialized = true; + c.$table.trigger( 'filterInit', c ); + ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] ); + }; + if ( $.isEmptyObject( wo.filter_formatter ) ) { + completed(); + } else { + len = wo.filter_formatterInit.length; + for ( indx = 0; indx < len; indx++ ) { + if ( wo.filter_formatterInit[ indx ] === 1 ) { + count++; + } + } + clearTimeout( wo.filter_initTimer ); + if ( !wo.filter_initialized && count === wo.filter_formatterCount ) { + // filter widget initialized + completed(); + } else if ( !wo.filter_initialized ) { + // fall back in case a filter_formatter doesn't call + // $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off + wo.filter_initTimer = setTimeout( function() { + completed(); + }, 500 ); + } + } + }, + + setDefaults: function( table, c, wo ) { + var isArray, saved, indx, col, $filters, + // get current ( default ) filters + filters = ts.getFilters( table ) || []; + if ( wo.filter_saveFilters && ts.storage ) { + saved = ts.storage( table, 'tablesorter-filters' ) || []; + isArray = $.isArray( saved ); + // make sure we're not just getting an empty array + if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) { + filters = saved; + } + } + // if no filters saved, then check default settings + if ( filters.join( '' ) === '' ) { + // allow adding default setting to external filters + $filters = c.$headers.add( wo.filter_$externalFilters ) + .filter( '[' + wo.filter_defaultAttrib + ']' ); + for ( indx = 0; indx <= c.columns; indx++ ) { + // include data-column='all' external filters + col = indx === c.columns ? 'all' : indx; + filters[indx] = $filters + .filter( '[data-column="' + col + '"]' ) + .attr( wo.filter_defaultAttrib ) || filters[indx] || ''; + } + } + c.$table.data( 'lastSearch', filters ); + return filters; + }, + parseFilter: function( c, filter, column, parsed ) { + return parsed ? c.parsers[column].format( filter, c.table, [], column ) : filter; + }, + buildRow: function( table, c, wo ) { + var col, column, $header, buildSelect, disabled, name, ffxn, tmp, + // c.columns defined in computeThIndexes() + cellFilter = wo.filter_cellFilter, + columns = c.columns, + arry = $.isArray( cellFilter ), + buildFilter = ''; + for ( column = 0; column < columns; column++ ) { + buildFilter += '' ).appendTo( c.$filters.eq( column ) ); + } else { + ffxn = ts.getColumnData( table, wo.filter_formatter, column ); + if ( ffxn ) { + wo.filter_formatterCount++; + buildFilter = ffxn( c.$filters.eq( column ), column ); + // no element returned, so lets go find it + if ( buildFilter && buildFilter.length === 0 ) { + buildFilter = c.$filters.eq( column ).children( 'input' ); + } + // element not in DOM, so lets attach it + if ( buildFilter && ( buildFilter.parent().length === 0 || + ( buildFilter.parent().length && buildFilter.parent()[0] !== c.$filters[column] ) ) ) { + c.$filters.eq( column ).append( buildFilter ); + } + } else { + buildFilter = $( '' ).appendTo( c.$filters.eq( column ) ); + } + if ( buildFilter ) { + tmp = $header.data( 'placeholder' ) || + $header.attr( 'data-placeholder' ) || + wo.filter_placeholder.search || ''; + buildFilter.attr( 'placeholder', tmp ); + } + } + if ( buildFilter ) { + // add filter class name + name = ( $.isArray( wo.filter_cssFilter ) ? + ( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) : + wo.filter_cssFilter ) || ''; + buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', column ); + if ( disabled ) { + buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true; + } + } + } + }, + bindSearch: function( table, $el, internal ) { + table = $( table )[0]; + $el = $( $el ); // allow passing a selector string + if ( !$el.length ) { return; } + var tmp, + c = table.config, + wo = c.widgetOptions, + namespace = c.namespace + 'filter', + $ext = wo.filter_$externalFilters; + if ( internal !== true ) { + // save anyMatch element + tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector; + wo.filter_$anyMatch = $el.filter( tmp ); + if ( $ext && $ext.length ) { + wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el ); + } else { + wo.filter_$externalFilters = $el; + } + // update values ( external filters added after table initialization ) + ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false ); + } + // unbind events + tmp = ( 'keypress keyup search change '.split( ' ' ).join( namespace + ' ' ) ); + $el + // use data attribute instead of jQuery data since the head is cloned without including + // the data/binding + .attr( 'data-lastSearchTime', new Date().getTime() ) + .unbind( tmp.replace( /\s+/g, ' ' ) ) + // include change for select - fixes #473 + .bind( 'keyup' + namespace, function( event ) { + $( this ).attr( 'data-lastSearchTime', new Date().getTime() ); + // emulate what webkit does.... escape clears the filter + if ( event.which === 27 ) { + this.value = ''; + // live search + } else if ( wo.filter_liveSearch === false ) { + return; + // don't return if the search value is empty ( all rows need to be revealed ) + } else if ( this.value !== '' && ( + // liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace + ( typeof wo.filter_liveSearch === 'number' && this.value.length < wo.filter_liveSearch ) || + // let return & backspace continue on, but ignore arrows & non-valid characters + ( event.which !== 13 && event.which !== 8 && + ( event.which < 32 || ( event.which >= 37 && event.which <= 40 ) ) ) ) ) { + return; + } + // change event = no delay; last true flag tells getFilters to skip newest timed input + ts.filter.searching( table, true, true ); + }) + .bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) { + var column = $( this ).data( 'column' ); + // don't allow 'change' event to process if the input value is the same - fixes #685 + if ( event.which === 13 || event.type === 'search' || + event.type === 'change' && this.value !== c.lastSearch[column] ) { + event.preventDefault(); + // init search with no delay + $( this ).attr( 'data-lastSearchTime', new Date().getTime() ); + ts.filter.searching( table, false, true ); + } + }); + }, + searching: function( table, filter, skipFirst ) { + var wo = table.config.widgetOptions; + clearTimeout( wo.searchTimer ); + if ( typeof filter === 'undefined' || filter === true ) { + // delay filtering + wo.searchTimer = setTimeout( function() { + ts.filter.checkFilters( table, filter, skipFirst ); + }, wo.filter_liveSearch ? wo.filter_searchDelay : 10 ); + } else { + // skip delay + ts.filter.checkFilters( table, filter, skipFirst ); + } + }, + checkFilters: function( table, filter, skipFirst ) { + var c = table.config, + wo = c.widgetOptions, + filterArray = $.isArray( filter ), + filters = ( filterArray ) ? filter : ts.getFilters( table, true ), + combinedFilters = ( filters || [] ).join( '' ); // combined filter values + // prevent errors if delay init is set + if ( $.isEmptyObject( c.cache ) ) { + // update cache if delayInit set & pager has initialized ( after user initiates a search ) + if ( c.delayInit && c.pager && c.pager.initialized ) { + c.$table.trigger( 'updateCache', [ function() { + ts.filter.checkFilters( table, false, skipFirst ); + } ] ); + } + return; + } + // add filter array back into inputs + if ( filterArray ) { + ts.setFilters( table, filters, false, skipFirst !== true ); + if ( !wo.filter_initialized ) { c.lastCombinedFilter = ''; } + } + if ( wo.filter_hideFilters ) { + // show/hide filter row as needed + c.$table + .find( '.' + tscss.filterRow ) + .trigger( combinedFilters === '' ? 'mouseleave' : 'mouseenter' ); + } + // return if the last search is the same; but filter === false when updating the search + // see example-widget-filter.html filter toggle buttons + if ( c.lastCombinedFilter === combinedFilters && filter !== false ) { + return; + } else if ( filter === false ) { + // force filter refresh + c.lastCombinedFilter = null; + c.lastSearch = []; + } + if ( wo.filter_initialized ) { + c.$table.trigger( 'filterStart', [filters] ); + } + if ( c.showProcessing ) { + // give it time for the processing icon to kick in + setTimeout( function() { + ts.filter.findRows( table, filters, combinedFilters ); + return false; + }, 30 ); + } else { + ts.filter.findRows( table, filters, combinedFilters ); + return false; + } + }, + hideFilters: function( table, c ) { + var $filterRow, $filterRow2, timer; + $( table ) + .find( '.' + tscss.filterRow ) + .addClass( tscss.filterRowHide ) + .bind( 'mouseenter mouseleave', function( e ) { + // save event object - http://bugs.jquery.com/ticket/12140 + var event = e; + $filterRow = $( this ); + clearTimeout( timer ); + timer = setTimeout( function() { + if ( /enter|over/.test( event.type ) ) { + $filterRow.removeClass( tscss.filterRowHide ); + } else { + // don't hide if input has focus + // $( ':focus' ) needs jQuery 1.6+ + if ( $( document.activeElement ).closest( 'tr' )[0] !== $filterRow[0] ) { + // don't hide row if any filter has a value + if ( c.lastCombinedFilter === '' ) { + $filterRow.addClass( tscss.filterRowHide ); + } + } + } + }, 200 ); + }) + .find( 'input, select' ).bind( 'focus blur', function( e ) { + $filterRow2 = $( this ).closest( 'tr' ); + clearTimeout( timer ); + var event = e; + timer = setTimeout( function() { + // don't hide row if any filter has a value + if ( ts.getFilters( c.$table ).join( '' ) === '' ) { + $filterRow2.toggleClass( tscss.filterRowHide, event.type === 'focus' ); + } + }, 200 ); + }); + }, + defaultFilter: function( filter, mask ) { + if ( filter === '' ) { return filter; } + var regex = ts.filter.regex.iQuery, + maskLen = mask.match( ts.filter.regex.igQuery ).length, + query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ], + len = query.length - 1, + indx = 0, + val = mask; + if ( len < 1 && maskLen > 1 ) { + // only one 'word' in query but mask has >1 slots + query[1] = query[0]; + } + // replace all {query} with query words... + // if query = 'Bob', then convert mask from '!{query}' to '!Bob' + // if query = 'Bob Joe Frank', then convert mask '{q} OR {q}' to 'Bob OR Joe OR Frank' + while ( regex.test( val ) ) { + val = val.replace( regex, query[indx++] || '' ); + if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) { + val = mask.replace( regex, val ); + } + } + return val; + }, + getLatestSearch: function( $input ) { + if ( $input ) { + return $input.sort( function( a, b ) { + return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' ); + }); + } + return $input || $(); + }, + multipleColumns: function( c, $input ) { + // look for multiple columns '1-3,4-6,8' in data-column + var temp, ranges, range, start, end, singles, i, indx, len, + wo = c.widgetOptions, + // only target 'all' column inputs on initialization + // & don't target 'all' column inputs if they don't exist + targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length, + columns = [], + val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' ); + // process column range + if ( targets && /-/.test( val ) ) { + ranges = val.match( /(\d+)\s*-\s*(\d+)/g ); + len = ranges.length; + for ( indx = 0; indx < len; indx++ ) { + range = ranges[indx].split( /\s*-\s*/ ); + start = parseInt( range[0], 10 ) || 0; + end = parseInt( range[1], 10 ) || ( c.columns - 1 ); + if ( start > end ) { + temp = start; start = end; end = temp; // swap + } + if ( end >= c.columns ) { + end = c.columns - 1; + } + for ( ; start <= end; start++ ) { + columns.push( start ); + } + // remove processed range from val + val = val.replace( ranges[ indx ], '' ); + } + } + // process single columns + if ( targets && /,/.test( val ) ) { + singles = val.split( /\s*,\s*/ ); + len = singles.length; + for ( i = 0; i < len; i++ ) { + if ( singles[ i ] !== '' ) { + indx = parseInt( singles[ i ], 10 ); + if ( indx < c.columns ) { + columns.push( indx ); + } + } + } + } + // return all columns + if ( !columns.length ) { + for ( indx = 0; indx < c.columns; indx++ ) { + columns.push( indx ); + } + } + return columns; + }, + processRow: function( c, data, vars ) { + var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, + fxn, ffxn, txt, + regex = ts.filter.regex, + wo = c.widgetOptions, + showRow = true; + data.$cells = data.$row.children(); + + if ( data.anyMatchFlag ) { + // look for multiple columns '1-3,4-6,8' + columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch ); + data.anyMatch = true; + data.rowArray = data.$cells.map( function( i ) { + if ( $.inArray( i, columnIndex ) > -1 ) { + if ( data.parsed[ i ] ) { + txt = data.cacheArray[ i ]; + } else { + txt = data.rawArray[ i ]; + txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt ); + if ( c.sortLocaleCompare ) { + txt = ts.replaceAccents( txt ); + } + } + return txt; + } + }).get(); + data.filter = data.anyMatchFilter; + data.iFilter = data.iAnyMatchFilter; + data.exact = data.rowArray.join( ' ' ); + data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact; + data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' ); + filterMatched = null; + matches = null; + for ( ffxn in ts.filter.types ) { + if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) { + matches = ts.filter.types[ffxn]( c, data ); + if ( matches !== null ) { + filterMatched = matches; + } + } + } + if ( filterMatched !== null ) { + showRow = filterMatched; + } else { + if ( wo.filter_startsWith ) { + showRow = false; + columnIndex = c.columns; + while ( !showRow && columnIndex > 0 ) { + columnIndex--; + showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0; + } + } else { + showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0; + } + } + data.anyMatch = false; + // no other filters to process + if ( data.filters.join( '' ) === data.filter ) { + return showRow; + } + } + + for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) { + data.filter = data.filters[ columnIndex ]; + data.index = columnIndex; + + // filter types to exclude, per column + excludeMatch = vars.excludeFilter[ columnIndex ]; + + // ignore if filter is empty or disabled + if ( data.filter ) { + data.cache = data.cacheArray[ columnIndex ]; + // check if column data should be from the cell or from parsed data + if ( wo.filter_useParsedData || data.parsed[ columnIndex ] ) { + data.exact = data.cache; + } else { + result = data.rawArray[ columnIndex ] || ''; + data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405 + } + data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ? + data.exact.toLowerCase() : data.exact; + result = showRow; // if showRow is true, show that row + + // in case select filter option has a different value vs text 'a - z|A through Z' + ffxn = wo.filter_columnFilters ? + c.$filters.add( c.$externalFilters ) + .filter( '[data-column="'+ columnIndex + '"]' ) + .find( 'select option:selected' ) + .attr( 'data-function-name' ) || '' : ''; + // replace accents - see #357 + if ( c.sortLocaleCompare ) { + data.filter = ts.replaceAccents( data.filter ); + } + + val = true; + if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) { + data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] ); + // val is used to indicate that a filter select is using a default filter; + // so we override the exact & partial matches + val = false; + } + // data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ), + // data.filter = case sensitive + data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter; + fxn = vars.functions[ columnIndex ]; + $cell = c.$headerIndexed[ columnIndex ]; + hasSelect = $cell.hasClass( 'filter-select' ); + filterMatched = null; + if ( fxn || ( hasSelect && val ) ) { + if ( fxn === true || hasSelect ) { + // default selector uses exact match unless 'filter-match' class is found + filterMatched = $cell.hasClass( 'filter-match' ) ? + data.iExact.search( data.iFilter ) >= 0 : + data.filter === data.exact; + } else if ( typeof fxn === 'function' ) { + // filter callback( exact cell content, parser normalized content, + // filter input value, column index, jQuery row object ) + filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data ); + } else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) { + // selector option function + txt = ffxn || data.filter; + filterMatched = + fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data ); + } + } + if ( filterMatched === null ) { + // cycle through the different filters + // filters return a boolean or null if nothing matches + matches = null; + for ( ffxn in ts.filter.types ) { + if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) { + matches = ts.filter.types[ ffxn ]( c, data ); + if ( matches !== null ) { + filterMatched = matches; + } + } + } + if ( filterMatched !== null ) { + result = filterMatched; + // Look for match, and add child row data for matching + } else { + txt = ( data.iExact + data.childRowText ) + .indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) ); + result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) ); + } + } else { + result = filterMatched; + } + showRow = ( result ) ? showRow : false; + } + } + return showRow; + }, + findRows: function( table, filters, combinedFilters ) { + if ( table.config.lastCombinedFilter === combinedFilters || + !table.config.widgetOptions.filter_initialized ) { + return; + } + var len, norm_rows, rowData, $rows, rowIndex, tbodyIndex, $tbody, columnIndex, + isChild, childRow, lastSearch, showRow, time, val, indx, + notFiltered, searchFiltered, query, injected, res, id, txt, + storedFilters = $.extend( [], filters ), + regex = ts.filter.regex, + c = table.config, + wo = c.widgetOptions, + // data object passed to filters; anyMatch is a flag for the filters + data = { + anyMatch: false, + filters: filters, + // regex filter type cache + filter_regexCache : [], + }, + vars = { + // anyMatch really screws up with these types of filters + noAnyMatch: [ 'range', 'notMatch', 'operators' ], + // cache filter variables that use ts.getColumnData in the main loop + functions : [], + excludeFilter : [], + defaultColFilter : [], + defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || '' + }; + + // parse columns after formatter, in case the class is added at that point + data.parsed = c.$headers.map( function( columnIndex ) { + return c.parsers && c.parsers[ columnIndex ] && + // force parsing if parser type is numeric + c.parsers[ columnIndex ].parsed || + // getData won't return 'parsed' if other 'filter-' class names exist + // ( e.g. ) + ts.getData && ts.getData( c.$headerIndexed[ columnIndex ], + ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' || + $( this ).hasClass( 'filter-parsed' ); + }).get(); + + for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) { + vars.functions[ columnIndex ] = + ts.getColumnData( table, wo.filter_functions, columnIndex ); + vars.defaultColFilter[ columnIndex ] = + ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || ''; + vars.excludeFilter[ columnIndex ] = + ( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ ); + } + + if ( c.debug ) { + ts.log( 'Filter: Starting filter widget search', filters ); + time = new Date(); + } + // filtered rows count + c.filteredRows = 0; + c.totalRows = 0; + // combindedFilters are undefined on init + combinedFilters = ( storedFilters || [] ).join( '' ); + + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true ); + // skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel! + // $rows = $tbody.children( 'tr' ).not( c.selectorRemove ); + columnIndex = c.columns; + // convert stored rows into a jQuery object + norm_rows = c.cache[ tbodyIndex ].normalized; + $rows = $( $.map( norm_rows, function( el ) { + return el[ columnIndex ].$row.get(); + }) ); + + if ( combinedFilters === '' || wo.filter_serversideFiltering ) { + $rows + .removeClass( wo.filter_filteredRow ) + .not( '.' + c.cssChildRow ) + .css( 'display', '' ); + } else { + // filter out child rows + $rows = $rows.not( '.' + c.cssChildRow ); + len = $rows.length; + + if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) || + typeof filters[c.columns] !== 'undefined' ) { + data.anyMatchFlag = true; + data.anyMatchFilter = '' + ( + filters[ c.columns ] || + wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() || + '' + ); + if ( wo.filter_columnAnyMatch ) { + // specific columns search + query = data.anyMatchFilter.split( regex.andSplit ); + injected = false; + for ( indx = 0; indx < query.length; indx++ ) { + res = query[ indx ].split( ':' ); + if ( res.length > 1 ) { + // make the column a one-based index ( non-developers start counting from one :P ) + id = parseInt( res[0], 10 ) - 1; + if ( id >= 0 && id < c.columns ) { // if id is an integer + filters[ id ] = res[1]; + query.splice( indx, 1 ); + indx--; + injected = true; + } + } + } + if ( injected ) { + data.anyMatchFilter = query.join( ' && ' ); + } + } + } + + // optimize searching only through already filtered rows - see #313 + searchFiltered = wo.filter_searchFiltered; + lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || []; + if ( searchFiltered ) { + // cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669 + for ( indx = 0; indx < columnIndex + 1; indx++ ) { + val = filters[indx] || ''; + // break out of loop if we've already determined not to search filtered rows + if ( !searchFiltered ) { indx = columnIndex; } + // search already filtered rows if... + searchFiltered = searchFiltered && lastSearch.length && + // there are no changes from beginning of filter + val.indexOf( lastSearch[indx] || '' ) === 0 && + // if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string + !regex.alreadyFiltered.test( val ) && + // if we are not doing exact matches, using '|' ( logical or ) or not '!' + !/[=\"\|!]/.test( val ) && + // don't search only filtered if the value is negative + // ( '> -10' => '> -100' will ignore hidden rows ) + !( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) && + // if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593 + !( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length && + !c.$headerIndexed[indx].hasClass( 'filter-match' ) ); + } + } + notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length; + // can't search when all rows are hidden - this happens when looking for exact matches + if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; } + if ( c.debug ) { + ts.log( 'Filter: Searching through ' + + ( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' ); + } + if ( data.anyMatchFlag ) { + if ( c.sortLocaleCompare ) { + // replace accents + data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter ); + } + if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) { + data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter ); + // clear search filtered flag because default filters are not saved to the last search + searchFiltered = false; + } + // make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true + // when c.ignoreCase is true, the cache contains all lower case data + data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ? + data.anyMatchFilter : + data.anyMatchFilter.toLowerCase(); + } + + // loop through the rows + for ( rowIndex = 0; rowIndex < len; rowIndex++ ) { + + txt = $rows[ rowIndex ].className; + // the first row can never be a child row + isChild = rowIndex && regex.child.test( txt ); + // skip child rows & already filtered rows + if ( isChild || ( searchFiltered && regex.filtered.test( txt ) ) ) { + continue; + } + + data.$row = $rows.eq( rowIndex ); + data.cacheArray = norm_rows[ rowIndex ]; + rowData = data.cacheArray[ c.columns ]; + data.rawArray = rowData.raw; + data.childRowText = ''; + + if ( !wo.filter_childByColumn ) { + txt = ''; + // child row cached text + childRow = rowData.child; + // so, if 'table.config.widgetOptions.filter_childRows' is true and there is + // a match anywhere in the child row, then it will make the row visible + // checked here so the option can be changed dynamically + for ( indx = 0; indx < childRow.length; indx++ ) { + txt += ' ' + childRow[indx].join( '' ) || ''; + } + data.childRowText = wo.filter_childRows ? + ( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) : + ''; + } + + showRow = ts.filter.processRow( c, data, vars ); + childRow = rowData.$row.filter( ':gt( 0 )' ); + + if ( wo.filter_childRows && childRow.length ) { + if ( wo.filter_childByColumn ) { + // cycle through each child row + for ( indx = 0; indx < childRow.length; indx++ ) { + data.$row = childRow.eq( indx ); + data.cacheArray = rowData.child[ indx ]; + data.rawArray = data.cacheArray; + // use OR comparison on child rows + showRow = showRow || ts.filter.processRow( c, data, vars ); + } + } + childRow.toggleClass( wo.filter_filteredRow, !showRow ); + } + + rowData.$row + .toggleClass( wo.filter_filteredRow, !showRow )[0] + .display = showRow ? '' : 'none'; + } + } + c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length; + c.totalRows += $rows.length; + ts.processTbody( table, $tbody, false ); + } + c.lastCombinedFilter = combinedFilters; // save last search + // don't save 'filters' directly since it may have altered ( AnyMatch column searches ) + c.lastSearch = storedFilters; + c.$table.data( 'lastSearch', storedFilters ); + if ( wo.filter_saveFilters && ts.storage ) { + ts.storage( table, 'tablesorter-filters', storedFilters ); + } + if ( c.debug ) { + ts.benchmark( 'Completed filter widget search', time ); + } + if ( wo.filter_initialized ) { + c.$table.trigger( 'filterEnd', c ); + } + setTimeout( function() { + c.$table.trigger( 'applyWidgets' ); // make sure zebra widget is applied + }, 0 ); + }, + getOptionSource: function( table, column, onlyAvail ) { + table = $( table )[0]; + var cts, txt, indx, len, + c = table.config, + wo = c.widgetOptions, + parsed = [], + arry = false, + source = wo.filter_selectSource, + last = c.$table.data( 'lastSearch' ) || [], + fxn = $.isFunction( source ) ? true : ts.getColumnData( table, source, column ); + + if ( onlyAvail && last[column] !== '' ) { + onlyAvail = false; + } + + // filter select source option + if ( fxn === true ) { + // OVERALL source + arry = source( table, column, onlyAvail ); + } else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '' ) >= 0 ) ) { + // selectSource is a jQuery object or string of options + return fxn; + } else if ( $.isArray( fxn ) ) { + arry = fxn; + } else if ( $.type( source ) === 'object' && fxn ) { + // custom select source function for a SPECIFIC COLUMN + arry = fxn( table, column, onlyAvail ); + } + if ( arry === false ) { + // fall back to original method + arry = ts.filter.getOptions( table, column, onlyAvail ); + } + + // get unique elements and sort the list + // if $.tablesorter.sortText exists ( not in the original tablesorter ), + // then natural sort the list otherwise use a basic sort + arry = $.grep( arry, function( value, indx ) { + return $.inArray( value, arry ) === indx; + }); + + if ( c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) { + // unsorted select options + return arry; + } else { + len = arry.length; + // parse select option values + for ( indx = 0; indx < len; indx++ ) { + txt = arry[ indx ]; + // parse array data using set column parser; this DOES NOT pass the original + // table cell to the parser format function + parsed.push({ + t : txt, + // check parser length - fixes #934 + p : c.parsers && c.parsers.length && c.parsers[ column ].format( txt, table, [], column ) || txt + }); + } + + // sort parsed select options + cts = c.textSorter || ''; + parsed.sort( function( a, b ) { + // sortNatural breaks if you don't pass it strings + var x = a.p.toString(), + y = b.p.toString(); + if ( $.isFunction( cts ) ) { + // custom OVERALL text sorter + return cts( x, y, true, column, table ); + } else if ( typeof( cts ) === 'object' && cts.hasOwnProperty( column ) ) { + // custom text sorter for a SPECIFIC COLUMN + return cts[column]( x, y, true, column, table ); + } else if ( ts.sortNatural ) { + // fall back to natural sort + return ts.sortNatural( x, y ); + } + // using an older version! do a basic sort + return true; + }); + // rebuild arry from sorted parsed data + arry = []; + len = parsed.length; + for ( indx = 0; indx < len; indx++ ) { + arry.push( parsed[indx].t ); + } + return arry; + } + }, + getOptions: function( table, column, onlyAvail ) { + table = $( table )[0]; + var rowIndex, tbodyIndex, len, row, cache, + c = table.config, + wo = c.widgetOptions, + arry = []; + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) { + cache = c.cache[tbodyIndex]; + len = c.cache[tbodyIndex].normalized.length; + // loop through the rows + for ( rowIndex = 0; rowIndex < len; rowIndex++ ) { + // get cached row from cache.row ( old ) or row data object + // ( new; last item in normalized array ) + row = cache.row ? + cache.row[ rowIndex ] : + cache.normalized[ rowIndex ][ c.columns ].$row[0]; + // check if has class filtered + if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) { + continue; + } + // get non-normalized cell content + if ( wo.filter_useParsedData || + c.parsers[column].parsed || + c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) { + arry.push( '' + cache.normalized[ rowIndex ][ column ] ); + } else { + // get raw cached data instead of content directly from the cells + arry.push( cache.normalized[ rowIndex ][ c.columns ].raw[ column ] ); + } + } + } + return arry; + }, + buildSelect: function( table, column, arry, updating, onlyAvail ) { + table = $( table )[0]; + column = parseInt( column, 10 ); + if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) { + return; + } + var indx, val, txt, t, $filters, $filter, + c = table.config, + wo = c.widgetOptions, + node = c.$headerIndexed[ column ], + // t.data( 'placeholder' ) won't work in jQuery older than 1.4.3 + options = '', + // Get curent filter value + currentValue = c.$table + .find( 'thead' ) + .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' ) + .val(); + // nothing included in arry ( external source ), so get the options from + // filter_selectSource or column data + if ( typeof arry === 'undefined' || arry === '' ) { + arry = ts.filter.getOptionSource( table, column, onlyAvail ); + } + + if ( $.isArray( arry ) ) { + // build option list + for ( indx = 0; indx < arry.length; indx++ ) { + txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '"' ); + val = txt; + // allow including a symbol in the selectSource array + // 'a-z|A through Z' so that 'a-z' becomes the option value + // and 'A through Z' becomes the option text + if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) { + t = txt.split( wo.filter_selectSourceSeparator ); + val = t[0]; + txt = t[1]; + } + // replace quotes - fixes #242 & ignore empty strings + // see http://stackoverflow.com/q/14990971/145346 + options += arry[indx] !== '' ? + '' : ''; + } + // clear arry so it doesn't get appended twice + arry = []; + } + + // update all selects in the same column ( clone thead in sticky headers & + // any external selects ) - fixes 473 + $filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) ) + .find( '.' + tscss.filter ); + if ( wo.filter_$externalFilters ) { + $filters = $filters && $filters.length ? + $filters.add( wo.filter_$externalFilters ) : + wo.filter_$externalFilters; + } + $filter = $filters.filter( 'select[data-column="' + column + '"]' ); + + // make sure there is a select there! + if ( $filter.length ) { + $filter[ updating ? 'html' : 'append' ]( options ); + if ( !$.isArray( arry ) ) { + // append options if arry is provided externally as a string or jQuery object + // options ( default value ) was already added + $filter.append( arry ).val( currentValue ); + } + $filter.val( currentValue ); + } + }, + buildDefault: function( table, updating ) { + var columnIndex, $header, noSelect, + c = table.config, + wo = c.widgetOptions, + columns = c.columns; + // build default select dropdown + for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) { + $header = c.$headerIndexed[columnIndex]; + noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) ); + // look for the filter-select class; build/update it if found + if ( ( $header.hasClass( 'filter-select' ) || + ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) { + ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) ); + } + } + } +}; + +ts.getFilters = function( table, getRaw, setFilters, skipFirst ) { + var i, $filters, $column, cols, + filters = false, + c = table ? $( table )[0].config : '', + wo = c ? c.widgetOptions : ''; + if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) || + // setFilters called, but last search is exactly the same as the current + // fixes issue #733 & #903 where calling update causes the input values to reset + ( $.isArray(setFilters) && setFilters.join('') === c.lastCombinedFilter ) ) { + return $( table ).data( 'lastSearch' ); + } + if ( c ) { + if ( c.$filters ) { + $filters = c.$filters.find( '.' + tscss.filter ); + } + if ( wo.filter_$externalFilters ) { + $filters = $filters && $filters.length ? + $filters.add( wo.filter_$externalFilters ) : + wo.filter_$externalFilters; + } + if ( $filters && $filters.length ) { + filters = setFilters || []; + for ( i = 0; i < c.columns + 1; i++ ) { + cols = ( i === c.columns ? + // 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' ) + wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector : + '[data-column="' + i + '"]' ); + $column = $filters.filter( cols ); + if ( $column.length ) { + // move the latest search to the first slot in the array + $column = ts.filter.getLatestSearch( $column ); + if ( $.isArray( setFilters ) ) { + // skip first ( latest input ) to maintain cursor position while typing + if ( skipFirst && $column.length > 1 ) { + $column = $column.slice( 1 ); + } + if ( i === c.columns ) { + // prevent data-column='all' from filling data-column='0,1' ( etc ) + cols = $column.filter( wo.filter_anyColumnSelector ); + $column = cols.length ? cols : $column; + } + $column + .val( setFilters[ i ] ) + .trigger( 'change.tsfilter' ); + } else { + filters[i] = $column.val() || ''; + // don't change the first... it will move the cursor + if ( i === c.columns ) { + // don't update range columns from 'all' setting + $column + .slice( 1 ) + .filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' ) + .val( filters[ i ] ); + } else { + $column + .slice( 1 ) + .val( filters[ i ] ); + } + } + // save any match input dynamically + if ( i === c.columns && $column.length ) { + wo.filter_$anyMatch = $column; + } + } + } + } + } + if ( filters.length === 0 ) { + filters = false; + } + return filters; +}; + +ts.setFilters = function( table, filter, apply, skipFirst ) { + var c = table ? $( table )[0].config : '', + valid = ts.getFilters( table, true, filter, skipFirst ); + if ( c && apply ) { + // ensure new set filters are applied, even if the search is the same + c.lastCombinedFilter = null; + c.lastSearch = []; + ts.filter.searching( c.table, filter, skipFirst ); + c.$table.trigger( 'filterFomatterUpdate' ); + } + return !!valid; +}; + +})( jQuery ); + +/*! Widget: stickyHeaders - updated 3/26/2015 (v2.21.3) *//* + * Requires tablesorter v2.8+ and jQuery 1.4.3+ + * by Rob Garrison + */ +;(function ($, window) { +'use strict'; +var ts = $.tablesorter || {}; + +$.extend(ts.css, { + sticky : 'tablesorter-stickyHeader', // stickyHeader + stickyVis : 'tablesorter-sticky-visible', + stickyHide: 'tablesorter-sticky-hidden', + stickyWrap: 'tablesorter-sticky-wrapper' +}); + +// Add a resize event to table headers +ts.addHeaderResizeEvent = function(table, disable, settings) { + table = $(table)[0]; // make sure we're using a dom element + if ( !table.config ) { return; } + var defaults = { + timer : 250 + }, + options = $.extend({}, defaults, settings), + c = table.config, + wo = c.widgetOptions, + checkSizes = function( triggerEvent ) { + var index, headers, $header, sizes, width, height, + len = c.$headers.length; + wo.resize_flag = true; + headers = []; + for ( index = 0; index < len; index++ ) { + $header = c.$headers.eq( index ); + sizes = $header.data( 'savedSizes' ) || [ 0,0 ]; // fixes #394 + width = $header[0].offsetWidth; + height = $header[0].offsetHeight; + if ( width !== sizes[0] || height !== sizes[1] ) { + $header.data( 'savedSizes', [ width, height ] ); + headers.push( $header[0] ); + } + } + if ( headers.length && triggerEvent !== false ) { + c.$table.trigger( 'resize', [ headers ] ); + } + wo.resize_flag = false; + }; + checkSizes( false ); + clearInterval(wo.resize_timer); + if (disable) { + wo.resize_flag = false; + return false; + } + wo.resize_timer = setInterval(function() { + if (wo.resize_flag) { return; } + checkSizes(); + }, options.timer); +}; + +// Sticky headers based on this awesome article: +// http://css-tricks.com/13465-persistent-headers/ +// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech +// ************************** +ts.addWidget({ + id: "stickyHeaders", + priority: 60, // sticky widget must be initialized after the filter widget! + options: { + stickyHeaders : '', // extra class name added to the sticky header row + stickyHeaders_attachTo : null, // jQuery selector or object to attach sticky header to + stickyHeaders_xScroll : null, // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window) + stickyHeaders_yScroll : null, // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window) + stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element + stickyHeaders_filteredToTop: true, // scroll table top into view after filtering + stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists + stickyHeaders_addResizeEvent : true, // trigger "resize" event on headers + stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header + stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs + }, + format: function(table, c, wo) { + // filter widget doesn't initialize on an empty table. Fixes #449 + if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) { + return; + } + var index, len, $t, + $table = c.$table, + // add position: relative to attach element, hopefully it won't cause trouble. + $attach = $(wo.stickyHeaders_attachTo), + namespace = c.namespace + 'stickyheaders ', + // element to watch for the scroll event + $yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window), + $xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window), + $thead = $table.children('thead:first'), + $header = $thead.children('tr').not('.sticky-false').children(), + $tfoot = $table.children('tfoot'), + $stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '', + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0, + // is this table nested? If so, find parent sticky header wrapper (div, not table) + $nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ? + $table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [], + nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0, + // clone table, then wrap to make sticky header + $stickyTable = wo.$sticky = $table.clone() + .addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders + ' ' + c.namespace.slice(1) + '_extra_table' ) + .wrap('
    '), + $stickyWrap = $stickyTable.parent() + .addClass(ts.css.stickyHide) + .css({ + position : $attach.length ? 'absolute' : 'fixed', + padding : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ), + top : stickyOffset + nestedStickyTop, + left : 0, + visibility : 'hidden', + zIndex : wo.stickyHeaders_zIndex || 2 + }), + $stickyThead = $stickyTable.children('thead:first'), + $stickyCells, + laststate = '', + spacing = 0, + setWidth = function($orig, $clone){ + var index, width, border, $cell, $this, + $cells = $orig.filter(':visible'), + len = $cells.length; + for ( index = 0; index < len; index++ ) { + $cell = $clone.filter(':visible').eq(index); + $this = $cells.eq(index); + // code from https://github.com/jmosbech/StickyTableHeaders + if ($this.css('box-sizing') === 'border-box') { + width = $this.outerWidth(); + } else { + if ($cell.css('border-collapse') === 'collapse') { + if (window.getComputedStyle) { + width = parseFloat( window.getComputedStyle($this[0], null).width ); + } else { + // ie8 only + border = parseFloat( $this.css('border-width') ); + width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border; + } + } else { + width = $this.width(); + } + } + $cell.css({ + 'width': width, + 'min-width': width, + 'max-width': width + }); + } + }, + resizeHeader = function() { + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0; + spacing = 0; + $stickyWrap.css({ + left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 : + $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing, + width: $table.outerWidth() + }); + setWidth( $table, $stickyTable ); + setWidth( $header, $stickyCells ); + }, + scrollSticky = function( resizing ) { + if (!$table.is(':visible')) { return; } // fixes #278 + // Detect nested tables - fixes #724 + nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0; + var offset = $table.offset(), + yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3 + xWindow = $.isWindow( $xScroll[0] ), + // scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop, + scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop, + tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)), + isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden', + cssSettings = { visibility : isVisible }; + + if ($attach.length) { + cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop(); + } + if (xWindow) { + // adjust when scrolling horizontally - fixes issue #143 + cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing; + } + if ($nestedSticky.length) { + cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop; + } + $stickyWrap + .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide ) + .addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide ) + .css(cssSettings); + if (isVisible !== laststate || resizing) { + // make sure the column widths match + resizeHeader(); + laststate = isVisible; + } + }; + // only add a position relative if a position isn't already defined + if ($attach.length && !$attach.css('position')) { + $attach.css('position', 'relative'); + } + // fix clone ID, if it exists - fixes #271 + if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; } + // clear out cloned table, except for sticky header + // include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing + $stickyTable.find('thead:gt(0), tr.sticky-false').hide(); + $stickyTable.find('tbody, tfoot').remove(); + $stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption); + // issue #172 - find td/th in sticky header + $stickyCells = $stickyThead.children().children(); + $stickyTable.css({ height:0, width:0, margin: 0 }); + // remove resizable block + $stickyCells.find('.' + ts.css.resizer).remove(); + // update sticky header class names to match real header after sorting + $table + .addClass('hasStickyHeaders') + .bind('pagerComplete' + namespace, function() { + resizeHeader(); + }); + + ts.bindEvents(table, $stickyThead.children().children('.' + ts.css.header)); + + // add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned. + $table.after( $stickyWrap ); + + // onRenderHeader is defined, we need to do something about it (fixes #641) + if (c.onRenderHeader) { + $t = $stickyThead.children('tr').children(); + len = $t.length; + for ( index = 0; index < len; index++ ) { + // send second parameter + c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] ); + } + } + + // make it sticky! + $xScroll.add($yScroll) + .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') ) + .bind('scroll resize '.split(' ').join( namespace ), function( event ) { + scrollSticky( event.type === 'resize' ); + }); + c.$table + .unbind('stickyHeadersUpdate' + namespace) + .bind('stickyHeadersUpdate' + namespace, function(){ + scrollSticky( true ); + }); + + if (wo.stickyHeaders_addResizeEvent) { + ts.addHeaderResizeEvent(table); + } + + // look for filter widget + if ($table.hasClass('hasFilters') && wo.filter_columnFilters) { + // scroll table into view after filtering, if sticky header is active - #482 + $table.bind('filterEnd' + namespace, function() { + // $(':focus') needs jQuery 1.6+ + var $td = $(document.activeElement).closest('td'), + column = $td.parent().children().index($td); + // only scroll if sticky header is active + if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) { + // scroll to original table (not sticky clone) + window.scrollTo(0, $table.position().top); + // give same input/select focus; check if c.$filters exists; fixes #594 + if (column >= 0 && c.$filters) { + c.$filters.eq(column).find('a, select, input').filter(':visible').focus(); + } + } + }); + ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) ); + // support hideFilters + if (wo.filter_hideFilters) { + ts.filter.hideFilters($stickyTable, c); + } + } + + $table.trigger('stickyHeadersInit'); + + }, + remove: function(table, c, wo) { + var namespace = c.namespace + 'stickyheaders '; + c.$table + .removeClass('hasStickyHeaders') + .unbind( ('pagerComplete filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') ) + .next('.' + ts.css.stickyWrap).remove(); + if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table + $(window) + .add(wo.stickyHeaders_xScroll) + .add(wo.stickyHeaders_yScroll) + .add(wo.stickyHeaders_attachTo) + .unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') ); + ts.addHeaderResizeEvent(table, false); + } +}); + +})(jQuery, window); + +/*! Widget: resizable - updated 5/17/2015 (v2.22.0) */ +;(function ($, window) { +'use strict'; +var ts = $.tablesorter || {}; + +$.extend(ts.css, { + resizableContainer : 'tablesorter-resizable-container', + resizableHandle : 'tablesorter-resizable-handle', + resizableNoSelect : 'tablesorter-disableSelection', + resizableStorage : 'tablesorter-resizable' +}); + +// Add extra scroller css +$(function(){ + var s = ''; + $(s).appendTo('body'); +}); + +ts.resizable = { + init : function( c, wo ) { + if ( c.$table.hasClass( 'hasResizable' ) ) { return; } + c.$table.addClass( 'hasResizable' ); + ts.resizableReset( c.table, true ); // set default widths + + // internal variables + wo.resizable_ = { + $wrap : c.$table.parent(), + mouseXPosition : 0, + $target : null, + $next : null, + overflow : c.$table.parent().css('overflow') === 'auto', + fullWidth : Math.abs(c.$table.parent().width() - c.$table.width()) < 20, + storedSizes : [] + }; + + var noResize, $header, column, storedSizes, + marginTop = parseInt( c.$table.css( 'margin-top' ), 10 ); + + wo.resizable_.storedSizes = storedSizes = ( ( ts.storage && wo.resizable !== false ) ? + ts.storage( c.table, ts.css.resizableStorage ) : + [] ) || []; + ts.resizable.setWidths( c, wo, storedSizes ); + + wo.$resizable_container = $( '
    ' ) + .css({ top : marginTop }) + .insertBefore( c.$table ); + // add container + for ( column = 0; column < c.columns; column++ ) { + $header = c.$headerIndexed[ column ]; + noResize = ts.getData( $header, ts.getColumnData( c.table, c.headers, column ), 'resizable' ) === 'false'; + if ( !noResize ) { + $( '
    ' ) + .appendTo( wo.$resizable_container ) + .attr({ + 'data-column' : column, + 'unselectable' : 'on' + }) + .data( 'header', $header ) + .bind( 'selectstart', false ); + } + } + c.$table.one('tablesorter-initialized', function() { + ts.resizable.setHandlePosition( c, wo ); + ts.resizable.bindings( this.config, this.config.widgetOptions ); + }); + }, + + setWidth : function( $el, width ) { + $el.css({ + 'width' : width, + 'min-width' : '', + 'max-width' : '' + }); + }, + + setWidths : function( c, wo, storedSizes ) { + var column, + $extra = $( c.namespace + '_extra_headers' ), + $col = c.$table.children( 'colgroup' ).children( 'col' ); + storedSizes = storedSizes || wo.resizable_.storedSizes || []; + // process only if table ID or url match + if ( storedSizes.length ) { + for ( column = 0; column < c.columns; column++ ) { + // set saved resizable widths + c.$headerIndexed[ column ].width( storedSizes[ column ] ); + if ( $extra.length ) { + // stickyHeaders needs to modify min & max width as well + ts.resizable.setWidth( $extra.eq( column ).add( $col.eq( column ) ), storedSizes[ column ] ); + } + } + if ( $( c.namespace + '_extra_table' ).length && !ts.hasWidget( c.table, 'scroller' ) ) { + ts.resizable.setWidth( $( c.namespace + '_extra_table' ), c.$table.outerWidth() ); + } + } + }, + + setHandlePosition : function( c, wo ) { + var startPosition, + hasScroller = ts.hasWidget( c.table, 'scroller' ), + tableHeight = c.$table.height(), + $handles = wo.$resizable_container.children(), + handleCenter = Math.floor( $handles.width() / 2 ); + + if ( hasScroller ) { + tableHeight = 0; + c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function(){ + var $this = $(this); + // center table has a max-height set + tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height(); + }); + } + // subtract out table left position from resizable handles. Fixes #864 + startPosition = c.$table.position().left; + $handles.each( function() { + var $this = $(this), + column = parseInt( $this.attr( 'data-column' ), 10 ), + columns = c.columns - 1, + $header = $this.data( 'header' ); + if ( !$header ) { return; } // see #859 + if ( !$header.is(':visible') ) { + $this.hide(); + } else if ( column < columns || column === columns && wo.resizable_addLastColumn ) { + $this.css({ + display: 'inline-block', + height : tableHeight, + left : $header.position().left - startPosition + $header.outerWidth() - handleCenter + }); + } + }); + }, + + // prevent text selection while dragging resize bar + toggleTextSelection : function( c, toggle ) { + var namespace = c.namespace + 'tsresize'; + c.widgetOptions.resizable_.disabled = toggle; + $( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle ); + if ( toggle ) { + $( 'body' ) + .attr( 'unselectable', 'on' ) + .bind( 'selectstart' + namespace, false ); + } else { + $( 'body' ) + .removeAttr( 'unselectable' ) + .unbind( 'selectstart' + namespace ); + } + }, + + bindings : function( c, wo ) { + var namespace = c.namespace + 'tsresize'; + wo.$resizable_container.children().bind( 'mousedown', function( event ) { + // save header cell and mouse position + var column, $this, + vars = wo.resizable_, + $extras = $( c.namespace + '_extra_headers' ), + $header = $( event.target ).data( 'header' ); + + column = parseInt( $header.attr( 'data-column' ), 10 ); + vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') ); + vars.target = column; + + // if table is not as wide as it's parent, then resize the table + vars.$next = event.shiftKey || wo.resizable_targetLast ? + $header.parent().children().not( '.resizable-false' ).filter( ':last' ) : + $header.nextAll( ':not(.resizable-false)' ).eq( 0 ); + + column = parseInt( vars.$next.attr( 'data-column' ), 10 ); + vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') ); + vars.next = column; + + vars.mouseXPosition = event.pageX; + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + ts.resizable.toggleTextSelection( c, true ); + }); + + $( document ) + .bind( 'mousemove' + namespace, function( event ) { + var vars = wo.resizable_; + // ignore mousemove if no mousedown + if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; } + if ( wo.resizable_throttle ) { + clearTimeout( vars.timer ); + vars.timer = setTimeout( function() { + ts.resizable.mouseMove( c, wo, event ); + }, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle ); + } else { + ts.resizable.mouseMove( c, wo, event ); + } + }) + .bind( 'mouseup' + namespace, function() { + if (!wo.resizable_.disabled) { return; } + ts.resizable.toggleTextSelection( c, false ); + ts.resizable.stopResize( c, wo ); + ts.resizable.setHandlePosition( c, wo ); + }); + + // resizeEnd event triggered by scroller widget + $( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }); + + // right click to reset columns to default widths + c.$table + .bind( 'columnUpdate' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }) + .find( 'thead:first' ) + .add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) ) + .bind( 'contextmenu' + namespace, function() { + // $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset + var allowClick = wo.resizable_.storedSizes.length === 0; + ts.resizableReset( c.table ); + ts.resizable.setHandlePosition( c, wo ); + wo.resizable_.storedSizes = []; + return allowClick; + }); + + }, + + mouseMove : function( c, wo, event ) { + if ( wo.resizable_.mouseXPosition === 0 || !wo.resizable_.$target ) { return; } + // resize columns + var vars = wo.resizable_, + $next = vars.$next, + leftEdge = event.pageX - vars.mouseXPosition; + if ( vars.fullWidth ) { + vars.storedSizes[ vars.target ] += leftEdge; + vars.storedSizes[ vars.next ] -= leftEdge; + ts.resizable.setWidths( c, wo ); + + } else if ( vars.overflow ) { + c.$table.add( $( c.namespace + '_extra_table' ) ).width(function(i, w){ + return w + leftEdge; + }); + if ( !$next.length ) { + // if expanding right-most column, scroll the wrapper + vars.$wrap[0].scrollLeft = c.$table.width(); + } + } else { + vars.storedSizes[ vars.target ] += leftEdge; + ts.resizable.setWidths( c, wo ); + } + vars.mouseXPosition = event.pageX; + // dynamically update sticky header widths + c.$table.trigger('stickyHeadersUpdate'); + }, + + stopResize : function( c, wo ) { + var $this, column, + vars = wo.resizable_; + vars.storedSizes = []; + if ( ts.storage ) { + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + if ( wo.resizable !== false ) { + // save all column widths + ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes ); + } + } + vars.mouseXPosition = 0; + vars.$target = vars.$next = null; + // will update stickyHeaders, just in case, see #912 + c.$table.trigger('stickyHeadersUpdate'); + } +}; + +// this widget saves the column widths if +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: "resizable", + priority: 40, + options: { + resizable : true, + resizable_addLastColumn : false, + resizable_widths : [], + resizable_throttle : false, // set to true (5ms) or any number 0-10 range + resizable_targetLast : false + }, + init: function(table, thisWidget, c, wo) { + ts.resizable.init( c, wo ); + }, + remove: function( table, c, wo, refreshing ) { + if (wo.$resizable_container) { + var namespace = c.namespace + 'tsresize'; + c.$table.add( $( c.namespace + '_extra_table' ) ) + .removeClass('hasResizable') + .children( 'thead' ).unbind( 'contextmenu' + namespace ); + + wo.$resizable_container.remove(); + ts.resizable.toggleTextSelection( c, false ); + ts.resizableReset( table, refreshing ); + $( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace ); + } + } +}); + +ts.resizableReset = function( table, refreshing ) { + $( table ).each(function(){ + var index, $t, + c = this.config, + wo = c && c.widgetOptions; + if ( table && c && c.$headerIndexed.length ) { + for ( index = 0; index < c.columns; index++ ) { + $t = c.$headerIndexed[ index ]; + if ( wo.resizable_widths && wo.resizable_widths[ index ] ) { + $t.css( 'width', wo.resizable_widths[ index ] ); + } else if ( !$t.hasClass( 'resizable-false' ) ) { + // don't clear the width of any column that is not resizable + $t.css( 'width', '' ); + } + } + // reset stickyHeader widths + c.$table.trigger( 'stickyHeadersUpdate' ); + if ( ts.storage && !refreshing ) { + ts.storage( this, ts.css.resizableStorage, {} ); + } + } + }); +}; + +})( jQuery, window ); + +/*! Widget: saveSort */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +// this widget saves the last sort only if the +// saveSort widget option is true AND the +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: 'saveSort', + priority: 20, + options: { + saveSort : true + }, + init: function(table, thisWidget, c, wo) { + // run widget format before all other widgets are applied to the table + thisWidget.format(table, c, wo, true); + }, + format: function(table, c, wo, init) { + var stored, time, + $table = c.$table, + saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true + sortList = { "sortList" : c.sortList }; + if (c.debug) { + time = new Date(); + } + if ($table.hasClass('hasSaveSort')) { + if (saveSort && table.hasInitialized && ts.storage) { + ts.storage( table, 'tablesorter-savesort', sortList ); + if (c.debug) { + ts.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time); + } + } + } else { + // set table sort on initial run of the widget + $table.addClass('hasSaveSort'); + sortList = ''; + // get data + if (ts.storage) { + stored = ts.storage( table, 'tablesorter-savesort' ); + sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : ''; + if (c.debug) { + ts.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time); + } + $table.bind('saveSortReset', function(event) { + event.stopPropagation(); + ts.storage( table, 'tablesorter-savesort', '' ); + }); + } + // init is true when widget init is run, this will run this widget before all other widgets have initialized + // this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice. + if (init && sortList && sortList.length > 0) { + c.sortList = sortList; + } else if (table.hasInitialized && sortList && sortList.length > 0) { + // update sort change + $table.trigger('sorton', [sortList]); + } + } + }, + remove: function(table, c) { + c.$table.removeClass('hasSaveSort'); + // clear storage + if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); } + } +}); + +})(jQuery); + +return $.tablesorter; +})); diff --git a/dist/js/jquery.tablesorter.widgets.min.js b/dist/js/jquery.tablesorter.widgets.min.js new file mode 100644 index 0000000..1771941 --- /dev/null +++ b/dist/js/jquery.tablesorter.widgets.min.js @@ -0,0 +1,3 @@ +/*! tablesorter (FORK) - updated 06-07-2015 (v2.22.1)*/ +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){return function(a,b,c){"use strict";var d=a.tablesorter||{};d.storage=function(e,f,g,h){e=a(e)[0];var i,j,k,l=!1,m={},n=e.config,o=n&&n.widgetOptions,p=h&&h.useSessionStorage||o&&o.storage_useSessionStorage?"sessionStorage":"localStorage",q=a(e),r=h&&h.id||q.attr(h&&h.group||o&&o.storage_group||"data-table-group")||o&&o.storage_tableId||e.id||a(".tablesorter").index(q),s=h&&h.url||q.attr(h&&h.page||o&&o.storage_page||"data-table-page")||o&&o.storage_fixedUrl||n&&n.fixedUrl||b.location.pathname;if(p in b)try{b[p].setItem("_tmptest","temp"),l=!0,b[p].removeItem("_tmptest")}catch(t){n&&n.debug&&d.log(p+" is not supported in this browser")}return a.parseJSON&&(l?m=a.parseJSON(b[p][f]||"null")||{}:(j=c.cookie.split(/[;\s|=]/),i=a.inArray(f,j)+1,m=0!==i?a.parseJSON(j[i]||"null")||{}:{})),(g||""===g)&&b.JSON&&JSON.hasOwnProperty("stringify")?(m[s]||(m[s]={}),m[s][r]=g,l?b[p][f]=JSON.stringify(m):(k=new Date,k.setTime(k.getTime()+31536e6),c.cookie=f+"="+JSON.stringify(m).replace(/\"/g,'"')+"; expires="+k.toGMTString()+"; path=/"),void 0):m&&m[s]?m[s][r]:""}}(jQuery,window,document),function(a){"use strict";var b=a.tablesorter||{};b.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",sortNone:"",sortAsc:"",sortDesc:"",active:"",hover:"",icons:"",iconSortNone:"bootstrap-icon-unsorted",iconSortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",iconSortDesc:"icon-chevron-down 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",iconSortAsc:"ui-icon-carat-1-n",iconSortDesc:"ui-icon-carat-1-s",filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",odd:"ui-state-default"}},a.extend(b.css,{wrapper:"tablesorter-wrapper"}),b.addWidget({id:"uitheme",priority:10,format:function(c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r=b.themes,s=d.$table.add(a(d.namespace+"_extra_table")),t=d.$headers.add(a(d.namespace+"_extra_headers")),u=d.theme||"jui",v=r[u]||{},w=a.trim([v.sortNone,v.sortDesc,v.sortAsc,v.active].join(" ")),x=a.trim([v.iconSortNone,v.iconSortDesc,v.iconSortAsc].join(" "));for(d.debug&&(i=new Date),s.hasClass("tablesorter-"+u)&&d.theme===d.appliedTheme&&e.uitheme_applied||(e.uitheme_applied=!0,n=r[d.appliedTheme]||{},q=!a.isEmptyObject(n),o=q?[n.sortNone,n.sortDesc,n.sortAsc,n.active].join(" "):"",p=q?[n.iconSortNone,n.iconSortDesc,n.iconSortAsc].join(" "):"",q&&(e.zebra[0]=a.trim(" "+e.zebra[0].replace(" "+n.even,"")),e.zebra[1]=a.trim(" "+e.zebra[1].replace(" "+n.odd,"")),d.$tbodies.children().removeClass([n.even,n.odd].join(" "))),v.even&&(e.zebra[0]+=" "+v.even),v.odd&&(e.zebra[1]+=" "+v.odd),s.children("caption").removeClass(n.caption||"").addClass(v.caption),l=s.removeClass((d.appliedTheme?"tablesorter-"+(d.appliedTheme||""):"")+" "+(n.table||"")).addClass("tablesorter-"+u+" "+(v.table||"")).children("tfoot"),d.appliedTheme=d.theme,l.length&&l.children("tr").removeClass(n.footerRow||"").addClass(v.footerRow).children("th, td").removeClass(n.footerCells||"").addClass(v.footerCells),t.removeClass((q?[n.header,n.hover,o].join(" "):"")||"").addClass(v.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(b){a(this)["mouseenter"===b.type?"addClass":"removeClass"](v.hover||"")}),t.each(function(){var c=a(this);c.find("."+b.css.wrapper).length||c.wrapInner('
    ')}),d.cssIcon&&t.find("."+b.css.icon).removeClass(q?[n.icons,p].join(" "):"").addClass(v.icons||""),s.hasClass("hasFilters")&&s.children("thead").children("."+b.css.filterRow).removeClass(q?n.filterRow||"":"").addClass(v.filterRow||"")),f=0;f1)))for(m=1;q>m;m++)k.eq(p[m][0]).addClass(r[m]||r[s])}),b.processTbody(c,f,!1);if(i=e.columns_thead!==!1?["thead tr"]:[],e.columns_tfoot!==!1&&i.push("tfoot tr"),i.length&&(h=n.find(i.join(",")).children().removeClass(l),q))for(m=0;q>m;m++)h.filter('[data-column="'+p[m][0]+'"]').addClass(r[m]||r[s])},remove:function(c,d,e){var f,g,h=d.$tbodies,i=(e.columns||["primary","secondary","tertiary"]).join(" ");for(d.$headers.removeClass(i),d.$table.children("tfoot").children("tr").children("th, td").removeClass(i),f=0;f=]/g,query:"(q|query)"},types:{regex:function(a,c){if(b.filter.regex.regex.test(c.filter)){var d,e=c.filter_regexCache[c.index]||b.filter.regex.regex.exec(c.filter),f=e instanceof RegExp;try{f||(c.filter_regexCache[c.index]=e=new RegExp(e[1],e[2])),d=e.test(c.exact)}catch(g){d=!1}return d}return null},operators:function(c,d){if(/^[<>]=?/.test(d.iFilter)&&""!==d.iExact){var e,f,g,h=c.table,i=d.index,j=d.parsed[i],k=b.formatFloat(d.iFilter.replace(b.filter.regex.operators,""),h),l=c.parsers[i],m=k;return(j||"numeric"===l.type)&&(g=a.trim(""+d.iFilter.replace(b.filter.regex.operators,"")),f=b.filter.parseFilter(c,g,i,!0),k="number"!=typeof f||""===f||isNaN(f)?k:f),!j&&"numeric"!==l.type||isNaN(k)||"undefined"==typeof d.cache?(g=isNaN(d.iExact)?d.iExact.replace(b.filter.regex.nondigit,""):d.iExact,e=b.formatFloat(g,h)):e=d.cache,/>/.test(d.iFilter)?f=/>=/.test(d.iFilter)?e>=k:e>k:/=e:k>e),f||""!==m||(f=!0),f}return null},notMatch:function(c,d){if(/^\!/.test(d.iFilter)){var e,f=d.iFilter.replace("!",""),g=b.filter.parseFilter(c,f,d.index,d.parsed[d.index])||"";return b.filter.regex.exact.test(g)?(g=g.replace(b.filter.regex.exact,""),""===g?!0:a.trim(g)!==d.iExact):(e=d.iExact.search(a.trim(g)),""===g?!0:!(c.widgetOptions.filter_startsWith?0===e:e>=0))}return null},exact:function(c,d){if(b.filter.regex.exact.test(d.iFilter)){var e=d.iFilter.replace(b.filter.regex.exact,""),f=b.filter.parseFilter(c,e,d.index,d.parsed[d.index])||"";return d.anyMatch?a.inArray(f,d.rowArray)>=0:f==d.iExact}return null},and:function(c,d){if(b.filter.regex.andTest.test(d.filter)){for(var e=d.index,f=d.parsed[e],g=d.iFilter.split(b.filter.regex.andSplit),h=d.iExact.search(a.trim(b.filter.parseFilter(c,g[0],e,f)))>=0,i=g.length-1;h&&i;)h=h&&d.iExact.search(a.trim(b.filter.parseFilter(c,g[i],e,f)))>=0,i--;return h}return null},range:function(a,c){if(b.filter.regex.toTest.test(c.iFilter)){var d,e,f,g,h=a.table,i=c.index,j=c.parsed[i],k=c.iFilter.split(b.filter.regex.toSplit);return e=k[0].replace(b.filter.regex.nondigit,"")||"",f=b.formatFloat(b.filter.parseFilter(a,e,i,j),h),e=k[1].replace(b.filter.regex.nondigit,"")||"",g=b.formatFloat(b.filter.parseFilter(a,e,i,j),h),(j||"numeric"===a.parsers[i].type)&&(d=a.parsers[i].format(""+k[0],h,a.$headers.eq(i),i),f=""===d||isNaN(d)?f:d,d=a.parsers[i].format(""+k[1],h,a.$headers.eq(i),i),g=""===d||isNaN(d)?g:d),!j&&"numeric"!==a.parsers[i].type||isNaN(f)||isNaN(g)?(e=isNaN(c.iExact)?c.iExact.replace(b.filter.regex.nondigit,""):c.iExact,d=b.formatFloat(e,h)):d=c.cache,f>g&&(e=f,f=g,g=e),d>=f&&g>=d||""===f||""===g}return null},wild:function(c,d){if(/[\?\*\|]/.test(d.iFilter)||b.filter.regex.orReplace.test(d.filter)){var e=d.index,f=d.parsed[e],g=d.iFilter.replace(b.filter.regex.orReplace,"|"),h=""+(b.filter.parseFilter(c,g,e,f)||"");return!c.$headerIndexed[e].hasClass("filter-match")&&/\|/.test(h)&&("|"===h[h.length-1]&&(h+="*"),h=d.anyMatch&&a.isArray(d.rowArray)?"("+h+")":"^("+h+")$"),new RegExp(h.replace(/\?/g,"\\S{1}").replace(/\*/g,"\\S*")).test(d.iExact)}return null},fuzzy:function(a,c){if(/^~/.test(c.iFilter)){var d,e=0,f=c.iExact.length,g=c.iFilter.slice(1),h=b.filter.parseFilter(a,g,c.index,c.parsed[c.index])||"";for(d=0;f>d;d++)c.iExact[d]===h[e]&&(e+=1);return e===h.length?!0:!1}return null}},init:function(d,e,f){b.language=a.extend(!0,{},{to:"to",or:"or",and:"and"},b.language);var g,h,i,j,k,l,m,n,o,p=b.filter.regex;if(e.$table.addClass("hasFilters"),f.searchTimer=null,f.filter_initTimer=null,f.filter_formatterCount=0,f.filter_formatterInit=[],f.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',f.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',m="\\{"+b.filter.regex.query+"\\}",a.extend(p,{child:new RegExp(e.cssChildRow),filtered:new RegExp(f.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+b.language.or+"|-|"+b.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+b.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+b.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+b.language.and+"|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+b.language.and+"|&&)\\s+)","gi"),orReplace:new RegExp("\\s+("+b.language.or+")\\s+","gi"),iQuery:new RegExp(m,"i"),igQuery:new RegExp(m,"ig")}),m=e.$headers.filter(".filter-false, .parser-false").length,f.filter_columnFilters!==!1&&m!==e.$headers.length&&b.filter.buildRow(d,e,f),i="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(e.namespace+"filter "),e.$table.bind(i,function(g,h){return m=f.filter_hideEmpty&&a.isEmptyObject(e.cache)&&!(e.delayInit&&"appendCache"===g.type),e.$table.find("."+c.filterRow).toggleClass(f.filter_filteredRow,m),/(search|filter)/.test(g.type)||(g.stopPropagation(),b.filter.buildDefault(d,!0)),"filterReset"===g.type?(e.$table.find("."+c.filter).add(f.filter_$externalFilters).val(""),b.filter.searching(d,[])):"filterEnd"===g.type?b.filter.buildDefault(d,!0):(h="search"===g.type?h:"updateComplete"===g.type?e.$table.data("lastSearch"):"",/(update|add)/.test(g.type)&&"updateComplete"!==g.type&&(e.lastCombinedFilter=null,e.lastSearch=[]),b.filter.searching(d,h,!0)),!1}),f.filter_reset&&(f.filter_reset instanceof a?f.filter_reset.click(function(){e.$table.trigger("filterReset")}):a(f.filter_reset).length&&a(document).undelegate(f.filter_reset,"click.tsfilter").delegate(f.filter_reset,"click.tsfilter",function(){e.$table.trigger("filterReset")})),f.filter_functions)for(k=0;k'+(j.data("placeholder")||j.attr("data-placeholder")||f.filter_placeholder.select||"")+"":"",m=h,i=h,h.indexOf(f.filter_selectSourceSeparator)>=0&&(m=h.split(f.filter_selectSourceSeparator),i=m[1],m=m[0]),g+="");e.$table.find("thead").find("select."+c.filter+'[data-column="'+k+'"]').append(g),i=f.filter_selectSource,n=a.isFunction(i)?!0:b.getColumnData(d,i,k),n&&b.filter.buildSelect(e.table,k,"",!0,j.hasClass(f.filter_onlyAvail))}b.filter.buildDefault(d,!0),b.filter.bindSearch(d,e.$table.find("."+c.filter),!0),f.filter_external&&b.filter.bindSearch(d,f.filter_external),f.filter_hideFilters&&b.filter.hideFilters(d,e),e.showProcessing&&(i="filterStart filterEnd ".split(" ").join(e.namespace+"filter "),e.$table.unbind(i.replace(/\s+/g," ")).bind(i,function(f,g){j=g?e.$table.find("."+c.header).filter("[data-column]").filter(function(){return""!==g[a(this).data("column")]}):"",b.isProcessing(d,"filterStart"===f.type,g?j:"")})),e.filteredRows=e.totalRows,i="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(e.namespace+"filter "),e.$table.unbind(i.replace(/\s+/g," ")).bind(i,function(){var a=this.config.widgetOptions;l=b.filter.setDefaults(d,e,a)||[],l.length&&(e.delayInit&&""===l.join("")||b.setFilters(d,l,!0)),e.$table.trigger("filterFomatterUpdate"),setTimeout(function(){a.filter_initialized||b.filter.filterInitComplete(e)},100)}),e.pager&&e.pager.initialized&&!f.filter_initialized&&(e.$table.trigger("filterFomatterUpdate"),setTimeout(function(){b.filter.filterInitComplete(e)},100))},formatterUpdated:function(a,b){var c=a.closest("table")[0].config.widgetOptions;c.filter_initialized||(c.filter_formatterInit[b]=1)},filterInitComplete:function(c){var d,e,f=c.widgetOptions,g=0,h=function(){f.filter_initialized=!0,c.$table.trigger("filterInit",c),b.filter.findRows(c.table,c.$table.data("lastSearch")||[])};if(a.isEmptyObject(f.filter_formatter))h();else{for(e=f.filter_formatterInit.length,d=0;e>d;d++)1===f.filter_formatterInit[d]&&g++;clearTimeout(f.filter_initTimer),f.filter_initialized||g!==f.filter_formatterCount?f.filter_initialized||(f.filter_initTimer=setTimeout(function(){h()},500)):h()}},setDefaults:function(c,d,e){var f,g,h,i,j,k=b.getFilters(c)||[];if(e.filter_saveFilters&&b.storage&&(g=b.storage(c,"tablesorter-filters")||[],f=a.isArray(g),f&&""===g.join("")||!f||(k=g)),""===k.join(""))for(j=d.$headers.add(e.filter_$externalFilters).filter("["+e.filter_defaultAttrib+"]"),h=0;h<=d.columns;h++)i=h===d.columns?"all":h,k[h]=j.filter('[data-column="'+i+'"]').attr(e.filter_defaultAttrib)||k[h]||"";return d.$table.data("lastSearch",k),k},parseFilter:function(a,b,c,d){return d?a.parsers[c].format(b,a.table,[],c):b},buildRow:function(d,e,f){var g,h,i,j,k,l,m,n,o=f.filter_cellFilter,p=e.columns,q=a.isArray(o),r='';for(h=0;p>h;h++)r+="").appendTo(e.$table.children("thead").eq(0)).find("td"),h=0;p>h;h++)k=!1,i=e.$headerIndexed[h],m=b.getColumnData(d,f.filter_functions,h),j=f.filter_functions&&m&&"function"!=typeof m||i.hasClass("filter-select"),g=b.getColumnData(d,e.headers,h),k="false"===b.getData(i[0],g,"filter")||"false"===b.getData(i[0],g,"parser"),j?r=a("').appendTo(e.$filters.eq(h)),r&&(n=i.data("placeholder")||i.attr("data-placeholder")||f.filter_placeholder.search||"",r.attr("placeholder",n))),r&&(l=(a.isArray(f.filter_cssFilter)?"undefined"!=typeof f.filter_cssFilter[h]?f.filter_cssFilter[h]||"":"":f.filter_cssFilter)||"",r.addClass(c.filter+" "+l).attr("data-column",h),k&&(r.attr("placeholder","").addClass(c.filterDisabled)[0].disabled=!0))},bindSearch:function(c,d,e){if(c=a(c)[0],d=a(d),d.length){var f,g=c.config,h=g.widgetOptions,i=g.namespace+"filter",j=h.filter_$externalFilters;e!==!0&&(f=h.filter_anyColumnSelector+","+h.filter_multipleColumnSelector,h.filter_$anyMatch=d.filter(f),j&&j.length?h.filter_$externalFilters=h.filter_$externalFilters.add(d):h.filter_$externalFilters=d,b.setFilters(c,g.$table.data("lastSearch")||[],e===!1)),f="keypress keyup search change ".split(" ").join(i+" "),d.attr("data-lastSearchTime",(new Date).getTime()).unbind(f.replace(/\s+/g," ")).bind("keyup"+i,function(d){if(a(this).attr("data-lastSearchTime",(new Date).getTime()),27===d.which)this.value="";else{if(h.filter_liveSearch===!1)return;if(""!==this.value&&("number"==typeof h.filter_liveSearch&&this.value.length=37&&d.which<=40)))return}b.filter.searching(c,!0,!0)}).bind("search change keypress ".split(" ").join(i+" "),function(d){var e=a(this).data("column");(13===d.which||"search"===d.type||"change"===d.type&&this.value!==g.lastSearch[e])&&(d.preventDefault(),a(this).attr("data-lastSearchTime",(new Date).getTime()),b.filter.searching(c,!1,!0))})}},searching:function(a,c,d){var e=a.config.widgetOptions;clearTimeout(e.searchTimer),"undefined"==typeof c||c===!0?e.searchTimer=setTimeout(function(){b.filter.checkFilters(a,c,d)},e.filter_liveSearch?e.filter_searchDelay:10):b.filter.checkFilters(a,c,d)},checkFilters:function(d,e,f){var g=d.config,h=g.widgetOptions,i=a.isArray(e),j=i?e:b.getFilters(d,!0),k=(j||[]).join("");return a.isEmptyObject(g.cache)?void(g.delayInit&&g.pager&&g.pager.initialized&&g.$table.trigger("updateCache",[function(){b.filter.checkFilters(d,!1,f)}])):(i&&(b.setFilters(d,j,!1,f!==!0),h.filter_initialized||(g.lastCombinedFilter="")),h.filter_hideFilters&&g.$table.find("."+c.filterRow).trigger(""===k?"mouseleave":"mouseenter"),g.lastCombinedFilter!==k||e===!1?(e===!1&&(g.lastCombinedFilter=null,g.lastSearch=[]),h.filter_initialized&&g.$table.trigger("filterStart",[j]),g.showProcessing?void setTimeout(function(){return b.filter.findRows(d,j,k),!1},30):(b.filter.findRows(d,j,k),!1)):void 0)},hideFilters:function(d,e){var f,g,h;a(d).find("."+c.filterRow).addClass(c.filterRowHide).bind("mouseenter mouseleave",function(b){var d=b;f=a(this),clearTimeout(h),h=setTimeout(function(){/enter|over/.test(d.type)?f.removeClass(c.filterRowHide):a(document.activeElement).closest("tr")[0]!==f[0]&&""===e.lastCombinedFilter&&f.addClass(c.filterRowHide)},200)}).find("input, select").bind("focus blur",function(d){g=a(this).closest("tr"),clearTimeout(h);var f=d;h=setTimeout(function(){""===b.getFilters(e.$table).join("")&&g.toggleClass(c.filterRowHide,"focus"===f.type)},200)})},defaultFilter:function(c,d){if(""===c)return c;var e=b.filter.regex.iQuery,f=d.match(b.filter.regex.igQuery).length,g=f>1?a.trim(c).split(/\s/):[a.trim(c)],h=g.length-1,i=0,j=d;for(1>h&&f>1&&(g[1]=g[0]);e.test(j);)j=j.replace(e,g[i++]||""),e.test(j)&&h>i&&""!==(g[i]||"")&&(j=d.replace(e,j));return j},getLatestSearch:function(b){return b?b.sort(function(b,c){return a(c).attr("data-lastSearchTime")-a(b).attr("data-lastSearchTime")}):b||a()},multipleColumns:function(c,d){var e,f,g,h,i,j,k,l,m,n=c.widgetOptions,o=n.filter_initialized||!d.filter(n.filter_anyColumnSelector).length,p=[],q=a.trim(b.filter.getLatestSearch(d).attr("data-column")||"");if(o&&/-/.test(q))for(f=q.match(/(\d+)\s*-\s*(\d+)/g),m=f.length,l=0;m>l;l++){for(g=f[l].split(/\s*-\s*/),h=parseInt(g[0],10)||0,i=parseInt(g[1],10)||c.columns-1,h>i&&(e=h,h=i,i=e),i>=c.columns&&(i=c.columns-1);i>=h;h++)p.push(h);q=q.replace(f[l],"")}if(o&&/,/.test(q))for(j=q.split(/\s*,\s*/),m=j.length,k=0;m>k;k++)""!==j[k]&&(l=parseInt(j[k],10),l-1?(d.parsed[e]?p=d.cacheArray[e]:(p=d.rawArray[e],p=a.trim(r.filter_ignoreCase?p.toLowerCase():p),c.sortLocaleCompare&&(p=b.replaceAccents(p))),p):void 0}).get(),d.filter=d.anyMatchFilter,d.iFilter=d.iAnyMatchFilter,d.exact=d.rowArray.join(" "),d.iExact=r.filter_ignoreCase?d.exact.toLowerCase():d.exact,d.cache=d.cacheArray.slice(0,-1).join(" "),l=null,i=null;for(o in b.filter.types)a.inArray(o,e.noAnyMatch)<0&&null===i&&(i=b.filter.types[o](c,d),null!==i&&(l=i));if(null!==l)s=l;else if(r.filter_startsWith)for(s=!1,g=c.columns;!s&&g>0;)g--,s=s||0===d.rowArray[g].indexOf(d.iFilter);else s=(d.iExact+d.childRowText).indexOf(d.iFilter)>=0;if(d.anyMatch=!1,d.filters.join("")===d.filter)return s}for(g=0;g=0:d.filter===d.exact:"function"==typeof n?l=n(d.exact,d.cache,d.filter,g,d.$row,c,d):"function"==typeof n[o||d.filter]&&(p=o||d.filter,l=n[p](d.exact,d.cache,d.filter,g,d.$row,c,d))),null===l){i=null;for(o in b.filter.types)a.inArray(o,m)<0&&null===i&&(i=b.filter.types[o](c,d),null!==i&&(l=i));null!==l?j=l:(p=(d.iExact+d.childRowText).indexOf(b.filter.parseFilter(c,d.iFilter,g,d.parsed[g])),j=!r.filter_startsWith&&p>=0||r.filter_startsWith&&0===p)}else j=l;s=j?s:!1}return s},findRows:function(c,d,e){if(c.config.lastCombinedFilter!==e&&c.config.widgetOptions.filter_initialized){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B=a.extend([],d),C=b.filter.regex,D=c.config,E=D.widgetOptions,F={anyMatch:!1,filters:d,filter_regexCache:[]},G={noAnyMatch:["range","notMatch","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:b.getColumnData(c,E.filter_defaultFilter,D.columns,!0)||""};for(F.parsed=D.$headers.map(function(d){return D.parsers&&D.parsers[d]&&D.parsers[d].parsed||b.getData&&"parsed"===b.getData(D.$headerIndexed[d],b.getColumnData(c,D.headers,d),"filter")||a(this).hasClass("filter-parsed")}).get(),m=0;m1&&(z=parseInt(y[0],10)-1,z>=0&&zt;t++)s=d[t]||"",v||(t=m),v=!(!v||!p.length||0!==s.indexOf(p[t]||"")||C.alreadyFiltered.test(s)||/[=\"\|!]/.test(s)||/(>=?\s*-\d)/.test(s)||/(<=?\s*\d)/.test(s)||""!==s&&D.$filters&&D.$filters.eq(t).find("select").length&&!D.$headerIndexed[t].hasClass("filter-match"));for(u=i.not("."+E.filter_filteredRow).length,v&&0===u&&(v=!1),D.debug&&b.log("Filter: Searching through "+(v&&f>u?u:"all")+" rows"),F.anyMatchFlag&&(D.sortLocaleCompare&&(F.anyMatchFilter=b.replaceAccents(F.anyMatchFilter)),E.filter_defaultFilter&&C.iQuery.test(G.defaultAnyFilter)&&(F.anyMatchFilter=b.filter.defaultFilter(F.anyMatchFilter,G.defaultAnyFilter),v=!1),F.iAnyMatchFilter=E.filter_ignoreCase&&D.ignoreCase?F.anyMatchFilter.toLowerCase():F.anyMatchFilter),j=0;f>j;j++)if(A=i[j].className,n=j&&C.child.test(A),!(n||v&&C.filtered.test(A))){if(F.$row=i.eq(j),F.cacheArray=g[j],h=F.cacheArray[D.columns],F.rawArray=h.raw,F.childRowText="",!E.filter_childByColumn){for(A="",o=h.child,t=0;t")>=0)return p;a.isArray(p)?m=p:"object"===a.type(n)&&p&&(m=p(c,d,e))}if(m===!1&&(m=b.filter.getOptions(c,d,e)),m=a.grep(m,function(b,c){return a.inArray(b,m)===c}),j.$headerIndexed[d].hasClass("filter-select-nosort"))return m;for(i=m.length,h=0;i>h;h++)g=m[h],l.push({t:g,p:j.parsers&&j.parsers.length&&j.parsers[d].format(g,c,[],d)||g});for(f=j.textSorter||"",l.sort(function(e,g){var h=e.p.toString(),i=g.p.toString();return a.isFunction(f)?f(h,i,!0,d,c):"object"==typeof f&&f.hasOwnProperty(d)?f[d](h,i,!0,d,c):b.sortNatural?b.sortNatural(h,i):!0}),m=[],i=l.length,h=0;i>h;h++)m.push(l[h].t);return m},getOptions:function(b,c,d){b=a(b)[0];var e,f,g,h,i,j=b.config,k=j.widgetOptions,l=[];for(f=0;fe;e++)h=i.row?i.row[e]:i.normalized[e][j.columns].$row[0],d&&h.className.match(k.filter_filteredRow)||(k.filter_useParsedData||j.parsers[c].parsed||j.$headerIndexed[c].hasClass("filter-parsed")?l.push(""+i.normalized[e][c]):l.push(i.normalized[e][j.columns].raw[c]));return l},buildSelect:function(d,e,f,g,h){if(d=a(d)[0],e=parseInt(e,10),d.config.cache&&!a.isEmptyObject(d.config.cache)){var i,j,k,l,m,n,o=d.config,p=o.widgetOptions,q=o.$headerIndexed[e],r='",s=o.$table.find("thead").find("select."+c.filter+'[data-column="'+e+'"]').val();if(("undefined"==typeof f||""===f)&&(f=b.filter.getOptionSource(d,e,h)),a.isArray(f)){for(i=0;i=0&&(l=k.split(p.filter_selectSourceSeparator),j=l[0],k=l[1]),r+=""!==f[i]?"":"";f=[]}m=(o.$filters?o.$filters:o.$table.children("thead")).find("."+c.filter),p.filter_$externalFilters&&(m=m&&m.length?m.add(p.filter_$externalFilters):p.filter_$externalFilters),n=m.filter('select[data-column="'+e+'"]'),n.length&&(n[g?"html":"append"](r),a.isArray(f)||n.append(f).val(s),n.val(s))}},buildDefault:function(a,c){var d,e,f,g=a.config,h=g.widgetOptions,i=g.columns;for(d=0;i>d;d++)e=g.$headerIndexed[d],f=!(e.hasClass("filter-false")||e.hasClass("parser-false")),(e.hasClass("filter-select")||b.getColumnData(a,h.filter_functions,d)===!0)&&f&&b.filter.buildSelect(a,d,"",c,e.hasClass(h.filter_onlyAvail))}},b.getFilters=function(d,e,f,g){var h,i,j,k,l=!1,m=d?a(d)[0].config:"",n=m?m.widgetOptions:"";if(e!==!0&&n&&!n.filter_columnFilters||a.isArray(f)&&f.join("")===m.lastCombinedFilter)return a(d).data("lastSearch");if(m&&(m.$filters&&(i=m.$filters.find("."+c.filter)),n.filter_$externalFilters&&(i=i&&i.length?i.add(n.filter_$externalFilters):n.filter_$externalFilters),i&&i.length))for(l=f||[],h=0;h1&&(j=j.slice(1)),h===m.columns&&(k=j.filter(n.filter_anyColumnSelector),j=k.length?k:j),j.val(f[h]).trigger("change.tsfilter")):(l[h]=j.val()||"",h===m.columns?j.slice(1).filter('[data-column*="'+j.attr("data-column")+'"]').val(l[h]):j.slice(1).val(l[h])),h===m.columns&&j.length&&(n.filter_$anyMatch=j));return 0===l.length&&(l=!1),l},b.setFilters=function(c,d,e,f){var g=c?a(c)[0].config:"",h=b.getFilters(c,!0,d,f);return g&&e&&(g.lastCombinedFilter=null,g.lastSearch=[],b.filter.searching(g.table,d,f),g.$table.trigger("filterFomatterUpdate")),!!h}}(jQuery),function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible", +stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),c.addHeaderResizeEvent=function(b,c,d){if(b=a(b)[0],b.config){var e={timer:250},f=a.extend({},e,d),g=b.config,h=g.widgetOptions,i=function(a){var b,c,d,e,f,i,j=g.$headers.length;for(h.resize_flag=!0,c=[],b=0;j>b;b++)d=g.$headers.eq(b),e=d.data("savedSizes")||[0,0],f=d[0].offsetWidth,i=d[0].offsetHeight,(f!==e[0]||i!==e[1])&&(d.data("savedSizes",[f,i]),c.push(d[0]));c.length&&a!==!1&&g.$table.trigger("resize",[c]),h.resize_flag=!1};return i(!1),clearInterval(h.resize_timer),c?(h.resize_flag=!1,!1):void(h.resize_timer=setInterval(function(){h.resize_flag||i()},f.timer))}},c.addWidget({id:"stickyHeaders",priority:60,options:{stickyHeaders:"",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(d,e,f){if(!(e.$table.hasClass("hasStickyHeaders")||a.inArray("filter",e.widgets)>=0&&!e.$table.hasClass("hasFilters"))){var g,h,i,j,k=e.$table,l=a(f.stickyHeaders_attachTo),m=e.namespace+"stickyheaders ",n=a(f.stickyHeaders_yScroll||f.stickyHeaders_attachTo||b),o=a(f.stickyHeaders_xScroll||f.stickyHeaders_attachTo||b),p=k.children("thead:first"),q=p.children("tr").not(".sticky-false").children(),r=k.children("tfoot"),s=isNaN(f.stickyHeaders_offset)?a(f.stickyHeaders_offset):"",t=s.length?s.height()||0:parseInt(f.stickyHeaders_offset,10)||0,u=k.parent().closest("."+c.css.table).hasClass("hasStickyHeaders")?k.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],v=u.length?u.height():0,w=f.$sticky=k.clone().addClass("containsStickyHeaders "+c.css.sticky+" "+f.stickyHeaders+" "+e.namespace.slice(1)+"_extra_table").wrap('
    '),x=w.parent().addClass(c.css.stickyHide).css({position:l.length?"absolute":"fixed",padding:parseInt(w.parent().parent().css("padding-left"),10),top:t+v,left:0,visibility:"hidden",zIndex:f.stickyHeaders_zIndex||2}),y=w.children("thead:first"),z="",A=0,B=function(a,c){var d,e,f,g,h,i=a.filter(":visible"),j=i.length;for(d=0;j>d;d++)g=c.filter(":visible").eq(d),h=i.eq(d),"border-box"===h.css("box-sizing")?e=h.outerWidth():"collapse"===g.css("border-collapse")?b.getComputedStyle?e=parseFloat(b.getComputedStyle(h[0],null).width):(f=parseFloat(h.css("border-width")),e=h.outerWidth()-parseFloat(h.css("padding-left"))-parseFloat(h.css("padding-right"))-f):e=h.width(),g.css({width:e,"min-width":e,"max-width":e})},C=function(){t=s.length?s.height()||0:parseInt(f.stickyHeaders_offset,10)||0,A=0,x.css({left:l.length?parseInt(l.css("padding-left"),10)||0:k.offset().left-parseInt(k.css("margin-left"),10)-o.scrollLeft()-A,width:k.outerWidth()}),B(k,w),B(q,j)},D=function(b){if(k.is(":visible")){v=u.length?u.offset().top-n.scrollTop()+u.height():0;var d=k.offset(),e=a.isWindow(n[0]),f=a.isWindow(o[0]),g=(l.length?e?n.scrollTop():n.offset().top:n.scrollTop())+t+v,h=k.height()-(x.height()+(r.height()||0)),i=g>d.top&&gg;g++)e.onRenderHeader.apply(i.eq(g),[g,e,w]);o.add(n).unbind("scroll resize ".split(" ").join(m).replace(/\s+/g," ")).bind("scroll resize ".split(" ").join(m),function(a){D("resize"===a.type)}),e.$table.unbind("stickyHeadersUpdate"+m).bind("stickyHeadersUpdate"+m,function(){D(!0)}),f.stickyHeaders_addResizeEvent&&c.addHeaderResizeEvent(d),k.hasClass("hasFilters")&&f.filter_columnFilters&&(k.bind("filterEnd"+m,function(){var d=a(document.activeElement).closest("td"),g=d.parent().children().index(d);x.hasClass(c.css.stickyVis)&&f.stickyHeaders_filteredToTop&&(b.scrollTo(0,k.position().top),g>=0&&e.$filters&&e.$filters.eq(g).find("a, select, input").filter(":visible").focus())}),c.filter.bindSearch(k,j.find("."+c.css.filter)),f.filter_hideFilters&&c.filter.hideFilters(w,e)),k.trigger("stickyHeadersInit")}},remove:function(d,e,f){var g=e.namespace+"stickyheaders ";e.$table.removeClass("hasStickyHeaders").unbind("pagerComplete filterEnd stickyHeadersUpdate ".split(" ").join(g).replace(/\s+/g," ")).next("."+c.css.stickyWrap).remove(),f.$sticky&&f.$sticky.length&&f.$sticky.remove(),a(b).add(f.stickyHeaders_xScroll).add(f.stickyHeaders_yScroll).add(f.stickyHeaders_attachTo).unbind("scroll resize ".split(" ").join(g).replace(/\s+/g," ")),c.addHeaderResizeEvent(d,!1)}})}(jQuery,window),function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{resizableContainer:"tablesorter-resizable-container",resizableHandle:"tablesorter-resizable-handle",resizableNoSelect:"tablesorter-disableSelection",resizableStorage:"tablesorter-resizable"}),a(function(){var b="";a(b).appendTo("body")}),c.resizable={init:function(b,d){if(!b.$table.hasClass("hasResizable")){b.$table.addClass("hasResizable"),c.resizableReset(b.table,!0),d.resizable_={$wrap:b.$table.parent(),mouseXPosition:0,$target:null,$next:null,overflow:"auto"===b.$table.parent().css("overflow"),fullWidth:Math.abs(b.$table.parent().width()-b.$table.width())<20,storedSizes:[]};var e,f,g,h,i=parseInt(b.$table.css("margin-top"),10);for(d.resizable_.storedSizes=h=(c.storage&&d.resizable!==!1?c.storage(b.table,c.css.resizableStorage):[])||[],c.resizable.setWidths(b,d,h),d.$resizable_container=a('
    ').css({top:i}).insertBefore(b.$table),g=0;g').appendTo(d.$resizable_container).attr({"data-column":g,unselectable:"on"}).data("header",f).bind("selectstart",!1);b.$table.one("tablesorter-initialized",function(){c.resizable.setHandlePosition(b,d),c.resizable.bindings(this.config,this.config.widgetOptions)})}},setWidth:function(a,b){a.css({width:b,"min-width":"","max-width":""})},setWidths:function(b,d,e){var f,g=a(b.namespace+"_extra_headers"),h=b.$table.children("colgroup").children("col");if(e=e||d.resizable_.storedSizes||[],e.length){for(f=0;ff||f===h&&d.resizable_addLastColumn)&&c.css({display:"inline-block",height:g,left:j.position().left-e+j.outerWidth()-i}):c.hide())})},toggleTextSelection:function(b,d){var e=b.namespace+"tsresize";b.widgetOptions.resizable_.disabled=d,a("body").toggleClass(c.css.resizableNoSelect,d),d?a("body").attr("unselectable","on").bind("selectstart"+e,!1):a("body").removeAttr("unselectable").unbind("selectstart"+e)},bindings:function(d,e){var f=d.namespace+"tsresize";e.$resizable_container.children().bind("mousedown",function(b){var f,g,h=e.resizable_,i=a(d.namespace+"_extra_headers"),j=a(b.target).data("header");for(f=parseInt(j.attr("data-column"),10),h.$target=j=j.add(i.filter('[data-column="'+f+'"]')),h.target=f,h.$next=b.shiftKey||e.resizable_targetLast?j.parent().children().not(".resizable-false").filter(":last"):j.nextAll(":not(.resizable-false)").eq(0),f=parseInt(h.$next.attr("data-column"),10),h.$next=h.$next.add(i.filter('[data-column="'+f+'"]')),h.next=f,h.mouseXPosition=b.pageX,h.storedSizes=[],f=0;f0?d.sortList=k:c.hasInitialized&&k&&k.length>0&&i.trigger("sorton",[k]))},remove:function(a,c){c.$table.removeClass("hasSaveSort"),b.storage&&b.storage(a,"tablesorter-savesort","")}})}(jQuery),a.tablesorter}); \ No newline at end of file diff --git a/dist/js/parsers/parser-date-extract.min.js b/dist/js/parsers/parser-date-extract.min.js new file mode 100644 index 0000000..240dc3e --- /dev/null +++ b/dist/js/parsers/parser-date-extract.min.js @@ -0,0 +1,6 @@ +/*! Parser: Extract out date - updated 10/26/2014 (v2.18.0) */ +!function(a){"use strict";var b={usLong:/[A-Z]{3,10}\.?\s+\d{1,2},?\s+(?:\d{4})(?:\s+\d{1,2}:\d{2}(?::\d{2})?(?:\s+[AP]M)?)?/i,mdy:/(\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i,dmy:/(\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i,dmyreplace:/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,ymd:/(\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i,ymdreplace:/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/};/*! extract US Long Date */ +a.tablesorter.addParser({id:"extractUSLongDate",is:function(){return!1},format:function(a){var c,d=a?a.match(b.usLong):a;return d?(c=new Date(d[0]),c instanceof Date&&isFinite(c)?c.getTime():a):a},type:"numeric"}),/*! extract MMDDYYYY */ +a.tablesorter.addParser({id:"extractMMDDYYYY",is:function(){return!1},format:function(a){var c,d=a?a.replace(/\s+/g," ").replace(/[\-.,]/g,"/").match(b.mdy):a;return d?(c=new Date(d[0]),c instanceof Date&&isFinite(c)?c.getTime():a):a},type:"numeric"}),/*! extract DDMMYYYY */ +a.tablesorter.addParser({id:"extractDDMMYYYY",is:function(){return!1},format:function(a){var c,d=a?a.replace(/\s+/g," ").replace(/[\-.,]/g,"/").match(b.dmy):a;return d?(c=new Date(d[0].replace(b.dmyreplace,"$2/$1/$3")),c instanceof Date&&isFinite(c)?c.getTime():a):a},type:"numeric"}),/*! extract YYYYMMDD */ +a.tablesorter.addParser({id:"extractYYYYMMDD",is:function(){return!1},format:function(a){var c,d=a?a.replace(/\s+/g," ").replace(/[\-.,]/g,"/").match(b.ymd):a;return d?(c=new Date(d[0].replace(b.ymdreplace,"$2/$3/$1")),c instanceof Date&&isFinite(c)?c.getTime():a):a},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-date-iso8601.min.js b/dist/js/parsers/parser-date-iso8601.min.js new file mode 100644 index 0000000..35e9361 --- /dev/null +++ b/dist/js/parsers/parser-date-iso8601.min.js @@ -0,0 +1,2 @@ +/*! Parser: ISO-8601 date - updated 10/26/2014 (v2.18.0) */ +!function(a){"use strict";var b=/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/;a.tablesorter.addParser({id:"iso8601date",is:function(a){return a?a.match(b):!1},format:function(a){var c=a?a.match(b):a;if(c){var d=new Date(c[1],0,1);return c[3]&&d.setMonth(c[3]-1),c[5]&&d.setDate(c[5]),c[7]&&d.setHours(c[7]),c[8]&&d.setMinutes(c[8]),c[10]&&d.setSeconds(c[10]),c[12]&&d.setMilliseconds(1e3*Number("0."+c[12])),d.getTime()}return a},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-date-month.min.js b/dist/js/parsers/parser-date-month.min.js new file mode 100644 index 0000000..45c1ec5 --- /dev/null +++ b/dist/js/parsers/parser-date-month.min.js @@ -0,0 +1,2 @@ +/*! Parser: Month - updated 10/26/2014 (v2.18.0) */ +!function(a){"use strict";var b=a.tablesorter;b.dates=a.extend({},b.dates,{monthCased:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}),b.dates.monthLower=b.dates.monthCased.join(",").toLocaleLowerCase().split(","),b.addParser({id:"month",is:function(){return!1},format:function(c,d){if(c){var e=-1,f=d.config,g=f.ignoreCase?c.toLocaleLowerCase():c;return a.each(b.dates["month"+(f.ignoreCase?"Lower":"Cased")],function(a,b){return 0>e&&g.match(b)?(e=a,!1):void 0}),0>e?c:e}return c},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-date-range.min.js b/dist/js/parsers/parser-date-range.min.js new file mode 100644 index 0000000..5eebe07 --- /dev/null +++ b/dist/js/parsers/parser-date-range.min.js @@ -0,0 +1,5 @@ +/*! Parser: date ranges - updated 2/23/2015 (v2.21.0) */ +!function(a){"use strict";var b={mdy:/(\d{1,2}[-\s]\d{1,2}[-\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/gi,dmy:/(\d{1,2}[-\s]\d{1,2}[-\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/gi,dmyreplace:/(\d{1,2})[-\s](\d{1,2})[-\s](\d{4})/,ymd:/(\d{4}[-\s]\d{1,2}[-\s]\d{1,2}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/gi,ymdreplace:/(\d{4})[-\s](\d{1,2})[-\s](\d{1,2})/};/*! date-range MMDDYYYY */ +a.tablesorter.addParser({id:"date-range-mdy",is:function(){return!1},format:function(a){var c,d,e,f,g=[];if(d=a.replace(/\s+/g," ").replace(/[\/\-.,]/g,"-").match(b.mdy),f=d&&d.length){for(e=0;f>e;e++)c=new Date(d[e]),g.push(c instanceof Date&&isFinite(c)?c.getTime():d[e]);return g.sort().join(" - ")}return a},type:"text"}),/*! date-range DDMMYYYY */ +a.tablesorter.addParser({id:"date-range-dmy",is:function(){return!1},format:function(a){var c,d,e,f,g=[];if(d=a.replace(/\s+/g," ").replace(/[\/\-.,]/g,"-").match(b.dmy),f=d&&d.length){for(e=0;f>e;e++)c=new Date((""+d[e]).replace(b.dmyreplace,"$2/$1/$3")),g.push(c instanceof Date&&isFinite(c)?c.getTime():d[e]);return g.sort().join(" - ")}return a},type:"text"}),/*! date-range DDMMYYYY */ +a.tablesorter.addParser({id:"date-range-ymd",is:function(){return!1},format:function(a){var c,d,e,f,g=[];if(d=a.replace(/\s+/g," ").replace(/[\/\-.,]/g,"-").match(b.ymd),f=d&&d.length){for(e=0;f>e;e++)c=new Date((""+d[e]).replace(b.ymdreplace,"$2/$3/$1")),g.push(c instanceof Date&&isFinite(c)?c.getTime():d[e]);return g.sort().join(" - ")}return a},type:"text"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-date-two-digit-year.min.js b/dist/js/parsers/parser-date-two-digit-year.min.js new file mode 100644 index 0000000..27f547f --- /dev/null +++ b/dist/js/parsers/parser-date-two-digit-year.min.js @@ -0,0 +1,2 @@ +/*! Parser: two digit year - updated 10/26/2014 (v2.18.0) */ +!function(a){"use strict";var b=50,c=a.tablesorter,d=(new Date).getFullYear();c.dates=a.extend({},c.dates,{regxxxxyy:/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{2})/,regyyxxxx:/(\d{2})[\/\s](\d{1,2})[\/\s](\d{1,2})/}),c.formatDate=function(a,c,e,f){if(a){var g,h,i=a.replace(/\s+/g," ").replace(/[-.,]/g,"/").replace(c,e),j=new Date(i);if(j instanceof Date&&isFinite(j)){for(g=j.getFullYear(),h=f&&f.config.dateRange||b;d-g>h;)g+=100;return j.setFullYear(g)}}return a},a.tablesorter.addParser({id:"ddmmyy",is:function(){return!1},format:function(a,b){return c.formatDate(a,c.dates.regxxxxyy,"$2/$1/19$3",b)},type:"numeric"}),a.tablesorter.addParser({id:"mmddyy",is:function(){return!1},format:function(a,b){return c.formatDate(a,c.dates.regxxxxyy,"$1/$2/19$3",b)},type:"numeric"}),a.tablesorter.addParser({id:"yymmdd",is:function(){return!1},format:function(a,b){return c.formatDate(a,c.dates.regyyxxxx,"$2/$3/19$1",b)},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-date-weekday.min.js b/dist/js/parsers/parser-date-weekday.min.js new file mode 100644 index 0000000..7bfb15f --- /dev/null +++ b/dist/js/parsers/parser-date-weekday.min.js @@ -0,0 +1,2 @@ +/*! Parser: weekday - updated 10/26/2014 (v2.18.0) */ +!function(a){"use strict";var b=a.tablesorter;b.dates=a.extend({},b.dates,{weekdayCased:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]}),b.dates.weekdayLower=b.dates.weekdayCased.join(",").toLocaleLowerCase().split(","),b.addParser({id:"weekday",is:function(){return!1},format:function(c,d){if(c){var e=-1,f=d.config;return c=f.ignoreCase?c.toLocaleLowerCase():c,a.each(b.dates["weekday"+(f.ignoreCase?"Lower":"Cased")],function(a,b){return 0>e&&c.match(b)?(e=a,!1):void 0}),0>e?c:e}return c},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-date.min.js b/dist/js/parsers/parser-date.min.js new file mode 100644 index 0000000..9f345a9 --- /dev/null +++ b/dist/js/parsers/parser-date.min.js @@ -0,0 +1,4 @@ +/*! Parser: dates - updated 10/26/2014 (v2.18.0) */ +!function(a){"use strict";/*! Sugar (http://sugarjs.com/dates#comparing_dates) */ +a.tablesorter.addParser({id:"sugar",is:function(){return!1},format:function(a){var b=Date.create?Date.create(a):a?new Date(a):a;return b instanceof Date&&isFinite(b)?b.getTime():a},type:"numeric"}),/*! Datejs (http://www.datejs.com/) */ +a.tablesorter.addParser({id:"datejs",is:function(){return!1},format:function(a){var b=Date.parse?Date.parse(a):a?new Date(a):a;return b instanceof Date&&isFinite(b)?b.getTime():a},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-duration.min.js b/dist/js/parsers/parser-duration.min.js new file mode 100644 index 0000000..29efa5c --- /dev/null +++ b/dist/js/parsers/parser-duration.min.js @@ -0,0 +1,3 @@ +/*! Parser: duration & countdown - updated 2/7/2015 (v2.19.0) */ +!function(a){"use strict";a.tablesorter.addParser({id:"duration",is:function(){return!1},format:function(a,b){var c,d,e=b.config,f="",g="",h=e.durationLength||4,i=new Array(h+1).join("0"),j=(e.durationLabels||"(?:years|year|y),(?:days|day|d),(?:hours|hour|h),(?:minutes|minute|min|m),(?:seconds|second|sec|s)").split(/\s*,\s*/),k=j.length;if(!e.durationRegex){for(c=0;k>c;c++)f+="(?:(\\d+)\\s*"+j[c]+"\\s*)?";e.durationRegex=new RegExp(f,"i")}for(d=(e.usNumberFormat?a.replace(/,/g,""):a.replace(/(\d)(?:\.|\s*)(\d)/g,"$1$2")).match(e.durationRegex),c=1;k+1>c;c++)g+=(i+(d[c]||0)).slice(-h);return g},type:"text"}),/*! Countdown parser ( hh:mm:ss ) */ +a.tablesorter.addParser({id:"countdown",is:function(){return!1},format:function(a,b){for(var c=b.config.durationLength||4,d=new Array(c+1).join("0"),e=a.split(/\s*:\s*/),f=e.length,g=[];f;)g.push((d+(e[--f]||0)).slice(-c));return g.length?g.reverse().join(""):a},type:"text"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-feet-inch-fraction.min.js b/dist/js/parsers/parser-feet-inch-fraction.min.js new file mode 100644 index 0000000..b471e51 --- /dev/null +++ b/dist/js/parsers/parser-feet-inch-fraction.min.js @@ -0,0 +1,2 @@ +/*! Parser: distance */ +!function(a){"use strict";var b=a.tablesorter;b.symbolRegex=/[\u215b\u215c\u215d\u215e\u00bc\u00bd\u00be]/g,b.processFractions=function(c,d){if(c){var e,f=0;c=a.trim(c.replace(/\"/,"")),/\s/.test(c)&&(f=b.formatFloat(c.split(" ")[0],d),c=a.trim(c.substring(c.indexOf(" "),c.length))),/\//g.test(c)?(e=c.split("/"),c=f+parseInt(e[0],10)/parseInt(e[1]||1,10)):b.symbolRegex.test(c)&&(c=f+c.replace(b.symbolRegex,function(a){return{"⅛":".125","⅜":".375","⅝":".625","⅞":".875","¼":".25","½":".5","¾":".75"}[a]}))}return c||0},a.tablesorter.addParser({id:"distance",is:function(){return!1},format:function(a,c){if(""===a)return"";var d=/^\s*\S*(\s+\S+)?\s*\'/.test(a)?a.split("'"):[0,a],e=b.processFractions(d[0],c),f=b.processFractions(d[1],c);return/[\'\"]/.test(a)?parseFloat(e)+(parseFloat(f)/12||0):parseFloat(e)+parseFloat(f)},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-file-type.min.js b/dist/js/parsers/parser-file-type.min.js new file mode 100644 index 0000000..66ef090 --- /dev/null +++ b/dist/js/parsers/parser-file-type.min.js @@ -0,0 +1,2 @@ +/*! Parser: filetype */ +!function(a){"use strict";a.tablesorter.fileTypes={separator:"|",equivalents:{"3D Image":"3dm|3ds|dwg|max|obj",Audio:"aif|aac|ape|flac|la|m4a|mid|midi|mp2|mp3|ogg|ra|raw|rm|wav|wma",Compressed:"7z|bin|cab|cbr|gz|gzip|iso|lha|lz|rar|tar|tgz|zip|zipx|zoo",Database:"csv|dat|db|dbf|json|ldb|mdb|myd|pdb|sql|tsv|wdb|wmdb|xlr|xls|xlsx|xml",Development:"asm|c|class|cls|cpp|cc|cs|cxx|cbp|cs|dba|fla|h|java|lua|pl|py|pyc|pyo|sh|sln|r|rb|vb",Document:"doc|docx|odt|ott|pages|pdf|rtf|tex|wpd|wps|wrd|wri",Executable:"apk|app|com|exe|gadget|lnk|msi",Fonts:"eot|fnt|fon|otf|ttf|woff",Icons:"ani|cur|icns|ico",Images:"bmp|gif|jpg|jpeg|jpe|jp2|pic|png|psd|tga|tif|tiff|wmf|webp",Presentation:"pps|ppt",Published:"chp|epub|lit|pub|ppp|fm|mobi",Script:"as|bat|cgi|cmd|jar|js|lua|scpt|scptd|sh|vbs|vb|wsf",Styles:"css|less|sass",Text:"info|log|md|markdown|nfo|tex|text|txt",Vectors:"awg|ai|eps|cdr|ps|svg",Video:"asf|avi|flv|m4v|mkv|mov|mp4|mpe|mpeg|mpg|ogg|rm|rv|swf|vob|wmv",Web:"asp|aspx|cer|cfm|htm|html|php|url|xhtml"}},a.tablesorter.addParser({id:"filetype",is:function(){return!1},format:function(b,c){var d,e=c.config,f=e.widgetOptions,g=b.lastIndexOf("."),h=a.tablesorter.fileTypes.separator,i=a.tablesorter.fileTypes.matching,j=a.tablesorter.fileTypes.equivalents;if(i||(d=[],a.each(j,function(a,b){d.push(b)}),i=a.tablesorter.fileTypes.matching=h+d.join(h)+h),g>=0&&(d=h+b.substring(g+1,b.length)+h,i.indexOf(d)>=0))for(g in j)if((h+j[g]+h).indexOf(d)>=0)return g+(f.group_separator?f.group_separator:"-")+b;return b},type:"text"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-globalize.min.js b/dist/js/parsers/parser-globalize.min.js new file mode 100644 index 0000000..4b636f7 --- /dev/null +++ b/dist/js/parsers/parser-globalize.min.js @@ -0,0 +1,4 @@ +/*! Parser: jQuery Globalize - updated 5/17/2015 (v2.22.0) */ +!function(a){"use strict";/*! jQuery Globalize date parser (https://github.com/jquery/globalize#date-module) */ +a.tablesorter.addParser({id:"globalize-date",is:function(){return!1},format:function(a,b,c,d){var e=b.config,f=e.globalize&&(e.globalize[d]||e.globalize)||{},g=Globalize&&Globalize.dateParser?Globalize.dateParser(f)(a):a?new Date(a):a;return g instanceof Date&&isFinite(g)?g.getTime():a},type:"numeric"}),/*! jQuery Globalize number parser (https://github.com/jquery/globalize#number-module) */ +a.tablesorter.addParser({id:"globalize-number",is:function(){return!1},format:function(b,c,d,e){var f=c.config,g=f.globalize&&(f.globalize[e]||f.globalize)||{},h=Globalize&&Globalize.numberParser?Globalize.numberParser(g)(b):b?a.tablesorter.formatFloat((b||"").replace(/[^\w,. \-()]/g,""),c):b;return b&&"number"==typeof h?h:b},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-ignore-articles.min.js b/dist/js/parsers/parser-ignore-articles.min.js new file mode 100644 index 0000000..41771a1 --- /dev/null +++ b/dist/js/parsers/parser-ignore-articles.min.js @@ -0,0 +1,2 @@ +/*! Parser: ignoreArticles - updated 9/15/2014 (v2.17.8) */ +!function(a){"use strict";var b=a.tablesorter;b.ignoreArticles={en:"the, a, an",de:"der, die, das, des, dem, den, ein, eine, einer, eines, einem, einen",nl:"de, het, de, een",es:"el, la, lo, los, las, un, una, unos, unas",pt:"o, a, os, as, um, uma, uns, umas",fr:"le, la, l'_, les, un, une, des",it:"il, lo, la, l'_, i, gli, le, un', uno, una, un",hu:"a, az, egy"},b.addParser({id:"ignoreArticles",is:function(){return!1},format:function(c,d,e,f){var g,h,i,j=d.config,k=c||"";return j.headers&&j.headers[f]&&j.headers[f].ignoreArticlesRegex||(j.headers||(j.headers={}),j.headers[f]||(j.headers[f]={}),i=b.getData(j.$headers.eq(f),b.getColumnData(d,j.headers,f),"ignoreArticles"),g=(b.ignoreArticles[i]||"the, a, an")+"",j.headers[f].ignoreArticlesRegex=new RegExp("^("+a.trim(g.split(/\s*\,\s*/).join("\\s|")+"\\s").replace("_\\s","")+")","i"),h=b.getData(j.$headers.eq(f),b.getColumnData(d,j.headers,f),"ignoreArticlesExcept"),j.headers[f].ignoreArticlesRegex2=""!==h?new RegExp("^("+h.replace(/\s/g,"\\s")+")","i"):""),g=j.headers[f].ignoreArticlesRegex,!g.test(k)||(h=j.headers[f].ignoreArticlesRegex2,h&&h.test(k))?k:k.replace(g,"")},type:"text"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-image.min.js b/dist/js/parsers/parser-image.min.js new file mode 100644 index 0000000..624029b --- /dev/null +++ b/dist/js/parsers/parser-image.min.js @@ -0,0 +1,2 @@ +/*! Parser: image - new 7/17/2014 (v2.17.5) */ +!function(a){"use strict";a.tablesorter.addParser({id:"image",is:function(){return!1},format:function(b,c,d){return a(d).find("img").attr(c.config.imgAttr||"alt")||b},parsed:!0,type:"text"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-input-select.min.js b/dist/js/parsers/parser-input-select.min.js new file mode 100644 index 0000000..82a7eba --- /dev/null +++ b/dist/js/parsers/parser-input-select.min.js @@ -0,0 +1,2 @@ +/*! Parser: input & select - updated 5/17/2015 (v2.22.0) */ +!function(a){"use strict";var b=function(a,b,c){};a.tablesorter.addParser({id:"inputs",is:function(){return!1},format:function(b,c,d){var e=a(d).find("input");return e.length?e.val():b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"inputs-numeric",is:function(){return!1},format:function(b,c,d){var e=a(d).find("input"),f=e.length?e.val():b,g=a.tablesorter.formatFloat((f||"").replace(/[^\w,. \-()]/g,""),c);return b&&"number"==typeof g?g:b?a.trim(b&&c.config.ignoreCase?b.toLocaleLowerCase():b):b},parsed:!0,type:"numeric"}),a.tablesorter.addParser({id:"checkbox",is:function(){return!1},format:function(b,c,d,e){var f=a(d),g=c.config.widgetOptions,h=c.config.checkboxClass||"checked",i=g.group_checkbox?g.group_checkbox:["checked","unchecked"],j=f.find('input[type="checkbox"]'),k=j.length?j[0].checked:"";return f.closest("tr").toggleClass(h+" "+h+"-"+e,k),j.length?i[k?0:1]:b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"select",is:function(){return!1},format:function(b,c,d){var e=a(d).find("select");return e.length?e.val():b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"select-text",is:function(){return!1},format:function(b,c,d){var e=a(d).find("select");return e.length?e.find("option:selected").text()||"":b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"textarea",is:function(){return!1},format:function(b,c,d){var e=a(d).find("textarea");return e.length?e.val():b},parsed:!0,type:"text"}),a(function(){a("table").on("tablesorter-initialized updateComplete",function(){var c=".parser-forms",d=function(b){b&&a(":focus").blur()};a(this).children("tbody").off(c).on("mouseleave"+c,function(a){d("TBODY"===a.target.nodeName)}).on("focus"+c,"select, input, textarea",function(){a(this).data("ts-original-value",this.value)}).on("blur"+c,"input, textarea",function(){this.value=a(this).data("ts-original-value")}).on("change keyup ".split(" ").join(c+" "),"select, input, textarea",function(c){if(27===c.which)return void(this.value=a(this).data("ts-original-value"));if("change"===c.type||"keyup"===c.type&&13===c.which&&("INPUT"===c.target.nodeName||"TEXTAREA"===c.target.nodeName&&c.altKey)){var d,e=a(c.target),f=e.closest("td"),g=f.closest("table"),h=f[0].cellIndex,i=g[0].config||!1,j=i&&i.$headerIndexed&&i.$headerIndexed[h]||[],k=e.val();if(j.length&&(j.hasClass("parser-false")||j.hasClass("sorter-false")&&j.hasClass("filter-false")))return;(k!==e.data("ts-original-value")||"checkbox"===c.target.type)&&(e.data("ts-original-value",k),g.trigger("updateCell",[f,d,function(){b(c,g,e)}]))}})})})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-metric.min.js b/dist/js/parsers/parser-metric.min.js new file mode 100644 index 0000000..93a376e --- /dev/null +++ b/dist/js/parsers/parser-metric.min.js @@ -0,0 +1,2 @@ +/*! Parser: metric */ +!function(a){"use strict";var b={"Y|Yotta|yotta":[1e24,Math.pow(1024,8)],"Z|Zetta|zetta":[1e21,Math.pow(1024,7)],"E|Exa|exa":[1e18,Math.pow(1024,6)],"P|Peta|peta":[1e15,Math.pow(1024,5)],"T|Tera|tera":[1e12,Math.pow(1024,4)],"G|Giga|giga":[1e9,Math.pow(1024,3)],"M|Mega|mega":[1e6,Math.pow(1024,2)],"k|Kilo|kilo":[1e3,1024],"h|hecto":[100,100],"da|deka":[10,10],"d|deci":[.1,.1],"c|centi":[.01,.01],"m|milli":[.001,.001],"µ|micro":[1e-6,1e-6],"n|nano":[1e-9,1e-9],"p|pico":[1e-12,1e-12],"f|femto":[1e-15,1e-15],"a|atto":[1e-18,1e-18],"z|zepto":[1e-21,1e-21],"y|yocto":[1e-24,1e-24]},c="(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(",d="(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)(";a.tablesorter.addParser({id:"metric",is:function(){return!1},format:function(e,f,g,h){var i,j,k="m|meter",l=a.tablesorter.formatFloat(e.replace(/[^\w,. \-()]/g,""),f),m=f.config.$headerIndexed[h],n=m.data("metric");if(n||(j=(m.attr("data-metric-name")||k).split("|"),n=[j[1]||j[0].substring(1),j[0]],n[2]=new RegExp(c+n[0]+"|"+n[1]+")"),n[3]=new RegExp(d+n[1]+")"),m.data("metric",n)),j=e.match(n[2])||e.match(n[3]))for(k in b)if(j[3].match(k))return i=/^[b|bit|byte|o|octet]/.test(j[4])?1:0,l*b[k][i];return l},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-named-numbers.min.js b/dist/js/parsers/parser-named-numbers.min.js new file mode 100644 index 0000000..096a772 --- /dev/null +++ b/dist/js/parsers/parser-named-numbers.min.js @@ -0,0 +1,2 @@ +/*! Parser: namedNumbers - updated 10/26/2014 (v2.18.0) */ +!function(a){"use strict";var b,c,d={negative:["negative","minus"],numbers:{zero:0,one:1,two:2,three:3,four:4,five:5,six:6,seven:7,eight:8,nine:9,ten:10,eleven:11,twelve:12,thirteen:13,fourteen:14,fifteen:15,sixteen:16,seventeen:17,eighteen:18,nineteen:19,twenty:20,thirty:30,forty:40,fourty:40,fifty:50,sixty:60,seventy:70,eighty:80,ninety:90},hundred:"hundred",powers:{thousand:1e3,million:1e6,billion:1e9,trillion:1e12,quadrillion:1e15,quintillion:1e18,sextillion:1e21,septillion:1e24,octillion:1e27,nonillion:1e30,decillion:1e33,undecillion:1e36,duodecillion:1e39,tredecillion:1e42,quattuordecillion:1e45,quindecillion:1e48,sexdecillion:1e51,septendecillion:1e54,octodecillion:1e57,novemdecillion:1e60,vigintillion:1e63,unvigintillion:1e66,duovigintillion:1e69,trevigintillion:1e72,quattuorvigintillion:1e75,quinvigintillion:1e78,sexvigintillion:1e81,septenvigintillion:1e84,octovigintillion:1e87,novemvigintillion:1e90,trigintillion:1e93,untrigintillion:1e96,duotrigintillion:1e99,googl:1e100}},e=new RegExp("("+d.negative.join("|")+")"),f=function(e,f){var g=e.replace(/[,."']/g,""),h=a.tablesorter.formatFloat(e||"",f),i=d.powers.hasOwnProperty(g)?d.powers[g]:null;h="number"==typeof h?h:d.numbers.hasOwnProperty(g)?d.numbers[g]:null,null!==h?c+=h:g===d.hundred?c*=100:null!==i&&(b+=c*i,c=0)};a.tablesorter.addParser({id:"namedNumbers",is:function(){return!1},format:function(g,h){b=0,c=0;var i,j=(g||"").split(/[\s-]+/),k=j.length;for(i=0;k>i;i++)f(j[i].toLowerCase(),h);return b=(b+c)*(g.match(e)?-1:1),b||d.numbers.hasOwnProperty(g)?b:a.tablesorter.formatFloat(g||"",h)},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-network.min.js b/dist/js/parsers/parser-network.min.js new file mode 100644 index 0000000..ff4a74a --- /dev/null +++ b/dist/js/parsers/parser-network.min.js @@ -0,0 +1,5 @@ +/*! Parser: network - updated 5/17/2015 (v2.22.0) */ +!function(a){"use strict";var b,c,d=a.tablesorter;/*! IPv6 Address parser (WIP) */ +a.extend(d.regex,{},{ipv4Validate:/((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})/,ipv4Extract:/([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/,ipv6Validate:/^\s*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/i}),d.addParser({id:"ipv6Address",is:function(a){return d.regex.ipv6Validate.test(a)},format:function(a,b){var c,e,f,g,h,i=b?"boolean"==typeof b?b:b&&b.config.ipv6HexFormat||!1:!1,j="",k="",l=8;if(a=a.replace(/\s*/g,""),d.regex.ipv4Validate.test(a)){for(g=a.match(d.regex.ipv4Extract),e="",c=1;cc;c++)j+="0000:";j+=f[1]}for(g=j.split(":"),c=0;l>c;c++)g[c]=i?("0000"+g[c]).slice(-4):("00000"+(parseInt(g[c],16)||0)).slice(-5),k+=c!=l-1?g[c]+":":g[c];return i?k:k.replace(/:/g,"")},type:"numeric"}),c=function(a){return/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/.test(a)},b=function(a,b){var c,e=a?a.split("."):"",f="",g=e.length;for(c=0;g>c;c++)f+=("000"+e[c]).slice(-3);return a?d.formatFloat(f,b):a},/*! Parser: ipv4Address (a.k.a. ipAddress) */ +d.addParser({id:"ipAddress",is:c,format:b,type:"numeric"}),d.addParser({id:"ipv4Address",is:c,format:b,type:"numeric"}),/*! Parser: MAC address */ +d.addParser({id:"MAC",is:function(a){return!1},format:function(a){var b,c,d="",e=(a||"").replace(/[:.-]/g,"").match(/\w{2}/g);if(e){for(c=e.length,b=0;c>b;b++)d+=("000"+parseInt(e[b],16)).slice(-3);return d}return a},type:"numeric"})}(jQuery); \ No newline at end of file diff --git a/dist/js/parsers/parser-roman.min.js b/dist/js/parsers/parser-roman.min.js new file mode 100644 index 0000000..ee1fc7e --- /dev/null +++ b/dist/js/parsers/parser-roman.min.js @@ -0,0 +1,2 @@ +/*! Parser: roman - updated 6/28/MMXIV (v2.17.3) */ +!function(a){"use strict";var b=/^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/i,c=/\b([MCDLXVI]+\b)/gi,d={I:1,V:5,X:10,L:50,C:100,D:500,M:1e3};a.tablesorter.addParser({id:"roman",is:function(){return!1},format:function(a){var c,e=a.toUpperCase().split(""),f=0;if(!a||!b.test(a))return a;for(;e.length;)c=d[e.shift()],f+=c*(cg;g++){if(s=l.row?l.row[g]:l.normalized[g][c.columns].$row,m=s.find("td").eq(e.column).text().replace(/[ ]/g," "),n=(m.match(e.regex)||[]).length,n>0&&e.alignIndex>0)for(i=Math.min(e.alignIndex,n),h=0,k=0,j=0;h++j?k:j;else k=m.indexOf(e.align);k>=0?(t.push(m.substring(0,k)||""),u.push(m.substring(k,m.length)||"")):(t.push(n>=1&&e.alignIndex>=n?"":m||""),u.push(n>=1&&e.alignIndex>=n?m||"":""))}for(p=a.extend([],t).sort(function(a,b){return b.length-a.length})[0],q=a.extend([],u).sort(function(a,b){return b.length-a.length})[0],e.width=e.width||Math.floor(p.length/(p.length+q.length)*100)+e.adjust,p="min-width:"+e.width+"%",q="min-width:"+(100-e.width)+"%",f=0;fg;g++)r=a(d.alignChar_wrap).length?a(d.alignChar_wrap).html(e.align)[0].outerHTML:e.align,s=l.row?l.row[g]:l.normalized[g][c.columns].$row,j=u[g].slice(e.align.length),s.find("td").eq(e.column).html(''+t[g]+''+(j.length?r+j:"")+"");d.alignChar_initialized=!0}},remove:function(b,c,d){if(!a.isEmptyObject(c.cache)){var e,f,g,h,i,j;for(e=0;ef;f++)i=h.row?h.row[f]:h.normalized[f][c.columns].$row,j=i.find("td").eq(d),j.html(j.text().replace(/\s/g," "))}}},b.addWidget({id:"alignChar",priority:100,options:{alignChar_wrap:"",alignChar_charAttrib:"data-align-char",alignChar_indexAttrib:"data-align-index",alignChar_adjustAttrib:"data-align-adjust"},init:function(a,c,d,e){e.alignChar_initialized=!1,e.alignChar_savedVars=[],b.alignChar.init(a,d,e),d.$table.on("pagerEnd refreshAlign",function(){d.$headers.filter("["+e.alignChar_charAttrib+"]").each(function(){b.alignChar.remove(a,d,this.column)}),b.alignChar.init(a,d,e)})},format:function(a,b,c){c.alignChar_initialized||b.$table.trigger("refreshAlign")},remove:function(a,c,d,e){e||(c.$headers.filter("["+d.alignChar_charAttrib+"]").each(function(){b.alignChar.remove(a,c,this.column)}),d.alignChar_initialized=!1)}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-build-table.min.js b/dist/js/widgets/widget-build-table.min.js new file mode 100644 index 0000000..b982403 --- /dev/null +++ b/dist/js/widgets/widget-build-table.min.js @@ -0,0 +1,2 @@ +/*! Widget: Build Table - updated 3/26/2015 (v2.21.3) */ +!function(a){"use strict";var b=a.tablesorter=a.tablesorter||{},c=b.buildTable=function(d,e){var f="TABLE"===d.nodeName?a(d):a("").appendTo(d),g=f[0],h=e.widgetOptions=a.extend(!0,{},c.defaults,e.widgetOptions),i=h.build_processing,j=h.build_type,k=h.build_source||e.data,l=function(b){var d=a.type(b),f=b instanceof jQuery;if("function"==typeof i&&(b=i(b,h)),e.data=b,f||"string"===d){if(f||/<\s*\/tr\s*>/.test(b))return c.html(g,b,h);try{if(b=a.parseJSON(b||"null"))return c.object(g,b,h)}catch(k){}}return"array"===d||"string"===d||"array"===j||"csv"===j?c.csv(g,b,h):c.object(g,b,h)};return g.config=e,b.buildTable.hasOwnProperty(j)||""===j?void(k instanceof jQuery?l(a.trim(k.html())):k&&(k.hasOwnProperty("url")||"json"===j)?a.ajax(h.build_source).done(function(a){l(a)}).fail(function(a,c,d){e.debug&&b.log("aborting build table widget, failed ajax load"),f.html('")}):l(k)):(e.debug&&b.log("aborting build table widget, incorrect build type"),!1)};c.defaults={build_type:"",build_source:"",build_processing:null,build_complete:"tablesorter-build-complete",build_headers:{rows:1,classes:[],text:[],widths:[]},build_footers:{rows:1,classes:[],text:[]},build_numbers:{addColumn:!1,sortable:!1},build_csvStartLine:0,build_csvSeparator:",",build_objectRowKey:"rows",build_objectCellKey:"cells",build_objectHeaderKey:"headers",build_objectFooterKey:"footers"},c.build={colgroup:function(b){var c="";return b&&b.length&&(c+="",a.each(b,function(a,b){c+=""}),c+=""),c},cell:function(b,c,d,e,f){var g,h,i=f?a(""):"",j=c.build_headers.classes,k=c.build_headers.widths;if(/string|number/.test(typeof b))h=a("<"+d+(j&&j[e]?' class="'+j[e]+'"':"")+">"+b+""),f&&k&&k[e]&&i.width(k[e]||"");else{h=a("<"+d+">");for(g in b)b.hasOwnProperty(g)&&("text"===g||"html"===g?h[g](b[g]):f&&"width"===g?i.width(b[g]||""):h.attr(g,b[g]))}return[h,i]},header:function(b,c){var d=c.build_headers.text,e=c.build_headers.classes,f=""+(c.build_numbers.addColumn?""+c.build_numbers.addColumn+"":"");return a.each(b,function(a,b){f+=/<\s*\/t(d|h)\s*>/.test(b)?b:""+(d&&d[a]?d[a]:b)+""}),f+""},rows:function(b,c,d,e,f,g){var h=g?"th":"td",i=""+(e.build_numbers.addColumn?"<"+h+">"+(g?"":f)+"":"");return a.each(b,function(a,b){i+=/<\s*\/t(d|h)\s*>/.test(b)?b:"<"+(g?h+(d&&d[a]?' class="'+d[a]+'"':""):h)+">"+(g&&c&&c.length&&c[a]?c[a]:b)+""}),i+""}},c.buildComplete=function(c,d){a(c).trigger(d.build_complete),b.setup(c,c.config)},c.array=function(a,b,d){return c.csv(a,b,d)},c.csv=function(b,d,e){var f,g,h,i="csv"===e.build_type||"string"==typeof d,j=a(b),k=i?d.replace("\r","").split("\n"):d,l=k.length,m=0,n=!1,o=e.build_headers.rows+(i?e.build_csvStartLine:0),p=e.build_footers.rows,q=0,r="",s=c.build.colgroup(e.build_headers.widths)+"";a.each(k,function(a,b){a>=l-p&&(n=!0),(i?a>=e.build_csvStartLine:!0)&&o>a?(g=i?c.splitCSV(b,e.build_csvSeparator):b,q=g.length,s+=c.build.header(g,e)):a>=o&&(a===o&&(s+=""),h=i?c.splitCSV(b,e.build_csvSeparator):b,n&&p>0&&(s+=(a===l-p?"":"")+(a===l?"":"")),h.length>1&&(m++,h.length!==q&&(r+="error on line "+a+": Item count ("+h.length+") does not match header count ("+q+") \n"),f=n?e.build_footers.classes:"",s+=c.build.rows(h,e.build_footers.text,f,e,m,n)))}),s+=p>0?"":"",r?j.html(r):(j.html(s),c.buildComplete(b,e))},c.splitCSV=function(b,c){var d,e,f=a.trim(b).split(c=c||",");for(d=f.length-1;d>=0;d--)'"'===f[d].replace(/\"\s+$/,'"').charAt(f[d].length-1)?(e=f[d].replace(/^\s+\"/,'"')).length>1&&'"'===e.charAt(0)?f[d]=f[d].replace(/^\s*"|"\s*$/g,"").replace(/""/g,'"'):d?f.splice(d-1,2,[f[d-1],f[d]].join(c)):f=f.shift().split(c).concat(f):f[d].replace(/""/g,'"');return f},c.html=function(b,d,e){var f=a(b);d instanceof jQuery?f.empty().append(d):f.html(d),c.buildComplete(b,e)},c.object=function(d,e,f){var g,h,i,j,k,l,m,n=d.config,o=f.build_objectHeaderKey,p=f.build_objectRowKey,q=e.hasOwnProperty(o)&&!a.isEmptyObject(e.kh)?e.kh:e.hasOwnProperty("headers")?e.headers:!1,r=e.hasOwnProperty(p)&&!a.isEmptyObject(e.kr)?e.kr:e.hasOwnProperty("rows")?e.rows:!1;return q&&r&&0!==q.length&&0!==r.length?(j=a(""),k=a("
    '+a.status+" "+c+"
    "),a.each(q,function(b,d){for(m=a("").appendTo(k.find("thead")),h=d.length,g=0;h>g;g++)i=c.build.cell(d[g],f,"th",g,0===b),i[0]&&i[0].length&&i[0].appendTo(m),0===b&&i[1]&&i[1].appendTo(j)}),j.find("col[style]").length&&k.prepend(j),l=a(""),a.each(r,function(b,d){var e;if(i="object"===a.type(d),i&&d.newTbody){l=a("").appendTo(k);for(e in d)d.hasOwnProperty(e)&&"newTbody"!==e&&l.attr(e,d[e])}else{if(0===b&&l.appendTo(k),m=a("").appendTo(l),i){for(e in d)d.hasOwnProperty(e)&&e!==f.build_objectCellKey&&m.attr(e,d[e]);d.hasOwnProperty(f.build_objectCellKey)&&(d=d.cells)}for(h=d.length,e=0;h>e;e++)j=c.build.cell(d[e],f,"td",e),j[0]&&j[0].length&&j[0].appendTo(m)}}),e.hasOwnProperty(f.build_objectFooterKey)&&(i=e[f.build_objectFooterKey],"clone"===i?(j=k.find("thead").html(),k.append(""+j+"")):(j=a("").appendTo(k),a.each(i,function(b,d){for(m=a("").appendTo(j),h=d.length,g=0;h>g;g++)l=c.build.cell(d[g],f,"th",g),l[0]&&l[0].length&&l[0].appendTo(m)}))),a(d).html(k.html()),void c.buildComplete(d,f)):(n.debug&&b.log("aborting build table widget, missing data for object build"),!1)},c.ajax=c.json=function(a,b,d){return c.object(a,b,d)}}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-chart.min.js b/dist/js/widgets/widget-chart.min.js new file mode 100644 index 0000000..b5bc747 --- /dev/null +++ b/dist/js/widgets/widget-chart.min.js @@ -0,0 +1 @@ +!function(a){"use strict";var b=a.tablesorter,c=[],d=[],e=[],f=[],g=[],h=[],i=[],j=[],k=b.chart={nonDigit:/[^\d,.\-()]/g,init:function(a,b){a.$table.off(b.chart_event).on(b.chart_event,function(){if(this.hasInitialized){var a=this.config;k.getCols(a,a.widgetOptions),k.getData(a,a.widgetOptions)}})},getCols:function(d,e){var f;for(c=[],h=[],j=[],f=0;f=0?j.push(e[f]):(g=i[f].getAttribute(c.textAttribute)||i[f].textContent||i.eq(f).text(),j.push(a.trim(g)));l.push(j)}}),l.sort(function(a,c){return 1===d.chart_sort[0][1]?b.sortNatural(c[d.chart_sort[0][0]],a[d.chart_sort[0][0]]):b.sortNatural(a[d.chart_sort[0][0]],c[d.chart_sort[0][0]])}),a.each(l,function(f,l){var m,n=0,o=[],p=l[d.chart_labelCol];o.push(""+p),a.each(l,function(e,f){var l;return e===d.chart_labelCol?(g.push(f),i.push({label:f}),!0):(m=!1,d.chart_useSelector&&b.hasWidget(c.table,"columnSelector")&&!c.selector.auto?c.selector.states[e]&&a.inArray(e,d.chart_ignoreColumns)<0&&(m=""+f):a.inArray(e,d.chart_ignoreColumns)<0&&(m=""+f),void(m!==!1&&(/s/i.test(""+d.chart_layout[o.length])?(o.push(m),h[n].data.push(m),j[n].data.push(m)):(l=b.formatFloat(m.replace(k.nonDigit,""),c.table),l=isNaN(l)?m:l,o.push(l),h[n].data.push(l),j[n].data.push({value:l})),n++)))}),e.push(o)})},remove:function(a,b){a.$table.off(b.chart_event)}};b.addWidget({id:"chart",options:{chart_incRows:"filtered",chart_useSelector:!1,chart_ignoreColumns:[],chart_parsed:[],chart_layout:{0:"string"},chart_labelCol:0,chart_sort:[[0,0]],chart_event:"chartData"},init:function(a,b,c,d){k.init(c,d)},remove:function(a,b,c){k.remove(b,c)}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-columnSelector.min.js b/dist/js/widgets/widget-columnSelector.min.js new file mode 100644 index 0000000..f407114 --- /dev/null +++ b/dist/js/widgets/widget-columnSelector.min.js @@ -0,0 +1 @@ +!function(a){"use strict";var b=a.tablesorter,c=".tscolsel",d=b.columnSelector={queryAll:"@media only all { [columns] { display: none; } } ",queryBreak:"@media all and (min-width: [size]) { [columns] { display: table-cell; } } ",init:function(e,f,g){var h,i;return h=a(g.columnSelector_layout),h.find("input").add(h.filter("input")).length?(f.$table.addClass(f.namespace.slice(1)+"columnselector"),i=f.selector={$container:a(g.columnSelector_container||"
    ")},i.$style=a("").prop("disabled",!0).appendTo("head"),i.$breakpoints=a("").prop("disabled",!0).appendTo("head"),i.isInitializing=!0,d.setupSelector(e,f,g),g.columnSelector_mediaquery&&d.setupBreakpoints(f,g),i.isInitializing=!1,i.$container.length?d.updateCols(f,g):f.debug&&b.log("ColumnSelector: >> container not found"),void f.$table.off("refreshColumnSelector"+c).on("refreshColumnSelector"+c,function(b,c){var e,f=a.isArray(c),g=this.config,h=g.widgetOptions;if(c&&g.selector.$container.length){if(f)for(a.each(c,function(a,b){c[a]=parseInt(b,10)}),e=0;e=0);d.updateAuto(g,h,i.$container.find('input[data-column="auto"]').prop("checked",!f))}else d.updateBreakpoints(g,h),d.updateCols(g,h)})):void(f.debug&&b.log("ColumnSelector: >> ERROR: Column Selector aborting, no input found in the layout! ***"))},setupSelector:function(c,e,f){var g,h=e.selector,i=h.$container,j=f.columnSelector_saveColumns&&b.storage,k=j?b.storage(c,"tablesorter-columnSelector"):[],l=j?b.storage(c,"tablesorter-columnSelector-auto"):{};h.auto=a.isEmptyObject(l)||"boolean"!==a.type(l.auto)?f.columnSelector_mediaqueryState:l.auto,h.states=[],h.$column=[],h.$wrapper=[],h.$checkbox=[],e.$table.children("thead").find("tr:first th",c).each(function(){var c=a(this),j=c.attr(f.columnSelector_priority)||1,l=c.attr("data-column"),m=b.getData(this,e.headers[l],"columnSelector");return isNaN(j)&&j.length>0||"disable"===m||f.columnSelector_columns[l]&&"disable"===f.columnSelector_columns[l]?!0:(h.states[l]=k&&"undefined"!=typeof k[l]?k[l]:"undefined"!=typeof f.columnSelector_columns[l]?f.columnSelector_columns[l]:"true"===m||"false"!==m,h.$column[l]=a(this),g=c.attr(f.columnSelector_name)||c.text(),void(i.length&&(h.$wrapper[l]=a(f.columnSelector_layout.replace(/\{name\}/g,g)).appendTo(i),h.$checkbox[l]=h.$wrapper[l].find("input").add(h.$wrapper[l].filter("input")).attr("data-column",l).toggleClass(f.columnSelector_cssChecked,h.states[l]).prop("checked",h.states[l]).on("change",function(){h.states[l]=this.checked,d.updateCols(e,f)}).change())))})},setupBreakpoints:function(b,e){var f=b.selector;e.columnSelector_mediaquery&&(f.lastIndex=-1,d.updateBreakpoints(b,e),b.$table.off("updateAll"+c).on("updateAll"+c,function(){d.updateBreakpoints(b,e),d.updateCols(b,e)})),f.$container.length&&(e.columnSelector_mediaquery&&(f.$auto=a(e.columnSelector_layout.replace(/\{name\}/g,e.columnSelector_mediaqueryName)).prependTo(f.$container),f.$auto.find("input").add(f.$auto.filter("input")).attr("data-column","auto").prop("checked",f.auto).toggleClass(e.columnSelector_cssChecked,f.auto).on("change",function(){d.updateAuto(b,e,a(this))}).change()),b.$table.off("update"+c).on("update"+c,function(){d.updateCols(b,e)}))},updateAuto:function(c,e,f){var g=c.selector;g.auto=f.prop("checked")||!1,a.each(g.$checkbox,function(a,b){b&&(b[0].disabled=g.auto,g.$wrapper[a].toggleClass("disabled",g.auto))}),e.columnSelector_mediaquery&&d.updateBreakpoints(c,e),d.updateCols(c,e),c.selector.$popup&&c.selector.$popup.find(".tablesorter-column-selector").html(g.$container.html()).find("input").each(function(){var b=a(this).attr("data-column");a(this).prop("checked","auto"===b?g.auto:g.states[b])}),e.columnSelector_saveColumns&&b.storage&&b.storage(c.$table[0],"tablesorter-columnSelector-auto",{auto:g.auto}),g.auto&&c.$table.trigger("columnUpdate")},updateBreakpoints:function(b,c){var e,f,g,h,i=b.selector,j=b.namespace+"columnselector",k=[],l="";if(c.columnSelector_mediaquery&&!i.auto)return i.$breakpoints.prop("disabled",!0),void i.$style.prop("disabled",!1);for(e=0;6>e;e++)g=[],b.$headers.filter("["+c.columnSelector_priority+"="+(e+1)+"]").each(function(){f=parseInt(a(this).attr("data-column"),10)+1,h=" col:nth-child("+f+")",g.push(j+h+","+j+"_extra_table"+h),h=" tr th:nth-child("+f+")",g.push(j+h+","+j+"_extra_table"+h),h=" tr td:nth-child("+f+")",g.push(j+h+","+j+"_extra_table"+h)}),g.length&&(k=k.concat(g),l+=d.queryBreak.replace(/\[size\]/g,c.columnSelector_breakpoints[e]).replace(/\[columns\]/g,g.join(",")));i.$style&&i.$style.prop("disabled",!0),k.length&&i.$breakpoints.prop("disabled",!1).html(d.queryAll.replace(/\[columns\]/g,k.join(","))+l)},updateCols:function(c,d){if(!(d.columnSelector_mediaquery&&c.selector.auto||c.selector.isInitializing)){var e,f,g=c.selector,h=[],i=c.namespace+"columnselector";g.$container.find("input[data-column]").filter('[data-column!="auto"]').each(function(){this.checked||(e=parseInt(a(this).attr("data-column"),10)+1,f=" col:nth-child("+e+")",h.push(i+f+","+i+"_extra_table"+f),f=" tr th:nth-child("+e+")",h.push(i+f+","+i+"_extra_table"+f),f=" tr td:nth-child("+e+")",h.push(i+f+","+i+"_extra_table"+f)),a(this).toggleClass(d.columnSelector_cssChecked,this.checked)}),d.columnSelector_mediaquery&&g.$breakpoints.prop("disabled",!0),g.$style&&g.$style.prop("disabled",!1).html(h.length?h.join(",")+" { display: none; }":""),d.columnSelector_saveColumns&&b.storage&&b.storage(c.$table[0],"tablesorter-columnSelector",g.states),c.$table.trigger("columnUpdate")}},attachTo:function(b,c){b=a(b)[0];var d,e,f,g=b.config,h=a(c);h.length&&g&&(h.find(".tablesorter-column-selector").length||h.append(''),d=g.selector,e=g.widgetOptions,h.find(".tablesorter-column-selector").html(d.$container.html()).find("input").each(function(){var b=a(this).attr("data-column"),c="auto"===b?d.auto:d.states[b];a(this).toggleClass(e.columnSelector_cssChecked,c).prop("checked",c)}),d.$popup=h.on("change","input",function(){f=a(this).toggleClass(e.columnSelector_cssChecked,this.checked).attr("data-column"),d.$container.find('input[data-column="'+f+'"]').prop("checked",this.checked).trigger("change")}))}};b.addWidget({id:"columnSelector",priority:10,options:{columnSelector_container:null,columnSelector_columns:{},columnSelector_saveColumns:!0,columnSelector_layout:'',columnSelector_name:"data-selector-name",columnSelector_mediaquery:!0,columnSelector_mediaqueryName:"Auto: ",columnSelector_mediaqueryState:!0,columnSelector_breakpoints:["20em","30em","40em","50em","60em","70em"],columnSelector_priority:"data-priority",columnSelector_cssChecked:"checked"},init:function(a,b,c,e){d.init(a,c,e)},remove:function(a,b,d,e){if(!e){var f=b.selector;f.$container.empty(),f.$popup&&f.$popup.empty(),f.$style.remove(),f.$breakpoints.remove(),b.$table.off("updateAll"+c+" update"+c)}}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-columns.min.js b/dist/js/widgets/widget-columns.min.js new file mode 100644 index 0000000..f69e165 --- /dev/null +++ b/dist/js/widgets/widget-columns.min.js @@ -0,0 +1,2 @@ +/*! Widget: columns */ +!function(a){"use strict";var b=a.tablesorter||{};b.addWidget({id:"columns",priority:30,options:{columns:["primary","secondary","tertiary"]},format:function(c,d,e){var f,g,h,i,j,k,l,m,n=d.$table,o=d.$tbodies,p=d.sortList,q=p.length,r=e&&e.columns||["primary","secondary","tertiary"],s=r.length-1;for(l=r.join(" "),g=0;g1)))for(m=1;q>m;m++)k.eq(p[m][0]).addClass(r[m]||r[s])}),b.processTbody(c,f,!1);if(i=e.columns_thead!==!1?["thead tr"]:[],e.columns_tfoot!==!1&&i.push("tfoot tr"),i.length&&(h=n.find(i.join(",")).children().removeClass(l),q))for(m=0;q>m;m++)h.filter('[data-column="'+p[m][0]+'"]').addClass(r[m]||r[s])},remove:function(c,d,e){var f,g,h=d.$tbodies,i=(e.columns||["primary","secondary","tertiary"]).join(" ");for(d.$headers.removeClass(i),d.$table.children("tfoot").children("tr").children("th, td").removeClass(i),f=0;f0&&c>=n?n:0,z=m?o.children().children():o;m&&f.$table.data("cssStickyHeaderBottom",(s.length?d:0)-(g.cssStickyHeaders_addCaption?b:0)),g.cssStickyHeaders_addCaption&&(z=z.add(p)),u!==g.cssStickyHeaders_addCaption&&(u=g.cssStickyHeaders_addCaption,u||x(p,0)),x(z,y)}),k.unbind(("filterEnd"+n).replace(/\s+/g," ")).bind("filterEnd"+n,function(){g.cssStickyHeaders_filteredToTop&&b.scrollTo(0,k.position().top)})},remove:function(c,d,e,f){if(!f){var g=d.namespace+"cssstickyheader ";a(b).unbind("scroll resize ".split(" ").join(g).replace(/\s+/g," ")),d.$table.unbind("filterEnd scroll resize ".split(" ").join(g).replace(/\s+/g," ")).add(d.$table.children("thead").children().children()).children("thead, caption").css({transform:"","-ms-transform":"","-webkit-transform":""})}}})}(jQuery,window); \ No newline at end of file diff --git a/dist/js/widgets/widget-editable.min.js b/dist/js/widgets/widget-editable.min.js new file mode 100644 index 0000000..a6f548b --- /dev/null +++ b/dist/js/widgets/widget-editable.min.js @@ -0,0 +1,2 @@ +/*! Widget: editable - updated 5/17/2015 (v2.22.0) */ +!function(a){"use strict";var b=a.tablesorter.editable={namespace:".tseditable",lastEdited:"tseditable-last-edited-cell",editComplete:function(a,c,d,e){d.removeClass(b.lastEdited).trigger(c.editable_editComplete,[a]),e&&setTimeout(function(){d.focus()},50)},selectAll:function(a){setTimeout(function(){var b,c;document.body.createTextRange?(b=document.body.createTextRange(),b.moveToElementText(a),b.select()):window.getSelection&&(c=window.getSelection(),b=document.createRange(),b.selectNodeContents(a),c.removeAllRanges(),c.addRange(b))},100)},getColumns:function(b,c){var d,e,f=[],g=[];if(!c.editable_columnsArray&&"string"===a.type(c.editable_columns)&&c.editable_columns.indexOf("-")>=0)for(e=c.editable_columns.split(/\s*-\s*/),d=parseInt(e[0],10)||0,e=parseInt(e[1],10)||b.columns-1,e>b.columns&&(e=b.columns-1);e>=d;d++)f.push(d),g.push("td:nth-child("+(d+1)+")");else a.isArray(c.editable_columns)&&a.each(c.editable_columnsArray||c.editable_columns,function(a,c){c").wrapInner(d.editable_wrapContent).children().length||a.isFunction(d.editable_wrapContent),g=b.getColumns(c,d).join(",");c.$tbodies.find(g).find("[contenteditable]").prop("contenteditable",!1),c.$tbodies.find(g).not("."+d.editable_noEdit).each(function(){e=a(this),f&&0===e.children("div, span").length&&e.wrapInner(d.editable_wrapContent),e.children("div, span").length?e.children("div, span").not("."+d.editable_noEdit).each(function(){var b=a(this);d.editable_trimContent&&b.html(function(b,c){return a.trim(c)}),b.prop("contenteditable",!0)}):(d.editable_trimContent&&e.html(function(b,c){return a.trim(c)}),e.prop("contenteditable",!0))})},bindEvents:function(c,d){var e=b.namespace;c.$table.off("updateComplete pagerComplete ".split(" ").join(e+" ").replace(/\s+/g," ")).on("updateComplete pagerComplete ".split(" ").join(e+" "),function(){b.update(c,c.widgetOptions)}).children("thead").add(a(c.namespace+"_extra_table").children("thead")).off("mouseenter"+e).on("mouseenter"+e,function(){c.$table.data("contentFocused")&&(c.$table.data("contentFocused",!0),a(":focus").trigger("focusout"))}),c.$tbodies.off("focus blur focusout keydown ".split(" ").join(e+" ").replace(/\s+/g," ")).on("focus"+e,"[contenteditable]",function(f){clearTimeout(a(this).data("timer")),c.$table.data("contentFocused",f.target);var g=a(this),h=d.editable_selectAll,i=g.closest("td").index(),j=g.html();d.editable_trimContent&&(j=a.trim(j)),g.off("keydown"+e).on("keydown"+e,function(a){d.editable_enterToAccept&&13===a.which&&a.preventDefault()}),g.data({before:j,original:j}),"function"==typeof d.editable_focused&&d.editable_focused(j,i,g),h&&("function"==typeof h?h(j,i,g)&&b.selectAll(g[0]):b.selectAll(g[0]))}).on("blur focusout keydown ".split(" ").join(e+" "),"[contenteditable]",function(f){if(c.$table.data("contentFocused")){var g,h,i=!1,j=a(f.target),k=j.html(),l=j.closest("td").index();if(d.editable_trimContent&&(k=a.trim(k)),27===f.which)return j.html(j.data("original")).trigger("blur"+e),c.$table.data("contentFocused",!1),!1;if(g=13===f.which&&(d.editable_enterToAccept||f.altKey)||d.editable_autoAccept&&"keydown"!==f.type,g&&j.data("before")!==k){if(h=d.editable_validate,i=k,"function"==typeof h?i=h(k,j.data("original"),l,j):"function"==typeof(h=a.tablesorter.getColumnData(c.table,h,l))&&(i=h(k,j.data("original"),l,j)),g&&i!==!1)return c.$table.find("."+b.lastEdited).removeClass(b.lastEdited),j.addClass(b.lastEdited).html(i).data("before",i).data("original",i).trigger("change"),c.$table.trigger("updateCell",[j.closest("td"),!1,function(){d.editable_autoResort?setTimeout(function(){c.$table.trigger("sorton",[c.sortList,function(){b.editComplete(c,d,c.$table.find("."+b.lastEdited),!0)},!0])},10):b.editComplete(c,d,c.$table.find("."+b.lastEdited))}]),!1}else i||"keydown"===f.type||(clearTimeout(j.data("timer")),j.data("timer",setTimeout(function(){a.isFunction(d.editable_blur)&&(k=j.html(),d.editable_blur(d.editable_trimContent?a.trim(k):k,l,j))},100)),j.html(j.data("original")))}})},destroy:function(a,c){var d=b.namespace,e=b.getColumns(a,c),f="updateComplete pagerComplete ".split(" ").join(d+" ").replace(/\s+/g," ");a.$table.off(f),f="focus blur focusout keydown ".split(" ").join(d+" ").replace(/\s+/g," "),a.$tbodies.off(f).find(e.join(",")).find("[contenteditable]").prop("contenteditable",!1)}};a.tablesorter.addWidget({id:"editable",options:{editable_columns:[],editable_enterToAccept:!0,editable_autoAccept:!0,editable_autoResort:!1,editable_wrapContent:"
    ",editable_trimContent:!0,editable_validate:null,editable_focused:null,editable_blur:null,editable_selectAll:!1,editable_noEdit:"no-edit",editable_editComplete:"editComplete"},init:function(a,c,d,e){e.editable_columns.length&&(b.update(d,e),b.bindEvents(d,e))},remove:function(a,c,d,e){e||b.destroy(c,d)}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-filter-formatter-html5.min.js b/dist/js/widgets/widget-filter-formatter-html5.min.js new file mode 100644 index 0000000..f67c90d --- /dev/null +++ b/dist/js/widgets/widget-filter-formatter-html5.min.js @@ -0,0 +1,2 @@ +/*! Widget: filter, html5 formatter functions - updated 7/17/2014 (v2.17.5) */ +!function(a){"use strict";var b=a.tablesorter||{},c=".compare-select",d=b.filterFormatter=a.extend({},b.filterFormatter,{addCompare:function(b,d,e){if(e.compare&&a.isArray(e.compare)&&e.compare.length>1){var f="",g=[c.slice(1)," "+c.slice(1),""],h=e.cellText?'":"";a.each(e.compare,function(a,b){f+=""}),b.wrapInner('
    ').prepend(h+'').appendTo(e),l=j.skipTest||"number"===k.attr("type")&&"test"!==k.val(),m=[],n=e.closest("table")[0].config,o=function(b,d){var f=j.addToggle?e.find(".toggle").is(":checked"):!0,g=e.find(".number").val(),h=(a.isArray(j.compare)?e.find(c).val()||j.compare[j.selected||0]:j.compare)||"",k=n.$table[0].hasInitialized?(b?b:j.delayed)||"":!0;i.val(!j.addToggle||f?(h?h:j.exactMatch?"=":"")+g:"").trigger(d?"":"search",k).end().find(".number").val(g),e.find(".number").length&&(e.find(".number")[0].disabled=j.disabled||!f),m.length&&(m.find(".number").val(g)[0].disabled=j.disabled||!f,m.find(c).val(h),j.addToggle&&(m.find(".toggle")[0].checked=f))};return k.remove(),l&&(h=j.addToggle?'
    ':"",h+='',e.append(h+'').find(".toggle, .number").bind("change",function(){o()}).closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed").closest("table").bind("filterReset",function(){a.isArray(j.compare)&&e.add(m).find(c).val(j.compare[j.selected||0]),j.addToggle&&(e.find(".toggle")[0].checked=!1,m.length&&(m.find(".toggle")[0].checked=!1)),e.find(".number").val(j.value),setTimeout(function(){o()},0)}),i=e.find("input[type=hidden]").bind("change",function(){e.find(".number").val(this.value),o()}),n.$table.bind("filterFomatterUpdate",function(){var a=d.updateCompare(e,i,j)[0]||j.value;e.find(".number").val(((a||"")+"").replace(/[><=]/g,"")),o(!1,!0),b.filter.formatterUpdated(e,f)}),j.compare&&(d.addCompare(e,f,j),e.find(c).bind("change",function(){o()})),n.$table.bind("stickyHeadersInit",function(){m=n.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),m.append(h).find(".toggle, .number").bind("change",function(){e.find(".number").val(a(this).val()),o()}),j.compare&&(d.addCompare(m,f,j),m.find(c).bind("change",function(){e.find(c).val(a(this).val()),o()})),o()}),o()),l?e.find('input[type="hidden"]'):a('')},html5Range:function(e,f,g){var h,i=a.extend({value:0,min:0,max:100,step:1,delayed:!0,valueToHeader:!0,exactMatch:!0,cellText:"",compare:"",allText:"all",skipTest:!1},g),j=a('').appendTo(e),k=i.skipTest||"range"===j.attr("type")&&"test"!==j.val(),l=[],m=e.closest("table")[0].config,n=function(b,d,g){b=("undefined"==typeof b?h.val():b).toString().replace(/[<>=]/g,"")||i.value;var j=(a.isArray(i.compare)?e.find(c).val()||i.compare[i.selected||0]:i.compare)||"",k=" ("+(j?j+b:b==i.min?i.allText:b)+")",n=m.$table[0].hasInitialized?(d?d:i.delayed)||"":!0;e.find("input[type=hidden]").val(j?j+b:b==i.min?"":(i.exactMatch?"=":"")+b).trigger(g?"":"search",n).end().find(".range").val(b),e.closest("thead").find("th[data-column="+f+"]").find(".curvalue").html(k),l.length&&(l.find(".range").val(b).end().find(c).val(j),l.closest("thead").find("th[data-column="+f+"]").find(".curvalue").html(k))};return j.remove(),k&&(e.html('').closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed").find(".tablesorter-header-inner").append(''),h=e.find("input[type=hidden]").bind("change"+m.namespace+"filter",function(){var b=this.value,d=(a.isArray(i.compare)?e.find(c).val()||i.compare[i.selected||0]:i.compare)||"";b!==this.lastValue&&(this.lastValue=d?d+b:b==i.min?"":(i.exactMatch?"=":"")+b,this.value=this.lastValue,n(b))}),e.find(".range").bind("change",function(){n(this.value)}),m.$table.bind("filterFomatterUpdate",function(){var a=d.updateCompare(e,h,i)[0];e.find(".range").val(a),n(a,!1,!0),b.filter.formatterUpdated(e,f)}),i.compare&&(d.addCompare(e,f,i),e.find(c).bind("change",function(){n()})),m.$table.bind("stickyHeadersInit",function(){l=m.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),l.html('').find(".range").bind("change",function(){n(l.find(".range").val())}),n(),i.compare&&(d.addCompare(l,f,i),l.find(c).bind("change",function(){e.find(c).val(a(this).val()),n()}))}),e.closest("table").bind("filterReset",function(){a.isArray(i.compare)&&e.add(l).find(c).val(i.compare[i.selected||0]),setTimeout(function(){n(i.value,!1,!0)},0)}),n()),k?e.find('input[type="hidden"]'):a('')},html5Color:function(c,d,e){var f,g,h=a.extend({value:"#000000",disabled:!1,addToggle:!0,exactMatch:!0,valueToHeader:!1,skipTest:!1},e),i=a('').appendTo(c),j=h.skipTest||"color"===i.attr("type")&&"test"!==i.val(),k=[],l=c.closest("table")[0].config,m=function(a,b){a=("undefined"==typeof a?g.val():a).toString().replace("=","")||h.value;var e=!0,f=" ("+a+")";h.addToggle&&(e=c.find(".toggle").is(":checked")),c.find(".colorpicker").length&&(c.find(".colorpicker").val(a)[0].disabled=h.disabled||!e),g.val(e?a+(h.exactMatch?"=":""):"").trigger(!l.$table[0].hasInitialized||b?"":"search"),h.valueToHeader?c.closest("thead").find("th[data-column="+d+"]").find(".curcolor").html(f):c.find(".currentColor").html(f),k.length&&(k.find(".colorpicker").val(a)[0].disabled=h.disabled||!e,h.addToggle&&(k.find(".toggle")[0].checked=e),h.valueToHeader?k.closest("thead").find("th[data-column="+d+"]").find(".curcolor").html(f):k.find(".currentColor").html(f))};return i.remove(),j&&(f=""+d+Math.round(100*Math.random()),f='
    '+(h.addToggle?'
    ':"")+''+(h.valueToHeader?"":'(#000000)')+"
    ",c.html(f),h.valueToHeader&&c.closest("thead").find("th[data-column="+d+"]").find(".tablesorter-header-inner").append(''),c.find(".toggle, .colorpicker").bind("change",function(){m(c.find(".colorpicker").val())}),g=c.find("input[type=hidden]").bind("change"+l.namespace+"filter",function(){m(this.value)}),l.$table.bind("filterFomatterUpdate",function(){m(g.val(),!0),b.filter.formatterUpdated(c,d)}),c.closest("table").bind("filterReset",function(){h.addToggle&&(c.find(".toggle")[0].checked=!1),setTimeout(function(){m()},0)}),l.$table.bind("stickyHeadersInit",function(){k=l.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(d),k.html(f).find(".toggle, .colorpicker").bind("change",function(){m(k.find(".colorpicker").val())}),m(k.find(".colorpicker").val())}),m(h.value)),j?c.find('input[type="hidden"]'):a('')}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-filter-formatter-jui.min.js b/dist/js/widgets/widget-filter-formatter-jui.min.js new file mode 100644 index 0000000..00892e4 --- /dev/null +++ b/dist/js/widgets/widget-filter-formatter-jui.min.js @@ -0,0 +1,2 @@ +/*! Widget: filter jQuery UI formatter functions - updated 7/17/2014 (v2.17.5) */ +!function(a){"use strict";var b=a.tablesorter||{},c=".compare-select",d=b.filterFormatter=a.extend({},b.filterFormatter,{addCompare:function(b,d,e){if(e.compare&&a.isArray(e.compare)&&e.compare.length>1){var f="",g=[c.slice(1)," "+c.slice(1),""],h=e.cellText?'":"";a.each(e.compare,function(a,b){f+=""}),b.wrapInner('
    ').prepend(h+'').appendTo(e).bind("change"+i.namespace+"filter",function(){l({value:this.value,delayed:!1})}),k=[],l=function(d,f){var g,j=!0,l=d&&d.value&&b.formatFloat((d.value+"").replace(/[><=]/g,""))||e.find(".spinner").val()||h.value,m=(a.isArray(h.compare)?e.find(c).val()||h.compare[h.selected||0]:h.compare)||"",n=d&&"boolean"==typeof d.delayed?d.delayed:i.$table[0].hasInitialized?h.delayed||"":!0;h.addToggle&&(j=e.find(".toggle").is(":checked")),g=h.disabled||!j?"disable":"enable",e.find(".filter").val(j?(m?m:h.exactMatch?"=":"")+l:"").trigger(f?"":"search",n).end().find(".spinner").spinner(g).val(l),k.length&&(k.find(".spinner").spinner(g).val(l).end().find(c).val(m),h.addToggle&&(k.find(".toggle")[0].checked=j))};return h.oldcreate=h.create,h.oldspin=h.spin,h.create=function(a,b){l(),"function"==typeof h.oldcreate&&h.oldcreate(a,b)},h.spin=function(a,b){l(b),"function"==typeof h.oldspin&&h.oldspin(a,b)},h.addToggle&&a('
    ').appendTo(e).find(".toggle").bind("change",function(){l()}),e.closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed"),a('').val(h.value).appendTo(e).spinner(h).bind("change keyup",function(){l()}),i.$table.bind("filterFomatterUpdate",function(){var a=d.updateCompare(e,j,h)[0];e.find(".spinner").val(a),l({value:a},!0),b.filter.formatterUpdated(e,f)}),h.compare&&(d.addCompare(e,f,h),e.find(c).bind("change",function(){l()})),i.$table.bind("stickyHeadersInit",function(){k=i.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),h.addToggle&&a('
    ').appendTo(k).find(".toggle").bind("change",function(){e.find(".toggle")[0].checked=this.checked,l()}),a('').val(h.value).appendTo(k).spinner(h).bind("change keyup",function(){e.find(".spinner").val(this.value),l()}),h.compare&&(d.addCompare(k,f,h),k.find(c).bind("change",function(){e.find(c).val(a(this).val()),l()}))}),i.$table.bind("filterReset",function(){a.isArray(h.compare)&&e.add(k).find(c).val(h.compare[h.selected||0]),h.addToggle&&(e.find(".toggle")[0].checked=!1),e.find(".spinner").spinner("value",h.value),setTimeout(function(){l()},0)}),l(),j},uiSlider:function(e,f,g){var h=a.extend({delayed:!0,valueToHeader:!1,exactMatch:!0,cellText:"",compare:"",allText:"all",value:0,min:0,max:100,step:1,range:"min"},g),i=e.closest("table")[0].config,j=a('').appendTo(e).bind("change"+i.namespace+"filter",function(){l({value:this.value})}),k=[],l=function(d,g){var j="undefined"!=typeof d?b.formatFloat((d.value+"").replace(/[><=]/g,""))||h.value:h.value,l=h.compare?j:j===h.min?h.allText:j,m=(a.isArray(h.compare)?e.find(c).val()||h.compare[h.selected||0]:h.compare)||"",n=m+l,o=d&&"boolean"==typeof d.delayed?d.delayed:i.$table[0].hasInitialized?h.delayed||"":!0;h.valueToHeader?e.closest("thead").find("th[data-column="+f+"]").find(".curvalue").html(" ("+n+")"):e.find(".ui-slider-handle").addClass("value-popup").attr("data-value",n),e.find(".filter").val(m?m+j:j===h.min?"":(h.exactMatch?"=":"")+j).trigger(g?"":"search",o).end().find(".slider").slider("value",j),k.length&&(k.find(c).val(m).end().find(".slider").slider("value",j),h.valueToHeader?k.closest("thead").find("th[data-column="+f+"]").find(".curvalue").html(" ("+n+")"):k.find(".ui-slider-handle").addClass("value-popup").attr("data-value",n))};return e.closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed"),h.valueToHeader&&e.closest("thead").find("th[data-column="+f+"]").find(".tablesorter-header-inner").append(''),h.oldcreate=h.create,h.oldslide=h.slide,h.create=function(a,b){l(),"function"==typeof h.oldcreate&&h.oldcreate(a,b)},h.slide=function(a,b){l(b),"function"==typeof h.oldslide&&h.oldslide(a,b)},a('
    ').appendTo(e).slider(h),i.$table.bind("filterFomatterUpdate",function(){var a=d.updateCompare(e,j,h)[0];e.find(".slider").slider("value",a),l({value:a},!1),b.filter.formatterUpdated(e,f)}),h.compare&&(d.addCompare(e,f,h),e.find(c).bind("change",function(){l({value:e.find(".slider").slider("value")})})),i.$table.bind("filterReset",function(){a.isArray(h.compare)&&e.add(k).find(c).val(h.compare[h.selected||0]),setTimeout(function(){l({value:h.value})},0)}),i.$table.bind("stickyHeadersInit",function(){k=i.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),a('
    ').val(h.value).appendTo(k).slider(h).bind("change keyup",function(){e.find(".slider").slider("value",this.value),l()}),h.compare&&(d.addCompare(k,f,h),k.find(c).bind("change",function(){e.find(c).val(a(this).val()),l()}))}),j},uiRange:function(c,d,e){var f=a.extend({delayed:!0,valueToHeader:!1,values:[0,100],min:0,max:100,range:!0},e),g=c.closest("table")[0].config,h=a('').appendTo(c).bind("change"+g.namespace+"filter",function(){j()}),i=[],j=function(){var a=h.val(),b=a.split(" - ");""===a&&(b=[f.min,f.max]),b&&b[1]&&k({values:b,delay:!1},!0)},k=function(a,b){var e=a&&a.values||f.values,h=e[0]+" - "+e[1],j=e[0]===f.min&&e[1]===f.max?"":h,k=a&&"boolean"==typeof a.delayed?a.delayed:g.$table[0].hasInitialized?f.delayed||"":!0;f.valueToHeader?c.closest("thead").find("th[data-column="+d+"]").find(".currange").html(" ("+h+")"):c.find(".ui-slider-handle").addClass("value-popup").eq(0).attr("data-value",e[0]).end().eq(1).attr("data-value",e[1]),c.find(".filter").val(j).trigger(b?"":"search",k).end().find(".range").slider("values",e),i.length&&(i.find(".range").slider("values",e),f.valueToHeader?i.closest("thead").find("th[data-column="+d+"]").find(".currange").html(" ("+h+")"):i.find(".ui-slider-handle").addClass("value-popup").eq(0).attr("data-value",e[0]).end().eq(1).attr("data-value",e[1]))};return c.closest("thead").find("th[data-column="+d+"]").addClass("filter-parsed"),f.valueToHeader&&c.closest("thead").find("th[data-column="+d+"]").find(".tablesorter-header-inner").append(''),f.oldcreate=f.create,f.oldslide=f.slide,f.create=function(a,b){k(),"function"==typeof f.oldcreate&&f.oldcreate(a,b)},f.slide=function(a,b){k(b),"function"==typeof f.oldslide&&f.oldslide(a,b)},a('
    ').appendTo(c).slider(f),g.$table.bind("filterFomatterUpdate",function(){j(),b.filter.formatterUpdated(c,d)}),g.$table.bind("filterReset",function(){c.find(".range").slider("values",f.values),setTimeout(function(){k()},0)}),g.$table.bind("stickyHeadersInit",function(){i=g.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(d).empty(),a('
    ').val(f.value).appendTo(i).slider(f).bind("change keyup",function(){c.find(".range").val(this.value),k()})}),h},uiDateCompare:function(e,f,g){var h,i,j=a.extend({cellText:"",compare:"",endOfDay:!0,defaultDate:"",changeMonth:!0,changeYear:!0,numberOfMonths:1},g),k=e.closest("table")[0].config,l=e.closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed"),m=a('').appendTo(e).bind("change"+k.namespace+"filter",function(){var a=this.value;a&&j.onClose(a)}),n=[],o=function(b){var d,f,g=h.datepicker("getDate")||"",i=(a.isArray(j.compare)?e.find(c).val()||j.compare[j.selected||0]:j.compare)||"",l=k.$table[0].hasInitialized?j.delayed||"":!0;h.datepicker("setDate",(""===g?"":g)||null),""===g&&(b=!1),d=h.datepicker("getDate"),f=d?(j.endOfDay&&/<=/.test(i)?d.setHours(23,59,59):d.getTime())||"":"",d&&j.endOfDay&&"="===i&&(i="",f+=" - "+d.setHours(23,59,59),b=!1),e.find(".dateCompare").val(i+f).trigger(b?"":"search",l).end(),n.length&&n.find(".dateCompare").val(i+f).end().find(c).val(i)};return i='',h=a(i).appendTo(e),j.oldonClose=j.onClose,j.onClose=function(a,b){o(),"function"==typeof j.oldonClose&&j.oldonClose(a,b)},h.datepicker(j),k.$table.bind("filterReset",function(){a.isArray(j.compare)&&e.add(n).find(c).val(j.compare[j.selected||0]),e.add(n).find(".date").val(j.defaultDate).datepicker("setDate",j.defaultDate||null),setTimeout(function(){o()},0)}),k.$table.bind("filterFomatterUpdate",function(){var a,g=m.val();/\s+-\s+/.test(g)?(e.find(c).val("="),a=g.split(/\s+-\s+/)[0],h.datepicker("setDate",a||null)):(a=d.updateCompare(e,m,j)[1].toString()||"",a=""!==a?/\d{5}/g.test(a)?new Date(Number(a)):a||"":""),e.add(n).find(".date").datepicker("setDate",a||null),setTimeout(function(){o(!0),b.filter.formatterUpdated(e,f)},0)}),j.compare&&(d.addCompare(e,f,j),e.find(c).bind("change",function(){o()})),k.$table.bind("stickyHeadersInit",function(){n=k.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),n.append(i).find(".date").datepicker(j),j.compare&&(d.addCompare(n,f,j),n.find(c).bind("change",function(){e.find(c).val(a(this).val()),o()}))}),m.val(j.defaultDate?j.defaultDate:"")},uiDatepicker:function(c,d,e){var f,g,h=a.extend({endOfDay:!0,textFrom:"from",textTo:"to",from:"",to:"",changeMonth:!0,changeYear:!0,numberOfMonths:1},e),i=[],j=c.closest("table")[0].config,k=function(a){return a instanceof Date&&isFinite(a)},l=a('').appendTo(c).bind("change"+j.namespace+"filter",function(){var a=this.value;a.match(" - ")?(a=a.split(" - "),c.find(".dateTo").val(a[1]),g(a[0])):a.match(">=")?g(a.replace(">=","")):a.match("<=")&&g(a.replace("<=",""))}),m=c.closest("thead").find("th[data-column="+d+"]").addClass("filter-parsed");return f="',a(f).appendTo(c),h.oldonClose=h.onClose,g=h.onClose=function(a,b){var d,e=c.find(".dateFrom").datepicker("getDate"),f=c.find(".dateTo").datepicker("getDate");e=k(e)?e.getTime():"",f=k(f)?(h.endOfDay?f.setHours(23,59,59):f.getTime())||"":"",d=e?f?e+" - "+f:">="+e:f?"<="+f:"",c.add(i).find(".dateRange").val(d).trigger("search"),e=e?new Date(e):"",f=f?new Date(f):"",/<=/.test(d)?c.add(i).find(".dateFrom").datepicker("option","maxDate",f||null).end().find(".dateTo").datepicker("option","minDate",null).datepicker("setDate",f||null):/>=/.test(d)?c.add(i).find(".dateFrom").datepicker("option","maxDate",null).datepicker("setDate",e||null).end().find(".dateTo").datepicker("option","minDate",e||null):c.add(i).find(".dateFrom").datepicker("option","maxDate",null).datepicker("setDate",e||null).end().find(".dateTo").datepicker("option","minDate",null).datepicker("setDate",f||null),"function"==typeof h.oldonClose&&h.oldonClose(a,b)},h.defaultDate=h.from||"",c.find(".dateFrom").datepicker(h),h.defaultDate=h.to||"+7d",c.find(".dateTo").datepicker(h),j.$table.bind("filterFomatterUpdate",function(){var a=l.val()||"",e="",f="";/\s+-\s+/.test(a)?(a=a.split(/\s+-\s+/)||[],e=a[0]||"",f=a[1]||""):/>=/.test(a)?e=a.replace(/>=/,"")||"":/<=/.test(a)&&(f=a.replace(/<=/,"")||""),e=""!==e?/\d{5}/g.test(e)?new Date(Number(e)):e||"":"",f=""!==f?/\d{5}/g.test(f)?new Date(Number(f)):f||"":"",c.add(i).find(".dateFrom").datepicker("setDate",e||null),c.add(i).find(".dateTo").datepicker("setDate",f||null),setTimeout(function(){g(),b.filter.formatterUpdated(c,d)},0)}),j.$table.bind("stickyHeadersInit",function(){i=j.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(d).empty(),i.append(f),h.defaultDate=h.from||"",i.find(".dateFrom").datepicker(h),h.defaultDate=h.to||"+7d",i.find(".dateTo").datepicker(h)}),c.closest("table").bind("filterReset",function(){c.add(i).find(".dateFrom").val("").datepicker("setDate",h.from||null),c.add(i).find(".dateTo").val("").datepicker("setDate",h.to||null),setTimeout(function(){g()},0)}),l.val(h.from?h.to?h.from+" - "+h.to:">="+h.from:h.to?"<="+h.to:"")}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-filter-formatter-select2.min.js b/dist/js/widgets/widget-filter-formatter-select2.min.js new file mode 100644 index 0000000..4f11746 --- /dev/null +++ b/dist/js/widgets/widget-filter-formatter-select2.min.js @@ -0,0 +1,2 @@ +/*! Widget: filter, select2 formatter function - updated 3/26/2015 (v2.21.3) */ +!function(a){"use strict";var b=a.tablesorter||{};b.filterFormatter=b.filterFormatter||{},b.filterFormatter.select2=function(c,d,e){var f,g,h=a.extend({cellText:"",match:!0,value:"",multiple:!0,width:"100%"},e),i=c.closest("table")[0].config,j=i.widgetOptions,k=a('').appendTo(c).bind("change"+i.namespace+"filter",function(){var a=this.value;a=a.replace(/[/()$^]/g,"").split("|"),c.find(".select2").select2("val",a),q()}),l=i.$headerIndexed[d],m=l.hasClass(j.filter_onlyAvail),n=[],o=h.match?"":"^",p=h.match?"":"$",q=function(){var b=!1,d=c.find(".select2").select2("val")||h.value||"";a.isArray(d)&&(b=!0,d=d.join("\x00")),d=d.replace(/[-[\]{}()*+?.,/\\^$|#\s]/g,"\\$&"),b&&(d=d.split("\x00")),k.val(a.isArray(d)&&d.length&&""!==d.join("")?"/("+o+(d||[]).join(p+"|"+o)+p+")/":"").trigger("search").end().find(".select2").select2("val",d),n.length&&n.find(".select2").select2("val",d)},r=function(){g=[],f=b.filter.getOptionSource(i.$table[0],d,m)||[],a.each(f,function(a,b){g.push({id:b,text:b})}),h.data=g};return l.toggleClass("filter-match",h.match),h.cellText&&c.prepend(""),h.ajax&&!a.isEmptyObject(h.ajax)||h.data||(r(),m&&i.$table.bind("filterEnd",function(){r(),c.add(n).find(".select2").select2(h)})),a('').val(h.value).appendTo(c).select2(h).bind("change",function(){q()}),i.$table.bind("filterFomatterUpdate",function(){var a=i.$table.data("lastSearch")[d]||"";a=a.replace(/^\/\(\^?/,"").replace(/\$\|\^/g,"|").replace(/\$?\)\/$/g,"").split("|"),c.find(".select2").select2("val",a),q(),b.filter.formatterUpdated(c,d)}),i.$table.bind("stickyHeadersInit",function(){n=i.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(d).empty(),a('').val(h.value).appendTo(n).select2(h).bind("change",function(){c.find(".select2").select2("val",n.find(".select2").select2("val")),q()}),h.cellText&&n.prepend("")}),i.$table.bind("filterReset",function(){c.find(".select2").select2("val",h.value||""),setTimeout(function(){q()},0)}),q(),k}}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-filter-type-insideRange.min.js b/dist/js/widgets/widget-filter-type-insideRange.min.js new file mode 100644 index 0000000..05fbbc8 --- /dev/null +++ b/dist/js/widgets/widget-filter-type-insideRange.min.js @@ -0,0 +1,2 @@ +/*! Widget: filter, insideRange filter type - updated 2/23/2015 (v2.21.0) */ +!function(a){"use strict";var b=a.tablesorter,c=/\d+/,d=/\s+-\s+/,e=function(a){return isNaN(a)?a:parseFloat(a)};b.filter.types.insideRange=function(a,b){if(c.test(b.iFilter)&&d.test(b.iExact)){var f,g,h,i,j=b.iExact.split(d),k=a.parsers[b.index].format;return j&&j.length<2?null:(h=e(k(j[0],a.table)),i=e(k(j[1],a.table)),g=e(k(b.iFilter,a.table)),h>i&&(f=i,i=h,h=f),g>=h&&i>=g)}return null}}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-filter.min.js b/dist/js/widgets/widget-filter.min.js new file mode 100644 index 0000000..7c95855 --- /dev/null +++ b/dist/js/widgets/widget-filter.min.js @@ -0,0 +1,2 @@ +/*! Widget: filter - updated 5/17/2015 (v2.22.1) */ +!function(a){"use strict";var b=a.tablesorter||{},c=b.css;a.extend(c,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",filterDisabled:"disabled",filterRowHide:"hideme"}),b.addWidget({id:"filter",priority:50,options:{filter_childRows:!1,filter_childByColumn:!1,filter_columnFilters:!0,filter_columnAnyMatch:!0,filter_cellFilter:"",filter_cssFilter:"",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_formatter:null,filter_functions:null,filter_hideEmpty:!0,filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_startsWith:!1,filter_useParsedData:!1,filter_serversideFiltering:!1,filter_defaultAttrib:"data-value",filter_selectSourceSeparator:"|"},format:function(a,c,d){c.$table.hasClass("hasFilters")||b.filter.init(a,c,d)},remove:function(d,e,f,g){var h,i,j=e.$table,k=e.$tbodies,l="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(e.namespace+"filter ");if(j.removeClass("hasFilters").unbind(l.replace(/\s+/g," ")).find("."+c.filterRow).remove(),!g){for(h=0;h=]/g,query:"(q|query)"},types:{regex:function(a,c){if(b.filter.regex.regex.test(c.filter)){var d,e=c.filter_regexCache[c.index]||b.filter.regex.regex.exec(c.filter),f=e instanceof RegExp;try{f||(c.filter_regexCache[c.index]=e=new RegExp(e[1],e[2])),d=e.test(c.exact)}catch(g){d=!1}return d}return null},operators:function(c,d){if(/^[<>]=?/.test(d.iFilter)&&""!==d.iExact){var e,f,g,h=c.table,i=d.index,j=d.parsed[i],k=b.formatFloat(d.iFilter.replace(b.filter.regex.operators,""),h),l=c.parsers[i],m=k;return(j||"numeric"===l.type)&&(g=a.trim(""+d.iFilter.replace(b.filter.regex.operators,"")),f=b.filter.parseFilter(c,g,i,!0),k="number"!=typeof f||""===f||isNaN(f)?k:f),!j&&"numeric"!==l.type||isNaN(k)||"undefined"==typeof d.cache?(g=isNaN(d.iExact)?d.iExact.replace(b.filter.regex.nondigit,""):d.iExact,e=b.formatFloat(g,h)):e=d.cache,/>/.test(d.iFilter)?f=/>=/.test(d.iFilter)?e>=k:e>k:/=e:k>e),f||""!==m||(f=!0),f}return null},notMatch:function(c,d){if(/^\!/.test(d.iFilter)){var e,f=d.iFilter.replace("!",""),g=b.filter.parseFilter(c,f,d.index,d.parsed[d.index])||"";return b.filter.regex.exact.test(g)?(g=g.replace(b.filter.regex.exact,""),""===g?!0:a.trim(g)!==d.iExact):(e=d.iExact.search(a.trim(g)),""===g?!0:!(c.widgetOptions.filter_startsWith?0===e:e>=0))}return null},exact:function(c,d){if(b.filter.regex.exact.test(d.iFilter)){var e=d.iFilter.replace(b.filter.regex.exact,""),f=b.filter.parseFilter(c,e,d.index,d.parsed[d.index])||"";return d.anyMatch?a.inArray(f,d.rowArray)>=0:f==d.iExact}return null},and:function(c,d){if(b.filter.regex.andTest.test(d.filter)){for(var e=d.index,f=d.parsed[e],g=d.iFilter.split(b.filter.regex.andSplit),h=d.iExact.search(a.trim(b.filter.parseFilter(c,g[0],e,f)))>=0,i=g.length-1;h&&i;)h=h&&d.iExact.search(a.trim(b.filter.parseFilter(c,g[i],e,f)))>=0,i--;return h}return null},range:function(a,c){if(b.filter.regex.toTest.test(c.iFilter)){var d,e,f,g,h=a.table,i=c.index,j=c.parsed[i],k=c.iFilter.split(b.filter.regex.toSplit);return e=k[0].replace(b.filter.regex.nondigit,"")||"",f=b.formatFloat(b.filter.parseFilter(a,e,i,j),h),e=k[1].replace(b.filter.regex.nondigit,"")||"",g=b.formatFloat(b.filter.parseFilter(a,e,i,j),h),(j||"numeric"===a.parsers[i].type)&&(d=a.parsers[i].format(""+k[0],h,a.$headers.eq(i),i),f=""===d||isNaN(d)?f:d,d=a.parsers[i].format(""+k[1],h,a.$headers.eq(i),i),g=""===d||isNaN(d)?g:d),!j&&"numeric"!==a.parsers[i].type||isNaN(f)||isNaN(g)?(e=isNaN(c.iExact)?c.iExact.replace(b.filter.regex.nondigit,""):c.iExact,d=b.formatFloat(e,h)):d=c.cache,f>g&&(e=f,f=g,g=e),d>=f&&g>=d||""===f||""===g}return null},wild:function(c,d){if(/[\?\*\|]/.test(d.iFilter)||b.filter.regex.orReplace.test(d.filter)){var e=d.index,f=d.parsed[e],g=d.iFilter.replace(b.filter.regex.orReplace,"|"),h=""+(b.filter.parseFilter(c,g,e,f)||"");return!c.$headerIndexed[e].hasClass("filter-match")&&/\|/.test(h)&&("|"===h[h.length-1]&&(h+="*"),h=d.anyMatch&&a.isArray(d.rowArray)?"("+h+")":"^("+h+")$"),new RegExp(h.replace(/\?/g,"\\S{1}").replace(/\*/g,"\\S*")).test(d.iExact)}return null},fuzzy:function(a,c){if(/^~/.test(c.iFilter)){var d,e=0,f=c.iExact.length,g=c.iFilter.slice(1),h=b.filter.parseFilter(a,g,c.index,c.parsed[c.index])||"";for(d=0;f>d;d++)c.iExact[d]===h[e]&&(e+=1);return e===h.length?!0:!1}return null}},init:function(d,e,f){b.language=a.extend(!0,{},{to:"to",or:"or",and:"and"},b.language);var g,h,i,j,k,l,m,n,o,p=b.filter.regex;if(e.$table.addClass("hasFilters"),f.searchTimer=null,f.filter_initTimer=null,f.filter_formatterCount=0,f.filter_formatterInit=[],f.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',f.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',m="\\{"+b.filter.regex.query+"\\}",a.extend(p,{child:new RegExp(e.cssChildRow),filtered:new RegExp(f.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+b.language.or+"|-|"+b.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+b.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+b.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+b.language.and+"|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+b.language.and+"|&&)\\s+)","gi"),orReplace:new RegExp("\\s+("+b.language.or+")\\s+","gi"),iQuery:new RegExp(m,"i"),igQuery:new RegExp(m,"ig")}),m=e.$headers.filter(".filter-false, .parser-false").length,f.filter_columnFilters!==!1&&m!==e.$headers.length&&b.filter.buildRow(d,e,f),i="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(e.namespace+"filter "),e.$table.bind(i,function(g,h){return m=f.filter_hideEmpty&&a.isEmptyObject(e.cache)&&!(e.delayInit&&"appendCache"===g.type),e.$table.find("."+c.filterRow).toggleClass(f.filter_filteredRow,m),/(search|filter)/.test(g.type)||(g.stopPropagation(),b.filter.buildDefault(d,!0)),"filterReset"===g.type?(e.$table.find("."+c.filter).add(f.filter_$externalFilters).val(""),b.filter.searching(d,[])):"filterEnd"===g.type?b.filter.buildDefault(d,!0):(h="search"===g.type?h:"updateComplete"===g.type?e.$table.data("lastSearch"):"",/(update|add)/.test(g.type)&&"updateComplete"!==g.type&&(e.lastCombinedFilter=null,e.lastSearch=[]),b.filter.searching(d,h,!0)),!1}),f.filter_reset&&(f.filter_reset instanceof a?f.filter_reset.click(function(){e.$table.trigger("filterReset")}):a(f.filter_reset).length&&a(document).undelegate(f.filter_reset,"click.tsfilter").delegate(f.filter_reset,"click.tsfilter",function(){e.$table.trigger("filterReset")})),f.filter_functions)for(k=0;k'+(j.data("placeholder")||j.attr("data-placeholder")||f.filter_placeholder.select||"")+"":"",m=h,i=h,h.indexOf(f.filter_selectSourceSeparator)>=0&&(m=h.split(f.filter_selectSourceSeparator),i=m[1],m=m[0]),g+="");e.$table.find("thead").find("select."+c.filter+'[data-column="'+k+'"]').append(g),i=f.filter_selectSource,n=a.isFunction(i)?!0:b.getColumnData(d,i,k),n&&b.filter.buildSelect(e.table,k,"",!0,j.hasClass(f.filter_onlyAvail))}b.filter.buildDefault(d,!0),b.filter.bindSearch(d,e.$table.find("."+c.filter),!0),f.filter_external&&b.filter.bindSearch(d,f.filter_external),f.filter_hideFilters&&b.filter.hideFilters(d,e),e.showProcessing&&(i="filterStart filterEnd ".split(" ").join(e.namespace+"filter "),e.$table.unbind(i.replace(/\s+/g," ")).bind(i,function(f,g){j=g?e.$table.find("."+c.header).filter("[data-column]").filter(function(){return""!==g[a(this).data("column")]}):"",b.isProcessing(d,"filterStart"===f.type,g?j:"")})),e.filteredRows=e.totalRows,i="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(e.namespace+"filter "),e.$table.unbind(i.replace(/\s+/g," ")).bind(i,function(){var a=this.config.widgetOptions;l=b.filter.setDefaults(d,e,a)||[],l.length&&(e.delayInit&&""===l.join("")||b.setFilters(d,l,!0)),e.$table.trigger("filterFomatterUpdate"),setTimeout(function(){a.filter_initialized||b.filter.filterInitComplete(e)},100)}),e.pager&&e.pager.initialized&&!f.filter_initialized&&(e.$table.trigger("filterFomatterUpdate"),setTimeout(function(){b.filter.filterInitComplete(e)},100))},formatterUpdated:function(a,b){var c=a.closest("table")[0].config.widgetOptions;c.filter_initialized||(c.filter_formatterInit[b]=1)},filterInitComplete:function(c){var d,e,f=c.widgetOptions,g=0,h=function(){f.filter_initialized=!0,c.$table.trigger("filterInit",c),b.filter.findRows(c.table,c.$table.data("lastSearch")||[])};if(a.isEmptyObject(f.filter_formatter))h();else{for(e=f.filter_formatterInit.length,d=0;e>d;d++)1===f.filter_formatterInit[d]&&g++;clearTimeout(f.filter_initTimer),f.filter_initialized||g!==f.filter_formatterCount?f.filter_initialized||(f.filter_initTimer=setTimeout(function(){h()},500)):h()}},setDefaults:function(c,d,e){var f,g,h,i,j,k=b.getFilters(c)||[];if(e.filter_saveFilters&&b.storage&&(g=b.storage(c,"tablesorter-filters")||[],f=a.isArray(g),f&&""===g.join("")||!f||(k=g)),""===k.join(""))for(j=d.$headers.add(e.filter_$externalFilters).filter("["+e.filter_defaultAttrib+"]"),h=0;h<=d.columns;h++)i=h===d.columns?"all":h,k[h]=j.filter('[data-column="'+i+'"]').attr(e.filter_defaultAttrib)||k[h]||"";return d.$table.data("lastSearch",k),k},parseFilter:function(a,b,c,d){return d?a.parsers[c].format(b,a.table,[],c):b},buildRow:function(d,e,f){var g,h,i,j,k,l,m,n,o=f.filter_cellFilter,p=e.columns,q=a.isArray(o),r='';for(h=0;p>h;h++)r+="").appendTo(e.$table.children("thead").eq(0)).find("td"),h=0;p>h;h++)k=!1,i=e.$headerIndexed[h],m=b.getColumnData(d,f.filter_functions,h),j=f.filter_functions&&m&&"function"!=typeof m||i.hasClass("filter-select"),g=b.getColumnData(d,e.headers,h),k="false"===b.getData(i[0],g,"filter")||"false"===b.getData(i[0],g,"parser"),j?r=a("').appendTo(e.$filters.eq(h)),r&&(n=i.data("placeholder")||i.attr("data-placeholder")||f.filter_placeholder.search||"",r.attr("placeholder",n))),r&&(l=(a.isArray(f.filter_cssFilter)?"undefined"!=typeof f.filter_cssFilter[h]?f.filter_cssFilter[h]||"":"":f.filter_cssFilter)||"",r.addClass(c.filter+" "+l).attr("data-column",h),k&&(r.attr("placeholder","").addClass(c.filterDisabled)[0].disabled=!0))},bindSearch:function(c,d,e){if(c=a(c)[0],d=a(d),d.length){var f,g=c.config,h=g.widgetOptions,i=g.namespace+"filter",j=h.filter_$externalFilters;e!==!0&&(f=h.filter_anyColumnSelector+","+h.filter_multipleColumnSelector,h.filter_$anyMatch=d.filter(f),j&&j.length?h.filter_$externalFilters=h.filter_$externalFilters.add(d):h.filter_$externalFilters=d,b.setFilters(c,g.$table.data("lastSearch")||[],e===!1)),f="keypress keyup search change ".split(" ").join(i+" "),d.attr("data-lastSearchTime",(new Date).getTime()).unbind(f.replace(/\s+/g," ")).bind("keyup"+i,function(d){if(a(this).attr("data-lastSearchTime",(new Date).getTime()),27===d.which)this.value="";else{if(h.filter_liveSearch===!1)return;if(""!==this.value&&("number"==typeof h.filter_liveSearch&&this.value.length=37&&d.which<=40)))return}b.filter.searching(c,!0,!0)}).bind("search change keypress ".split(" ").join(i+" "),function(d){var e=a(this).data("column");(13===d.which||"search"===d.type||"change"===d.type&&this.value!==g.lastSearch[e])&&(d.preventDefault(),a(this).attr("data-lastSearchTime",(new Date).getTime()),b.filter.searching(c,!1,!0))})}},searching:function(a,c,d){var e=a.config.widgetOptions;clearTimeout(e.searchTimer),"undefined"==typeof c||c===!0?e.searchTimer=setTimeout(function(){b.filter.checkFilters(a,c,d)},e.filter_liveSearch?e.filter_searchDelay:10):b.filter.checkFilters(a,c,d)},checkFilters:function(d,e,f){var g=d.config,h=g.widgetOptions,i=a.isArray(e),j=i?e:b.getFilters(d,!0),k=(j||[]).join("");return a.isEmptyObject(g.cache)?void(g.delayInit&&g.pager&&g.pager.initialized&&g.$table.trigger("updateCache",[function(){b.filter.checkFilters(d,!1,f)}])):(i&&(b.setFilters(d,j,!1,f!==!0),h.filter_initialized||(g.lastCombinedFilter="")),h.filter_hideFilters&&g.$table.find("."+c.filterRow).trigger(""===k?"mouseleave":"mouseenter"),g.lastCombinedFilter!==k||e===!1?(e===!1&&(g.lastCombinedFilter=null,g.lastSearch=[]),h.filter_initialized&&g.$table.trigger("filterStart",[j]),g.showProcessing?void setTimeout(function(){return b.filter.findRows(d,j,k),!1},30):(b.filter.findRows(d,j,k),!1)):void 0)},hideFilters:function(d,e){var f,g,h;a(d).find("."+c.filterRow).addClass(c.filterRowHide).bind("mouseenter mouseleave",function(b){var d=b;f=a(this),clearTimeout(h),h=setTimeout(function(){/enter|over/.test(d.type)?f.removeClass(c.filterRowHide):a(document.activeElement).closest("tr")[0]!==f[0]&&""===e.lastCombinedFilter&&f.addClass(c.filterRowHide)},200)}).find("input, select").bind("focus blur",function(d){g=a(this).closest("tr"),clearTimeout(h);var f=d;h=setTimeout(function(){""===b.getFilters(e.$table).join("")&&g.toggleClass(c.filterRowHide,"focus"===f.type)},200)})},defaultFilter:function(c,d){if(""===c)return c;var e=b.filter.regex.iQuery,f=d.match(b.filter.regex.igQuery).length,g=f>1?a.trim(c).split(/\s/):[a.trim(c)],h=g.length-1,i=0,j=d;for(1>h&&f>1&&(g[1]=g[0]);e.test(j);)j=j.replace(e,g[i++]||""),e.test(j)&&h>i&&""!==(g[i]||"")&&(j=d.replace(e,j));return j},getLatestSearch:function(b){return b?b.sort(function(b,c){return a(c).attr("data-lastSearchTime")-a(b).attr("data-lastSearchTime")}):b||a()},multipleColumns:function(c,d){var e,f,g,h,i,j,k,l,m,n=c.widgetOptions,o=n.filter_initialized||!d.filter(n.filter_anyColumnSelector).length,p=[],q=a.trim(b.filter.getLatestSearch(d).attr("data-column")||"");if(o&&/-/.test(q))for(f=q.match(/(\d+)\s*-\s*(\d+)/g),m=f.length,l=0;m>l;l++){for(g=f[l].split(/\s*-\s*/),h=parseInt(g[0],10)||0,i=parseInt(g[1],10)||c.columns-1,h>i&&(e=h,h=i,i=e),i>=c.columns&&(i=c.columns-1);i>=h;h++)p.push(h);q=q.replace(f[l],"")}if(o&&/,/.test(q))for(j=q.split(/\s*,\s*/),m=j.length,k=0;m>k;k++)""!==j[k]&&(l=parseInt(j[k],10),l-1?(d.parsed[e]?p=d.cacheArray[e]:(p=d.rawArray[e],p=a.trim(r.filter_ignoreCase?p.toLowerCase():p),c.sortLocaleCompare&&(p=b.replaceAccents(p))),p):void 0}).get(),d.filter=d.anyMatchFilter,d.iFilter=d.iAnyMatchFilter,d.exact=d.rowArray.join(" "),d.iExact=r.filter_ignoreCase?d.exact.toLowerCase():d.exact,d.cache=d.cacheArray.slice(0,-1).join(" "),l=null,i=null;for(o in b.filter.types)a.inArray(o,e.noAnyMatch)<0&&null===i&&(i=b.filter.types[o](c,d),null!==i&&(l=i));if(null!==l)s=l;else if(r.filter_startsWith)for(s=!1,g=c.columns;!s&&g>0;)g--,s=s||0===d.rowArray[g].indexOf(d.iFilter);else s=(d.iExact+d.childRowText).indexOf(d.iFilter)>=0;if(d.anyMatch=!1,d.filters.join("")===d.filter)return s}for(g=0;g=0:d.filter===d.exact:"function"==typeof n?l=n(d.exact,d.cache,d.filter,g,d.$row,c,d):"function"==typeof n[o||d.filter]&&(p=o||d.filter,l=n[p](d.exact,d.cache,d.filter,g,d.$row,c,d))),null===l){i=null;for(o in b.filter.types)a.inArray(o,m)<0&&null===i&&(i=b.filter.types[o](c,d),null!==i&&(l=i));null!==l?j=l:(p=(d.iExact+d.childRowText).indexOf(b.filter.parseFilter(c,d.iFilter,g,d.parsed[g])),j=!r.filter_startsWith&&p>=0||r.filter_startsWith&&0===p)}else j=l;s=j?s:!1}return s},findRows:function(c,d,e){if(c.config.lastCombinedFilter!==e&&c.config.widgetOptions.filter_initialized){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B=a.extend([],d),C=b.filter.regex,D=c.config,E=D.widgetOptions,F={anyMatch:!1,filters:d,filter_regexCache:[]},G={noAnyMatch:["range","notMatch","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:b.getColumnData(c,E.filter_defaultFilter,D.columns,!0)||""};for(F.parsed=D.$headers.map(function(d){return D.parsers&&D.parsers[d]&&D.parsers[d].parsed||b.getData&&"parsed"===b.getData(D.$headerIndexed[d],b.getColumnData(c,D.headers,d),"filter")||a(this).hasClass("filter-parsed")}).get(),m=0;m1&&(z=parseInt(y[0],10)-1,z>=0&&zt;t++)s=d[t]||"",v||(t=m),v=!(!v||!p.length||0!==s.indexOf(p[t]||"")||C.alreadyFiltered.test(s)||/[=\"\|!]/.test(s)||/(>=?\s*-\d)/.test(s)||/(<=?\s*\d)/.test(s)||""!==s&&D.$filters&&D.$filters.eq(t).find("select").length&&!D.$headerIndexed[t].hasClass("filter-match"));for(u=i.not("."+E.filter_filteredRow).length,v&&0===u&&(v=!1),D.debug&&b.log("Filter: Searching through "+(v&&f>u?u:"all")+" rows"),F.anyMatchFlag&&(D.sortLocaleCompare&&(F.anyMatchFilter=b.replaceAccents(F.anyMatchFilter)),E.filter_defaultFilter&&C.iQuery.test(G.defaultAnyFilter)&&(F.anyMatchFilter=b.filter.defaultFilter(F.anyMatchFilter,G.defaultAnyFilter),v=!1),F.iAnyMatchFilter=E.filter_ignoreCase&&D.ignoreCase?F.anyMatchFilter.toLowerCase():F.anyMatchFilter),j=0;f>j;j++)if(A=i[j].className,n=j&&C.child.test(A),!(n||v&&C.filtered.test(A))){if(F.$row=i.eq(j),F.cacheArray=g[j],h=F.cacheArray[D.columns],F.rawArray=h.raw,F.childRowText="",!E.filter_childByColumn){for(A="",o=h.child,t=0;t")>=0)return p;a.isArray(p)?m=p:"object"===a.type(n)&&p&&(m=p(c,d,e))}if(m===!1&&(m=b.filter.getOptions(c,d,e)),m=a.grep(m,function(b,c){return a.inArray(b,m)===c}),j.$headerIndexed[d].hasClass("filter-select-nosort"))return m;for(i=m.length,h=0;i>h;h++)g=m[h],l.push({t:g,p:j.parsers&&j.parsers.length&&j.parsers[d].format(g,c,[],d)||g});for(f=j.textSorter||"",l.sort(function(e,g){var h=e.p.toString(),i=g.p.toString();return a.isFunction(f)?f(h,i,!0,d,c):"object"==typeof f&&f.hasOwnProperty(d)?f[d](h,i,!0,d,c):b.sortNatural?b.sortNatural(h,i):!0}),m=[],i=l.length,h=0;i>h;h++)m.push(l[h].t);return m},getOptions:function(b,c,d){b=a(b)[0];var e,f,g,h,i,j=b.config,k=j.widgetOptions,l=[];for(f=0;fe;e++)h=i.row?i.row[e]:i.normalized[e][j.columns].$row[0],d&&h.className.match(k.filter_filteredRow)||(k.filter_useParsedData||j.parsers[c].parsed||j.$headerIndexed[c].hasClass("filter-parsed")?l.push(""+i.normalized[e][c]):l.push(i.normalized[e][j.columns].raw[c]));return l},buildSelect:function(d,e,f,g,h){if(d=a(d)[0],e=parseInt(e,10),d.config.cache&&!a.isEmptyObject(d.config.cache)){var i,j,k,l,m,n,o=d.config,p=o.widgetOptions,q=o.$headerIndexed[e],r='",s=o.$table.find("thead").find("select."+c.filter+'[data-column="'+e+'"]').val();if(("undefined"==typeof f||""===f)&&(f=b.filter.getOptionSource(d,e,h)),a.isArray(f)){for(i=0;i=0&&(l=k.split(p.filter_selectSourceSeparator),j=l[0],k=l[1]),r+=""!==f[i]?"":"";f=[]}m=(o.$filters?o.$filters:o.$table.children("thead")).find("."+c.filter),p.filter_$externalFilters&&(m=m&&m.length?m.add(p.filter_$externalFilters):p.filter_$externalFilters),n=m.filter('select[data-column="'+e+'"]'),n.length&&(n[g?"html":"append"](r),a.isArray(f)||n.append(f).val(s),n.val(s))}},buildDefault:function(a,c){var d,e,f,g=a.config,h=g.widgetOptions,i=g.columns;for(d=0;i>d;d++)e=g.$headerIndexed[d],f=!(e.hasClass("filter-false")||e.hasClass("parser-false")),(e.hasClass("filter-select")||b.getColumnData(a,h.filter_functions,d)===!0)&&f&&b.filter.buildSelect(a,d,"",c,e.hasClass(h.filter_onlyAvail))}},b.getFilters=function(d,e,f,g){var h,i,j,k,l=!1,m=d?a(d)[0].config:"",n=m?m.widgetOptions:"";if(e!==!0&&n&&!n.filter_columnFilters||a.isArray(f)&&f.join("")===m.lastCombinedFilter)return a(d).data("lastSearch");if(m&&(m.$filters&&(i=m.$filters.find("."+c.filter)),n.filter_$externalFilters&&(i=i&&i.length?i.add(n.filter_$externalFilters):n.filter_$externalFilters),i&&i.length))for(l=f||[],h=0;h1&&(j=j.slice(1)),h===m.columns&&(k=j.filter(n.filter_anyColumnSelector),j=k.length?k:j),j.val(f[h]).trigger("change.tsfilter")):(l[h]=j.val()||"",h===m.columns?j.slice(1).filter('[data-column*="'+j.attr("data-column")+'"]').val(l[h]):j.slice(1).val(l[h])),h===m.columns&&j.length&&(n.filter_$anyMatch=j));return 0===l.length&&(l=!1),l},b.setFilters=function(c,d,e,f){var g=c?a(c)[0].config:"",h=b.getFilters(c,!0,d,f);return g&&e&&(g.lastCombinedFilter=null,g.lastSearch=[],b.filter.searching(g.table,d,f),g.$table.trigger("filterFomatterUpdate")),!!h}}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-formatter.min.js b/dist/js/widgets/widget-formatter.min.js new file mode 100644 index 0000000..7ad69d6 --- /dev/null +++ b/dist/js/widgets/widget-formatter.min.js @@ -0,0 +1,2 @@ +/*! Widget: formatter - 2/9/2015 (v2.19.1) */ +!function(a){"use strict";var b=a.tablesorter;b.formatter={init:function(a){var c=a.widgetOptions.formatter_event+" pagerComplete updateComplete ".split(" ").join(".tsformatter ");a.$table.off(c.replace(/\s+/g," ")).on(c,function(){b.formatter.setup(a)}),b.formatter.setup(a)},setup:function(c){if(!a.isEmptyObject(c.cache)){var d,e,f,g,h,i,j,k=c.widgetOptions,l={config:c,wo:k},m=[],n=[];for(j=0;jf;f++)for(l.$row=g.normalized[f][c.columns].$row,l.$cells=l.$row.children("th, td"),j=0;j1&&""!==d?c.hasClass(b.css.sortAsc)?(g=Math.floor(parseFloat(d)/e)*e,g>parseFloat(f||0)?g:parseFloat(f||0)):(g=Math.ceil(parseFloat(d)/e)*e,g=e?h[e-1]:d||"")},separator:function(b,c,d,e){var f=(d+"").split(b.widgetOptions.group_separator);return a.trim(f&&e>0&&f.length>=e?f[(e||1)-1]:"")},word:function(a,b,c,d){var e=(c+" ").match(/\w+/g);return e&&e.length>=d?e[d-1]:c||""},letter:function(a,b,c,d){return c?(c+" ").substring(0,d):""},date:function(a,b,c,d,e){var f=a.widgetOptions,g=new Date(c||""),h=g.getHours();return"year"===d?g.getFullYear():"month"===d?f.group_months[g.getMonth()]:"monthyear"===d?f.group_months[g.getMonth()]+" "+g.getFullYear():"day"===d?f.group_months[g.getMonth()]+" "+g.getDate():"week"===d?f.group_week[g.getDay()]:"time"===d?("00"+(h>12?h-12:0===h?h+12:h)).slice(-2)+":"+("00"+g.getMinutes()).slice(-2)+" "+("00"+f.group_time[h>=12?1:0]).slice(-2):f.group_dateString(g)}},update:function(c,d,e){if(!a.isEmptyObject(d.cache)){var f,g,h,i,j,k,l,m,n,o=e.grouping_language,p="",q=!1,r=d.sortList[0]?d.sortList[0][0]:-1;if(d.$table.find("tr.group-hidden").removeClass("group-hidden").end().find("tr.group-header").remove(),e.group_collapsible&&d.$table.data("pagerSavedHeight",0),r>=0&&!d.$headerIndexed[r].hasClass("group-false")){for(e.group_currentGroup="",e.group_currentGroups={},j=(d.$headerIndexed[r].attr("class")||"").match(/(group-\w+(-\w+)?)/g),k=j?j[0].split("-"):["group","letter",1],e.group_collapsible&&e.group_saveGroups&&b.storage&&(e.group_currentGroups=b.storage(c,"tablesorter-groups")||{},n="number"===k[1]&&k[2]>1?"dir"+d.sortList[0][1]:"",m=e.group_currentGroup=""+r+n+k.join(""),e.group_currentGroups[m]?q=!0:e.group_currentGroups[m]=[]),g=0;g1&&""!==h&&(h+=" - "+(parseInt(h,10)+(parseInt(k[2],10)-1)*(d.$headerIndexed[r].hasClass(b.css.sortAsc)?1:-1))),a.isFunction(e.group_formatter)&&(h=e.group_formatter((h||"").toString(),r,c,d,e)||h),i.eq(f).before(''+(e.group_collapsible?"":"")+''+h+''),e.group_saveGroups&&!q&&e.group_collapsed&&e.group_collapsible&&e.group_currentGroups[e.group_currentGroup].push(h)));d.$table.find("tr.group-header").bind("selectstart",!1).each(function(){var b,d,f,g=a(this),h=g.nextUntil("tr.group-header").filter(":visible");(e.group_count||a.isFunction(e.group_callback))&&(d=g.find(".group-count"),d.length&&(e.group_count&&d.html(e.group_count.replace(/\{num\}/g,h.length)),a.isFunction(e.group_callback)&&e.group_callback(g.find("td"),h,r,c))),e.group_saveGroups&&e.group_currentGroups.length&&e.group_currentGroups[e.group_currentGroup].length?(f=g.find(".group-name").text().toLowerCase(),b=a.inArray(f,e.group_currentGroups[e.group_currentGroup])>-1,g.toggleClass("collapsed",b),h.toggleClass("group-hidden",b)):e.group_collapsed&&e.group_collapsible&&(g.addClass("collapsed"),h.addClass("group-hidden"))}),d.$table.trigger(e.group_complete)}}},bindEvents:function(c,d,e){e.group_collapsible&&(e.group_currentGroups=[],d.$table.on("click toggleGroup keyup","tr.group-header",function(f){if(f.stopPropagation(),"keyup"!==f.type||13===f.which){var g,h,i,j=a(this),k=j.find(".group-name").text().toLowerCase();!f.shiftKey||"click"!==f.type&&"keyup"!==f.type||j.siblings(".group-header").trigger("toggleGroup"),j.toggleClass("collapsed"),j.nextUntil("tr.group-header").toggleClass("group-hidden",j.hasClass("collapsed")),e.group_saveGroups&&b.storage&&(h=d.$table.find(".group-header"),g=j.hasClass("collapsed"),e.group_currentGroups[e.group_currentGroup]||(e.group_currentGroups[e.group_currentGroup]=[]),g&&e.group_currentGroup?e.group_currentGroups[e.group_currentGroup].push(k):e.group_currentGroup&&(i=a.inArray(k,e.group_currentGroups[e.group_currentGroup]),i>-1&&e.group_currentGroups[e.group_currentGroup].splice(i,1)),b.storage(c,"tablesorter-groups",e.group_currentGroups))}})),a(e.group_saveReset).on("click",function(){b.grouping.clearSavedGroups(c)}),d.$table.on("pagerChange.tsgrouping",function(){b.grouping.update(c,d,e)})},clearSavedGroups:function(a){a&&b.storage&&(b.storage(a,"tablesorter-groups",""),b.grouping.update(a,a.config,a.config.widgetOptions))}},b.addWidget({id:"group",priority:100,options:{group_collapsible:!0,group_collapsed:!1,group_saveGroups:!0,group_saveReset:null,group_count:" ({num})",group_separator:"-",group_formatter:null,group_callback:null,group_complete:"groupingComplete",group_checkbox:["checked","unchecked"],group_months:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],group_week:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],group_time:["AM","PM"],group_dateString:function(a){return a.toLocaleString()}},init:function(a,c,d,e){b.grouping.bindEvents(a,d,e)},format:function(a,c,d){b.grouping.update(a,c,d)},remove:function(a,b,c){b.$table.off("click","tr.group-header").off("pagerChange.tsgrouping").find(".group-hidden").removeClass("group-hidden").end().find("tr.group-header").remove()}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-headerTitles.min.js b/dist/js/widgets/widget-headerTitles.min.js new file mode 100644 index 0000000..cffd8f5 --- /dev/null +++ b/dist/js/widgets/widget-headerTitles.min.js @@ -0,0 +1,2 @@ +/*! Widget: headerTitles - updated 3/5/2014 (v2.15.6) */ +!function(a){"use strict";var b=a.tablesorter;b.addWidget({id:"headerTitles",options:{headerTitle_useAria:!1,headerTitle_tooltip:"",headerTitle_cur_text:[" sort: A - Z"," sort: Z - A","ly unsorted"],headerTitle_cur_numeric:[" sort: 0 - 9"," sort: 9 - 0","ly unsorted"],headerTitle_nxt_text:[" sort: A - Z"," sort: Z - A","remove sort"],headerTitle_nxt_numeric:[" sort: 0 - 9"," sort: 9 - 0","remove sort"],headerTitle_output_sorted:"current{current}; activate to {next}",headerTitle_output_unsorted:"current{current}; activate to {next} ",headerTitle_output_nosort:"No sort available",headerTitle_type:[],headerTitle_callback:null},init:function(b,c,d,e){d.$table.on("refreshHeaderTitle",function(){c.format(b,d,e)}),a.isArray(e.headerTitle_tooltip)?d.$headers.each(function(){a(this).addClass(e.headerTitle_tooltip[this.column]||"")}):""!==e.headerTitle_tooltip&&d.$headers.addClass(e.headerTitle_tooltip)},format:function(c,d,e){var f;d.$headers.each(function(){var c=this,g=a(this),h=e.headerTitle_type[c.column]||d.parsers[c.column].type||"text",i=g.hasClass(b.css.sortAsc)?0:g.hasClass(b.css.sortDesc)?1:2,j=c.order[(c.count+1)%(d.sortReset?3:2)];e.headerTitle_useAria?f=g.hasClass("sorter-false")?e.headerTitle_output_nosort:g.attr("aria-label")||"":(f=(e.headerTitle_prefix||"")+(g.hasClass("sorter-false")?e.headerTitle_output_nosort:b.isValueInArray(c.column,d.sortList)>=0?e.headerTitle_output_sorted:e.headerTitle_output_unsorted),f=f.replace(/\{(current|next|name)\}/gi,function(a){return{"{name}":g.text(),"{current}":e["headerTitle_cur_"+h][i]||"","{next}":e["headerTitle_nxt_"+h][j]||""}[a.toLowerCase()]})),g.attr("title",a.isFunction(e.headerTitle_callback)?e.headerTitle_callback(g,f):f)})},remove:function(b,c,d){c.$headers.attr("title",""),c.$table.off("refreshHeaderTitle"),a.isArray(d.headerTitle_tooltip)?c.$headers.each(function(){a(this).removeClass(d.headerTitle_tooltip[this.column]||"")}):""!==d.headerTitle_tooltip&&c.$headers.removeClass(d.headerTitle_tooltip)}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-math.min.js b/dist/js/widgets/widget-math.min.js new file mode 100644 index 0000000..adc2aaa --- /dev/null +++ b/dist/js/widgets/widget-math.min.js @@ -0,0 +1,9 @@ +/*! Widget: math - updated 5/17/2015 (v2.22.0) */ +!function(a){"use strict";var b=a.tablesorter,c={events:"tablesorter-initialized update updateAll updateRows addRows updateCell filterReset filterEnd ".split(" ").join(".tsmath "),getRow:function(c,d,e,f){var g,h,i=c.config,j=[],k=e.closest("tr"),l=k.children().not("["+f+"=ignore]");return k.hasClass(d.filter_filteredRow||"filtered")||(d.math_ignore.length&&(l=l.not("[data-column="+d.math_ignore.join("],[data-column=")+"]")),j=l.not(e).map(function(){return g=a(this),h=g.attr(i.textAttribute),"undefined"==typeof h&&(h=this.textContent||g.text()),h=b.formatFloat(h.replace(/[^\w,. \-()]/g,""),c)||0,isNaN(h)?0:h}).get()),j},getColumn:function(c,d,e,f,g){var h,i,j,k,l,m=[],n=c.config,o=d.filter_filteredRow||"filtered",p=parseInt(e.attr("data-column"),10),q=n.$table.children("tbody").children(),r=e.closest("tr");if("above"===f)for(k=q.index(r),h=k;h>=0;)j=q.eq(h).children().filter("[data-column="+p+"]"),l=j.filter("["+g+"^=above]").length,(!q.eq(h).hasClass(o)&&q.eq(h).not("["+g+"=ignore]").length&&h!==k||l&&h!==k)&&(l?h=0:j.length&&(i=j.attr(n.textAttribute),"undefined"==typeof i&&(i=j[0].textContent||j.text()),i=b.formatFloat(i.replace(/[^\w,. \-()]/g,""),c)||0,m.push(isNaN(i)?0:i))),h--;else q.each(function(){j=a(this).children().filter("[data-column="+p+"]"),a(this).hasClass(o)||!j.not("["+g+"^=above],["+g+"^=col]").length||j.is(e)||(i=j.attr(n.textAttribute),"undefined"==typeof i&&(i=(j[0]?j[0].textContent:"")||j.text()),i=b.formatFloat(i.replace(/[^\w,. \-()]/g,""),c)||0,m.push(isNaN(i)?0:i))});return m},getAll:function(c,d,e){var f,g,h,i=[],j=c.config,k=d.filter_filteredRow||"filtered",l=j.$table.children("tbody").children();return l.each(function(){a(this).hasClass(k)||a(this).children().each(function(){g=a(this),h=parseInt(g.attr("data-column"),10),!g.filter("["+e+"]").length&&a.inArray(h,d.math_ignore)<0&&(f=g.attr(j.textAttribute),"undefined"==typeof f&&(f=(g[0]?g[0].textContent:"")||g.text()),f=b.formatFloat(f.replace(/[^\w,. \-()]/g,""),c)||0,i.push(isNaN(f)?0:f))})}),i},recalculate:function(a,d,e,f){if(d&&(!e.math_isUpdating||f)){f&&b.computeColumnIndex(d.$table.children("tbody").children());var g="data-"+(e.math_data||"math"),h=d.$tbodies.find("["+g+"]");c.mathType(a,e,h,e.math_priority,g),h=d.$table.find("."+d.cssInfoBlock+", tfoot").find("["+g+"]"),c.mathType(a,e,h,e.math_priority,g),c.mathType(a,e,d.$table.find("["+g+"^=all]"),["all"],g),e.math_isUpdating=!0,d.$table.trigger("update")}},mathType:function(d,e,f,g,h){if(f.length){var i,j,k,l,m,n=b.equations;"all"===g[0]&&(m=c.getAll(d,e,h)),a.each(g,function(b,g){f.filter("["+h+"^="+g+"]").each(function(){k=a(this),i=(k.attr(h)||"").replace(g+"-",""),l="row"===g?c.getRow(d,e,k,h):"all"===g?m:c.getColumn(d,e,k,g,h),n[i]&&(j=n[i](l),d.config.debug&&console&&console.log&&console.log(k.attr(h),l,"=",j),c.output(k,e,j,l))})})}},output:function(c,d,e,f){var g=b.formatMask(c.attr("data-"+d.math_data+"-mask")||d.math_mask,e,d.math_wrapPrefix,d.math_wrapSuffix);a.isFunction(d.math_complete)&&(g=d.math_complete(c,d,g,e,f)),g!==!1&&c.html(g)}};/** + * @preserve IntegraXor Web SCADA - JavaScript Number Formatter + * http:// www.integraxor.com/ + * author: KPL, KHL + * (c)2011 ecava + * Dual licensed under the MIT or GPL Version 2 licenses. + */ +b.formatMask=function(a,b,c,d){if(!a||isNaN(+b))return b;var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x="",y="";if(s=a.length,t=a.search(/[0-9\-\+#]/),u=t>0?a.substring(0,t):"",x=u,t>0&&c&&(x=/\{content\}/.test(c||"")?(c||"").replace(/\{content\}/g,u||""):(c||"")+u),w=a.split("").reverse().join(""),v=w.search(/[0-9\-\+#]/),q=s-v,q+="."===a.substring(q,q+1)?1:0,u=v>0?a.substring(q,s):"",y=u,""!==u&&d&&(y=/\{content\}/.test(d||"")?(d||"").replace(/\{content\}/g,u||""):u+(d||"")),a=a.substring(t,q),b="-"==a.charAt(0)?-b:+b,e=0>b?b=-b:0,f=a.match(/[^\d\-\+#]/g),g=f&&f[f.length-1]||".",h=f&&f[1]&&f[0]||",",a=a.split(g),b=b.toFixed(a[1]&&a[1].length),b=+b+"",j=a[1]&&a[1].lastIndexOf("0"),l=b.split("."),(!l[1]||l[1]&&l[1].length<=j)&&(b=(+b).toFixed(j+1)),m=a[0].split(h),a[0]=m.join(""),i=a[0]&&a[0].indexOf("0"),i>-1)for(;l[0].lengthq;q++)o+=n.charAt(q),!((q-p+1)%k)&&r-k>q&&(o+=h);b[0]=o}return b[1]=a[1]&&b[1]?g+b[1]:"",x+((e?"-":"")+b[0]+b[1])+y},b.equations={count:function(a){return a.length},sum:function(b){var c=0;return a.each(b,function(a){c+=b[a]}),c},mean:function(a){var c=b.equations.sum(a);return c/a.length},median:function(a){a.sort(function(a,b){return a-b});var b=Math.floor(a.length/2);return a.length%2?a[b]:(a[b-1]+a[b])/2},mode:function(a){if(0===a.length)return"none";var b,c,d={},e=1,f=[a[0]];for(b=0;be?(f=[c],e=d[c]):d[c]===e&&(f.push(c),e=d[c]);return f.sort(function(a,b){return a-b})},max:function(a){return Math.max.apply(Math,a)},min:function(a){return Math.min.apply(Math,a)},range:function(a){var b=a.sort(function(a,b){return a-b});return b[a.length-1]-b[0]},variance:function(a,c){for(var d=b.equations.mean(a),e=0,f=a.length;f--;)e+=Math.pow(a[f]-d,2);return e/=a.length-(c?0:1)},varp:function(a){return b.equations.variance(a,!0)},vars:function(a){return b.equations.variance(a)},stdevs:function(a){var c=b.equations.variance(a);return Math.sqrt(c)},stdevp:function(a){var c=b.equations.variance(a,!0);return Math.sqrt(c)}},b.addWidget({id:"math",priority:100,options:{math_data:"math",math_ignore:[],math_mask:"#,##0.00",math_complete:null,math_priority:["row","above","col"],math_prefix:"",math_suffix:"",math_event:"recalculate"},init:function(a,d,e,f){e.$table.off((c.events+" updateComplete.tsmath "+f.math_event).replace(/\s+/g," ")).on(c.events+" "+f.math_event,function(d){var g="tablesorter-initialized"===d.type;(!f.math_isUpdating||g)&&(/filter/.test(d.type)||b.computeColumnIndex(e.$table.children("tbody").children()),c.recalculate(a,e,f,g))}).on("updateComplete.tsmath",function(){setTimeout(function(){f.math_isUpdating=!1},20)}),f.math_isUpdating=!1},remove:function(b,d,e,f){f||a(b).off((c.events+" updateComplete.tsmath "+e.math_event).replace(/\s+/g," ")).find("[data-"+e.math_data+"]").empty()}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-output.min.js b/dist/js/widgets/widget-output.min.js new file mode 100644 index 0000000..193de50 --- /dev/null +++ b/dist/js/widgets/widget-output.min.js @@ -0,0 +1,2 @@ +/*! Widget: output - updated 5/17/2015 (v2.22.0) */ +!function(a){"use strict";var b=a.tablesorter,c=b.output={event:"outputTable",regexQuote:/([\n\t\x09\x0d\x0a]|<[^<]+>)/,regexBR:/(|\n)/g,regexIMG:/]+alt\s*=\s*['"]([^'"]+)['"][^>]*>/i,regexHTML:/<[^<]+>/g,replaceCR:"\r\n",replaceTab:" ",popupTitle:"Output",popupStyle:"width:100%;height:100%;",message:"Your device does not support downloading. Please try again in desktop browser.",init:function(a){a.$table.off(c.event).on(c.event,function(){c.process(a,a.widgetOptions)})},processRow:function(b,d,e,f){var g,h,i,j,k,l,m=b.widgetOptions,n=[],o=m.output_duplicateSpans,p=e&&f&&m.output_headerRows&&a.isFunction(m.output_callbackJSON),q=0;return d.each(function(b){n[b]||(n[b]=[]),q=0,a(this).children().each(function(){if(g=a(this),g.filter("[rowspan]").length)for(j=parseInt(g.attr("rowspan"),10)-1,l=c.formatData(m,g,e),h=1;j>=h;h++)n[b+h]||(n[b+h]=[]),n[b+h][q]=e?l:o?l:"";if(g.filter("[colspan]").length)for(k=parseInt(g.attr("colspan"),10)-1,l=c.formatData(m,g,e),i=1;k>=i;i++)if(g.filter("[rowspan]").length)for(j=parseInt(g.attr("rowspan"),10),h=0;j>h;h++)n[b+h]||(n[b+h]=[]),n[b+h][q+i]=p?m.output_callbackJSON(g,l,q+i)||l+"("+(q+i)+")":e?l:o?l:"";else n[b][q+i]=p?m.output_callbackJSON(g,l,q+i)||l+"("+(q+i)+")":e?l:o?l:"";if(m.output_hiddenColumns||"none"!==g.css("display")){for(;"undefined"!=typeof n[b][q];)q++;n[b][q]=n[b][q]||c.formatData(m,g,e),q++}})}),n},ignoreColumns:function(b,c){return a.each(c,function(d,e){c[d]=a.grep(e,function(c,d){return a.inArray(d,b.output_ignoreColumns)<0})}),c},process:function(d,e){var f,g,h,i,j,k,l=window.JSON&&JSON.hasOwnProperty("stringify"),m=0,n=(e.output_separator||",").toLowerCase(),o="json"===n,p="array"===n,q=o||p?",":e.output_separator,r=e.output_saveRows,s=d.$table;e.output_regex=new RegExp("("+(/\\/.test(q)?"\\":"")+q+")"),g=s.find("thead tr:visible").not("."+(b.css.filterRow||"tablesorter-filter-row")),i=c.processRow(d,g,!0,o),h=s.children("tbody").children("tr"),e.output_includeFooter&&(h=h.add(s.children("tfoot").children("tr").clone())),h=/^f/.test(r)?h.not("."+(e.filter_filteredRow||"filtered")):/^v/.test(r)?h.filter(":visible"):/^[.#:\[]/.test(r)?h.filter(r):h,j=c.processRow(d,h),k=i.length,e.output_ignoreColumns.length&&(i=c.ignoreColumns(e,i),j=c.ignoreColumns(e,j)),o?(n=[],a.each(j,function(a,b){n.push(c.row2Hash(i[k>1&&e.output_headerRows?a%k:k-1],b))}),f=l?JSON.stringify(n):n):(n=c.row2CSV(e,e.output_headerRows?i:[i[k>1&&e.output_headerRows?m%k:k-1]],p).concat(c.row2CSV(e,j,p)),f=p&&l?JSON.stringify(n):n.join("\n")),(!a.isFunction(e.output_callback)||e.output_callback(d,f))&&(/p/i.test(e.output_delivery||"")?c.popup(f,e.output_popupStyle,o||p):c.download(e,f))},row2CSV:function(a,b,c){var d,e,f=[],g=b.length;for(e=0;g>e;e++)d=(b[e]||[]).join("").replace(/\"/g,""),(b[e]||[]).length>0&&""!==d&&(f[f.length]=c?b[e]:b[e].join(a.output_separator));return f},row2Hash:function(b,c){var d={};return a.each(c,function(a,c){a"+c.popupTitle+'"),e.document.close(),e.focus(),!0},download:function(a,b){var d,e,f,g=window.navigator,h=document.createElement("a");if(/(iP)/g.test(g.userAgent))return alert(c.message),!1;try{f=!!new Blob}catch(i){f=!1}return f?(window.URL=window.URL||window.webkitURL,e=new Blob(["\ufeff",b],{type:a.output_encoding}),g.msSaveBlob?g.msSaveBlob(e,a.output_saveFileName):(h.href=window.URL.createObjectURL(e),h.download=a.output_saveFileName,document.createEvent&&(d=document.createEvent("MouseEvents"),d.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),h.dispatchEvent(d))),!1):(window.open(a.output_encoding+encodeURIComponent(b)+"?download","_self"),!0)},remove:function(a){a.$table.off(c.event)}};b.addWidget({id:"output",options:{output_separator:",",output_ignoreColumns:[],output_hiddenColumns:!1,output_includeFooter:!1,output_dataAttrib:"data-name",output_headerRows:!1,output_delivery:"popup",output_saveRows:"filtered",output_duplicateSpans:!0,output_replaceQuote:"“;",output_includeHTML:!1,output_trimSpaces:!0,output_wrapQuotes:!1,output_popupStyle:"width=500,height=300",output_saveFileName:"mytable.csv",output_callback:function(a,b){return!0},output_callbackJSON:function(a,b,c){return b+"("+c+")"},output_encoding:"data:application/octet-stream;charset=utf8,"},init:function(a,b,d){c.init(d)},remove:function(a,b){c.remove(b)}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-pager.min.js b/dist/js/widgets/widget-pager.min.js new file mode 100644 index 0000000..60a14d9 --- /dev/null +++ b/dist/js/widgets/widget-pager.min.js @@ -0,0 +1,2 @@ +/*! Widget: Pager - updated 5/17/2015 (v2.22.0) */ +!function(a){"use strict";var b,c=a.tablesorter;c.addWidget({id:"pager",priority:55,options:{pager_output:"{startRow} to {endRow} of {totalRows} rows",pager_updateArrows:!0,pager_startPage:0,pager_pageReset:0,pager_size:10,pager_maxOptionSize:20,pager_savePages:!0,pager_storageKey:"tablesorter-pager",pager_fixedHeight:!1,pager_countChildRows:!1,pager_removeRows:!1,pager_ajaxUrl:null,pager_customAjaxUrl:function(a,b){return b},pager_ajaxObject:{dataType:"json"},pager_processAjaxOnInit:!0,pager_ajaxProcessing:function(a){return[0,[],null]},pager_css:{container:"tablesorter-pager",errorRow:"tablesorter-errorRow",disabled:"disabled"},pager_selectors:{container:".pager",first:".first",prev:".prev",next:".next",last:".last",gotoPage:".gotoPage",pageDisplay:".pagedisplay",pageSize:".pagesize"}},init:function(a){b.init(a)},format:function(a,c){return c.pager&&c.pager.initialized?void b.moveToPage(a,c.pager,!1):b.initComplete(a,c)},remove:function(a,c,d,e){b.destroyPager(a,c,e)}}),b=c.pager={init:function(d){if(!d.hasInitialized||!d.config.pager.initialized){var e,f=d.config,g=f.widgetOptions,h=g.pager_selectors,i=f.pager=a.extend({totalPages:0,filteredRows:0,filteredPages:0,currentFilters:[],page:g.pager_startPage,startRow:0,endRow:0,ajaxCounter:0,$size:null,last:{},setSize:g.pager_size,setPage:g.pager_startPage,events:"filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete pageSize pageSet pageAndSize pagerUpdate refreshComplete "},f.pager);i.isInitializing||(i.isInitializing=!0,f.debug&&c.log("Pager: Initializing"),i.size=a.data(d,"pagerLastSize")||g.pager_size,i.$container=a(h.container).addClass(g.pager_css.container).show(),i.$goto=i.$container.find(h.gotoPage),i.$size=i.$container.find(h.pageSize),i.totalRows=f.$tbodies.eq(0).children("tr").not(g.pager_countChildRows?"":"."+f.cssChildRow).length,i.oldAjaxSuccess=i.oldAjaxSuccess||g.pager_ajaxObject.success,f.appender=b.appender,i.initializing=!0,g.pager_savePages&&c.storage&&(e=c.storage(d,g.pager_storageKey)||{},i.page=(isNaN(e.page)?i.page:e.page)||i.setPage||0,i.size=(isNaN(e.size)?i.size:e.size)||i.setSize||10,a.data(d,"pagerLastSize",i.size)),i.regexRows=new RegExp("("+(g.filter_filteredRow||"filtered")+"|"+f.selectorRemove.slice(1)+"|"+f.cssChildRow+")"),i.initialized=!1,f.$table.trigger("pagerBeforeInitialized",f),b.enablePager(d,f,!1),i.ajaxObject=g.pager_ajaxObject,i.ajaxObject.url=g.pager_ajaxUrl,"string"==typeof g.pager_ajaxUrl?(i.ajax=!0,g.filter_serversideFiltering=!0,f.serverSideSorting=!0,b.moveToPage(d,i)):(i.ajax=!1,f.$table.trigger("appendCache",[{},!0])))}},initComplete:function(a,d){var e=d.pager;b.bindEvents(a,d),b.setPageSize(a,0,d),e.ajax||b.hideRowsSetup(a,d),e.initialized=!0,e.initializing=!1,e.isInitializing=!1,d.debug&&c.log("Pager: Triggering pagerInitialized"),d.$table.trigger("pagerInitialized",d),d.widgetOptions.filter_initialized&&c.hasWidget(a,"filter")||b.updatePageDisplay(a,d,!e.ajax)},bindEvents:function(d,e){var f,g,h=e.pager,i=e.widgetOptions,j=i.pager_selectors;e.$table.off(a.trim(h.events.split(" ").join(".pager "))).on("filterInit.pager filterStart.pager",function(b,c){h.currentFilters=a.isArray(c)?c:e.$table.data("lastSearch"),"filterStart"===b.type&&i.pager_pageReset!==!1&&(e.lastCombinedFilter||"")!==(h.currentFilters||[]).join("")&&(h.page=i.pager_pageReset)}).on("filterEnd.pager sortEnd.pager",function(){h.currentFilters=e.$table.data("lastSearch"),(h.initialized||h.initializing)&&(e.delayInit&&e.rowsCopy&&0===e.rowsCopy.length&&b.updateCache(d),b.updatePageDisplay(d,e,!1),e.$table.trigger("applyWidgets"))}).on("disable.pager",function(a){a.stopPropagation(),b.showAllRows(d,e)}).on("enable.pager",function(a){a.stopPropagation(),b.enablePager(d,e,!0)}).on("destroy.pager",function(a,c){a.stopPropagation(),b.destroyPager(d,e,c)}).on("updateComplete.pager",function(a,c,d){if(a.stopPropagation(),c&&!d&&!h.ajax){var f=e.$tbodies.eq(0).children("tr").not(e.selectorRemove);h.totalRows=f.length-(i.pager_countChildRows?0:f.filter("."+e.cssChildRow).length),h.totalPages=Math.ceil(h.totalRows/h.size),f.length&&e.rowsCopy&&0===e.rowsCopy.length&&b.updateCache(c),h.page>=h.totalPages&&b.moveToLastPage(c,h),b.hideRows(c,e),b.changeHeight(c,e),b.updatePageDisplay(c,e,!1),e.$table.trigger("applyWidgets"),b.updatePageDisplay(c,e)}}).on("pageSize.pager refreshComplete.pager",function(a,c){a.stopPropagation(),b.setPageSize(d,parseInt(c,10)||h.setSize||10,e),b.hideRows(d,e),b.updatePageDisplay(d,e,!1)}).on("pageSet.pager pagerUpdate.pager",function(a,c){a.stopPropagation(),"pagerUpdate"===a.type&&(c="undefined"==typeof c?h.page+1:c,h.last.page=!0),h.page=(parseInt(c,10)||1)-1,b.moveToPage(d,h,!0),b.updatePageDisplay(d,e,!1)}).on("pageAndSize.pager",function(a,c,f){a.stopPropagation(),h.page=(parseInt(c,10)||1)-1,b.setPageSize(d,parseInt(f,10)||h.setSize||10,e),b.moveToPage(d,h,!0),b.hideRows(d,e),b.updatePageDisplay(d,e,!1)}),f=[j.first,j.prev,j.next,j.last],g=["moveToFirstPage","moveToPrevPage","moveToNextPage","moveToLastPage"],e.debug&&!h.$container.length&&c.log("Pager: >> Container not found"),h.$container.find(f.join(",")).attr("tabindex",0).off("click.pager").on("click.pager",function(c){c.stopPropagation();var e,j=a(this),k=f.length;if(!j.hasClass(i.pager_css.disabled))for(e=0;k>e;e++)if(j.is(f[e])){b[g[e]](d,h);break}}),h.$goto.length?h.$goto.off("change.pager").on("change.pager",function(){h.page=a(this).val()-1,b.moveToPage(d,h,!0),b.updatePageDisplay(d,e,!1)}):e.debug&&c.log("Pager: >> Goto selector not found"),h.$size.length?(h.$size.find("option").removeAttr("selected"),h.$size.off("change.pager").on("change.pager",function(){return h.$size.val(a(this).val()),a(this).hasClass(i.pager_css.disabled)||(b.setPageSize(d,parseInt(a(this).val(),10),e),b.changeHeight(d,e)),!1})):e.debug&&c.log("Pager: >> Size selector not found")},pagerArrows:function(a,b){var c=a.pager,d=!!b,e=d||0===c.page,f=Math.min(c.totalPages,c.filteredPages),g=d||c.page===f-1||0===f,h=a.widgetOptions,i=h.pager_selectors;h.pager_updateArrows&&(c.$container.find(i.first+","+i.prev).toggleClass(h.pager_css.disabled,e).attr("aria-disabled",e),c.$container.find(i.next+","+i.last).toggleClass(h.pager_css.disabled,g).attr("aria-disabled",g))},calcFilters:function(b,c){var d,e,f,g=c.widgetOptions,h=c.pager,i=c.$table.hasClass("hasFilters");if(i&&!g.pager_ajaxUrl)if(a.isEmptyObject(c.cache))h.filteredRows=h.totalRows=c.$tbodies.eq(0).children("tr").not(g.pager_countChildRows?"":"."+c.cssChildRow).length;else for(h.filteredRows=0,d=c.cache[0].normalized,f=d.length,e=0;f>e;e++)h.filteredRows+=h.regexRows.test(d[e][c.columns].$row[0].className)?0:1;else i||(h.filteredRows=h.totalRows)},updatePageDisplay:function(d,e,f){if(!e.pager.initializing){var g,h,i,j,k,l,m=e.widgetOptions,n=e.pager,o=n.size||n.setSize||10;if(m.pager_countChildRows&&h.push(e.cssChildRow),n.$size.add(n.$goto).removeClass(m.pager_css.disabled).removeAttr("disabled").attr("aria-disabled","false"),n.totalPages=Math.ceil(n.totalRows/o),e.totalRows=n.totalRows,b.calcFilters(d,e),e.filteredRows=n.filteredRows,n.filteredPages=Math.ceil(n.filteredRows/o)||0,Math.min(n.totalPages,n.filteredPages)>=0){if(h=n.size*n.page>n.filteredRows&&f,n.page=h?m.pager_pageReset||0:n.page,n.startRow=h?n.size*n.page+1:0===n.filteredRows?0:n.size*n.page+1,n.endRow=Math.min(n.filteredRows,n.totalRows,n.size*(n.page+1)),i=n.$container.find(m.pager_selectors.pageDisplay),g=(n.ajaxData&&n.ajaxData.output?n.ajaxData.output||m.pager_output:m.pager_output).replace(/\{page([\-+]\d+)?\}/gi,function(a,b){return n.totalPages?n.page+(b?parseInt(b,10):1):0}).replace(/\{\w+(\s*:\s*\w+)?\}/gi,function(a){var b,c,d=a.replace(/[{}\s]/g,""),e=d.split(":"),f=n.ajaxData,g=/(rows?|pages?)$/i.test(d)?0:"";return/(startRow|page)/.test(e[0])&&"input"===e[1]?(b=(""+("page"===e[0]?n.totalPages:n.totalRows)).length,c="page"===e[0]?n.page+1:n.startRow,''):e.length>1&&f&&f[e[0]]?f[e[0]][e[1]]:n[d]||(f?f[d]:g)||g}),n.$goto.length){for(h="",j=b.buildPageSelect(n,e),l=j.length,k=0;l>k;k++)h+='";n.$goto.html(h).val(n.page+1)}i.length&&(i["INPUT"===i[0].nodeName?"val":"html"](g),i.find(".ts-startRow, .ts-page").off("change.pager").on("change.pager",function(){var b=a(this).val(),c=a(this).hasClass("ts-startRow")?Math.floor(b/n.size)+1:b;e.$table.trigger("pageSet.pager",[c])}))}b.pagerArrows(e),b.fixHeight(d,e),n.initialized&&f!==!1&&(e.debug&&c.log("Pager: Triggering pagerComplete"),e.$table.trigger("pagerComplete",e),m.pager_savePages&&c.storage&&c.storage(d,m.pager_storageKey,{page:n.page,size:n.size}))}},buildPageSelect:function(b,c){var d,e,f,g,h,i,j=c.widgetOptions,k=Math.min(b.totalPages,b.filteredPages)||1,l=5*Math.ceil(k/j.pager_maxOptionSize/5),m=k>j.pager_maxOptionSize,n=b.page+1,o=l,p=k-l,q=[1],r=m?l:1;for(d=r;k>=d;)q.push(d),d+=m?l:1;if(q.push(k),m){for(f=[],e=Math.max(Math.floor(j.pager_maxOptionSize/l)-1,5),o=n-e,1>o&&(o=1),p=n+e,p>k&&(p=k),d=o;p>=d;d++)f.push(d);q=a.grep(q,function(b,c){return a.inArray(b,q)===c}),h=q.length,i=f.length,h-i>l/2&&h+i>j.pager_maxOptionSize&&(g=Math.floor(h/2)-Math.floor(i/2),Array.prototype.splice.apply(q,[g,i])),q=q.concat(f)}return q=a.grep(q,function(b,c){return a.inArray(b,q)===c}).sort(function(a,b){return a-b})},fixHeight:function(b,c){var d,e,f=c.pager,g=c.widgetOptions,h=c.$tbodies.eq(0);h.find("tr.pagerSavedHeightSpacer").remove(),g.pager_fixedHeight&&!f.isDisabled&&(e=a.data(b,"pagerSavedHeight"),e&&(d=e-h.height(),d>5&&a.data(b,"pagerLastSize")===f.size&&h.children("tr:visible").length')))},changeHeight:function(c,d){var e,f=d.$tbodies.eq(0);f.find("tr.pagerSavedHeightSpacer").remove(),f.children("tr:visible").length||f.append(' '),e=f.children("tr").eq(0).height()*d.pager.size,a.data(c,"pagerSavedHeight",e),b.fixHeight(c,d),a.data(c,"pagerLastSize",d.pager.size)},hideRows:function(a,b){if(!b.widgetOptions.pager_ajaxUrl){var d,e=0,f=b.pager,g=b.widgetOptions,h=b.$tbodies.eq(0).children("tr"),i=h.length,j=f.page*f.size,k=j+f.size,l=g&&g.filter_filteredRow||"filtered",m=0,n=0;for(f.cacheIndex=[],d=0;i>d;d++)h[d].className.match(l)||(n===j&&h[d].className.match(b.cssChildRow)?h[d].style.display="none":(h[d].style.display=n>=j&&k>n?"":"none",m!==n&&n>=j&&k>n&&(f.cacheIndex.push(d),m=n),n+=h[d].className.match(b.cssChildRow+"|"+b.selectorRemove.slice(1))&&!g.pager_countChildRows?0:1,n===k&&"none"!==h[d].style.display&&h[d].className.match(c.css.cssHasChild)&&(e=d)));if(e>0&&h[e].className.match(c.css.cssHasChild))for(;++e> Ajax Error",g,h),c.showError(e,h.message+" ("+g.status+")"),f.$tbodies.eq(0).children("tr").detach(),i.totalRows=0;else{if(a.isArray(A)?(m=isNaN(A[0])&&!isNaN(A[1]),w=A[m?1:0],i.totalRows=isNaN(w)?i.totalRows||0:w,f.totalRows=f.filteredRows=i.filteredRows=i.totalRows,u=0===i.totalRows?[""]:A[m?0:1]||[],t=A[2]):(i.ajaxData=A,f.totalRows=i.totalRows=A.total,f.filteredRows=i.filteredRows="undefined"!=typeof A.filteredRows?A.filteredRows:A.total,t=A.headers,u=A.rows),v=u&&u.length,u instanceof jQuery)j.pager_processAjaxOnInit&&(f.$tbodies.eq(0).children("tr").detach(),f.$tbodies.eq(0).append(u));else if(v){for(k=0;v>k;k++){for(z+="",l=0;l"+u[k][l]+"";z+=""}j.pager_processAjaxOnInit&&f.$tbodies.eq(0).html(z)}if(j.pager_processAjaxOnInit=!0,t&&t.length===B)for(n=y.hasClass("hasStickyHeaders"),p=n?j.$sticky.children("thead:first").children("tr").children():"",o=y.find("tfoot tr:first").children(),q=f.$headers.filter("th "),x=q.length,l=0;x>l;l++)r=q.eq(l),r.find("."+c.css.icon).length?(s=r.find("."+c.css.icon).clone(!0),r.find(".tablesorter-header-inner").html(t[l]).append(s),n&&p.length&&(s=p.eq(l).find("."+c.css.icon).clone(!0),p.eq(l).find(".tablesorter-header-inner").html(t[l]).append(s))):(r.find(".tablesorter-header-inner").html(t[l]),n&&p.length&&p.eq(l).find(".tablesorter-header-inner").html(t[l])),o.eq(l).html(t[l])}f.showProcessing&&c.isProcessing(e),i.totalPages=Math.ceil(i.totalRows/(i.size||i.setSize||10)),i.last.totalRows=i.totalRows,i.last.currentFilters=i.currentFilters,i.last.sortList=(f.sortList||[]).join(","),i.initializing=!1,b.updatePageDisplay(e,f,!1),y.trigger("updateCache",[function(){i.initialized&&setTimeout(function(){f.debug&&c.log("Pager: Triggering pagerChange"),y.trigger("applyWidgets").trigger("pagerChange",i),b.updatePageDisplay(e,f)},0)}])}i.initialized||f.$table.trigger("applyWidgets")},getAjax:function(d,e){var f,g=b.getAjaxUrl(d,e),h=a(document),i=e.pager;""!==g&&(e.showProcessing&&c.isProcessing(d,!0),h.on("ajaxError.pager",function(a,c,f,g){b.renderAjax(null,d,e,c,g),h.off("ajaxError.pager")}),f=++i.ajaxCounter,i.last.ajaxUrl=g,i.ajaxObject.url=g,i.ajaxObject.success=function(a,c,g){fe;e++)n.push(l+"["+j[e][0]+"]="+j[e][1]);i=i.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g,n.length?n.join("&"):l),n=[]}if(m){for(m=m[1],f=k.length,e=0;f>e;e++)k[e]&&n.push(m+"["+e+"]="+encodeURIComponent(k[e]));i=i.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g,n.length?n.join("&"):m),g.currentFilters=k}return a.isFunction(h.pager_customAjaxUrl)&&(i=h.pager_customAjaxUrl(b,i)),d.debug&&c.log("Pager: Ajax url = "+i),i},renderTable:function(a,d){var e,f,g,h,i=a.config,j=i.pager,k=i.widgetOptions,l=i.$table.hasClass("hasFilters"),m=d&&d.length||0,n=j.page*j.size,o=j.size;if(1>m)return void(i.debug&&c.log("Pager: >> No rows for pager to render"));if(j.page>=j.totalPages)return b.moveToLastPage(a,j);if(j.cacheIndex=[],j.isDisabled=!1,j.initialized&&(i.debug&&c.log("Pager: Triggering pagerChange"),i.$table.trigger("pagerChange",i)),k.pager_removeRows){for(c.clearTableBody(a),e=c.processTbody(a,i.$tbodies.eq(0),!0),f=l?0:n,g=l?0:n,h=0;o>h&&fn&&o>=h&&(h++,j.cacheIndex.push(f),e.append(d[f]))),f++;c.processTbody(a,e,!1)}else b.hideRows(a,i);b.updatePageDisplay(a,i),k.pager_startPage=j.page,k.pager_size=j.size,a.isUpdating&&(i.debug&&c.log("Pager: Triggering updateComplete"),i.$table.trigger("updateComplete",[a,!0]))},showAllRows:function(d,e){var f,g,h,i=e.pager,j=e.widgetOptions;for(i.ajax?b.pagerArrows(e,!0):(i.isDisabled=!0,a.data(d,"pagerLastPage",i.page),a.data(d,"pagerLastSize",i.size),i.page=0,i.size=i.totalRows,i.totalPages=1,e.$table.addClass("pagerDisabled").removeAttr("aria-describedby").find("tr.pagerSavedHeightSpacer").remove(),b.renderTable(d,e.rowsCopy),e.$table.trigger("applyWidgets"),e.debug&&c.log("Pager: Disabled")),g=i.$size.add(i.$goto).add(i.$container.find(".ts-startRow, .ts-page ")),h=g.length,f=0;h>f;f++)g.eq(f).attr("aria-disabled","true").addClass(j.pager_css.disabled)[0].disabled=!0},updateCache:function(c){var d=c.config,e=d.pager;d.$table.trigger("updateCache",[function(){if(!a.isEmptyObject(c.config.cache)){var f,g=[],h=c.config.cache[0].normalized;for(e.totalRows=h.length,f=0;fg-1&&0!==g&&(e.page=g-1),j.currentFilters=""===(j.currentFilters||[]).join("")?[]:j.currentFilters,e.currentFilters=""===(e.currentFilters||[]).join("")?[]:e.currentFilters,(j.page!==e.page||j.size!==e.size||j.totalRows!==e.totalRows||(j.currentFilters||[]).join(",")!==(e.currentFilters||[]).join(",")||(j.ajaxUrl||"")!==(e.ajaxObject.url||"")||(j.optAjaxUrl||"")!==(i.pager_ajaxUrl||"")||j.sortList!==(h.sortList||[]).join(","))&&(h.debug&&c.log("Pager: Changing to page "+e.page),e.last={page:e.page,size:e.size,sortList:(h.sortList||[]).join(","),totalRows:e.totalRows,currentFilters:e.currentFilters||[],ajaxUrl:e.ajaxObject.url||"",optAjaxUrl:i.pager_ajaxUrl},e.ajax?b.getAjax(d,h):e.ajax||b.renderTable(d,h.rowsCopy),a.data(d,"pagerLastPage",e.page),e.initialized&&f!==!1&&(h.debug&&c.log("Pager: Triggering pageMoved"),h.$table.trigger("pageMoved",h).trigger("applyWidgets"),!e.ajax&&d.isUpdating&&(h.debug&&c.log("Pager: Triggering updateComplete"),h.$table.trigger("updateComplete",[d,!0])))))}},setPageSize:function(c,d,e){var f=e.pager;f.size=d||f.size||f.setSize||10,f.$size.val(f.size),a.data(c,"pagerLastPage",f.page),a.data(c,"pagerLastSize",f.size),f.totalPages=Math.ceil(f.totalRows/f.size),f.filteredPages=Math.ceil(f.filteredRows/f.size),b.moveToPage(c,f,!0)},moveToFirstPage:function(a,c){c.page=0,b.moveToPage(a,c,!0)},moveToLastPage:function(a,c){c.page=Math.min(c.totalPages,c.filteredPages)-1,b.moveToPage(a,c,!0)},moveToNextPage:function(a,c){c.page++,c.page>=Math.min(c.totalPages,c.filteredPages)-1&&(c.page=Math.min(c.totalPages,c.filteredPages)-1),b.moveToPage(a,c,!0)},moveToPrevPage:function(a,c){c.page--,c.page<=0&&(c.page=0),b.moveToPage(a,c,!0)},destroyPager:function(d,e,f){var g=e.pager;g.initialized=!1,e.$table.off(a.trim(g.events.split(" ").join(".pager "))),f||(b.showAllRows(d,e),g.$container.hide(),e.appender=null,delete d.config.rowsCopy,c.storage&&c.storage(d,e.widgetOptions.pager_storageKey,""))},enablePager:function(d,e,f){var g,h=e.pager;h.isDisabled=!1,h.page=a.data(d,"pagerLastPage")||h.page||0,h.size=a.data(d,"pagerLastSize")||parseInt(h.$size.find("option[selected]").val(),10)||h.size||h.setSize||10,h.$size.val(h.size),h.totalPages=Math.ceil(Math.min(h.totalRows,h.filteredRows)/h.size),e.$table.removeClass("pagerDisabled"),d.id&&(g=d.id+"_pager_info",h.$container.find(e.widgetOptions.pager_selectors.pageDisplay).attr("id",g),e.$table.attr("aria-describedby",g)),b.changeHeight(d,e),f&&(e.$table.trigger("updateRows"),b.setPageSize(d,h.size,e),b.hideRowsSetup(d,e),e.debug&&c.log("Pager: Enabled"))},appender:function(c,d){var e=c.config,f=e.widgetOptions,g=e.pager;g.ajax?b.moveToPage(c,g,!0):(e.rowsCopy=d,g.totalRows=f.pager_countChildRows?e.$tbodies.eq(0).children("tr").length:d.length,g.size=a.data(c,"pagerLastSize")||g.size||f.pager_size||g.setSize||10,g.totalPages=Math.ceil(g.totalRows/g.size),b.moveToPage(c,g),b.updatePageDisplay(c,e,!1))}},c.showError=function(b,c){var d,e,f,g,h,i=a(b),j=i.length;for(d=0;j>d;d++)f=i[d].config,f&&(g=f.widgetOptions,h=f.pager&&f.pager.cssErrorRow||g.pager_css&&g.pager_css.errorRow||"tablesorter-errorRow","undefined"==typeof c?f.$table.find("thead").find(f.selectorRemove).remove():e=a(/tr\>/.test(c)?c:''+c+"").click(function(){a(this).remove()}).appendTo(f.$table.find("thead:first")).addClass(h+" "+f.selectorRemove.slice(1)).attr({role:"alert","aria-live":"assertive"}))}}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-print.min.js b/dist/js/widgets/widget-print.min.js new file mode 100644 index 0000000..ab123ca --- /dev/null +++ b/dist/js/widgets/widget-print.min.js @@ -0,0 +1 @@ +!function(a){"use strict";var b=a.tablesorter,c=b.printTable={event:"printTable",basicStyle:"table, tr, td, th { border : solid 1px black; border-collapse : collapse; } td, th { padding: 2px; }",init:function(a){a.$table.unbind(c.event).bind(c.event,function(){c.process(a,a.widgetOptions)})},process:function(b,d){var e,f=a("
    ").append(b.$table.clone()),g=c.basicStyle+"table { width: 100% }.tablesorter-filter-row { display: none }.tablesorter-header { background-image: none !important; }";f.find("["+d.print_dataAttrib+"]").each(function(){e=a(this),e.text(e.attr(d.print_dataAttrib))}),/a/i.test(d.print_rows)?g+="tbody tr { display: table-row !important; }":/f/i.test(d.print_rows)&&(g+="tbody tr:not(."+(d.filter_filteredRow||"filtered")+") { display: table-row !important; }"),/s/i.test(d.print_columns)&&b.selector&&b.widgets.indexOf("columnSelector")>=0?g+=d.columnSelector_mediaquery&&b.selector.auto?"":b.selector.$style.text():/a/i.test(d.print_columns)&&(g+="td, th { display: table-cell !important; }"),g+=d.print_extraCSS,a.isFunction(d.print_callback)?d.print_callback(b,f,g):c.printOutput(b,f.html(),g)},printOutput:function(a,b,c){var d=a.widgetOptions,e=window.open("",d.print_title,"width=500,height=300"),f=d.print_title||a.$table.find("caption").text()||a.$table[0].id||document.title||"table";return e.document.write(""+f+""+(d.print_styleSheet?'':"")+""+b+""),e.document.close(),e.print(),e.close(),!0},remove:function(a){a.$table.off(c.event)}};b.addWidget({id:"print",options:{print_title:"",print_dataAttrib:"data-name",print_rows:"filtered",print_columns:"selected",print_extraCSS:"",print_styleSheet:"",print_callback:null},init:function(a,b,d){c.init(d)},remove:function(a,b){c.remove(b)}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-reflow.min.js b/dist/js/widgets/widget-reflow.min.js new file mode 100644 index 0000000..80f20af --- /dev/null +++ b/dist/js/widgets/widget-reflow.min.js @@ -0,0 +1 @@ +!function(a){"use strict";var b=a.tablesorter,c={init:function(b,d,e){var f,g=e.reflow_dataAttrib,h=e.reflow_headerAttrib,i=[];d.$table.addClass(e.reflow_className).off("refresh.tsreflow updateComplete.tsreflow2").on("refresh.tsreflow updateComplete.tsreflow2",function(){c.init(b,d,e)}),d.$headers.each(function(){f=a(this),i.push(a.trim(f.attr(h)||f.text()))}),d.$tbodies.children().each(function(){a(this).children().each(function(b){a(this).attr(g,i[b])})})},init2:function(d,e,f){var g,h,i,j,k,l,m=e.columns,n=f.reflow2_headerAttrib,o=[];for(e.$table.addClass(f.reflow2_className).off("refresh.tsreflow2 updateComplete.tsreflow2").on("refresh.tsreflow2 updateComplete.tsreflow2",function(){c.init2(d,e,f)}),i=0;m>i;i++)j=e.$headers.filter('[data-column="'+i+'"]'),j.length>1?(k=[],j.each(function(){g=a(this),g.hasClass(f.reflow2_classIgnore)||k.push(g.attr(n)||g.text())})):k=[j.attr(n)||j.text()],o.push(k);k='=0;)g.prepend(k+(0===i&&l>1?" "+f.reflow2_labelTop:"")+'">'+o[b][i]+""),i--}),b.processTbody(d,h,!1)})},remove:function(a,b,c){b.$table.removeClass(c.reflow_className)},remove2:function(a,b,c){b.$table.removeClass(c.reflow2_className)}};b.addWidget({id:"reflow",options:{reflow_className:"ui-table-reflow",reflow_headerAttrib:"data-name",reflow_dataAttrib:"data-title"},init:function(a,b,d,e){c.init(a,d,e)},remove:function(a,b,d){c.remove(a,b,d)}}),b.addWidget({id:"reflow2",options:{reflow2_className:"ui-table-reflow",reflow2_classIgnore:"ui-table-reflow-ignore",reflow2_headerAttrib:"data-name",reflow2_labelClass:"ui-table-cell-label",reflow2_labelTop:"ui-table-cell-label-top"},init:function(a,b,d,e){c.init2(a,d,e)},remove:function(a,b,d){c.remove2(a,b,d)}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-repeatheaders.min.js b/dist/js/widgets/widget-repeatheaders.min.js new file mode 100644 index 0000000..8f89c32 --- /dev/null +++ b/dist/js/widgets/widget-repeatheaders.min.js @@ -0,0 +1,2 @@ +/*! Widget: repeatHeaders - updated 2/7/2015 (v2.19.0) */ +!function(a){"use strict";a.tablesorter.addWidget({id:"repeatHeaders",priority:10,options:{rowsToSkip:4},format:function(b,c,d){var e,f,g,h,i="";if(!d.repeatHeaders){for(i='',e=0;e"+a.trim(c.$headers.eq(e).text())+"";d.repeatHeaders=i+""}for(h=d&&d.rowsToSkip||4,c.$table.find("tr.repeated-header").remove(),f=c.$tbodies.find("tr"),g=f.length,e=h;g>e;e+=h)f.eq(e).before(d.repeatHeaders)},remove:function(a,b,c){c.repeatHeaders="",b.$table.find("tr.repeated-header").remove()}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-resizable.min.js b/dist/js/widgets/widget-resizable.min.js new file mode 100644 index 0000000..88fbb9b --- /dev/null +++ b/dist/js/widgets/widget-resizable.min.js @@ -0,0 +1,2 @@ +/*! Widget: resizable - updated 5/17/2015 (v2.22.0) */ +!function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{resizableContainer:"tablesorter-resizable-container",resizableHandle:"tablesorter-resizable-handle",resizableNoSelect:"tablesorter-disableSelection",resizableStorage:"tablesorter-resizable"}),a(function(){var b="";a(b).appendTo("body")}),c.resizable={init:function(b,d){if(!b.$table.hasClass("hasResizable")){b.$table.addClass("hasResizable"),c.resizableReset(b.table,!0),d.resizable_={$wrap:b.$table.parent(),mouseXPosition:0,$target:null,$next:null,overflow:"auto"===b.$table.parent().css("overflow"),fullWidth:Math.abs(b.$table.parent().width()-b.$table.width())<20,storedSizes:[]};var e,f,g,h,i=parseInt(b.$table.css("margin-top"),10);for(d.resizable_.storedSizes=h=(c.storage&&d.resizable!==!1?c.storage(b.table,c.css.resizableStorage):[])||[],c.resizable.setWidths(b,d,h),d.$resizable_container=a('
    ').css({top:i}).insertBefore(b.$table),g=0;g').appendTo(d.$resizable_container).attr({"data-column":g,unselectable:"on"}).data("header",f).bind("selectstart",!1);b.$table.one("tablesorter-initialized",function(){c.resizable.setHandlePosition(b,d),c.resizable.bindings(this.config,this.config.widgetOptions)})}},setWidth:function(a,b){a.css({width:b,"min-width":"","max-width":""})},setWidths:function(b,d,e){var f,g=a(b.namespace+"_extra_headers"),h=b.$table.children("colgroup").children("col");if(e=e||d.resizable_.storedSizes||[],e.length){for(f=0;ff||f===h&&d.resizable_addLastColumn)&&c.css({display:"inline-block",height:g,left:j.position().left-e+j.outerWidth()-i}):c.hide())})},toggleTextSelection:function(b,d){var e=b.namespace+"tsresize";b.widgetOptions.resizable_.disabled=d,a("body").toggleClass(c.css.resizableNoSelect,d),d?a("body").attr("unselectable","on").bind("selectstart"+e,!1):a("body").removeAttr("unselectable").unbind("selectstart"+e)},bindings:function(d,e){var f=d.namespace+"tsresize";e.$resizable_container.children().bind("mousedown",function(b){var f,g,h=e.resizable_,i=a(d.namespace+"_extra_headers"),j=a(b.target).data("header");for(f=parseInt(j.attr("data-column"),10),h.$target=j=j.add(i.filter('[data-column="'+f+'"]')),h.target=f,h.$next=b.shiftKey||e.resizable_targetLast?j.parent().children().not(".resizable-false").filter(":last"):j.nextAll(":not(.resizable-false)").eq(0),f=parseInt(h.$next.attr("data-column"),10),h.$next=h.$next.add(i.filter('[data-column="'+f+'"]')),h.next=f,h.mouseXPosition=b.pageX,h.storedSizes=[],f=0;f0?d.sortList=k:c.hasInitialized&&k&&k.length>0&&i.trigger("sorton",[k]))},remove:function(a,c){c.$table.removeClass("hasSaveSort"),b.storage&&b.storage(a,"tablesorter-savesort","")}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-scroller.min.js b/dist/js/widgets/widget-scroller.min.js new file mode 100644 index 0000000..f1a2102 --- /dev/null +++ b/dist/js/widgets/widget-scroller.min.js @@ -0,0 +1,2 @@ +/*! Widget: scroller - updated 5/17/2015 (v2.22.0) */ +!function(a,b){"use strict";var c=a.tablesorter,d=c.css;a.extend(c.css,{scrollerWrap:"tablesorter-scroller",scrollerHeader:"tablesorter-scroller-header",scrollerTable:"tablesorter-scroller-table",scrollerFooter:"tablesorter-scroller-footer",scrollerFixed:"tablesorter-scroller-fixed",scrollerFixedPanel:"tablesorter-scroller-fixed-panel",scrollerHasFix:"tablesorter-scroller-has-fixed-columns",scrollerHideColumn:"tablesorter-scroller-hidden-column",scrollerHideElement:"tablesorter-scroller-hidden",scrollerSpacerRow:"tablesorter-scroller-spacer",scrollerBarSpacer:"tablesorter-scroller-bar-spacer",scrollerAddedHeight:"tablesorter-scroller-added-height",scrollerHack:"tablesorter-scroller-scrollbar-hack",scrollerReset:"tablesorter-scroller-reset",scrollerRtl:"ts-scroller-rtl"}),c.addWidget({id:"scroller",priority:60,options:{scroller_height:300,scroller_jumpToHeader:!0,scroller_upAfterSort:!0,scroller_fixedColumns:0,scroller_rowHighlight:"hover",scroller_addFixedOverlay:!1,scroller_barWidth:null},format:function(a,b,d){b.isScrolling||c.scroller.setup(b,d)},remove:function(a,b,d){c.scroller.remove(b,d)}}),c.window_resize=function(){c.timer_resize&&clearTimeout(c.timer_resize),c.timer_resize=setTimeout(function(){a(b).trigger("resizeEnd")},250)},a(function(){var b="";a(b).appendTo("body")}),c.scroller={isFirefox:navigator.userAgent.toLowerCase().indexOf("firefox")>-1,isOldIE:document.all&&!b.atob,isSafari:navigator.userAgent.toLowerCase().indexOf("safari")>-1&&-1===navigator.userAgent.toLowerCase().indexOf("chrome"),hasScrollBar:function(a,b){return b?a.get(0).scrollWidth>a.width():a.get(0).scrollHeight>a.height()},setWidth:function(a,b){a.css({width:b,"min-width":b,"max-width":b})},getBarWidth:function(){var b=a("
    ").css({position:"absolute",top:"-9999px",left:0,width:"100px",height:"100px",overflow:"scroll",visibility:"hidden"}).appendTo("body"),c=b[0],d=c.offsetWidth-c.clientWidth;return b.remove(),d},setup:function(e,f){var g,h,i,j,k,l,m,n,o=a(b),p=e.namespace+"tsscroller",q=a(),r=e.namespace.slice(1)+"tsscroller",s=e.$table;f.scroller_calcWidths=[],f.scroller_isBusy=!0,f.scroller_barSetWidth=null!==f.scroller_barWidth?f.scroller_barWidth:c.scroller.getBarWidth()||15,g=f.scroller_height||300,i=a(''+s.children("thead")[0].outerHTML+"
    "),f.scroller_$header=i.addClass(e.namespace.slice(1)+"_extra_table"),j=s.children("tfoot"),j.length&&(q=a('
    ').addClass(e.namespace.slice(1)+"_extra_table").append(j.clone(!0)).wrap('
    '),l=q.children("tfoot").eq(0).children("tr").children()),f.scroller_$footer=q,s.wrap('
    ').before(i).find("."+d.filterRow).addClass(d.filterRowHide),f.scroller_$container=s.parent(),q.length&&s.after(q.parent()),k=i.wrap('
    ').find("."+d.header),s.wrap('
    '),m=s.parent(),c.bindEvents(e.table,k),s.hasClass("hasFilters")&&c.filter.bindSearch(s,i.find("."+d.filter)),s.find("thead").addClass(d.scrollerHideElement),h=m.parent().height(),m.off("scroll"+p).on("scroll"+p,function(){if(f.scroller_jumpToHeader){var b=o.scrollTop()-i.offset().top;0!==a(this).scrollTop()&&h>b&&b>0&&o.scrollTop(i.offset().top)}i.parent().add(q.parent()).scrollLeft(a(this).scrollLeft())}),n="sortEnd setFixedColumnSize updateComplete pagerComplete pagerInitialized columnUpdate ".split(" ").join(p+" "),s.off(n).on("sortEnd"+p,function(){f.scroller_upAfterSort&&s.parent().animate({scrollTop:0},"fast")}).on("setFixedColumnSize"+p,function(a,b){var g=f.scroller_$container;"undefined"==typeof b||isNaN(b)||(f.scroller_fixedColumns=parseInt(b,10)),c.scroller.removeFixed(e,f),b=f.scroller_fixedColumns,b>0&&b'),k=j.find("."+d.scrollerTable),k.children("table").addClass(a.namespace.slice(1)+"_extra_table").attr("id","").children("thead, tfoot").remove(),b.scroller_$fixedColumns=j,l.hasClass(d.scrollerRtl)&&j.addClass(d.scrollerRtl),g=j.find("tr"),h=g.length,e=0;h>e;e++)g.eq(e).children(":gt("+(n-1)+")").remove();if(j.addClass(d.scrollerHideElement).prependTo(m),a.$table.hasClass("hasFilters"))for(g=j.find("."+d.filter).not("."+d.filterDisabled).prop("disabled",!1),c.filter.bindSearch(l,j.find("."+d.filter)),g=m.children("."+d.scrollerHeader).find("."+d.filter),h=g.length,e=0;h>e;e++)g.eq(e).hasClass(d.filterDisabled||"disabled")||g.eq(e).prop("disabled",n>e);for(a.$table.add("."+d.scrollerFooter+" table").children("thead").children("tr."+d.headerRow).children().attr("tabindex",-1),g=b.scroller_$header.add(j.find("."+d.scrollerTable+" table")).children("thead").children("tr."+d.headerRow),h=g.length,e=0;h>e;e++)for(i=g.eq(e).children(),f=0;ff?-1:0);c.bindEvents(a.table,j.find("."+d.header)),c.scroller.bindFixedColumnEvents(a,b),(c.scroller.isFirefox||c.scroller.isOldIE)&&k.wrap('
    ')},bindFixedColumnEvents:function(b,e){var f=c.scroller,g=b.namespace+"tsscrollerFixed",h=((c.hasWidget(b.table,"filter")?"filterEnd":"tablesorter-initialized")+" sortEnd ").split(" ").join(g+" "),i="scroll"+g,j=e.scroller_$fixedColumns.find("."+d.scrollerTable),k=!0,l=!0;b.$table.off(h).on(h,function(){f.updateFixed(b,e,!1),f.resize(b,e)}).parent().off(i).on(i,function(){e.scroller_isBusy||(k||!f.isFirefox)&&(l=!1,j[0].scrollTop=a(this).scrollTop(),setTimeout(function(){l=!0},20))}),j.off(i).on(i,function(){(l||!f.isFirefox)&&(k=!1,b.$table.parent()[0].scrollTop=a(this).scrollTop(),setTimeout(function(){k=!0},20))}).scroll(),""!==e.scroller_rowHighlight&&(h="mouseover mouseleave ".split(" ").join(g+" "),b.$table.off(h,"tbody > tr").on(h,"tbody > tr",function(a){var c=b.$table.children("tbody").children("tr").index(this);j.children("table").children("tbody").children("tr").eq(c).add(this).toggleClass(e.scroller_rowHighlight,"mouseover"===a.type)}),j.find("table").off(h,"tbody > tr").on(h,"tbody > tr",function(a){var c=j.children("table").children("tbody").children("tr"),d=c.index(this);b.$table.children("tbody").children("tr").eq(d).add(this).toggleClass(e.scroller_rowHighlight,"mouseover"===a.type)}))},updateFixed:function(b,e){var f=e.scroller_$container;if(0===e.scroller_fixedColumns)return e.scroller_isBusy=!1,void c.scroller.removeFixed(b,e);if(b.isScrolling){e.scroller_isBusy=!0,f.find("."+d.scrollerFixed).length||c.scroller.setupFixed(b,e);var g,h,i,j,k,l,m,n,o,p,q,r,s,t=b.$table,u=t.parent(),v=e.scroller_$header,w=e.scroller_$footer,x=e.scroller_$container.children("."+d.scrollerTable).children("table").children("tbody"),y=e.scroller_$header.children("thead").children("."+d.headerRow),z=e.scroller_$fixedColumns.addClass(d.scrollerHideElement),A=z.find("."+d.scrollerTable).children("table"),B=A.children("tbody"),C=c.scroller,D=e.scroller_barSetWidth,E=e.scroller_fixedColumns,F=t.hasClass(d.scrollerRtl),G=t.find("tbody td"),H=parseInt(G.css("border-right-width"),10)||1,I=parseInt((G.css("border-spacing")||"").split(/\s/)[0],10)/2||0,J=parseInt(t.css("padding-left"),10)+parseInt(t.css("padding-right"),10)-H,K=e.scroller_calcWidths;for(c.scroller.removeFixed(b,e,!1),g=0;E>g;g++)J+=K[g]+I;for(J=J+2*H-I,C.setWidth(z.add(z.children()),J),C.setWidth(z.children().children("table"),J),t.find("."+d.scrollerSpacerRow).remove(),s='',g=0;g';for(b.$tbodies.eq(0).prepend(s+=""),h=0;hi;i++)k=a(y[i].outerHTML),k.children("td, th").slice(E).remove(),l.append(k);for(m=z.find("thead").children("tr."+d.headerRow).children(),n=z.find(d.scrollerSpacerRow).children(),o=z.find("tfoot").children("tr").eq(0).children(),k=v.children("thead").children("tr").children("td, th"),y=w.children("tfoot").children("tr").children("td, th"),g=0;gg&&(G=m.eq(g).add(n.eq(g)).add(o.eq(g)),C.setWidth(G,K[g])),G=k.eq(g).add(y.eq(g)),C.setWidth(G,K[g]);c.processTbody(A,l,!1)}for(r=c.scroller.hasScrollBar(u)?D:0,(C.isFirefox||C.isOldIE)&&A.css("width",J).parent().css("width",J+r),z.removeClass(d.scrollerHideElement),g=0;E>g;g++)f.children("div").children("table").find("th:nth-child("+(g+1)+"), td:nth-child("+(g+1)+")").addClass(d.scrollerHideColumn);J-=H,q=u.parent().innerWidth()-J,u.width(q),f.children("."+d.scrollerTable).css(F?"right":"left",J),f.children("."+d.scrollerHeader+", ."+d.scrollerFooter).css(F?"right":"left",J+(F&&c.scroller.isSafari?r:0)),v.parent().add(w.parent()).width(q-r),q=c.scroller.hasScrollBar(u,!0),r=q?D:0,!z.find("."+d.scrollerBarSpacer).length&&q?(G=a('
    ').css("height",r+"px"),z.find("."+d.scrollerTable).append(G)):q||z.find("."+d.scrollerBarSpacer).remove(),c.scroller.updateRowHeight(b,e),z.height(f.height()),z.removeClass(d.scrollerHideElement),e.scroller_isBusy=!1}},fixHeight:function(a,b){var c,e,f,g,h,i=a.length;for(c=0;i>c;c++)g=a.eq(c),h=b.eq(c),e=g.height(),f=h.height(),e>f?h.addClass(d.scrollerAddedHeight).height(e):f>e&&g.addClass(d.scrollerAddedHeight).height(f)},updateRowHeight:function(a,b){var e,f,g=b.scroller_$fixedColumns;b.scroller_$container.find("."+d.scrollerAddedHeight).removeClass(d.scrollerAddedHeight).height(""),e=b.scroller_$header.children("thead").children("tr"),f=g.children("."+d.scrollerHeader).children("table").children("thead").children("tr"),c.scroller.fixHeight(e,f),e=b.scroller_$footer.children("tfoot").children("tr"),f=g.children("."+d.scrollerFooter).children("table").children("tfoot").children("tr"),c.scroller.fixHeight(e,f),(c.scroller.isFirefox||c.scroller.isOldIE)&&(g=g.find("."+d.scrollerHack)),e=a.$table.children("tbody").children("tr"),f=g.children("."+d.scrollerTable).children("table").children("tbody").children("tr"),c.scroller.fixHeight(e,f)},removeFixed:function(a,b,c){var e=a.$table,f=b.scroller_$container,g=e.hasClass(d.scrollerRtl);(c||"undefined"==typeof c)&&f.find("."+d.scrollerFixed).remove(),f.find("."+d.scrollerHideColumn).removeClass(d.scrollerHideColumn),f.children(":not(."+d.scrollerFixed+")").css(g?"right":"left",0)},remove:function(c,e){var f=e.scroller_$container,g=c.namespace+"tsscroller";c.$table.off(g).insertBefore(f).find("thead").removeClass(d.scrollerHideElement).children("tr."+d.headerRow).children().attr("tabindex",0).end().find("."+d.filterRow).removeClass(d.scrollerHideElement+" "+d.filterRowHide),c.$table.find("."+d.filter).not("."+d.filterDisabled).prop("disabled",!1),f.remove(),a(b).off(g),c.isScrolling=!1}}}(jQuery,window); \ No newline at end of file diff --git a/dist/js/widgets/widget-staticRow.min.js b/dist/js/widgets/widget-staticRow.min.js new file mode 100644 index 0000000..2473064 --- /dev/null +++ b/dist/js/widgets/widget-staticRow.min.js @@ -0,0 +1,2 @@ +/*! widget: staticRow - updated 2/9/2015 (v2.19.1) */ +!function(a){"use strict";var b=a.tablesorter,c=function(b){var c,d,e,f,g,h=b.config;h&&(d=h.widgetOptions,h.$tbodies.each(function(){c=a(this).children(),g=c.length,c.filter(d.staticRow_class).each(function(){c=a(this),f=c.data(d.staticRow_index),"undefined"!=typeof f?(e=parseFloat(f),f=/%/.test(f)?Math.round(e/100*g):e):f=c.index(),c.data(d.staticRow_data,f)})}))};b.addWidget({id:"staticRow",options:{staticRow_class:".static",staticRow_data:"static-index",staticRow_index:"row-index",staticRow_event:"staticRowsRefresh"},init:function(a,b,d,e){c(a),d.$table.unbind(("updateComplete.tsstaticrows "+e.staticRow_event).replace(/\s+/g," ")).bind("updateComplete.tsstaticrows "+e.staticRow_event,function(){c(a),d.$table.trigger("applyWidgets")})},format:function(b,c,d){var e,f,g,h,i,j,k,l;c.$tbodies.each(function(){for(i=a.tablesorter.processTbody(b,a(this),!0),j=!0,g=0,k=i.children(d.staticRow_class),h=i.children("tr").length-1,l=k.length;j&&l>g;)j=!1,k.each(function(){e=a(this).data(d.staticRow_data),e=e>=h?h:0>e?0:e,e!==a(this).index()&&(j=!0,f=a(this).detach(),e>=h?f.appendTo(i):0===e?f.prependTo(i):f.insertBefore(i.find("tr:eq("+e+")")))}),g++;a.tablesorter.processTbody(b,i,!1)}),c.$table.trigger("staticRowsComplete",b)},remove:function(a,b,c){b.$table.unbind(("updateComplete.tsstaticrows "+c.staticRow_event).replace(/\s+/g," "))}})}(jQuery); \ No newline at end of file diff --git a/dist/js/widgets/widget-stickyHeaders.min.js b/dist/js/widgets/widget-stickyHeaders.min.js new file mode 100644 index 0000000..4a15a61 --- /dev/null +++ b/dist/js/widgets/widget-stickyHeaders.min.js @@ -0,0 +1,2 @@ +/*! Widget: stickyHeaders - updated 3/26/2015 (v2.21.3) */ +!function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),c.addHeaderResizeEvent=function(b,c,d){if(b=a(b)[0],b.config){var e={timer:250},f=a.extend({},e,d),g=b.config,h=g.widgetOptions,i=function(a){var b,c,d,e,f,i,j=g.$headers.length;for(h.resize_flag=!0,c=[],b=0;j>b;b++)d=g.$headers.eq(b),e=d.data("savedSizes")||[0,0],f=d[0].offsetWidth,i=d[0].offsetHeight,(f!==e[0]||i!==e[1])&&(d.data("savedSizes",[f,i]),c.push(d[0]));c.length&&a!==!1&&g.$table.trigger("resize",[c]),h.resize_flag=!1};return i(!1),clearInterval(h.resize_timer),c?(h.resize_flag=!1,!1):void(h.resize_timer=setInterval(function(){h.resize_flag||i()},f.timer))}},c.addWidget({id:"stickyHeaders",priority:60,options:{stickyHeaders:"",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(d,e,f){if(!(e.$table.hasClass("hasStickyHeaders")||a.inArray("filter",e.widgets)>=0&&!e.$table.hasClass("hasFilters"))){var g,h,i,j,k=e.$table,l=a(f.stickyHeaders_attachTo),m=e.namespace+"stickyheaders ",n=a(f.stickyHeaders_yScroll||f.stickyHeaders_attachTo||b),o=a(f.stickyHeaders_xScroll||f.stickyHeaders_attachTo||b),p=k.children("thead:first"),q=p.children("tr").not(".sticky-false").children(),r=k.children("tfoot"),s=isNaN(f.stickyHeaders_offset)?a(f.stickyHeaders_offset):"",t=s.length?s.height()||0:parseInt(f.stickyHeaders_offset,10)||0,u=k.parent().closest("."+c.css.table).hasClass("hasStickyHeaders")?k.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],v=u.length?u.height():0,w=f.$sticky=k.clone().addClass("containsStickyHeaders "+c.css.sticky+" "+f.stickyHeaders+" "+e.namespace.slice(1)+"_extra_table").wrap('
    '),x=w.parent().addClass(c.css.stickyHide).css({position:l.length?"absolute":"fixed",padding:parseInt(w.parent().parent().css("padding-left"),10),top:t+v,left:0,visibility:"hidden",zIndex:f.stickyHeaders_zIndex||2}),y=w.children("thead:first"),z="",A=0,B=function(a,c){var d,e,f,g,h,i=a.filter(":visible"),j=i.length;for(d=0;j>d;d++)g=c.filter(":visible").eq(d),h=i.eq(d),"border-box"===h.css("box-sizing")?e=h.outerWidth():"collapse"===g.css("border-collapse")?b.getComputedStyle?e=parseFloat(b.getComputedStyle(h[0],null).width):(f=parseFloat(h.css("border-width")),e=h.outerWidth()-parseFloat(h.css("padding-left"))-parseFloat(h.css("padding-right"))-f):e=h.width(),g.css({width:e,"min-width":e,"max-width":e})},C=function(){t=s.length?s.height()||0:parseInt(f.stickyHeaders_offset,10)||0,A=0,x.css({left:l.length?parseInt(l.css("padding-left"),10)||0:k.offset().left-parseInt(k.css("margin-left"),10)-o.scrollLeft()-A,width:k.outerWidth()}),B(k,w),B(q,j)},D=function(b){if(k.is(":visible")){v=u.length?u.offset().top-n.scrollTop()+u.height():0;var d=k.offset(),e=a.isWindow(n[0]),f=a.isWindow(o[0]),g=(l.length?e?n.scrollTop():n.offset().top:n.scrollTop())+t+v,h=k.height()-(x.height()+(r.height()||0)),i=g>d.top&&gg;g++)e.onRenderHeader.apply(i.eq(g),[g,e,w]);o.add(n).unbind("scroll resize ".split(" ").join(m).replace(/\s+/g," ")).bind("scroll resize ".split(" ").join(m),function(a){D("resize"===a.type)}),e.$table.unbind("stickyHeadersUpdate"+m).bind("stickyHeadersUpdate"+m,function(){D(!0)}),f.stickyHeaders_addResizeEvent&&c.addHeaderResizeEvent(d),k.hasClass("hasFilters")&&f.filter_columnFilters&&(k.bind("filterEnd"+m,function(){var d=a(document.activeElement).closest("td"),g=d.parent().children().index(d);x.hasClass(c.css.stickyVis)&&f.stickyHeaders_filteredToTop&&(b.scrollTo(0,k.position().top),g>=0&&e.$filters&&e.$filters.eq(g).find("a, select, input").filter(":visible").focus())}),c.filter.bindSearch(k,j.find("."+c.css.filter)),f.filter_hideFilters&&c.filter.hideFilters(w,e)),k.trigger("stickyHeadersInit")}},remove:function(d,e,f){var g=e.namespace+"stickyheaders ";e.$table.removeClass("hasStickyHeaders").unbind("pagerComplete filterEnd stickyHeadersUpdate ".split(" ").join(g).replace(/\s+/g," ")).next("."+c.css.stickyWrap).remove(),f.$sticky&&f.$sticky.length&&f.$sticky.remove(),a(b).add(f.stickyHeaders_xScroll).add(f.stickyHeaders_yScroll).add(f.stickyHeaders_attachTo).unbind("scroll resize ".split(" ").join(g).replace(/\s+/g," ")),c.addHeaderResizeEvent(d,!1)}})}(jQuery,window); \ No newline at end of file diff --git a/dist/js/widgets/widget-storage.min.js b/dist/js/widgets/widget-storage.min.js new file mode 100644 index 0000000..9a0e023 --- /dev/null +++ b/dist/js/widgets/widget-storage.min.js @@ -0,0 +1,2 @@ +/*! Widget: storage - updated 3/26/2015 (v2.21.3) */ +!function(a,b,c){"use strict";var d=a.tablesorter||{};d.storage=function(e,f,g,h){e=a(e)[0];var i,j,k,l=!1,m={},n=e.config,o=n&&n.widgetOptions,p=h&&h.useSessionStorage||o&&o.storage_useSessionStorage?"sessionStorage":"localStorage",q=a(e),r=h&&h.id||q.attr(h&&h.group||o&&o.storage_group||"data-table-group")||o&&o.storage_tableId||e.id||a(".tablesorter").index(q),s=h&&h.url||q.attr(h&&h.page||o&&o.storage_page||"data-table-page")||o&&o.storage_fixedUrl||n&&n.fixedUrl||b.location.pathname;if(p in b)try{b[p].setItem("_tmptest","temp"),l=!0,b[p].removeItem("_tmptest")}catch(t){n&&n.debug&&d.log(p+" is not supported in this browser")}return a.parseJSON&&(l?m=a.parseJSON(b[p][f]||"null")||{}:(j=c.cookie.split(/[;\s|=]/),i=a.inArray(f,j)+1,m=0!==i?a.parseJSON(j[i]||"null")||{}:{})),(g||""===g)&&b.JSON&&JSON.hasOwnProperty("stringify")?(m[s]||(m[s]={}),m[s][r]=g,l?b[p][f]=JSON.stringify(m):(k=new Date,k.setTime(k.getTime()+31536e6),c.cookie=f+"="+JSON.stringify(m).replace(/\"/g,'"')+"; expires="+k.toGMTString()+"; path=/"),void 0):m&&m[s]?m[s][r]:""}}(jQuery,window,document); \ No newline at end of file diff --git a/dist/js/widgets/widget-uitheme.min.js b/dist/js/widgets/widget-uitheme.min.js new file mode 100644 index 0000000..4c803db --- /dev/null +++ b/dist/js/widgets/widget-uitheme.min.js @@ -0,0 +1,2 @@ +/*! Widget: uitheme - updated 3/26/2015 (v2.21.3) */ +!function(a){"use strict";var b=a.tablesorter||{};b.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",sortNone:"",sortAsc:"",sortDesc:"",active:"",hover:"",icons:"",iconSortNone:"bootstrap-icon-unsorted",iconSortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",iconSortDesc:"icon-chevron-down 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",iconSortAsc:"ui-icon-carat-1-n",iconSortDesc:"ui-icon-carat-1-s",filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",odd:"ui-state-default"}},a.extend(b.css,{wrapper:"tablesorter-wrapper"}),b.addWidget({id:"uitheme",priority:10,format:function(c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r=b.themes,s=d.$table.add(a(d.namespace+"_extra_table")),t=d.$headers.add(a(d.namespace+"_extra_headers")),u=d.theme||"jui",v=r[u]||{},w=a.trim([v.sortNone,v.sortDesc,v.sortAsc,v.active].join(" ")),x=a.trim([v.iconSortNone,v.iconSortDesc,v.iconSortAsc].join(" "));for(d.debug&&(i=new Date),s.hasClass("tablesorter-"+u)&&d.theme===d.appliedTheme&&e.uitheme_applied||(e.uitheme_applied=!0,n=r[d.appliedTheme]||{},q=!a.isEmptyObject(n),o=q?[n.sortNone,n.sortDesc,n.sortAsc,n.active].join(" "):"",p=q?[n.iconSortNone,n.iconSortDesc,n.iconSortAsc].join(" "):"",q&&(e.zebra[0]=a.trim(" "+e.zebra[0].replace(" "+n.even,"")),e.zebra[1]=a.trim(" "+e.zebra[1].replace(" "+n.odd,"")),d.$tbodies.children().removeClass([n.even,n.odd].join(" "))),v.even&&(e.zebra[0]+=" "+v.even),v.odd&&(e.zebra[1]+=" "+v.odd),s.children("caption").removeClass(n.caption||"").addClass(v.caption),l=s.removeClass((d.appliedTheme?"tablesorter-"+(d.appliedTheme||""):"")+" "+(n.table||"")).addClass("tablesorter-"+u+" "+(v.table||"")).children("tfoot"),d.appliedTheme=d.theme,l.length&&l.children("tr").removeClass(n.footerRow||"").addClass(v.footerRow).children("th, td").removeClass(n.footerCells||"").addClass(v.footerCells),t.removeClass((q?[n.header,n.hover,o].join(" "):"")||"").addClass(v.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(b){a(this)["mouseenter"===b.type?"addClass":"removeClass"](v.hover||"")}),t.each(function(){var c=a(this);c.find("."+b.css.wrapper).length||c.wrapInner('
    ')}),d.cssIcon&&t.find("."+b.css.icon).removeClass(q?[n.icons,p].join(" "):"").addClass(v.icons||""),s.hasClass("hasFilters")&&s.children("thead").children("."+b.css.filterRow).removeClass(q?n.filterRow||"":"").addClass(v.filterRow||"")),f=0;f + Peter + Parker + 28 + $9.99 + 20% + Jul 6, 2006 8:14 AM + + + John + Hood + 33 + $19.99 + 25% + Dec 10, 2002 5:14 AM + + + Clark + Kent + 18 + $15.89 + 44% + Jan 12, 2003 11:14 AM + + + Bruce + Almighty + 45 + $153.19 + 44% + Jan 18, 2001 9:12 AM + + + Bruce + Evans + 22 + $13.19 + 11% + Jan 18, 2007 9:12 AM + \ No newline at end of file diff --git a/docs/assets/build.json b/docs/assets/build.json new file mode 100644 index 0000000..d5390eb --- /dev/null +++ b/docs/assets/build.json @@ -0,0 +1,37 @@ +{ + "headers": [ + [ + { "text": "First Name", "class": "fname", "width": "20%" }, + "Last Name", + { "text": "Age", "class": "age", "data-sorter": false }, + "Total", + { "text": "Discount", "class": "sorter-false" }, + { "text": "Date", "class": "date", "width": "20%" } + ] + ], + "footers": "clone", + "rows": [ + [ "Peter", "Parker", 28, "$9.99", "20%", "Jul 6, 2006 8:14 AM" ], + [ "John", "Hood", 33, "$19.99", "25%", "Dec 10, 2002 5:14 AM" ], + [ "Clark", "Kent", 18, "$15.89", "44%", "Jan 12, 2003 11:14 AM" ], + + { "newTbody": true, "class": "tablesorter-infoOnly" }, + { "cells": [ { "html": "JSON Info Row", "colspan": 6 } ] }, + + { "newTbody": true }, + [ "Bruce", "Evans", 22, "$13.19", "11%", "Jan 18, 2007 9:12 AM" ], + [ "Brice", "Almighty", 45, "$153.19", "44%", "Jan 18, 2001 9:12 AM" ], + + { "class": "specialRow", + "cells": [ + { "text": "Fred", "class": "fname" }, + { "text": "Smith", "class": "lname" }, + { "text": 18, "class": "age", "data-info": "fake ID!, he's only 16" }, + { "text": "$22.44", "class": "total" }, + "8%", + { "text": "Aug 20, 2012 10:15 AM", "class": "date" } + ], + "data-info": "This row likes turtles" + } + ] +} \ No newline at end of file diff --git a/docs/assets/build.txt b/docs/assets/build.txt new file mode 100644 index 0000000..c24058b --- /dev/null +++ b/docs/assets/build.txt @@ -0,0 +1,9 @@ +Album,Artist,Price ($) +Lateralus,Tool,$13.00 +Aenima,Tool,$12.00 +"10,000 days",Tool,$14.00 +Down In It,Nine Inch Nails,$3.00 +Broken,Nine Inch Nails,$6.00 +Muse,Black Holes and Revelations,$7.00 +Anon,"fake album, with comma", $1.00 +Album,Artist,Price ($) \ No newline at end of file diff --git a/docs/assets/theme_switcher.json b/docs/assets/theme_switcher.json new file mode 100644 index 0000000..12d3144 --- /dev/null +++ b/docs/assets/theme_switcher.json @@ -0,0 +1,303 @@ +[ + { + "theme_name": "base", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/base/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "black-tie", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/black-tie/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "blitzer", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/blitzer/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "cupertino", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/cupertino/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "dark-hive", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/dark-hive/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "dot-luv", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/dot-luv/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "eggplant", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/eggplant/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "excite-bike", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/excite-bike/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "flick", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/flick/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "hot-sneaks", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/hot-sneaks/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "humanity", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/humanity/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "le-frog", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/le-frog/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "mint-choc", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/mint-choc/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "overcast", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/overcast/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "pepper-grinder", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/pepper-grinder/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "redmond", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/redmond/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "smoothness", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "south-street", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/south-street/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "start", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/start/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "sunny", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/sunny/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "swanky-purse", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/swanky-purse/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "trontastic", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/trontastic/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "ui-darkness", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/ui-darkness/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "ui-lightness", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/ui-lightness/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + { + "theme_name": "vader", + "theme_url": "//code.jquery.com/ui/1.11.2/themes/vader/jquery-ui.css", + "group": "Official", + "active": "yes", + "author": "jQuery Project", + "license": "//jquery.org/license" + }, + + { + "theme_name": "aristo", + "theme_url": "//taitems.github.com/Aristo-jQuery-UI-Theme/css/Aristo/Aristo.css", + "group": "3rd-party", + "active": "yes", + "author": "https://github.com/taitems/Aristo-jQuery-UI-Theme", + "license": "MIT" + }, + { + "theme_name": "jquery-ui-bootstrap", + "theme_url": "//jquery-ui-bootstrap.github.io/jquery-ui-bootstrap/css/custom-theme/jquery-ui-1.10.3.custom.css", + "group": "3rd-party", + "active": "yes", + "author": "https://github.com/jquery-ui-bootstrap/jquery-ui-bootstrap", + "license": "Copyright 2012, Addy Osmani - Dual licensed under the MIT or GPL Version 2 licenses" + }, + { + "theme_name": "Absolution", + "hosted_locally": "yes", + "theme_url": "/lib/jquery-ui-1.10.0.custom/css/3rd-party/Absolution/absolution.css", + "group": "3rd-party", + "active": "yes", + "author": "//www.michaelvanderheeren.be/archives/382", + "license": "https://github.com/michaelvanderheeren/Absolution/blob/master/README.md", + "notes": "You are free to redistribute or change the theme. You can change the theme, but you should keep the references to contributors!" + }, + { + "theme_name": "Selene", + "theme_url": "//gravityonmars.github.com/Selene/css/ui-selene/jquery-ui-1.8.17.custom.css", + "group": "3rd-party", + "active": "yes", + "author": "https://github.com/gravityonmars/Selene", + "license": "MIT" + }, + { + "theme_name": "kiandra-delta", + "theme_url": "//kiandra.github.com/Delta-jQuery-UI-Theme/theme/jquery-ui.css", + "group": "3rd-party", + "active": "yes", + "author": "https://github.com/kiandra/Delta-jQuery-UI-Theme", + "license": "Dual licensed under the MIT or GPL Version 2 licenses." + }, + + + { + "theme_name": "arctic", + "theme_url": "//cdn.wijmo.com/themes/arctic/jquery-wijmo.css", + "group": "Wijmo", + "active": "yes", + "author": "//wijmo.com", + "license": "//wijmo.com/license" + }, + { + "theme_name": "midnight", + "theme_url": "//cdn.wijmo.com/themes/midnight/jquery-wijmo.css", + "group": "Wijmo", + "active": "yes", + "author": "//wijmo.com", + "license": "//wijmo.com/license" + }, + { + "theme_name": "rocket", + "theme_url": "//cdn.wijmo.com/themes/rocket/jquery-wijmo.css", + "group": "Wijmo", + "active": "yes", + "author": "//wijmo.com", + "license": "//wijmo.com/license" + }, + { + "theme_name": "cobalt", + "theme_url": "//cdn.wijmo.com/themes/cobalt/jquery-wijmo.css", + "group": "Wijmo", + "active": "yes", + "author": "//wijmo.com", + "license": "//wijmo.com/license" + }, + { + "theme_name": "sterling", + "theme_url": "//cdn.wijmo.com/themes/sterling/jquery-wijmo.css", + "group": "Wijmo", + "active": "yes", + "author": "//wijmo.com", + "license": "//wijmo.com/license" + }, + { + "theme_name": "metro", + "theme_url": "//cdn.wijmo.com/themes/metro/jquery-wijmo.css", + "group": "Wijmo", + "active": "yes", + "author": "//wijmo.com", + "license": "//wijmo.com/license" + }, + { + "theme_name": "metro-dark", + "theme_url": "//cdn.wijmo.com/themes/metro-dark/jquery-wijmo.css", + "group": "Wijmo", + "active": "yes", + "author": "//wijmo.com", + "license": "//wijmo.com/license" + } +] diff --git a/docs/css/bootstrap-v2.min.css b/docs/css/bootstrap-v2.min.css new file mode 100644 index 0000000..c59a666 --- /dev/null +++ b/docs/css/bootstrap-v2.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("images/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("images/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} diff --git a/docs/css/bootstrap.min.css b/docs/css/bootstrap.min.css new file mode 100644 index 0000000..cd1c616 --- /dev/null +++ b/docs/css/bootstrap.min.css @@ -0,0 +1,5 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px \9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.form-group-sm .form-control{height:30px;line-height:30px}select[multiple].form-group-sm .form-control,textarea.form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:5px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.form-group-lg .form-control{height:46px;line-height:46px}select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:10px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.active,.btn-default.focus,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.active,.btn-primary.focus,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.active,.btn-success.focus,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.active,.btn-info.focus,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.active,.btn-warning.focus,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.active,.btn-danger.focus,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px)and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px)and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px)and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file diff --git a/docs/css/images/glyphicons-halflings-white.png b/docs/css/images/glyphicons-halflings-white.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf6484a29d8da269f9bc874b25493a45fae3bae GIT binary patch literal 8777 zcmZvC1yGz#v+m*$LXcp=A$ZWB0fL7wNbp_U*$~{_gL`my3oP#L!5tQYy99Ta`+g_q zKlj|KJ2f@c)ARJx{q*bbkhN_!|Wn*Vos8{TEhUT@5e;_WJsIMMcG5%>DiS&dv_N`4@J0cnAQ-#>RjZ z00W5t&tJ^l-QC*ST1-p~00u^9XJ=AUl7oW-;2a+x2k__T=grN{+1c4XK0ZL~^z^i$ zp&>vEhr@4fZWb380S18T&!0cQ3IKpHF)?v=b_NIm0Q>vwY7D0baZ)n z31Fa5sELUQARIVaU0nqf0XzT+fB_63aA;@<$l~wse|mcA;^G1TmX?-)e)jkGPfkuA z92@|!<>h5S_4f8QP-JRq>d&7)^Yin8l7K8gED$&_FaV?gY+wLjpoW%~7NDe=nHfMG z5DO3j{R9kv5GbssrUpO)OyvVrlx>u0UKD0i;Dpm5S5dY16(DL5l{ixz|mhJU@&-OWCTb7_%}8-fE(P~+XIRO zJU|wp1|S>|J3KrLcz^+v1f&BDpd>&MAaibR4#5A_4(MucZwG9E1h4@u0P@C8;oo+g zIVj7kfJi{oV~E(NZ*h(@^-(Q(C`Psb3KZ{N;^GB(a8NE*Vwc715!9 zr-H4Ao|T_c6+VT_JH9H+P3>iXSt!a$F`>s`jn`w9GZ_~B!{0soaiV|O_c^R2aWa%}O3jUE)WO=pa zs~_Wz08z|ieY5A%$@FcBF9^!1a}m5ks@7gjn;67N>}S~Hrm`4sM5Hh`q7&5-N{|31 z6x1{ol7BnskoViZ0GqbLa#kW`Z)VCjt1MysKg|rT zi!?s##Ck>8c zpi|>$lGlw#@yMNi&V4`6OBGJ(H&7lqLlcTQ&1zWriG_fL>BnFcr~?;E93{M-xIozQ zO=EHQ#+?<}%@wbWWv23#!V70h9MOuUVaU>3kpTvYfc|LBw?&b*89~Gc9i&8tlT#kF ztpbZoAzkdB+UTy=tx%L3Z4)I{zY(Kb)eg{InobSJmNwPZt$14aS-uc4eKuY8h$dtfyxu^a%zA)>fYI&)@ZXky?^{5>xSC?;w4r&td6vBdi%vHm4=XJH!3yL3?Ep+T5aU_>i;yr_XGq zxZfCzUU@GvnoIk+_Nd`aky>S&H!b*{A%L>?*XPAgWL(Vf(k7qUS}>Zn=U(ZfcOc{B z3*tOHH@t5Ub5D~#N7!Fxx}P2)sy{vE_l(R7$aW&CX>c|&HY+7};vUIietK%}!phrCuh+;C@1usp;XLU<8Gq8P!rEI3ieg#W$!= zQcZr{hp>8sF?k&Yl0?B84OneiQxef-4TEFrq3O~JAZR}yEJHA|Xkqd49tR&8oq{zP zY@>J^HBV*(gJvJZc_0VFN7Sx?H7#75E3#?N8Z!C+_f53YU}pyggxx1?wQi5Yb-_`I`_V*SMx5+*P^b=ec5RON-k1cIlsBLk}(HiaJyab0`CI zo0{=1_LO$~oE2%Tl_}KURuX<`+mQN_sTdM&* zkFf!Xtl^e^gTy6ON=&gTn6)$JHQq2)33R@_!#9?BLNq-Wi{U|rVX7Vny$l6#+SZ@KvQt@VYb%<9JfapI^b9j=wa+Tqb4ei;8c5 z&1>Uz@lVFv6T4Z*YU$r4G`g=91lSeA<=GRZ!*KTWKDPR}NPUW%peCUj`Ix_LDq!8| zMH-V`Pv!a~QkTL||L@cqiTz)*G-0=ytr1KqTuFPan9y4gYD5>PleK`NZB$ev@W%t= zkp)_=lBUTLZJpAtZg;pjI;7r2y|26-N7&a(hX|`1YNM9N8{>8JAuv}hp1v`3JHT-=5lbXpbMq7X~2J5Kl zh7tyU`_AusMFZ{ej9D;Uyy;SQ!4nwgSnngsYBwdS&EO3NS*o04)*juAYl;57c2Ly0(DEZ8IY?zSph-kyxu+D`tt@oU{32J#I{vmy=#0ySPK zA+i(A3yl)qmTz*$dZi#y9FS;$;h%bY+;StNx{_R56Otq+?pGe^T^{5d7Gs&?`_r`8 zD&dzOA|j8@3A&FR5U3*eQNBf<4^4W_iS_()*8b4aaUzfk2 zzIcMWSEjm;EPZPk{j{1>oXd}pXAj!NaRm8{Sjz!D=~q3WJ@vmt6ND_?HI~|wUS1j5 z9!S1MKr7%nxoJ3k`GB^7yV~*{n~O~n6($~x5Bu{7s|JyXbAyKI4+tO(zZYMslK;Zc zzeHGVl{`iP@jfSKq>R;{+djJ9n%$%EL()Uw+sykjNQdflkJZSjqV_QDWivbZS~S{K zkE@T^Jcv)Dfm93!mf$XYnCT--_A$zo9MOkPB6&diM8MwOfV?+ApNv`moV@nqn>&lv zYbN1-M|jc~sG|yLN^1R2=`+1ih3jCshg`iP&mY$GMTcY^W^T`WOCX!{-KHmZ#GiRH zYl{|+KLn5!PCLtBy~9i}`#d^gCDDx$+GQb~uc;V#K3OgbbOG0j5{BRG-si%Bo{@lB zGIt+Ain8^C`!*S0d0OSWVO+Z89}}O8aFTZ>p&k}2gGCV zh#<$gswePFxWGT$4DC^8@84_e*^KT74?7n8!$8cg=sL$OlKr&HMh@Rr5%*Wr!xoOl zo7jItnj-xYgVTX)H1=A2bD(tleEH57#V{xAeW_ezISg5OC zg=k>hOLA^urTH_e6*vSYRqCm$J{xo}-x3@HH;bsHD1Z`Pzvsn}%cvfw%Q(}h`Dgtb z0_J^niUmoCM5$*f)6}}qi(u;cPgxfyeVaaVmOsG<)5`6tzU4wyhF;k|~|x>7-2hXpVBpc5k{L4M`Wbe6Q?tr^*B z`Y*>6*&R#~%JlBIitlZ^qGe3s21~h3U|&k%%jeMM;6!~UH|+0+<5V-_zDqZQN79?n?!Aj!Nj`YMO9?j>uqI9-Tex+nJD z%e0#Yca6(zqGUR|KITa?9x-#C0!JKJHO(+fy@1!B$%ZwJwncQW7vGYv?~!^`#L~Um zOL++>4qmqW`0Chc0T23G8|vO)tK=Z2`gvS4*qpqhIJCEv9i&&$09VO8YOz|oZ+ubd zNXVdLc&p=KsSgtmIPLN69P7xYkYQ1vJ?u1g)T!6Ru`k2wkdj*wDC)VryGu2=yb0?F z>q~~e>KZ0d_#7f3UgV%9MY1}vMgF{B8yfE{HL*pMyhYF)WDZ^^3vS8F zGlOhs%g_~pS3=WQ#494@jAXwOtr^Y|TnQ5zki>qRG)(oPY*f}U_=ip_{qB0!%w7~G zWE!P4p3khyW-JJnE>eECuYfI?^d366Shq!Wm#x&jAo>=HdCllE$>DPO0N;y#4G)D2y#B@5=N=+F%Xo2n{gKcPcK2!hP*^WSXl+ut; zyLvVoY>VL{H%Kd9^i~lsb8j4>$EllrparEOJNT?Ym>vJa$(P^tOG)5aVb_5w^*&M0 zYOJ`I`}9}UoSnYg#E(&yyK(tqr^@n}qU2H2DhkK-`2He% zgXr_4kpXoQHxAO9S`wEdmqGU4j=1JdG!OixdqB4PPP6RXA}>GM zumruUUH|ZG2$bBj)Qluj&uB=dRb)?^qomw?Z$X%#D+Q*O97eHrgVB2*mR$bFBU`*} zIem?dM)i}raTFDn@5^caxE^XFXVhBePmH9fqcTi`TLaXiueH=@06sl}>F%}h9H_e9 z>^O?LxM1EjX}NVppaO@NNQr=AtHcH-BU{yBT_vejJ#J)l^cl69Z7$sk`82Zyw7Wxt z=~J?hZm{f@W}|96FUJfy65Gk8?^{^yjhOahUMCNNpt5DJw}ZKH7b!bGiFY9y6OY&T z_N)?Jj(MuLTN36ZCJ6I5Xy7uVlrb$o*Z%=-)kPo9s?<^Yqz~!Z* z_mP8(unFq65XSi!$@YtieSQ!<7IEOaA9VkKI?lA`*(nURvfKL8cX}-+~uw9|_5)uC2`ZHcaeX7L8aG6Ghleg@F9aG%X$#g6^yP5apnB>YTz&EfS{q z9UVfSyEIczebC)qlVu5cOoMzS_jrC|)rQlAzK7sfiW0`M8mVIohazPE9Jzn*qPt%6 zZL8RELY@L09B83@Be;x5V-IHnn$}{RAT#<2JA%ttlk#^(%u}CGze|1JY5MPhbfnYG zIw%$XfBmA-<_pKLpGKwbRF$#P;@_)ech#>vj25sv25VM$ouo)?BXdRcO{)*OwTw)G zv43W~T6ekBMtUD%5Bm>`^Ltv!w4~65N!Ut5twl!Agrzyq4O2Fi3pUMtCU~>9gt_=h-f% z;1&OuSu?A_sJvIvQ+dZNo3?m1%b1+s&UAx?8sUHEe_sB7zkm4R%6)<@oYB_i5>3Ip zIA+?jVdX|zL{)?TGpx+=Ta>G80}0}Ax+722$XFNJsC1gcH56{8B)*)eU#r~HrC&}` z|EWW92&;6y;3}!L5zXa385@?-D%>dSvyK;?jqU2t_R3wvBW;$!j45uQ7tyEIQva;Db}r&bR3kqNSh)Q_$MJ#Uj3Gj1F;)sO|%6z#@<+ zi{pbYsYS#u`X$Nf($OS+lhw>xgjos1OnF^$-I$u;qhJswhH~p|ab*nO>zBrtb0ndn zxV0uh!LN`&xckTP+JW}gznSpU492)u+`f{9Yr)js`NmfYH#Wdtradc0TnKNz@Su!e zu$9}G_=ku;%4xk}eXl>)KgpuT>_<`Ud(A^a++K&pm3LbN;gI}ku@YVrA%FJBZ5$;m zobR8}OLtW4-i+qPPLS-(7<>M{)rhiPoi@?&vDeVq5%fmZk=mDdRV>Pb-l7pP1y6|J z8I>sF+TypKV=_^NwBU^>4JJq<*14GLfM2*XQzYdlqqjnE)gZsPW^E@mp&ww* zW9i>XL=uwLVZ9pO*8K>t>vdL~Ek_NUL$?LQi5sc#1Q-f6-ywKcIT8Kw?C(_3pbR`e|)%9S-({if|E+hR2W!&qfQ&UiF^I!|M#xhdWsenv^wpKCBiuxXbnp85`{i|;BM?Ba`lqTA zyRm=UWJl&E{8JzYDHFu>*Z10-?#A8D|5jW9Ho0*CAs0fAy~MqbwYuOq9jjt9*nuHI zbDwKvh)5Ir$r!fS5|;?Dt>V+@F*v8=TJJF)TdnC#Mk>+tGDGCw;A~^PC`gUt*<(|i zB{{g{`uFehu`$fm4)&k7`u{xIV)yvA(%5SxX9MS80p2EKnLtCZ>tlX>*Z6nd&6-Mv$5rHD*db;&IBK3KH&M<+ArlGXDRdX1VVO4)&R$f4NxXI>GBh zSv|h>5GDAI(4E`@F?EnW zS>#c&Gw6~_XL`qQG4bK`W*>hek4LX*efn6|_MY+rXkNyAuu?NxS%L7~9tD3cn7&p( zCtfqe6sjB&Q-Vs7BP5+%;#Gk};4xtwU!KY0XXbmkUy$kR9)!~?*v)qw00!+Yg^#H> zc#8*z6zZo>+(bud?K<*!QO4ehiTCK&PD4G&n)Tr9X_3r-we z?fI+}-G~Yn93gI6F{}Dw_SC*FLZ)5(85zp4%uubtD)J)UELLkvGk4#tw&Tussa)mTD$R2&O~{ zCI3>fr-!-b@EGRI%g0L8UU%%u_<;e9439JNV;4KSxd|78v+I+8^rmMf3f40Jb}wEszROD?xBZu>Ll3;sUIoNxDK3|j3*sam2tC@@e$ z^!;+AK>efeBJB%ALsQ{uFui)oDoq()2USi?n=6C3#eetz?wPswc={I<8x=(8lE4EIsUfyGNZ{|KYn1IR|=E==f z(;!A5(-2y^2xRFCSPqzHAZn5RCN_bp22T(KEtjA(rFZ%>a4@STrHZflxKoqe9Z4@^ zM*scx_y73?Q{vt6?~WEl?2q*;@8 z3M*&@%l)SQmXkcUm)d@GT2#JdzhfSAP9|n#C;$E8X|pwD!r#X?0P>0ZisQ~TNqupW z*lUY~+ikD`vQb?@SAWX#r*Y+;=_|oacL$2CL$^(mV}aKO77pg}O+-=T1oLBT5sL2i z42Qth2+0@C`c+*D0*5!qy26sis<9a7>LN2{z%Qj49t z=L@x`4$ALHb*3COHoT?5S_c(Hs}g!V>W^=6Q0}zaubkDn)(lTax0+!+%B}9Vqw6{H zvL|BRM`O<@;eVi1DzM!tXtBrA20Ce@^Jz|>%X-t`vi-%WweXCh_LhI#bUg2*pcP~R z*RuTUzBKLXO~~uMd&o$v3@d0shHfUjC6c539PE6rF&;Ufa(Rw@K1*m7?f5)t`MjH0 z)_V(cajV5Am>f!kWcI@5rE8t6$S>5M=k=aRZROH6fA^jJp~2NlR4;Q2>L$7F#RT#9 z>4@1RhWG`Khy>P2j1Yx^BBL{S`niMaxlSWV-JBU0-T9zZ%>7mR3l$~QV$({o0;jTI ze5=cN^!Bc2bT|BcojXp~K#2cM>OTe*cM{Kg-j*CkiW)EGQot^}s;cy8_1_@JA0Whq zlrNr+R;Efa+`6N)s5rH*|E)nYZ3uqkk2C(E7@A|3YI`ozP~9Lexx#*1(r8luq+YPk z{J}c$s` zPM35Fx(YWB3Z5IYnN+L_4|jaR(5iWJi2~l&xy}aU7kW?o-V*6Av2wyZTG!E2KSW2* zGRLQkQU;Oz##ie-Z4fI)WSRxn$(ZcD;TL+;^r=a4(G~H3ZhK$lSXZj?cvyY8%d9JM zzc3#pD^W_QnWy#rx#;c&N@sqHhrnHRmj#i;s%zLm6SE(n&BWpd&f7>XnjV}OlZntI70fq%8~9<7 zMYaw`E-rp49-oC1N_uZTo)Cu%RR2QWdHpzQIcNsoDp`3xfP+`gI?tVQZ4X={qU?(n zV>0ASES^Xuc;9JBji{)RnFL(Lez;8XbB1uWaMp@p?7xhXk6V#!6B@aP4Rz7-K%a>i z?fvf}va_DGUXlI#4--`A3qK7J?-HwnG7O~H2;zR~RLW)_^#La!=}+>KW#anZ{|^D3 B7G?kd literal 0 HcmV?d00001 diff --git a/docs/css/images/glyphicons-halflings.png b/docs/css/images/glyphicons-halflings.png new file mode 100644 index 0000000000000000000000000000000000000000..a9969993201f9cee63cf9f49217646347297b643 GIT binary patch literal 12799 zcma*OWmH^Ivn@*S;K3nSf_t!#;0f+&pm7Po8`nk}2q8f5;M%x$SdAkd9FAvlc$ zx660V9e3Ox@4WZ^?7jZ%QFGU-T~%||Ug4iK6bbQY@zBuF2$hxOw9wF=A)nUSxR_5@ zEX>HBryGrjyuOFFv$Y4<+|3H@gQfEqD<)+}a~mryD|1U9*I_FOG&F%+Ww{SJ-V2BR zjt<81Ek$}Yb*95D4RS0HCps|uLyovt;P05hchQb-u2bzLtmog&f2}1VlNhxXV);S9 zM2buBg~!q9PtF)&KGRgf3#z7B(hm5WlNClaCWFs!-P!4-u*u5+=+D|ZE9e`KvhTHT zJBnLwGM%!u&vlE%1ytJ=!xt~y_YkFLQb6bS!E+s8l7PiPGSt9xrmg?LV&&SL?J~cI zS(e9TF1?SGyh+M_p@o1dyWu7o7_6p;N6hO!;4~ z2B`I;y`;$ZdtBpvK5%oQ^p4eR2L)BH>B$FQeC*t)c`L71gXHPUa|vyu`Bnz)H$ZcXGve(}XvR!+*8a>BLV;+ryG1kt0=)ytl zNJxFUN{V7P?#|Cp85QTa@(*Q3%K-R(Pkv1N8YU*(d(Y}9?PQ(j;NzWoEVWRD-~H$=f>j9~PN^BM2okI(gY-&_&BCV6RP&I$FnSEM3d=0fCxbxA6~l>54-upTrw zYgX@%m>jsSGi`0cQt6b8cX~+02IghVlNblR7eI;0ps}mpWUcxty1yG56C5rh%ep(X z?)#2d?C<4t-KLc*EAn>>M8%HvC1TyBSoPNg(4id~H8JwO#I)Bf;N*y6ai6K9_bA`4 z_g9(-R;qyH&6I$`b42v|0V3Z8IXN*p*8g$gE98+JpXNY+jXxU0zsR^W$#V=KP z3AEFp@OL}WqwOfsV<)A^UTF4&HF1vQecz?LWE@p^Z2){=KEC_3Iopx_eS42>DeiDG zWMXGbYfG~W7C8s@@m<_?#Gqk;!&)_Key@^0xJxrJahv{B&{^!>TV7TEDZlP|$=ZCz zmX=ZWtt4QZKx**)lQQoW8y-XLiOQy#T`2t}p6l*S`68ojyH@UXJ-b~@tN`WpjF z%7%Yzv807gsO!v=!(2uR)16!&U5~VPrPHtGzUU?2w(b1Xchq}(5Ed^G|SD7IG+kvgyVksU) z(0R)SW1V(>&q2nM%Z!C9=;pTg!(8pPSc%H01urXmQI6Gi^dkYCYfu6b4^tW))b^U+ z$2K&iOgN_OU7n#GC2jgiXU{caO5hZt0(>k+c^(r><#m|#J^s?zA6pi;^#*rp&;aqL zRcZi0Q4HhVX3$ybclxo4FFJW*`IV`)Bj_L3rQe?5{wLJh168Ve1jZv+f1D}f0S$N= zm4i|9cEWz&C9~ZI3q*gwWH^<6sBWuphgy@S3Qy?MJiL>gwd|E<2h9-$3;gT9V~S6r z)cAcmE0KXOwDA5eJ02-75d~f?3;n7a9d_xPBJaO;Z)#@s7gk5$Qn(Fc^w@9c5W0zY z59is0?Mt^@Rolcn{4%)Ioat(kxQH6}hIykSA)zht=9F_W*D#<}N(k&&;k;&gKkWIL z0Of*sP=X(Uyu$Pw;?F@?j{}=>{aSHFcii#78FC^6JGrg-)!)MV4AKz>pXnhVgTgx8 z1&5Y=>|8RGA6++FrSy=__k_imx|z-EI@foKi>tK0Hq2LetjUotCgk2QFXaej!BWYL zJc{fv(&qA7UUJ|AXLc5z*_NW#yWzKtl(c8mEW{A>5Hj^gfZ^HC9lQNQ?RowXjmuCj4!!54Us1=hY z0{@-phvC}yls!PmA~_z>Y&n&IW9FQcj}9(OLO-t^NN$c0o}YksCUWt|DV(MJB%%Sr zdf}8!9ylU2TW!=T{?)g-ojAMKc>3pW;KiZ7f0;&g)k}K^#HBhE5ot)%oxq$*$W@b# zg4p<Ou`ME|Kd1WHK@8 zzLD+0(NHWa`B{em3Ye?@aVsEi>y#0XVZfaFuq#;X5C3{*ikRx7UY4FF{ZtNHNO?A_ z#Q?hwRv~D8fPEc%B5E-ZMI&TAmikl||EERumQCRh7p;)>fdZMxvKq;ky0}7IjhJph zW*uuu*(Y6)S;Od--8uR^R#sb$cmFCnPcj9PPCWhPN;n`i1Q#Qn>ii z{WR|0>8F`vf&#E(c2NsoH=I7Cd-FV|%(7a`i}gZw4N~QFFG2WtS^H%@c?%9UZ+kez z;PwGgg_r6V>Kn5n(nZ40P4qMyrCP3bDkJp@hp6&X3>gzC>=f@Hsen<%I~7W+x@}b> z0}Et*vx_50-q@PIV=(3&Tbm}}QRo*FP2@)A#XX-8jYspIhah`9ukPBr)$8>Tmtg&R z?JBoH17?+1@Y@r>anoKPQ}F8o9?vhcG79Cjv^V6ct709VOQwg{c0Q#rBSsSmK3Q;O zBpNihl3S0_IGVE)^`#94#j~$;7+u870yWiV$@={|GrBmuz4b)*bCOPkaN0{6$MvazOEBxFdKZDlbVvv{8_*kJ zfE6C`4&Kkz<5u%dEdStd85-5UHG5IOWbo8i9azgg#zw-(P1AA049hddAB*UdG3Vn0 zX`OgM+EM|<+KhJ<=k?z~WA5waVj?T9eBdfJGebVifBKS1u<$#vl^BvSg)xsnT5Aw_ZY#}v*LXO#htB>f}x3qDdDHoFeb zAq7;0CW;XJ`d&G*9V)@H&739DpfWYzdQt+Kx_E1K#Cg1EMtFa8eQRk_JuUdHD*2;W zR~XFnl!L2A?48O;_iqCVr1oxEXvOIiN_9CUVTZs3C~P+11}ebyTRLACiJuMIG#`xP zKlC|E(S@QvN+%pBc6vPiQS8KgQAUh75C0a2xcPQDD$}*bM&z~g8+=9ltmkT$;c;s z5_=8%i0H^fEAOQbHXf0;?DN5z-5+1 zDxj50yYkz4ox9p$HbZ|H?8ukAbLE^P$@h}L%i6QVcY>)i!w=hkv2zvrduut%!8>6b zcus3bh1w~L804EZ*s96?GB&F7c5?m?|t$-tp2rKMy>F*=4;w*jW}^;8v`st&8)c; z2Ct2{)?S(Z;@_mjAEjb8x=qAQvx=}S6l9?~H?PmP`-xu;ME*B8sm|!h@BX4>u(xg_ zIHmQzp4Tgf*J}Y=8STR5_s)GKcmgV!$JKTg@LO402{{Wrg>#D4-L%vjmtJ4r?p&$F!o-BOf7ej~ z6)BuK^^g1b#(E>$s`t3i13{6-mmSp7{;QkeG5v}GAN&lM2lQT$@(aQCcFP(%UyZbF z#$HLTqGT^@F#A29b0HqiJsRJAlh8kngU`BDI6 zJUE~&!cQ*&f95Ot$#mxU5+*^$qg_DWNdfu+1irglB7yDglzH()2!@#rpu)^3S8weW z_FE$=j^GTY*|5SH95O8o8W9FluYwB=2PwtbW|JG6kcV^dMVmX(wG+Otj;E$%gfu^K z!t~<3??8=()WQSycsBKy24>NjRtuZ>zxJIED;YXaUz$@0z4rl+TW zWxmvM$%4jYIpO>j5k1t1&}1VKM~s!eLsCVQ`TTjn3JRXZD~>GM z$-IT~(Y)flNqDkC%DfbxaV9?QuWCV&-U1yzrV@0jRhE;)ZO0=r-{s@W?HOFbRHDDV zq;eLo+wOW;nI|#mNf(J?RImB9{YSO2Y`9825Lz#u4(nk3)RGv3X8B(A$TsontJ8L! z9JP^eWxtKC?G8^xAZa1HECx*rp35s!^%;&@Jyk)NexVc)@U4$^X1Dag6`WKs|(HhZ#rzO2KEw3xh~-0<;|zcs0L>OcO#YYX{SN8m6`9pp+ zQG@q$I)T?aoe#AoR@%om_#z=c@ych!bj~lV13Qi-xg$i$hXEAB#l=t7QWENGbma4L zbBf*X*4oNYZUd_;1{Ln_ZeAwQv4z?n9$eoxJeI?lU9^!AB2Y~AwOSq67dT9ADZ)s@ zCRYS7W$Zpkdx$3T>7$I%3EI2ik~m!f7&$Djpt6kZqDWZJ-G{*_eXs*B8$1R4+I}Kf zqniwCI64r;>h2Lu{0c(#Atn)%E8&)=0S4BMhq9$`vu|Ct;^ur~gL`bD>J@l)P$q_A zO7b3HGOUG`vgH{}&&AgrFy%K^>? z>wf**coZ2vdSDcNYSm~dZ(vk6&m6bVKmVgrx-X<>{QzA!)2*L+HLTQz$e8UcB&Djq zl)-%s$ZtUN-R!4ZiG=L0#_P=BbUyH+YPmFl_ogkkQ$=s@T1v}rNnZ^eMaqJ|quc+6 z*ygceDOrldsL30w`H;rNu+IjlS+G~p&0SawXCA1+D zC%cZtjUkLNq%FadtHE?O(yQTP486A{1x<{krq#rpauNQaeyhM3*i0%tBpQHQo-u)x z{0{&KS`>}vf2_}b160XZO2$b)cyrHq7ZSeiSbRvaxnKUH{Q`-P(nL&^fcF2){vhN- zbX&WEjP7?b4A%0y6n_=m%l00uZ+}mCYO(!x?j$+O$*TqoD_Q5EoyDJ?w?^UIa491H zE}87(bR`X;@u#3Qy~9wWdWQIg1`cXrk$x9=ccR|RY1~%{fAJ@uq@J3e872x0v$hmv ze_KcL(wM|n0EOp;t{hKoohYyDmYO;!`7^Lx;0k=PWPGZpI>V5qYlzjSL_(%|mud50 z7#{p97s`U|Sn$WYF>-i{i4`kzlrV6a<}=72q2sAT7Zh{>P%*6B;Zl;~0xWymt10Mo zl5{bmR(wJefJpNGK=fSRP|mpCI-)Nf6?Pv==FcFmpSwF1%CTOucV{yqxSyx4Zws3O z8hr5Uyd%ezIO7?PnEO0T%af#KOiXD$e?V&OX-B|ZX-YsgSs%sv-6U+sLPuz{D4bq| zpd&|o5tNCmpT>(uIbRf?8c}d3IpOb3sn6>_dr*26R#ev<_~vi)wleW$PX|5)$_ z+_|=pi(0D(AB_sjQ;sQQSM&AWqzDO1@NHw;C9cPdXRKRI#@nUW)CgFxzQ1nyd!+h& zcjU!U=&u|>@}R(9D$%lu2TlV>@I2-n@fCr5PrZNVyKWR7hm zWjoy^p7v8m#$qN0K#8jT- zq`mSirDZDa1Jxm;Rg3rAPhC)LcI4@-RvKT+@9&KsR3b0_0zuM!Fg7u>oF>3bzOxZPU&$ab$Z9@ zY)f7pKh22I7ZykL{YsdjcqeN++=0a}elQM-4;Q)(`Ep3|VFHqnXOh14`!Bus& z9w%*EWK6AiAM{s$6~SEQS;A>ey$#`7)khZvamem{P?>k)5&7Sl&&NXKk}o!%vd;-! zpo2p-_h^b$DNBO>{h4JdGB=D>fvGIYN8v&XsfxU~VaefL?q} z3ekM?iOKkCzQHkBkhg=hD!@&(L}FcHKoa zbZ7)H1C|lHjwEb@tu=n^OvdHOo7o+W`0-y3KdP#bb~wM=Vr_gyoEq|#B?$&d$tals ziIs-&7isBpvS|CjC|7C&3I0SE?~`a%g~$PI%;au^cUp@ER3?mn-|vyu!$7MV6(uvt z+CcGuM(Ku2&G0tcRCo7#D$Dirfqef2qPOE5I)oCGzmR5G!o#Q~(k~)c=LpIfrhHQk zeAva6MilEifE7rgP1M7AyWmLOXK}i8?=z2;N=no)`IGm#y%aGE>-FN zyXCp0Sln{IsfOBuCdE*#@CQof%jzuU*jkR*Su3?5t}F(#g0BD0Zzu|1MDes8U7f9; z$JBg|mqTXt`muZ8=Z`3wx$uizZG_7>GI7tcfOHW`C2bKxNOR)XAwRkLOaHS4xwlH4 zDpU29#6wLXI;H?0Se`SRa&I_QmI{zo7p%uveBZ0KZKd9H6@U?YGArbfm)D*^5=&Rp z`k{35?Z5GbZnv>z@NmJ%+sx=1WanWg)8r}C_>EGR8mk(NR$pW<-l8OTU^_u3M@gwS z7}GGa1)`z5G|DZirw;FB@VhH7Dq*0qc=|9lLe{w2#`g+_nt>_%o<~9(VZe=zI*SSz4w43-_o>4E4`M@NPKTWZuQJs)?KXbWp1M zimd5F;?AP(LWcaI-^Sl{`~>tmxsQB9Y$Xi*{Zr#py_+I$vx7@NY`S?HFfS!hUiz$a z{>!&e1(16T!Om)m)&k1W#*d#GslD^4!TwiF2WjFBvi=Ms!ADT)ArEW6zfVuIXcXVk z>AHjPADW+mJzY`_Ieq(s?jbk4iD2Rb8*V3t6?I+E06(K8H!!xnDzO%GB;Z$N-{M|B zeT`jo%9)s%op*XZKDd6*)-^lWO{#RaIGFdBH+;XXjI(8RxpBc~azG1H^2v7c^bkFE zZCVPE+E*Q=FSe8Vm&6|^3ki{9~qafiMAf7i4APZg>b%&5>nT@pHH z%O*pOv(77?ZiT{W zBibx}Q12tRc7Py1NcZTp`Q4ey%T_nj@1WKg5Fz_Rjl4wlJQj)rtp8yL3r!Shy zvZvnmh!tH4T6Js-?vI0<-rzzl{mgT*S0d_7^AU_8gBg^03o-J=p(1o6kww2hx|!%T z-jqp}m^G*W?$!R#M%Ef?&2jYxmx+lXWZszpI4d$pUN`(S)|*c^CgdwY>Fa>> zgGBJhwe8y#Xd*q0=@SLEgPF>+Qe4?%E*v{a`||luZ~&dqMBrRfJ{SDMaJ!s_;cSJp zSqZHXIdc@@XteNySUZs^9SG7xK`8=NBNM)fRVOjw)D^)w%L2OPkTQ$Tel-J)GD3=YXy+F4in(ILy*A3m@3o73uv?JC}Q>f zrY&8SWmesiba0|3X-jmlMT3 z*ST|_U@O=i*sM_*48G)dgXqlwoFp5G6qSM3&%_f_*n!PiT>?cNI)fAUkA{qWnqdMi+aNK_yVQ&lx4UZknAc9FIzVk% zo6JmFH~c{_tK!gt4+o2>)zoP{sR}!!vfRjI=13!z5}ijMFQ4a4?QIg-BE4T6!#%?d&L;`j5=a`4is>U;%@Rd~ zXC~H7eGQhhYWhMPWf9znDbYIgwud(6$W3e>$W4$~d%qoJ z+JE`1g$qJ%>b|z*xCKenmpV$0pM=Gl-Y*LT8K+P)2X#;XYEFF4mRbc~jj?DM@(1e`nL=F4Syv)TKIePQUz)bZ?Bi3@G@HO$Aps1DvDGkYF50O$_welu^cL7;vPiMGho74$;4fDqKbE{U zd1h{;LfM#Fb|Z&uH~Rm_J)R~Vy4b;1?tW_A)Iz#S_=F|~pISaVkCnQ0&u%Yz%o#|! zS-TSg87LUfFSs{tTuM3$!06ZzH&MFtG)X-l7>3)V?Txuj2HyG*5u;EY2_5vU0ujA? zHXh5G%6e3y7v?AjhyX79pnRBVr}RmPmtrxoB7lkxEzChX^(vKd+sLh?SBic=Q)5nA zdz7Mw3_iA>;T^_Kl~?1|5t%GZ;ki_+i>Q~Q1EVdKZ)$Sh3LM@ea&D~{2HOG++7*wF zAC6jW4>fa~!Vp5+$Z{<)Qxb|{unMgCv2)@%3j=7)Zc%U<^i|SAF88s!A^+Xs!OASYT%7;Jx?olg_6NFP1475N z#0s<@E~FI}#LNQ{?B1;t+N$2k*`K$Hxb%#8tRQi*Z#No0J}Pl;HWb){l7{A8(pu#@ zfE-OTvEreoz1+p`9sUI%Y{e5L-oTP_^NkgpYhZjp&ykinnW;(fu1;ttpSsgYM8ABX4dHe_HxU+%M(D=~) zYM}XUJ5guZ;=_ZcOsC`_{CiU$zN3$+x&5C`vX-V3`8&RjlBs^rf00MNYZW+jCd~7N z%{jJuUUwY(M`8$`B>K&_48!Li682ZaRknMgQ3~dnlp8C?__!P2z@=Auv;T^$yrsNy zCARmaA@^Yo2sS%2$`031-+h9KMZsIHfB>s@}>Y(z988e!`%4=EDoAQ0kbk>+lCoK60Mx9P!~I zlq~wf7kcm_NFImt3ZYlE(b3O1K^QWiFb$V^a2Jlwvm(!XYx<`i@ZMS3UwFt{;x+-v zhx{m=m;4dgvkKp5{*lfSN3o^keSpp9{hlXj%=}e_7Ou{Yiw(J@NXuh*;pL6@$HsfB zh?v+r^cp@jQ4EspC#RqpwPY(}_SS$wZ{S959`C25777&sgtNh%XTCo9VHJC-G z;;wi9{-iv+ETiY;K9qvlEc04f;ZnUP>cUL_T*ms``EtGoP^B#Q>n2dSrbAg8a>*Lg zd0EJ^=tdW~7fbcLFsqryFEcy*-8!?;n%;F+8i{eZyCDaiYxghr z$8k>L|2&-!lhvuVdk!r-kpSFl`5F5d4DJr%M4-qOy3gdmQbqF1=aBtRM7)c_Ae?$b8 zQg4c8*KQ{XJmL)1c7#0Yn0#PTMEs4-IHPjkn0!=;JdhMXqzMLeh`yOylXROP- zl#z3+fwM9l3%VN(6R77ua*uI9%hO7l7{+Hcbr(peh;afUK?B4EC09J{-u{mv)+u#? zdKVBCPt`eU@IzL)OXA`Ebu`Xp?u0m%h&X41}FNfnJ*g1!1wcbbpo%F4x!-#R9ft!8{5`Ho}04?FI#Kg zL|k`tF1t_`ywdy8(wnTut>HND(qNnq%Sq=AvvZbXnLx|mJhi!*&lwG2g|edBdVgLy zjvVTKHAx(+&P;P#2Xobo7_RttUi)Nllc}}hX>|N?-u5g7VJ-NNdwYcaOG?NK=5)}` zMtOL;o|i0mSKm(UI_7BL_^6HnVOTkuPI6y@ZLR(H?c1cr-_ouSLp{5!bx^DiKd*Yb z{K78Ci&Twup zTKm)ioN|wcYy%Qnwb)IzbH>W!;Ah5Zdm_jRY`+VRJ2 zhkspZ9hbK3iQD91A$d!0*-1i#%x81|s+SPRmD}d~<1p6!A13(!vABP2kNgqEG z?AMgl^P+iRoIY(9@_I?n1829lGvAsRnHwS~|5vD2+Zi53j<5N4wNn0{q>>jF9*bI) zL$kMXM-awNOElF>{?Jr^tOz1glbwaD-M0OKOlTeW3C!1ZyxRbB>8JDof(O&R1bh%3x#>y2~<>OXO#IIedH0Q`(&&?eo-c~ z>*Ah#3~09unym~UC-UFqqI>{dmUD$Y4@evG#ORLI*{ZM)Jl=e1it!XzY($S3V zLG!Y6fCjE>x6r@5FG1n|8ompSZaJ>9)q6jqU;XxCQk9zV(?C9+i*>w z21+KYt1gXX&0`x3E)hS7I5}snbBzox9C@Xzcr|{B8Hw;SY1$}&BoYKXH^hpjW-RgJ z-Fb}tannKCv>y~^`r|(1Q9;+sZlYf3XPSX|^gR01UFtu$B*R;$sPZdIZShRr>|b@J z;#G{EdoY+O;REEjQ}X7_YzWLO+Ey3>a_KDe1CjSe| z6arqcEZ)CX!8r(si`dqbF$uu&pnf^Np{1f*TdJ`r2;@SaZ z#hb4xlaCA@Pwqj#LlUEe5L{I$k(Zj$d3(~)u(F%&xb8={N9hKxlZIO1ABsM{Mt|)2 zJ^t9Id;?%4PfR4&Ph9B9cFK~@tG3wlFW-0fXZS_L4U*EiAA%+`h%q2^6BCC;t0iO4V=s4Qug{M|iDV@s zC7|ef-dxiR7T&Mpre!%hiUhHM%3Qxi$Lzw6&(Tvlx9QA_7LhYq<(o~=Y>3ka-zrQa zhGpfFK@)#)rtfz61w35^sN1=IFw&Oc!Nah+8@qhJ0UEGr;JplaxOGI82OVqZHsqfX ze1}r{jy;G?&}Da}a7>SCDsFDuzuseeCKof|Dz2BPsP8? zY;a)Tkr2P~0^2BeO?wnzF_Ul-ekY=-w26VnU%U3f19Z-pj&2 z4J_a|o4Dci+MO)mPQIM>kdPG1xydiR9@#8m zh27D7GF{p|a{8({Q-Pr-;#jV{2zHR>lGoFtIfIpoMo?exuQyX_A;;l0AP4!)JEM$EwMInZkj+8*IHP4vKRd zKx_l-i*>A*C@{u%ct`y~s6MWAfO{@FPIX&sg8H{GMDc{4M3%$@c8&RAlw0-R<4DO3 trJqdc$mBpWeznn?E0M$F`|3v=`3%T2A17h;rxP7$%JLd=6(2u;`(N3pt&so# literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-bg_diagonals-thick_90_eeeeee_40x40.png b/docs/css/images/ui-bg_diagonals-thick_90_eeeeee_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..f524612a93bfad669d891773694528acfae8348b GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^8XznHBp80OT7LpkOiAAEF8}|FtTsFg2>S z4={E+nQaGTRC&5MhIkx*d(~Q~L4n8h;+uNeb^Vv3+8lZ8x$nQ_(L6cF==!-MxN^qU8@z2i%xiAbfQT5gZ1-s z;)j7MW;;xkc9{Fxp{aY>ix?Bv=ZiG0#Cn6`?Y^5FM+O5Epd$~Nl7e8 zwMs5Z1yT$~28O1(2FALEh9L$PRwkBKriQu(=2iv<9QzbiQ8eV{r(~v8;?_|4c;-x? O1_n=8KbLh*2~7a;9BEJh literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-bg_flat_15_cd0a0a_40x100.png b/docs/css/images/ui-bg_flat_15_cd0a0a_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..3c355cd37f74f626af7ff3090bf923b5773054a2 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^8bF-F$P6UUt$JVyq?iMILR`;sajBSF#sayV1s;*b zK-vS0-A-oP0U7+BE{-7@=aUm8SQj_^Vqjp3U|=jYYbyszsg}4#l%yn#D^o*V19K|_1CD))swf(A^HVa@DsgM5d^~d|Py>UftDnm{ Hr-UW|1?(`w literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-bg_glass_100_e4f1fb_1x400.png b/docs/css/images/ui-bg_glass_100_e4f1fb_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..68991a3821cf238d0d5684e6d0ff48428fd5e67f GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^j6gI&fCnc6a#?2AmP!?*K(O3p^r= zfwTu0yPeFo12X1#x;Tb-9DjR$E!Uw0iMEH&D=(^a1a8=6ux&@m#Uum0HC$Cn^BQO9 zbX#|bPCoh|(PDCaP4nLa-x?1l3-IRey2WcA*PfOBor$4gkw(|2+zF}2OnBENzT0M- z*vNbA5aafOR=K1fhfIT6cAV{w{C(hWMA_Qr=UZ%UFD*DK!q{^~xY}vo3jJ+DRXs23 zlllx2TNWm?*jd#Zt_2$Ae9yC4|MAkKeN8}js+PD$l%yn#D^o*V19K|_1CD))swf(A^HVa@DsgM5d^~d|Py>UftDnm{r-UW|L~MZP literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-bg_glass_50_3baae3_1x400.png b/docs/css/images/ui-bg_glass_50_3baae3_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..4addcce70b7be6e02f393b3f80f565ec77324878 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^j6gI&fCnc6a#?2AmP!?*K(O3p^r= zfwTu0yPeFo12XzNT^vI^jwgG}+ExAiw3-?l2($%eO_5sawlc8m*_E@Y@9+QjN=bT? z7IQY^;E|w{H;x3HKT_15$(t-M+%0>#wC$$P8XccqJ+~FF@TpxZdB)MU*eBVM z7oJ3j85tU`NlDt8yz89B?1el2Z#eS$yN^#}PfyQ6pPrLEw|Hur4_{tUO_QmvAUQh^kMk%6J9u7Rnc6a#?2AmP!?*K(O3p^r= zfwTu0yPeFo12SfKx;Tb-9DjRWk*|qCg7v}oduhd&vkH=>OeIW&p9tir?GTz`%3ZpeMiCM7L|#v6JySJ-K88XY9)p+BSyIc;|^2HFnp;@kX)t*OummUuqK+do+Vl?GR%& zk1Km^$v>rBiMEfeoC3O0wZt`|BqgyV)hf9t6-Y4{85o-C8W`&u8ip8H vSeaN_nHuUEm|GbbaO_i5MbVI(pOTqYiCaVE`Ce}=kDQ`WYIxVv~ z<<>IJ#HFVzj>tceEB@o~tm?4n!fTWA#EWDv_0}p+tz3IE=;NGUK5h}OV>s^T{S(Q5 ze8%}(%F;7Wfv!?5ag8WRNi0dVN-jzTQVd20hNij(#=3@vAqEy!CYDyFhPnpkRt5$f h`xI4CH00)|WTsW()=>F)=1ial22WQ%mvv4FO#mChbWi{Q literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-bg_highlight-hard_70_000000_1x100.png b/docs/css/images/ui-bg_highlight-hard_70_000000_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..925419fe57e90e78a77f2ee81de785cf1f64a976 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^j6j?s03;ZUuHXC*q?nSt-Ch3w7g=q17Rci)@Q5r1 z(jH*!b~4)z$guWwaSV~ToO~iLRl;FP=|sg`HRmR2XBTtl2A$^H`fRsf^QiUkL`Cs* zz2SM}FUhh+!eXlA3_SxLCI$vmbAwa!Ma8v&#;BIKMwFx^mZVxG7o`Fz1|tJQQ(XgN zT|>hV0}Cq?ODj`DT?2C~0|SnIimE6Ya`RI%(<*UmsC+zgCQt)|r>mdKI;Vst070-p A_y7O^ literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-bg_highlight-soft_100_deedf7_1x100.png b/docs/css/images/ui-bg_highlight-soft_100_deedf7_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..f751680fb33524955d0367027268602aef3e296c GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^j6j?szyu^`+!HJTQfx`y?k@kqfHUIz9iRwjfk$L9 zkoEv$x0Bg+K*m8&7sn8d^G_$(W*uUXaFCbZQKH#2!SC&Z2LUpzC2s|Hsea+Jbw0P? z3tL)I`4v~6@r#QHBKU<#bF?j~Z{O0z67hk5a^UK{_6ZIyZh2bABlaN-R^mP7% z*9`ZqI4Uv!eW>LP=_RFxxlWhL63y1FSjZ>$@oW70m%^o=o?9hWPu%{hGh?CunV(vl zLTgW}os%n@_+q!6k*I0GhrUxi=f9r!{i;2~>XGjkuJ)xXO4r;sd@}We-P^F~ERK_= zJYA_j*OKqEeq74M*H4pyo>47vjVMV;EJ?LWE=mPb3`Pcqrn&~kx`u`!1{PK(mR6>Q ox(4P}1_m7a6jf0)o&W#< literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-bg_highlight-soft_25_ffef8f_1x100.png b/docs/css/images/ui-bg_highlight-soft_25_ffef8f_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..1218f089ce52ab117115a136fcbffb67a54f8ad5 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^j6j?szyu^`+!HJTQfx`y?k@kqfHUIz9iRwjfk$L9 zkoEv$x0Bg+Kt{2ri(`n!`KJ@kayBOju(pSvm~OYF|A<=ACV}V=dESj2RRUiW9vObH zS)HW>aR^Q(qW?RQD{kS9I_06dbQ=k2g|CN~|bky{qe&Aa(p!KRHt`Q|Ei6yC4$wjF^ ziowXh&{WsJSl7@n#K6MJ#L~*tP}jiR%D{kQpQ0*?hTQy=%(P0}8Y&;poC(yx;OXk; Jvd$@?2>@izXh#45 literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-icons_2694e8_256x240.png b/docs/css/images/ui-icons_2694e8_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..e7bd2569d74f0c7b1c0a972a332380a976cd0d3c GIT binary patch literal 4549 zcmeHK2U8Qw)=okQgeFb85=9ZDg(gT1B^U@Dr1KJ_sPv{NHAq#u6afX{l`1VFO=>8D zGyy}?P$Gi#B25T{T=bi{GxtAy&+P0uyR*-n-DhXcob%M!@D?)z9|HgYVAe%xn*sp9 zGZ(N;Pjfa;>FOPwZLk>YnyxUr9cZUUj6$*G3bFd=N-XE9868ju&W z(NIp(U1DN*PIPFJ@Sh*5y$xslX;8?WWgGXK!Jlzk4)cf+m)4oHEQHNv9@JJT;@}Vn zW17MyqgxqAB;`)*F-wgrNygfL(H-Zzl1ECSB+7SY3v?#MUo>l}_o^@FKnAuhJlYcn9Qs`k z_%zcT8lntvH_n&a7W}@N>P)g8By?oBR^y2P^xO6@Td3L-Dv-V;ErC)WOt3_cMfqJ}i-e`FFU!hBT) z@j)GGUSGAqr+bK}3x0_0C*bP<$4WwO(^@nB>TAI^1D*d9XWD#kF7q2<2qoS;I)nUn zGD0%Folo{+o+<@}s|-(ANH8N-KvIUDr17%BO%k|b;J78V0u@NfJj}dK663GnKL1N- zd*_OGrOW%^`KvITf}PdSU@!JXd$-ICM^+fT^Q*9c7YnY=|Bi;ZK)v>l^;G6}8Z_%= z7BRXjdm-`6jYfCDIIiuV*(H5Mbb2LyeBp-jKxICDA*_HC zFJD4n#e}e`Q7oNZC>nxcU=$+nv4aj|j@e0JZO!^SA?jF9wJy7A*NuHzx}gswrO-97 z-1p*mY&Sd0ZgKFuXr7mCF624G=^zftz>a3LZe*O&?jXiW6pcdJw(`!40c+77sx5@b zoE&}3X!cP^`_)|fdaq=t;|Z7^$~G(bGl3=Eu#ZD1Vp+ZxDk4WEy;g6EY1||u|9qUC zccJBpj;pUSzQGRJ`rYAQYE~wwVnDq3cLv0g=F-*ZAmk;TI-bsYNk-0Uk=te{6S#9v zpr|=l{x0JhyP}Yf_zdLHo@T=&nv%FY2m@SaPk5C1%xVtYgT%TV<#MF6XR~9e4CwWk zq^q9X{AlheJjg1{zgGvD(gj)$i;meGT^bKyd?S7pC?RKTF75aSoHr-lJ#4ir(LOc794An1S@ zq*0c{g3@HyM~x%Www-8S(Be5q1aJGQLI7_0qw_y@_M8mxqjbmZGW3o9ODx2TTbX@8 zJ?s~%mOl2rDQut4(BxS$g_QJ!0Ak5lg{zM30<7;-C4g^3OI!OG_2kQ+)3 z^Cy+^fs^BumcfRAU~Mf{kXq+1$L>eZqkkId^UrrivX^!e2xcR~{o*j?SB8r(H$g?~ z!lYWwP*~shNEHW-q}Obk_Na@84~{y?h9W=?O#lxUe3BeYe=q*H5iI>d7Y(SxuH&@* zpJp++CFDLCy|&xZ%D7-a`9J_E0t+OugmP)zJ=q4ZvumiQZ-yXX3rZJ98|4*wJNV~M z0sUg{8T@$`rXWT;RdobZgjb~dAjKt~{X&RpPr*u4)O)S!`$d$>Rlz@LQ`%1@WZB55 zL%Et6LnNb8R(yV&JboE87WV)*(=)Yelh?3hQPp?aQ^VSRX+yN-w>+=sg*2_5`o#TV znIXLXp_sqalwSAHbBS++PL@+uG(Ir_uGmQ|!4zXz%|%nXZzMH{WE zx2Hen9w}GP+Rm{w|68$b zs3?WM2EO>CPx|@oV{S%Enu3Q1?jNKToqcQG#hW)LjVB=a?R`NgMW*>aO3Co%%q@aW zcI_5ZLoXUHNJ`$>zgCg&M|qkMd5)Lg$Zz$y-fv^DQohlIzK-)nZbl|8`~yCm7_~H4WI1}JXs#5 zIpkcE$_o>XZ9jTpWD9bp8mTVHB9}Z^<*!+Py`uh$X1P`&)pHK;BaPcUJcyrjyjU{V zu8MwI^4o4i1_s7$$%>2x%xy>f&FBxYqIp>sRRXVSREGC^(X%#IlE_C}VIw89q7{qB zd~-R&fDbu>ot6%v6#0;d9RK`1sY~h=n;mJ_e7wgC(i69U}+h>z6I2nqt(Vb%0CO)_v%BG zgM4v%BOMuj36tBMHMR%b?D=*Q0Wn`%Pvn^q9NR+;!>_}S6TODb5%2I~%IN^70s8bb zlY3oS*WZ>sGe7>8os+BqRxxvb(AZgbX9fvimio|irPXGJz*Q&dQW@^{Gxp2GZz92= zzmV6@(oyq)!TH|%;?@3gNwj1)h511jwS&$@wT>u<&pF}p$x22k6ee7aI5 z^aCS@pn-Pn=}OMF`0FKAbnZra=QzKKfcO122bm#p@ zEK}ydqEB9x#gqX+oo+?yfdb^?EEjwoX2pltAJH%C5;MSyrI&4UV+p~@z%Cv4fRW(0 zA4?QDZa#%$wh70Qux_jt$yCg)j`S~^6fP-%32*w2GP9)2JP~eAsM+4>wXb*7e}DdO z0n7Fx0TeRtLgU(<`gIxlRBej*h8%gTB?N>u#;_U}7b$8`DT1Dhtv;+8DQwk}k~A>R@Ncz`s{h;6GjZ zRHgid%5b>iUmIu^Bzjk2IoNO9zi`_uBJb{}_!pUUB7AdEVN?yv#{pJd)GI*HhM`5p zAP>!6pJ}T@`%9G@g+7wqM$wABMz+;P&f4y34&~>w1&kJqnnU@MhA8WL5VO3}N$0{% zPm8UW>I6#>2kbY`a1t#4#I1G#cNC_Ig6WP$=%|@XQ7FOJ?Jw%G+|onb2eL06J}dWi z^jtU80f(3r$p1>(S%!;kMKIPbAt7(f6tk7+8y`kuSbV}BCdE?Rlr&=taf?)+n>QA` z7xo|fUwxgE9CwCgW^xDuRs6EFso#EWO)M7i`W$^<0KdKE2lvp>MbdsOSG7XwicWu( z-z1sbuQ9SjGrJ1nJJLLg;jXjuERrBN)X5lID-z~b_ZmKvX&({BlMJ6r-aDoZo9&<* zIgb!ih>i=AKb!|uv&8P~24p%&r4qmVTFs_N@occEQ%~N*iDqi4Euz34y7-EqE!z8V zFV+F6EX~uCC@dyedv`6xGUJpego$X2{H%%H@aB$wvTrNieHXY&)UgCDa%43e3G&;iS=doX+NE zT!FV!sP`NDMR?3ZXR?y%U&rOR>5Kj1A7$d==+C+Je*dyC8hJv+<3gCB0CnIZqnOB9 zy%4eu zB7?fRIyVWbYB>$v0B%I|R^0 L8fsT*VxIg5%&2X^ literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-icons_2e83ff_256x240.png b/docs/css/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..429489e65df2b9304e7ce7f5a5a3c1a5d116ed8a GIT binary patch literal 4549 zcmeHK2U8Qw)=okQgeFb85=9ZDg(gT1B^U@Dr1KJ_sPv{N1PD@^?hl=A5U-hPRj*_!s~H0JAPi+Y|r* zp1FW+dYZF&QdjTjY=gyE-yA6!LH+;nUj_J^SG~^!vJNmcGz0Lm%7W>Q+n!`eUB2y$ zaK-R($P6%FQsL4>p|sPJPh5;P`;_Y?2V59JFnY_$;N);>JD-x(S4OCZ!lw!Gv(RpT#g)sX$)L zMtvDccZrGN`IJMWg#Y|t&22d2PlE#POxxJs4E~JUa+pVq_|%T_GTm0VIHB`*@`j>!2PnXB=h9~jzkeS44&54~hf z&P%i6BhX`b?>&^Y)3>5c0~iIA>Ius5+}WtFpG@`0GSO8jjw5iw(!fkNE)XQFCOyVu z$8ThwLk)bvs=7^ZVUY9peW^!)S*?dkkVxN|Ezp@1f6=6+-lM*p4e8&y@MupQaOihE z;L}V~2v!;3Zk#8#E%<#k#hGM1Kx|KUts+bT&~Mv9ZJ}yUtdzv!?-R;sp3^6GMVnY$ zya}{>%0D{P=|ay&xP~KCX&eR^ahbI%DP+Buc~1njoLKumGWawV9yzE<|09D)5$3DR zj|*y7^ZKdUZ8tD9=IMe2Pa~a==gDCN)ks0K- zlVOtS?L4v<^JEDqOl4@?LV_8w0+KTHB#o60Y?8p`{m0EI<)}bP#$m>Fk{EwE_xWE! z+dEghD_q_O&tHY%73{1A2YPTX+PY+BI5I=w9bbh7yjbwH{&zIQ1?seatfw%))1X-| zwTRYT*~7*$HyGUofzN)Gvf{{Y5mQQXjnz+fq( zS2uY&X9s~QNgoN3);NsV9uV{ihBEz%=ge-;-?yzyQU5y2Ko|ZJyai+=W%Z~E;@6g( zF8_s2LVrt~|E(yM>+Uz5ni7!>ipv=-Z%zqGq~)O?h^yzDeZPOD2bm00D%KCVTN`O6 zy?lv*<>SJtMlp1DA!rDOfl-LO#|}D>Ic6t?wl?YSVAXM+YMpjft{eNbbb}vAN+D}t zx$i}BxGr{<-J;-m(OfUv9LRHq(*Zn^fgR0g-M~1h-98l~Q8)r++sZvJ2CPAQs5TQL zva|IuBUwk-wyQbxbzVtO#}hC;lx8PMy| ziB~;&j_%*ofSO&^vfRBO1({j8dDMja+O zeY$mI)})C!Du9y$T^?d^#F355Bf)v+dg-CdagyX)f1WTc?%Zee>Bdl)`(mm*Yc3HyLB}IX-UiEkx>ERTOz9>UYpL z1i4gbE4S42n%~#Ny#c=GX{+y2S6%B+tWc4=0MA0GN%O(1;2OWb*+i`prY)TK3(g}` zEMSoXOdwX8JpF)w-KS;glaYdYHI;I5TqK*V%4bAcLyTX*o*D*}(O*b~GKE7~fuI9s zkVa`D3rdq+A2o(Z-FBjVK}+Bq7QF4N3IVv~jm-bp*>f@=jL;po$fydnwe)fKO=0_Vh9=L7D5S(EL=a2*DqMAR7hrv#Dgk_pmHTLMzL+u1p0sH{O`DJ@IBAuudv{yLQ{J1Vto%rFvut)mCua3O8C* zZ%=>zB_G1How-~kP{>iywlg@jtng0xj>xN+xxNXYm$7h_fAkK&dxTsaYa7SX{BOn9 z!NO$zYWU)hUg_tzkGUBwY4RT)xPOpVboQ-&7iZp-I2MoOxAz616q)9GDaAvZGq;F3 zSv6Zs^*v~UASr2Q|5|yTALVI$#5rDmBfr(-I=_v9;sf%<8<+X$Tz&A#0_Gk6$U41W zx}0~BHknp{@cMhcSMsQ!!Ph7WlGHrMFH6ZfrdiA*G zxtb@x6=YZOAwV8-kJ15F`9K|^IjUZB2wu&^arRjk>zwjqg&o3fDGSG|{nNL_!CUx( zVmTikffH^-CqUSa*?4}6oJ%cLl%7XwB6N6!$@R*Y^+CxeN7n*f15bY;B?NDL-0&8b z8YsJF#a-eet`=JE;&Qx!Elvk$o#cBqO%ou40@%wR&ejcwy2%g`m8hR=5UpDYj2 z9CEHn<%WvJv>m-LvIRL)jZ~LpkxL$|^4F}tUQz!=vs|N);yDNSk;-iz7R1jvRwS8Y zS4lrD`E55m9RuUGWJSgR=C;HCX7qXLf-W_#*2AMde(R0`K%fR^msaNiz+zuBZsH0Emn zxdTI>F5bB$?reSY*$oXDe9`RT(}U*I(ru}YXO+d(I9f)pZvoZjXtmMyvd=>HJ^B#k zAYZ)RaC^F6{KR%gwe0~nd!C&{K=hZE6M1F?$M#_T(Ce_{1g{};#5;nRavH#?pFS8N?bIdkd7TAm0^3Bjz}A7o3wCjKs4DobaOk_VcGg%=S-e#lwjo?(3rFP$Y=c;2^Fehs%}s%gBN`TV}y;Yy}uhXWZ^T;b*NeERi_Fn zp~YJE4VK$gv{}F%UMNZ%O+@yhgRoc+R%3^+t3yw_mUd!19$6{(;KuYG095E(GY#+B z3V?fgw(V6Rqf8@2F+8#UOqs4_V+ejZQw)J@*A+%m#w)~rn4|Lqogbh=;3FAtjqG~bUB%r^NQW3S*2pT501TM;!e zcHvfwJHJ&2`|EANI9Z{(`dts}owjv{;i5-xKqcMaSvSyZ-Obo3%&riF0n|1qkFJCX z{lLf}sJ~5nx`MMc?s{=0ox73VInHk)Aby4P6R(}mb~!F%%(^%MpgBFIyJXsakV$uMhPPZcUKmqb`mJ7ZPv*JVS59^n9iWv~Z(n`0vam3&xV5g3Iz;N)} zkHv}{H=n{W+r(o@SQk!7^&ptm)3gNutPt0PPhpkfXOA_A$#i}C8d5D94J&15$=3>!@lrw;hM zTw}__Wg(04-O&w$R6#r&kj93f17`97b|wNjl?7=at&H18i5KQ*b#OCe;NPn$@SiSy zs#N|$WjI{%uL(2@61}Ui9PBsdU$AW!o_qIG+=~o45x%*|P^yOI;{dBp>J=bp!_cC9 zfQM$U*R;iPs;fys)NXQ#A#VjTIhKCUt7N5|Ei7^y6CC!)u{36xo=8XmK zh5g6=S6^o*#hziAnT$oCie8p9_SvtkiNzpZpQG;$;J3H@;2sjPNZOC#s!~W<(dn!7 zn;?_>G=`UGW>-OcN18{`+_iR|g%U)ES{Y+&MdIA*Uj1h>?IYq?qTzGNd&jh)v+Z=l z=MiEGQL#bthx4E+mYAL0fD8wzl&LSjRH`_U0iw47VUkw z7i+&%rsnBMBn}g-y}OodnSMGYgb8nr_^gTB@aB$svTrNibr-lgrDHK1j`QI*o@*WZ z*rjC;)&vJNrNNF$#d)o2k0SDh=&T^MuB@XGJQoUZeVZC%N~ka76_|UG!byYk7@f_{ z*nDrN5brnki}2`&&SWLizmCgs;}`qIKgz_$(w}qd`Tk{LB;tfhz+;)A0CnIZqnOB9 zIDo{~`kSaARg;LB8EYYh?SWW9qo7lDqRiXS@si;CZ4m#`)UBv zD!|z>z(vW)&*jVjWZ=^B5^z}wX=!t~qLQ3~lC-o0TtNvAf37O%@jnDlZ|D22kN=0D zpd^1&N%oBYhftx~dU!_Q{S(2=+chB2(a!~-;p~0K1*Yric-O_$#nJh(Z?B8W*&%=~ L(onln6Z7OhJ=b#J literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-icons_3d80b3_256x240.png b/docs/css/images/ui-icons_3d80b3_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..a8fe309eaf9d081e0da17ba1bb9570e08b762278 GIT binary patch literal 4549 zcmeHK2U8Qw)=okQgeFb85=9ZDg(gT1B^U@Dr1KJ_sPv{NHAq#u6afX{l`1XLrG_F% z6EHLlB_c>K(g`IO{bugW{SV(WJA2OV>@#Qg*_kuvJU7(8!$`+N2LJ#VwNaYJ008jZ z1#Hn$ozIinI!EUlOoqCqNM&sG|BwGFPNUA7XqA!#BSDHDzDboo5gEsx}DZfFfEtu2UqUtG>#C436ZF}k)% z2LVwf{(CP~C%4jl_RSp!RnO4m2SsTPYsQ1emFKs`f*@`}lJAV0f{afj3V@3RTH}}T;WmbRN zO$sF$81%y{I@+R--Th~Z*eWeEK3ECs4-lefVPTO3T}xVPges2nYkfg%{<=<@P;F-@ z9_VCM7iDJG1w9Ci^GnMj2>{AKTc(IF5~@rttfQdYK&X3SvVJ8@0Gsng1e2Kp8R%XT?Ha{==LT!;!s&nM<#T3O#~jf4(r?LNp3vh`IQWY@fAi9lT~WZH&rQG2 z(@nuaiU3!`T$wHYA1ld@B+CIpdzy14o(Mp{Zws-8sywq$5Q%$;FQs}(o6r?yWOn&B z(B?Vs=uoE&>q^8+2Lf{?W1o=FeaJ9bo)I|B}G=HuoGk#E`S}QS& z(q7&Tie+ptxDUp0Z2ihyu8EC=;^gp8p>jIT!0Ok4)$a;+dH(+Z#;H-9(8s_)34=Gc zxjJVCfl7&=@DY|+jL0q!^cjXS{)S`EYR}uVu1Hq>HbX}f_8Pniq$g$eDD&f17agwt zg;sojORVpmNTr*uw;h@ikPY%n=`HWh@QI|Qp#X@p`@21#e23$9V%=3bZ7QAD_o!(GKav!JSHUtr z3S+TdtV}zFfpfw+9@g2Amvm7cTH(ZYi?h&k1j>yZJ-D_XT&9d+XL?3F@yO;AQ~$8LXN zQ;ysn`c+nW0WZ;M$dg_5`U&)D{L%mnaFaFeN%{+mS#UQJ>vWXOmdcvRilxw@*P;@x zyL0lQIVbTTixA%)Eo4$BXelHzYGY(+$j{LM&}*Nar(K&iEQzmDbC&s4NpwUVCOUk+ zb7az_jycMQll+|?W3Ysg^{XR+xfgnAp-Zvi0z-gYQ<6EBGlh2j2XP$Ye8E z!~g?`nJQP;?_bv`Y1$+tzfMhsj0^|KYO~@6fm$Eq1 zlE8#gXVpcGAyT#+s9#az*@yY>dMiT!F1aIfKeu-s^zb7z$8A!y4Ze#^#LJuMy+9r8 zSBi!%_MtIsk4E3~RBF@}o8yP>Wr|Y5G3T zU~q}cel~Jrr@4iGUhniH0VEI16UP!tC2%orB!S3E^{D4g;O$>E}NBG^qU%&Wt z3q7at7nv9W=xvl$5l|s+p|1TTr&!iYLCW2E%Z(A$8kG+VPRm#L|D;VxAElrr1A}(O zN=6Kkj7nPeIxu?rI$$*B5pKGBa>pvCe$lL=_pG~$x$VljaPxsIxBI0OjqSSly&vY+6J5-k?GZU;2(v8RAwlyBQn$||Wh+Lyg@JWIO$lRhNM2iS5K5k5uJ^QPXk+>gK`XOn zlcBx`jprvNZtvYF%k?>Z9v6Oro7cc+<+#pgeV}NceEHT@9vWvaToRvY$3M~z)r(hi zFHs`@aoij zE-V}?*ocmYupF~+{Svy6QX(%ohg3&saS4*^6|d@ol1`3p_&fWb{YHxM-}gC zzABLuA{^az^vb{*5vS^*7a0ja;((EZ}Dfr)g*aFZ)=bc(zRi z?UeZUov<_vjMJPM84Z}-3j3SUA7h1cGR!LY-c%_K?e(B%tSrQlPc}n_i>QUm7LIvl zvxWd4v-msA?SfBbgTk_Wb9W`KsFrQCr`+)J9LrBRP4DsDugVmyGTL7HMZmU47or&8 zjnf%!PxFbJ*y^aV-sfb^wGs1+`r2|L%ZOmx8mu3B8+sh?F=UGPfEQ6r1vvE6rluG@ z=+wCRzT}1J@%PNEL^ZIIiR+_=j@oc`%%;4}3~u*IUeaJ9q8A+y6y(NiX!mVp=y})TcC_0Q3&kGnn9d`B5^ZaS{(Wmc za4*-EtukbkLFklTfX}vMKWB+BLE{z0Wk`J~&%QFV`Qh&I;ZJfjSBx)1hI8o{ommDj zfOl%&mh>SjV{APyj~Jjb!Di+IPE{>&2E?fj_MH9#v@oV~7wsLEVg~dh z1G|9!HqEJW_SV>&MHMuz209nmzYBqQ<o^J%B3Bvcw}f$fp?&_!`WD2eCJ-Thb|_hZjjL+2X_!0uzCqTCRS>f$u*R z$+O*l4##W}j>TbJSPhb~h)pf&Uls{mf*%9k_`~V+q9WsXs41apYrDs`&R)0r;@<+6 z4pI5(&>WU*VGLzEF`atFhGFv*=&e#qzX62qx(_>pqV>^)lfflG+vZ4;PrZy zAp@Ir-HQ7ZyhCEnx)plPLqLuuO`QPw)nY1 z@hgSyaM`!U-y}fzzT8rv&zNuimPuI7{m-$l(rJWvW+Or*C>yQg3_r zHGM5`kWrrO?}Y6oxX5N0ea#{g^3Fs)Q-QYOaX5y_E97xP^r?%2dUQT+f#P-h*1YHZ z-c#S}Z?h6(&auQu4nm*`Ul%v_*{-gNL?hl_pzZbJwKf0f8XUYp+Kc9>luKUL>Z|aX zAd~ylh8L-3RzN&Q>PJzWwKnbrVg$QdDML$n!tBa!{TDLz6T(=6{!8%($J8M+?KHy| z5h8MtF#)oNbD&D5=ny62lWI88L?yXd7}!k{TNbcM{SfZK z+%J)#es&Up#RO{ZtR|VKoe>2vVXfg`)UoTHoRQD=tVO%-16PPzX2W4vFHXbR*0E1r z8n$3{a6nTk?5ISP+oJX;Ja>r30#fVDJQ~h*DIeRnp*E&~`bu7gxfaTuG&qjYSly1v z^K=OId}q4=k9zD#RxtkSI2|{BwO#n5OiT>z1(%*5U*|`{Pbhd?5F-?z3S6KU5jwA& z$p#mC;#WkV?E-Aia-aJ4&d<)qUm5{^gdH)c%)fb z9;`yZ!>hq*yR%W$hQXDoXNA454J3^TYVa?zp1Cz~oj2as{g4)Z zj`n^|3JyL_=LR4Jmy{KQON&WLn!@E3WaJbiCB@)!3UK&KWq!B+A-H=wK6HNiKLj}i z+1m=z=lnl}a^=>;a{~9D2qvD+e*X48P5?DW&wEZVZFl?oPR365j!(UNos`ZG0ko0& KnicApXa50iY+M@v literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-icons_72a7cf_256x240.png b/docs/css/images/ui-icons_72a7cf_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd16e6e4e9da9334b44c8cccedf65fe82632775 GIT binary patch literal 4549 zcmeHK2U8Qw)=okQgaFc{D^V0dT4;jQP=bNbK{_u%ib`*aLVzGu=~4s~gjcGxh%~98 z2+{-$O=%H9dXXlCl8b&bcjo?w@0p!FXLt6Qv-|AKnRA{R8QfxG;AH>+08Bb)EfW9$ zc;*7O=xNU82_4XHRKsy5kd?oQfhmB8MFvc7)cPb-^73sT zqzjgpUAmv?k}{_T8Uw#*EqG1JR4h_98sFjiX|PKH#otulf-9{lhI1sno{5N-xhWur= z0J}{pH5rKe?j0R%*~{VaBSn0bo`o2!j1K?^!&q5ar9fAb)*7HnV*=Wrk()oSlE>BB z7>oNm*fhjgIP^gGg5vzsvdDsfGSHS8^0TBGvn$&O=q3>Ak(g{y2^YlYd=|xKrT}@c z>vg4Mokd25=acpg;(l`j)wdC_pZfV+88$J$8T?>dve-v3LP~qqk{~{tsb5REfSsK` zgmD6&h-romNyr}CVHfL{6O6R}qBF*4IftBZk{f|?LuUVu$WedK2MlSyzBNEcfL^kq zRHmJ0u232bOofj@2uC=O{BPI8tW(*#S%H-sbIz%7l`7P6YgU% zV>dF+q5Hq!R9we7v8cKGKGZ|NjOIf{NQBSyCg@Cxzi8A{>sDLJg7j@(c(f}9IPksh z|7p507^ehqGs>0S68OH7>_oQeC$*)yR1zlvn76GVHc-_kmWrZr_lc!6&*>97qm0cj z-UQk{3^CGix|+L|B+5Q5#p`L ziw$g3_57*{KHWt=o%cmUX=xhI*4WKq5{uJgYH zx3;f%l{>!=n!5@o$lF>D^mpT5w025QvuA`L+P@0%domMh{O+iW@z-koSW9Mlr%tn0 zVjiWlyo-xvsyDm~CU9>3%v`RHjf4{9iI1W3x-P)?F9ECH6z%f@{sD~9qPd_CfkBdn zuWoX8%nSgP6F(9otngUTT_ETa9BuNIz>(FKw`Wt4toC(=fiCPNcoPUCXLhRy5LOo* zFaL#hd|z{{->pdH>uxt48xv6V3QOtDZ%&DcORYJ>P$&1{e*J%hwLLS{i63 zJbg$3Wn)4rhS7Ak!59dZ0VYVpu2fz=pyl_pYn zR+b)iIP(zKdNrHA)-w_6a15r0vd#$njAM>9=wTNOTav4W3d>T-uhkl&>NhB;KObl7 zm2YvZ?c$?Etg}Tmf4Bdanvo7F>k}*dod&U>xpXx$5OqnrhP%C10>)7(eA^UljBx4- z5HaJ--GQyLDF}LtO+y~-YSfKmPU4sP;ehLGagWlUS^z;Cv>_>CmAZ@U&&o+B^g*KI zr(1`njT+d)d;~eb`5_ih8eYFV9F%*mhaS2VD?z#S=Lu6{PQ8YoZVZOHUG{M+9@BUJ z;bLl^@EerFw|2YYIp$-W(A^MK&!_xwt~xYuDK1!K0~W2v{&AgmK0^Ddg77mD-~HY} z$fW`s*~P}!d_Kl*^@v>$8$IXRsv7$u`SP53L?%*IiWhE)Q2+hSI&y_LW$wtAe;$== z4v*+(1hLTM>iPfcHYG!!gc8uLu8@`GBwKG*JR{K>V14~}Rk5J-z5*(gF$~HA1no0{ z)JqbW(Hd-e=uu?KmLu&8S|Z1gz-=ED2*5RWc<#scuA@G2nC_@mn!es|k$LjsW_k}$ z7ypH-sfWLB0^g%EFn(5eLQZ%>0x_qpAXG+n09N;@;=s2!*^lPui(sjC@5LU~gQY&`U;s7vHG-Dk z(+oz}xa=px*LIqkVe|SYA4nhtV4eh?R4PTdCsPM@atZeENfQ8ULg`{?BRs=z2mSoX zuUF_bO+3%c7zndfQA0w7d4xOnlbmDOF5pzU@|GJS-fLFgFE}Y*5%`lfrF@lfONNGR zN|j95NeVh?+55Nge4 zd+PHqxnRbvjHOEc0`~IO?SaW9`FBcpgkMF^_KpKRjf5)wqPF?m!ewh&TG&6fT$cfu~*UEBzPoBnwpX1>(^j$fs^f zSj>fmp|=Tb@(q~=f>NNsK*N}bYWJy6o|;k5vlfYV15?J6Qrr{_n;)7W4xBb&I0QcUrN!LyydCrg7g z2OO)CIUyp^t%olRZ9q;`LzP7t)S^3!+%>DOSJZydELF=Vd&~lUq;Q#q2J&%?7D{B> zR?tsLeA@|2!@{{NSWwY`*{!g@8T}z%BqzhXg8x;O^59-KX2#l50`+J!WT=Q%q-^1c zcQ$Jf@F7c}-NHWjL=G30<(IoFc}cBoqb=o{x7TQX$_eLyzoyLWQ1331ugSPoB>JmA zr5#J8F5I~!=45sA*$s7RLgCE8)BUE?k}b*gXB91RQ^Zas)n zpbtTJs4dMmZhWh~%4VO7E!S4uKk7^Ku^bbUeQTg@@O9`>yyu`9@*PoBDHY(@N1vKv ze6K_E`rDFcW=G#Lvl7+8%BF4)>f3AXOrroyk{=qbG+R%TIBO)F%R^m%Mt>RmJxQ|f z&FAs8aL~Bnl(G0?HCLFXm}uJN2eKjJ5`LF1mZmXC$^lJ6!wQMQKV&Tlv7Mch`|>yN zyOkAK83+z?#I{v6V8qdN=)HE0j1EyYQPZ!ICWyR(!{EcK@9#zrntP9N9%$5f)~bMt zX>k_417)`5t>y^(7Yb5_;}JcWKpf7U#mN5a%HY$^#qDVKN0v(6_)*;l0A>1?41>Ei z{NNt$Ejty+2&3=`OpxEMWItz#G*0Io#cf1;AMNfa(c_1o&BZRo&v%50N%Em?a ztaSHrAGZf$@+Qw&ZW)G|HYri|e!IpTp6*rf$-!p;P4^=OvW$O6+sV5jrf#pylt+$_ zUbxll#%I~i_IgVoRz|S4ZpYnfyLHWesPNGnP;nP{#uYSEdoyMdyCcY;548!*r7LE{ zJTSBm>}%DUD(7g4yZHsU=%ncv4UzutVF;e<XH5N%9YX|IwqeS ze5S=j`9``UL3#{&ptsev0}BhuE5nQsph7k~G90DKgZ1pX5CLf7$zU@w2px$RqxO5h zTxHC_XQGM-T~YM|Q~?4jkj9#*4Q6x)b|e5flmuuXEwHV_gbTB@+W2V-@bA^+`A!!< zRVaO-G8`=XRR@>`irkf73i2KG%il5$%enh0_C-3KFz;+c2vyzUvA<;p^$HNQZeU*4 z&rP%2W72Hj`cnBuzPCiDVWdL0p-rWsla`yRed+m3e#3dg#$djLfs-{|h-psoxKsXy zhxz79HIjv}J^q_VC>fr6>{>lfI1Eui!*xc&v{lU{Pfmia+g;RQzNL%24`f?BcvkA; z;IU?)4aOPg$^A;$UP6d&hQX>AQII#L3Ym)Z^$)|b%-$gn6QWOC6*Z#s2@6#3n>XgY z=Jy`^U45OE7;}atCJGLTE__+s&}+B4DjJP^eU84zpU=+XgIjR$0(mc*vr;~JS-ZEw zcbr1$RUcZUnOOnx9%>v$an;y*6o`}TYov{=6iBlxyLF!_w2w%m2?oz4?j6yF%(T%B zokxnwN5%xo9n66$nWMLN{L}3vlPACYTFE?-sNp16?FuXUH(QM1; z$4*TF zc}2OKiZW;XKZJ6XmV+|_&z}gUUM~It4!+I+btkVo&Tt(Mhr7-u&JIqGeR`ag&kg}} MPzG8R8rUcQ0oZ+pLjV8( literal 0 HcmV?d00001 diff --git a/docs/css/images/ui-icons_ffffff_256x240.png b/docs/css/images/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..cd6c26561dcce4ed91d3f9d6f98b6bf9feb03847 GIT binary patch literal 6299 zcmZu#cQ{;Mw>~q<7|})-qC`T78qrHe?>&h`$&hH#N3WyzV1gh-M)V*^^b$m(6GRPy zV3_El%`oB0?|%1tzI&hh$2sflbM|`nUTg33?svWMMh2SHl$R+10HD^^QZoSn(8VLL zOF?>ZSAXpZzcAp(x|(Xhd2GsH`$Y@tq4m(~!fO3+SD9D(L}7%e#CifB0-EPfVhjF(Y;v@dzkVhIR7>%_F!v+^<}pR(rD z`KCMf5E5QHTc$qiYr*$^Se2B?@u)>TV;K7i|KbgU(#c!}c^|-W`tl4t@mc_r;wH&7 zZ9I6Huj63Wkk)m_Sz^DcQzKku|6o8y14oLMhYQj|E03O}7zV5>IXP(s#t@i|~w%mv{W7Yg!(_A^@dV_R75Vl_T|oIHS7IOgJ^^c$ubp zG5=Ghc1OGV1FNT|J*}rszAuo;Mu&hW1b68zb+ahf!}V0Co$!yDVsEI4q~C^vJ(c#d zJYN%&wrjOcnd>al89iJ4%CCvG;&#i)%O({saBtpQGkx0AcThe=1m)0}=rXIg8+cGY za2j!Kzxi*lOIp^8aikO+&w+4WdTtLjFln+@SjRtKf&q!`+WpW$$6H(-?iyhOY-0>- zB)tNSLt}PIVY63WV?*9(eREL?!$9;ZRa(OD3onHDv<&WiYjY2tsS_P^2|Ec6qdFSh zy_&w_UNd0zK4g_dt0~RYuP0NvX?w|wCvORf8O&9M?=Gb4T@sM9e00$ki8OLmX%c$d;Azc9!XlCKQw#esFlYNedUgravl0 zZFVLx#-GnDEj!bFbTizrlpJa32(s)lRG_p@!T8@r8^W|aj_@m@FxwM{n%k7|E#xco z{iIhlT{>WJl;z{1k3{YK+W0X9{LVLtyiAEvET62T|@6?gS>b&DJy9Vwu>Gkwg8 z(sIJH2S^6PK)_W1I=p0Fi9;qOkYm(hT9hF*-d}CD%j;dzk$w?O5X^X~AhDsNT!>U1KkcESal zv>}{3zzp#$|5aOaR~Y<~O|oSBh_nth5s4v^T+(+Ge;NK|TEq$2Q;`l=Rr_ zy2l~>M@I1!Gj3h=lhW+lmJI7z=D3rgLgZRUanHx-7Wp+4`?r0ihUTXXs@vud9WkS(}yl1K-!UwC|Pv*2!F`&3@YfPa#{r3xB-{S%K>hM3z0e=F&f>2 zv!~q4$1T>S9SIaIkl$;YombU*TebRaiSp|XH+K=@%gPSOGQ0dEd*R`by$JhP2wD){ z9{xN*)WJY7zfe^;J7|W*0W1wFqUT^`*W$Q6xd`cNggyxXI^+ULb=*Ga?!hZ}J#(4Ae~b(x#|3Kqd++^|aO=6OnjS$f zrLaq>?foUVkI84-+66(|^gY(c&t81I*whg#;>T>)g%o_tIWOsL;hGzD9&x^w$!u?? zc1aX{ilHwH=a#hC{(;(vOj`fe>+61gbj6YUT1xIs-^bJ?uj>Nji@FL{t{;m2dLPyf zsn(Z6|G76&^k%3qx&qr+qW}F^j2nM)l1lE-&Z~uC)$r!3 z$w*KNn|M14Dsw}k%V+T+1fzevgyjAT+1)#8X^2G|50NdF-0i)Gu!`DjNo3?ni!qT@ zn}td;fOe>_IYYLWh3bBgCV&3EF75n&E2(%`{~7>McIa+YirconA~7b(#qu|e9F#Qw z2am*qNVOaWEb4J$(8aZZ3`?n%>vhpuNPi*2rLlR4js1vAi$7+okfFl6cbJDVweWFc zy~U*2gFNXlzimnQwU^YMqu&>||NV>}|*x#4Z|%qjk(6Y7&O z48E}aF}a`1ZT6O;a%#>wiIi}Y^KkPSZS~cPTw#;7u_*_}EOTOg3I$D_bqziW|Wlq z@ev=vZI{YeG)nK;FIa#1GkIxYN@se7jjYs{%UC9YU`042;#;Mzf`NuRVGI3-&4~Gr zs!7*|+&Hmx&Glb4EJ4RKD&d{y(Xf+>>Gjh_oAyK;`S})aL}$eiBrBc3E0iS(R^yPc zA7-ILR{RIL3(BjPTGW(IQ|A`g%+=%_9+mesD zg0RPmQoijBiUvz&{*0P3odtL%-S9SvW9KICq0|_w?F6WT1BWMN_Z&@r`RzOqwYEA_ zz1*E^4`>AMG}JXZQ9KIreO6l4rWR4pa&k)>z8P5fQ~?zK=N` z*eNQG0FL(!eJ;mjV}k%x6fd%V*yJqW^W~)imCc*}w6hV!)K#6fLL>3dvy^1@yY)QR zOA{psOfg(tqWwD<>-}ABrEt=cD9cBTw#AyMnfs!72CTwE6pymbX?KU$f32JQ;*55A zIVL)B4|^%9uR7M$v3E?60PZgsxh*>_^x`7GKKl+@NyCBLD67F=rnXtEv_#u(;XoIyFUx<&vU9K*-LM?ZkhUN?ojT@67{z%?axFPm4R~r=pvgt z7q50h)r6IJP?l6bGo3W}4N?e$03O1d#h;0ATKAvyB0q%(yuT{Zh<%}h2=DA??pYAt zTMi&-9pHE}sp@bB?pLsqbhn4kLJbHtHc*j9mEc6#%;#t1N-;YCAhKw{=XkDWA-eQI z;wx=5x{@<5mW12=6ry){EGerQz96PFB-n4>NB%+n>PL(}>oJH}NDSd(?|haoa)oHz zLr0AIj#7?r=$j1m6heWNX1u0mnP!^=e+7FSl)?VCF9LXFW`2UNbIAHSo-Wy1RfqaQ z06sl=9t?sB)BVHs{)O5PgjyraveieR=!ix0ELX^j&gZ*G~ZeZ2BJSq!THq67MyqTC_IJ}$`iS(o!#b86t z-Z71rxPWyQ^0_h?Ey?-7f8@irVYr1j%q`{G*SeErvTB5<=J{jH0mgrLFH2T_0?$?i zw=f6g=!a^l@#>U6SDUzEDI;)PJ>gWq>{AKs$OeN?@#3g3%(7ylVRee4WheXnOg9!H z1BzwgGkIGq|E}ny(f0=@F*l}qgnWn}R{1N$I`x6x^Qny;qtmWPj4N_-nF4uEKm z{JD9OXSH)LGsD7DH>e^tu%~5wr-G)DYdA|qABlLBK~&&jN+f`JvrsrZN+4Fn6Am9D zrND)1=_c6-QGJ469B!7durRTrPH>sp)j4Za{n}Gi`SClljR&OXXC*j}-gNr*HHUKC z(5hZdRi*C@h(U!9{sS@fg=oKL3*P-*b6^#i<@?L#Bjb0~>ODMQ6w%u#9yDN6gh|W-7gFfcBj_KiO+PE6~nW!Xk z903;K4N6cNbSKvTQVmSt>9}`!V)=w`N2(OX)xQv_la^t(pTjs^rfoIWY$ppd9=3TU z^85K1v9hNl0sQv*kr(!O&FTF+MRb+C|COB+vS+wBP+rhxPZSJT%m|SC3ZdW_W%*md z{F{sXgmHVZ)3WyE1xp2vtERY0cgePt--lK|y5AA#9CEu(P)m8buYIROs{E&UTd8-0 zM)*RHh{*CSrD(&Sv3PG``}^`{`-tzai`LuLa_~YFhKo=-rNklg;DFNvo2^eM9J)n? z%K0fPFMRd8&()bC9_n9c!4in{A`i7aT0-sgN&1>|?v=ZJ)v9?{oJA6TqP;earr!R> zv&u6!tA191ynGExYYXA1+BGT6un{BZG0E5A`noTlHc3PD2;;09U4D{qDVmhp|~VGjF+TwO1_5 zf%1m(OBuMwnyr%iJV|9#%L$+8th3CPY2=rC)B(@?;j@jNL?89;LnHZwR}!Iu>-;+X zPm;9%1adlOa+wsl9HW;Oq1J|&em1jKa>0;Ss^HuwP#_uz#(XfyseO2IlMTGNa<9jb z;3;lNGpg6m(2F%qGY^$q7WmwO4$X<1{2hstE3h$Yc4<0@H}JdKp-T83+kbAqnSXwn zepFVM*1D=)36}dtqE^SjF)gmrZf)Y2EI5o&dXGS4)}BXl88p@AG+Oi*RX^H(lKO5` zdQYE-B>XwWE9z$mO1uucc_@yoSk~>Y%G{ISIjqPS{9Og$>405b`$)FV1gYWv;7?t= zGXb5$R82|<9ABHu;7ou0?l9lLw)iZ8ffKTe0K(4iI+<-)(>~Qwohka>3KcTv!gNay zOk#dk!Wu9Qr{iUzH7@dN)8l?PLF0KEKh}UF0vf9^{L1l3{X!2;e7Sut^maRh)dVB; zG)*eru?7V-s(LTAKYV7|VI{cQ?KvUgQCO`yTRUV>qQWU(K&J_!N4<2Ia^i`pqX~BW zqF^SU{ey&#df>APuy9{S7~HE_R(sN78#q)m`O{R+;;iO17HuNv#-CHUU!SXEN(c$$>_!a8+Ba; zttQsRqD2j`HlmzQl*YM+)4M~uDSVBC0);%D8#ijI1x>D?)@8X#Qs{a@Hw6wBasu7> z;9;|O@vjDz79}%)Dsf6|c;1Xy)C7@3dv2iIlE>0B|D$K4W6FzDY-n=w`i4Yy_@Poq zOfe}CZq@iuI`kvPXln8|xpy=xY;>$v&Co&;|H4ffincnxR8=z%!I5Q_+2ptkbl%qoYV&LiwVs4S#kd*DKtyPV-+Xg%&@;`-I0uP#QIN@p zWAVGm)l+{CnKnsr45OS|qnrdh)9Q-Y%?{#xI#5|4X7Yph^1JIQCYsYa+#Otggb_ro z^;01npu0XAZ^|LnSDa|S^kB{u!*U|L{5{mmS$+%LKVd8wxhL!UcKpPLB*i=ycfyE{ ze%UbfJjqvmt2Nx8Rcuv&M*6?knx7K%j31F_SOi;RX?eT8?`-RB~kS| z;B4cI6FQtXkc8xaO8I|F6IrZb=DKTif}ptXQpyk;%c`g>W;co*DM%Q|*FtxVq5H;_ z(Mqw)C4nS*+Az^NC)N?SZHmhym3g43;D9udg~{7>$SE3*$RU!HX?5!9y1|K0W|*NU zdeFH4p%Z61lAJ&p^e{3PsK+ajq6D0zQv7esnZJN}husi8>yoWn6;tI#VRM}1qoqtg2EL%G<$#2tA} z?EeTHvD$#iBOy*0AP6ob+<)tUocu6_lJfQ*x|)=w%Sft)eBeg2PeJpL*L@M(7Q=$X z?WsV${B34g!{?Oj1EQz{lD6nZ5wJL%djC;ZT@q)>(xc9a($)>X^9R_yYK~~*_-z=) z!BuJs?-UpJlKD4Y>9TgF99hs+6VZ%C-K?{`R6tnl~NEX+YRM zFi#4!k^=q=>@tYies7YT#`v55q?sOZHyh_m%L#?weqAd~frl!b>vo8?%jKSj&=XgG zb3v+82h5nATT!XK!5{$|BqCsRRMEv+eHPjPPf(rvM7Fs|Y0;Oya~HAj?yRA1;oN5P zh5XaMahO%>PUQcB?d3Guw(V|)Fx6-FPp=N(c9^S%rL$`lI5P@%$?bPOH>ODM2}yOd zKQG9p_5fMWLlWX&Hvi!DAVIG9Pq1 zupd;l(qXLwgVIdJ#ApS#2o@?rO#({H0fQa4SkX?zXMV?95-hQ1`wI$Zvs&qN_4riF zAu{(DF}>swWutk8N4l9_YyvCLur*L?WiA^Ag~7Z1af&P6W7xekSo+D`q;?z|3I_1b z&VQI3r1xmLKWOP+4?7cC4^B355gFt^otQ1{6?^QFhkc@5<+=6DcS}+n>Gbe<@g=j3S&5;ugTcBhTlbz0&cP?l*=p+iwNi&ku_w~hZ zg9YLR(Ujr6;W1bx%Kcaf9~yDTsF=mCq4z?}zwWL6z}wcw+fMF@r`?4CZi$IY3X4ey zi;LeClaaeEEhjE6EG8`{CYGwm0_OtP{1C(vuAKP(jyV^L|nb_Ib1|a+F6fQae+Uf>sl`7T|{{`%}!!Q5< literal 0 HcmV?d00001 diff --git a/docs/css/jq.css b/docs/css/jq.css new file mode 100644 index 0000000..ae7e235 --- /dev/null +++ b/docs/css/jq.css @@ -0,0 +1,106 @@ +html { box-sizing: border-box; } +*, *:before, *:after { box-sizing: inherit; } +body,div,h1 {font-family:'trebuchet ms', verdana, arial;margin:0;padding:0;} +body {background-color:#fff;color:#333;margin:0;padding:0;} +h1,h2 {font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;margin:0;} +h1 {font-size:large;font-weight:400;} +h2 {color:#333;font-size:small;font-weight:400;} +h3 {color:#444;} +kbd {margin:0px 0.1em; padding:0.1em 0.6em;border-radius: 3px;border: 1px solid rgb(204, 204, 204);color: rgb(51, 51, 51);line-height: 1.4;font-family: Arial,Helvetica,sans-serif;font-size: 10px;display: inline-block;box-shadow: 0px 1px 0px rgba(0,0,0,0.2), inset 0px 0px 0px 2px #ffffff;background-color: rgb(247, 247, 247);-moz-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset;-webkit-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset;-moz-border-radius: 3px;-webkit-border-radius: 3px;text-shadow: 0 1px 0 #fff;} +.demo {width:600px;margin:20px auto;} +.demo h1,.demo h1 a {font-size:120%;text-align:center;text-decoration:none;color:#000;} +.demo p,.center {text-align:center;} +.demo table.tablesorter {font-size:14px;} +table th {vertical-align:top;} +#config th {text-shadow:none;} +table td.info { background: #eee; } +table.info {border:#000 1px solid;border-collapse:collapse;margin:10px 0 0 10px;} +table.tablesorter table.info tbody th,table.tablesorter table.info td {border:#000 1px solid;} +table.tablesorter table.info tbody th {background:#eee;} +table.options {width:100%;} +table.options pre {width:95%;} +table.options .property, .setwidth {width:115px;} +table.options .type {width:100px; } +table.options .defaults {width:160px;} +table.options .examples {width:60px;} +table.options thead th:nth-child(1) { width: 10%; } +table.options thead .defaults { width: 1%; } +table.compatibility { width: 50%; float: right; font-size: .8em; margin-left: 20px; } +table.compatibility th,table.compatibility td { text-align: center; padding: 2px; } +pre,#display {overflow-x:auto;padding:15px;border:1px solid #ddd;border-left-width:5px;} +pre.lang-js, pre.lang-javascript {border-left-color: #f1bf26;} +pre.lang-html {border-left-color: #ef6328;} +pre.lang-css {border-left-color: #27aae2;} +pre,#display {background-color:#eee;font-size:small;list-style:none;} +pre.prettyprint {padding:5px;} +code {background-color: #e6e6e6; padding: 1px 5px;} +a code {text-decoration:underline;} +pre.normal {background-color:transparent;border:none;border-left-width:0;overflow-x:auto;} +#logo {background:url(images/jq.png);display:block;float:right;height:31px;margin-right:10px;margin-top:10px;width:110px;} +#main {margin:0 20px 20px;padding:0 15px 15px 0;clear:both;} +#content {padding:20px;} +#busy {background-color:#e95555;border:1px ridge #ccc;color:#eee;display:none;padding:3px;position:absolute;right:7px;top:7px;} +#start,#case,.bright {color:#007baa;} +#demo strong {color:#a00;} +hr {height:1px;} +ul {list-style:square;padding-left:20px;} +#banner {margin:20px 20px 5px 20px;padding:0;text-align:left;} +#banner *,.demo h1,.demo h1 em {color:#232121;font-family:Georgia, Palatino, Times New Roman;font-size:30px;font-style:normal;font-weight:400;margin:0;padding:0;} +#banner h1 {display:block;float:left;} +#banner h1 em,.demo h1 em {color:#6cf;} +#banner h2 {float:right;font-size:26px;margin:10px 10px -10px -10px;} +#root #banner h2 { margin-right: 100px; } +#banner h3 {clear:both;display:block;font-size:12px;margin-top:-20px;border-bottom:1px solid #888;} +#banner a {display:block;font-size:14px;margin:5px 0 0;padding:10px 0 0;float:right;} +.github-btn {border:0;overflow:hidden;vertical-align: middle;} +a.external {background-image:url(../img/external.png);background-position:center right;background-repeat:no-repeat;padding-right:12px;} +a.link {background-image:url(../img/link.png);background-position:center right;background-repeat:no-repeat;padding-right:12px;} +form {font-size:10pt;margin-bottom:20px;width:auto;} +form fieldset {padding:10px;text-align:left;width:140px;} +div#main h1 {border-bottom:1px solid #cdcdcd;display:block;padding:4px 0 2px;} +table#tablesorter-demo {margin: 10px 0 0 0;} +table, p.small,.smallcode code {font-size:small;} +p.small {padding-left: 25px;} +.xsmall {font-size:11px;} +p.tip em, div.tip em,.label-info {padding: 2px; background-color: #5bc0de; color: #fff; border-radius: .25em;} +.label { padding: 0.1em 0.6em 0.1em; font-size: 75%; color: #fff; border-radius: .25em; } +span.tip em, .label-success, .version .label-success { background-color: #2b7e7e; } /*5cb85c*/ +.older .label-success { background-color: #8eCe8e; } +span.tip.old em, .label-default { background-color: #999; } +span.warning { background-color: #f0ad4e; } /* orange */ +span.warn em, .label.alert { background-color: #d9534f; } /* red */ +.label.warning { background-color: #f0ad4e; } +tr td.lookhere, span.lookhere { background-color: rgba(230,191,153,0.5); } +div.ui-slider .ui-slider-handle { width: 0.8em; height: 0.8em; } +.next-up { padding-top: 10px; font-size: 90%; } +.narrow-block { width: 50%; margin: 50px auto; } +.spacer { height: 800px; } +.halfspacer { height: 400px; } +.right { text-align:right; } +#pager-demo th.remove { width: 20px; } /* pager demo */ +#pager-demo button.remove { width: 20px; height: 20px; font-size: 10px; color: #800; } +.box { width: 50%; min-width: 300px; float: left; padding: 1%; } +a.alert, a.permalink.alert { color: #a00; padding: 0; } +span.alert { padding: 1px 3px; } +.hidden { display: none; } +.fade { opacity: 0.5; } +.results { color: red; } +.clear { clear: both; } +.good { color: #080; } +.bad { color: #800; } +.bootstrap_buttons button { margin: 5px 0 0 0; } +#main .ui-accordion-header a, #main .ui-accordion-content { font-size: 14px; } +#banner small { font-size: 16px; vertical-align: super; } +.accordion { position: relative; } +.accordion .accordion-link { position: absolute; right: 1%; margin-top: 16px; z-index: 1; width: 12px; height: 12px;} +.accordion .accordion .accordion-link { margin-top: 12px; } /* nested accordion */ +.tablesorter .accordion .accordion-link { margin-top: 11px; } +.remark, .error { font-weight: bold; color: red; font-size: 18px; } +table th.nobold { font-weight: normal; } +table th a { text-decoration: underline; color: #000; } +#group .ui-slider,#align .ui-slider { width: 100px; height: 3px; font-size: 0.8em; display: inline-block; margin-left: 10px; } +#group .demo-label,#align .demo-label { display: inline-block; min-width: 120px; } +#align .demo-label { display: inline-block; min-width: 150px; } +@media all and (max-width: 700px) { + table.compatibility, div.box { float: none; width: 100%; margin: 0; } +} diff --git a/docs/css/jquery-ui.min.css b/docs/css/jquery-ui.min.css new file mode 100644 index 0000000..24e9b43 --- /dev/null +++ b/docs/css/jquery-ui.min.css @@ -0,0 +1,7 @@ +/*! jQuery UI - v1.11.4 - 2015-03-11 +* http://jqueryui.com +* Includes: core.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, draggable.css, menu.css, progressbar.css, resizable.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande%2CLucida%20Sans%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=deedf7&bgTextureHeader=highlight_soft&bgImgOpacityHeader=100&borderColorHeader=aed0ea&fcHeader=222222&iconColorHeader=72a7cf&bgColorContent=f2f5f7&bgTextureContent=highlight_hard&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=362b36&iconColorContent=72a7cf&bgColorDefault=d7ebf9&bgTextureDefault=glass&bgImgOpacityDefault=80&borderColorDefault=aed0ea&fcDefault=2779aa&iconColorDefault=3d80b3&bgColorHover=e4f1fb&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=74b2e2&fcHover=0070a3&iconColorHover=2694e8&bgColorActive=3baae3&bgTextureActive=glass&bgImgOpacityActive=50&borderColorActive=2694e8&fcActive=ffffff&iconColorActive=ffffff&bgColorHighlight=ffef8f&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=25&borderColorHighlight=f9dd34&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=cd0a0a&bgTextureError=flat&bgImgOpacityError=15&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=eeeeee&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=90&opacityOverlay=80&bgColorShadow=000000&bgTextureShadow=highlight_hard&bgImgOpacityShadow=70&opacityShadow=30&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ + +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;min-height:0;font-size:100%}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none;cursor:pointer}.ui-selectmenu-button span.ui-icon{right:0.5em;left:auto;margin-top:-8px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:0.4em 2.1em 0.4em 1em;display:block;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Lucida Grande,Lucida Sans,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Lucida Grande,Lucida Sans,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#f2f5f7 url("images/ui-bg_highlight-hard_100_f2f5f7_1x100.png") 50% top repeat-x;color:#362b36}.ui-widget-content a{color:#362b36}.ui-widget-header{border:1px solid #aed0ea;background:#deedf7 url("images/ui-bg_highlight-soft_100_deedf7_1x100.png") 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #aed0ea;background:#d7ebf9 url("images/ui-bg_glass_80_d7ebf9_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#2779aa}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#2779aa;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #74b2e2;background:#e4f1fb url("images/ui-bg_glass_100_e4f1fb_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#0070a3}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#0070a3;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #2694e8;background:#3baae3 url("images/ui-bg_glass_50_3baae3_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #f9dd34;background:#ffef8f url("images/ui-bg_highlight-soft_25_ffef8f_1x100.png") 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#cd0a0a url("images/ui-bg_flat_15_cd0a0a_40x100.png") 50% 50% repeat-x;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_72a7cf_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_72a7cf_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_3d80b3_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_2694e8_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_2e83ff_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:6px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:6px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:6px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:6px}.ui-widget-overlay{background:#eee url("images/ui-bg_diagonals-thick_90_eeeeee_40x40.png") 50% 50% repeat;opacity:.8;filter:Alpha(Opacity=80)}.ui-widget-shadow{margin:-7px 0 0 -7px;padding:7px;background:#000 url("images/ui-bg_highlight-hard_70_000000_1x100.png") 50% top repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px} \ No newline at end of file diff --git a/docs/css/magnific-popup.css b/docs/css/magnific-popup.css new file mode 100644 index 0000000..3c176c5 --- /dev/null +++ b/docs/css/magnific-popup.css @@ -0,0 +1,405 @@ +/* Magnific Popup CSS */ +.mfp-bg { + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1042; + overflow: hidden; + position: fixed; + background: #0b0b0b; + opacity: 0.8; + filter: alpha(opacity=80); +} +.mfp-wrap { + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1043; + position: fixed; + outline: none !important; + -webkit-backface-visibility: hidden; +} +.mfp-container { + text-align: center; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + padding: 0 8px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.mfp-container:before { + content:''; + display: inline-block; + height: 100%; + vertical-align: middle; +} +.mfp-align-top .mfp-container:before { + display: none; +} +.mfp-content { + position: relative; + display: inline-block; + vertical-align: middle; + margin: 0 auto; + text-align: left; + z-index: 1045; +} +.mfp-inline-holder .mfp-content, .mfp-ajax-holder .mfp-content { + width: 100%; + cursor: auto; +} +.mfp-ajax-cur { + cursor: progress; +} +.mfp-zoom-out-cur, .mfp-zoom-out-cur .mfp-image-holder .mfp-close { + cursor: -moz-zoom-out; + cursor: -webkit-zoom-out; + cursor: zoom-out; +} +.mfp-zoom { + cursor: pointer; + cursor: -webkit-zoom-in; + cursor: -moz-zoom-in; + cursor: zoom-in; +} +.mfp-auto-cursor .mfp-content { + cursor: auto; +} +.mfp-close, .mfp-arrow, .mfp-preloader, .mfp-counter { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mfp-loading.mfp-figure { + display: none; +} +.mfp-hide { + display: none !important; +} +.mfp-preloader { + color: #cccccc; + position: absolute; + top: 50%; + width: auto; + text-align: center; + margin-top: -0.8em; + left: 8px; + right: 8px; + z-index: 1044; +} +.mfp-preloader a { + color: #cccccc; +} +.mfp-preloader a:hover { + color: white; +} +.mfp-s-ready .mfp-preloader { + display: none; +} +.mfp-s-error .mfp-content { + display: none; +} +button.mfp-close, button.mfp-arrow { + overflow: visible; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + display: block; + outline: none; + padding: 0; + z-index: 1046; + -webkit-box-shadow: none; + box-shadow: none; +} +button::-moz-focus-inner { + padding: 0; + border: 0; +} +.mfp-close { + width: 44px; + height: 44px; + line-height: 44px; + position: absolute; + right: 0; + top: 0; + text-decoration: none; + text-align: center; + opacity: 0.65; + filter: alpha(opacity=65); + padding: 0 0 18px 10px; + color: white; + font-style: normal; + font-size: 28px; + font-family: Arial, Baskerville, monospace; +} +.mfp-close:hover, .mfp-close:focus { + opacity: 1; + filter: alpha(opacity=100); +} +.mfp-close:active { + top: 1px; +} +.mfp-close-btn-in .mfp-close { + color: #333333; +} +.mfp-image-holder .mfp-close, .mfp-iframe-holder .mfp-close { + color: white; + right: -6px; + text-align: right; + padding-right: 6px; + width: 100%; +} +.mfp-counter { + position: absolute; + top: 0; + right: 0; + color: #cccccc; + font-size: 12px; + line-height: 18px; +} +.mfp-arrow { + position: absolute; + opacity: 0.65; + filter: alpha(opacity=65); + margin: 0; + top: 50%; + margin-top: -55px; + padding: 0; + width: 90px; + height: 110px; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +.mfp-arrow:active { + margin-top: -54px; +} +.mfp-arrow:hover, .mfp-arrow:focus { + opacity: 1; + filter: alpha(opacity=100); +} +.mfp-arrow:before, .mfp-arrow:after, .mfp-arrow .mfp-b, .mfp-arrow .mfp-a { + content:''; + display: block; + width: 0; + height: 0; + position: absolute; + left: 0; + top: 0; + margin-top: 35px; + margin-left: 35px; + border: medium inset transparent; +} +.mfp-arrow:after, .mfp-arrow .mfp-a { + border-top-width: 13px; + border-bottom-width: 13px; + top: 8px; +} +.mfp-arrow:before, .mfp-arrow .mfp-b { + border-top-width: 21px; + border-bottom-width: 21px; + opacity: 0.7; +} +.mfp-arrow-left { + left: 0; +} +.mfp-arrow-left:after, .mfp-arrow-left .mfp-a { + border-right: 17px solid white; + margin-left: 31px; +} +.mfp-arrow-left:before, .mfp-arrow-left .mfp-b { + margin-left: 25px; + border-right: 27px solid #3f3f3f; +} +.mfp-arrow-right { + right: 0; +} +.mfp-arrow-right:after, .mfp-arrow-right .mfp-a { + border-left: 17px solid white; + margin-left: 39px; +} +.mfp-arrow-right:before, .mfp-arrow-right .mfp-b { + border-left: 27px solid #3f3f3f; +} +.mfp-iframe-holder { + padding-top: 40px; + padding-bottom: 40px; +} +.mfp-iframe-holder .mfp-content { + line-height: 0; + width: 100%; + max-width: 900px; +} +.mfp-iframe-holder .mfp-close { + top: -40px; +} +.mfp-iframe-scaler { + width: 100%; + height: 0; + overflow: hidden; + padding-top: 56.25%; +} +.mfp-iframe-scaler iframe { + position: absolute; + display: block; + top: 0; + left: 0; + width: 100%; + height: 100%; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); + background: black; +} +/* Main image in popup */ +img.mfp-img { + width: auto; + max-width: 100%; + height: auto; + display: block; + line-height: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 40px 0 40px; + margin: 0 auto; +} +/* The shadow behind the image */ +.mfp-figure { + line-height: 0; +} +.mfp-figure:after { + content:''; + position: absolute; + left: 0; + top: 40px; + bottom: 40px; + display: block; + right: 0; + width: auto; + height: auto; + z-index: -1; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); + background: #444444; +} +.mfp-figure small { + color: #bdbdbd; + display: block; + font-size: 12px; + line-height: 14px; +} +.mfp-figure figure { + margin: 0; +} +.mfp-bottom-bar { + margin-top: -36px; + position: absolute; + top: 100%; + left: 0; + width: 100%; + cursor: auto; +} +.mfp-title { + text-align: left; + line-height: 18px; + color: #f3f3f3; + word-wrap: break-word; + padding-right: 36px; +} +.mfp-image-holder .mfp-content { + max-width: 100%; +} +.mfp-gallery .mfp-image-holder .mfp-figure { + cursor: pointer; +} +@media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px) { + /** + * Remove all paddings around the image on small screen + */ + .mfp-img-mobile .mfp-image-holder { + padding-left: 0; + padding-right: 0; + } + .mfp-img-mobile img.mfp-img { + padding: 0; + } + .mfp-img-mobile .mfp-figure:after { + top: 0; + bottom: 0; + } + .mfp-img-mobile .mfp-figure small { + display: inline; + margin-left: 5px; + } + .mfp-img-mobile .mfp-bottom-bar { + background: rgba(0, 0, 0, 0.6); + bottom: 0; + margin: 0; + top: auto; + padding: 3px 5px; + position: fixed; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .mfp-img-mobile .mfp-bottom-bar:empty { + padding: 0; + } + .mfp-img-mobile .mfp-counter { + right: 5px; + top: 3px; + } + .mfp-img-mobile .mfp-close { + top: 0; + right: 0; + width: 35px; + height: 35px; + line-height: 35px; + background: rgba(0, 0, 0, 0.6); + position: fixed; + text-align: center; + padding: 0; + } +} +@media all and (max-width: 900px) { + .mfp-arrow { + -webkit-transform: scale(0.75); + transform: scale(0.75); + } + .mfp-arrow-left { + -webkit-transform-origin: 0; + transform-origin: 0; + } + .mfp-arrow-right { + -webkit-transform-origin: 100%; + transform-origin: 100%; + } + .mfp-container { + padding-left: 6px; + padding-right: 6px; + } +} +.mfp-ie7 .mfp-img { + padding: 0; +} +.mfp-ie7 .mfp-bottom-bar { + width: 600px; + left: 50%; + margin-left: -300px; + margin-top: 5px; + padding-bottom: 5px; +} +.mfp-ie7 .mfp-container { + padding: 0; +} +.mfp-ie7 .mfp-content { + padding-top: 44px; +} +.mfp-ie7 .mfp-close { + top: 0; + right: 0; + padding-top: 0; +} \ No newline at end of file diff --git a/docs/css/menu.css b/docs/css/menu.css new file mode 100644 index 0000000..62a9235 --- /dev/null +++ b/docs/css/menu.css @@ -0,0 +1,72 @@ +/* top menu - http://codepen.io/jetpacmonkey/pen/ktIJz */ +*{box-sizing:border-box;} +html,body{min-height:100%;} +a{text-decoration:none;} +#main{transition:margin .3s ease;} +.main-nav{position:fixed;top:0;width:0;height:100%;background:#3B3B3B;color:#fff;overflow:hidden;transition:width .3s ease;} +.main-nav h2{color:#fff;font-size:20px;margin:0 0 15px 30px;} +.main-nav em{color:#6cf;font-style:normal;} +.main-nav .page-links a{display:block;background:linear-gradient(#3e3e3e,#383838);border-top:1px solid #484848;border-bottom:1px solid #2E2E2E;color:#FFF;white-space:nowrap;text-overflow:ellipsis;padding:10px;} +.main-nav a:hover,.main-nav a:focus{background:linear-gradient(#484848,#383838);color:#FFF;text-decoration:none;} +#main-nav-check:checked + #main-nav{width:250px;} +#main-nav-check:checked ~ #main{margin-left:250px;overflow:hidden;} +#main-nav-check:checked ~ #main .main-header{opacity:1;} +#root #main-nav-check:checked ~ #main #banner h1{padding-left:0;} +#root p{margin:1em 0;} +#root #banner{margin:0;} +#root #banner h1{padding-left:30px;border:0;} +#root #banner h2{margin-right:100px;} +#root div#main h1,#root div#main h3{line-height:normal;margin:0;} +#root #main{margin:0;padding:0 15px 15px;} +.page-search{padding:10px;} +.search-prev,.search-next,.search-clear{font-size:11px;padding:6px 3px;} +.input-group-btn{width:auto;} +.input-group input.search.form-control{width:100%;font-size:14px;border-radius:4px 0 0 4px!important;-webkit-border-radius:4px 0 0 4px!important;background-clip:padding-box;} +.status{position:absolute;right:60px;top:1em;background:#FFF;color:#555;font-size:9px;} +.status.busy{width:20px;height:20px;margin-top:-4px;background:no-repeat center center;background-color:#fff!important;background-image:url(../../addons/pager/icons/loading.gif);text-indent:100%;white-space:nowrap;overflow:hidden;} +.status.label-danger{color:#FFF;background-color:#d9534f;cursor:pointer;} +.highlight{background:#FF0;color:#000;cursor:pointer;padding:0 3px;} +.highlight.selected{background:orange;} +.message{margin:2px auto;} +/* http://codepen.io/pedrocampos/pen/gufrx */ +.main-header{background:#3B3B3B;color:#fff;text-align:center;vertical-align:middle;text-shadow:#222 0 -1px 1px;position:fixed;width:25px;height:25px;top:10px;left:10px;transition:all .3s ease;border-radius:5px;-webkit-border-radius:5px;background-clip:padding-box;z-index:10;cursor:pointer;opacity:.5;filter:alpha(opacity=50);padding:5px;} +.main-header:hover{opacity:1;filter:alpha(opacity=100);} +.main-header span{position:relative;top:7px;-webkit-transition-duration:0;-moz-transition-duration:0;-o-transition-duration:0;transition-duration:0;-webkit-transition-delay:.2s;-moz-transition-delay:.2s;-o-transition-delay:.2s;transition-delay:.2s;margin:0 auto;} +.main-header span:before,.main-header span:after{position:absolute;content:'';} +.main-header span,.main-header span:before,.main-header span:after{width:15px;height:2px;background-color:#fff;display:block;} +.main-header span:before{margin-top:-5px;-webkit-transition-property:margin, 0;-moz-transition-property:margin, 0;-o-transition-property:margin, 0;transition-property:margin, transform;-webkit-transition-duration:.2s;-moz-transition-duration:.2s;-o-transition-duration:.2s;transition-duration:.2s;-webkit-transition-delay:.2s, 0;-moz-transition-delay:.2s, 0;-o-transition-delay:.2s, 0;transition-delay:.2s, 0;} +.main-header span:after{margin-top:5px;-webkit-transition-property:margin, 0;-webkit-transition-duration:.2s;-moz-transition-duration:.2s;-o-transition-duration:.2s;transition-duration:.2s;-webkit-transition-delay:.2s, 0;-moz-transition-delay:.2s, 0;-o-transition-delay:.2s, 0;transition-delay:.2s, 0;} +#main-nav-check:checked ~ #main .main-header span{background-color:rgba(0,0,0,0.0);-webkit-transition-delay:.2s;-moz-transition-delay:.2s;-o-transition-delay:.2s;transition-delay:.2s;} +#main-nav-check:checked ~ #main .main-header span:before{margin-top:0;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);-webkit-transition-delay:0 .2s;-moz-transition-delay:0 .2s;-o-transition-delay:0 .2s;transition-delay:0 .2s;} +#main-nav-check:checked ~ #main .main-header span:after{margin-top:0;-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transition-delay:0 .2s;-moz-transition-delay:0 .2s;-o-transition-delay:0 .2s;transition-delay:0 .2s;} +/* http://www.cssflow.com/snippets/toggle-switches */ +.search-options{padding-left:6px;} +.switch{position:relative;display:inline-block;height:26px;width:100px;margin-top:5px;background:rgba(0,0,0,0.25);border-radius:3px;-webkit-border-radius:3px;background-clip:padding-box;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.3), 0 1px rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.3), 0 1px rgba(255,255,255,0.1);} +.switch-label{position:relative;z-index:2;float:left;width:48px;line-height:26px;font-size:11px;color:rgba(255,255,255,0.35);text-align:center;text-shadow:0 1px 1px rgba(0,0,0,0.45);cursor:pointer;} +.switch-label:active{font-weight:700;} +.switch-label-off{padding-left:2px;} +.switch-label-on{padding-right:2px;} +.switch-input:checked + .switch-label{font-weight:700;color:#ddd;text-shadow:0 1px rgba(128,128,128,0.25);-webkit-transition:.15s ease-out;-moz-transition:.15s ease-out;-o-transition:.15s ease-out;transition:.15s ease-out;} +.switch-selection{display:block;position:absolute;z-index:1;top:2px;left:2px;width:48px;height:22px;border-radius:3px;-webkit-border-radius:3px;background-clip:padding-box;-webkit-transition:left .15s ease-out;-moz-transition:left .15s ease-out;-o-transition:left .15s ease-out;transition:left .15s ease-out;} +.main-nav-check,.switch-input{display:none;} +.switch-selection-right{left:50px;} /* separated from next line or IE ignores it */ +.switch-input:checked + .switch-label-on ~ .switch-selection{left:50px;} +.glyphicon-question-sign{top:-6px;} +.glyphicon-question-sign:before{color: #666;text-shadow:#222 0 -1px 1px;} +.glyphicon-question-sign:before:hover{color: #357ebd;} +/* tipsy */ +.tipsy{font-size:12px;position:absolute;z-index:100000;padding:5px;} +.tipsy-inner{background-color:#000;color:#FFF;max-width:250px;text-align:center;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;padding:5px 8px 4px;} +.tipsy-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000;} +.tipsy-arrow-n{border-bottom-color:#000;} +.tipsy-arrow-s{border-top-color:#000;} +.tipsy-arrow-e{border-left-color:#000;} +.tipsy-arrow-w{border-right-color:#000;} +.tipsy-n .tipsy-arrow{top:0;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent;} +.tipsy-nw .tipsy-arrow{top:0;left:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent;} +.tipsy-ne .tipsy-arrow{top:0;right:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent;} +.tipsy-s .tipsy-arrow{bottom:0;left:50%;margin-left:-5px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent;} +.tipsy-sw .tipsy-arrow{bottom:0;left:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent;} +.tipsy-se .tipsy-arrow{bottom:0;right:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent;} +.tipsy-e .tipsy-arrow{right:0;top:50%;margin-top:-5px;border-left-style:solid;border-right:none;border-top-color:transparent;border-bottom-color:transparent;} +.tipsy-w .tipsy-arrow{left:0;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent;} diff --git a/docs/css/prettify.css b/docs/css/prettify.css new file mode 100644 index 0000000..eb11a34 --- /dev/null +++ b/docs/css/prettify.css @@ -0,0 +1,55 @@ +/* Hemisu Light */ +/* Original theme - http://noahfrederick.com/vim-color-scheme-hemisu/ */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { color: #111111; } + +@media screen { + .str { color: #739200; } /* string content */ + .kwd { color: #739200; } /* a keyword */ + .com { color: #888888; } /* a comment */ + .typ { color: #ff0055; } /* a type name */ + .lit { color: #538192; } /* a literal value */ + .pun { color: #111111; } /* punctuation */ + .opn { color: #111111; } /* lisp open bracket */ + .clo { color: #111111; } /* lisp close bracket */ + .tag { color: #111111; } /* a markup tag name */ + .atn { color: #739200; } /* a markup attribute name */ + .atv { color: #ff0055; } /* a markup attribute value */ + .dec { color: #111111; } /* a declaration */ + .var { color: #111111; } /* a variable name */ + .fun { color: #538192; } /* a function name */ +} +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { color: #060; } + .kwd { color: #006; font-weight: bold; } + .com { color: #600; font-style: italic; } + .typ { color: #404; font-weight: bold; } + .lit { color: #044; } + .pun, .opn, .clo { color: #440; } + .tag { color: #006; font-weight: bold; } + .atn { color: #404; } + .atv { color: #060; } +} +/* Style */ +pre.prettyprint { + font-family: Menlo, Monaco, Consolas, monospace; + font-size: 12px; + line-height: 1.5; + padding: 10px; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { margin-top: 0; margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, li.L1, li.L2, li.L3, li.L4, li.L5, li.L6, li.L7, li.L8, li.L9 { + /* */ +} + +/* Alternate shading for lines */ +li.L1, li.L3, li.L5, li.L7, li.L9 { + /* */ +} diff --git a/docs/css/rangeslider.css b/docs/css/rangeslider.css new file mode 100644 index 0000000..5f6b993 --- /dev/null +++ b/docs/css/rangeslider.css @@ -0,0 +1,87 @@ +.rangeslider, +.rangeslider__fill { + background: #e6e6e6; + display: block; + height: 10px; + width: 100%; + -moz-box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.3); + box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.3); + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; +} + +.rangeslider { + position: relative; + margin-top: 4px; +} + +.rangeslider--disabled { + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40); + opacity: 0.4; +} + +.rangeslider__fill { + background: #00ff00; + position: absolute; + top: 0; +} + +.rangeslider__handle { + background: white; + border: 1px solid #ccc; + cursor: pointer; + display: inline-block; + width: 20px; + height: 20px; + position: absolute; + top: -5px; + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIgc3RvcC1vcGFjaXR5PSIwLjAiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNncmFkKSIgLz48L3N2Zz4g'); + background-size: 100%; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(100%, rgba(0, 0, 0, 0.1))); + background-image: -moz-linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1)); + background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1)); + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1)); + -moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.3); + box-shadow: 0 0 8px rgba(0, 0, 0, 0.3); + -moz-border-radius: 50%; + -webkit-border-radius: 50%; + border-radius: 50%; +} +.rangeslider__handle:after { + content: ""; + display: block; + width: 9px; + height: 9px; + margin: auto; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIgc3RvcC1vcGFjaXR5PSIwLjEzIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjZmZmZmZmIiBzdG9wLW9wYWNpdHk9IjAuMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); + background-size: 100%; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(0, 0, 0, 0.13)), color-stop(100%, rgba(255, 255, 255, 0))); + background-image: -moz-linear-gradient(rgba(0, 0, 0, 0.13), rgba(255, 255, 255, 0)); + background-image: -webkit-linear-gradient(rgba(0, 0, 0, 0.13), rgba(255, 255, 255, 0)); + background-image: linear-gradient(rgba(0, 0, 0, 0.13), rgba(255, 255, 255, 0)); + -moz-border-radius: 50%; + -webkit-border-radius: 50%; + border-radius: 50%; +} +.rangeslider__handle:active { + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIgc3RvcC1vcGFjaXR5PSIwLjEiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4xMiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); + background-size: 100%; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(0, 0, 0, 0.1)), color-stop(100%, rgba(0, 0, 0, 0.12))); + background-image: -moz-linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.12)); + background-image: -webkit-linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.12)); + background-image: linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.12)); +} + +input[type="range"]:focus + .rangeslider .rangeslider__handle { + -moz-box-shadow: 0 0 8px rgba(255, 0, 255, 0.9); + -webkit-box-shadow: 0 0 8px rgba(255, 0, 255, 0.9); + box-shadow: 0 0 8px rgba(255, 0, 255, 0.9); +} diff --git a/docs/css/select2-3.4.6.min.css b/docs/css/select2-3.4.6.min.css new file mode 100644 index 0000000..bf9157d --- /dev/null +++ b/docs/css/select2-3.4.6.min.css @@ -0,0 +1 @@ +.select2-container{margin:0;position:relative;display:inline-block;zoom:1;*display:inline;vertical-align:middle}.select2-container,.select2-drop,.select2-search,.select2-search input{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.select2-container .select2-choice{display:block;height:26px;padding:0 0 0 8px;overflow:hidden;position:relative;border:1px solid #aaa;white-space:nowrap;line-height:26px;color:#444;text-decoration:none;border-radius:4px;background-clip:padding-box;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#eee),color-stop(0.5,#fff));background-image:-webkit-linear-gradient(center bottom,#eee 0,#fff 50%);background-image:-moz-linear-gradient(center bottom,#eee 0,#fff 50%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff',endColorstr = '#eeeeee',GradientType = 0);background-image:linear-gradient(to top,#eee 0,#fff 50%)}.select2-container.select2-drop-above .select2-choice{border-bottom-color:#aaa;border-radius:0 0 4px 4px;background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#eee),color-stop(0.9,#fff));background-image:-webkit-linear-gradient(center bottom,#eee 0,#fff 90%);background-image:-moz-linear-gradient(center bottom,#eee 0,#fff 90%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#eeeeee',GradientType=0);background-image:linear-gradient(to bottom,#eee 0,#fff 90%)}.select2-container.select2-allowclear .select2-choice .select2-chosen{margin-right:42px}.select2-container .select2-choice>.select2-chosen{margin-right:26px;display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;float:none;width:auto}.select2-container .select2-choice abbr{display:none;width:12px;height:12px;position:absolute;right:24px;top:8px;font-size:1px;text-decoration:none;border:0;background:url('select2.png') right top no-repeat;cursor:pointer;outline:0}.select2-container.select2-allowclear .select2-choice abbr{display:inline-block}.select2-container .select2-choice abbr:hover{background-position:right -11px;cursor:pointer}.select2-drop-mask{border:0;margin:0;padding:0;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:9998;background-color:#fff;filter:alpha(opacity=0)}.select2-drop{width:100%;margin-top:-1px;position:absolute;z-index:9999;top:100%;background:#fff;color:#000;border:1px solid #aaa;border-top:0;border-radius:0 0 4px 4px;-webkit-box-shadow:0 4px 5px rgba(0,0,0,.15);box-shadow:0 4px 5px rgba(0,0,0,.15)}.select2-drop.select2-drop-above{margin-top:1px;border-top:1px solid #aaa;border-bottom:0;border-radius:4px 4px 0 0;-webkit-box-shadow:0 -4px 5px rgba(0,0,0,.15);box-shadow:0 -4px 5px rgba(0,0,0,.15)}.select2-drop-active{border:1px solid #5897fb;border-top:0}.select2-drop.select2-drop-above.select2-drop-active{border-top:1px solid #5897fb}.select2-drop-auto-width{border-top:1px solid #aaa;width:auto}.select2-drop-auto-width .select2-search{padding-top:4px}.select2-container .select2-choice .select2-arrow{display:inline-block;width:18px;height:100%;position:absolute;right:0;top:0;border-left:1px solid #aaa;border-radius:0 4px 4px 0;background-clip:padding-box;background:#ccc;background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#ccc),color-stop(0.6,#eee));background-image:-webkit-linear-gradient(center bottom,#ccc 0,#eee 60%);background-image:-moz-linear-gradient(center bottom,#ccc 0,#eee 60%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee',endColorstr = '#cccccc',GradientType = 0);background-image:linear-gradient(to top,#ccc 0,#eee 60%)}.select2-container .select2-choice .select2-arrow b{display:block;width:100%;height:100%;background:url('select2.png') no-repeat 0 1px}.select2-search{display:inline-block;width:100%;min-height:26px;margin:0;padding-left:4px;padding-right:4px;position:relative;z-index:10000;white-space:nowrap}.select2-search input{width:100%;height:auto!important;min-height:26px;padding:4px 20px 4px 5px;margin:0;outline:0;font-family:sans-serif;font-size:1em;border:1px solid #aaa;border-radius:0;-webkit-box-shadow:none;box-shadow:none;background:#fff url('select2.png') no-repeat 100% -22px;background:url('select2.png') no-repeat 100% -22px,-webkit-gradient(linear,left bottom,left top,color-stop(0.85,#fff),color-stop(0.99,#eee));background:url('select2.png') no-repeat 100% -22px,-webkit-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url('select2.png') no-repeat 100% -22px,-moz-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url('select2.png') no-repeat 100% -22px,linear-gradient(to bottom,#fff 85%,#eee 99%) 0 0}.select2-drop.select2-drop-above .select2-search input{margin-top:4px}.select2-search input.select2-active{background:#fff url('select2-spinner.gif') no-repeat 100%;background:url('select2-spinner.gif') no-repeat 100%,-webkit-gradient(linear,left bottom,left top,color-stop(0.85,#fff),color-stop(0.99,#eee));background:url('select2-spinner.gif') no-repeat 100%,-webkit-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url('select2-spinner.gif') no-repeat 100%,-moz-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url('select2-spinner.gif') no-repeat 100%,linear-gradient(to bottom,#fff 85%,#eee 99%) 0 0}.select2-container-active .select2-choice,.select2-container-active .select2-choices{border:1px solid #5897fb;outline:0;-webkit-box-shadow:0 0 5px rgba(0,0,0,.3);box-shadow:0 0 5px rgba(0,0,0,.3)}.select2-dropdown-open .select2-choice{border-bottom-color:transparent;-webkit-box-shadow:0 1px 0 #fff inset;box-shadow:0 1px 0 #fff inset;border-bottom-left-radius:0;border-bottom-right-radius:0;background-color:#eee;background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#fff),color-stop(0.5,#eee));background-image:-webkit-linear-gradient(center bottom,#fff 0,#eee 50%);background-image:-moz-linear-gradient(center bottom,#fff 0,#eee 50%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee',endColorstr='#ffffff',GradientType=0);background-image:linear-gradient(to top,#fff 0,#eee 50%)}.select2-dropdown-open.select2-drop-above .select2-choice,.select2-dropdown-open.select2-drop-above .select2-choices{border:1px solid #5897fb;border-top-color:transparent;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(0.5,#eee));background-image:-webkit-linear-gradient(center top,#fff 0,#eee 50%);background-image:-moz-linear-gradient(center top,#fff 0,#eee 50%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee',endColorstr='#ffffff',GradientType=0);background-image:linear-gradient(to bottom,#fff 0,#eee 50%)}.select2-dropdown-open .select2-choice .select2-arrow{background:transparent;border-left:none;filter:none}.select2-dropdown-open .select2-choice .select2-arrow b{background-position:-18px 1px}.select2-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.select2-results{max-height:200px;padding:0 0 0 4px;margin:4px 4px 4px 0;position:relative;overflow-x:hidden;overflow-y:auto;-webkit-tap-highlight-color:rgba(0,0,0,0)}.select2-results ul.select2-result-sub{margin:0;padding-left:0}.select2-results ul.select2-result-sub>li .select2-result-label{padding-left:20px}.select2-results ul.select2-result-sub ul.select2-result-sub>li .select2-result-label{padding-left:40px}.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub>li .select2-result-label{padding-left:60px}.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub>li .select2-result-label{padding-left:80px}.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub>li .select2-result-label{padding-left:100px}.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub>li .select2-result-label{padding-left:110px}.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub>li .select2-result-label{padding-left:120px}.select2-results li{list-style:none;display:list-item;background-image:none}.select2-results li.select2-result-with-children>.select2-result-label{font-weight:bold}.select2-results .select2-result-label{padding:3px 7px 4px;margin:0;cursor:pointer;min-height:1em;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.select2-results .select2-highlighted{background:#3875d7;color:#fff}.select2-results li em{background:#feffde;font-style:normal}.select2-results .select2-highlighted em{background:transparent}.select2-results .select2-highlighted ul{background:#fff;color:#000}.select2-results .select2-no-results,.select2-results .select2-searching,.select2-results .select2-selection-limit{background:#f4f4f4;display:list-item;padding-left:5px}.select2-results .select2-disabled.select2-highlighted{color:#666;background:#f4f4f4;display:list-item;cursor:default}.select2-results .select2-disabled{background:#f4f4f4;display:list-item;cursor:default}.select2-results .select2-selected{display:none}.select2-more-results.select2-active{background:#f4f4f4 url('select2-spinner.gif') no-repeat 100%}.select2-more-results{background:#f4f4f4;display:list-item}.select2-container.select2-container-disabled .select2-choice{background-color:#f4f4f4;background-image:none;border:1px solid #ddd;cursor:default}.select2-container.select2-container-disabled .select2-choice .select2-arrow{background-color:#f4f4f4;background-image:none;border-left:0}.select2-container.select2-container-disabled .select2-choice abbr{display:none}.select2-container-multi .select2-choices{height:auto!important;height:1%;margin:0;padding:0;position:relative;border:1px solid #aaa;cursor:text;overflow:hidden;background-color:#fff;background-image:-webkit-gradient(linear,0% 0,0% 100%,color-stop(1%,#eee),color-stop(15%,#fff));background-image:-webkit-linear-gradient(top,#eee 1%,#fff 15%);background-image:-moz-linear-gradient(top,#eee 1%,#fff 15%);background-image:linear-gradient(to bottom,#eee 1%,#fff 15%)}.select2-locked{padding:3px 5px 3px 5px!important}.select2-container-multi .select2-choices{min-height:26px}.select2-container-multi.select2-container-active .select2-choices{border:1px solid #5897fb;outline:0;-webkit-box-shadow:0 0 5px rgba(0,0,0,.3);box-shadow:0 0 5px rgba(0,0,0,.3)}.select2-container-multi .select2-choices li{float:left;list-style:none}html[dir="rtl"] .select2-container-multi .select2-choices li{float:right}.select2-container-multi .select2-choices .select2-search-field{margin:0;padding:0;white-space:nowrap}.select2-container-multi .select2-choices .select2-search-field input{padding:5px;margin:1px 0;font-family:sans-serif;font-size:100%;color:#666;outline:0;border:0;-webkit-box-shadow:none;box-shadow:none;background:transparent!important}.select2-container-multi .select2-choices .select2-search-field input.select2-active{background:#fff url('select2-spinner.gif') no-repeat 100%!important}.select2-default{color:#999!important}.select2-container-multi .select2-choices .select2-search-choice{padding:3px 5px 3px 18px;margin:3px 0 3px 5px;position:relative;line-height:13px;color:#333;cursor:default;border:1px solid #aaa;border-radius:3px;-webkit-box-shadow:0 0 2px #fff inset,0 1px 0 rgba(0,0,0,0.05);box-shadow:0 0 2px #fff inset,0 1px 0 rgba(0,0,0,0.05);background-clip:padding-box;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#e4e4e4;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee',endColorstr='#f4f4f4',GradientType=0);background-image:-webkit-gradient(linear,0% 0,0% 100%,color-stop(20%,#f4f4f4),color-stop(50%,#f0f0f0),color-stop(52%,#e8e8e8),color-stop(100%,#eee));background-image:-webkit-linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:-moz-linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:linear-gradient(to top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%)}html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice{margin-left:0;margin-right:5px}.select2-container-multi .select2-choices .select2-search-choice .select2-chosen{cursor:default}.select2-container-multi .select2-choices .select2-search-choice-focus{background:#d4d4d4}.select2-search-choice-close{display:block;width:12px;height:13px;position:absolute;right:3px;top:4px;font-size:1px;outline:0;background:url('select2.png') right top no-repeat}html[dir="rtl"] .select2-search-choice-close{right:auto;left:3px}.select2-container-multi .select2-search-choice-close{left:3px}.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover{background-position:right -11px}.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close{background-position:right -11px}.select2-container-multi.select2-container-disabled .select2-choices{background-color:#f4f4f4;background-image:none;border:1px solid #ddd;cursor:default}.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice{padding:3px 5px 3px 5px;border:1px solid #ddd;background-image:none;background-color:#f4f4f4}.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close{display:none;background:0}.select2-result-selectable .select2-match,.select2-result-unselectable .select2-match{text-decoration:underline}.select2-offscreen,.select2-offscreen:focus{clip:rect(0 0 0 0)!important;width:1px!important;height:1px!important;border:0!important;margin:0!important;padding:0!important;overflow:hidden!important;position:absolute!important;outline:0!important;left:0!important;top:0!important}.select2-display-none{display:none}.select2-measure-scrollbar{position:absolute;top:-10000px;left:-10000px;width:100px;height:100px;overflow:scroll}@media only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min-resolution:2dppx){.select2-search input,.select2-search-choice-close,.select2-container .select2-choice abbr,.select2-container .select2-choice .select2-arrow b{background-image:url('select2x2.png')!important;background-repeat:no-repeat!important;background-size:60px 40px!important}.select2-search input{background-position:100% -21px!important}} \ No newline at end of file diff --git a/docs/css/select2-spinner.gif b/docs/css/select2-spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..5b33f7e54f4e55b6b8774d86d96895db9af044b4 GIT binary patch literal 1849 zcma*odr(tX9tZI2z31lM+(&YVk%mZ}5P~KlG2s=WSbGzm0!x7^P##Mnh7t-jP!X0Q zk_SQ}Po-L1tlDK;6l?(>v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$ zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_* zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k? z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5 z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4 zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6 z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD EAHN$8j{pDw literal 0 HcmV?d00001 diff --git a/docs/css/select2.png b/docs/css/select2.png new file mode 100644 index 0000000000000000000000000000000000000000..1d804ffb99699b9e030f1010314de0970b5a000d GIT binary patch literal 613 zcmV-r0-F7aP)#WY!I$JQV$)A5aAS1BM||2XVJl=+L1^1S1H% zM-&lx?NZpUrHhn>fk<>POqf2sh40}xxGZfc+t+#Eb(qHy9_3*1(U%t9t)QDnI#YAL(|ACV(>)>6WD-t!8tutHkdb^#3`HzoJG3A2@T`% zA|K@o*b!`R#(7)PWrMFn2))Ca3MR4(zaT`Zr61*kZK5NPnZwQszxh$fyv3?&4c>$q z2m=+yc0dRXRAsPDxF6sD;@rK4JGdR_``1S~o6Xi@2&aR6hcSrEp9HVRzEqVDqBn<1%hR=D4e1f^ra^A|34Cjc=Gny{F(o#MrvPYgZuTJOz(n)-F<| zj()qR;C={)N<0RRvDZ^@6ND+W*}gh-Lip(MDt!(zMSO)!j2j+*hxgzC-e3$@(O2p* zu;+gddm(cZwXTCLx*Ky4THOa*^b^F`woveIeCK^0aR|TJ00000NkvXXu0mjfA#WC6 literal 0 HcmV?d00001 diff --git a/docs/css/select2x2.png b/docs/css/select2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..4bdd5c961d452c49dfa0789c2c7ffb82c238fc24 GIT binary patch literal 845 zcmV-T1G4;yP)upQ6WKflyv?C|ADVW!U!t`EpA+x zB)5#EjWk-_X77YJZtQo`E0SF)^1bZr%)B7Cd`*OK*r z5WG-7e-R9G9^69ksDt29&oyHqxPSt|-S>xi3%PTd+GjY+BGF|nWC(7D-sd(kxqd9~ zS@2YF5vB+>dP8+$l^{oO3-lEWiGA*QIU)Wds#9M6RZ9N zcQ4y4)xqQOxD=vwu%7cz1nY#$lT&y8HCmkWgpwQP#3dhnYj9|2aS_R}IUF_^6s#$= zTm%~>A#oM?KIg$kh=<`gJkeoHa2LrulVy$Yx+N_0R3$4I!R*0677f(FKqm`2_o4~W z0h}fQZ`lC^1A+m;fM7uI(R1`S0KtG@KrkQ}5DW+&@cTnDVIow56KciMk7a899t0bC zC1KI{TsMe5NAR%GD_5`B-@ad4k~K3SO%H z_M31|`HV?E6)u$E3c&*<*n20+V@mRCop>R5;DWuZCmjSo7p@R&OYl^@G + + + + jQuery plugin: Tablesorter 2.0 - Adding a table row + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Click on the [ Add Rows ] button to add two new rows.
    • +
    • The "addRows" method was added in version 2.0.16, and is not part of the original plugin.
    • +
    • This example could have used the "update" method to add rows, but to remove rows only the "update" method works.
    • +
    • This method is better used for the pager plugin when not all of the rows are displayed.
    • +
    +

    + +

    Demo

    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-ajax.html b/docs/example-ajax.html new file mode 100644 index 0000000..a129081 --- /dev/null +++ b/docs/example-ajax.html @@ -0,0 +1,138 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Appending table data with ajax + + + + + + + + + + + + + + + + + + + + +
    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +Append new table data
    + +

    + NOTE! With the latest version of jQuery, this demo will only work when the ajax page is hosted online. +

    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-apply-widget.html b/docs/example-apply-widget.html new file mode 100644 index 0000000..99bffb5 --- /dev/null +++ b/docs/example-apply-widget.html @@ -0,0 +1,131 @@ + + + + + jQuery plugin: Tablesorter 2.0 - applyWidgetId vs. applyWidgets + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! Click on [ Apply Widget Id ], then sort the table a few times... then click on [ Apply Widgets ] and sort again (these methods are part of the original plugin). +

    + +

    Demo

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + +
    +
    + Next up: Columns widget ›› +
    + +
    + + + + diff --git a/docs/example-child-rows-filtered.html b/docs/example-child-rows-filtered.html new file mode 100644 index 0000000..919c7c1 --- /dev/null +++ b/docs/example-child-rows-filtered.html @@ -0,0 +1,634 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Child Rows with Filter Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +

    NOTE!

    +
      +
    • v2.22.0, +
        +
      • Added filter_childByColumn to allow filtering to work on child row columns. See the By Column demo below.
      • +
      • Extra white-space was added after each line in the child row content to account for the loss of white-space which occurs while processing cell content using textContent.
      • +
      • *NOTE* Start getting in the habit of using a class name to hide content as jQuery 3.0+ will likely change how show() & hide() work (ref).
      • +
      +

      +
    • +
    • As of v2.15.12, +
        +
      • This demo includes the pager widget.
      • +
      • Parents of child rows now have a tablesorter-hasChildRow class name added.
      • +
      • The last row of each page now includes any child rows. For example, on page 1, click on the "SO71783" row link and the associated child row will now show, as it should
      • +
      • NOTE! A new css definition was added to every default theme; the "filtered" class name (set by the filter_filteredRow widgetOption) has been added to properly hide/show child rows when filtered.
      • +
      • The additional code to always hide child row cells on pagerChange is no longer needed.
      • +
      +
    • +
    • Click the link in the Order # column to reveal the hidden child row cells (original demo). This option is available in the original plugin.
    • +
    • The filter widget will NOT work with the original tablesorter plugin.
    • +
    +
    + +

    Demo

    + Filter Child Row: Combined/Disabled | By Column +

    +

    Combined Child Row Content

    + filter_childRows : true + +
      +
    • If true, the child row content is included in ALL filters. Enter "cali" (california) in any column filter and the same rows show up.
    • +
    • When false, child row content is ignored. Enter "cali" and no rows will be found.
    • +
    + +
    + First + Prev + + Next + Last + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Order #CustomerPODateTotal
    + SO71774 + Good ToysPO348186287Jul 20, 2007$972.78
    Shipping Address
    99700 Bell Road
    Auburn, California 95603
    SO71775Cycle ClearancePO58159451May 6, 2007$2,313.13
    Shipping Address
    2255 254th Avenue Se
    Albany, Oregon 97321
    SO71776West Side MartPO19952192051May 12, 2007$87.09
    Shipping Address
    251 The Metro Center
    Wokingham, England RG41 1QW
    SO71777Demand DistributorsPO20097113391Apr 26, 2007$1,267.82
    Comment
    Please send ATTN: Judy
    Shipping Address
    25102 Springwater
    Wenatchee, Washington 98801
    SO71778Purchase MartPO19894146890Apr 18, 2007$1,503.98
    Shipping Address
    Wrentham Village
    Wrentham, Massachusetts 02093
    SO71779Initial Bike CompanyPO19633118218Dec 20, 2007$48,425.55
    Shipping Address
    789 West Alameda
    Westminster, Colorado 80030
    SO71780Nearby Cycle ShopPO19604173239Aug 29, 2007$42,452.65
    Shipping Address
    Burgess Hill
    Edward Way
    West Sussex, England RH15 9UD
    SO71781Sundry Sporting GoodsPO19401117806Mar 9, 2008$29,262.41
    Comment
    Please send ATTN: Rudolph
    Shipping Address
    595 Burning Street
    Vancouver, British Columbia V7L 4J4
    SO71782Professional Sales and ServicePO19372114749Jul 27, 2007$43,962.79
    Shipping Address
    57251 Serene Blvd
    Van Nuys, California 91411
    SO71783Eastside Department StorePO19343113609May 15, 2007$92,663.56
    Shipping Address
    9992 Whipple Rd
    Union City, California 94587
    SO71784Action Bicycle SpecialistsPO19285135919Nov 30, 2007$119,960.82
    Shipping Address
    Warrington Ldc Unit 25/2
    Woolston, England WA1 4SY
    SO71785Metro Cycle ShopPO19169115427Feb 1, 2008$39,805.12
    Comment
    Please send ATTN: Henry
    Shipping Address
    2507 Pacific Ave S
    Tacoma, Washington 98403
    SO71786Greater Bike StorePO17690128583Dec 7, 2007$4,657.19
    Shipping Address
    55 Lakeshore Blvd East
    Toronto, Ontario M4B 1V6
    SO71787Fun Toys and BikesPO18038111279Jun 1, 2007$38,211.11
    Shipping Address
    6500 East Grant Road
    Tucson, Arizona 85701
    SO71788Reliable Retail CenterPO17951176595Jul 10, 2007$1,806.12
    Shipping Address
    609 Evans Avenue
    Toronto, Ontario M4B 1V4
    SO71789Eastside Parts ShopPO17516128941May 22, 2007$143.50
    Comment
    Please send ATTN: Andrew
    Shipping Address
    7000 Victoria Park Avenue
    Toronto, Ontario M4B 1V4
    SO71790Successful Sales CompanyPO17487184338Apr 15, 2007$5,306.48
    Shipping Address
    7009 Sw Hall Blvd.
    Tigard, Oregon 97223
    SO71791Convenient Sales and ServicePO17139191080Nov 14, 2007$26,692.85
    Shipping Address
    950 Gateway Street
    Springfield, Oregon 97477
    SO71792Corner Bicycle SupplyPO17545115036Mar 17, 2008$67,683.32
    Shipping Address
    2511 Baker Road
    Toronto, Ontario M4B 1V7
    SO71793Mountain Toy StorePO17226152414Sep 5, 2007$1,943.93
    Comment
    Please send ATTN: Marvin
    Shipping Address
    First Colony Mall
    Sugar Land, Texas 77478
    SO71794Vigorous Exercise CompanyPO17574111985Dec 14, 2007$87,770.74
    Shipping Address
    9950 Ferrand Drive, 9th Floor
    Toronto, Ontario M4B 1V4
    SO71795Bike Part WholesalersPO17371184627Feb 6, 2008$41,224.10
    Shipping Address
    254a Baker Street
    Botany
    Sydney, New South Wales 1002
    SO71796Extreme Riding SuppliesPO17052159664Jul 13, 2007$63,686.27
    Shipping Address
    Riverside
    Sherman Oaks, California 91403
    SO71797Riding CyclesPO16501134889Dec 2, 2007$86,222.81
    Comment
    Please send ATTN: Jon
    Shipping Address
    Galashiels
    Liverpool, England L4 4HB
    SO71798Work and Play AssociationPO16994135863Jan 20, 2008$40,048.63
    Shipping Address
    2533 Eureka Rd.
    Southgate, Michigan 48195
    SO71799Metro Sports EquipmentPO15486196616Oct 18, 2007$23,080.67
    Shipping Address
    6, rue des Pyrenees
    Saint Ouen, Loir et Cher 41100
    SO71800Quick Parts and ServicePO15544127760Feb 19, 2008$37,253.44
    Shipping Address
    99954 Boul. Laurier, Local 060, Place
    Sainte-Foy, Quebec G1W
    SO71801Getaway InnPO15515173664Mar 6, 2008$47,720.54
    Comment
    Please send ATTN: Min
    Shipping Address
    54, avenue des Ternes
    Saint Ouen, Loir et Cher 41100
    SO71802Blue-Ribbon Bike CompanyPO15457184141Sep 22, 2007$42,013.42
    Shipping Address
    790 Shelbyville Road
    Saint Matthews, Kentucky 40207
    SO71803World of BikesPO15341174104Mar 1, 2008$43,964.97
    Shipping Address
    660 Lindbergh
    Saint Louis, Missouri 63103
    SO71804Bikes for TwoPO14906114459Aug 18, 2007$2,431.21
    Shipping Address
    63 West Beaver Creek
    Richmond Hill, Ontario L4E 3M5
    SO71805Nationwide SupplyPO14703194514Jun 27, 2007$76,535.55
    Comment
    Please send ATTN: Pilar
    Shipping Address
    4250 Concord Road
    Rhodes, New South Wales 2138
    SO71806Valley Toy StorePO14790111844Jun 2, 2007$20,261.90
    Shipping Address
    252851 Rowan Place
    Richmond, British Columbia V6B 3P7
    SO71807Courteous Bicycle SpecialistsPO14935135211Oct 28, 2007$656.84
    Shipping Address
    995 Crescent
    Richmond Hill, Ontario L4E 3M5
    SO71808Odometers and Accessories CompanyPO14761198562Oct 28, 2007$42,231.51
    Shipping Address
    253711 Mayfield Place, Unit 150
    Richmond, British Columbia V6B 3P7
    SO71809Fitness Bike AccessoriesPO14645153239Jan 12, 2008$3,743.42
    Comment
    Please send ATTN: John
    Shipping Address
    Level 7
    114 Albert Road
    Rhodes, New South Wales 2138
    SO71810Two-Seater BikesPO13804148315May 27, 2007$1,093.53
    Shipping Address
    5700 Legacy Dr
    Plano, Texas 75074
    SO71811Racing ToysPO13717180066Feb 26, 2008$3,493.04
    Shipping Address
    9228 Via Del Sol
    Phoenix, Arizona 85004
    SO71812Fashionable Bikes and AccessoriesPO13543115747Apr 28, 2007$35,146.04
    Shipping Address
    Sports Store At Park City
    Park City, Utah 84098
    SO71813Liquidation SalesPO13630186295Jan 17, 2008$12,707.47
    Comment
    Please send ATTN: Jenny
    Shipping Address
    No. 6
    Millenium Court
    Perth, South Australia 6006
    SO71814Our Sporting Goods StorePO12818173864May 31, 2007$7,517.54
    Shipping Address
    6030 Conroy Road
    Ottawa, Ontario K4B 1S3
    SO71815Thrifty Parts and SalesPO13021155785Jan 1, 2008$1,261.44
    Shipping Address
    Oxnard Outlet
    Oxnard, California 93030
    SO71816Engineered Bike SystemsPO12992180445Jul 29, 2007$3,754.97
    Shipping Address
    123 Camelia Avenue
    Oxnard, California 93030
    SO71817Home Town Bike StorePO12905185178May 21, 2007$689.96
    Comment
    Please send ATTN: Danielle
    Shipping Address
    955 Green Valley Crescent
    Ottawa, Ontario K4B 1S1
    SO71818Utilitarian Sporting GoodsPO12470139718Apr 25, 2007$61,356.31
    Shipping Address
    4635 S. Harrison Blvd.
    Ogden, Utah 84401
    SO71819Fabrikam Inc., WestPO12354153257May 19, 2007$41,746.15
    Shipping Address
    46460 West Oaks Drive
    Novi, Michigan 48375
    SO71820Racing Sales and ServicePO12673129941Apr 26, 2007$68,686.02
    Shipping Address
    510, avenue de Villiers
    Orleans, Loiret 45000
    SO71821Bike Goods PO11977190694May 25, 2007$5,904.88
    Comment
    Please send ATTN: Gary
    Shipping Address
    254075 Biscayne Blvd.
    North Miami Beach, Florida 33162
    SO71822Popular Bike LinesPO11774139099Dec 19, 2007$31,191.60
    Shipping Address
    Level 7
    80 Arthur Street
    Newcastle, New South Wales 2300
    SO71823Enterprise CenterPO11310159994Sep 7, 2007$2,818.81
    Shipping Address
    Kurfürstenstr 574
    München, Hessen 80074
    SO71824Outdoor Equipment StorePO11455162600Oct 29, 2007$115,117.41
    Shipping Address
    6 Cotton Road
    Nashua, New Hampshire 03064
    SO71825One Bike CompanyPO11165197222Dec 28, 2007$4,824.62
    Comment
    Please send ATTN: Shanay
    Shipping Address
    5 place Ville-Marie
    Montreal, Quebec H1Y 2H7
    SO71826Rodeway Bike StorePO11397155355Oct 29, 2007$40,083.06
    Shipping Address
    Winterfeldtstr 5557
    Kreditorenbuchhaltung
    Münster, Saarland 48001
    SO71827Metal Processing CompanyPO11107195325Aug 22, 2007$9,247.52
    Shipping Address
    770 Notre Datme Quest Bureau 800
    Montreal, Quebec H1Y 2H7
    SO71828Grand IndustriesPO11194153355Aug 10, 2007$52,553.87
    Shipping Address
    6333 Cote Vertu
    Montreal, Quebec H1Y 2H7
    SO71829Family Cycle StorePO10962123279Jul 16, 2007$40,095.88
    Comment
    Please send ATTN: James
    Shipping Address
    660 Saint-Jacques, Bureau 400
    Montreal, Quebec H1Y 2H8
    SO71830Petroleum Products DistributorsPO10875112195Nov 8, 2007$55,088.00
    Shipping Address
    20225 Lansing Ave
    Montreal, Quebec H1Y 2H7
    SO71831Tachometers and AccessoriesPO10295111084Aug 8, 2007$2,228.06
    Shipping Address
    Wymbush
    Milton Keynes, England MK8 8DF
    SO71832Closest Bicycle StorePO10353140756Sep 3, 2007$39,531.61
    Shipping Address
    Garamonde Drive, Wymbush
    PO Box 4023
    Milton Keynes, England MK8 8ZD
    SO71833Another Bicycle CompanyPO10411123072Jan 26, 2008$70,377.54
    Comment
    Please send ATTN: Stanley
    Shipping Address
    567 Sw Mcloughlin Blvd
    Milwaukie, Oregon 97222
    SO71834Rustic Bike StorePO377116268Feb 22, 2008$2,310.51
    Shipping Address
    Buergermeister-ulrich-str 3000
    Buchhaltung
    Augsburg, Bayern 86150
    SO71835Running and Cycling GearPO870120974Jun 13, 2007$71,605.92
    Shipping Address
    No. 60 Bellis Fair Parkway
    Bellingham, Washington 98225
    SO71836Safe Cycles ShopPO841118259Sep 13, 2007$90,216.85
    Shipping Address
    2681 Eagle Peak
    Bellevue, Washington 98004
    SO71837Riders CompanyPO1624180133Aug 24, 2007$39,989.36
    Comment
    Please send ATTN: Kim
    Shipping Address
    Tanger Factory
    Branch, Minnesota 55056
    SO71838Cycles Sales and RepairPO1305123041Sep 7, 2007$15,165.23
    Shipping Address
    3387, rue Marbeuf
    Bobigny, Seine Saint Denis 93000
    SO71839Front Runner BikesPO1537119063Jan 26, 2008$75,173.33
    Shipping Address
    DeSouth Square
    Bradenton, Florida 34205
    SO71840Community Department StoresPO1450191043Oct 2, 2007$1,234.39
    Shipping Address
    3639, rue des Grands Champs
    Boulogne-sur-Mer, Pas de Calais 62200
    SO71841Rural Cycle EmporiumPO1798133189Nov 23, 2007$112,758.77
    Comment
    Please send ATTN: Kathleen
    Shipping Address
    6388 Lake City Way
    Burnaby, British Columbia V5A 3A6
    SO71842Price-Cutter Discount BikesPO1740169151Nov 22, 2007$12.91
    Shipping Address
    6700 Boul Taschereau
    Brossard, Quebec J4Z 1C5
    SO71843Future BikesPO2001122796Jun 24, 2007$7,775.72
    Shipping Address
    67255 - 8th Street N.E., Suite 350
    Calgary, Alberta T2P 2G8
    SO71844Sales and Supply CompanyPO2813198985Jun 12, 2007$48,077.41
    Shipping Address
    Corporate Ofc A/p
    123 Fourth Ave
    Chantilly, Virginia 20151
    SO71845Trailblazing SportsPO2697119362Mar 4, 2008$45,992.37
    Comment
    Please send ATTN: Frank
    Shipping Address
    251340 E. South St.
    Cerritos, California 90703
    SO71846Sports StorePO2378131604Jul 2, 2007$2,711.41
    Shipping Address
    Internet House, 3399 Science Park
    Cambridge, England CB4 4BZ
    SO71847Camping and Sports StorePO18502143784Jul 15, 2007$119,981.15
    Shipping Address
    400-25155 West Pender St
    Vancouver, British Columbia V7L 4J4
    SO71848Locks CompanyPO18763153352Nov 9, 2007$16,667.88
    Shipping Address
    70259 West Sunnyview Ave
    Visalia, California 93291
    SO71849Principal Bike CompanyPO18125130930Jan 18, 2008$25,746.16
    Comment
    Please send ATTN: Alvaro
    Shipping Address
    Mountain Square
    Upland, California 91786
    SO71850Quitting Business DistributorsPO18241134627Aug 28, 2007$10,492.47
    Shipping Address
    University Plaza
    Tampa, Florida 33602
    SO71851Rapid BikesPO18299133687Jun 17, 2007$51,104.88
    Shipping Address
    992 St Clair Ave East
    Toronto, Ontario M4B 1V7
    SO71852Painters Bicycle SpecialistsPO20213171866Mar 24, 2008$10,406.62
    Shipping Address
    9975 Union St.
    Waterbury, Connecticut 06710
    SO71853Famous Bike ShopPO18531164420May 3, 2007$4,578.20
    Comment
    Please send ATTN: Jim
    Shipping Address
    999 West Georgia St.
    Vancouver, Ontario V5T 1Y9
    SO71854Helpful Sales and Repair Service PO16385143469Nov 11, 2007$36,819.69
    Shipping Address
    Licensing Account
    Seaford, Victoria 3198
    SO71855Self-Contained Cycle Parts CompanyPO18589189353Jun 23, 2007$429.62
    Shipping Address
    12, rue des Grands Champs
    Verrieres Le Buisson, Essonne 91370
    SO71856Transport BikesPO16530177647Nov 18, 2007$665.43
    Shipping Address
    25130 South State Street
    Sandy, Utah 84070
    SO71857First Cycle StorePO16269151631Jan 4, 2008$37,400.41
    Comment
    Please send ATTN: Mike
    Shipping Address
    25250 N 90th St
    Scottsdale, Arizona 85257
    SO71858Thrilling Bike ToursPO16153112278Oct 6, 2007$15,275.20
    Shipping Address
    4660 Rodeo Road
    Santa Fe, New Mexico 87501
    SO71859Bike WorldPO16182112142Apr 11, 2007$8,654.14
    Shipping Address
    60025 Bollinger Canyon Road
    San Ramon, California 94583
    SO71860Vinyl and Plastic Goods CorporationPO17835163979Feb 20, 2008$3,651.79
    Shipping Address
    No. 25800-130 King Street West
    Toronto, Ontario M4B 1V5
    SO71861Two Bike ShopsPO14152156429Nov 30, 2007$2,430.32
    Comment
    Please send ATTN: Jim
    Shipping Address
    35525-9th Street Sw
    Puyallup, Washington 98371
    SO71862Fad OutletPO14065190039Feb 19, 2008$1,622.62
    Shipping Address
    2550 Ne Sandy Blvd
    Portland, Oregon 97205
    SO71863Sports Products StorePO16124166561Apr 30, 2007$3,673.32
    Shipping Address
    Po Box 252525
    Santa Ana, California 92701
    SO71864Good Bike ShopPO14268188903Oct 9, 2007$37,623.76
    Shipping Address
    99433 S. Greenbay Rd.
    Racine, Wisconsin 53182
    SO71865Neighborhood Bicycle StorehousePO15109136609May 30, 2007$290.23
    Comment
    Please send ATTN: Cecilia
    Shipping Address
    69, boulevard Tremblay
    Roncq, Nord 59223
    SO71866Exchange Parts Inc.PO14297151936Jan 27, 2008$43,277.65
    Shipping Address
    7700 Green Road
    Raleigh, North Carolina 27603
    SO71867Vigorous Sports StorePO13050111529Jul 29, 2007$1,170.54
    Shipping Address
    Banbury
    Oxon, England OX16 8RS
    SO71868Cycle MerchantsPO14210134527Aug 15, 2007$1,932.67
    Shipping Address
    575 Rue St Amable
    Quebec, Quebec G1R
    SO71869Certified Sports SupplyPO14877155420Feb 21, 2008$143.50
    Comment
    Please send ATTN: Gabriele
    Shipping Address
    250551 Shellbridge Way
    Richmond, British Columbia V6B 3P7
    SO71870Accessories NetworkPO13195134898Feb 1, 2008$1,903.38
    Shipping Address
    699bis, rue des Peupliers
    Paris, Seine (Paris) 75008
    SO71871Remote Bicycle SpecialistsPO14239120760Aug 10, 2007$2,168.53
    Shipping Address
    No. 2000-25080 Beaver Hall Hill
    Quebec, Quebec G1R
    SO71872First CenterPO13137112099Jan 2, 2008$215.91
    Shipping Address
    22, rue Lafayette
    Pantin, Seine Saint Denis 93500
    SO71873Incomparable Bicycle StorePO12325121185Jul 5, 2007$5,941.29
    Comment
    Please send ATTN: Faith
    Shipping Address
    99 Edgewater Drive
    Norwood, Massachusetts 02062
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    <table class="tablesorter">
    +  <colgroup>
    +    <col width="85" />
    +    <col width="250" />
    +    <col width="100" />
    +    <col width="90" />
    +    <col width="70" />
    +  </colgroup>
    +  <thead>
    +    <tr>
    +      <th>Order #</th>
    +      <th>Customer</th>
    +      <th>PO</th>
    +      <th>Date</th>
    +      <th>Total</th>
    +    </tr>
    +  </thead>
    +  <tbody>
    +    <tr>
    +      <td rowspan="2"> <!-- rowspan="2" makes the table look nicer -->
    +        <a href="#" class="toggle">SO71774</a> <!-- link to toggle view of the child row -->
    +      </td>
    +      <td>Good Toys</td>
    +      <td>PO348186287</td>
    +      <td>Jul 20, 2007</td>
    +      <td>$972.78</td>
    +    </tr>
    +    <tr class="tablesorter-childRow">
    +      <td colspan="4">
    +        <div class="bold">Shipping Address</div>
    +        <div>99700 Bell Road<br>Auburn, California 95603</div>
    +      </td>
    +    </tr>
    +    <tr>
    +      <td rowspan="2"> <!-- rowspan="2" makes the table look nicer -->
    +        <a href="#" class="toggle">SO71775</a> <!-- link to toggle view of the child row -->
    +      </td>
    +      <td>Cycle Clearance</td>
    +      <td>PO58159451</td>
    +      <td>May 6, 2007</td>
    +      <td>$2,313.13</td>
    +    </tr>
    +    <tr class="tablesorter-childRow">
    +      <td colspan="4">
    +        <div class="bold">Shipping Address</div>
    +        <div>2255 254th Avenue Se<br>Albany, Oregon 97321</div>
    +      </td>
    +    </tr>
    +
    +    <!-- View page source for complete HTML markup -->
    +
    +  </tbody>
    +</table>
    +
    +<div id="pager" class="pager">
    +  <form>
    +    <input type="button" value="&lt;&lt;" class="first" />
    +    <input type="button" value="&lt;" class="prev" />
    +    <input type="text" class="pagedisplay"/>
    +    <input type="button" value="&gt;" class="next" />
    +    <input type="button" value="&gt;&gt;" class="last" />
    +    <select class="pagesize">
    +      <option selected="selected"  value="10">10</option>
    +      <option value="20">20</option>
    +      <option value="30">30</option>
    +      <option value="40">40</option>
    +    </select>
    +  </form>
    +</div>
    +
    + +
    + +

    childByColumn

    + filter_childByColumn : true +
      +
    • This option requires the filter_childRow option to be set to true in order to work.
    • +
    • If true, child row content can be filtered in the same manner as regular rows. Try searching for values in the "FastCar" column, or values between in the "RapidZoo" column. Only one match in a child row is required to show the entire parent/child group.
    • +
    • If false, child row content will be grouped together and included in any column search; as was the behavior before this option was added.
    • +
    • Extra css was added to override the theme row highlighting to group parent/child highlighting; it just doesn't look that good and it may be removed from the themes in the future.
    • +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    RegionFastCarRapidZooSuperGlue
    MiddleFCIDM2015Q1RZIDM2015Q1SGIDM2015Q1
    Joseph$ 423$ 182$ 255
    Lawrence$ 1,908$ 1,642$ 2,593
    Maria$ 1,502$ 1,969$ 3,408
    Matt$ 1,170$ 1,093$ 2,039
    NorthFCIDN2015Q1RZIDN2015Q1SGIDN2015Q1
    Joseph$ 3,643$ 2,846$ 1,574
    Lawrence$ 3,456$ 2,658$ 1,685
    Maria$ 3,235$ 2,616.99$ 1,612.33
    Matt$ 3,868$ 2,926$ 1,254
    WestFCIDW2015Q1RZIDW2015Q1SGIDW2015Q1
    Joseph$ 5,507$ 3,186$ 4,882
    Lawrence$ 4,082$ 4,272$ 6,124
    Maria$ 5,520$ 4,461$ 4,872
    Matt$ 5,737$ 4,598$ 4,233
    +
    + +

    CSS

    +
    +
    
    +	
    +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-child-rows.html b/docs/example-child-rows.html new file mode 100644 index 0000000..568e0c5 --- /dev/null +++ b/docs/example-child-rows.html @@ -0,0 +1,448 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Child Rows + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Click the link in the Order # column to reveal the hidden child row cells + (original demo).
    • +
    • This option is available in the original plugin.
    • +
    • This demo had the default child row class name changed from "expand-child" to "tablesorter-childRow" in v2.4.
    • +
    • As of v2.15.12, +
        +
      • Parents of child rows now have a tablesorter-hasChildRow class name added.
      • +
      • The last row of each page now includes any child rows. For example, on page 1, click on the "SO71783" row link and the associated child row will now show, as it should
      • +
      • NOTE! A new css definition was added to every default theme; the "filtered" class name (set by the filter_filteredRow widgetOption) has been added to properly hide/show child rows when filtered. Please see the Child Rows with Filter Widget demo.
      • +
      • The additional code to always hide child row cells on pagerChange is no longer needed.
      • +
      +
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Order #CustomerPODateTotal
    + SO71774 + Good ToysPO348186287Jul 20, 2007$972.78
    Shipping Address
    99700 Bell Road
    Auburn, California 95603
    SO71775Cycle ClearancePO58159451May 6, 2007$2,313.13
    Shipping Address
    2255 254th Avenue Se
    Albany, Oregon 97321
    SO71776West Side MartPO19952192051May 12, 2007$87.09
    Shipping Address
    251 The Metro Center
    Wokingham, England RG41 1QW
    SO71777Demand DistributorsPO20097113391Apr 26, 2007$1,267.82
    Comment
    Please send ATTN: Judy
    Shipping Address
    25102 Springwater
    Wenatchee, Washington 98801
    SO71778Purchase MartPO19894146890Apr 18, 2007$1,503.98
    Shipping Address
    Wrentham Village
    Wrentham, Massachusetts 02093
    SO71779Initial Bike CompanyPO19633118218Dec 20, 2007$48,425.55
    Shipping Address
    789 West Alameda
    Westminster, Colorado 80030
    SO71780Nearby Cycle ShopPO19604173239Aug 29, 2007$42,452.65
    Shipping Address
    Burgess Hill
    Edward Way
    West Sussex, England RH15 9UD
    SO71781Sundry Sporting GoodsPO19401117806Mar 9, 2008$29,262.41
    Comment
    Please send ATTN: Rudolph
    Shipping Address
    595 Burning Street
    Vancouver, British Columbia V7L 4J4
    SO71782Professional Sales and ServicePO19372114749Jul 27, 2007$43,962.79
    Shipping Address
    57251 Serene Blvd
    Van Nuys, California 91411
    SO71783Eastside Department StorePO19343113609May 15, 2007$92,663.56
    Shipping Address
    9992 Whipple Rd
    Union City, California 94587
    SO71784Action Bicycle SpecialistsPO19285135919Nov 30, 2007$119,960.82
    Shipping Address
    Warrington Ldc Unit 25/2
    Woolston, England WA1 4SY
    SO71785Metro Cycle ShopPO19169115427Feb 1, 2008$39,805.12
    Comment
    Please send ATTN: Henry
    Shipping Address
    2507 Pacific Ave S
    Tacoma, Washington 98403
    SO71786Greater Bike StorePO17690128583Dec 7, 2007$4,657.19
    Shipping Address
    55 Lakeshore Blvd East
    Toronto, Ontario M4B 1V6
    SO71787Fun Toys and BikesPO18038111279Jun 1, 2007$38,211.11
    Shipping Address
    6500 East Grant Road
    Tucson, Arizona 85701
    SO71788Reliable Retail CenterPO17951176595Jul 10, 2007$1,806.12
    Shipping Address
    609 Evans Avenue
    Toronto, Ontario M4B 1V4
    SO71789Eastside Parts ShopPO17516128941May 22, 2007$143.50
    Comment
    Please send ATTN: Andrew
    Shipping Address
    7000 Victoria Park Avenue
    Toronto, Ontario M4B 1V4
    SO71790Successful Sales CompanyPO17487184338Apr 15, 2007$5,306.48
    Shipping Address
    7009 Sw Hall Blvd.
    Tigard, Oregon 97223
    SO71791Convenient Sales and ServicePO17139191080Nov 14, 2007$26,692.85
    Shipping Address
    950 Gateway Street
    Springfield, Oregon 97477
    SO71792Corner Bicycle SupplyPO17545115036Mar 17, 2008$67,683.32
    Shipping Address
    2511 Baker Road
    Toronto, Ontario M4B 1V7
    SO71793Mountain Toy StorePO17226152414Sep 5, 2007$1,943.93
    Comment
    Please send ATTN: Marvin
    Shipping Address
    First Colony Mall
    Sugar Land, Texas 77478
    SO71794Vigorous Exercise CompanyPO17574111985Dec 14, 2007$87,770.74
    Shipping Address
    9950 Ferrand Drive, 9th Floor
    Toronto, Ontario M4B 1V4
    SO71795Bike Part WholesalersPO17371184627Feb 6, 2008$41,224.10
    Shipping Address
    254a Baker Street
    Botany
    Sydney, New South Wales 1002
    SO71796Extreme Riding SuppliesPO17052159664Jul 13, 2007$63,686.27
    Shipping Address
    Riverside
    Sherman Oaks, California 91403
    SO71797Riding CyclesPO16501134889Dec 2, 2007$86,222.81
    Comment
    Please send ATTN: Jon
    Shipping Address
    Galashiels
    Liverpool, England L4 4HB
    SO71798Work and Play AssociationPO16994135863Jan 20, 2008$40,048.63
    Shipping Address
    2533 Eureka Rd.
    Southgate, Michigan 48195
    SO71799Metro Sports EquipmentPO15486196616Oct 18, 2007$23,080.67
    Shipping Address
    6, rue des Pyrenees
    Saint Ouen, Loir et Cher 41100
    SO71800Quick Parts and ServicePO15544127760Feb 19, 2008$37,253.44
    Shipping Address
    99954 Boul. Laurier, Local 060, Place
    Sainte-Foy, Quebec G1W
    SO71801Getaway InnPO15515173664Mar 6, 2008$47,720.54
    Comment
    Please send ATTN: Min
    Shipping Address
    54, avenue des Ternes
    Saint Ouen, Loir et Cher 41100
    SO71802Blue-Ribbon Bike CompanyPO15457184141Sep 22, 2007$42,013.42
    Shipping Address
    790 Shelbyville Road
    Saint Matthews, Kentucky 40207
    SO71803World of BikesPO15341174104Mar 1, 2008$43,964.97
    Shipping Address
    660 Lindbergh
    Saint Louis, Missouri 63103
    SO71804Bikes for TwoPO14906114459Aug 18, 2007$2,431.21
    Shipping Address
    63 West Beaver Creek
    Richmond Hill, Ontario L4E 3M5
    SO71805Nationwide SupplyPO14703194514Jun 27, 2007$76,535.55
    Comment
    Please send ATTN: Pilar
    Shipping Address
    4250 Concord Road
    Rhodes, New South Wales 2138
    SO71806Valley Toy StorePO14790111844Jun 2, 2007$20,261.90
    Shipping Address
    252851 Rowan Place
    Richmond, British Columbia V6B 3P7
    SO71807Courteous Bicycle SpecialistsPO14935135211Oct 28, 2007$656.84
    Shipping Address
    995 Crescent
    Richmond Hill, Ontario L4E 3M5
    SO71808Odometers and Accessories CompanyPO14761198562Oct 28, 2007$42,231.51
    Shipping Address
    253711 Mayfield Place, Unit 150
    Richmond, British Columbia V6B 3P7
    SO71809Fitness Bike AccessoriesPO14645153239Jan 12, 2008$3,743.42
    Comment
    Please send ATTN: John
    Shipping Address
    Level 7
    114 Albert Road
    Rhodes, New South Wales 2138
    SO71810Two-Seater BikesPO13804148315May 27, 2007$1,093.53
    Shipping Address
    5700 Legacy Dr
    Plano, Texas 75074
    SO71811Racing ToysPO13717180066Feb 26, 2008$3,493.04
    Shipping Address
    9228 Via Del Sol
    Phoenix, Arizona 85004
    SO71812Fashionable Bikes and AccessoriesPO13543115747Apr 28, 2007$35,146.04
    Shipping Address
    Sports Store At Park City
    Park City, Utah 84098
    SO71813Liquidation SalesPO13630186295Jan 17, 2008$12,707.47
    Comment
    Please send ATTN: Jenny
    Shipping Address
    No. 6
    Millenium Court
    Perth, South Australia 6006
    SO71814Our Sporting Goods StorePO12818173864May 31, 2007$7,517.54
    Shipping Address
    6030 Conroy Road
    Ottawa, Ontario K4B 1S3
    SO71815Thrifty Parts and SalesPO13021155785Jan 1, 2008$1,261.44
    Shipping Address
    Oxnard Outlet
    Oxnard, California 93030
    SO71816Engineered Bike SystemsPO12992180445Jul 29, 2007$3,754.97
    Shipping Address
    123 Camelia Avenue
    Oxnard, California 93030
    SO71817Home Town Bike StorePO12905185178May 21, 2007$689.96
    Comment
    Please send ATTN: Danielle
    Shipping Address
    955 Green Valley Crescent
    Ottawa, Ontario K4B 1S1
    SO71818Utilitarian Sporting GoodsPO12470139718Apr 25, 2007$61,356.31
    Shipping Address
    4635 S. Harrison Blvd.
    Ogden, Utah 84401
    SO71819Fabrikam Inc., WestPO12354153257May 19, 2007$41,746.15
    Shipping Address
    46460 West Oaks Drive
    Novi, Michigan 48375
    SO71820Racing Sales and ServicePO12673129941Apr 26, 2007$68,686.02
    Shipping Address
    510, avenue de Villiers
    Orleans, Loiret 45000
    SO71821Bike Goods PO11977190694May 25, 2007$5,904.88
    Comment
    Please send ATTN: Gary
    Shipping Address
    254075 Biscayne Blvd.
    North Miami Beach, Florida 33162
    SO71822Popular Bike LinesPO11774139099Dec 19, 2007$31,191.60
    Shipping Address
    Level 7
    80 Arthur Street
    Newcastle, New South Wales 2300
    SO71823Enterprise CenterPO11310159994Sep 7, 2007$2,818.81
    Shipping Address
    Kurfürstenstr 574
    München, Hessen 80074
    SO71824Outdoor Equipment StorePO11455162600Oct 29, 2007$115,117.41
    Shipping Address
    6 Cotton Road
    Nashua, New Hampshire 03064
    SO71825One Bike CompanyPO11165197222Dec 28, 2007$4,824.62
    Comment
    Please send ATTN: Shanay
    Shipping Address
    5 place Ville-Marie
    Montreal, Quebec H1Y 2H7
    SO71826Rodeway Bike StorePO11397155355Oct 29, 2007$40,083.06
    Shipping Address
    Winterfeldtstr 5557
    Kreditorenbuchhaltung
    Münster, Saarland 48001
    SO71827Metal Processing CompanyPO11107195325Aug 22, 2007$9,247.52
    Shipping Address
    770 Notre Datme Quest Bureau 800
    Montreal, Quebec H1Y 2H7
    SO71828Grand IndustriesPO11194153355Aug 10, 2007$52,553.87
    Shipping Address
    6333 Cote Vertu
    Montreal, Quebec H1Y 2H7
    SO71829Family Cycle StorePO10962123279Jul 16, 2007$40,095.88
    Comment
    Please send ATTN: James
    Shipping Address
    660 Saint-Jacques, Bureau 400
    Montreal, Quebec H1Y 2H8
    SO71830Petroleum Products DistributorsPO10875112195Nov 8, 2007$55,088.00
    Shipping Address
    20225 Lansing Ave
    Montreal, Quebec H1Y 2H7
    SO71831Tachometers and AccessoriesPO10295111084Aug 8, 2007$2,228.06
    Shipping Address
    Wymbush
    Milton Keynes, England MK8 8DF
    SO71832Closest Bicycle StorePO10353140756Sep 3, 2007$39,531.61
    Shipping Address
    Garamonde Drive, Wymbush
    PO Box 4023
    Milton Keynes, England MK8 8ZD
    SO71833Another Bicycle CompanyPO10411123072Jan 26, 2008$70,377.54
    Comment
    Please send ATTN: Stanley
    Shipping Address
    567 Sw Mcloughlin Blvd
    Milwaukie, Oregon 97222
    SO71834Rustic Bike StorePO377116268Feb 22, 2008$2,310.51
    Shipping Address
    Buergermeister-ulrich-str 3000
    Buchhaltung
    Augsburg, Bayern 86150
    SO71835Running and Cycling GearPO870120974Jun 13, 2007$71,605.92
    Shipping Address
    No. 60 Bellis Fair Parkway
    Bellingham, Washington 98225
    SO71836Safe Cycles ShopPO841118259Sep 13, 2007$90,216.85
    Shipping Address
    2681 Eagle Peak
    Bellevue, Washington 98004
    SO71837Riders CompanyPO1624180133Aug 24, 2007$39,989.36
    Comment
    Please send ATTN: Kim
    Shipping Address
    Tanger Factory
    Branch, Minnesota 55056
    SO71838Cycles Sales and RepairPO1305123041Sep 7, 2007$15,165.23
    Shipping Address
    3387, rue Marbeuf
    Bobigny, Seine Saint Denis 93000
    SO71839Front Runner BikesPO1537119063Jan 26, 2008$75,173.33
    Shipping Address
    DeSouth Square
    Bradenton, Florida 34205
    SO71840Community Department StoresPO1450191043Oct 2, 2007$1,234.39
    Shipping Address
    3639, rue des Grands Champs
    Boulogne-sur-Mer, Pas de Calais 62200
    SO71841Rural Cycle EmporiumPO1798133189Nov 23, 2007$112,758.77
    Comment
    Please send ATTN: Kathleen
    Shipping Address
    6388 Lake City Way
    Burnaby, British Columbia V5A 3A6
    SO71842Price-Cutter Discount BikesPO1740169151Nov 22, 2007$12.91
    Shipping Address
    6700 Boul Taschereau
    Brossard, Quebec J4Z 1C5
    SO71843Future BikesPO2001122796Jun 24, 2007$7,775.72
    Shipping Address
    67255 - 8th Street N.E., Suite 350
    Calgary, Alberta T2P 2G8
    SO71844Sales and Supply CompanyPO2813198985Jun 12, 2007$48,077.41
    Shipping Address
    Corporate Ofc A/p
    123 Fourth Ave
    Chantilly, Virginia 20151
    SO71845Trailblazing SportsPO2697119362Mar 4, 2008$45,992.37
    Comment
    Please send ATTN: Frank
    Shipping Address
    251340 E. South St.
    Cerritos, California 90703
    SO71846Sports StorePO2378131604Jul 2, 2007$2,711.41
    Shipping Address
    Internet House, 3399 Science Park
    Cambridge, England CB4 4BZ
    SO71847Camping and Sports StorePO18502143784Jul 15, 2007$119,981.15
    Shipping Address
    400-25155 West Pender St
    Vancouver, British Columbia V7L 4J4
    SO71848Locks CompanyPO18763153352Nov 9, 2007$16,667.88
    Shipping Address
    70259 West Sunnyview Ave
    Visalia, California 93291
    SO71849Principal Bike CompanyPO18125130930Jan 18, 2008$25,746.16
    Comment
    Please send ATTN: Alvaro
    Shipping Address
    Mountain Square
    Upland, California 91786
    SO71850Quitting Business DistributorsPO18241134627Aug 28, 2007$10,492.47
    Shipping Address
    University Plaza
    Tampa, Florida 33602
    SO71851Rapid BikesPO18299133687Jun 17, 2007$51,104.88
    Shipping Address
    992 St Clair Ave East
    Toronto, Ontario M4B 1V7
    SO71852Painters Bicycle SpecialistsPO20213171866Mar 24, 2008$10,406.62
    Shipping Address
    9975 Union St.
    Waterbury, Connecticut 06710
    SO71853Famous Bike ShopPO18531164420May 3, 2007$4,578.20
    Comment
    Please send ATTN: Jim
    Shipping Address
    999 West Georgia St.
    Vancouver, Ontario V5T 1Y9
    SO71854Helpful Sales and Repair Service PO16385143469Nov 11, 2007$36,819.69
    Shipping Address
    Licensing Account
    Seaford, Victoria 3198
    SO71855Self-Contained Cycle Parts CompanyPO18589189353Jun 23, 2007$429.62
    Shipping Address
    12, rue des Grands Champs
    Verrieres Le Buisson, Essonne 91370
    SO71856Transport BikesPO16530177647Nov 18, 2007$665.43
    Shipping Address
    25130 South State Street
    Sandy, Utah 84070
    SO71857First Cycle StorePO16269151631Jan 4, 2008$37,400.41
    Comment
    Please send ATTN: Mike
    Shipping Address
    25250 N 90th St
    Scottsdale, Arizona 85257
    SO71858Thrilling Bike ToursPO16153112278Oct 6, 2007$15,275.20
    Shipping Address
    4660 Rodeo Road
    Santa Fe, New Mexico 87501
    SO71859Bike WorldPO16182112142Apr 11, 2007$8,654.14
    Shipping Address
    60025 Bollinger Canyon Road
    San Ramon, California 94583
    SO71860Vinyl and Plastic Goods CorporationPO17835163979Feb 20, 2008$3,651.79
    Shipping Address
    No. 25800-130 King Street West
    Toronto, Ontario M4B 1V5
    SO71861Two Bike ShopsPO14152156429Nov 30, 2007$2,430.32
    Comment
    Please send ATTN: Jim
    Shipping Address
    35525-9th Street Sw
    Puyallup, Washington 98371
    SO71862Fad OutletPO14065190039Feb 19, 2008$1,622.62
    Shipping Address
    2550 Ne Sandy Blvd
    Portland, Oregon 97205
    SO71863Sports Products StorePO16124166561Apr 30, 2007$3,673.32
    Shipping Address
    Po Box 252525
    Santa Ana, California 92701
    SO71864Good Bike ShopPO14268188903Oct 9, 2007$37,623.76
    Shipping Address
    99433 S. Greenbay Rd.
    Racine, Wisconsin 53182
    SO71865Neighborhood Bicycle StorehousePO15109136609May 30, 2007$290.23
    Comment
    Please send ATTN: Cecilia
    Shipping Address
    69, boulevard Tremblay
    Roncq, Nord 59223
    SO71866Exchange Parts Inc.PO14297151936Jan 27, 2008$43,277.65
    Shipping Address
    7700 Green Road
    Raleigh, North Carolina 27603
    SO71867Vigorous Sports StorePO13050111529Jul 29, 2007$1,170.54
    Shipping Address
    Banbury
    Oxon, England OX16 8RS
    SO71868Cycle MerchantsPO14210134527Aug 15, 2007$1,932.67
    Shipping Address
    575 Rue St Amable
    Quebec, Quebec G1R
    SO71869Certified Sports SupplyPO14877155420Feb 21, 2008$143.50
    Comment
    Please send ATTN: Gabriele
    Shipping Address
    250551 Shellbridge Way
    Richmond, British Columbia V6B 3P7
    SO71870Accessories NetworkPO13195134898Feb 1, 2008$1,903.38
    Shipping Address
    699bis, rue des Peupliers
    Paris, Seine (Paris) 75008
    SO71871Remote Bicycle SpecialistsPO14239120760Aug 10, 2007$2,168.53
    Shipping Address
    No. 2000-25080 Beaver Hall Hill
    Quebec, Quebec G1R
    SO71872First CenterPO13137112099Jan 2, 2008$215.91
    Shipping Address
    22, rue Lafayette
    Pantin, Seine Saint Denis 93500
    SO71873Incomparable Bicycle StorePO12325121185Jul 5, 2007$5,941.29
    Comment
    Please send ATTN: Faith
    Shipping Address
    99 Edgewater Drive
    Norwood, Massachusetts 02062
    + +
    +
    + + + + + + +
    +
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    <table class="tablesorter">
    +  <colgroup>
    +    <col width="85" />
    +    <col width="250" />
    +    <col width="100" />
    +    <col width="90" />
    +    <col width="70" />
    +  </colgroup>
    +  <thead>
    +    <tr>
    +      <th>Order #</th>
    +      <th>Customer</th>
    +      <th>PO</th>
    +      <th>Date</th>
    +      <th>Total</th>
    +    </tr>
    +  </thead>
    +  <tbody>
    +    <tr>
    +      <td rowspan="2"> <!-- rowspan="2" makes the table look nicer -->
    +        <a href="#" class="toggle">SO71774</a> <!-- link to toggle view of the child row -->
    +      </td>
    +      <td>Good Toys</td>
    +      <td>PO348186287</td>
    +      <td>Jul 20, 2007</td>
    +      <td>$972.78</td>
    +    </tr>
    +    <tr class="tablesorter-childRow">
    +      <td colspan="4">
    +        <div class="bold">Shipping Address</div>
    +        <div>99700 Bell Road<br>Auburn, California 95603</div>
    +      </td>
    +    </tr>
    +    <tr>
    +      <td rowspan="2"> <!-- rowspan="2" makes the table look nicer -->
    +        <a href="#" class="toggle">SO71775</a> <!-- link to toggle view of the child row -->
    +      </td>
    +      <td>Cycle Clearance</td>
    +      <td>PO58159451</td>
    +      <td>May 6, 2007</td>
    +      <td>$2,313.13</td>
    +    </tr>
    +    <tr class="tablesorter-childRow">
    +      <td colspan="4">
    +        <div class="bold">Shipping Address</div>
    +        <div>2255 254th Avenue Se<br>Albany, Oregon 97321</div>
    +      </td>
    +    </tr>
    +
    +    <!-- View page source for complete HTML markup -->
    +
    +  </tbody>
    +</table>
    +
    +<div id="pager" class="pager">
    +  <form>
    +    <input type="button" value="&lt;&lt;" class="first" />
    +    <input type="button" value="&lt;" class="prev" />
    +    <input type="text" class="pagedisplay"/>
    +    <input type="button" value="&gt;" class="next" />
    +    <input type="button" value="&gt;&gt;" class="last" />
    +    <select class="pagesize">
    +      <option selected="selected"  value="10">10</option>
    +      <option value="20">20</option>
    +      <option value="30">30</option>
    +      <option value="40">40</option>
    +    </select>
    +  </form>
    +</div>
    +
    + + + +
    + + + diff --git a/docs/example-css-highlighting.html b/docs/example-css-highlighting.html new file mode 100644 index 0000000..781f274 --- /dev/null +++ b/docs/example-css-highlighting.html @@ -0,0 +1,361 @@ + + + + + jQuery plugin: Tablesorter 2.0 - CSS Column & Row Highlights + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • The css in this demo only works with modern browsers (IE9+).
    • +
    • This css is originally from this CSS-Tricks article; it has been modified to work with tablesorter themes.
    • +
    • + It does not work properly on cells with rowspan or colspan within the tbody (I am referring to info-only tbodies, since tablesorter does not yet support sorting with these spans); if you do need a script to highlight spanned columns & rows, then take a look at the wholly plugin. +

      +
    • +
    • To add Hover Highlighting: +
        +
      • Add a class name of "hover-highlight" to enable hover row and column highlighting.
      • +
      • Include the CSS shown on this page.
      • +
      • If needed, modify the table background color & zebra striping row colors.
      • +
      • Modify the hover highlight row and/or column color definitions as desired (they can be different colors).
      • +
      +

      +
    • +
    • To add Focus Highlighting: +
        +
      • Add a class name of "focus-highlight" to enable focused cell with row and column highlighting.
      • +
      • Click on a table cell in the demo below to see the highlight; only one element, per page, can be active at a time.
      • +
      • Include the CSS and the extra javascript shown on this page to make table cells focusable.
      • +
      • If needed, modify the table background color & zebra striping row colors.
      • +
      • Modify the focus highlight row and/or column color definitions as desired (they can be different colors).
      • +
      +
    • +
    +

    + +

    Demo

    +
    + +
    +

    Hover + Focus Highlight

    + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent182.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56$153.1923%+9
    A256JohnClark44($19.89)25.1%(5)
    A23ElvisPresley24($9.99)50%(22)
    A10FrankCarter40-12.9920%(6)
    +
    + +
    +

    Hover Highlight Only

    + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent182.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56$153.1923%+9
    A256JohnClark44($19.89)25.1%(5)
    A23ElvisPresley24($9.99)50%(22)
    A10FrankCarter40-12.9920%(6)
    +
    + +
    +

    Focus Highlight Only (click on a tbody cell)

    + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent182.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56$153.1923%+9
    A256JohnClark44($19.89)25.1%(5)
    A23ElvisPresley24($9.99)50%(22)
    A10FrankCarter40-12.9920%(6)
    +
    + +
    +

    Zebra + Hover + Focus Highlight

    + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent182.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56$153.1923%+9
    A256JohnClark44($19.89)25.1%(5)
    A23ElvisPresley24($9.99)50%(22)
    A10FrankCarter40-12.9920%(6)
    +
    + +
    +

    Zebra + Hover Highlight Only

    + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent182.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56$153.1923%+9
    A256JohnClark44($19.89)25.1%(5)
    A23ElvisPresley24($9.99)50%(22)
    A10FrankCarter40-12.9920%(6)
    +
    + +
    +

    Zebra + Focus Highlight Only (click on a tbody cell)

    + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent182.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56$153.1923%+9
    A256JohnClark44($19.89)25.1%(5)
    A23ElvisPresley24($9.99)50%(22)
    A10FrankCarter40-12.9920%(6)
    +
    + + + +
    +
    + +

    CSS

    +
    +
    
    +	
    +

    Javascript

    +
    +
    
    +	
    + +
    + + + + + + diff --git a/docs/example-dragtable.html b/docs/example-dragtable.html new file mode 100644 index 0000000..e425964 --- /dev/null +++ b/docs/example-dragtable.html @@ -0,0 +1,245 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Dragtable Mod (beta) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    +
    +
    + +

    Notes

    +
    +
      +
    • This demo uses a modified version of the jQuery UI Dragtable widget (beta) to work with tablesorter.
    • +
    • This mod has been tested with the following widgets: alignChar, columns, cssStickyHeaders, editable, filter, grouping, headerTitles, math, output, pager print, reflow, resizable, repeatHeaders, staticRow, uitheme & zebra.
    • +
    • This mod does not currently work with the following widgets: +
        +
      • chart - needs more work to be compatible.
      • +
      • columnSelector - needs more work - making this compatible will require significant changes to the dragtable core.
      • +
      • saveSort - this saves the newly moved sorted column properly, but on page reload the column order is restored so it sorts the incorrect column.
      • +
      • scroller - way too much work to make this compatible.
      • +
      • stickyHeaders - needs more work - can't get the drag handle in the cloned sticky header from passing the mousedown on to the original drag handle.
      • +
      +
    • +
    • Any widgets not listed above can be assumed to be incompatible, for now.
    • +
    +
    + +

    Tablesorter setup

    +
    + A complete javascript example can be found in the demo section, below the table. +

    + To use this mod: +
      +
    • Initialize the dragtable mod script first, then initialize tablesorter.
    • +
    • Warning! When setting up the initialization code, make sure that the dragtable sortClass option exactly matches the tablesorter selectorSort option, or the table will be unsortable. +
      $('table')
      +  .dragtable({ sortClass: '.sorter' }) // this is already the default value
      +  .tablesorter({ selectorSort: '.sorter' }); // this default value is 'th, td'
    • +
    • Warning! Do not reference a column using jQuery data (e.g. $('th:contains(Name)').data('sorter', 'text');) or by it's zero-based index(1) because these references do not get updated after a column move! +

      + Instead, use one of the following methods (these examples set the column parser): +

      Set parser by data-attribute or header class

      +
      <tr>
      +	<th class="col-id" data-sorter="digit">...</th> <!-- parser set by data-attribute -->
      +	<th class="col-name drag-enable sorter-text">...</th> <!-- parser set by header class -->
      +	<th class="col-date drag-enable">...</th> <!-- parser set by headers option (see below) -->
      +</tr>
      +

      Or, set parser by headers option

      +
      $('table').tablesorter({
      +	headers : {
      +		'.col-date' : { sorter : 'shortDate' }
      +	}
      +});
    • +
    • In order to get dragtable to work, the mod will add a div to act as a dragable handle and wrap the header text in a div(2) which needs to be targeted by the selectorSort option to make it clickable for sorting. +

      + The resulting HTML may look like this: +
      <tr>
      +	<th class="col-id" data-sorter="digit">
      +		<div class="table-handle-disabled"></div>
      +		<!-- clicking on the "sort" wrapper below will not trigger a sort, because the cell is not set to sort -->
      +		<div class="sorter">9999</div>
      +	</th>
      +	<th class="col-name sorter-text drag-enable">
      +		<div class="table-handle"></div>
      +		<div class="sorter">Name</div>
      +	</th>
      +	<th class="col-date drag-enable">
      +		<div class="table-handle"></div>
      +		<div class="sorter">1/1/2015</div>
      +	</th>
      +</tr>
      +
    • +
    + (1) Options that use a column index (such as the sortList), or an array of settings (like the resizable_widths option) are updated internally by the mod. +

    + (2) The class name for the dragable handle is set by the dragtable dragHandle option & the class name for the clickable div wrapping the header text is set by the dragtable sortClass option. +
    + +
    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Student Grades
    Name (0) Major (1)Sex (2)English (3)Japanese (4)Calculus (5)Geometry (6)
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student01 (0)Languages (1)male (2)80 (3)70 (4)75 (5)80 (6)
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    + +

    HTML

    +
    +
    
    +		
    + +

    Javascript

    +
    +
    
    +		
    + +

    Optional CSS

    +
    +
    
    +		
    + +
    + + + diff --git a/docs/example-empty-table.html b/docs/example-empty-table.html new file mode 100644 index 0000000..92bc9da --- /dev/null +++ b/docs/example-empty-table.html @@ -0,0 +1,97 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Initializing tablesorter on an empty table + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! The presorting of an empty table and automatic sorting of appended data was added in version 2.0.14 (not part of the original plugin). +

    + +

    Demo

    +
    + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    + +Append new table data +
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +
    +
    +
    +	
    + +
    + + + diff --git a/docs/example-extending-defaults.html b/docs/example-extending-defaults.html new file mode 100644 index 0000000..cb94806 --- /dev/null +++ b/docs/example-extending-defaults.html @@ -0,0 +1,117 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Extending default options + + + + + + + + + + + + + + + + + + + + +
    +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-extractors-parsers.html b/docs/example-extractors-parsers.html new file mode 100644 index 0000000..3c7827a --- /dev/null +++ b/docs/example-extractors-parsers.html @@ -0,0 +1,125 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Using extractors with parsers + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • The extractor type was added in v2.17.6 and allows you to apply two parsers to a column: +
        +
      • In this demo, the last column contains select dropdowns that have "good", "medium" and "bad" options.
      • +
      • So there is a need to use a parser to extract content from the selected option within the select and then use the grades parser to give each grade a sortable value.
      • +
      • Thanks to TheSin- for adding this functionality!
      • +
      +
    • +
    • The extractor is always used before the parser.
    • +
    • Individual columns can be modified by adding the following (they all do the same thing), set in order of priority: +
        +
      • jQuery data data-extractor="select".
      • +
      • metadata class="{ extractor: 'select'}". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { extractor : 'select' } }.
      • +
      • header class name class="extractor-select".
      • +
      +
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorGenderEnglishJapaneseCalculusOverall grades
    Student01Languagesmale807075
    Student02Mathematicsmale9088100
    Student03Languagesfemale859580
    Student04Languagesmale205065
    Student05Mathematicsfemale707870
    Student06Mathematicsmale446560
    Student07Languagesfemale999289
    Student08Mathematicsfemale909890
    Student09Mathematicsmale557266
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-header-column-span.html b/docs/example-header-column-span.html new file mode 100644 index 0000000..a55cebd --- /dev/null +++ b/docs/example-header-column-span.html @@ -0,0 +1,100 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Sorting Across Multiple Columns + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Clicking on any of the sortable header cells will cause all columns below it to sort.
    • +
    • This demo will only work in tablesorter version 2.3+.
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Sort All Columns
    IndexFirst GroupSecond Group
    Natural SortNumericAnimalsUrl
    IndexNatural SortNumericAnimalsUrl
    0abc 12310Koalahttp://www.google.com
    1abc 1234Oxhttp://www.yahoo.com
    2abc 910Girafeehttp://www.facebook.com
    3zyx 24767Bisonhttp://www.whitehouse.gov/
    4abc 113Chimphttp://www.ucla.edu/
    5abc 256Elephanthttp://www.wikipedia.org/
    6abc 9155Lionhttp://www.nytimes.com/
    7ABC 1087Zebrahttp://www.google.com
    8zyx 1999Koalahttp://www.mit.edu/
    9zyx 120Llamahttp://www.nasa.gov/
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-locale-sort.html b/docs/example-locale-sort.html new file mode 100644 index 0000000..4541269 --- /dev/null +++ b/docs/example-locale-sort.html @@ -0,0 +1,170 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Sorting Accented Characters + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Accented characters will get replaced by their character equivalent when the sortLocaleCompare option is true.
    • +
    • In the javascript code block below you can see the default $.tablesorter.characterEquivalents table and an example of how to extend it to include other equivalents.
    • +
    • If you have a specific language requirement, please refer to the Language wiki pages to see if it is there. If not, please consider sharing the code or even just share the character equivalents themselves.
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeLocation
    a1a10AnderEParker28Béchar
    a1a2ÄndereHood33Bebington
    A1a1AndéreKent18Berlin
    A2b2CotÉAlmighty45Beckum
    A1d2CÔteEvans56Curaçao
    a2b11CÔtÉClark44Béjaïa
    A2b1ÇotePresley24Bekkevoort
    A1b0AndéréCarter40Bègles
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-meta-headers.html b/docs/example-meta-headers.html new file mode 100644 index 0000000..d839eed --- /dev/null +++ b/docs/example-meta-headers.html @@ -0,0 +1,129 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Disable headers using metadata + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Page Header

    +
    +
    <script src="js/jquery-latest.min.js"></script>
    +
    +<!-- Tablesorter: required -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- Tablesorter: optional (but required for this demo) -->
    +<script src="../js/extras/jquery.metadata.js"></script>
    +
    +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-meta-parsers.html b/docs/example-meta-parsers.html new file mode 100644 index 0000000..ed98525 --- /dev/null +++ b/docs/example-meta-parsers.html @@ -0,0 +1,121 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Setting column parser using metadata + + + + + + + + + + + + + + + + + + + + + + +
    +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Page Header

    +
    +
    <script src="js/jquery-latest.min.js"></script>
    +
    +<!-- Tablesorter: required -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- Tablesorter: optional (but required for this demo) -->
    +<script src="../js/extras/jquery.metadata.js"></script>
    +
    +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + \ No newline at end of file diff --git a/docs/example-meta-sort-list.html b/docs/example-meta-sort-list.html new file mode 100644 index 0000000..ec2b341 --- /dev/null +++ b/docs/example-meta-sort-list.html @@ -0,0 +1,123 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Setting initial sorting order with metadata + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Page Header

    +
    +
    <script src="js/jquery-latest.min.js"></script>
    +
    +<!-- Tablesorter: required -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- Tablesorter: optional (but required for this demo) -->
    +<script src="../js/extras/jquery.metadata.js"></script>
    +
    +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + \ No newline at end of file diff --git a/docs/example-method-sortreset.html b/docs/example-method-sortreset.html new file mode 100644 index 0000000..6095854 --- /dev/null +++ b/docs/example-method-sortreset.html @@ -0,0 +1,156 @@ + + + + + jQuery plugin: Tablesorter 2.0 - resetting the entire table sort + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Click on the reset button to reset the sort. The button can be used at any time.
    • +
    • Reset the table by triggering a sortReset event on the table (see the javascript code below).
    • +
    • This method was added in version 2.4.7.
    • +
    +

    + +

    Demo

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent182.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56$153.1923%+9
    A256JohnClark44($19.89)25.1%(5)
    A23ElvisPresley24($9.99)50%(22)
    A10FrankCarter40-12.9920%(6)
    + +

    Javascript

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-multiple-tbodies.html b/docs/example-multiple-tbodies.html new file mode 100644 index 0000000..e3d2c63 --- /dev/null +++ b/docs/example-multiple-tbodies.html @@ -0,0 +1,109 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Sorting with Multiple Tbodies + + + + + + + + + + + + + + + + + + + + + +
    +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameA-headB-headC-head
    NameA-footB-footC-foot
    This row is within the first tbody set as an info block - it is not sorted!
    DDDr1c1r1c2r1c3
    AAAr2c1r2c2r2c3
    CCCr3c1r3c2r3c3
    BBBr4c1r4c2r4c3
    summary info for the first group
    Another row referring to the first group
    Zorror5c1r5c2r5c3
    Calebr6c1r6c2r6c3
    Momor7c1r7c2r7c3
    Wolfier8c1r8c2r8c3
    summary info for the second group
    Ulyssesr9c1r9c2r9c3
    Peneloper10c1r10c2r10c3
    Edvaldr11c1r11c2r11c3
    Janr12c1r12c2r12c3
    summary info for the last group
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-custom-sort.html b/docs/example-option-custom-sort.html new file mode 100644 index 0000000..e30bd29 --- /dev/null +++ b/docs/example-option-custom-sort.html @@ -0,0 +1,150 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Using a Custom Sort Script + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Modified the textSorter option to allow setting the sorter per column v2.12: +
        +
      • *NOTE* The textSorter function parameters have changed! It is now function(a, b, direction, column, table) (previously function(a, b, table, column)).
      • +
      • The "Icelandic Alphabet" column is using the Sugar library to sort: +
          +
        • Solved (4/28/2014)! please note that at the time of this writing, there is an issue with it not sorting properly (ref)
        • +
        • You can tell it is working properly when you sort the Icelandic Alphabet column and the numeric column numbers are sequential (see row #37).
        • +
        +
      • +
      • The "Plain Text Sort" column is using a basic alphabetical sort (with localeCompare if set). Sort that column, then the last column to see how it differs from an alphanumeric sort.
      • +
      • The sorting of empty cells still occurs regardless of the custom textSorter setting.
      • +
      +
    • +
    • One custom sort used here is from the original tablesorter plugin v2.0.3. Sort the first "Plain Text Sort" column to see how it sorts alphanumeric data.
    • +
    • This option is not part of the original plugin (v2.2).
    • +
    +

    + +

    Demo

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NumericIcelandic AlphabetPlain Text SortAlphanumeric Sort
    01Aa1a10a1a10
    02Áa1a1a1a1
    03Ba2b2a2b2
    04Ca1a3a1a3
    05Da2b10a2b10
    06Ða1a20a1a20
    07Ea1b04a1b04
    08Éa1a0a1a0
    09Ęa1a4a1a4
    10Fa1a6a1a6
    11Ga1b5a1b5
    12Ha1b99a1b99
    13Ia2b5a2b5
    14Íb10b10
    15Jb3b3
    16Kb5b5
    17Lb7b7
    18Mb9b9
    19Nb12b12
    20Ob30b30
    21Ób45b45
    22Pb78b78
    23Qb67b67
    24Rb62b62
    25Sb01b01
    26Tb0b0
    27Ub77b77
    28Úb96b96
    29Va1b55a1b55
    30Wa1b84a1b84
    31Xb25b25
    32Yb41b41
    33Ýb79b79
    34Zb49b49
    35Þb94b94
    36Æb118b118
    37Öb80b80
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-date-format.html b/docs/example-option-date-format.html new file mode 100644 index 0000000..88ee8e5 --- /dev/null +++ b/docs/example-option-date-format.html @@ -0,0 +1,176 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Changing the date format + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • The dateFormat option was modified in version 2.0.23 (not part of the original plugin).
    • +
    • The dateFormat option will ONLY work with the shortDate parser.
    • +
    • The date can be separated by any of the following: slash, dash, period, comma, space(s) or tab (/-., ).
    • +
    • This date format parser will only work with a four digit year. You can write your own if you need a two digit year parser.
    • +
    • In versions 2.3+, columns can be disabled using any of the following methods (they all do the same thing), in order of priority: +
        +
      • jQuery data data-date-format="mmddyyyy" (see the Javascript block below on how to set it directly; data-dateFormat is equivalent to data-date-format).
      • +
      • metadata class="{ dateFormat: "mmddyyyy" }". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { dateFormat: "mmddyyyy" } }.
      • +
      • header class name class="dateFormat-mmddyyyy".
      • +
      • overall dateFormat option setting.
      • +
      +
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Date MMDDYYYYDate DDMMYYYYDate YYYYMMDD
    8-7-20117-8-20112011-8-7
    11/1/2011 12:34 AM1/11/2011 12:34 AM2011/11/1 12:34 AM
    12/28/201128/12/20112011/12/28
    6 30 201130 6 20112011 6 30
    11/1/2011 12:35 AM1/11/2011 12:35 AM2011/11/1 12:35 AM
    3.4.20114.3.20112011.3.4
    07 01-2011 1:15 PM01 7-2011 1:15 PM2011-7 01 1:15 PM
    04/5,20115/04,20112011,04/5
    11/1/2011 12:34 PM1/11/2011 12:34 PM2011/11/1 12:34 PM
    1/21 201121.1/20112011/1.21
    5.24-201124.5-20112011-5.24
    07/01-2011 12:15 PM01-7/2011 12:15 PM2011/7-01 12:15 PM
    10,14,201114,10,20112011,10,14
    09 07 2011 07 09 20112011 09 07
    2 27.201127 2.20112011 2 27
    8 07 2010 07 8 20102010 8 07
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-debug.html b/docs/example-option-debug.html new file mode 100644 index 0000000..8f57176 --- /dev/null +++ b/docs/example-option-debug.html @@ -0,0 +1,119 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Enabling debug mode + + + + + + + + + + + + + + + + + + + + +
    +

    + NOTE! If firebug is installed the debuging information will be displayed in the firebug console. +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-delay-init.html b/docs/example-option-delay-init.html new file mode 100644 index 0000000..6ac0ffa --- /dev/null +++ b/docs/example-option-delay-init.html @@ -0,0 +1,3365 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Demonstration of delayInit option + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! If firebug is installed the debuging information will be displayed in the firebug console. Watch for + "Building cache for..." row in particular. +

    + +

    Demo

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ConstellationBayer refFlamsteed noStart nameGCVS refGCVS noSAO noStar no Max mag Min magComp sepSpectral typeRA hrRA minRA secDEC +-DEC degDEC minDEC secPos err
    Andromedaalp21ALPHERATZ7376512.6.1481.5B8IVpMnHg0823.269+29525.551.3.58
    Andromedabet43MIRACH54471112.6.1480.4M0+IIIa1943.942+353713.931.3.23
    Andromedagam 157ALMAAK37734161.2.269.6.14K3-IIb2353.977+421946.961.2.14
    Andromedagam 257377352661.4.849.6.14B8V+A0V2354.731+421951.121.2.15
    Andromedadel315405861.3.2728.7.14K3III03919.704+305139.693
    Andromedaeps30741641.4.37G6IIIFe-3CH103833.345+291842.31.2.44
    Andromedazet34742674.6.14162.7K1IIe04720.329+24161.1.751.2.23
    Andromedaeta38743881.4.42131.7G8IIIb0571.12.58+23251.3.871.2.67
    Andromedathe24537771.4.61A2V0171.5.12+384053.61.2.54
    Andromedaiot17532161.4.29B8V23381.8.16+43165.12.141.2.23
    Andromedakap19532641.4.1446.8B9IVn234024.515+44202.5.141.2.67
    Andromedalam16532041.3.82217.6G8III-IV233733.857+462729.451.2.88
    Andromedamu37542811.3.87266.7A5V05645.223+382957.571.2.97
    Andromedanu35366991.4.53B5V+F8V04948.844+41443.941.2.29
    Andromedaxi46ADHIL371551.4.88K0-IIIb12220.423+453143.51.2.27
    Andromedaomi1526091.3.620.3B6IIIpe+A2p23155.27+421933.651.2.73
    Andromedapi29540331.4.3635.2B5V03652.869+33431.9.571.2.02
    Andromedarho27538281.5.18F5III0211.7.92+37587.8.141.3.36
    Andromedasig25537981.4.52A2V01819.676+36477.8.141.3.26
    Andromedatau53374181.4.9452.3B8III14034.781+403437.211.2.66
    Andromedaups50373624.9.14114F8V13647.831+412419.561.3.41
    Andromedaphi42369722581.4.2550.4B7Ve1930.174+471430.5.141.2.57
    Andromedachi52374061.4.98G8III13920.999+442310.8.141.2.35
    Andromedapsi20533551.4.95184G5Ib+A0V23461.2.62+462513.11.141.2.95
    Andromedaome48372281.4.83119F5IV12739.324+452424.321.3.61
    Andromeda2526235.1.140.4A3Vn23236.338+424528.161.2.55
    Andromeda3526491.4.65K0IIIbFe-0.52341.10.64+5031.7.511.2.63
    Andromeda4527111.5.3348.2K5III23739.269+462313.971.3.75
    Andromeda5527135.7.14F5V23745.389+491744.891.2.64
    Andromeda6527611.5.94F5IV231027.198+433239.71.2.77
    Andromeda7527871.4.52F0V231233.031+492422.711.2.45
    Andromeda8528711.4.85219.4M2+IIIBa0.3231744.676+49055.161.2.56
    Andromeda9AN100675288161.6.16A7Vm231823.356+414625.8.141.3.73
    Andromeda10529141.5.79M0III231952.346+42441.091.2.96
    Andromeda11529071.5.44K0III231929.759+483731.41.2.95
    Andromeda12731901.5.77121.1F5V232053.269+381056.151.2.99
    Andromeda13530391.5.75B9III23271.7.27+425442.961.2.45
    Andromeda14733111.5.22K0III233117.42+39141.10.631.2.33
    Andromeda15733461.5.59A1Vp233437.553+40141.11.391.2.68
    Andromeda18356425.3.14B9V23391.8.54+502817.981.2.46
    Andromeda22361235.3.14F2II01019.26+46420.171.3.16
    Andromeda23361731.5.72F0IV01330.884+4121.7.541.2.45
    Andromeda26362566.11.146.2.14B8V01842.123+434728.1.141.2.25
    Andromeda28GN10196740411.5.181.5.22139.3A7III(A5-F0)0301.7.39+29451.5.933.4.14
    Andromeda32540791.5.33G8III0411.7.21+392731.1.141.2.85
    Andromeda36743592561.5.4780.6K1IV05458.042+233742.131.2.07
    Andromeda39368741.5.9820.9.14A5m1254.268+412042.471.2.63
    Andromeda41369505.3.14A3m180.892+435631.951.2.86
    Andromeda44369841.5.65F8V11018.719+42453.371.2.24
    Andromeda45544941.5.810.4B7III-IV1111.10.02+374326.731.2.53
    Andromeda47546551.5.58A2Vm12340.585+374254.11.2.28
    Andromeda49372751.5.27K0III1301.6.95+47026.2.141.2.24
    Andromeda51373751.3.57K3-III13759.575+483741.571.2.76
    Andromeda55375875.4.1459.8gK115317.394+404347.281.2.77
    Andromeda56551071.5.67190.4K0III1561.9.39+37156.3.141.2.81
    Andromeda58552891.4.82A5IV-V2829.283+375132.951.2.85
    Andromeda59553301.5.6316.2.14B9V21052.76+39222.12.141.2.83
    Andromeda59553316.1.1416.2.14A1Vn21053.732+39234.921.2.02
    Andromeda60378671.4.83K3.5IIIBa0.5:21313.306+441354.31.2.96
    Andromeda62379485.3.14A1V21916.793+472247.971.2.39
    Andromeda63379601.5.59B9pSi22058.176+5091.5.271.2.67
    Andromeda64380051.5.19G8III22424.882+50023.521.3.08
    Andromeda65233191.4.71191.7K4+III22537.408+501643.081.3.28
    Andromeda66233536.12.14F4V22751.82+50341.11.481.4.31
    Antliaalp2014051.4.25K4III10271.9.34-3141.3.891.2.84
    Antliadel2014421.5.5610.9.14B9.5V102935.373-303625.781.2.76
    Antliaeps2004161.4.51K3IIIa92914.743-35571.5.571.2.87
    Antliazet 12004451.6.188A0V93046.125-315321.7.141.2.57
    Antliazet 22004591.5.93A9IV93132.211-315218.511.2.76
    Antliaeta2009261.5.2331.1.14F1III-IV95852.234-355327.9.142.11.14
    Antliathe1779081.4.790.1A8V+F7II-III9441.12.18-27461.10.371.2.37
    Antliaiot2019274.6.14K1III105643.09-37816.391.2.86
    Apusalp2571931.3.83K3IIIa144751.643-79241.161.4.21
    Apusbet2574241.4.2451.1K0III16431.4.06-773131.5.77
    Apusgam2574071.3.89G8-K0III163327.208-785349.411.5.05
    Apusdel 12573801.4.68102.9M5IIIb162020.785-784144.951.5.02
    Apusdel 22573811.5.27102.9K3III162026.798-78401.2.495.7.14
    Apuseps2571425.6.14B4V142222.68-80632.021.4.93
    Apuszet2538821.4.78K2-III172159.5-674613.291.4.88
    Apuseta2586931.4.91A2m141813.612-81027.431.4.27
    Apusthe2571125.5.14M6.5III:14519.773-764748.261.4.47
    Apusiot2574911.5.410.1B9V+B9.5V17221.5.65-70723.8.141.4.84
    Apuskap 12572891.5.4927B3IVe153130.767-732322.611.4.07
    Apuskap 22573071.5.6515B7III-IV154021.211-732648.291.4.07
    Aqillaalp53ALTAIR1251222260.77165.2A7V195047.001+8526.7.141.2.63
    Aqillabet60ALSHAIN1252351.3.71175G8IV195518.797+62424.311.3.43
    Aqillagam50TARAZED1052232251.2.72132.6K3II194615.59+103647.911.3.06
    Aqilladel301246031.3.36108.9F3IV192529.897+3653.211.2.28
    Aqillaeps13DENEB EL OKAB1043184.2.14131.1K1-IIICN0.5Ba0.2185937.363+1541.5.761.2.85
    Aqillazet17DENEB EL OKAB1044612191.2.99158.6A0Vn19524.611+135148.441.2.99
    Aqillaeta551251593.9.14F6Ib195228.373+1020.251.2.84
    Aqillathe651441502271.3.23113.7B9.5III201118.288-04917.271.2.69
    Aqillaiot411435971.4.3647B5III193643.298-1171.11.391.2.38
    Aqillakap391436001.4.95B0.5III193653.462-7139.081.2.23
    Aqillalam161430211.3.44B9Vn19614.938-45257.011.2.29
    Aqillamu381247991.4.45177.5K3-IIIbCN0.519341.5.71+72244.051.2.55
    Aqillanu321246281.4.66201F2Ib192631.082+02019.141.3.68
    Aqillaxi591252101.4.71G9+IIIb195414.867+82741.031.2.01
    Aqillaomi541053385.11.1414.4.14F8V19511.1.26+102456.281.2.83
    Aqillapi521052821.5.721.4.14G2III:+A1V:194842.083+114857.441.2.96
    Aqillarho671058781.4.95A2V201416.638+151151.081.2.21
    Aqillasig441249031.5.1747.8B3V+B3V19391.11.62+52352.281.3.33
    Aqillatau631254031.5.52gK02041.8.17+71640.51.2.86
    Aqillaups491250321.5.91A3IV194539.924+73647.641.3.85
    Aqillaphi611054381.5.28A1IV195614.24+112525.481.2.93
    Aqillachi471051681.5.270.4G0:III+A3V194233.966+114935.781.2.62
    Aqillapsi481051991.6.26B9III-IV194434.131+13181.10.421.2.91
    Aqillaome 1251046911.5.28F0IV191748.998+113543.611.2.64
    Aqillaome 2291047286.2.14A2V191953.037+11326.3.141.2.15
    Aqilla41238795.2.14B9V184449.931+2335.721.2.53
    Aqilla51426065.9.1412.8.14A2Vm184628.546-05741.91.2.02
    Aqilla81427066.1.14F2III185122.148-3191.4.791.2.99
    Aqilla10V1286512861043031.5.831.5.93A4p(Eu-Cr-Sr)185846.904+135423.711.3.62
    Aqilla111043081.5.2317.8.14F8V18591.5.24+133720.551.2.77
    Aqilla121429314.2.14K1III19140.837-54420.421.2.06
    Aqilla141429591.5.420.1A1V19254.531-34156.41.2.38
    Aqilla151429961.5.4238.5K1III19457.64-4153.311.2.54
    Aqilla18Y500081044885.2.14B8III-V19658.598+11416.641.2.41
    Aqilla191243181.5.22F0III-IV19859.903+6423.561.3.86
    Aqilla201431341.5.34B3V191240.718-75622.331.2.68
    Aqilla21V1288512881244085.6.141.5.1636.2B8II-IIIp(Hg:)191342.706+21737.631.2.49
    Aqilla221244551.5.59A3IV191631.02+4501.4.751.2.59
    Aqilla231244875.1.143.1.14K2II-III191832.467+151.6.581.2.39
    Aqilla241244921.6.41423.4K0-IIIa:Ba0.4CH1191850.905+02020.581.3.39
    Aqilla261432865.1.14115.9G8III-IV192032.904-52456.691.2.63
    Aqilla271432921.5.49B9III192035.677-05331.611.3.27
    Aqilla28V1208512081047221.5.511.5.5660.2F0III191939.345+122229.181.3.02
    Aqilla311048071.5.16105.6G8IVHdel 1192458.202+115639.741.2.35
    Aqilla351246755.8.14A0IVp19290.974+1571.1.461.2.66
    Aqilla361434825.3.14M1III193039.829-24719.751.3.32
    Aqilla371627925.12.14G9IIIa19351.7.69-103337.881.3.32
    Aqilla421436211.5.46F3IV193747.308-43851.33.5.14
    Aqilla451436781.5.6742A3IV194043.335-03716.511.2.25
    Aqilla461051561.6.34B9IIIpHgMn19421.12.89+121136.11.2.78
    Aqilla511630361.5.3921.1.14F0V195046.806-104548.591.2.52
    Aqilla561438941.5.7946.5gK519541.8.44-83427.321.2.32
    Aqilla571438981.5.7135.7B7Vn195437.647-81338.071.2.71
    Aqilla571438991.6.4935.7B8V195438.126-81413.511.2.47
    Aqilla581252191.5.61A0III195444.803+01625.431.2.21
    Aqilla621440451.5.68K4III20423.189-04233.511.3.47
    Aqilla641440951.5.99K1IV2081.1.12-04041.681.2.79
    Aqilla661441811.5.47K5III201313.865-1033.631.2.56
    Aqilla681444681.6.139.8.14B9V202824.858-32127.891.2.78
    Aqilla691444951.4.91K2III202939-2531.7.721.2.85
    Aqilla701446241.4.89K5II203643.61-23258.551.3.78
    Aqilla711446491.4.3232.2G7.5IIIa203820.258-1618.771.2.76
    Aquariusalp34SADALMELIK1458622411.2.96113G2Ib22547.033-0191.11.381.2.75
    Aquariusbet22SADALSUUD1454572371.2.9135.5G0Ib213133.545-53416.271.2.95
    Aquariusgam48SADACHBIA1460441.3.8437.4A0V222139.376-12314.371.2.44
    Aquariusdel76SKAT1653752461.3.27A3V225439.019-154914.951.2.55
    Aquariuseps2ALBALI1448101.3.77A1V204740.566-92944.661.2.82
    Aquariuszet 1551461071.4.591.8.14F6IV222849.705-0113.3.141.2.49
    Aquariuszet 2551461083471.4.42191.8.14F3V222850.053-011.12.181.2.37
    Aquariuseta621461814.2.14B9IV-Vn223521.384-071.2.951.2.31
    Aquariusthe43ANCHA1459911.4.16G8III-IV221650.034-74659.921.2.01
    Aquariusiot331648611.4.27B9IV-V22626.232-13521.10.791.2.86
    Aquariuskap63SITULA1462105.3.1498.3K2III223745.385-41340.881.2.91
    Aquariuslam731463621.3.74M2.5IIIaFe-1225236.856-73446.761.2.28
    Aquariusmu61448951.4.73A3m205239.238-85859.881.2.83
    Aquariusnu131641821.4.51G8III21935.652-112218.141.2.95
    Aquariusxi231455371.4.690.1A7V213745.112-75115.241.2.97
    Aquariusomi311458371.4.69B7IVe22318.805-2919.481.2.84
    Aquariuspi521275201.4.66B1Ve222516.629+12238.461.2.25
    Aquariusrho461460231.5.37B8IIIpMn:Hg:22201.11.21-74916.181.3.68
    Aquariussig571651341.4.82A0IV s223038.827-104040.711.3.12
    Aquariustau 1691652981.5.6623.7.14A0V224742.776-14323.2.141.2.63
    Aquariustau 2711653214.1.14132.5M0III224935.511-133533.321.3.22
    Aquariusups591912355.2.14F4IV223441.643-204229.591.2.63
    Aquariusphi901465851.4.22M1.5III231419.356-6256.423.3.14
    Aquariuschi921466125.6.14M3III231650.946-74335.561.3.77
    Aquariuspsi 1911465981.4.2149.2K0III231553.506-9515.771.2.88
    Aquariuspsi 2931466201.4.39B5V231754.225-91056.871.2.64
    Aquariuspsi 3951466351.4.981.4.14A0V231857.689-93638.421.2.78
    Aquariusome 11021658185F0IV233947.108-141318.321.2.63
    Aquariusome 21051658421.4.495B9.5V234243.337-143241.693.12.14
    Aquarius11260621.5.1659.7K1III203924.893+0291.11.131.2.52
    Aquarius3EN401571448141.4.411.4.45M3III204744.239-5139.741.2.56
    Aquarius41448771.5.991.1.14F5V+F7V205125.742-53735.381.2.14
    Aquarius51448891.5.55B9III20521.8.79-53024.821.2.48
    Aquarius71449681.5.51176.6gK5205654.036-94151.031.2.76
    Aquarius111450221.6.21G1V21033.828-44348.831.2.28
    Aquarius121450651.5.892.7.14G4III2141.4.45-549231.2.72
    Aquarius151452781.5.82B5V21181.11.86-4311.9.851.2.95
    Aquarius161453171.5.87gG721211.4.07-43336.341.2.01
    Aquarius171453511.5.99M0III212256.256-9191.9.671.2.28
    Aquarius181643641.5.4948.9F1V21241.11.99-125241.361.3.59
    Aquarius191453825.7.14F0IV212513.082-944551.2.16
    Aquarius201453761.6.36F0III212451.673-32354.391.3.16
    Aquarius211453841.5.49K4III212516.941-33324.861.2.11
    Aquarius251269655.1.14136.8K0III213933.293+21436.621.2.02
    Aquarius261269971.5.67K2III21421.10.33+1171.6.941.2.68
    Aquarius281272351.5.58gK42211.5.24+03617.751.2.02
    Aquarius29DX401461.6.371.6.783.6.14A2V22226.558-165751.41.2.76
    Aquarius301458361.5.54K0III22316.445-63120.921.2.09
    Aquarius321458535.3.14A5m22447.439-05423.571.2.23
    Aquarius351648881.5.81B2.5IV22859.01-18311.10.971.2.71
    Aquarius381649101.5.46B7III221037.489-113353.871.2.16
    Aquarius391649236.3.14F2V221225.754-141137.81.2.97
    Aquarius411909861.5.325.1.14K0III+F2V221417.956-21427.291.2.48
    Aquarius421649741.5.34gK0221648.119-124953.231.2.15
    Aquarius441459931.5.75G6III22171.6.58-52313.491.2.51
    Aquarius451649961.5.95gG722190.776-131818.371.2.01
    Aquarius471910831.5.13K2III222135.579-213553.781.3.98
    Aquarius491911051.5.53gG9222330.871-244545.391.2.89
    Aquarius501650441.5.76G6.5III222427.5.14-133146.171.3.24
    Aquarius511460671.5.780.3A0V22241.6.91-4501.12.711.2.39
    Aquarius531650771.6.573.3.14G2V222634.213-164429.6.141.2.05
    Aquarius531650781.6.353.3.14G1V222634.356-164432.521.2.71
    Aquarius561651271.6.37B8V s223017.384-14351.8.961.2.95
    Aquarius581651471.6.38A8III223141.328-105420.491.2.23
    Aquarius601461601.5.8998.1G6III22341.2.56-13427.481.2.68
    Aquarius661652521.4.69K4III224335.256-184949.363.5.14
    Aquarius671462731.6.41A0Vn224314.253-65747.141.2.36
    Aquarius681652931.5.26G7III224733.138-193647.921.2.81
    Aquarius70FM401761653081.6.161.6.19A9III-IV224830.224-103320.371.2.64
    Aquarius74HI402101653595.8.140.1B9III225328.713-113659.542.4.14
    Aquarius771653761.5.56K2.5IIIb225445.457-161619.251.2.46
    Aquarius781463821.6.19K3III225434.137-71216.991.2.34
    Aquarius811464471.6.21K5III23123.641-7340.41.3.98
    Aquarius821464651.6.15M2III23232.558-63426.681.2.21
    Aquarius831464981.5.430.2F2IV+F0V2351.9.03-74137.451.2.11
    Aquarius861916511.4.472.9.14G9III23640.881-234435.261.2.31
    Aquarius881916831.3.66K1III23926.793-211020.551.2.77
    Aquarius891916871.4.690.4G2IV+A2V23954.828-222727.171.2.62
    Aquarius941656255.8.140.2G5IV23191.6.92-132731.961.3.49
    Aquarius961466391.5.5510.6.14F3IV-V231923.965-5727.821.3.39
    Aquarius971656585.2.140.4A3Vp232239.211-15221.271.2.76
    Aquarius981918581.3.97K0III232258.22-2061.1.841.2.33
    Aquarius991919001.4.39K5III23261.2.67-203830.911.2.35
    Aquarius1001919701.6.29A9III233142.001-21229.9.141.2.36
    Aquarius1011919881.4.711A1n233316.613-205452.141.2.32
    Aquarius1031658341.5.34K5III234134.489-18137.611.2.96
    Aquarius1041658361.4.82120.1G0Ib-II234145.8-174859.221.2.51
    Aquarius1061658541.5.24B9Vn23441.12.84-181636.811.2.51
    Aquarius1071658671.5.296.6.14F2III+F2V23460.929-184040.631.2.95
    Aquarius108ET401631659181.5.161.5.21B9p(Si-Cr-Sr)235121.283-185432.51.2.41
    Araalp2280691981.2.9555.6B2Vne173150.558-495234.521.3.64
    Arabet2447251941.2.85K3Ib-IIa172518.024-553147.621.3.12
    Aragam2447261951.3.3417.9.14B1Ib172523.625-562239.411.3.21
    Aradel2539451.3.6247.4B8Vn17311.5.56-60411.6.141.3.89
    Araeps 12443314.6.14K4IIIab165935.06-53938.041.3.83
    Araeps 22443881.5.2925F6V1731.8.55-53141.12.911.3.96
    Arazet2443151861.3.13K3III165837.223-555924.481.3.31
    Araeta2441681.3.7623.6.14K5III164947.117-59229.331.3.11
    Arathe2452421.3.66B2Ib18637.836-50530.4.141.3.95
    Araiot2278861.5.2542.8B2IIIne172316.077-47281.5.183.2.14
    Arakap2447341.5.2330G8III172559.974-50380.971.3.94
    Aralam2282571.4.77F3IV174023.569-492455.891.3.93
    Aramu2449811.5.15G3IV-V17448.7.14-51502.8.141.3.75
    Aranu 1V0539605392450651.5.661.6.1812.3.14B2V+B3V175028.249-533644.061.3.74
    Aranu 22450726.9.14B9.5III-IV17511.10.55-53749.981.3.42
    Arapi2448961.5.25A5IV-V17381.5.48-54301.1.391.3.12
    Arasig12281621.4.59A0V173539.551-463020.251.3.02
    Ariesalp13HAMAL75151172K2-IIICa-1271.10.98+232744.611.2.04
    Ariesbet6SHERATAN75012141.2.64A5V15438.402+204828.731.2.92
    Ariesgam 15926801.4.837.8.14B9V15331.804+191745.061.3.45
    Ariesgam 25MESARTHIM926812621.4.757.8.14A1pSi15331.825+191737.211.2.52
    Ariesdel57BOTEIN933281.4.35K2III31137.753+194336.131.2.12
    Arieseps48756731.4.631.5.14A2V s2591.12.96+212025.1.141.2.96
    Arieszet58758101.4.89A1V31454.097+21240.051.2.11
    Arieseta17752041.5.27F5V21248.063+211239.352.12.14
    Ariesthe22928771.5.62A1Vn2181.7.42+19541.4.231.3.78
    Ariesiot8927215.1.141.2.1415721.039+17493.8.141.2.92
    Arieskap12751465.3.14A2m2633.898+223853.961.2.33
    Arieslam9750512641.4.7937.4F0V15755.729+233545.93.3.14
    Ariesmu34930621.5.690.1A0Vnp:24221.97+20041.531.2.87
    Ariesnu32754951.5.43A7V23848.978+215740.951.2.46
    Ariesxi24929321.5.47B7IV22449.055+103638.361.2.52
    Ariesomi37930821.5.77B9Vn24432.944+151842.321.2.45
    Ariespi42931271.5.22B6V24917.519+172751.41.2.29
    Ariesrho 245RZ70018931891.5.626.1.14M6III25548.493+181953.861.2.05
    Ariesrho 346931951.5.63F6V25626.138+18123.381.2.89
    Ariessig43931441.5.49B7V25129.6.14+15455.271.2.71
    Ariestau 161758861.5.280.2B5IV32113.629+21849.191.2.43
    Ariestau 263758995.9.14K3III32245.245+204430.891.2.63
    Aries1749661.5.862.8.14K1III+A6V1501.8.46+221631.291.2.99
    Aries4926371.5.84B9.5V1481.10.17+165720.2.141.3.38
    Aries7RR70010750301.6.421.6.84K0III15551.015+233438.561.2.28
    Aries10751141.5.630.8F8IV2339.345+25561.8.231.3.56
    Aries11751491.6.151.6.14B9IV-Vn2649.244+254216.891.2.43
    Aries14751711.4.98105.9F2III2925.344+255623.371.2.18
    Aries15928225.7.14M3IIIab21037.59+19301.1.211.2.06
    Aries16751886.2.14gK42111.12.44+255612.6.141.2.47
    Aries19928411.5.71M0III2131.3.95+151647.381.2.32
    Aries20752391.5.79F6IV-V21546.037+254658.891.2.94
    Aries21752381.5.580.2F6V21542.77+25235.111.2.55
    Aries26UU70034929796.1.141.6.15A9III23038.43+195118.9.141.2.92
    Aries27929831.6.23G5III-IV23054.384+174213.8.141.2.73
    Aries29929986.4.14F8V23254.168+1521.4.751.2.62
    Aries30754712706.5.1438.3F6III2370.514+2438511.2.92
    Aries31930221.5.68F7V23637.89+122651.621.2.18
    Aries33755105.3.1428.6.14A3V24041.094+273391.2.65
    Aries35755321.4.66B3V24327.113+274225.761.3.24
    Aries36930811.6.46K2III24419.126+174550.421.2.06
    Aries38UV70035930831.5.181.5.22A7IV24457.576+122644.81.2.08
    Aries39755781.4.51K1.5III24754.522+291449.81.2.58
    Aries40931181.5.820.2K1III24832.103+18171.1.391.2.69
    Aries41755961.3.63124.9B8Vn24959.024+271537.931.2.28
    Aries47756625.8.14F5IV2581.5.13+20401.7.491.2.63
    Aries49756935.9.14A3m3154.137+262744.441.2.64
    Aries51756966.7.14G03226.031+263633.691.2.57
    Aries52757236.8.140.2B7V3526.676+2515191.2.76
    Aries53UW70036932846.1.14B1.5V3725.656+175248.161.2.44
    Aries54932931.6.27M0III3821.166+184742.131.2.97
    Aries55757571.5.72B8III3936.737+29437.491.2.72
    Aries56SX70024757881.5.671.5.81B7p(Si-HeI)31214.241+271525.341.2.29
    Aries59758635.9.14G6IV31955.8+274161.3.21
    Aries60758756.12.14gK332025.578+253945.931.2.14
    Aries62758921.5.52G5III3221.11.14+273626.9.141.3.12
    Aries64759125.5.14gK432418.457+244326.811.2.88
    Aries65759156.8.14A1V32426.098+20481.12.732.8.14
    Aries66759456.3.14K0IV32826.566+224815.3.141.2.23
    Aurigaalp13CAPELLA40186420.08G5IIIe+G0III51641.358+455952.981.3.54
    Aurigabet34MENKALINAN40750571.9.14184.6A2IV55931.733+445650.721.3.36
    Aurigadel33255021.3.72115.4K0-III55931.63+54171.4.881.3.08
    Aurigaeps7ALMAAZ39955361.2.99207.6F0Iae+B5158.14+434923.7.143.8.14
    Aurigazet8HOEDUS I399661.3.75K4II+B8V5228.682+41432.91.3.18
    Aurigaeta10HOEDUS II40026381.3.17B3V5630.88+41141.4.161.3.71
    Aurigathe37BOGARDUS58636581.2.623.5.14A0pSi55943.3+371244.661.3.34
    Aurigaiot3HASSALEH57522351.2.69K3II45659.613+33957.91.3.59
    Aurigakap44781431.4.35G8.5IIIb61522.687+292952.791.2.74
    Aurigalam15402331.4.71146.6G1.5IV-VFe-15191.8.66+40556.611.3.56
    Aurigamu11577551.4.86A4Vm51325.701+38294.1.141.3.88
    Auriganu32585021.3.9754.6G9.5III*55129.386+39854.621.3.68
    Aurigaxi30254501.4.99A2V55450.768+554225.321.3.56
    Aurigaomi27405831.5.47A2VpCr54554.033+494934.631.3.55
    Aurigapi35407561.4.26M3II55956.121+45561.12.611.3.38
    Aurigarho20402691.5.23B3V52148.427+414816.951.3.61
    Aurigasig21579811.4.998.7.14K4III52439.15+37231.7.531.3.51
    Aurigatau29584651.4.5249.6G8IIIFe-15491.10.69+391052.261.3.21
    Aurigaups31584961.4.74M0+III-IIIbFe-0.55511.2.76+371820.391.3.59
    Aurigaphi24580515.7.14206.8K3IIICN+252738.899+342832.641.2.79
    Aurigachi25581641.4.76B5Iab53243.68+321131.421.2.67
    Aurigapsi 146410761.4.91K5-M0Iab-Ib62453.894+491716.611.3.85
    Aurigapsi 250412391.4.7952.1K3III63919.892+422919.8.141.3.87
    Aurigapsi 352593195.2.14B8III63849.178+39541.8.961.3.98
    Aurigapsi 455412885.2.14K5III6431.4.78+443128.271.3.79
    Aurigapsi 556413301.5.2536.2G0V64644.343+433438.771.3.06
    Aurigapsi 657413461.5.22K0III64739.563+484722.431.3.09
    Aurigapsi 758413805.2.1440.9K3III65045.947+414653.141.3.89
    Aurigapsi 861595891.6.48B9.5pSi65357.006+383018.141.3.66
    Aurigapsi 9414461.5.87B8IIIe65632.259+461627.8.141.3.98
    Aurigaome4575481.4.945.1.14A1V45915.365+375324.6.141.4.92
    Auriga2574751.4.78K2.5IIIbBa0.445237.975+36421.11.191.3.69
    Auriga5575591.5.953.7.14F5V5018.279+392341.331.3.36
    Auriga6575601.6.58K4I5023.224+393917.791.4.21
    Auriga925019590.1F0V5640.619+513551.831.3.71
    Auriga12401836.9.14B551627.119+462458.381.3.03
    Auriga14KW C80256577991.4.955.8.1414.3.14A9IV51524.393+324115.691.2.48
    Auriga16578531.4.544.2.14K2.5IIIbFe-15181.10.85+332217.9.141.2.97
    Auriga17AR80071578581.6.151.6.82Ap(Hg-Mn)+B9V51818.867+33461.1.961.2.06
    Auriga18578931.6.493.8.14A7V51923.562+33591.8.171.3.06
    Auriga19579065.3.14A5II5200.89+335728.451.2.67
    Auriga22771391.6.46B9V s52322.908+28561.12.481.2.83
    Auriga26582805.4.140.2F9III+B9.5V53838.082+302932.661.2.79
    Auriga36407781.5.73B9.5pSiFe6058.602+47547.1.141.3.52
    Auriga38408186.1.14K0II6317.991+425441.451.3.11
    Auriga39408401.5.87F3V651.3.26+425854.151.3.58
    Auriga40587491.5.36A4m6635.1+382857.621.3.75
    Auriga41409241.6.827.7.14A8V61136.466+484246.521.3.25
    Auriga41409256.9.147.7.14A3V61136.626+484239.991.3.74
    Auriga42409991.6.52F0V61734.652+462527.2.141.3.91
    Auriga43410101.6.38K2III61816.854+462137.941.3.34
    Auriga45256811.5.36F5III62146.2+53271.7.551.3.52
    Auriga47411305.9.14gK46301.3.07+46411.8.171.3.54
    Auriga48RT800125912851.5.82F4Ib-G1Ib62834.094+302934.891.2.58
    Auriga49785241.5.27A0Vnn6351.12.79+28119.941.2.47
    Auriga51593161.5.69K5III63839.536+392326.971.3.91
    Auriga53785711.5.790.1B9npEu63822.981+28591.3.291.2.46
    Auriga54785936.3.140.8B7III63933.129+281547.021.2.92
    Auriga59OX80311595711.5.941.6.1422.3.14A7n-F3IV6531.1.75+38521.8.991.3.72
    Auriga60595766.3.14dF565313.392+382616.551.3.59
    Auriga62596586K2III6591.2.84+3831.8.381.3.13
    Auriga63598664.9.14K4III-IIIa71139.318+391913.9.141.3.37
    Auriga64416791.5.78A5Vn7181.2.04+40530.391.3.51
    Auriga65600101.5.1311.4.14K0III7221.2.75+364538.061.3.87
    Auriga66417381.5.19K1+IIIaCN17241.8.61+404020.321.3.34
    Bootesalp16ARCTURUS100944147-0.04K1.5IIIFe-0.5141539.687+191056.771.2.22
    Bootesbet42NEKKAR453373.5.14G8IIIaBa0.3Fe-0.515156.75+4023261.2.23
    Bootesgam27SEGINUS642031483.3.1433.4A7III14321.4.79+381829.7.141.2.25
    Bootesdel49645891.3.47104.9G8IIIFe-1151530.171+331853.281.2.45
    Booteseps 136IZAR835001542.7.142.8.14K0-II-III144459.229+27427.141.2.43
    Booteseps 2363115.12.142.8.14A2V144459.2+274301.1.68
    Booteszet301011453101.4.43101.2.14A2III14411.8.92+134341.881.2.25
    Booteseta8MUPHRID1007661421.2.68112.6G0IV135441.076+182351.721.2.73
    Bootesthe23ASELLUS PRIMUS291374.5.1469.5F7V142511.8.14+51511.2.831.2.95
    Bootesiot21ASELLUS SECUNDUS290711.4.7538.7A9V14161.9.25+51221.2.141.2.82
    Booteskap 117290451.6.6913.4.14F1V141327.744+514715.571.2.47
    Booteskap 217ASELLUS TERTIUS290461.4.5413.4.14A8IV141329.026+514724.551.2.93
    Booteslam19449651.4.18A0p141623.025+46517.981.2.72
    Bootesmu 151ALKALUROPS646861.4.31108.9F2IVa152429.445+372237.761.2.39
    Bootesmu 251646873166.5.14108.9G1V152430.891+372051.591.2.26
    Bootesnu 152455805.2.14K4.5IIIbBa0.4153055.763+404959.071.2.41
    Bootesnu 253455905.2.140.1A5V153146.993+405357.961.2.48
    Bootesxi371012503121.4.557.2.14G8Ve+K4Ve145123.298+1961.3.961.2.25
    Bootesomi351011844.6.14G8.5III144514.473+165751.71.2.22
    Bootespi 1291011381.4.945.7.14B9pMnHgSi144043.595+16256.9.141.2.01
    Bootespi 2291011391.5.885.7.14A6V144043.932+16251.3.911.2.84
    Bootesrho25642021.3.5842.2K3-III143149.789+302217.211.2.64
    Bootessig28834161.4.46237.1F2V143440.826+294442.531.2.26
    Bootestau41007064.5.145F6IV134715.736+172724.151.2.61
    Bootesups51007254.7.14K5.5III134928.632+154752.41.2.62
    Bootesphi54456431.5.24G7III-IVFe-2153749.609+40211.12.491.2.11
    Booteschi48837291.5.26A2V151429.167+29951.491.2.96
    Bootespsi43836451.4.54K2III15426.743+265651.361.2.69
    Bootesome41836241.4.81K4-IIIabCa0.51521.6.13+25029.391.2.74
    Bootes1829421.5.754.8.14A1V134040.454+195720.451.2.41
    Bootes2829461.5.62G9III13411.2.17+222944.681.2.92
    Bootes3829931.5.95G5III+A7V:134643.313+25421.7.781.2.31
    Bootes6830151.4.91K4III134942.788+211550.791.2.01
    Bootes71007515.7.14G5III13531.12.99+175558.071.2.25
    Bootes9830845.1.14K3III135634.179+272931.421.2.89
    Bootes10831031.5.76A0V s135838.907+214146.211.2.36
    Bootes11831301.6.23A7III1411.10.77+27231.11.581.2.26
    Bootes12832031.4.83F9IV w141023.939+25529.921.3.26
    Bootes13CF90107449055.2.145.3.1479.7M2IIIab14817.267+492729.641.2.69
    Bootes141009251.5.54F6IV14141.5.63+125734.231.2.31
    Bootes151009341.5.291.1.14K1III141450.876+1061.2.881.2.19
    Bootes181009751.5.41156.4F5IV141916.289+13015.381.2.88
    Bootes201009801.4.86K3III141945.216+161824.7.141.2.34
    Bootes221010251.5.39F0m142627.354+191336.61.2.65
    Bootes24291651.5.59G3IV142837.806+495041.291.2.71
    Bootes26833951.5.92F2IV143232.545+221535.881.2.74
    Bootes311206011.4.86G7+IIIHdel -0.5144138.79+8942.341.2.14
    Bootes321011521.5.56G8III144143.539+113938.221.2.07
    Bootes33451531.5.39A1V143850.235+442416.261.2.73
    Bootes34W90006834881.4.735.4.14M2-M4III144325.368+263140.111.2.65
    Bootes38MERGA452261.5.74F7IV w144918.688+46658.431.2.72
    Bootes39452311.5.692.9.14F6V+F5V144941.295+484314.221.2.36
    Bootes40644491.5.64F0-2IV-III145936.972+391554.861.2.45
    Bootes44I99109453571.4.760.7F9-G1Vn15347.358+473915.8.141.2.52
    Bootes45836711.4.93244.1F5V15718.074+24521.8.741.2.23
    Bootes46836821.5.67gK215823.781+26181.4.151.2.46
    Bootes47453701.5.576.2.14A1V15525.834+4891.3.621.1.46
    Bootes50646561.5.37B9Vn152148.556+32561.1.591.2.39
    Caelumalp2169261.4.456.6.14F2V44033.681-415149.921.1.39
    Caelumbet1952395.5.14F1V4421.3.66-37839.751.3.63
    Caelumgam 11955321.4.553K3III5424.396-352859.521.2.28
    Caelumgam 2X1000071955341.6.281.6.39F1III-F2IV5426.111-354218.671.2.62
    Caelumdel2168505.7.14B2IV-V43050.145-445713.3.141.1.22
    Caelumzet1953001.6.37K1IV44749.624-30113.9.141.2.53
    Camelopardalisalp9132981.4.29O9.5Ia4543.3.14+662033.611.3.99
    Camelopardalisbet10133514.3.1480.8G1Ib-IIa5325.096+602632.061.3.17
    Camelopardalisgam50061.4.63106.3A2IVn35021.513+711956.21.4.77
    Camelopardalis1246721.5.7710.3.14B0III4321.1.21+535439.061.3.16
    Camelopardalis2247441.5.350.3A8V43958.095+532823.261.3.87
    Camelopardalis3247435.5.143.8.14K0III43954.709+53446.581.3.58
    Camelopardalis4248295.3.1499A3m4480.284+564526.1.141.3.89
    Camelopardalis5249041.5.5212.9.14B9.5V4553.12.14+551532.931.3.82
    Camelopardalis7249291.4.470.4A1V45717.18+53451.7.641.3.83
    Camelopardalis8249436.8.14K4III45946.314+53919.821.3.18
    Camelopardalis11BV110099250015.8.14180.5B2.5Ve561.8.67+585820.531.3.93
    Camelopardalis12BM110090250031.6.18180.5K0III561.12.69+59116.171.3.97
    Camelopardalis14134136.5.14A7Vn51331.283+624128.781.4.97
    Camelopardalis15251251.6.13B5V51927.838+5871.2.191.4.93
    Camelopardalis16251611.5.28106.2A0Vn52327.614+573239.61.3.59
    Camelopardalis17135181.5.42M1IIIa5301.10.07+6341.2.173.7.14
    Camelopardalis18252411.6.48F8V53233.824+571316.221.3.82
    Camelopardalis19135501.6.151.6.14A0V53715.123+64916.641.3.91
    Camelopardalis22252986.9.14F55391.5.45+562136.331.3.15
    Camelopardalis23135901.6.15gG55441.8.78+612835.513.2.14
    Camelopardalis24253336.5.14K0III5431.1.47+563453.681.3.27
    Camelopardalis26253621.5.94A4Vn54630.399+56656.411.3.72
    Camelopardalis29254031.6.5425.1.14A4IV-V55034.023+56551.7.831.3.84
    Camelopardalis30254191.6.14A0V s55217.361+585750.571.3.45
    Camelopardalis31TU110028254475.12.141.5.29A0IV-V55457.79+595317.961.3.84
    Camelopardalis36137561.5.32K1.5IIIbCN-0.561251.073+65436.3.141.4.69
    Camelopardalis37255971.5.36G8III6959.095+58561.8.941.3.77
    Camelopardalis40137721.5.35102.7K3III61540.638+595956.821.3.16
    Camelopardalis42139731.5.14B4IV65057.146+673418.881.4.98
    Camelopardalis43139865.12.14B7III65342.246+685317.741.4.71
    Camelopardalis47262981.6.352.2.14A8m72217.225+59541.7.281.3.08
    Camelopardalis49BC110081143221.6.431.6.48F0p(Sr-Cr-Eu)74627.433+624950.151.3.62
    Camelopardalis51143211.5.92gK274640.182+652720.841.3.65
    Camelopardalis53AX110077144021.5.956.8.14A2p(Sr-Cr-Eu)8142.343+601927.671.3.15
    Canceralp65ACUBENS982671.4.250.1A5m85829.238+115127.851.2.56
    Cancerbet17ALTARF1165691.3.5229.2K4IIIBa0.581630.933+9111.7.891.2.36
    Cancergam43ASELLUS BOREALIS803781.4.66106.3A1IV84317.152+21281.6.571.2.91
    Cancerdel47ASELLUS AUSTRALIS980871.3.9438.4K0III-IIIb84441.093+18915.391.2.88
    Cancereps41980246.3.14134.9A8Vn84026.994+193241.941.2.65
    Cancerzet 116TEGMEN976452931.5.6360.9F8V8121.12.93+173851.871.2.77
    Cancerzet 216976466.2.145.9.14G5V81213.263+173851.631.2.32
    Cancereta33802431.5.33K3III83242.495+202628.1.141.2.65
    Cancerthe31978811.5.350.3K5III83135.736+18539.871.2.53
    Canceriot 148804164.2.1430.4.14G7.5IIIaBa0.184641.817+284535.761.2.87
    Canceriot 248804151.6.5730.4.14A3V84640.022+284554.671.2.07
    Cancerkap76983781.5.240.3B8IIIpMn9744.821+10401.5.561.2.07
    Cancerlam19801131.5.98B9.5V82032.111+24119.941.2.55
    Cancermu 19BL120089799401.5.976.4.14M3III8618.366+22381.8.281.2.95
    Cancermu 210799595.3.14G1IVb8745.826+213454.111.2.58
    Cancernu69805951.5.45A0pSi9244.26+24271.10.721.2.73
    Cancerxi77806661.5.140.1G9IIIFe-1CH-0.59921.535+22243.472.4.14
    Canceromi 162982475.2.14A5III85714.93+151921.5.141.2.56
    Canceromi 263982501.5.67F0IV85735.186+153453.281.2.99
    Cancerpi 181984271.6.510.1G9V91217.571+145945.911.2.04
    Cancerpi 282984561.5.34K1III91513.857+145629.591.2.13
    Cancerrho 153BO120092804765.9.141.6.3743.1M3III85228.587+281533.251.2.93
    Cancerrho 255804781.5.9585G8V85235.822+281950.841.2.59
    Cancerrho 358805111.5.22G8II-III85539.671+275538.711.2.39
    Cancersig 146610291.6.13G5III84521.421+304152.051.2.59
    Cancersig 151611021.5.6679A8Vma s85234.63+322827.2.141.2.95
    Cancersig 257611251.5.391.5.14G7III85414.682+303445.721.2.81
    Cancersig 259611461.5.45A7IV85656.632+325437.31.2.91
    Cancersig 361611571.6.290.1F6V85758.725+30141.1.341.2.81
    Cancersig 364611775.2.1489.3G8III85932.643+32251.6.761.2.64
    Cancertau72806501.5.43G8III980.056+293914.931.2.29
    Cancerups 130802291.5.75F0IIIn83130.483+24451.781.2.24
    Cancerups 232802451.6.36G9III8330.073+2451.4.952.2.14
    Cancerphi 122801811.5.57130.6K5III82627.697+275336.251.2.51
    Cancerphi 223801871.6.325.2.14A6V82646.783+26561.3.671.2.96
    Cancerphi 223801886.3.145.2.14A3V82647.005+26567.3.141.2.54
    Cancerchi18801041.5.14F6V8201.3.85+27131.3.531.2.63
    Cancerpsi14799951.5.73112.1G7V81027.196+253026.331.2.33
    Cancerome 12798611.5.83gG88055.855+252333.861.2.96
    Cancerome 24798691.6.31109.3A1V8143.779+25522.771.2.69
    Cancer1973991.5.78K3+III75659.444+154724.971.2.91
    Cancer3974721.5.55gK38047.308+171831.111.2.68
    Cancer5974851.5.99B9.5Vn8130.289+162719.1.141.2.92
    Cancer8975425.12.14A1V851.4.94+1375.3.141.2.25
    Cancer12975941.6.27F3V8842.432+133826.751.2.46
    Cancer15BM120090800161.5.531.5.65B9p(Si-Cr)8131.8.92+293923.441.2.57
    Cancer20977811.5.95A9V82321.826+181956.071.2.57
    Cancer21977886.8.141M2III82355.236+103755.221.2.81
    Cancer25978061.6.14F6V82549.876+17246.451.2.79
    Cancer27BP120093978191.5.411.5.75M3III82643.893+123916.911.2.87
    Cancer28CX120124802046.1.14A582836.767+24840.981.2.15
    Cancer29978431.5.950.2A5V82837.333+141238.871.2.36
    Cancer34979021.6.46A1V83239.855+10357.561.2.64
    Cancer35979281.6.58G0III83519.42+193524.391.2.84
    Cancer361169531.5.88A3V8371.5.75+93919.651.2.59
    Cancer371169751.6.53A1V8381.5.64+93428.871.2.41
    Cancer39803331.6.39149.8G8III8401.6.23+20027.6.141.2.46
    Cancer45980691.5.640.1A3V+G0III8431.12.89+124051.181.2.02
    Cancer49BI120087980891.5.581.5.71A0p(Si-Cr)84445.046+10454.031.2.64
    Cancer50981171.5.87A1V84655.987+12635.641.3.24
    Cancer54981681.6.380.1G1V8511.1.48+15211.2.591.2.62
    Cancer60982351.5.41gK585555.58+113733.851.2.28
    Cancer66612021.5.824.6.14A2V9124.074+32151.8.521.2.23
    Cancer67805856.7.14103.5A8Vn9148.88+27549.8.141.2.26
    Cancer70806091.6.38A1V941.9.68+275353.781.2.69
    Cancer75806591.5.98112G5IV-V9847.391+263744.781.2.59
    Cancer79806746.1.140.1G5III91020.871+215947.091.2.28
    Canes Venaticialp 112632565.6.1419.4.14F0V12560.391+381853.451.2.01
    Canes Venaticialp 212COR CAROLI632571332.9.1419.4.14A0pSiEuHg12561.1.67+38191.6.221.2.42
    Canes Venaticibet8CHARA442301.4.26G0V123344.543+412126.811.2.82
    Canes Venatici2440972991.5.6611.4.14M1III+F7V12161.7.57+403936.571.2.16
    Canes Venatici3441271.5.29M0III121948.74+48591.2.941.2.86
    Canes Venatici4AI130063441551.5.891.6.15F3IV122347.046+423233.581.2.96
    Canes Venatici5283664.8.14G6IIIBa0.212241.1.68+513344.31.2.81
    Canes Venatici6630005.2.14G9III122550.932+3911.6.971.2.35
    Canes Venatici7284071.6.21229F6-8V12301.2.85+51321.7.831.2.24
    Canes Venatici9442651.6.37A7Vn123846.27+405228.361.2.11
    Canes Venatici10631771.5.95G0V124459.452+391643.961.2.75
    Canes Venatici11443321.6.27A6m124841.797+48280.921.2.49
    Canes Venatici14633381.5.25B9V13544.45+354756.151.2.13
    Canes Venatici15633741.6.28284.4B7III13941.999+38321.6.142.5.14
    Canes Venatici17633801.5.91284.4A9III-IV13101.3.08+382956.111.2.03
    Canes Venatici19445311.5.79A7V131531.951+405118.521.3.04
    Canes Venatici20AO130068445494.7.141.4.75F3IIIp131732.554+403421.511.2.68
    Canes Venatici21BK130088445561.5.15A0V131814.57+494055.691.2.43
    Canes Venatici23445705.6.14K1III132018.95+4091.1.881.2.38
    Canes Venatici24446684.7.14A5V133427.285+49057.381.2.22
    Canes Venatici25636481.4.821.7.14A7III133727.64+361741.551.2.26
    Canis Majoralp 19SIRIUSG15188167-1.4611.2.14A1Vm6451.8.17-164258.111.2.29
    Canis Majoralp 22898.5.144.5.146451.8.17-164258.110.995
    Canis Majorbet2MIRZAM151428621.1.98185.9B1II-III62241.966-175721.591.2.17
    Canis Majorgam23MULIPHEIN1523034.12.14B8II7345.5-153759.521.2.75
    Canis Majordel25WEZEN173047721.1.84F8Ia7823.476-262335.481.2.98
    Canis Majoreps21ADHARA172676701.5.147.5.14B2II65837.561-285819.411.2.12
    Canis Majorzet1FURUD196698603.2.14175.5B2.5V62018.797-30348.11.2.07
    Canis Majoreta31ALUDRA173651751.2.45178.7B5Ia7245.7.14-291811.3.141.2.32
    Canis Majorthe141520714.7.14K4III6541.11.95-12219.1.141.2.66
    Canis Majoriot201521261.4.37B3II6561.8.14-17314.561.2.68
    Canis Majorkap131972581.3.96B1.5IVne64950.463-323030.661.2.65
    Canis Majorlam1968571.4.48B4V6281.10.48-323448.361.2.44
    Canis Majormu1815212352.8.14G5III+A26561.6.48-14236.511.2.91
    Canis Majornu 161516945.7.1417.4.14G8III+F3IV-V63622.837-183935.781.2.39
    Canis Majornu 271517021.3.95K1III63641.032-191522.6.141.2.88
    Canis Majornu 381517301.4.43K1-II-III63753.391-181414.581.2.36
    Canis Majorxi 141718951.4.3324.6.14B0.5IV63151.343-23251.5.981.2.38
    Canis Majorxi 251719821.4.54A0V6351.3.56-225753.471.2.41
    Canis Majoromi 224172839713.2.14B3Iab731.1.75-23500.131.2.69
    Canis Majoromi 1161725421.3.87K2+Iab6541.7.08-24111.2.311.2.77
    Canis Majorpi191725791.4.6811.6.14gF265537.398-2081.11.191.2.57
    Canis Majorsig221727971.3.4710K7Ib7143.159-27561.5.521.2.91
    Canis Majortau301734464.4.140.2O9Ib71842.444-245715.191.2.23
    Canis Majorome281732821.3.85B2IV-Ve71448.677-264621.842.2.14
    Canis Major10FT1401831971491.5.131.5.4436.3B2Ve64428.36-31413.531.2.02
    Canis Major111519191.5.29B9III64651.096-142533.341.2.09
    Canis Major12HK1402111723186.6.146.9.14B9p6471.1.94-21055.511.2.75
    Canis Major15EY1401681725201.4.791.4.84B1III-IV65332.899-201327.181.2.27
    Canis Major171725691.5.7450.5A3IV6551.2.07-202416.911.2.92
    Canis Major261731931.5.92B2V7121.12.18-255633.071.2.94
    Canis Major27EW1401661732641.4.421.4.820.1B3IVe71415.171-26211.8.551.2.96
    Canis Major29UW1400361734441.4.841.5.33O7Ia:fp+OB71840.349-243331.771.2.14
    Canis Minoralp10PROCYON115756800.384.6.14F5IV-V73918.123+51329.951.2.58
    Canis Minorbet3GOMEISA115456762.9.14138.7B8Ve7271.9.38+81721.5.141.2.88
    Canis Minorgam41154781.4.32130K3-IIIFe-0.57281.9.83+85532.471.2.88
    Canis Minordel 171155811.5.25F0III7321.5.71+15452.091.2.71
    Canis Minordel 281156101.5.59F2V7331.11.44+31724.791.2.94
    Canis Minordel 391156441.5.8190A0Vnn73415.821+32217.381.2.69
    Canis Minoreps21154251.4.99G6.5IIb72538.871+91633.821.2.53
    Canis Minorzet131160431.5.14B8II75141.975+1460.721.2.94
    Canis Minoreta51154771.5.254F0III7281.2.78+656311.2.65
    Canis Minor1968715.3.14A5IV72458.174+11401.10.511.2.55
    Canis Minor6969521.4.54K1+IIIBa0.472947.786+12023.671.2.73
    Canis Minor11972245.3.14A1Vnn74616.217+10461.5.951.2.57
    Canis Minor141161821.5.2988.6K0III75820.636+21329.191.2.13
    Capricornusalp 15ALGIEDI PRIMA1634221.4.24377.7G3Ib201738.868-123029.5.141.2.64
    Capricornusalp 26ALGEDI SECUNDA1634271.3.57377.7G8IIIb20181.3.66-123241.331.3.07
    Capricornusbet 19DABIHG1634812283.8.14F8V+A020210.672-144652.931.2.39
    Capricornusbet 2DABIH MINOR1634713416.1.14204.6A0III202046.562-14471.5.611.2.92
    Capricornusgam40NASHIRA1645602501.3.68F0p21401.5.46-163944.441.2.79
    Capricornusdel49DENEB ALGEDI1646442391.2.87Am21471.2.58-16738.191.2.49
    Capricornuseps391645201.4.68B2.5Vpe21371.4.15-192757.421.2.38
    Capricornuszet341903411.3.7421.3.14G4Ib212640.039-222440.741.2.05
    Capricornuseta221899861.4.840.3A5V21424.293-195118.3.141.2.88
    Capricornusthe231641324.7.14A1V21556.849-171357.991.2.42
    Capricornusiot321643461.4.28G7IIIFe-1.5212214.812-16501.4.561.2.57
    Capricornuskap431645931.4.73G8III214239.497-185158.733.5.14
    Capricornuslam481646391.5.58A1V214632.105-112157.471.2.79
    Capricornusmu511647135.8.14F1III215317.77-13336.5.142.6.14
    Capricornusnu8ALSHAT1634681.4.7654.1B9.5V202039.838-124533.081.3.95
    Capricornusxi 111633281.6.34K0III201157.923-122332.561.2.77
    Capricornusxi 221633371.5.8571.6F7V201225.887-12371.2.731.2.65
    Capricornusomi 1121636261.5.9421.9.14A3Vn202953.874-183459.561.2.66
    Capricornusomi 2121636251.6.7421.9.14A7V202952.494-18351.11.871.2.27
    Capricornuspi101635921.5.253.3.14B8II-III202719.226-181242.181.3.92
    Capricornusrho111636141.4.78249.5F2IV202851.602-174849.041.3.32
    Capricornussig71634451.5.2856.5K3II201923.603-1971.6.491.3.35
    Capricornustau 2141637711.5.220.3B6III203916.374-145717.391.2.11
    Capricornusups151637795.1.14M2III20401.2.64-18819.8.141.2.25
    Capricornusphi281901731.5.24gG9211537.882-20391.5.951.2.63
    Capricornuschi251900505.3.1467A0V21833.618-211137.141.2.73
    Capricornuspsi161896641.4.14F4V20461.5.46-251615.4.141.2.47
    Capricornusome181897814.11.14M0-III-IIIbBa0.2205149.297-26559.4.141.2.75
    Capricornus31634021.6.3226.9.14B9pHg201622.828-122013.421.2.16
    Capricornus41891141.5.87K0III20181.1.91-214836.171.2.32
    Capricornus171896671.5.93A020461.9.87-213049.871.2.57
    Capricornus191639751.5.78K0III205447.854-175522.731.3.28
    Capricornus20AO1600681640436.2.14B9p(Si)205936.149-1921.6.511.2.24
    Capricornus241900254.5.1426.2.14M0.5III2171.7.78-25021.5.141.2.91
    Capricornus271900691.6.25F1IV21933.003-203322.891.2.34
    Capricornus291642631.5.28M3III211544.858-151017.461.2.25
    Capricornus301642861.5.430.1B8III211757.288-17591.6.681.2.86
    Capricornus311642897.5.14F2V211815.67-172743.771.3.82
    Capricornus331902951.5.41K0III21241.9.66-20511.7.341.2.57
    Capricornus351903491.5.78K5III212714.811-211146.231.2.69
    Capricornus361903741.4.51G5III212843.42-214825.991.2.11
    Capricornus371904611.5.69F1V213451.018-2051.3.911.2.09
    Capricornus411905591.5.245.1.14G9III21420.756-231545.691.2.15
    Capricornus421645801.5.18G1V+G0V214132.879-14251.191.2.99
    Capricornus441646001.5.88F0IV21431.4.21-142358.521.2.41
    Capricornus451646121.5.99F0V21440.954-144458.081.2.65
    Capricornus461456375.9.14G8II-III21450.289-9457.081.2.22
    Capricornus47AG1600611456485.9.141.6.14M3III214616.284-91633.241.2.26
    CarinaalpCANOPUS23448063-0.72F0II62357.183-524144.441.1.21
    CarinabetMIAPLACIDUS250495911.1.68A2IV91312.8.14-69431.1.961.1.21
    CarinaepsAVIOR235932861.1.86K3III+B2:V82230.838-593034.271.1.62
    Carinathe2510831051.2.76B0Vp104257.334-642339.861.2.58
    CarinaiotTURAIS236808921.2.25A8Ib9171.5.03-591631.141.1.34
    Carinanu9935A5Ib-B7III9470-65400
    CarinarhoHR41401043.3.14103152-614100
    Carinaups 12506953.1.145A6Ib9471.6.83-65418.791.1.53
    Carinaups 22506961.6.265B7III9471.6.02-65420.8.141.1.11
    Carinachi2356351.3.47B3IVp75646.69-525855.951.1.74
    Carinaome2508851011.3.32B8III101344.223-70216.441.1.91
    Cassiopeiaalp18SHEDIR2160971.2.2364.4K0IIIa04030.465+563214.431.2.95
    Cassiopeiabet11CAPH2113321.2.2731.3.14F2III-IV091.10.19+59858.991.2.54
    Cassiopeiagam27MARJ1148291.2.472.3.14B0IVe05642.514+60430.11.2.13
    Cassiopeiadel37RUCHBAH22268121.2.68131.7A5III-IV12548.986+60141.6.911.2.08
    Cassiopeiaeps45SEGIN120311.3.38B3III15423.71+63401.12.271.4.08
    Cassiopeiazet17215661.3.66B2IV03658.297+535348.862.7.14
    Cassiopeiaeta24ACHIRD217321.3.4411.6.14F9V+dM00496.4.14+574857.211.2.85
    Cassiopeiathe33MARFAK220701.4.33145.6A7V1111.6.83+55859.361.2.31
    Cassiopeiaiot122982691.4.522.3.14A5pSr2291.3.97+67241.8.561.4.53
    Cassiopeiakap15112561.4.16B1Ia03259.965+625554.41.3.26
    Cassiopeialam14214891.4.730.5B8Vn03146.411+543120.2.141.2.26
    Cassiopeiamu30MARFAK220241.5.17190.5G5Vb1816.36+545513.621.2.24
    Cassiopeianu25217291.4.89B9III04850.06+50585.8.141.2.44
    Cassiopeiaxi19216374.8.14B2V0421.3.99+503045.081.3.68
    Cassiopeiaomi22366201.4.5433.6B5IIIe04443.532+48171.3.741.3.72
    Cassiopeiapi20366021.4.94A5V04328.113+47128.751.2.51
    Cassiopeiarho7358791.4.54G20e235423.5.14+572958.031.2.27
    Cassiopeiasig8359471.4.882.8.14B1V23590.532+554517.721.2.96
    Cassiopeiatau5357631.4.87K1IIIa23471.3.28+58391.6.913.9.14
    Cassiopeiaups 126218321.4.8394.1K2III0550.125+585821.621.2.45
    Cassiopeiaups 228218551.4.63G8IIIbFe-0.505639.82+591051.741.3.78
    Cassiopeiaphi34221911.4.98133.8F0Ia1201.4.08+581353.712.4.14
    Cassiopeiachi39223971.4.71G9IIIb13355.928+591355.41.3.22
    Cassiopeiapsi36117511.4.7423.2.14K0III12556.034+68747.981.3.13
    Cassiopeiaome46120381.4.99B8III15559.947+68411.6.551.4.38
    Cassiopeia1351471.4.85B0.5IV23636.861+59251.11.461.2.15
    Cassiopeia2351865.7.14167.2A5III23944.096+591958.531.2.47
    Cassiopeia4206141.4.9898.6M1III232450.251+621658.161.2.74
    Cassiopeia6V0566180566208691.5.341.5.451.5.14A3eqIa-0234850.168+621252.231.2.87
    Cassiopeia9109541.5.88246A1III0413.631+621716.271.2.23
    Cassiopeia10109781.5.59B9III0626.579+641146.271.2.55
    Cassiopeia12111725.4.14B9III02447.487+614951.961.2.99
    Cassiopeia13112431.6.18B6V03125.334+66311.10.451.2.12
    Cassiopeia16112651.6.48B9III03424.889+66451.1.331.2.46
    Cassiopeia21YZ18005342161.5.716.12.1436A2V+F2V04539.035+745916.841.3.71
    Cassiopeia2342261.5.41B8III04746.098+745051.091.3.26
    Cassiopeia31116121.5.29A0Vnn11039.356+684643.581.3.07
    Cassiopeia32RU180013116175.5.145.6.14B9IV11141.425+6511.7.641.2.12
    Cassiopeia35117121.6.3455.5A2Vnn1211.5.22+643930.8.141.3.63
    Cassiopeia3844221.5.81F6V13113.763+701552.521.3.55
    Cassiopeia4044531.5.2853.3G8III13830.914+73224.3.141.3.83
    Cassiopeia4244701.5.18B9V14255.891+703721.341.4.98
    Cassiopeia43V0557180557119191.5.551.5.64B9p(Si-Sr-Cr)14220.524+68234.91.3.85
    Cassiopeia44119411.5.7866B8IIIn14319.682+60331.4.281.4.64
    Cassiopeia4745621.5.3895.6F0Vn251.7.03+771652.461.4.88
    Cassiopeia4845541.4.540.5A3IV2157.365+705425.351.3.31
    Cassiopeia4945651.5.225.4.14G8III2531.212+76654.381.3.91
    Cassiopeia5045601.3.98A2V2326.099+722516.781.3.75
    Cassiopeia52120956A1Vn2252.687+64541.5.231.3.53
    Cassiopeia53120971.5.58B8Ib230.287+642323.9.141.3.75
    Cassiopeia55121806.7.14G0II-III+B9V21429.043+663128.12.141.3.76
    Centaurusalp 1RIGIL KENTAURUS252838150-0.0120.9.14G2V143936.167-60501.7.351.3.44
    Centaurusalp 21511.1.3521K1V143936.1-605081.3.28
    Centaurusalp 23091.1.3521K1V143948-605100
    CentaurusbetAGENA2525821440.611.3.14B1III14349.462-602222.731.3.87
    Centaurusgam 12236031271.2.171.5.14A1IV124131.006-485734.711.2.84
    Centaurusgam 212835124120-485800
    Centaurusdel2396891162.6.14268.6B2IVne12821.534-504320.791.2.09
    Centauruseps2410471392.3.1436.9B1III133953.282-532758.721.2.21
    Centauruszet2245381431.2.55B2.5IV135532.383-471717.961.2.17
    Centauruseta62250441491.2.31B1.5Vne143530.429-42928.1.141.2.49
    Centaurusthe5MENKENT2051881462.6.1469.9K0-IIIb14640.962-36221.12.141.2.25
    Centaurusiot2043711361.2.75A2V132035.842-364244.291.2.72
    Centauruskap2253441581.3.133.9.14B2IV14591.9.98-42615.3.141.2.38
    Centauruslam2514721131.3.1316.3.14B9III113546.817-6311.11.161.2.11
    Centaurusmu2244711413.4.1448B2IV-Ve134937.015-422825.711.2.94
    Centaurusnu2244691.3.41B2IV134930.313-414115.821.2.92
    Centaurusxi 12238701.4.85A0V13333.169-493138.461.2.32
    Centaurusxi 22239091.4.2725.1.14B1.5V13654.616-495422.221.2.68
    Centaurusomi 12391451.5.1313.3.14G30-Ia113146.144-592632.121.2.78
    Centaurusomi 22391461.5.15A2Ia113148.671-593056.471.2.69
    Centauruspi2389861.3.890.2B5Vn11210.481-542927.6.141.2.17
    Centaurusrho2397371.3.96B3V121139.133-52221.6.821.2.86
    Centaurussig2234541.3.91B2V12281.2.19-501350.831.2.09
    Centaurustau2235601.3.86A2V123742.162-483228.441.2.84
    Centaurusups 12245851.3.87B2IV-V135840.773-44481.12.791.2.04
    Centaurusups 22246211.4.34F6II14143.429-45361.12.541.2.65
    Centaurusphi2245771.3.83B2IV135816.263-4261.2.791.2.66
    Centauruschi2246731.4.36B2V1461.2.09-411046.631.2.11
    Centauruspsi2054534.5.1436A0IV142033.407-37531.7.231.2.55
    Centaurus12048121.4.23F3IV134541.263-33237.621.2.46
    Centaurus2V08061908062048751.4.161.4.26M5III134926.732-34271.2.711.2.83
    Centaurus32049161.4.567.9.14B5IIIp135149.58-325939.81.2.19
    Centaurus32049176.6.147.9.14B8V135150.073-325941.421.2.37
    Centaurus42049441.4.7314.9.14B4IV135312.5.14-315539.591.2.52
    Cepheusalp5ALDERAMIN193022351.2.44206.8A7V211834.783+62358.2.142.4.14
    Cepheusbet8ALFIRK100572361.3.2313.4.14B1IV212839.628+703338.671.2.13
    Cepheusgam35ERRAI108181.3.21K1III-IV233920.864+773756.561.2.08
    Cepheusdel27345081.3.7540.8F5Ib-G2Ib22291.10.55+582454.521.2.72
    Cepheuseps23342271.4.19127.8F0IV22151.1.99+57236.711.2.71
    Cepheuszet21341371.3.35K1.5Ib221051.287+58121.4.431.3.19
    Cepheuseta3190191.3.4351.7K0IV204517.395+615019.751.1.94
    Cepheusthe2188971.4.22A7III202934.885+625938.691.1.38
    Cepheusiot32202681.3.52K0-III224940.826+66121.1.491.2.33
    Cepheuskap196651.4.397.3.14B9III20853.352+7742410.951
    Cepheuslam22341495.4.14O6I(n)fp221130.707+592452.231.2.15
    CepheusmuHERSCHEL'S GARNET STAR336934.8.1419.5.14M2-Ia214330.441+584648.11.1.99
    Cepheusnu10196241.4.29A2Ia214526.951+61714.771.2.38
    Cepheusxi17ALKURHAH198271.4.297.7.14A3/6Vm22347.426+643740.241.1.74
    Cepheusomi34205541.4.753.1.14K0III231837.549+68641.71.2.86
    Cepheuspi33106291.4.411G2III23753.903+752315.351.1.38
    Cepheusrho 128103751.5.83A2Vm222642.548+78471.8.831.1.99
    Cepheusrho 229AL KALB AL RAI104025.5.14A3V222952.917+784927.331.1.05
    Cepheus4190041.5.58A8V204311.3.14+663926.941.2.78
    Cepheus6193131.5.18B3IVe211922.242+645218.381.2.35
    Cepheus7194321.5.44B7V212746.096+664833.031.1.62
    Cepheus9V0337200337195411.4.691.4.78B2Ib213755.245+62454.972.3.14
    Cepheus11101261.4.56K1III214155.298+711841.341.1.95
    Cepheus12196421.5.52M1IIIb214725.318+604133.871.1.44
    Cepheus13338645.8.14B8Ib215453.12+563640.441.2.78
    Cepheus14LZ200274339901.5.561.5.66O8.5III+O9Vn2221.4.76+5801.1.561.2.77
    Cepheus16102165.3.14131.4F5V215914.962+731047.591.1.13
    Cepheus18MO200277198281.5.131.5.33M5III22352.868+6371.11.291.1.01
    Cepheus19198495.11.1460.4O9.5Ib2251.8.95+621647.581.1.58
    Cepheus20198471.5.27K4III2250.508+62471.8.451.1.04
    Cepheus24102651.4.79G7II-III22948.426+722028.511.1.44
    Cepheus25199911.5.75K3III22181.12.38+624816.8.141.1.35
    Cepheus26200751.5.46B0.5Ibe:22271.5.97+65756.371.1.44
    Cepheus30201901.5.19A3IV223839.045+63353.9.141.2.96
    Cepheus31104255.8.14F3III-IV223546.115+733835.551.1.64
    Cetusalp92MENKAR110920221.2.53M1.5IIIa3216.777+4522.931.2.93
    Cetusbet16DIPHDA14742082.4.14G9.5IIICH-104335.383-17591.11.851.2.57
    Cetusgam86KAFFALJIDHMA1107072711.3.472.8.14A3V24318.048+3141.8.551.2.76
    Cetusdel821106654.7.14B2IV23928.945+01942.661.2.47
    Cetuseps831485281.4.840.1F5V+F6V23933.813-115219.691.2.44
    Cetuszet55BATEN KAITOS1480591.3.73187K0IIIBa0.115127.638-10201.6.191.3.45
    Cetuseta311476321.3.45233.5K1.5IIICN1Fe0.51835.401-101055.981.3.43
    Cetusthe451292743.6.1465.4K0III-IIIb1241.1.09-8110.561.2.52
    Cetusiot8DENEB KAITOS SHEMALI1286941.3.56108.8K1.5III01925.665-84925.981.2.82
    Cetuskap 1961111201.4.83268.7G5V31921.692+3221.12.711.2.09
    Cetuskap 2971111421.5.69G8.5III3211.6.88+34032.231.2.75
    Cetuslam911108894.7.14B6III25942.907+85426.5.141.3.84
    Cetusmu871107231.4.270.1F0IV24456.53+10650.821.2.95
    Cetusnu781106351.4.868.1.14G8III23552.456+53535.531.2.95
    Cetusxi 1651104081.4.37G6II-IIICN-221259.998+85048.261.3.05
    Cetusxi 2731105431.4.28B9III2281.9.36+82736.181.2.59
    Cetusomi68MIRA12982520210118.7M7IIIe+Bep21920.729-25839.421.2.62
    Cetuspi 1891485751.4.25B7V2441.7.64-135131.341.3.02
    Cetusrho721483851.4.89B9.5Vn22556.996-121725.721.2.32
    Cetussig761484451.4.75F4IV2321.5.31-151440.561.2.61
    Cetustau521479863.5.1489.8G8V1441.4.18-155614.621.2.66
    Cetusups591674714M0III200.305-21440.231.2.65
    Cetusphi 1171474231.4.76K0III0441.11.94-103634.241.3.87
    Cetusphi 2191474701.5.19F7IV-V0501.7.95-103839.311.3.96
    Cetusphi 3221475191.5.31K4III0561.1.27-111559.631.2.86
    Cetusphi 4231475461.5.61G7III05843.854-112248.361.3.95
    Cetuschi531480361.4.67184F3III14935.101-10411.11.151.2.92
    Cetus11659721.6.26K0II-III235821.215-155051.061.2.74
    Cetus21470591.4.55B9.5Vn0344.397-17201.9.481.2.62
    Cetus31470661.4.94K3Ib0430.107-103034.261.2.03
    Cetus61471331.4.89F7V01115.884-15281.4.591.3.11
    Cetus7AE2100591471691.4.261.4.46M1III-M3III01438.428-185557.661.2.06
    Cetus9BE2100831472371.6.39202.1G2V02251.77-121233.891.3.74
    Cetus101287601.6.19G8III02637.414-0258.591.2.66
    Cetus121287911.5.7210.6.14M0III0301.2.61-35726.351.2.65
    Cetus131288395.2.140.3F8V03514.872-33534.291.3.71
    Cetus141288431.5.93F5IV03532.778-03020.261.2.92
    Cetus151288686.9.14K00381.4.19-0301.12.691.2.71
    Cetus181474321.6.1569.5G0V04528.674-125250.521.2.58
    Cetus201290091.4.77M0III0530.506-1839.61.2.13
    Cetus211290191.6.16G5IV05417.582-84426.771.2.59
    Cetus251290941.5.4399.9K0III-IV131.2.64-4501.12.151.2.59
    Cetus261096436.4.1416F1V1349.011+1220.411.2.68
    Cetus271476016.12.14K0III1536.836-95845.371.2.35
    Cetus281476061.5.58A1V161.5.32-95021.771.2.37
    Cetus291096946.7.14G51759.632+15934.921.2.66
    Cetus301476221.5.82F7IV1746.22-9471.7.911.2.98
    Cetus321291546.4.14K0III1101.11.73-85421.641.3.61
    Cetus331097151.5.95K4III11033.599+22644.351.2.11
    Cetus341291691.5.94K4III11143.478-2151.4.251.3.16
    Cetus371291931.5.1349.8F5V11424.046-75522.571.2.06
    Cetus381291965.7.14114.1F5V11449.17-05825.631.2.63
    Cetus39AY2100781292041.5.351.5.58177.6G5III-IVe11636.253-2301.1.271.2.84
    Cetus401292106.8.14F811659.023-21644.291.3.31
    Cetus421292351.5.871.6.14G8III+A7V11948.331-03031.931.2.48
    Cetus431292621.6.49gK012234.816-02658.911.2.89
    Cetus44AV2100751292756.2.141.6.2284.6F0V1241.2.01-8026.951.2.82
    Cetus461478034.9.14K2.5IIIb12537.207-143555.91.2.38
    Cetus471478121.5.66F0IIIDel Del12651.585-13323.721.2.59
    Cetus481670865.12.1422A1V12936.131-213745.581.2.81
    Cetus491478861.5.63A3V13437.763-154034.331.2.28
    Cetus501479011.5.42K2IIIaBa0.2CN113558.946-15240.261.2.12
    Cetus561674161.4.85K4III15640.187-223136.271.2.77
    Cetus571674661.5.41M1III15946.116-204928.12.141.2.84
    Cetus601296551.5.43A5III231.11.46+0742.321.2.96
    Cetus611296671.5.9342.9G5II-III+G5V2348.174-02024.961.2.25
    Cetus631297391.5.93gG921135.855-14931.8.141.3.08
    Cetus641103901.5.63G0IV21121.9.14+8341.11.431.2.65
    Cetus661297521.5.5416.4.14F8V21247.497-22337.071.3.89
    Cetus671297981.5.51G8.5III21659.044-62519.781.2.41
    Cetus691104951.5.28M2III22156.624+02344.61.2.81
    Cetus701298581.5.42F0Vn2221.12.59-0536.4.141.2.75
    Cetus711298881.6.33A0III22458.355-24648.191.2.52
    Cetus751299591.5.35gG32321.9.12-121.6.261.2.18
    Cetus771299841.5.7594.7gK423442.652-75133.721.3.26
    Cetus791299926.8.14G023519.963-33337.51.3.92
    Cetus801300041.5.53146.7M0III2360.048-74953.851.2.94
    Cetus811300261.5.65gG523741.803-32346.031.2.43
    Cetus841300551.5.714F7IV24113.939-04145.291.2.79
    Cetus931109211.5.61B7V3222.509+4211.10.331.2.77
    Cetus941303555.6.143.2.14F8V31246.451-11145.891.2.89
    Cetus951304081.5.381.2.14G9IV31822.408-05548.631.2.61
    Chamaeleonalp2564964.7.14F5III81831.63-76551.10.790.925
    Chamaeleonbet2569241.4.26B5Vn121820.641-791843.891.2.77
    Chamaeleongam2567314.11.14M0III103528.2.14-783627.651.1.06
    Chamaeleondel 12585921.5.470.6K0III104515.677-802811.1.141.1.28
    Chamaeleondel 22585931.4.45B2.5IV104546.487-803224.951.1.74
    Chamaeleoneps2568941.4.910.9B9Vn115937.258-781318.8.141.2.36
    Chamaeleonzet2585385.11.14B5V93353.217-805629.330.576
    Chamaeleoneta2565431.5.47B8V84119.699-785748.570.205
    Chamaeleonthe2565031.4.3531K2IIICN0.582038.564-77291.4.280.645
    Chamaeleoniot2585301.5.36F3-5IV9241.9.39-804713.580.75
    Chamaeleonkap2568995.4.14K4III12446.449-76311.8.761.2.16
    Chamaeleonmu 12585541.5.52A0IV10043.532-821252.860.891
    Chamaeleonmu 22585616.6.14G6-8III1041.7.62-813356.650.892
    Chamaeleonnu2566581.5.45G8III94621.135-764633.850.52
    Chamaeleonpi2568571.5.65F1III113715.471-755347.311.2.76
    Circinusalp2528531531.3.1915.6.14ApSrEuCr:144230.397-645830.7.1460.544
    Circinusbet2423844.7.14A3V151730.841-58481.4.581.3.11
    Circinusgam2424631.4.510.9B5IV+F8152322.698-591914.891.3.83
    Circinusdel2530845.9.1450O8.5V151656.74-605726.741.3.16
    Circinuseps2530881.4.86K2.5III151738.851-633637.831.3.31
    Circinuszet2529516.9.14B3Vn145442.388-655929.4.141.3.63
    Circinuseta2530051.5.17G8III15448.153-64153.563.4.14
    Circinusthe2529655.11.140.1B4Vnpe145644.014-624651.041.3.07
    ColumbaalpPHACT196059521.2.6413.5.14B7IVe53938.953-34427.11.141.2.93
    ColumbabetWAZN196240553.12.14K2III55057.596-35466.11.141.2.62
    Columbagam1963521.4.3633.8B2.5IV55732.237-351659.981.2.89
    Columbadel1967351.3.85G7II6221.6.05-33261.11.291.2.08
    Columbaeps1959241.3.87K1IIIa5311.12.85-352814.281.2.25
    Columbaeta2176501.3.96K0III5591.8.16-424854.991.1.62
    Columbathe1965145.2.14B9IV6731.636-371510.3.141.2.14
    Columbakap1966431.4.37K0.5IIIa61633.079-35826.11.141.2.11
    Columbalam1962761.4.87B5V5531.6.71-33481.4.821.2.69
    Columbamu1961491.5.17O9.5V54559.918-321823.321.3.42
    Columbanu 11706011.6.16F0IV53716.528-275216.951.2.49
    Columbanu 21706131.5.31F4V53744.625-2841221.2.47
    Columbaxi1963161.4.97K1III55529.874-37714.791.2.81
    Columbaomi1957211.4.83K0IV51729.067-345343.181.2.03
    Columbapi 12177206.12.14Am6641.031-421754.891.1.61
    Columbapi 22177305.5.140.1A0V6752.939-42914.1.141.1.57
    Columbasig1963305.5.14F2III55620.964-312256.61.2.78
    Coma Berenicesalp42DIADEM1004431.5.220.2F5V13959.287+173145.731.2.32
    Coma Berenicesbet43827061.4.2690.8F9.5V131152.398+275241.371.2.22
    Coma Berenicesgam15823131.4.36K1IIIFe0.5122656.27+28161.6.142.7.14
    Coma Berenices2821231.5.873.6.14F0IV-V12416.603+212733.131.2.97
    Coma Berenices3999731.6.39A4V121031.608+164833.171.2.36
    Coma Berenices4821781.5.66K4III121151.127+255213.181.2.79
    Coma Berenices5821821.5.57K0II-III12121.9.73+203230.9.141.2.75
    Coma Berenices61000125.1.14A3V12160.171+1453571.2.43
    Coma Berenices7822111.4.95G8IIIFe-0.5121620.524+235643.291.2.49
    Coma Berenices8822391.6.27A5III vs121919.124+2321.4.551.2.82
    Coma Berenices9822441.6.33F8V s121929.586+28924.631.2.31
    Coma Berenices111000531.4.749.1.14G8+III122043.011+174734.241.2.86
    Coma Berenices12822731.4.8165.3G0III-IV+A3V122230.314+255046.021.2.89
    Coma Berenices13GN250196822911.5.151.5.18A2V(Am)122418.517+26554.861.2.31
    Coma Berenices14823101.4.95F0p122624.065+27161.5.551.2.18
    Coma Berenices16823145A4V122659.337+264932.31.2.72
    Coma Berenices17AI250063823301.5.235.4.14145.4A0p(Cr-Eu-Sr)122854.695+255445.891.2.84
    Coma Berenices18823331.5.48F5III122926.94+24631.871.2.75
    Coma Berenices20823361.5.69A3V122943.231+205345.831.2.18
    Coma Berenices21UU250034823461.5.411.5.46A3p(Sr-Cr-Eu)12310.564+24341.1.871.2.41
    Coma Berenices22823781.6.29A4Vm123334.166+241659.161.2.42
    Coma Berenices23823901.4.810.4A0IV123451.053+223745.11.2.74
    Coma Berenices241001591.6.5620.2.14A9Vm12351.6.29+182237.871.2.08
    Coma Berenices241001603025.2.1420.2.14K2III12351.7.51+182237.361.2.62
    Coma Berenices251001761.5.68K5III123658.328+17522.361.2.09
    Coma Berenices26824211.5.46G9III12391.7.77+21345.151.2.83
    Coma Berenices271002525.12.14K3III124638.731+163438.761.2.06
    Coma Berenices281002691.6.56A1V124814.338+133311.12.141.2.91
    Coma Berenices291002835.7.14A1V124854.24+14720.861.2.83
    Coma Berenices30825151.5.7842.5A2V124917.445+27331.8.381.2.65
    Coma Berenices31825371.4.94G0III125141.919+273226.421.2.19
    Coma Berenices321003091.6.32196.5M0III12521.12.32+17425.641.2.02
    Coma Berenices35825503044.9.1481G8III+F6V125317.775+211441.521.2.63
    Coma Berenices361003571.4.78M1-IIIb125855.481+172433.331.2.04
    Coma Berenices37632884.9.145.5.14G9IIICH-2Fe1Ca113016.481+30471.6.241.2.23
    Coma Berenices381003741.5.96K0III1311.9.37+177231.2.44
    Coma Berenices39826501.5.991.2.14F4V13621.207+2191.12.541.2.11
    Coma Berenices40FS250182826515.3.146.1.14M5III13622.564+223657.741.2.41
    Coma Berenices41826594.8.14K5III1371.10.13+273728.821.2.21
    Corona AustralisalpALFECCA MERIDIANA2109904.11.14A2V19928.334-375416.351.3.68
    Corona Australisbet2110054.11.14K0II19101.1.24-392027.6.141.3.75
    Corona Australisgam2109283371.4.93131.6.14F8V19625.123-37347.781.3.95
    Corona Australisdel2295131.4.59K1III19820.896-402948.151.3.39
    Corona Australiseps2107811.4.87F2V185843.417-37625.981.3.96
    Corona Australiszet2294611.4.75B9.5V1931.6.45-42542.911.3.27
    Corona Australiseta 12292991.5.49A3V184850.485-434048.191.3.14
    Corona Australiseta 22293071.5.61B9IV184934.984-43261.2.471.3.67
    Corona Australisthe2291111.4.64G8III183330.182-421845.061.3.59
    Corona Australiskap 12102961.6.3221.4.14A0III183323.276-38431.12.771.3.99
    Corona Australiskap 22102951.5.6521.4.14B9V183323.108-384334.451.4.37
    Corona Australislam2105011.5.1329.2A2Vn184346.948-381924.561.3.83
    Corona Australismu2292851.5.24G5-6III184744.476-402421.831.3.83
    Corona Borealisalp5ALPHEKKA838931651.2.23A0V+G5V153441.28+264252.981.2.23
    Corona Borealisbet3NUSAKAN838311.3.680.3F0p152749.751+29620.491.2.62
    Corona Borealisgam8839581.3.840.2B9IV+A3V154244.574+261743.931.2.16
    Corona Borealisdel10840191.4.63G3.5III-IVFe-1154935.661+2645.7.141.2.17
    Corona Borealiseps13840981.4.15101.4K2IIIab155735.261+265240.351.2.34
    Corona Borealiszet 176483366.4.14B9V153922.206+36381.11.771.2.59
    Corona Borealiszet 27648343185.7.146.4.14B7V153922.695+36389.2.141.2.78
    Corona Borealiseta2646733151.5.58100.5G0V15231.12.22+301716.191.2.98
    Corona Borealisthe4647691.4.140.5B6Vnne153255.784+312132.581.2.81
    Corona Borealisiot14841521.4.99A0p:Hg:16126.651+29511.3.711.2.63
    Corona Borealiskap11649481.4.82134.6K1IVa155113.937+353926.491.2.23
    Corona Borealislam12649741.5.4594.3F0IV155547.676+375649.191.2.25
    Corona Borealismu6647905.11.14M1.5III-IIIb153514.954+39035.771.2.68
    Corona Borealisnu 120652575.2.14364.4M2IIIab162221.44+334756.651.2.61
    Corona Borealisnu 221652591.5.39K5III162229.22+334213.291.2.16
    Corona Borealisxi19652541.4.85185.1K0III16221.5.35+305331.671.2.04
    Corona Borealisomi1837681.5.51147.3K0III15201.8.36+293657.861.2.34
    Corona Borealispi9648701.5.56gG9154359.306+323057.011.2.27
    Corona Borealisrho15650241.5.4189.6G0+VaFe-11611.2.13+331813.261.2.87
    Corona Borealissig17TZ270033651653201.5.696.4.14F8V161440.757+335130.661.2.48
    Corona Borealistau16651081.4.762.2.14K1-III-IV16858.289+3629271.2.11
    Corona Borealisups18842811.5.78123.4A3V161644.763+2990.71.2.91
    Corvusalp1ALCHIBA1805054.2.14F2III-IV12824.767-244344.051.2.08
    Corvusbet9KRAZ1809151251.2.65G5II123423.241-232348.221.2.17
    Corvusgam4GIENAH GHURAB1571761201.2.59B8IIIpHgMn121548.371-173230.991.2.56
    Corvusdel7ALGORAB1573231231.2.9524.4.14B9.5V122951.857-163055.561.2.65
    Corvuseps2MINKAR1805311173K2.5IIIaBa0.2:12101.7.88-223711.1.141.2.78
    Corvuszet51807001.5.2111.2.14B8Vne122033.709-221257.321.2.28
    Corvuseta81573451.4.31F2III-IV12321.4.21-161146.141.2.68
    Corvus31805461.5.46A2V12111.3.54-23361.8.521.2.67
    Corvus61807471.5.68gK1122321.57-245025.541.2.43
    Crateralp7ALKES1563754.8.14K0+III105946.465-181755.661.2.17
    Craterbet111796241.4.48A2III111139.493-224932.871.2.09
    Cratergam151566614.8.145.3.14A5V112452.92-17411.2.471.2.23
    Craterdel121566051.3.56G8III-IV111920.45-144642.91.2.32
    Cratereps141566581.4.83K5III112436.56-105133.531.2.85
    Craterzet271568691.4.73G8IIIa114445.794-18211.2.831.2.49
    Cratereta301569881.5.18A0V11560.938-1791.2.971.2.35
    Craterthe211382964.7.14B9.5Vn113640.907-9488.11.141.2.31
    Crateriot241568021.5.481.4.14F7V113840.071-13121.6.641.2.21
    Craterkap161566851.5.9427.9.14F4III-IV11271.9.99-122124.591.2.41
    Craterlam131566465.9.14F5III112321.897-184648.441.2.82
    Craterpsi1565281.6.130.2A0V111230.391-18300.11.2.98
    CruxalpACRUX3011.1.334.7.14+++122635.948-63556.51.2.99
    Cruxalp 1ACRUX A2519041211.1.334.4.14B0.5IV122635.948-63556.51.2.88
    Cruxalp 2ACRUX B1222.1.145B1122642-63701.3.64
    CruxbetMIMOSA2402591311.1.25371.6B0.5III124743.293-594119.341.2.42
    Cruxgam 1GACRUX2400191241.1.63110.6M3.5III12311.9.53-57647.561.2.97
    Cruxgam 22400221.6.42110.6A3V123116.72-57451.561.2.85
    Cruxdel2397911182.8.14B2IV12151.8.75-584455.811.2.17
    Cruxeps2518621.3.59K3-4III122121.55-60241.4.461.2.89
    Cruxzet2518414.4.1433.8B2.5V121826.118-6401.11.181.2.36
    Cruxeta2517421.4.1544F2III12652.824-643649.221.2.13
    Cruxthe 12517051.4.334.5.14Am1231.1.51-631846.41.2.98
    Cruxthe 22517171.4.72B2IV12419.163-63956.281.2.91
    Cruxiot2520161.4.6927.5.14K0III124537.878-605852.411.2.73
    Cruxkap2520775.9.14B5Ia125349.076-602236.661.2.02
    Cruxlam2403681.4.62B4Vne125439.152-59847.541.2.96
    Cruxmu 12403664.3.1434.9B2IV-V125435.619-571040.021.2.24
    Cruxmu 22403671.5.1734.9B5Vne125436.825-57105.6.141.2.08
    Cygnusalp50DENEB499412321.1.2575.4A2Ia204125.93+451649.291.2.15
    Cygnusbet 16ALBIREO873012233.8.1434.7K3II+B9.5V193043.309+275734.591.2.85
    Cygnusbet 26873023395.11.1434.7B8Ve193045.338+275755.181.2.09
    Cygnusgam37SADR495282292.2.14141.2F8Ib202213.71+401524.12.141.2.03
    Cygnusdel18487962241.2.872B9.5IV+F1V194458.535+45750.661.1.39
    Cygnuseps53GIENAH704742331.2.4654.9K0-III20461.12.86+33581.12.921.2.88
    Cygnuszet64710702343.2.1491.2G8+III-IIIaBa0.6211256.182+301337.071.2.37
    Cygnuseta21691161.3.8946K0III195618.385+3550.311.2.84
    Cygnusthe13318151.4.4848.4F4V193626.463+501315.541.2.48
    Cygnusiot 17316731.5.75A1V192725.925+521913.781.1.25
    Cygnusiot 210317021.3.79A5Vn192942.359+514347.211.1.74
    Cygnuskap1315371.3.77G9III19171.6.54+53221.6.561.1.97
    Cygnuslam54705053431.4.5390.9B5Ve204724.524+362927.141.2.79
    Cygnusmu 178899401.4.732F6V21441.8.06+284434.311.2.26
    Cygnusmu 278899396.8.142G2V21441.8.12+284435.271.2.16
    Cygnusnu58502741.3.94A1Vn20571.10.41+41101.1.982.8.14
    Cygnusxi62504241.3.72K4.5Ib-II21455.865+435540.271.3.41
    Cygnusomi 130493321.4.83337.5A5IIIn201318.019+464856.51.1.75
    Cygnusomi 231V0695310695493371.3.731.3.89337.5K4Iab+B4IV-V201337.9+464428.891.2.91
    Cygnusomi 332V1488311488493853.9.141.4.14208.9K5Iab+B4IV-V201528.306+474251.711.1.79
    Cygnuspi 180AZELFAFAGE336651.4.67B3IV21421.5.59+511122.971.2.83
    Cygnuspi 281512931.4.23B3III214647.615+491834.591.2.96
    Cygnusrho73510354.2.14G8IIIFe-0.5213358.854+453530.571.3.05
    Cygnussig67711651.4.23B9Iab211724.949+392340.881.2.39
    Cygnustau65711211.3.721F2IV211447.472+38243.931.2.96
    Cygnusups66711731.4.4315.3.14B2Vne211755.072+345348.581.2.84
    Cygnusphi12686371.4.69G8III-IV193922.599+3091.12.271.2.11
    Cygnuschi689431.4.23158S6+/1e195033.86+325451.031.2.08
    Cygnuspsi24321141.4.923.1.14A4Vn195537.774+522620.221.1.68
    Cygnusome 143496431.5.69dF020271.2.81+49230.431.1.65
    Cygnusome 245497121.4.9556.3B2.5IV20301.3.53+48571.5.941.2.85
    Cygnusome 346497411.5.4456.8M2IIIab203118.833+491313.471.2.02
    Cygnus2871591.4.97B3IV19241.7.04+293716.731.3.17
    Cygnus4V1741311741683014.6.14B9p(Si)19261.9.25+36194.12.141.2.19
    Cygnus8684471.4.74B3IV193146.314+34271.10.881.2.36
    Cygnus9873851.5.380.1F8III+A0V193450.937+292747.021.2.44
    Cygnus11685526.5.14B8Vne193548.333+365640.221.2.88
    Cygnus14486915.4.14B9III193926.461+42491.5.731.1.52
    Cygnus15687781.4.89G7+III194416.601+372115.561.2.92
    Cygnus16318981.5.9639.2G1.5Vb194148.923+503130.691.1.49
    Cygnus17688271.4.9926F7V194625.598+334339.611.2.89
    Cygnus19V1509311509689475.8.145.4.1455.5M2IIIa195033.979+384320.671.2.34
    Cygnus20320425.3.14K3IIICN1195037.724+525916.961.1.22
    Cygnus22691011.4.94B5IV195551.729+38291.12.131.3.69
    Cygnus23320851.5.14B5V195317.413+573125.1.141.1.96
    Cygnus25V1746311746692311.5.19B3IV-Ve195955.193+37234.791.2.58
    Cygnus26490985.5.1441.8K1II-III20121.608+50616.8.141.1.98
    Cygnus27694131.5.3611.9.14K0IV20621.758+355821.181.2.79
    Cygnus28V1624311624695181.4.911.4.97B3VeV20925.62+365022.711.2.72
    Cygnus29V1644311644696781.4.941.4.97212.4A2V201432.027+364822.971.2.37
    Cygnus33323784.3.14A3IV-Vn201323.884+56341.3.861.2.24
    Cygnus34P319216697731.4.81B2pe201747.17+38158.871.2.96
    Cygnus35698061.5.17F5Ib201839.117+345857.761.2.41
    Cygnus36698031.5.58A2V201828.611+365959.731.2.72
    Cygnus39699501.4.43K2.5IIIFe-0.5202351.591+321124.891.3.25
    Cygnus40700561.5.62A3V202734.26+382625.471.2.34
    Cygnus41700954.1.14F5II202923.739+30221.6.711.3.38
    Cygnus42700961.5.88A1Ib202920.403+362717.191.2.63
    Cygnus44701351.6.192F5Iab203059.233+36569.6.141.3.35
    Cygnus47702031.4.61117.6K2Ib+B3V203354.21+35151.3.141.2.61
    Cygnus48702871.6.32180.8B8IIIn203731.777+313421.321.3.41
    Cygnus49703621.5.512.5.14G8IIb20411.2.57+321825.9.141.3.03
    Cygnus51328091.5.393B2V20421.12.42+502024.311.1.22
    Cygnus52704671.4.226.1.14G9.5III204539.735+30431.11.411.3.66
    Cygnus55V1661311661500991.4.811.4.8721.3.14B3eaIa204856.35+46651.241.2.55
    Cygnus56501215.4.1475.5A4mDel Del20501.4.36+44333.711.2.04
    Cygnus57501801.4.78B5V205314.757+442314.381.2.61
    Cygnus59V0832310832503351.4.491.4.8820.1.14B1.5Venn205949.562+473115.571.2.02
    Cygnus60503591.5.372.6.14B1Ve2111.10.23+46921.271.3.48
    Cygnus61V1803 A709193461.5.191.5.2728.7.14K5V21654.572+384444.831.2.47
    Cygnus63504561.4.5515.7.14K4Ib-IIa21636.11+473854.31.2.22
    Cygnus68506905O7.5III:n((f))211827.149+435645.381.2.88
    Cygnus69713291.5.9453.4B0Ib212547.011+36403.8.141.2.47
    Cygnus70713581.5.31B3V212721.368+3770.671.2.51
    Cygnus71509341.5.24K0-III212926.96+463226.131.3.93
    Cygnus72714804.9.14K0.5III213446.571+38321.2.651.2.42
    Cygnus74511015.1.14A5V213656.958+402448.791.2.83
    Cygnus75511675.11.1457.9M1IIIab21401.11.65+431625.991.3.15
    Cygnus76511896.11.1462.1A2V214134.296+404819.11.141.2.92
    Cygnus77512071.5.690.1A0V214222.876+41437.661.2.91
    Cygnus79716431.5.65151.2A0V214325.653+38171.1.731.2.23
    Delphinusalp9SUALOCIN1063571.3.7743.4B9IV203938.295+155443.291.2.73
    Delphinusbet6ROTANEV1063161.3.630.6F5IV203732.956+143542.631.2.49
    Delphinusgam 1121064751.5.149.8.14F7V204638.737+16727.591.3.56
    Delphinusgam 2121064763421.4.279.8.14K1IV204639.49+16727.391.3.21
    Delphinusdel111064251.4.43A7IIIpDel Del204327.542+15428.361.3.24
    Delphinuseps2DENEB DULFIM1062304.3.14B6III20331.12.79+11181.11.852.5.14
    Delphinuszet41062741.4.68A3V203518.535+144027.231.3.08
    Delphinuseta31062481.5.38A3IV s203357.031+13138.141.2.46
    Delphinusthe81063421.5.72K3Ib203843.944+131853.991.3.19
    Delphinusiot51063221.5.43A2V203749.127+112239.711.2.76
    Delphinuskap71260595.5.14203.6G2IV20391.7.76+10510.7.141.3.67
    Delphinus11061726.8.140.9A1eShell203017.965+105345.481.2.04
    Delphinus101063841.5.99gK4204116.221+143458.821.2.77
    Delphinus131262221.5.581.4.14A0V204748.331+6030.141.2.68
    Delphinus141262651.6.33A1V s204948.228+751511.2.26
    Delphinus151065361.5.98108F5V204937.778+123242.561.2.45
    Delphinus161066661.5.5836A4V205538.581+12341.6.611.2.69
    Delphinus171066651.5.17K0III205536.667+134317.471.2.22
    Delphinus181067121.5.48198.2gG6205825.911+105021.241.2.24
    Doradoalp233564321.3.270.2A0IIISi43359.821-55242.141.2.47
    Doradobet2493111.3.76F6Ia53337.513-622923.651.1.06
    Doradogam2334571.4.25F4III4161.1.54-51291.11.691.1.27
    Doradodel2493461.4.35A7V54446.417-65441.7.891.1.24
    Doradoeps2493685.11.14B6V54953.589-66541.4.391.1.08
    Doradozet2338221.4.72F7V5530.634-572821.991.1.75
    Doradoeta 12494481.5.71A0V661.9.33-66222.671.1.41
    Doradoeta 22494695.1.14M2.5III61114.945-653522.2.141.1.75
    Doradothe2492251.4.83K2.5IIIa51345.346-67111.7.190.942
    Doradokap2336641.5.27A8-9III-IV44421.194-594357.951.1.66
    Doradolam2339811.5.14G6III52619.194-585445.721.2.83
    Doradonu2494615.6.14B8V6844.242-6850360.405
    Doradopi 12495321.5.56K5III62238.183-69591.2.710.548
    Doradopi 22495501.5.38G8III62528.61-694124.830.441
    Dracoalp11THUBAN162731.3.65A0III14423.349+642233.021.1.91
    Dracobet23RASTABAN304291971.2.794.2.14G2Ib-IIa173025.957+52185.7.141.1.92
    Dracogam33ETAMIN306532061.2.23140.1K5III175636.375+512920.261.1.45
    Dracodel57ALTAIS182222223.7.1488.1G9III191233.286+673941.570.764
    Dracoeps63TYL95401.3.833.2.14G7IIIbCN-219481.10.89+70161.4.291.1.27
    Dracozet22ALDHIBAH173651871.3.17B6III17847.224+654252.761.1.81
    Dracoeta14BOOBOO170741761.2.74564.9G8-IIIab162359.488+613051.251.1.78
    Dracothe13297654.1.14F8IV16153.327+5833551.1.34
    Dracoiot12ED ASICH295201641.3.29254.6K2III152455.758+585757.711.1.94
    Dracokap575931.3.87B6IIIpe123328.974+694717.641.2.63
    Dracolam1GIAUSAR155321.3.84M0IIICa-1113124.274+691951.921.2.73
    Dracomu21ARRAKIS302393255.8.14192F7V17519.757+542813.331.1.52
    Draconu 124304471.4.8862.3A6V17321.10.39+55113.5.141.1.36
    Draconu 225KUMA304501.4.8762.3A4m173216.1.14+551022.591.1.71
    Dracoxi32GRUMIUM306311.3.75316K2-III175331.713+565221.511.1.61
    Dracoomi47312181.4.6634.6G9IIIFe-0.518511.12.66+592318.151.1.52
    Dracopi58182991.4.59A2III s192040.113+654252.121.1.46
    Dracorho67186761.4.51124K3III20249.041+675224.781.1.93
    Dracosig61ALSAFI183961.4.68315.6K0V193221.633+693940.140.784
    Dracotau6093661.4.45K2+IIIbCN1Fe1191533.006+732119.621.1.51
    Dracoups5292831.4.82K0IIIBa0.2185423.861+711749.931.1.74
    Dracophi4390841.4.220.2A0pSi:182045.453+712016.441.1.25
    Dracochi4490871.3.570.1F7V18211.3.91+724358.421.1.91
    Dracopsi 131DZIBAN88901.4.5830.2F5IV-V174156.365+72855.930.114
    Dracopsi 13188911.5.7930.2G0V174157.951+72924.670.638
    Dracopsi 23489611.5.45F2-3II-III17551.11.25+72018.920.842
    Dracoome28175764.8.1472.3F5V173657.074+684528.660.548
    Draco2155675.2.14K0III11361.2.82+691922.431.2.31
    Draco3156065.3.14K3III114228.365+664441.521.2.14
    Draco4CQ340117158161.4.955.4.14M3IIIa12301.6.54+69121.4.281.2.64
    Draco676001.4.94K3III*123443.987+70118.521.3.13
    Draco7159021.5.43gK5124734.347+664725.321.2.21
    Draco8159411.5.24F0V125528.525+652618.411.2.53
    Draco9159601.5.32K2III125955.099+663550.321.2.79
    Draco10CU340121161991.4.521.4.6790.2M3III135125.915+644323.731.1.31
    Draco15171075A0III162759.001+68461.5.220.755
    Draco16300121.5.5390.3B9.5Vn16361.11.51+52540.531.1.63
    Draco17300135.8.1490.3B9V163613.742+525527.991.1.09
    Draco18171881.4.83K0III*164055.184+643520.531.1.28
    Draco19172811.4.89F6V16561.1.72+6585.2.141.1.32
    Draco20172853241.6.41141F1-3V165625.221+65220.591.1.35
    Draco26175461.5.230.6G0Va173459.531+615229.791.1.47
    Draco27175265.5.14163.4K0III173157.865+6886.12.140.477
    Draco30305915.2.140.1A2V17491.4.63+504651.751.1.75
    Draco3589395.4.14F6IV-V s174926.998+765746.190.34
    Draco36178285.3.14F5V181353.781+642350.191.1.67
    Draco37178371.5.95gK1181517.6.14+684521.1.141.1.76
    Draco39309491.4.983.8.14A1V182354.545+58481.2.341.1.38
    Draco4089946.4.1419.3.14F71801.3.62+8001.2.691.1.16
    Draco4189961.5.6819.3.14F71801.9.94+80014.561.1.19
    Draco42178881.4.82K1.5IIIFe-0.5182559.071+653348.611.1.45
    Draco45310391.4.77F7Ib183234.446+57244.541.1.74
    Draco46311195.4.14146.8B9.5pHg:184237.938+553222.12.141.2.19
    Draco48312841.5.66K1III185644.974+574853.151.1.27
    Draco49313231.5.48G5.5IIbFe-0.519043.372+553930.1.141.2.76
    Draco5092501.5.35A1Vn184622.176+75261.2.411.1.74
    Draco51313711.5.38A0Vn19455.172+532348.241.1.65
    Draco53314685.12.14G8III191140.567+5651331.1.67
    Draco54314971.4.99K2III191355.206+574218.2.141.2.22
    Draco55181871.6.25A0V19945.78+6558431.1.13
    Draco5993411.5.13A9V1991.9.75+763337.620.822
    Draco64186581.5.27193.8M1III-IIIb20128.543+644915.521.1.95
    Draco65186691.6.5796.8gG720220.273+64381.3.611.1.05
    Draco66187001.5.39K3III20532.855+615943.841.1.17
    Draco68187511.5.7593F5V201134.898+62443.41.1.87
    Draco6996066.2.14M3III195936.688+762852.860.898
    Draco71DE340128188071.5.72B9V201936.653+621526.821.1.57
    Draco73AF34006098021.5.151.5.22A0p(Sr-Cr-Eu)203130.433+745716.6.141.1.14
    Draco7434131.5.96209K0III+F8V202927.526+81528.621.1.82
    Draco7534081.5.46197.7G9III202814.371+812521.791.1.23
    Draco7634581.5.75A0V204235.183+823152.381.1.87
    Equuleusalp8KITALPHA1266621.3.920.1G0III+A5V211549.441+51452.221.2.16
    Equuleusbet101267491.5.1689.2A3V212253.629+64839.991.2.98
    Equuleusgam51265931.4.69352.5F0IIIp211020.546+10753.331.2.14
    Equuleusdel71266431.4.490.2F5V+G0V211428.853+10025.171.2.29
    Equuleuseps11264283441.5.23101F6IV20591.4.17+41737.031.2.93
    Equuleuslam23457.3.142.8.1421212+71001
    Equuleus31265181.5.6181.7K5III21434.663+5301.9.861.2.09
    Equuleus41265351.5.9434.9F8V21526.725+55729.571.3.69
    Equuleus61265976.7.14352.5A2V s211031.234+10256.031.2.96
    Equuleus91267191.5.82M2IIIa21211.4.99+72115.861.2.37
    EridanusalpACHERNAR232481130.46B3Vpe13742.925-57141.12.131.2.45
    Eridanusbet67CURSA131794391.2.79116.7A3III5750.969-551.11.171.2.86
    Eridanusgam34ZAURAK149283311.2.9552.8M0.5IIICa-1Cr-13581.1.73-133030.641.2.92
    Eridanusdel23RANA1306861.3.54K0+IV34314.916-94548.21.2.98
    Eridanuseps181305641.3.732K2V33255.854-92729.651.3.06
    Eridanuszet13ZIBAL1303874.8.14A5m31550.019-8491.10.971.2.35
    Eridanuseta3AZHA1301971.3.89K1-IIIbBa0.2:25625.651-85353.391.2.56
    Eridanusthe 1ACAMAR216113211.3.248.3.14A4III25815.691-401816.981.3.09
    Eridanusthe 22161141.4.358.3.14A1V25816.301-401816.252.2.14
    Eridanusiot2159994.11.14K0III24040.055-395119.351.2.25
    Eridanuskap2159061.4.25B5IV22659.162-474214.12.141.2.93
    Eridanuslam691318241.4.27B2IVne591.8.82-84514.751.2.21
    Eridanusmu571314684.2.14B5IV44530.145-31516.651.2.37
    Eridanusnu481313461.3.9350.9B2III43619.147-3211.8.841.2.14
    Eridanusxi421311761.5.17A2V42340.847-34443.621.2.52
    Eridanusomi 138BEID1310194.4.14F2II-III41151.936-65015.291.3.76
    Eridanusomi 240KEID1310631.4.4383.4K1-V41516.321-7391.9.891.2.42
    Eridanuspi261491581.4.42M2III3461.8.65-1266.1.142.3.14
    Eridanusrho 181302431.5.75K0II311.10.08-73946.481.2.86
    Eridanusrho 291302541.5.321.9.14K0II-III3242.305-7417.3.141.2.22
    Eridanusrho 3101302691.5.26A8V3416.422-7363.8.141.2.09
    Eridanustau 111485841.4.47F6V2451.6.63-183420.841.2.23
    Eridanustau 22ANGETENAR1680941.4.7546.7K0III2511.2.08-21014.591.2.86
    Eridanustau 3111682494.9.14A4IV3223.517-233727.941.2.28
    Eridanustau 4161684601.3.695.5.14M3.5IIIaCa-131931.002-214528.251.2.01
    Eridanustau 5191686341.4.27B8V+B8V33347.263-213758.361.2.97
    Eridanustau 6271688271.4.23F3III34650.874-231458.881.2.03
    Eridanustau 7281688361.5.24A234739.619-235228.921.2.51
    Eridanustau 8331689251.4.65B6V35342.632-243645.181.2.36
    Eridanustau 9361690171.4.66B6V+B9.5V35955.454-24059.081.3.38
    Eridanusups 1501695701.4.51K0IIICN-143330.628-294559.771.2.84
    Eridanusups 252THEEMIM1951481.3.82G8IIIa43533.064-303344.491.2.92
    Eridanusups 4411949021.3.560.2B9V41753.67-334754.221.2.54
    Eridanusphi2326961.3.5687.6B8V-IV21630.611-513044.181.2.38
    Eridanuschi2325733.7.144.8.14G8IIIbCNIV15557.496-513632.141.2.89
    Eridanuspsi651317001.4.81B3V5126.347-71026.8.141.2.48
    Eridanusome611315681.4.39F4III+A6III45253.672-5279.9.141.2.58
    Eridanus41681831.5.45A5V25723.72-235143.061.3.98
    Eridanus51302281.5.56B9.5V25941.106-22753.951.2.29
    Eridanus61681911.5.84K2III2581.5.63-233621.921.2.98
    Eridanus7CV3601221302426.1.14M2III3050.962-25243.351.3.24
    Eridanus141303951.6.14F1V31635.728-9916.411.3.21
    Eridanus151684521.4.880.2G6III31822.137-223040.531.2.59
    Eridanus171305281.4.73B9V s33037.052-5430.451.2.16
    Eridanus20EG3601511490631.5.231.5.32B9p(Si)33617.383-17281.1.351.2.41
    Eridanus211306341.5.96K1V3391.1.19-53734.021.2.93
    Eridanus221306521.5.53B9IIIpSi420034038.326-51238.81.2.15
    Eridanus241306981.5.25B7V34430.498-1947.131.2.92
    Eridanus251307041.5.55K4III34456.472-01747.861.2.35
    Eridanus301307891.5.488.3.14B8V35241.587-52140.881.2.36
    Eridanus321308051.6.146.8.14A2V35417.385-2571.9.531.2.92
    Eridanus321308062771.4.796.8.14G8III35417.517-25716.931.2.85
    Eridanus351308781.5.28B5V4132.034-13258.831.2.52
    Eridanus371310011.5.44G8III41022.494-65526.141.2.84
    Eridanus391494781.4.876.4.14K3III41423.684-101522.691.2.86
    Eridanus431949841.3.96K4III4241.2.07-3410.91.2.35
    Eridanus451312701.4.91K3II-III43152.698-0238.481.2.64
    Eridanus46EH3601521313091.5.721.2.14B9p(Si)43354.754-64420.191.2.69
    Eridanus47DV3601441313155.1.141.5.13M3III4341.11.97-81352.831.3.08
    Eridanus511313581.5.2380F0V43736.107-22824.431.2.12
    Eridanus53SCEPTRUM1497811.3.870.8K2IIIb4381.10.82-141814.581.2.09
    Eridanus54DM3601351498181.4.281.4.360.1M4III44026.49-194017.651.2.16
    Eridanus55DW3601451314421.6.829.3.14F4IIIp(Sr)44334.635-84737.491.2.93
    Eridanus551314436.7.149.3.14G8III44335.147-84745.81.3.49
    Eridanus56DX3601461314511.5.761.5.98B2Ve4441.5.04-83013.8.141.2.54
    Eridanus581498881.5.51G2.5V44736.3-16561.3.881.2.76
    Eridanus591499011.5.77F6V44832.498-161946.381.2.53
    Eridanus601499245.3.14K0III4501.11.87-16131.1.751.3.55
    Eridanus621316141.5.5167.3B6V45624.159-51017.261.2.61
    Eridanus631500601.5.38G4V45950.487-101547.991.2.83
    Eridanus64S3600021500641.4.774.8.14F0IV45955.764-123215.141.3.35
    Eridanus661317775.12.1452.8B9V+A1V5645.692-43917.521.2.24
    Eridanus681318135.12.14F2V5843.632-42722.131.2.76
    FornaxalpFORNACIS1683731.3.873.6.14F8V3121.4.68-285913.361.2.08
    Fornaxbet1939311.4.464.7.14K0-IIIFe-0.52491.5.62-322421.441.2.51
    Fornaxgam 11680811.6.1440.9K1III24951.008-243337.171.3.79
    Fornaxgam 21680821.5.39A0V24954.159-275630.351.2.87
    Fornaxdel1944675B5IV34214.923-315618.7.141.2.19
    Fornaxeps1682381.5.89G5IV3137.608-28528.511.2.59
    Fornaxzet1682091.5.71F2V25936.146-251626.721.2.11
    Fornaxeta 11939161.6.51K0-1III24733.703-35331.2.511.2.08
    Fornaxeta 21939401.5.925K0III25014.812-355037.111.3.36
    Fornaxeta 31939441.5.47K5III25040.416-354033.591.2.55
    Fornaxiot 11937951.5.75G8-K0III2361.9.63-30241.11.2.63
    Fornaxiot 21938291.5.83F4V23818.665-301139.851.2.82
    Fornaxkap1677365.2.14G0Va22232.569-234859.131.2.37
    Fornaxlam 11937635.9.14K0III2331.7.29-34390.011.2.33
    Fornaxlam 21938111.5.79G5IV23658.608-343441.641.2.56
    Fornaxmu1935731.5.28B9V21254.51-304325.851.2.88
    Fornaxnu1675321.4.69B9.5pSi2429.451-291748.81.2.44
    Fornaxpi1934551.5.35G5III2114.747-3001.6.431.2.31
    Fornaxrho1945351.5.54G6III34756.052-30105.6.141.2.08
    Fornaxsig1688205.9.145A3V34627.405-292016.611.2.42
    Fornaxtau1687016.1.14A0V33847.666-275634.691.3.45
    Fornaxphi1937231.5.14A2V2281.1.78-334839.511.2.67
    Fornaxchi 11942891.6.39A1IV32555.763-355515.221.3.34
    Fornaxchi 21943121.5.71K2III32733.368-354054.161.2.86
    Fornaxchi 31943186.5.146.3.14A1V3281.11.64-35511.11.891.2.76
    Fornaxpsi1939651.5.92F6IV25334.327-38261.12.622.7.14
    Fornaxome1678824.9.1410.8.14B9.5V23350.652-281357.161.2.62
    Geminialp 166CASTOR A60198781.1.982A1V73435.994+315318.541.3.14
    Geminialp 2CASTOR B792.9.14273436+3153191.3.17
    Geminibet78POLLUX79666811.1.14201.1K0IIIb74518.943+28134.281.2.69
    Geminigam24ALHENA95912641.1.93143.5A0IV63742.727+162357.41.2.82
    Geminidel55WASAT792941.3.530.2F2IV7201.7.66+215856.391.2.42
    Geminieps27MEBSUTA78682661.2.98110.3G8Ib64355.922+25751.891.2.84
    Geminizet43MEKBUDA790311.3.790.1F7-G3Ib741.6.21+20341.12.991.2.39
    Geminieta7PROPUS78135591.3.28M3III61452.649+223024.342.2.14
    Geminithe34595703.6.1478.7A3III65247.338+335740.381.2.53
    Geminiiot60793741.3.79G9IIIbHdel -172543.596+274753.041.2.01
    Geminikap77796531.3.577.1.14G8IIIa74426.855+242352.71.2.16
    Geminilam54967461.3.58A3V7181.5.61+163225.371.2.27
    Geminimu13TEJAT POSTERIOR78297611.2.88121.7M3IIIab62257.618+223048.771.2.12
    Gemininu18784231.4.150.2B6IIIe62857.784+201243.451.2.62
    Geminixi31ALZIRR960741.3.36F5III64517.36+125343.981.2.55
    Geminiomi71602474.9.14F3III7391.9.45+34351.3.911.2.87
    Geminipi80603401.5.1421M1IIIa74730.343+332456.521.2.86
    Geminirho62601181.4.18220.4F0V7291.6.71+31471.3.611.2.68
    Geminisig75796381.4.28182.2K1III74318.737+28530.521.2.84
    Geminitau46598581.4.411.9.14K2-III7111.8.68+301442.951.2.11
    Geminiups69795334.6.1446.1M0III-IIIb73555.342+265344.51.2.47
    Geminiphi83797741.4.97A3V75329.798+264556.741.2.45
    Geminichi798961.4.9478.6K1.5III8331.076+274739.521.2.79
    Geminiome42789991.5.18G5IIa-Ib7224.778+241255.541.2.96
    Gemini1779151.4.160.2G7III641.7.21+231548.061.2.81
    Gemini2779716.9.14K06648.648+233818.751.2.84
    Gemini3780501.5.750.7B2.5Ib6944.041+23648.421.2.19
    Gemini4780636.7.14B961029.911+225952.051.2.81
    Gemini5780795.8.14K0III61132.279+242512.6.142.8.14
    Gemini6BU380098780981.5.748.1.14M1-M2Ia-Iab61219.129+225430.491.2.28
    Gemini8781686.8.140.1G8III61619.4.14+235811.8.141.2.67
    Gemini9781761.6.25B3Ib61658.705+234427.241.2.14
    Gemini11LU380269782221.7.211.7.24B0II61919.306+23281.9.281.2.31
    Gemini12782257B961922.527+231627.841.2.72
    Gemini16784021.6.22A2V s62756.644+202946.051.2.73
    Gemini19957786.4.14A8V63137.374+15541.12.341.2.53
    Gemini25786361.6.4255.9G5Ib64120.96+281147.161.2.25
    Gemini26960151.5.21A2V64224.32+173842.951.2.99
    Gemini28786921.5.44K4III64445.433+285815.151.2.72
    Gemini30960511.4.4927.2.14K0IIICN1Ca164359.293+131340.351.2.42
    Gemini32960841.6.46A9III64554.212+124137.11.2.81
    Gemini33OV380309961611.5.8527.5.14B7III64949.821+16121.10.441.2.61
    Gemini35961791.5.65gK365025.478+132447.771.2.78
    Gemini36788051.5.2711.3.14A2V65133.015+214540.411.2.77
    Gemini37788661.5.73G0V65518.646+252232.211.2.02
    Gemini38962651.4.657F0Vp65438.682+131039.921.2.91
    Gemini39789296.1.1428.8.14F7V65847.371+26451.911.2.46
    Gemini40789476.4.14B8III65927.913+255451.061.2.82
    Gemini41963631.5.68K3Ib7015.788+16444.231.2.59
    Gemini44790426.2.14B8Vn7518.352+223814.491.2.99
    Gemini45965351.5.4410.4.14G8III7822.2.14+155550.681.2.51
    Gemini47791411.5.78A4IV71123.052+265123.221.2.79
    Gemini48791621.5.85F5III-IV71226.359+24742.441.2.06
    Gemini49791726.9.14A071249.339+254454.541.2.37
    Gemini51BQ380094966381.6.637.2.14149.2M4IIIab71322.275+16932.291.2.61
    Gemini52791991.5.8223.9.14M1III71441.944+24531.5.681.2.88
    Gemini53792211.5.71M1IIIa71557.144+275351.061.2.91
    Gemini56793285.1.1416.5.14M0IIIab72156.828+202636.751.2.41
    Gemini57793525.3.14G8III72328.499+2531.2.441.2.25
    Gemini58793546.2.14A1V72328.18+225643.281.2.64
    Gemini59793661.5.76g:F072433.436+273816.611.2.75
    Gemini61793911.5.93F2Vn72656.281+201526.341.2.16
    Gemini63794031.5.22F5V+F5V72744.358+212642.452.11.14
    Gemini64794275.5.14A4V72920.397+2871.5.471.2.01
    Gemini65794345.1.1412.8.14K2III72948.737+275458.161.2.84
    Gemini68970161.5.250.2A1Vn73336.471+154935.921.2.55
    Gemini70602431.5.56159.9K0III73832.844+35254.921.2.13
    Gemini74971205.5.14K5IIIFe-0.573928.607+174028.711.2.04
    Gemini76796501.5.31K4-5III7441.6.58+25471.3.431.2.15
    Gemini79796651.6.33A1V7451.9.91+201858.541.2.23
    Gemini81972211.4.880.1K4III-IIIb7461.7.61+183036.071.2.93
    Gemini82797041.6.180.3G2III+A4V74833.637+23828.321.2.55
    Gemini85797991.5.35A0V s75539.876+19531.2.311.2.69
    GrusalpALNAIR2309922421.1.7428.4.14B7IV22814.012-465739.81.2.38
    Grusbet2312582442.1.14M5III224240.067-46531.4.921.2.16
    Grusgam2133742403.1.14B8III215355.744-372153.481.3.38
    Grusdel 12311541.3.975.6.14G6-8III222916.196-432944.331.2.06
    Grusdel 22311614.11.1460.6M4.5IIIa222945.484-434457.541.2.89
    Gruseps2475931.3.49A3V224833.296-51190.521.2.27
    Gruszet2476804.12.14G8-K0III23052.834-524514.781.2.34
    Gruseta2475701.4.8524.4.14K2IIICNIV224537.904-53300.161.2.69
    Grusthe2314441.4.281.2.14F5mDel Del23652.818-433114.6.141.2.34
    Grusiot2314683.9.14K1III231021.57-451447.891.2.77
    Gruskap2477111.5.37K5III23439.593-535754.711.3.96
    Gruslam2135431.4.46K3III2261.6.32-393235.731.3.73
    Grusmu 12310551.4.79G8III+G221536.978-412047.861.2.46
    Grusmu 22310635.1.14G8III221626.648-413738.571.2.88
    Grusnu2138501.5.4727.3.14G9III222839.203-39754.941.3.03
    Grusxi2307261.5.29K0III21321.5.47-411046.21.2.52
    Grusomi2478741.5.52F4V232636.52-524317.731.2.43
    Gruspi 12311051.6.622.7.14S5,7e222243.927-455652.121.3.89
    Gruspi 22311111.5.624.9.14F3III-IV22231.7.94-455541.751.3.27
    Grusrho2312651.4.8514.2.14K0III224330.084-412451.671.2.66
    Grussig 12312111.6.28A3Vn223629.275-403457.721.2.54
    Grussig 22312171.5.862.8.14A1V223658.782-403528.141.2.47
    Grustau 12313436.4.14G0V225337.913-483553.311.2.16
    Grustau 32313645.7.14Am225647.759-47581.8.911.3.61
    Grusups2143131.5.611.1.14A1V23653.638-385331.591.2.24
    Grusphi2315391.5.53F5V23181.9.28-404928.281.2.38
    Herculesalp 164RASALGETHI1026801901.3.484.9.14M5Ib-II171438.882+142325.251.2.53
    Herculesalp 2641026813271.5.394.9.14G5III+F2V171439.219+142324.9.141.2.33
    Herculesbet27KORNEPHOROS844111781.2.77256.2G7IIIa163013.2.14+212922.491.2.33
    Herculesgam201021071.3.7541.6A9III162155.217+1991.11.331.2.11
    Herculesdel65SARIN849511911.3.148.5.14A3IV17151.1.12+245021.221.2.03
    Herculeseps58657161.3.92A0V17017.386+305535.281.2.82
    Herculeszet40654851811.2.81111.1.14G0IV164117.216+313610.6.141.2.11
    Herculeseta44655041.3.53113.5G7.5IIIbFe-1164253.778+385520.5.141.2.68
    Herculesthe91664851.3.86K1IIaCN+2175615.194+37151.1.961.2.99
    Herculesiot85468723.8.14116B3IV173927.894+46022.832.1.14
    Herculeskap 17MARFIK101951528.1.14G8III1681.4.54+17248.921.2.43
    Herculeskap 271019521.6.2528.1.14K1III1681.4.12+17316.141.2.44
    Herculeslam76MAASYM851631.4.41K3.5III173044.313+26638.51.2.09
    Herculesmu86853971.3.4233.8G5IV174627.574+274314.6.141.2.04
    Herculesnu94665241.4.41F2II175830.172+301121.971.2.69
    Herculesxi92855903.7.14G8+III175745.911+291452.531.2.81
    Herculesomi103857501.3.83B9.5V18732.554+284545.041.2.66
    Herculespi67658901921.3.16K3IIab17151.2.84+364833.111.2.47
    Herculesrho 175660013281.4.524.2.14B9.5III172340.983+37845.491.2.59
    Herculesrho 275660001.5.474.2.14A0Vn172340.675+37848.211.2.78
    Herculessig35461614.2.140.1B9V16341.6.97+422613.331.1.65
    Herculestau22460281.3.896.7.14B5IV161944.444+461848.141.1.28
    Herculesups6458651.4.76B9III16247.905+4621.12.441.1.87
    Herculesphi11459111.4.26B9p:Mn:16846.184+44561.5.691.1.49
    Herculeschi1457721.4.62F8VFe-2Hdel -1155240.531+42271.5.751.2.35
    Herculesome24KAJAM1021531.4.5728.4.14B9pCr162524.967+14159.681.2.42
    Hercules2457881.5.37M3IIIBa0.3155437.861+43818.691.2.85
    Hercules4457901.5.75B9pe155530.572+4233581.2.43
    Hercules51018795.12.14G8IIIbFe-0.516114.289+17491.5.961.2.74
    Hercules81019621.6.14A0Vnn16846.616+171220.781.2.77
    Hercules91214311.5.48gK5161315.475+5115.631.2.81
    Hercules10LQ400265842401.5.581.5.83M4IIIa161137.97+232941.131.2.12
    Hercules161020401.5.69K3III161528.673+184829.821.2.24
    Hercules211215681.5.85A2pSr:16241.10.25+65653.551.2.08
    Hercules25652901.5.540.2A5V162524.129+372338.711.2.63
    Hercules281216761.5.63B9.5III163235.709+53116.391.2.94
    Hercules291022341.4.84K7III163236.306+112916.841.2.95
    Hercules30G409107461085.4.14M6-III162838.521+415254.51.1.33
    Hercules34461281.6.45A1V16301.6.44+485739.341.1.55
    Hercules361217741.6.9369.6A3IV164035.13+41225.741.2.15
    Hercules371217761.5.7769.6A1V164038.676+4131.10.991.2.75
    Hercules39845431.5.920.1F2III164136.695+26550.621.2.74
    Hercules42462104.9.1425.6.14M2.5IIIab163844.869+485542.381.1.52
    Hercules431218431.5.1582.5K5III164549.898+83457.431.2.75
    Hercules451218651.5.24122.7B9pCr:164746.411+51448.291.2.61
    Hercules471218951.5.49A3m165019.384+71451.511.2.85
    Hercules49V08231024356.4.14B9.5pCr:16521.4.52+145827.8.141.2.59
    Hercules50846411.5.72M1IIIa165038.966+294823.661.2.77
    Hercules51846515.4.14K0.5IIIaCa0.5165145.281+243923.2.141.2.52
    Hercules52V0637400637463051.4.781.4.851.8.14A3Vp(Sr-Cr-Eu)164914.249+455859.821.1.62
    Hercules53656271.5.3270.9F0-2V165258.044+31421.5.951.2.13
    Hercules541024761.5.352.5.14K4III165522.204+182559.851.2.51
    Hercules56846926.8.1417.9.14G5III16551.2.19+254350.261.2.35
    Hercules57847201.6.28gG5165731.021+25211.9.821.2.76
    Hercules59657361.5.25A3IV17136.355+33341.5.741.2.91
    Hercules601025841.4.9156A4IV17522.695+124427.12.141.2.12
    Hercules61657611.6.69M4IIIab17330.237+352451.331.2.63
    Hercules63V0620400620848961.6.191.6.23A8V17111.3.16+241415.921.2.03
    Hercules68u659131.4.8213.4.144.4.14B1.5Vp+B5III171719.542+3360.471.2.86
    Hercules69659211.4.65A2V171740.308+371729.571.2.35
    Hercules70850215.12.14222.9A2V172054.184+242958.291.2.46
    Hercules72659631.5.39230G0V172039.563+32281.3.861.2.91
    Hercules73850621.5.74F0IV17241.6.99+225736.641.2.78
    Hercules74466451.5.59M0III172021.127+461427.351.1.36
    Hercules77467231.5.85A4V172644.248+481536.271.1.33
    Hercules78851821.5.62A1V173149.56+282427.11.141.2.32
    Hercules79852641.5.770.1A2Vn173731.1.14+241835.651.2.05
    Hercules82468381.5.37gK1173637.647+48351.8.461.1.19
    Hercules83853441.5.52159.6K4III174228.362+243350.491.2.97
    Hercules84853601.5.71G2IIIb174321.561+241939.881.2.14
    Hercules87854375.12.14K2III174849.147+253722.151.2.16
    Hercules88V0744400744469971.6.651.6.94B7Vne17501.3.36+4823391.1.67
    Hercules89V0441400441855451.5.341.5.54F2Ibe175525.189+2630.081.2.97
    Hercules90470371.5.161.6.14K1IIIbCN-1175318.6.14+40028.661.1.89
    Hercules931032851.4.67K0.5IIb1801.3.24+16451.3.221.2.57
    Hercules95856471.5.186.3.14G8III18129.926+213542.691.2.81
    Hercules95856483291.4.966.3.14A5IIIn18130.429+213544.21.2.09
    Hercules96856721.5.28B3IV18223.092+20500.851.2.53
    Hercules97856761.6.21B3Vn18230.127+225523.351.2.88
    Hercules98857255.6.14M3-IIIZrO 0+1861.1.13+22131.7.691.2.23
    Hercules99666485.4.141.7.14F7V1871.1.17+303343.121.2.85
    Hercules100857525.9.1414.3.14A3V18749.532+26550.541.2.27
    Hercules100857531.5.8614.3.14A3V18749.542+2661.4.971.2.62
    Hercules101857705.1.14A8III18852.859+20242.891.2.27
    Hercules102857691.4.3623.4.14B2IV18845.528+204852.11.2.35
    Hercules104V0669400669667371.6.62M3III181154.191+312418.871.2.67
    Hercules105859211.5.27K3III:Ba0.418191.10.03+242645.311.2.78
    Hercules106859411.4.95M1III182017.906+215740.891.2.69
    Hercules107859575.12.14A7V18211.1.24+28521.11.961.2.55
    Hercules108859561.5.63A5m182057.062+295132.491.2.29
    Hercules109860031.3.84221.8K2.5IIIab182341.889+214611.2.141.2.41
    Hercules110864061.4.1963.8F6V184539.723+203246.781.3.33
    Hercules1111040931.4.36121.3A5III18471.1.72+181053.31.2.82
    Hercules112865211.5.48B9II-IIIpHg185216.44+212530.551.2.94
    Hercules113865671.4.5935.7G4III+A6V185444.898+223842.731.2.36
    Horologiumalp2167101.3.86K1III4140.122-421740.181.1.83
    Horologiumbet2487011.4.99A3-5IIIm:25847.74-64415.731.2.71
    Horologiumgam2486421.5.7420G8III-IV24527.497-634216.191.2.11
    Horologiumdel2166821.4.93A9V41050.588-415936.821.2.88
    Horologiumzet2328571.5.21F4IV24039.677-543259.751.2.66
    Horologiumeta2328351.5.31A6V23724.234-523235.331.1.64
    Horologiumiot2328641.5.41G0V24233.452-50480.761.2.61
    Horologiumlam2485551.5.35F2III22453.942-601843.061.1.62
    Horologiummu2329815.11.14F0IV3336.844-594415.871.1.17
    Horologiumnu2486561.5.26A2V2491.1.72-624823.631.1.96
    Hydraalp30ALPHARD136871951.1.98283.1K3II-III92735.254-83931.171.2.54
    Hydrabet2029011.4.280.8B9IIIpSi115254.56-335428.591.2.83
    Hydragam461815431353138.4G8-IIIa131855.306-231017.631.2.42
    Hydradel41169651.4.16243.7A1Vnn83739.379+54213.311.2.53
    Hydraeps111171121.3.380.2G5III84646.587+6251.7.531.2.65
    Hydrazet16117264883.11.14G9II-III85523.629+55643.81.2.92
    Hydraeta71170504.3.14B3V84313.482+32354.941.2.72
    Hydrathe221175271.3.8827.1.14B9.5V91421.88+21851.231.2.74
    Hydraiot351370351.3.91K2.5III-IIIbBa0.393951.369-1834.471.2.74
    Hydrakap381553885.6.14B5V94018.361-141956.331.2.91
    Hydralam411557851.3.61112.2K0IIICN1101035.285-122114.751.2.32
    Hydramu421559801.3.81K4.5III10261.5.31-16501.10.651.2.64
    Hydranu1562561073.11.14K2III104937.497-161137.161.2.05
    Hydraxi2025581.3.5468.2G7III11330.137-315127.331.2.85
    Hydraomi2026954.7.14B9V11401.12.98-344440.711.2.23
    Hydrapi491822441451.3.27K2-III-IIIbFe-0.514622.294-264056.581.2.74
    Hydrarho131171461.4.3612.4.14A0Vn84825.975+55015.661.2.07
    Hydrasig5MINCHIR1169881.4.44K1+III83845.454+32028.941.2.12
    Hydratau 1311368954.6.1465.7F6V9291.8.84-2461.8.221.2.25
    Hydratau 2321369321.4.57A3V93158.934-1111.5.571.2.35
    Hydraups 1391555424.12.14G7-III95128.711-145047.731.2.87
    Hydraups 2401557134.6.14B9III-IV1051.7.72-13353.131.2.87
    Hydraphi 21560936.3.143.4.14M1III103616.687-162040.091.2.97
    Hydraphi 31561221.4.91G8IIIFe-0.5103834.948-165235.891.2.66
    Hydrachi 11795141.4.940.2F3IV11519.92-271736.621.3.05
    Hydrachi 21795221.5.71A0IV11557.554-271716.181.2.04
    Hydrapsi451814101.4.95K1III1391.3.76-2375.9.141.2.82
    Hydraome181174201.4.97K2II-III9558.381+5532.451.2.36
    Hydra11358771.5.61F3V82435.023-3451.4.241.2.57
    Hydra2LM4202611359161.5.5972.8A5III-IV82627.179-35914.881.2.06
    Hydra3HV4202221360761.5.661.5.76A2p(Sr-Cr-Eu)83528.168-75855.841.2.43
    Hydra61545151.4.98K4III8401.1.52-122831.411.2.11
    Hydra91545521.4.8831G9.5III84143.302-155635.851.2.54
    Hydra101170881.6.13A6V8451.1.82+54050.021.2.26
    Hydra121546221.4.3219.9.14G8-IIIFe-184622.527-133251.771.2.35
    Hydra14KX4202571363081.5.31B9p(Hg-Mn)84921.724-32634.981.2.67
    Hydra151363451.5.540.9A4m85134.456-71037.651.2.64
    Hydra171364081.6.914.1.14A7m85529.52-75813.4.141.2.39
    Hydra171364091.6.674.1.14A2m85529.559-75815.961.2.05
    Hydra191366045.6.141B9.5III9842.153-83522.821.2.67
    Hydra201366221.5.46G8II9935.544-84715.981.2.98
    Hydra21KW4202561366626.11.141.6.58A3mIII:+A0V:91226.048-7635.211.2.46
    Hydra231367251.5.241.6.14K2III91641.72-6211.11.211.2.37
    Hydra241367281.5.47B9III91641.336-84440.971.2.55
    Hydra261550961.4.793.4.14G8III91946.418-115829.821.2.51
    Hydra271367684.8.14231.8G8III-IV+F5V92029.016-93320.761.2.28
    Hydra281368321.5.59K5III92524.028-573.8.141.2.08
    Hydra291368611.6.540.3A2V92714.56-91325.231.2.73
    Hydra331369641.5.56K1III93432.628-55453.431.2.16
    Hydra341370116.4.14A1V93751.472-92528.371.2.07
    Hydra371553771.6.31A0Vn93947.37-10341.12.781.2.85
    Hydra441789795.8.1419.1.14K4III10340.883-234442.631.2.24
    Hydra471821341.5.15B8VpShell135831.155-245819.851.2.08
    Hydra481821521.5.77F7V1400.093-25037.571.2.57
    Hydra501823495.8.14K3III141246.025-271540.341.2.28
    Hydra511824831.4.77K4III14231.5.26-274514.181.2.68
    Hydra521825701.4.970.1B8V14281.10.19-292929.811.2.52
    Hydra541828551.4.948.5.14F2III-IV14460.057-252635.251.2.56
    Hydra551828751.5.63A0IIIp144722.545-253727.691.2.76
    Hydra561828821.5.24G5III144744.818-26514.8.141.2.18
    Hydra571828831.5.77B9V144757.513-263846.571.2.89
    Hydra581829111.4.41K4III145017.306-275737.391.2.57
    Hydra591830581.5.650.4A4V+A6V145839.245-273926.181.2.45
    Hydra601830991.5.85A4IV1526.5.14-28338.571.2.49
    HydrusalpHEAD OF HYDRUS248474151.2.86F0V15846.229-61341.11.411.1.55
    Hydrusbet25567042.8.14G2IV02545.217-771515.631.2.42
    Hydrusgam256029281.3.24M2III34714.381-741420.260.891
    Hydrusdel2485454.9.14A3V22144.995-683933.51.1.07
    Hydruseps2486214.11.14B9V23935.421-68160.31.2.05
    Hydruszet2486441.4.84A2IV-V24532.598-673659.971.1.24
    Hydruseta 22484601.4.69G8.5III15456.075-673850.121.1.47
    Hydrusthe2559451.5.530.1B3V+A0IV3215.438-71541.8.671.2.47
    Hydrusiot2559731.5.52F4III31557.65-772318.610.804
    HydruskapSMC2558805.1.14K1III22252.232-733844.921.1.39
    Hydruslam2557105.7.14K5III04835.362-745524.171.2.03
    Hydrusmu2558981.5.28G8III23140.538-79633.371.1.45
    Hydrusnu2559291.4.75K3III25028.552-7540.341.1.04
    Hydruspi 12485181.5.55M1III21414.745-675030.151.1.58
    Hydruspi 22485211.5.69K2III21528.517-674447.221.1.57
    Hydrussig2558351.6.16F5-6IV-V15550.356-782055.421.1.27
    Hydrustau 12558061.6.3316G6-8III14121.266-79854.441.1.11
    Hydrustau 22582806.6.1439.7F0IV14746.544-801036.121.1.36
    Indusalp2303002313.11.1466K0IIICNIII-IV203734.058-471729.351.3.51
    Indusbet2467841.3.6517.3.14K1II205448.61-582714.981.3.41
    Indusgam2470316.12.14F1III212615.487-543937.571.4.08
    Indusdel2472444.4.140.1F0IV215755.115-545933.631.4.44
    Induseps2472871.4.69K4-5V22321.561-56471.9.621.3.93
    Induszet2303911.4.89K5III204929.039-461336.861.3.42
    Induseta2467091.4.51A7III-IV-A920441.2.49-515515.741.3.62
    Industhe2469651.4.396.1.14A5V211951.983-532658.511.4.25
    Indusiot2467625.5.14K1II-III205130.103-513630.131.3.61
    Induskap 1BG4400852472476.12.14F3V215830.012-59044.791.3.21
    Induskap 22473031.5.62K4III22550.929-593810.2.141.3.24
    Indusmu2468541.5.16K2III21514.175-544337.111.3.04
    Indusnu2580331.5.290.1A3V:+F9V222436.826-721519.711.3.76
    Indusomi2550871.5.53K2-3III215047.164-693746.371.3.85
    Induspi2472301.6.19Am215614.014-575358.141.3.52
    Indusrho2580846.5.14G2-3IV225439.475-70425.491.3.11
    Lacertaalp7345421.3.7736.3A1V223117.494+501657.091.2.57
    Lacertabet3343951.4.43G8.5IIIbCa1222333.619+521344.491.2.16
    Lacerta1721911.4.13K3-II-III221558.204+374455.781.2.15
    Lacerta2519041.4.5748.2B6V22211.1.59+46321.11.921.2.74
    Lacerta4519701.4.57B9Iab222430.959+492835.031.2.01
    Lacerta5520551.4.36M0II+B8V222931.912+474224.631.3.95
    Lacerta6520791.4.51B2IV223029.24+43724.561.2.06
    Lacerta8725091.5.7322.4.14B2Ve223552.336+39381.3.491.2.37
    Lacerta9346281.4.63A8IV223722.403+513242.691.2.96
    Lacerta10725751.4.8862.2O9V223915.692+3931.6.141.3.95
    Lacerta11522511.4.46K2+III-IIIb224030.856+441634.781.2.75
    Lacerta12DD450127726271.5.161.5.2869B1.5III224128.609+401331.921.2.17
    Lacerta13523175.8.1414.6.14K0III22441.5.89+41491.9.251.2.38
    Lacerta14V0360450360524121.5.911.5.981B3IV:eaV225021.799+41571.12.521.2.32
    Lacerta15524361.4.94104.4M0III22521.2.43+431845.111.2.21
    Lacerta16EN450157525121.5.4162.1B2IV225623.609+413614.281.3.55
    Leoalp32REGULUS989671001.1.35177.6B7V10822.317+11582.2.141.2.79
    Leobet94DENEBOLA998091141.2.14264A3V11491.3.82+143419.4.141.2.13
    Leogam 141ALGIEBA812981021.2.614.5.14K1-IIIbFe-0.5101958.346+195029.931.2.34
    Leogam 241812992963.8.144.5.14G7IIIFe-1101958.646+195025.651.2.96
    Leodel68ZOSMA817271111.2.56191.4A4V11141.6.98+203125.261.2.58
    Leoeps17RAS ELASED AUSTRALIS81004981.2.98G1II94551.073+234627.211.2.05
    Leozet36ADHAFERA812651.3.44325.9F0III101641.406+23251.2.191.2.52
    Leoeta30989551.3.520.1A0Ib10719.951+164545.51.2.98
    Leothe70CHERTAN995121121.3.34A2V111414.403+152546.421.2.11
    Leoiot78995871.3.941.1.14F4IV112355.494+103144.921.2.84
    Leokap1AL MINILIAR AL ASAD808071.4.462.5.14K2III92439.257+261056.411.2.15
    Leolam4ALTERF808851.4.31K5III93143.198+22581.4.482.8.14
    Leomu24RASALAS810641.3.88K2IIICN1Ca195245.819+26024.961.2.49
    Leonu27988761.5.26B9IV95813.369+122641.151.2.63
    Leoxi5986271.4.97K0-III-IIIb93156.749+111759.271.2.87
    Leoomi14SUBRA987091.3.52F6II+A1-5V9419.4.14+95332.291.2.07
    Leopi291180444.7.14M2-IIIab1001.12.08+8239.131.2.29
    Leorho471183551.3.85B1Ib103248.666+91823.721.2.02
    Leosig771188044.5.14B9.5V s11211.8.89+6145.641.2.61
    Leotau841188751.4.9591.1G7.5IIIa112756.252+25122.231.2.96
    Leoups911382984.3.140.1G8.5IIICN-0.5113656.941-04925.681.2.76
    Leophi741381021.4.4796.9A7IVn111639.702-3391.5.921.2.27
    Leochi631186481.4.63276.4F2III-IV1151.1.37+7201.9.661.2.65
    Leopsi16987331.5.35281.8M2IIIab94343.9+14118.12.141.2.99
    Leoome21177171.5.410.5F9V92827.455+9324.451.2.93
    Leo31177181.5.7125.2.14K0III92829.142+81117.511.2.04
    Leo61177515.7.1437.3K2.5IIIbFe-0.593157.604+94256.71.2.02
    Leo7986621.6.3641.2A1V93552.923+142246.511.2.42
    Leo8986731.5.69gK19371.2.98+162616.631.2.64
    Leo101178075K1III9371.12.86+6501.8.721.2.76
    Leo13809701.6.24gK294138.503+255446.131.2.36
    Leo15616561.5.64A2IV94333.255+295828.8.141.2.61
    Leo18987551.5.63gK494623.316+114835.881.2.57
    Leo19987671.6.45A7Vn94725.93+11341.5.751.2.84
    Leo20DG460130810356.8.146.12.140.3A8IV94950.086+211046.031.2.32
    Leo22810541.5.32A5IV95153.019+242342.981.2.73
    Leo23988091.6.46M0III9511.2.39+13358.261.2.51
    Leo31989641.4.377.9.14K3.5IIIbFe-110754.269+95951.341.2.71
    Leo34989911.6.440.2F7V101138.23+132118.411.2.76
    Leo35812601.5.97G1.5IV-V101632.254+233011.9.141.2.72
    Leo37990341.5.41M1.5IIIab101640.744+134341.941.2.07
    Leo39812701.5.827.6.14F8Vb w101714.572+23622.261.2.69
    Leo40990651.4.79F6IV101944.133+192815.281.2.49
    Leo42990806.12.14A1V102150.274+145832.291.2.61
    Leo431182696.7.14K3III10230.432+63233.271.2.55
    Leo44DE4601281182865.6.14M2IIIabS102515.191+8475.5.141.2.99
    Leo45CX460124991361.5.971.6.1537.2A0p(Si-Cr-Sr)102738.977+94545.331.2.55
    Leo46991721.5.46M1.5IIIbCa-110321.11.81+14813.931.2.54
    Leo481183765.8.14G8.5IIIFe-1Ca-1103447.996+65713.791.3.08
    Leo49TX4600311183801.5.661.5.75A2V10351.2.57+8391.1.141.2.39
    Leo51992811.5.49gK3104624.533+185329.481.2.89
    Leo52992821.5.48gG4104625.269+141140.741.2.39
    Leo53993051.5.34A2V104915.426+103242.751.2.71
    Leo54815834.5.146.5.14A1V105536.809+244459.031.2.02
    Leo54815846.3.146.5.14A2Vn105537.26+244455.631.2.16
    Leo551185741.5.91F2/3III/V105542.441+0441.12.811.2.19
    Leo56VY4600431185761.5.696.3.14M5.5III10561.1.77+6117.6.141.2.72
    Leo581186101.4.840.1K1IIICN-0.511033.65+3371.2.831.2.13
    Leo591186151.4.9944.8A5III11044.817+661.4.851.2.06
    Leo60816371.4.42A1m11219.762+201046.941.2.49
    Leo611379471.4.74M0IIIBa0.211149.706-2291.4.351.2.28
    Leo621186341.5.95K3III11336.622-001.3.171.2.56
    Leo64816811.6.46A5m11739.708+231925.351.2.57
    Leo651186681.5.522.2.14G9IIICN-111654.22+15719.891.2.76
    Leo67816921.5.684.8.14A3IV11849.075+243930.551.2.25
    Leo691187311.5.42A0V111345.575-041.10.931.2.01
    Leo72817361.4.63M3IIb11151.12.39+23543.811.2.77
    Leo73995251.5.32K3III111551.882+131827.341.3.05
    Leo751187641.5.18M0III-IIIb111717.399+2037.61.2.79
    Leo761187781.5.91gK0111854.961+1391.1.521.2.74
    Leo791188311.5.39G8IIICN-0.511241.2.96+12428.271.2.17
    Leo801188511.6.37F3IV112550.035+35135.911.2.41
    Leo81996011.5.5755.7F2V112536.342+162723.471.2.22
    Leo831188646.5.1428.5.14K0IV112645.347+3047.161.2.47
    Leo85996291.5.74gK4112941.857+152447.961.2.72
    Leo86996371.5.52K0III113029.026+182434.781.2.95
    Leo871382381.4.77K3.5IIIFe-1113018.892-301.12.611.2.31
    Leo88996486.2.1415.5.14G0V113144.927+142152.231.2.36
    Leo891189291.5.77F5V113421.956+3336.521.2.52
    Leo90996731.5.953.6.14B4V113442.471+164749.371.2.24
    Leo92819411.5.26K1III114047.071+21211.10.321.2.73
    Leo93DQ819981.4.5374.3G5III-IVe+A7V114759.118+20131.8.171.2.83
    Leo95998691.5.5390A3V115540.532+153848.321.2.42
    Leo Minorbet31620531.4.210.5G9IIIab102753.009+364226.2.141.2.94
    Leo Minor7615291.5.8562.8gG893043.229+333920.821.2.29
    Leo Minor8615401.5.37M1IIIab93132.394+3561.11.171.2.07
    Leo Minor9615611.6.18gK493330.29+36291.12.881.2.81
    Leo Minor10SU470021615701.4.54G8.5III93413.383+362351.221.2.35
    Leo Minor11SV470022615861.5.413.3.14G8V93539.598+354836.691.2.25
    Leo Minor13616481.6.14F3V94242.774+35536.51.2.22
    Leo Minor19431151.5.14F6V s95741.043+41320.351.2.86
    Leo Minor20618081.5.36407G3VaHdel 11010.672+315525.4.141.2.09
    Leo Minor21618741.4.48A7V10725.754+351441.21.2.59
    Leo Minor22619531.6.46G8III10151.6.41+31281.5.241.2.87
    Leo Minor23812581.5.35A0Vn101614.411+291837.731.2.29
    Leo Minor24812591.6.49G0V101628.133+284056.781.2.34
    Leo Minor27620105.9.14A6V10231.6.39+335429.151.2.63
    Leo Minor28620195.5.14gK110241.8.65+33431.6.641.2.44
    Leo Minor30620381.4.74F0V102554.858+334745.781.2.25
    Leo Minor32620761.5.77A4V10301.6.34+385530.841.2.59
    Leo Minor33621015.9.1443.3A0IV103151.353+322246.161.2.48
    Leo Minor34621211.5.58A2Vn103330.907+345918.941.2.45
    Leo Minor35621471.6.28F3V103621.419+361936.51.2.87
    Leo Minor37621731.4.71G2.5IIa103843.227+315834.281.2.39
    Leo Minor38621781.5.85F9V10391.7.44+375436.751.2.37
    Leo Minor40814851.5.5118.4.14A4Vn10431.1.39+261931.861.2.04
    Leo Minor41814905.8.14A3Vn104324.946+231118.221.2.57
    Leo Minor42622361.5.24198.1A1Vn104551.892+304056.231.2.74
    Leo Minor43815331.6.15sgK1104857.176+292457.381.2.94
    Leo Minor44815426.4.14F3V104953.761+275826.361.2.79
    Leo Minor46PRAECIPUA622971.3.83K0+III-IV105318.696+341253.571.2.76
    Leo Minor48815766.2.14A8V105442.171+252926.791.2.82
    Leo Minor50815911.6.35K0105634.426+253001.2.06
    Lepusalp11ARNEB150547481.2.5835.8F0Ib53243.799-174920.241.3.23
    Lepusbet9NIHAL170457461.2.842.6.14G5II52814.725-204534.281.3.38
    Lepusgam131707593.6.1496.5F6V54427.801-222654.361.3.47
    Lepusdel151709261.3.81K0IIIFe-1.5CH0.555119.28-2052451.3.85
    Lepuseps2170051371.3.19K5III5527.645-222215.561.3.04
    Lepuszet141508011.3.55A3Vn54657.325-144919.221.2.28
    Lepuseta161509571.3.71F1III55624.283-141041.2.71
    Lepusthe181511101.4.67A1Vn661.9.43-14561.6.551.2.38
    Lepusiot31502231.4.4512.7.14B8V51217.887-11521.8.531.2.16
    Lepuskap41502391.4.362.6.14B9V51313.876-125629.471.2.21
    Lepuslam61503401.4.29B0.5IV51934.506-131036.371.2.73
    Lepusmu5150237401.3.31B9IIIpHgMn51255.867-161219.991.3.41
    Lepusnu71503455.3.14B7IVnn51959.058-121855.971.2.63
    Lepus11700101.5.75K1IV5244.947-224741.551.2.91
    Lepus81503961.5.25B2IV52330.158-135537.91.2.85
    Lepus101705061.5.55A0V5311.7.02-205149.421.3.13
    Lepus121707151.5.87A254213.927-222224.711.2.55
    Lepus17SS4800191510931.4.825.6.14A0Veq+M1III6459.115-16293.6.141.2.79
    Lepus191511421.5.31M2III6741.621-19957.341.2.06
    Libraalp 19ZUBEN ELGENUBI1588401551.2.75A3IV145052.719-16230.391.2.38
    Libraalp 281588361.5.15F4IV145041.206-155950.321.2.07
    Librabet27ZUBEN ESCHAMALI1404301601.2.61B8V15170.43-92258.531.2.08
    Libragam38ZUBEN HAKRIKI1593701.3.910.1G8.5III153531.582-144722.5.141.2.92
    Libradel19ZUBEN ELAKRIBI1402701.4.92106.3B9.5V15058.353-8311.8.271.2.92
    Libraeps311592341.4.94F5IV15241.11.03-101920.261.2.95
    Librazet 1321592801.5.64K5III152815.417-164259.371.2.54
    Librazet 3341593071.5.82gG6153040.373-163634.021.2.38
    Librazet 4351593355.5.14B2Vn153255.231-165110.5.141.2.13
    Libraeta441594661.5.41F0IV15441.4.12-154022.231.2.35
    Librathe461595631.4.15G8.5IIIb155349.535-164345.821.2.95
    Libraiot 1241590901.4.540.1A0pSi151213.284-194730.281.2.75
    Libraiot 2251591056.8.14A3Vn151319.179-193850.921.2.99
    Librakap431594421.4.74172M0-IIIb154156.802-194043.921.2.17
    Libralam451838955.3.14B2.5V155320.066-20101.5.141.2.17
    Libramu71588211.5.311.8.14A1pSrCrEu144919.074-14856.161.2.69
    Libranu211590285.2.14K5-III15637.561-161524.491.2.25
    Libraxi 1131588875.8.14G7III145422.88-115354.471.2.22
    Libraxi 2151589151.5.46K4III145646.106-112434.991.2.61
    Libraomi291591916.3.1444.4F0III15211.1.53-153253.951.2.34
    Librasig20BRACHIUM1831391591.3.29M3-III1541.4.15-251655.141.2.55
    Libratau401836491.3.66B2.5V153839.386-294640.281.2.65
    Libraups391836191.3.583.5.14K3III15371.1.66-2881.6.281.2.69
    Libra21585281.6.21G7III142325.624-114250.661.2.11
    Libra41827951.5.73B9144313.58-245951.41.2.99
    Libra51587881.6.333.1.14K1III144557.79-152734.631.2.84
    Libra111401761.4.94G8III-IV14511.1.32-21756.711.2.59
    Libra121829835.3.14K2III145420.131-243831.831.2.86
    Libra161402401.4.49F0V14571.10.72-42047.451.2.51
    Libra171589356.6.14A1V145813.387-11917.911.2.66
    Libra181589461.5.8719.7.14K3-IIICN1145853.614-11838.541.2.43
    Libra231832751.6.45G4V151328.674-251833.421.2.13
    Libra261591221.6.17B9.5III151433.729-17461.6.861.2.35
    Libra281591871.6.17G8III152053.65-18931.281.2.46
    Libra361835801.5.15K4III153437.314-28248.981.2.36
    Libra371406091.4.62K1III-IV15341.10.97-10352.521.2.77
    Libra411594111.5.38G8III153854.546-19181.6.931.2.39
    Libra421836861.4.96K3IIICN1154016.864-23491.5.471.2.18
    Libra471595721.5.940.7B5V15550.343-192259.11.2.86
    Libra48FX4901871596071.4.741.4.96B5IIIpe15581.11.74-141645.741.2.53
    Libra491596251.5.47155.1F8V16019.584-16320.161.2.96
    Libra501408971.5.55A0V s16047.636-82441.081.2.26
    Lupusalp2251281522.3.1427.6.14B1.5III/Vn144155.798-472317.4.141.3.96
    Lupusbet2253351571.2.68B2III/IV145831.91-4381.2.461.2.78
    Lupusgam2259381661.2.7850.6B2IV15351.8.56-41100.531.3.14
    Lupusdel2256911621.3.22B1.5IV152122.33-403851.651.2.86
    Lupuseps2257121.3.370.4B2IV-V152240.863-444121.921.3.36
    Lupuszet2423041.3.4171.9G8III151217.128-52556.961.3.82
    Lupuseta2072081.3.4115B2.5IV1601.7.28-382348.61.2.26
    Lupusthe2073321.4.23B2.5Vn16635.527-36481.8.411.2.85
    Lupusiot2248331.3.55B2.5IV141924.224-46328.372.11.14
    Lupuskap 12255251.3.8726.6.14B9.5Vne151156.062-484416.141.3.27
    Lupuskap 22255261.5.6926.6.14A3IV151157.633-484437.261.3.29
    Lupuslam2254834.5.140.4B3V15850.591-451647.351.3.54
    Lupusmu2256381.4.271.3.14B8Ve151831.983-475230.441.4.28
    Lupusnu 12257035F8V15221.8.17-475540.431.3.96
    Lupusnu 22256971.5.65G3-5V152148.205-48191.3.521.3.52
    Lupusxi 12071445.12.1410.3.14A3V155653.514-335758.571.2.79
    Lupusxi 22071451.5.6210.3.14B9V155654.169-335750.981.2.47
    Lupusomi2252481.4.320.1B5IV145138.378-433431.5.141.2.38
    Lupuspi2254261.4.721.8.14B5V1551.7.84-4731.3.991.3.97
    Lupusrho2250714.5.14B5V143753.19-492532.21.3.33
    Lupussig2417811.4.42B2III143236.934-502725.241.3.61
    Lupustau 12249191.4.56158.2B2IV14261.8.36-451317.9.141.2.79
    Lupustau 22249201.4.350.1F4IV+A7:14261.10.16-452245.881.2.14
    Lupusups2065971.5.371.4.14A0pSi152444.924-394236.641.2.65
    Lupusphi 12065521.3.5617.3.14K5III152148.371-361541.021.2.17
    Lupusphi 22065801.4.54B4V15231.9.53-365130.591.2.93
    Lupuschi52070401.3.95B9IV155057.516-333737.761.2.08
    Lupuspsi 132068431.4.67G8III153946.047-342441.871.2.53
    Lupuspsi 242068891.4.75B5V154241.027-344237.741.2.87
    Lupusome2260041.4.3311.8.14K4.5III15381.3.52-42341.2.391.3.13
    Lupus12064451.4.91F1II151437.333-31319.9.141.2.38
    Lupus21833461.4.34G9IIIaFe1151749.822-30855.311.2.57
    Lupus62256001.5.16G5Ia+B15161.4.43-412928.361.2.66
    Lynxalp4061414931.3.13K7IIIab9211.3.92+342333.161.2.58
    Lynx1UW510036137871.4.95M3IIIab61754.899+613055.041.3.26
    Lynx2UZ510039256651.4.431.4.73A2V61937.397+59039.371.3.67
    Lynx4256781.5.940.7A3V6221.3.45+592220.7.141.3.26
    Lynx5257331.5.2195.4K4III62648.895+58251.1.921.3.24
    Lynx6257711.5.88179.6K0III-IV63047.159+58945.871.3.97
    Lynx7258141.6.45K0III:63432.808+55211.10.751.3.07
    Lynx8138971.5.94157G8IV-V63741.397+612852.271.3.52
    Lynx11258421.5.85A2V63738.495+565127.481.3.53
    Lynx12259392881.4.87171.7.14A3V64614.133+592630.421.3.69
    Lynx13259471.5.35K0III64649.577+57109.3.141.3.98
    Lynx14260121.5.330.9G4III+A2V6531.5.57+592655.051.3.65
    Lynx15260511.4.350.9G5III-IV65716.538+582521.481.3.55
    Lynx16414634.9.14A2Vn65737.093+45539.181.3.92
    Lynx18262485.2.14K2III71554.879+593815.11.141.3.28
    Lynx19263121.5.4515.1.14B8V72252.056+551653.141.3.16
    Lynx19263111.6.5315.1.14B9V72250.897+55171.4.421.3.25
    Lynx21417641.4.64A1V72642.836+491241.971.3.21
    Lynx22418081.5.36169.3F6V72955.985+494021.1.141.4.12
    Lynx23264596.6.14K5III74049.537+57457.931.3.84
    Lynx24264741.4.9954.7A3IVn7430.406+584237.481.3.24
    Lynx25420551.6.25gK275429.262+47231.9.781.3.32
    Lynx26420581.5.45gK475442.683+473352.611.3.73
    Lynx27266871.4.8445.6A2V8827.431+513023.991.3.78
    Lynx28421741.6.26A1V871.9.81+431537.861.3.15
    Lynx29267561.5.64A7IV81750.433+593416.8.141.3.18
    Lynx30267841.5.89F4V82026.108+574435.541.3.55
    Lynx31MABSUTHAT423191.4.25K4.5III-IIIb82250.151+431117.2.141.3.49
    Lynx32608961.6.24F5Vb vw83321.764+36261.10.841.2.48
    Lynx33609071.5.78A2Vnn83443.841+36251.10.311.2.65
    Lynx34424901.5.37G8IV8411.1.56+45501.2.321.3.64
    Lynx35425761.5.15K0III85156.851+434335.661.3.38
    Lynx36427591.5.32B8IIIpMn91348.207+43131.4.151.2.53
    Lynx38613911.3.822.7.14A3V91850.67+36481.9.491.2.72
    Lynx42429581.5.25F0V93821.732+401422.641.2.62
    Lynx43616361.5.62G8III9420.315+394528.961.2.34
    Lyraalp3VEGA671742140.0362.8A0Va183656.336+38471.1.181.2.32
    Lyrabet10SHELIAK674511.3.4545.7B8IIpe18504.8.14+332145.751.2.28
    Lyragam14SULAFAT676632171.3.24176.9B9III185856.614+324122.321.2.53
    Lyradel 111675371.5.58174.6B2.5V185343.564+365818.11.141.3.71
    Lyradel 212675594.3.1486.2M4II185430.219+365355.831.2.19
    Lyraeps 14673096.2.14209.3F1V184420.302+394015.5.141.1.55
    Lyraeps 14DOUBLE DOUBLE673103345.6.14209.3A4V184420.372+39401.12.191.1.26
    Lyraeps 25673153351.5.14209.3A8Vn184422.896+393646.521.1.89
    Lyrazet 16673211.4.3643.7A4m184446.373+373618.371.2.04
    Lyrazet 27673241.5.7343.7F0IV184448.208+373540.31.2.59
    Lyraeta20ALADFAR680101.4.3928.3.14B2.5IV191345.518+39845.681.2.98
    Lyrathe21680651.4.36100.2K0+II191622.087+3881.1.421.2.22
    Lyraiot18678341.5.28B6IV19718.121+3660.831.2.26
    Lyrakap1668691.4.33K2IIIabCN0.5181951.709+36352.511.3.55
    Lyralam15676821.4.93K2.5IIIBa0.51900.862+32844.131.2.34
    Lyramu2ALATHFAR669435.12.14A3IVn182413.806+393025.731.2.37
    Lyranu 18674411.5.9158.7B3IV184945.906+324845.671.2.91
    Lyranu 29674461.5.2519A3V184952.918+32331.3.471.2.68
    Lyra13R520001479191.3.885M5III185520.123+435646.11.1.86
    Lyra16480115.1.14200A7V19126.372+46561.5.251.1.29
    Lyra17678351.5.233.5.14F0V19725.608+32301.5.931.2.41
    Lyra19V0471520471679461.5.911.5.98B9p(Si)191145.979+31170.671.2.92
    Mensaalp2562745.9.14G6V61014.385-744510.9.140.623
    Mensabet2561541.5.31G8III5243.092-711850.031.1.99
    Mensagam2562011.5.1938.2K2III53153.032-762027.610.918
    Mensadel2583721.5.69K2-3III+A41759.086-801250.621.1.79
    Mensaeps2564151.5.53K2-3III72538.037-79538.580.607
    Mensazet2584511.5.64A5III6401.2.65-804848.641.1.47
    Mensaeta2561451.5.47K4III4551.11.07-74561.12.971.1.21
    Mensathe2563551.5.45B9.5V65634.289-79251.12.850.478
    Mensaiot2562146.5.14B8III53536.289-784914.9.141.1.94
    Mensakap2562481.5.47B9V55016.412-792140.961.2.31
    Mensalam2562391.6.53K0III54748.778-72421.8.490.88
    Mensamu2561221.5.54B8II-IIISi:4431.4.25-705551.671.1.39
    Mensanu2583781.5.79F0-2III42057.931-813447.511.1.94
    Mensaxi2583951.5.85G8-K0III45850.663-822813.631.2.59
    Mensapi2584211.5.65G1V5371.9.21-80288.6.141.1.66
    Microscopiumalp2124724.9.1420.5.14G7III204958.074-334647.341.2.95
    Microscopiumbet2124996.4.14A2Vn205158.797-331038.371.3.23
    Microscopiumgam2126361.4.6725.7.14G6III21117.475-321527.961.2.28
    Microscopiumdel2127091.5.68K0/1III2161.1.99-30730.711.2.27
    Microscopiumeps2128741.4.71A1V211756.281-321021.3.141.2.68
    Microscopiumzet2126665.3.14F3V21257.957-383753.711.2.23
    Microscopiumeta2305231.5.53132.9K3III21625.515-41231.9.651.2.22
    Microscopiumthe 12306441.4.82ApCrEuSr212045.632-404834.651.2.97
    Microscopiumthe 22306671.5.770.5A0IIIpSi212424.827-41023.951.2.87
    Microscopiumiot2303795.11.144.3.14F1IV204829.174-435918.651.3.65
    Microscopiumnu2302765.11.14K0III203355.113-443057.921.3.17
    Monocerosalp261349861.3.93K0III74114.846-9331.4.281.2.12
    Monocerosbet 1111333162874.6.147.1.14B3Ve62848.978-7158.441.2.45
    Monocerosbet 2111333175.4.147.1.14B3ne62849.461-721.3.511.2.66
    Monocerosgam51330121.3.9851.4K1.5IIIBa0.361451.346-61629.141.2.78
    Monocerosdel221343301.4.1532A2V71151.859-02933.911.2.96
    Monoceroseps81138101.4.4412.9.14A5IV62346.093+43534.221.2.56
    Monoceroszet291355511.4.3466G2Ib8835.649-2591.1.771.2.12
    Monoceros1V04745504741327141.5.931.6.36F2IV5591.1.49-92256.132.5.14
    Monoceros21327155.3.14A6IIIm vs5591.4.35-93330.3.141.2.45
    Monoceros31510371.4.951.9.14B5III6150.424-103552.731.2.09
    Monoceros61513181.6.75F0Del Del61735.152-104331.131.2.29
    Monoceros71331141.5.27B2.5V61942.796-74922.6.141.2.25
    Monoceros91332676.9.14B56270.893-42120.481.2.49
    Monoceros101332905.6.1477.2B2V62757.566-44543.531.2.07
    Monoceros121140231.5.84K0V63219.209+45120.711.2.23
    Monoceros131140344.5.14A0Ib63254.234+71958.451.2.59
    Monoceros141140851.6.4510.5.14A0V s63446.357+73420.971.2.13
    Monoceros15S5500021142581.4.621.4.682.9.14O7.5III-Vf64058.688+95344.411.2.85
    Monoceros161143881.5.93B2.5V64632.425+83513.581.2.18
    Monoceros171144101.4.77K4III64719.817+8213.911.2.63
    Monoceros181144281.4.47K0+IIIaBa0.264751.642+22443.661.2.23
    Monoceros19V06375506371341061.4.965.1.14B1IV-Vea7254.718-41421.291.2.03
    Monoceros201342821.4.92186.2K0III71013.681-41413.691.2.31
    Monoceros21V05715505711343161.5.435.5.14F2V71123.593-0187.1.141.2.01
    Monoceros241344141.6.413.8.14G5III71519.325-0941.261.2.48
    Monoceros251348991.5.13121.7F6III73716.683-4639.681.2.97
    Monoceros271353451.4.93K2III75944.147-34046.81.2.49
    Monoceros28V06455506451353801.4.68K4III8113.284-12333.411.2.63
    Muscaalp2519741261.2.6929.6.14B2IV-V12371.10.56-6981.7.651.2.42
    Muscabet2520191303.5.14101.3.14B2.5V124616.897-68629.471.2.78
    Muscagam2569551.3.87B5V123227.998-72758.663
    Muscadel2570001.3.62K2III13216.308-713256.121.3.78
    Muscaeps2518304.11.14M5III121734.142-675738.61.2.56
    Muscazet 12518681.5.74K0III12221.11.75-681827.11.141.3.03
    Muscazet 22518661.5.1532.4A5V12221.7.97-673119.721.2.68
    Muscaeta2522244.8.1460B8V131514.897-675340.621.3.38
    Muscathe2521621.5.515.3.14B0Ia+WC5:1387-651822.531.2.76
    Muscaiot 12570415.5.14K0III13251.7.77-745315.871.3.03
    Muscaiot 22570471.6.63B9V132718.294-744130.551.3.61
    Muscalam2515751.3.6440.6A7III114536.392-664343.311.2.16
    Muscamu2515971.4.72K4III114814.328-664853.481.2.84
    Normagam 12266191.4.99F9Ia16170.885-5041.5.551.3.23
    Normagam 22436434.2.1444.9G8III161950.415-50920.191.3.19
    Normadel2265001.4.72Am16629.436-451023.641.3.82
    Normaeps2267731.4.4722.8.14B4V16271.11.83-473318.2.141.3.83
    Normazet2434491.5.81F2III161322.574-553227.381.3.72
    Normaeta2264661.4.65G8III1631.12.84-491347.41.3.03
    Normathe2266001.5.14B8V161515.329-472219.791.3.46
    Normaiot 12432791.4.630.5A7IV16331.947-574631.041.4.16
    Normaiot 22433681.5.57B9.5V16918.499-57561.2.911.3.25
    Normakap2434541.4.9414.9.14G8III161328.744-543750.021.3.19
    Normalam2266501.5.450.3A3Vn161917.696-424025.971.3.51
    Normamu2269001.4.94B0Ia16341.4.23-44243.211.3.43
    Octansalp2578791.5.15A7III+G2III21442.964-77125.351.4.76
    Octansbet2589411.4.15A9IV-V22461.3.49-812253.761.3.69
    Octansgam 12589895.11.14G7III23521.6.77-8211.7.871.2.31
    Octansgam 22589961.5.73K0III235732.747-82101.11.581.2.31
    Octansgam 32582151.5.28G8III0101.2.44-821326.521.2.21
    Octansdel2586981.4.32K2III142654.87-83401.4.161.6.18
    Octanseps2589285.1.14M5III22201.1.43-802623.4.141.4.04
    Octanszet2585151.5.42A8-9IV85641.623-853947.011.6.98
    Octanseta2586001.6.19A1V105913.809-843537.840.584
    Octansthe2582071.4.78K3III0135.746-77356.391.3.22
    Octansiot2586541.5.460.6K0III125458.748-85723.851.2.91
    Octanskap2586741.5.58Am134055.807-85471.9.551.4.18
    Octanslam2589141.5.292.8.14G8-K0III215054.282-82438.5.141.5.36
    Octansmu 12578386F4III-IV20421.3.49-761050.181.4.27
    Octansnu2579481.3.760.1K0III214128.687-772324.3.141.4.14
    Octansxi2589461.5.35B6IV225022.881-80726.551.3.62
    Octanspi 12587131.5.65G8-K0III15150.147-831339.161.6.46
    Octanspi 22587141.5.65G8Ib15446.678-83217.531.6.76
    Octansrho2587311.5.57A2V154316.896-842754.921.8.24
    OctanssigPOLARIS AUSTRALIS2588573511.5.47F0III21845.415-885723.5724.357
    Octanstau2589701.5.49K2III23281.3.96-872856.191.2.98
    Octansups2589321.5.77K0III223137.43-85581.2.331.3.92
    Octansphi2575841.5.47A0V182336.076-75238.71.5.99
    Octanschi2587991.5.28K3III185447.177-873621.1715.798
    Octanspsi2580201.5.51F3III221750.024-773041.981.3.39
    Octansome2587171.5.91B9.5V15111.8.54-844715.281.7.68
    Ophiuchusalp55RASALHAGUE1029322002.8.140.1A5III173456.075+123336.211.2.57
    Ophiuchusbet60CEBALRAI1226712031.2.77K2III174328.357+4342.2.142.9.14
    Ophiuchusgam621227541.3.75A0Vnp174753.568+24226.191.2.32
    Ophiuchusdel1YED PRIOR1410521731.2.7465.5M0.5III161420.74-34139.531.2.11
    Ophiuchuseps2YED POSTERIOR1410861741.3.24110.6G9.5IIIbFe-0.5161819.283-44132.921.2.57
    Ophiuchuszet13FIEHT1600061801.2.56O9.5Vn16371.9.48-10341.1.551.2.87
    Ophiuchuseta35SABIK1603321881.2.43100.3A2V171022.695-154329.431.2.18
    Ophiuchusthe421853201931.3.27B2IV17220.585-245958.221.2.46
    Ophiuchusiot251024581.4.38B8V16540.481+10955.041.2.22
    Ophiuchuskap271219621853.2.14K2III165740.096+92230.12.141.2.85
    Ophiuchuslam10MARFIC1216583231.3.82151.2.14A0V+A4V163054.833+1591.2.441.2.09
    Ophiuchusmu571417721.4.62B8II-IIIp:Mn173750.721-871.7.851.2.83
    Ophiuchusnu641420042071.3.34K0IIIaCN-117591.1.08-94625.2.141.2.38
    Ophiuchusxi401852961.4.393.7.14F1III-IV17210.227-21646.251.2.69
    Ophiuchusomi 1391852385.2.1410.2.14K0II-III17180.677-241713.151.2.18
    Ophiuchusomi 2391852376.8.1410.2.14F6IV-V17180.467-24171.2.661.2.17
    Ophiuchusrho 151843825.2.143.2.14B2IV162535.158-232649.711.2.95
    Ophiuchusrho 251843811.5.923.2.14B2V162535.051-232645.981.2.73
    Ophiuchussig491223871.4.34K2II172630.884+4825.131.2.53
    Ophiuchustau691420503301.5.24181.9.14F2V1831.4.62-81049.41.2.31
    Ophiuchusups31411871.4.631.1.14A3m162748.22-82218.2.141.2.77
    Ophiuchusphi81599631.4.28120G8+IIIa16311.8.33-163645.661.2.96
    Ophiuchuschi71599181.4.42B2IV:pe16271.1.01-182722.921.2.81
    Ophiuchuspsi41598924.5.14K0II-III16241.6.83-20214.611.2.57
    Ophiuchusome91844501.4.45A7p16321.8.26-212759.061.2.32
    Ophiuchus12V21331412691.6.57K2V163621.454-21928.7.141.2.11
    Ophiuchus141217901.5.74F2-4III-IV164142.447+11052.421.2.15
    Ophiuchus161218346.3.14B9.5III164529.699+1113.9.141.2.35
    Ophiuchus191218596.1.1423.4.14A3V16471.9.31+2352.461.2.36
    Ophiuchus201601181.4.65F7IV164950.038-104658.881.2.51
    Ophiuchus211219111.5.510.4A2V s165124.917+11258.351.2.29
    Ophiuchus231414311.5.25K2III165435.681-6913.961.2.93
    Ophiuchus241848221.5.581A0V165648.004-2390.451.2.01
    Ophiuchus261848971.5.75F4V1701.9.48-245920.751.2.95
    Ophiuchus291602311.6.26K0III17151.205-18531.8.151.2.05
    Ophiuchus301414831.4.8294.1K4III1711.3.82-41321.411.2.17
    Ophiuchus36A1851983265.7.144.6.14K0V171520.847-26361.4.541.2.13
    Ophiuchus361851995.11.144.6.14K1V171521.016-26361.9.981.2.26
    Ophiuchus371026461.5.3330.3.14M2IIIa171227.854+10351.6.841.2.66
    Ophiuchus411415861.4.731K2III171636.707-02642.671.2.96
    Ophiuchus431853501.5.35K5III172321.597-28834.741.2.36
    Ophiuchus441854011.4.17A3m172622.224-241030.961.2.08
    Ophiuchus451854121.4.29F5IVDel Sct*172721.284-29521.1.421.2.21
    Ophiuchus511854701.4.81B9.5Ve173124.953-235745.71.2.51
    Ophiuchus52V21255921251855261.6.57B8p(Si)173518.483-22237.71.2.47
    Ophiuchus531225261.5.8141.3A2V173436.717+93512.4.141.2.88
    Ophiuchus581856601.4.87F6V174325.807-214059.771.2.52
    Ophiuchus611226901.6.1720.6.14A1IV-V174434.05+23445.741.2.24
    Ophiuchus66V20485920481230051.4.551.4.85B2-B6IV-VneV18015.787+4226.7.141.2.49
    Ophiuchus671230131.3.9754.5B5Ib18038.713+25553.461.2.68
    Ophiuchus681230351.4.450.6A2Vn18145.211+11818.791.2.51
    Ophiuchus70P1231073314.3.14151.9.14K0V18527.347+22958.281.2.98
    Ophiuchus711231401.4.64G8III18718.353+8442.1.141.2.88
    Ophiuchus721231421.3.7354.4A4IV s18720.986+93349.931.2.96
    Ophiuchus731231871.5.730.3F2V18933.85+35935.941.2.34
    Ophiuchus741233771.4.8628.1.14G8III182052.072+32237.631.2.13
    Orionalp58BETELGEUSE113271560.5174.4M1-2Ia-Iab5551.10.21+72425.431.2.47
    Orionbet19RIGEL131907410.129.5.149.5.14B8Ia:51432.281-81261.2.57
    Orionbet19RIGEL1319072840.129.5.149.5.14B8Ia:51432.281-81261.3.72
    Oriongam24BELLATRIX112740441.1.64179B2III5251.7.55+62058.661.3.21
    Oriondel 134MINTAKA132220471.2.2351.7O9.5II5320.397-01756.811.2.49
    Oriondel 3341322211.6.8551.7B2V5320.463-0171.4.381.2.31
    Orioneps46ALNILAM132346501.7.14179.9B0Ia5361.12.12-1127.5.141.2.73
    Orionzet50ALNITAK132444532.5.142.4.14O9.7Ib54045.524-15633.531.2.83
    Orioneta28132071431.3.361.5.14B1V+B2e52428.638-22349.381.2.59
    Orionthe 141TRAPEZIUMBM6000907.9.141.8.65117B2V+A7IV53516.412-5231.6.761.2.83
    Orionthe 141TRAPEZIUMV10166010161323142861.6.721.7.65117B0.5Vp53516.47-52322.8.141.2.06
    Orionthe 243TRAPEZIUM1323215.8.14117O9.5Vp53522.883-52457.621.2.13
    Orioniot44NAIR AL SAIF132323491.2.7711.4.14O9III53525.982-55435.61.2.65
    Orionkap53SAIPH132542542.6.14B0.5Ia54745.394-9401.10.861.2.87
    Orionlam39HEKA1129212851.3.544.4.14O8III((f))5351.8.26+9561.2.561.2.13
    Orionmu611133894.12.140.3A2V6223.017+93850.831.2.58
    Orionnu67952591.4.42B3V6734.319+14461.6.441.2.82
    Orionxi70953621.4.4840B3IV61156.413+141231.541.2.56
    Orionomi 14941761.4.74S3.5/1-45231.955+14151.2.141.3.63
    Orionomi 29942184.7.14100.4K2-IIIFe-145622.281+133051.91.2.12
    Orionpi 17942011.4.65171.6A0Vp45453.755+1092.6.141.2.53
    Orionpi 221121241.4.36A1Vn45036.721+8540.561.2.03
    Orionpi 31TABIT112106341.3.1994.6F6V44950.413+65740.661.2.69
    Orionpi 431121421.3.69B2III+B2IV4511.12.65+53618.211.2.64
    Orionpi 581121971.3.72B3III+B0V45415.084+22626.231.3.22
    Orionpi 6101122811.4.47K2-II45832.88+14250.871.2.76
    Orionrho171125281.4.466.9.14K0.5III51317.46+25139.831.2.56
    Orionsig481324061.3.810.2O9.5V53844.76-2360.151.2.06
    Oriontau201319523.6.1436B5III51736.39-65039.831.2.87
    Orionups361322221.4.62B0V53155.834-7181.5.381.3.95
    Orionphi 1371129141.4.41B0III53449.24+92922.341.2.87
    Orionphi 2401129584.9.14K0IIIbFe-253654.316+91726.361.2.53
    Orionchi 154777051.4.410.6G0V55422.931+201634.181.2.91
    Orionchi 262779111.4.63B2Ia6355.201+20818.4.141.2.16
    Orionpsi 1251127341.4.95B1Vpe52444.821+15046.971.2.34
    Orionpsi 2301127751.4.592.7.14B2IV52650.227+3544.311.2.61
    Orionome471130011.4.57B3IIIe53911.12.14+4717.261.3.64
    Orion51121791.5.33M1III45322.783+23029.363.8.14
    Orion6941971.5.19A3V45446.892+112533.551.2.78
    Orion11V1032601032942901.4.651.4.69B9p(Si)5434.144+152414.541.2.24
    Orion131124361.6.17124G1IV5738.321+92818.851.2.96
    Orion14I1124402831.5.3470.7Am5752.912+82954.151.2.04
    Orion15943591.4.82F2IV5941.969+153550.091.2.28
    Orion161124671.5.43168A2m5919.644+94946.521.3.12
    Orion18944261.5.56A0V5161.4.65+112028.711.2.52
    Orion211126241.5.34F5II5191.11.43+23545.011.2.09
    Orion221320281.4.73B2IV-V52145.746-02257.151.2.52
    Orion23112697531.9B1V52249.959+33239.821.2.77
    Orion271320705.8.14G9III-IVFe-152428.929-05329.311.2.29
    Orion291320671.4.14G8IIIFe-0.552356.824-74828.961.2.66
    Orion31CI6001101321761.4.671.4.7112.5.14K5III52943.998-1531.711.3.41
    Orion321128494.2.140.9B5V53047.085+55653.241.2.91
    Orion331128611.5.461.9.14B1IV+B1.5V53114.523+31732.211.2.85
    Orion35946521.5.64B3V53354.236+141820.411.2.89
    Orion381129041.5.360.4A2V53416.742+3460.51.2.07
    Orion421323201.4.591.5.14B1V53523.173-45017.881.2.88
    Orion451323361.5.2619.1.14F0III53539.53-45121.381.2.53
    Orion491324114.8.14A4V53853.108-71246.541.2.85
    Orion511130561.4.91K1III54228.64+12828.671.2.17
    Orion521131501.5.271.4.14A5V5480.245+62714.651.2.08
    Orion551325911.5.35B2IV-V55121.99-7311.4.961.2.61
    Orion561132201.4.7843.4K1.5IIb55226.45+15118.591.2.22
    Orion57949861.5.92B2V55456.685+194458.291.2.79
    Orion59V10046010041133151.5.881.5.9236.7A5m55824.422+15013.391.2.35
    Orion601133211.5.2219.1.14A1V s55849.582+0331.10.551.2.69
    Orion631134291.5.67gG76458.225+52512.4.141.2.64
    Orion64951661.5.14B8III6327.317+194126.281.2.63
    Orion661134301.5.63G4III6458.351+4930.921.2.39
    Orion68953591.5.7586.3B9.5V6121.1.44+194726.131.2.76
    Orion69953651.4.95B5Vn6121.3.05+16749.811.2.31
    Orion71954325.2.1425.4.14F6V61450.867+19922.671.2.43
    Orion72954475.3.14B7V61525.138+16835.491.2.21
    Orion73954571.5.33B9II-III61544.977+123341.2.45
    Orion74954765.4.14204F5IV-V61626.622+121619.691.2.76
    Orion751136751.5.390.1A2V6171.6.82+95632.451.2.85
    PavoalpPEACOCK2465742301.1.94245.4B2IV202538.895-56441.6.321.3.83
    Pavobet2548621.3.42A7III204457.468-661211.1.141.3.64
    Pavogam2549991.4.22F6V212626.628-652158.711.3.97
    Pavodel2547331.3.56G6-8IV20843.492-661055.284.2.14
    Pavoeps2577571.3.96A0V20035.476-725437.781.5.58
    Pavozet2576204.1.1455.6K0III18431.2.72-712541.471.4.28
    Pavoeta2540201.3.62K2II174544-644325.6.143.3.14
    Pavothe2543741.5.73A8V184837.844-65440.131.3.08
    Pavoiot2541571.5.49G0V181026.111-6208.2.141.3.33
    Pavokap2544131.4.44F5I-II185657.014-67140.811.4.66
    Pavolam2543931.4.2263.1B2II-IIIe18521.12.89-621115.881.3.29
    Pavomu 12547021.5.76K0III20023.005-665657.611.3.93
    Pavomu 22547071.5.31K2IVCNII20152.372-665638.51.3.78
    Pavonu2542731.4.64B7-8III183122.405-621641.641.3.31
    Pavoxi2542261.4.363.5.14K4III182313.548-612938.141.3.51
    Pavoomi2578965.2.14M1-2III211320.416-70735.081.3.11
    Pavopi2541471.4.35A7pSr18834.807-63406.6.141.3.09
    Pavorho2548351.4.88F5Del Del203735.269-613147.291.4.05
    Pavosig2548711.5.41K0III204918.028-684635.671.3.78
    Pavotau2545081.6.27A6IV-V191628.548-691126.171.4.75
    Pavoups2548541.5.15B9III204157.117-664538.521.3.49
    Pavophi 12548231.4.76F1III203534.844-603454.011.3.71
    Pavophi 22548465.12.14F8V20401.2.76-603255.981.3.97
    Pavoome2544231.5.14K2IIICNIV185836.435-60121.1.991.3.56
    Pegasusalp54MARKAB1083782491.2.49B9V23445.656+151218.891.2.49
    Pegasusbet53SCHEAT909812481.2.42253.1M2.5II-III23346.46+28458.071.2.88
    Pegasusgam88ALGENIB9178131.2.83163.4B2IV01314.156+15110.81.2.34
    Pegasuseps8ENIF1270292381.2.39142.5K2Ib21441.11.66+952301.3.69
    Pegasuszet42HOMAM1081033.4.1464.3B8V224127.732+104952.791.3.62
    Pegasuseta44MATAR907342451.2.9490.4G2II-III+F0V22430.139+301316.491.2.01
    Pegasusthe26BIHAM1273401.3.53A2Vp22101.11.88+61152.311.3.21
    Pegasusiot24902381.3.76103.7F5V2270.676+252042.231.2.28
    Pegasuskap10899491.4.130.3F5IV214438.714+253842.091.2.69
    Pegasuslam47907751.3.95G8IIIa*224631.882+233356.251.3.15
    Pegasusmu48SADALBARI908161.3.48G8+III22500.205+24361.5.791.2.26
    Pegasusnu221272851.4.84K4III22540.799+5330.621.2.68
    Pegasusxi461081651.4.19145F6III-IV224641.595+121021.961.2.76
    Pegasusomi43907171.4.79A1IV224145.411+291827.3.141.2.66
    Pegasuspi 127720641.5.5870.2G8IIIb22913.645+331020.521.2.76
    Pegasuspi 229720771.4.29F5III22959.245+331041.521.2.95
    Pegasusrho501278394.9.14A1V225513.685+84857.441.2.04
    Pegasussig491278101.5.16248F7IV225224.8.14+9501.8.461.2.32
    Pegasustau62SALM911864.6.14A5Vp232038.245+234425.281.2.29
    Pegasusups68912534.4.14F8III232522.786+232414.951.2.72
    Pegasusphi811088785.8.14M2.5IIIb235229.295+19713.9.141.2.24
    Pegasuschi89917924.8.14M2+III01436.175+201224.9.141.2.78
    Pegasuspsi84916111.4.66M3III235745.54+25829.7.141.2.09
    Pegasus11070734.8.1436.2K1III21221.5.94+194816.241.2.26
    Pegasus2897521.4.5729.8.14M1+III212956.893+233819.731.2.59
    Pegasus31269401.6.1839.2A2V213743.65+6371.5.611.3.11
    Pegasus41269561.5.6727.2.14A9IV-Vn213831.936+54617.581.3.52
    Pegasus51072881.5.45F1IV213745.439+19191.6.731.2.09
    Pegasus71270025.3.14M2IIIab214215.471+54048.391.2.79
    Pegasus91073651.4.34G5Ib214430.71+172059.661.2.56
    Pegasus111270601.5.64A1V214713.984+2411.10.181.2.56
    Pegasus12899721.5.29K0IbHdel 0.521461.4.48+225655.961.2.86
    Pegasus131074251.5.290.2F2III-IV21501.8.96+17171.8.381.2.55
    Pegasus14900405.4.14A1V s214950.689+301027.6.141.3.41
    Pegasus15900651.5.53F6IV-V vw215229.907+284736.311.2.55
    Pegasus16900755.8.14B3Ve21531.3.76+255530.391.3.04
    Pegasus171075281.5.54A2Vnn215656.356+12435.491.2.71
    Pegasus181272196B3III2201.7.07+6431.1.961.3.51
    Pegasus191272391.5.65gK52211.9.38+81525.691.2.15
    Pegasus201075875.6.1454.7F4III2211.5.49+1371.11.561.2.24
    Pegasus211076255.8.14B9.5V22319.031+11231.10.961.3.01
    Pegasus23902175.7.14B9Vn22534.627+285750.261.2.86
    Pegasus25902521.5.78B7Vne22750.289+21421.10.271.2.26
    Pegasus28902871.6.46A3III221030.075+205840.51.2.08
    Pegasus301274531.5.3714.8.14B5IV222027.613+547221.3.09
    Pegasus31IN1078541.4.855.5.14B2IV-Ve222131.092+121218.8.141.3.68
    Pegasus32904401.4.8172.6B9III222119.328+281949.711.2.51
    Pegasus33904626.4.1478.4F7V222339.597+205054.071.3.36
    Pegasus341275291.5.753.3.14F7V222637.446+42337.231.2.42
    Pegasus351275401.4.79181.5K0III222751.552+44143.981.2.98
    Pegasus361275441.5.58K5IIIa22298.1.14+9744.311.2.34
    Pegasus371275511.5.480.9F2V+F2V222957.991+42554.181.2.56
    Pegasus38724061.5.650.2B9.5V22301.1.36+323421.431.2.09
    Pegasus391079861.6.42F1V223235.44+201348.021.2.97
    Pegasus401080641.5.821.5.14G8II223852.614+193119.751.2.31
    Pegasus411080781.6.21A2V223947.009+194052.011.2.86
    Pegasus451081541.6.25gG6224528.167+192159.651.2.71
    Pegasus51908961.5.49G2.5IVa225727.94+20461.7.541.3.19
    Pegasus521083071.5.750.7A8V+F6V22591.11.08+114343.81.3.41
    Pegasus551279761.4.52M1IIIab2370.267+92433.961.2.43
    Pegasus56910191.4.76G8Ib2371.6.96+25281.5.761.2.89
    Pegasus57GZ A6202081280011.4.951.5.2332.9M4SIII23931.456+84038.061.2.33
    Pegasus581280071.5.39B9III23101.1.81+94919.211.2.13
    Pegasus591280221.5.16A5Vn231144.197+8431.12.381.2.78
    Pegasus60910801.6.17231.5G8III-IV231149.173+265049.681.2.38
    Pegasus61911301.6.49G5II-III231546.279+281452.421.2.14
    Pegasus63731871.5.59M0III232049.577+302453.741.2.56
    Pegasus64732051.5.320.4B6III232154.883+314844.561.2.82
    Pegasus65912201.6.29B9.5V232240.506+204942.91.2.43
    Pegasus661085805.8.140.1K3III23231.4.85+121849.781.2.01
    Pegasus67732411.5.57B9III232450.822+32231.5.331.2.16
    Pegasus69HV620222912781.5.961.5.98A0p(Hg-Mn)232740.36+25101.1.711.2.29
    Pegasus701086381.4.55G7+III23291.9.08+124538.221.2.13
    Pegasus71HW620223913401.5.32M5IIIa233328.1.14+222955.351.2.25
    Pegasus72733413501.4.980.5K4IIIb233357.199+311931.41.2.59
    Pegasus73733451.5.63gK0233438.222+332950.481.2.69
    Pegasus741087291.6.2698.3A1V233739.757+164931.881.2.87
    Pegasus75KS6202521087321.5.5327.9.14A1Vn233756.792+18241.2.671.2.34
    Pegasus771087895.6.14M2III234322.371+101953.551.2.42
    Pegasus78914571.4.930.9K0III234359.465+292141.51.2.49
    Pegasus79915221.5.97A2m234939.411+285032.581.2.04
    Pegasus80HH6202091284211.5.745.9.14M3III235121.207+91848.371.2.39
    Pegasus82HT6202201088795.3.141.5.39A4Vn235237.129+105650.731.2.34
    Pegasus85916691.5.7575.5G5VbFe-2021.10.22+27455.461.2.18
    Pegasus86917011.5.51G5III0541.987+132347.381.2.19
    Pegasus87917341.5.53G9III091.2.88+181243.311.2.95
    Perseusalp33MIRPHAK38787251.1.79167F5Ib32419.371+495140.311.3.01
    Perseusbet26ALGOL38592242.12.1481.9B8V381.10.31+405720.441.2.66
    Perseusgam2323789231.2.9357G8III+A2V3447.788+533023.241.4.84
    Perseusdel3939053263.1.1499.1B5IIIe34255.49+474715.214.7.14
    Perseuseps4556840301.2.898.8.14B0.5V+A2V35751.22+40036.661.3.54
    Perseuszet4456799291.2.8512.9.14B1Ib3541.7.25+31530.941.3.15
    Perseuseta15MIRAM236551.3.7628.3.14K3-Ib-IIa25041.826+555343.731.3.33
    Perseusthe13382884.12.1419.6.14F8V2441.11.99+491342.594.6.14
    Perseusiot385974.5.14146.2G0V394.1.14+493648.091.3.08
    Perseuskap27386093.8.1427.7.14K0III3929.755+445126.351.3.28
    Perseuslam47244121.4.29A0IVn4635.026+50211.4.541.3.07
    Perseusmu51394041.4.1483.8G0Ib41453.851+482433.571.3.08
    Perseusnu41390781.3.7731.4F5II3451.11.64+423442.641.3.74
    Perseusxi46MENKIB568564.4.14O7.5III(n)((f))35857.91+354727.541.2.75
    Perseusomi38ATIK566731.3.831B1III34419.137+321717.791.3.71
    Perseuspi22GORGONEA SECUNDA560474.7.14A2Vn25845.693+393945.931.2.41
    Perseusrho25GORGONEA TERTIA561381.3.39M4II351.10.92+385025.2.141.3.03
    Perseussig35388901.4.36K3III33034.482+475942.921.3.69
    Perseustau18236851.3.9551.7G4III+A4V25415.457+524545.031.3.36
    Perseusphi225544.7.14B2Vep14339.645+504119.341.3.97
    Perseuspsi37389801.4.23B5Ve33629.39+481133.611.3.94
    Perseusome28GORGONEA QUARTA562241.4.63177.4K1III31117.391+393641.671.2.48
    Perseus1V0436630436226901.5.491.5.85B1.5V15159.419+55850.711.2.77
    Perseus2226961.5.79B9IIIpHgMn1521.9.33+504734.221.2.02
    Perseus3376651.5.69K0IV15833.552+491215.291.2.98
    Perseus4228595.4.14B8III2218.11.14+542915.291.3.44
    Perseus5230111.6.3660B5Ia21128.998+573844.651.3.34
    Perseus7231491.5.98121.9G7III2181.4.48+573059.741.3.75
    Perseus8231431.5.75K3III21759.844+575359.851.4.85
    Perseus9232561.5.1711.6.14A2Ia22221.4.14+555044.631.3.32
    Perseus10233041.6.25B2Ia22515.974+563636.421.4.39
    Perseus11235551.5.77B7IIIpHg2431.2.72+55621.391.3.58
    Perseus12557931.4.910.1F9V24214.935+401137.811.2.05
    Perseus14382891.5.43G0Ib-IICa1CH-12441.5.47+441749.271.2.43
    Perseus16559281.4.23249.3F2III25034.988+38191.7.271.2.67
    Perseus17559461.4.53K5+III25130.897+35334.831.2.85
    Perseus20559751.5.330.2F4IV25342.583+382015.341.2.29
    Perseus21LT630268560315.3.141.5.14B9p(Si-Eu-Sr-Cr)25717.244+31563.2.141.2.38
    Perseus24560521.4.93K2III2591.3.66+351059.353.8.14
    Perseus29239441.5.15B3V31837.807+501319.721.3.99
    Perseus30387041.5.47B8V31747.397+44129.761.4.13
    Perseus31387145.3.14B5V3191.7.64+50541.871.3.72
    Perseus32387501.4.95A3V32126.567+431946.721.3.24
    Perseus34388721.4.670.8B3V32922.097+493032.031.3.64
    Perseus36389241.5.31F4III33226.256+46325.381.3.38
    Perseus40566461.4.9720B0.5V34222.547+335753.861.2.85
    Perseus42V0467630467567275.5.141.5.18A2V34932.648+33528.8.141.2.62
    Perseus43243141.5.2875.3F5IV35636.488+504143.241.3.04
    Perseus48MX630286393364B3Vpe4839.684+474245.111.3.92
    Perseus49570006.9.14K1III4815.281+374339.711.2.97
    Perseus50570061.5.51F7V4836.593+38223.2.141.2.57
    Perseus52394091.4.71G5Ib+A2V41453.348+40291.1.481.3.91
    Perseus53V0469630469394831.4.811.4.86B4.5V42133.13+462955.571.3.11
    Perseus54571711.4.93110G8III42024.647+34340.391.2.85
    Perseus55572121.5.73B8V42429.153+34749.831.2.34
    Perseus56572161.5.764.9.14F4V42437.446+335735.231.2.33
    Perseus57396046.9.14116.2F0V43324.89+43349.961.3.28
    Perseus58396391.4.250.1K4III+A3V43641.332+411553.051.3.48
    Perseus59396991.5.29A1Vn44254.328+432154.561.3.96
    PhoenixalpANKAA21509351.2.390.1K0III02617.076-421821.761.2.57
    Phoenixbet215365101.3.31101G8III161.5.44-46437.3.141.2.26
    Phoenixgam2155161.3.41M0-IIIa12821.953-43191.5.631.2.48
    Phoenixdel2155361.3.95K0III13115.096-49421.681.2.47
    Phoenixeps2149831.3.88K0III0924.718-454450.951.2.65
    Phoenixzet2323061.3.926.6.14B6V+B9V1823.088-551444.861.3.42
    Phoenixeta2321621.4.3619.8.14A0IV04321.245-572747.141.2.11
    Phoenixthe2317196.9.143.7.14A8V+F0V233927.988-463816.1.141.3.85
    Phoenixiot2316751.4.717.7.14A2VpSrCrEu23351.4.65-423654.321.2.05
    Phoenixkap2150921.3.94A7V02612.2.14-434047.611.2.79
    Phoenixlam 12151311.4.7730.3.14A0V03124.974-48481.12.461.2.79
    Phoenixlam 22151571.5.51F6V03541.12-4803.4.141.2.67
    Phoenixmu2151941.4.59G8III04119.565-4651.5.951.3.28
    Phoenixnu2154281.4.96F8V1151.11.36-453153.291.2.98
    Phoenixxi2321525.7.1413.2.14ApSrEuCr04146.37-56301.5.621.2.46
    Phoenixpi2480871.5.13K0III235855.732-524445.011.3.88
    Phoenixrho2322031.5.22F2III05041.091-50591.12.711.2.06
    Phoenixsig2480181.5.18B3V234715.957-501334.381.3.12
    Phoenixtau2318951.5.71G8III014.5.14-484835.661.2.48
    Phoenixups2153741.5.210.2A3IV1747.882-412913.611.3.69
    Phoenixphi2156975.11.14A3V15422.011-422949.361.2.66
    Phoenixchi2157391.5.14K5III2142.399-444248.311.2.61
    Phoenixpsi2156961.4.41M4III15338.788-46181.9.371.2.26
    Phoenixome2322686.11.14G8III121.1.97-5701.8.431.2.96
    Pictoralp249647681.3.27A7IV6481.11.44-615629.021.1.22
    Pictorbet2341341.3.85A5V54717.115-51359.171.1.32
    Pictorgam2341541.4.51K1III54949.613-56100.061.1.23
    Pictordel2343591.4.81B3III+O9V61017.887-54587.1.141.1.76
    Pictorzet2339261.5.45F7III-IV51922.103-503621.521.1.55
    Pictoreta 12171401.5.3810.4.14F2V5248.644-4991.5.321.1.76
    Pictoreta 22171645.3.14K5III5457.993-493440.291.2.02
    Pictorthe2339651.6.2738.2A0V52446.178-521858.671.1.52
    Pictoriot 12337091.5.6112.3.14F0IV45055.171-532741.321.2.21
    Pictoriot 22337101.6.4212.3.14F4V:45056.324-532734.961.1.83
    Pictorkap2339526.11.14B8-9V52222.236-5683.5.141.1.21
    Pictorlam2336381.5.31K0-1III44246.376-502852.381.1.52
    Pictormu2345645.7.142.4.14B9Ve63158.374-584515.5.141.1.13
    Pictornu2344731.5.61Am62255.841-56221.12.261.1.71
    Piscesalp113ALRISCHA1102912651.4.33164A0pSiSr221.2.81+24549.121.2.24
    Piscesbet4FUM AL SAMAKAH1279341.4.53B6Ve23352.612+3491.12.231.2.67
    Piscesgam61280851.3.69G9-III:Fe-223171.9.39+31656.191.2.55
    Piscesdel631094741.4.43113.3K4IIIb04840.953+7356.2.141.2.95
    Pisceseps711096271.4.280.2K0III1256.614+75324.311.2.71
    Pisceszet 1861097392591.5.240.1A7IV11343.886+73431.131.3.16
    Pisceszet 2861097406.3.140.1F7V11345.311+73441.991.2.31
    Pisceseta99924841.3.620.8G7IIIa13129.014+152044.731.2.74
    Piscesthe101281961.4.28K1III232758.11+62244.071.2.32
    Piscesiot171283101.4.1369.9F7V233957.034+53734.591.2.31
    Pisceskap81281861.4.94163.4A0pCrSi:Sr:232655.954+11520.4.141.3.73
    Pisceslam181283364.5.14A7V23421.2.15+14648.41.2.22
    Piscesmu981099261.4.84182.5K4III1301.11.35+6837.631.2.54
    Piscesnu1061100651.4.44K3IIIbBa0.114125.898+52915.261.2.74
    Piscesxi1111102061.4.62K0III15333.349+31115.2.141.2.51
    Piscesomi110TORCULARIS SEPTENTRIONALIS1101101.4.26G8III14523.629+9927.611.3.53
    Piscespi102925361.5.57F0V1371.5.32+12829.711.2.98
    Piscesrho93924361.5.38F2V:12615.265+191020.421.3.19
    Piscessig69543745.5.14B9.5V1249.075+314815.781.2.97
    Piscestau83745461.4.51K0.5IIIb11139.638+30522.551.3.18
    Piscesups90746371.4.76A3V11927.995+271550.691.3.15
    Piscesphi85745711.4.657.9.14K0III11344.904+24350.591.2.44
    Pisceschi84745441.4.66G8.5III-IIIa11127.211+2121.4.751.3.03
    Piscespsi 174744822571.5.3429.9.14A1Vn1540.941+212823.741.2.35
    Piscespsi 174744831.5.5629.9.14A0Vn1541.676+212755.411.2.89
    Piscespsi 279745061.5.55A3V1757.206+204421.231.2.67
    Piscespsi 381922831.5.55G0III1949.206+193930.511.2.52
    Piscesome281285134.1.141F4IV235918.706+65147.841.2.93
    Pisces11278366.11.14A7III225459.506+1353.213.1.14
    Pisces21278811.5.433.9.14gK1225927.437+05746.221.2.61
    Pisces31464431.6.21G4III23037.902+0111.9.271.2.31
    Pisces51279935.4.14G8III-IV23840.915+2740.21.2.27
    Pisces71281265.5.14K2III232020.592+52252.431.2.19
    Pisces91281881.6.25G7III232714.772+1721.181.3.14
    Pisces131467561.6.38K1III233157.575-159.4.141.2.54
    Pisces141467801.5.87A2m23341.9.15-11451.121.2.29
    Pisces161282811.5.68F6Vb vw233623.286+267.6.141.3.38
    Pisces19TX6600311283741.4.795.2.14C7,2(N0)(Tc)234623.502+3291.12.821.3.21
    Pisces201469151.5.49172.7G8III234756.542-24541.791.2.02
    Pisces211284011.5.77A5Vm234927.472+1433.91.2.23
    Pisces221284271.5.55K4IIIaBa0.3235157.822+25549.211.2.89
    Pisces241469541.5.930.1G9III235255.551-3920.161.2.63
    Pisces251284361.6.28A1V23531.4.74+2526.351.2.23
    Pisces261284661.6.21B9V23551.7.81+7415.6.141.3.03
    Pisces271470081.4.861.1.14G9III235840.423-33321.682.2.14
    Pisces291470415.1.14B7III-IV0149.428-31391.2.16
    Pisces30YY6600521470421.4.311.4.41M3III0157.64-6050.631.2.73
    Pisces311285441.6.32A6V0224.216+85724.721.2.93
    Pisces321285471.5.63F0V0229.688+8291.7.541.2.71
    Pisces33BC1285721.4.61K0IIIbCN-0.50520.146-54227.331.2.08
    Pisces34917501.5.517.7.14B9Vn0101.2.27+11844.411.2.72
    Pisces35UU A6600341090876.1.146.5.14F1IV-V+F1IV-V01458.812+84915.371.2.81
    Pisces361091006.11.14G8II-III01634.042+81424.991.2.83
    Pisces381091117F501724.602+85235.911.2.32
    Pisces40918506.8.14K001956.272+16151.3.831.2.26
    Pisces411091521.5.37gK302035.87+81124.841.3.87
    Pisces42918661.6.2328.9.14K3III02225.479+132857.731.2.58
    Pisces441091921.5.77G5III02524.216+15622.511.2.72
    Pisces47TV660029919101.4.651.5.42M3III-M4IIIb0281.2.32+175335.461.2.96
    Pisces48919126.6.14K5III0281.12.05+162642.081.2.86
    Pisces511092621.5.67B9.5V03223.798+65720.141.3.38
    Pisces52740841.5.3849.6K0III03235.462+201739.71.2.41
    Pisces53AG660061919951.5.811.5.94B2.5IV03647.327+151353.751.2.97
    Pisces54741751.5.87122K0+V03921.779+21151.1.691.2.52
    Pisces55741822521.5.366.6.14K0III+F3V03955.562+212617.921.3.69
    Pisces57920721.5.38M4IIIa04632.981+152832.21.2.08
    Pisces58920805.5.14G8II0471.1.46+115826.191.2.67
    Pisces59XX660049920821.6.13F0V04713.574+193443.141.2.99
    Pisces601094611.5.99G8III04723.618+64427.371.3.49
    Pisces61742801.6.54F8V04754.819+205530.621.3.98
    Pisces621094701.5.93G8III04817.401+71759.711.2.52
    Pisces64920995.7.1476.7F8V04858.713+165626.11.141.3.39
    Pisces65I742962547.1.144.5.14F5III04953.2+274236.691.2.38
    Pisces657429574.5.14F4III04952.808+274238.811.2.95
    Pisces66921452551.5.740.5A1VN05435.242+191117.891.3.96
    Pisces67743736.9.14A5IV05558.521+271233.361.2.88
    Pisces68743951.5.42gG605750.149+285931.771.2.92
    Pisces72922301.5.6855.2F4II-III151.5.58+145646.051.2.62
    Pisces731096566gK51452.614+53922.771.2.57
    Pisces75922506.12.14G8III1633.632+125722.621.2.74
    Pisces771096661.6.3533F3V1549.204+45429.881.2.46
    Pisces78544451.6.25F5IV181.1.28+32043.171.2.44
    Pisces801096971.5.52159.3F0III-IV1822.208+53859.261.2.36
    Pisces82544931.5.16F0V1111.6.67+312528.991.3.73
    Pisces87923261.5.98B8III1141.7.71+1680.631.3.88
    Pisces881097536.3.14gG611442.393+65942.581.2.93
    Pisces891097931.5.16A3V11747.94+33651.921.3.08
    Pisces91746471.5.23gK51211.7.67+284417.991.3.25
    Pisces94924445.5.14K1III12641.665+191425.5.141.2.05
    Pisces97VX660042924635.9.146.2.14A3V12952.883+182120.451.2.94
    Pisces101925301.6.22B9.5III13546.44+143940.871.2.97
    Pisces104925566.9.14K013915.428+14171.8.391.3.76
    Pisces105925581.5.97K2III13940.763+162420.9.141.2.72
    Pisces107748831.5.2419K1V14229.789+20161.6.891.2.89
    Pisces109926111.6.27G3Va14455.846+20459.11.3.21
    Pisces1121102661.5.88G2IV201.9.57+3549.551.2.34
    Pisces Austrinusalp24FOMALHAUT1915242471.1.16A3V225739.071-293720.9.141.2.47
    Pisces Austrinusbet172138831.4.2930.3.14A0V223130.366-322045.571.2.73
    Pisces Austrinusgam222141531.4.464.2.14A0III*225231.564-325232.021.3.42
    Pisces Austrinusdel232141891.4.215.2.14G8III225556.919-323222.871.2.14
    Pisces Austrinuseps181913181.4.17B8V224039.348-27236.831.3.58
    Pisces Austrinuszet1911961.6.43K1III223053.715-26425.4.141.2.98
    Pisces Austrinuseta121908221.5.421.9.14B8V22050.239-28271.12.761.2.78
    Pisces Austrinusthe102132925.1.140.1A2V214744.227-305354.181.2.31
    Pisces Austrinusiot92132581.4.3420A0V214456.825-33132.771.2.42
    Pisces Austrinuslam161909851.5.43B8III221418.769-27461.1.251.2.65
    Pisces Austrinusmu142135764.5.14A2V22822.999-325919.2.141.2.33
    Pisces Austrinuspi2142755.11.14F0V+F3V23329.792-344457.991.2.57
    Pisces Austrinustau152136021.4.92F6V22101.8.94-323254.241.2.57
    Pisces Austrinusups2135771.4.99M1III22825.96-34237.651.2.43
    Pisces Austrinus52130346.5.14A021291.3.77-311418.761.3.23
    Pisces Austrinus62130781.5.976.8.14A2IV213214.621-335640.861.2.65
    Pisces Austrinus72131366.11.14A7Vn213648.884-33252.581.2.89
    Pisces Austrinus81904781.5.7318.4.14A7/8IV21361.10.74-261017.391.2.34
    Pisces Austrinus132135171.6.47K5III22423.897-295459.771.3.39
    Pisces Austrinus191913371.6.17M5III224222.136-292139.391.2.68
    Pisces Austrinus211914441.5.97G8/K0III225120.947-29321.10.441.2.84
    PuppiszetNAOS198752831.2.25O5f8335.079-4001.11.511.2.76
    Puppisnu218071651.3.17B8III63745.659-431145.311.1.36
    Puppisxi7ASMIDISKE174601821.3.345.1.14G6Iab-Ib74917.657-245135.241.2.49
    Puppisomi1745584.5.1427B0V:pe:7481.5.57-255613.761.2.01
    Puppispi197795742.7.1469.2K3Ib7171.8.85-37550.991.2.51
    Puppisrho15175217841.2.8129.6.14F6IIpDel Del8732.644-241815.211.2.76
    Puppissig 1218755771.3.2522.3.14K5III72913.877-43181.5.261.1.72
    Puppistau234735691.2.93K1III64956.168-503653.161.1.48
    Puppischi1986361.4.79A2V75740.107-30201.4.261.2.28
    Puppis11743911.4.5926.2.14K3Ib74332.374-282439.782.12.14
    Puppis2PV6803201533621.6.881.7.3216.8.14A8V+A8V74528.655-14411.9.821.2.17
    Puppis21533636.7.1416.8.14A2V74529.103-144126.541.2.18
    Puppis31744001.3.96A2Iabe74348.437-285717.941.2.13
    Puppis41533725.4.14F0V74556.852-143349.691.2.22
    Puppis51534141.5.482dF574756.671-121135.211.2.07
    Puppis61534541.5.18K3III74941.19-171342.421.2.16
    Puppis81534991.6.36F275140.862-12491.10.241.2.22
    Puppis91535001.5.170.4G0V:75146.29-135352.911.2.75
    Puppis101535201.5.69F1Ia75218.851-145046.661.2.22
    Puppis111748524.2.14F7II75651.53-225248.511.2.89
    Puppis121749325.11.14cK27591.5.05-231837.641.2.55
    Puppis141537961.6.13B3III8441.493-194341.131.2.94
    Puppis161538904.4.14B5IV891.1.07-191442.041.2.42
    Puppis181539241.5.5493F6V81039.879-134757.251.2.97
    Puppis191539421.4.7271G9III-IIIb81116.308-125536.921.2.12
    Puppis201539931.4.99G5II81319.957-154717.621.3.04
    Puppis211540761.6.16A2V81723.083-16171.6.451.2.73
    Puppis221541776.11.14gG782246.755-13316.841.2.03
    Pyxisalp1995461.3.68B1.5III84335.529-33111.10.941.2.88
    Pyxisbet1994901.3.9712.6.14G7Ib-II8401.6.15-351829.5.141.2.01
    Pyxisgam1765594.1.14K3-III85031.942-274235.711.3.13
    Pyxisdel1766971.4.8923.8.14A3IV85531.542-274055.161.2.87
    Pyxiseps 12000471.5.5917.6.14A4IV-V9956.428-302155.111.2.09
    Pyxiszet1762531.4.8952.4G4III83942.522-293340.381.2.51
    Pyxiseta1761891.5.2716A0V83752.18-261518.141.2.67
    Pyxisthe1773221.4.72M1III92129.608-255755.571.2.03
    Pyxiskap1770021.4.582.1.14K4III981.2.98-255130.8.141.2.77
    Pyxislam1773741.4.69G8.5IIICN-1.5*9231.12.62-28501.1.811.2.41
    Reticulumalp2489691.3.3548.5G8II-III41425.509-622825.6.141.1.92
    Reticulumbet2488771.3.851480K2+III3441.11.81-644825.321.2.77
    Reticulumgam2489251.4.51M4III4053.8-62934.171.2.37
    Reticulumdel2489181.4.56M2IIIab35844.736-61241.2.141.1.39
    Reticulumeps2334631.4.4413.8.14K2IVa41628.922-59181.7.131.1.13
    Reticulumzet 12487701.5.54309.6G2.5VFe1Hdel 131746.172-623431.461.2.35
    Reticulumzet 22487741.5.24309.6G1V3181.12.64-6230231.1.63
    Reticulumeta2490091.5.24G8III42153.361-632311.9.141.1.69
    Reticulumthe2489861.5.873.9.14B9III-IV41740.174-631520.9.141.1.37
    Reticulumiot2489271.4.97K4III4118.164-61443.931.1.96
    Reticulumkap2488191.4.7260F5IV-V32922.664-625615.291.1.25
    Sagittaalp5SHAM1051201.4.3790G1II19401.5.79+18049.691.2.81
    Sagittabet61051331.4.37G8IIIaCN0.519411.2.45+172833.541.2.93
    Sagittagam121055001.3.47M0-III195845.429+192931.821.2.16
    Sagittadel71052591.3.82M2II+A0V194723.277+18321.3.411.3.11
    Sagittaeps41050611.5.6688.9G8III193717.405+162746.121.2.74
    Sagittazet810529850.2A3V194858.674+19831.521.2.72
    Sagittaeta161056595.1.14K2III2051.9.82+195927.961.2.87
    Sagittathe17882761.6.4883.9F5IV20956.606+205454.531.2.36
    Sagitta1869871.5.64A4V191517.388+211355.911.2.25
    Sagitta21047971.6.25340.6A2III-IV192422.086+165616.11.141.2.23
    Sagitta91053601.6.23O7.5Iaf195221.757+184019.311.2.74
    Sagitta10S7100021054361.5.246.4.14F6Ib-G5Ib19561.1.83+16385.4.141.2.64
    Sagitta111054711.5.53B9III195745.435+164720.651.2.15
    Sagitta13VZ7100441055221.5.271.5.5728.5.14M4IIIa2001.3.18+173059.511.2.98
    Sagitta151056355.8.14203.7G1V2041.6.85+1741.12.191.2.16
    Sagitta18884331.6.13K1III201619.742+213555.171.3.76
    SagittariusalpALRAMI2296591.3.97B8V192353.172-403657.521.3.54
    Sagittariusbet 1ARKAB PRIOR2296464.1.1428.3.14B9V192238.276-442732.411.3.56
    Sagittariusbet 2ARKAB POSTERIOR2296541.4.29F2III192313.175-444758.961.3.47
    Sagittariusgam 1W7200061862371.4.291.5.140.1F4-G2Ib1851.1.77-293448.091.2.11
    Sagittariusgam 210ALNASL2096962081.2.99K0III18548.488-302526.661.2.94
    Sagittariusdel19KAUS MEDIA1866812102.7.1458.1K3-IIIa*182059.673-294941.391.3.99
    Sagittariuseps20KAUS AUSTRALIS2100912121.1.8536.1B9.5III18241.10.71-34234.9.141.2.51
    Sagittariuszet38ASCELLA1876002182.6.1450.5A2III+A4IV19236.71-295249.111.2.77
    Sagittariuseta2099572093.11.143.5.14M3.5III181737.642-364542.181.3.49
    Sagittariusthe 12117161.4.37B3IV195944.186-351634.751.2.91
    Sagittariusthe 22117175.3.1430A4/5IV195951.3-344152.431.3.41
    Sagittariusiot2299271.4.13K0II-III195515.669-41521.6.221.4.18
    Sagittariuskap 12301771.5.5952A0V202227.515-42258.894.1.14
    Sagittariuskap 22301841.5.640.6A5V202353.198-422522.3.141.3.59
    Sagittariuslam22KAUS BOREALIS1868412131.2.81K1+IIIb182758.249-252518.11.141.2.56
    Sagittariusmu131864971.3.86B8Iap181345.822-21331.751.2.62
    Sagittariusnu 132AIN AL RAMI1874261.4.832.5.14K2I+B9V:18541.10.02-224441.761.2.65
    Sagittariusnu 2351874451.4.99K3II-IIIBa0.8CN218551.7.15-224017.171.2.69
    Sagittariusxi 1361874985.8.14A0II185720.481-203922.911.2.09
    Sagittariusxi 2371875041.3.51K1III185743.796-21623.973.1.14
    Sagittariusomi391876431.3.7735.7G9IIIb19441.005-214429.671.2.07
    Sagittariuspi41ALBALDAH1877562211.2.8960.1F2II19945.839-21125.4.141.2.28
    Sagittariusrho 1441625121.3.93F0IV-V192140.371-175049.731.2.98
    Sagittariusrho 2451625211.5.87gG9192150.876-181830.191.2.64
    Sagittariussig34NUNKI1874482162.2.14309B2.5V185515.918-261748.211.3.11
    Sagittariustau401876832201.3.32K1+IIIb19656.414-274013.531.2.42
    Sagittariusups461625181.4.61B2Vpe+A2IaShell192143.629-155718.5.141.2.99
    Sagittariusphi271872392151.3.170.1B8III184539.383-265926.771.2.99
    Sagittariuschi 1471881015.3.140.1Am192516.514-243031.161.2.93
    Sagittariuschi 3491881051.5.43K4III192529.691-235744.271.2.32
    Sagittariuspsi421878821.4.850.1G8:III+A8V191532.445-251523.771.2.96
    Sagittariusome58TEREBELLUM1887224.7.14G5V195550.381-261757.881.2.94
    Sagittarius3X7200071857554.2.144.9.14F5-G2II174733.641-274950.81.2.15
    Sagittarius41860611.4.76B9V175947.571-234857.711.2.93
    Sagittarius61609981.6.28K3III18123.127-17924.811.2.43
    Sagittarius71861631.5.34F3III18251.109-241656.141.2.74
    Sagittarius91862041.5.97O4V((f))18352.448-242138.311.2.13
    Sagittarius111864371.4.9842.1K0III181143.359-23421.3.571.2.91
    Sagittarius141865091.5.44K3III181415.948-214247.371.3.23
    Sagittarius151865431.5.38B0Ia18151.12.26-204341.551.2.86
    Sagittarius161865441.5.956O9.5II18151.12.45-202316.591.2.35
    Sagittarius182101165.6.14K0III-IV18251.1.53-304523.571.2.44
    Sagittarius211867941.4.811.7.14K2II182521.021-2032301.2.31
    Sagittarius241869811.5.49K4Ib183353.517-24156.671.2.03
    Sagittarius251869951.6.51F3II-III183432.775-241320.571.2.29
    Sagittarius261871461.6.23Am184151.636-234959.971.3.76
    Sagittarius281872551.5.3713.7.14K4III184620.614-222332.021.2.05
    Sagittarius291873241.5.2416.6.14K4III184940.139-201928.8.142.1.14
    Sagittarius301873421.6.6121.1.14A7III185050.454-22943.561.2.07
    Sagittarius331874221.5.69K1Ib18540.104-212134.961.2.73
    Sagittarius431624131.4.96G8II-III191738.093-18571.10.811.2.53
    Sagittarius501881211.5.59K3III192619.126-214635.851.3.15
    Sagittarius511883261.5.65A7m19361.1.79-24431.8.521.2.67
    Sagittarius521883374.6.142.7.14B9193642.44-24530.731.2.91
    Sagittarius531884071.6.340.2B9.5V+A3IV193949.43-232539.551.2.12
    Sagittarius541628836.2.140.1K2III+F8V194043.386-161735.41.3.77
    Sagittarius551629155.6.140.2F1III194231.119-16726.521.2.35
    Sagittarius561629641.4.86K1III194621.734-194539.981.2.75
    Sagittarius571630601.5.92G5III19521.12.26-19241.881.2.92
    Sagittarius59TEREBELLUM1887421.4.52K2.5IIb195656.812-27101.11.561.2.46
    Sagittarius60TEREBELLUM1887781.4.83G6IIIBa0.2195857.225-261144.231.2.29
    Sagittarius611631415.2.14A3IV195757.028-152929.241.2.14
    Sagittarius62TEREBELLUMV38727238721888441.4.451.4.64M4III20239.502-274235.311.3.03
    Sagittarius631631951.5.71A3V20158.597-133813.4.141.2.61
    Sagittarius651632531.6.55A1Vn20526.355-123954.651.2.09
    Scorpiusalp 121ANTARES1844151770.962.9.14M1.5Iab-Ib+B4Ve162924.449-262555.171.2.14
    Scorpiusalp 23215.1.142.4.14162924-262603
    Scorpiusbet 18ACRAB1596821721.2.62101B1V16526.238-194819.371.2.58
    Scorpiusbet 281596831.4.92B2V16526.534-19487.7.141.2.36
    Scorpiusdel7DSCHUBBA1840141711.2.320.2B0.3IV16020.021-223718.1.141.2.28
    Scorpiuseps262080781831.2.29K2.5III16501.9.26-341735.821.2.89
    Scorpiuszet 12273751.4.73B1Iape165359.739-422143.551.3.44
    Scorpiuszet 22274021.3.62K4III165435.02-422141.31.3.68
    Scorpiuseta2277071891.3.33F3III-IVp17121.9.12-431420.781.3.21
    ScorpiustheGIRTAB2282012011.1.87F1II173719.157-425952.031.3.92
    Scorpiusiot 12284202043.3.1437.5F2Iae174735.095-40737.181.3.93
    Scorpiusiot 22284661.4.8132.6A2Ib17501.11.57-40526.6.141.3.14
    Scorpiuskap2091632021.2.41B1.5III174229.264-39148.281.3.22
    Scorpiuslam35SHAULA2089541991.1.6394.9B2IV+B173336.551-37613.611.3.46
    Scorpiusmu 12081021843.8.14390B1.5V+B6.5V165152.228-38251.021.3.61
    Scorpiusmu 22081161.3.57390B2IV165220.131-3811.3.131.3.33
    Scorpiusnu 114JABBAH1597644.1.1441.1B3V161159.728-192738.081.2.55
    Scorpiusnu 2141597636.3.1441.1B8V+B9VpSi161158.573-192658.711.2.43
    Scorpiusxi1596653191.4.7771.2.14F5IV16422.121-112223.5.141.2.56
    Scorpiusomi191843291.4.55A5II162038.19-24101.10.291.2.53
    Scorpiuspi61839871691.2.89B1V+B2V155851.124-26650.611.2.85
    Scorpiusrho51839571.3.8838.3B2IV-V155653.126-291250.081.2.87
    Scorpiussig20ALNIYAT1843361751.2.892B1III16211.11.15-253534.121.2.61
    Scorpiustau23ALNIYAT1844811791.2.82B0V163552.953-281257.761.2.39
    Scorpiusups34LESATH2088961961.2.69B2IV173045.843-371745.051.3.47
    Scorpiuschi171597931.5.22K3III161350.857-115015.451.2.26
    Scorpiuspsi151410221.4.94A3IV161159.998-10351.171.3.03
    Scorpiusome 191841231.3.96B1V16648.446-20401.8.981.2.17
    Scorpiusome 2101841351.4.32G3II-III16724.322-20521.6.971.2.84
    Scorpius11838541.4.64B3V155058.704-25451.4.721.2.77
    Scorpius21838961.4.592.3.14B2.5Vn155336.719-251937.911.2.11
    Scorpius3V09277309271839145.8.14B8IIIp(He weak)155439.508-251437.311.2.02
    Scorpius41839311.5.62A3V155530.054-261557.271.2.14
    Scorpius111597151.5.783.5.14B9.5Vnn16736.383-124443.821.2.13
    Scorpius121842171.5.673.9.14B9V161215.922-28251.2.571.2.81
    Scorpius131842211.4.59B2V161218.186-275535.121.2.58
    Scorpius161410241.5.43A4V16121.7.79-83251.21.2.24
    Scorpius181410665.5.1425.8.14G2Va161537.266-8221.10.471.2.23
    Scorpius221844291.4.79B2V16301.12.46-25654.441.2.14
    Scorpius251846301.6.71gG6164651.336-253143.011.2.48
    Scorpius272082321.5.48K5III165711.7.14-331533.571.2.02
    Sculptoralp1667161.4.31B7IIIp05836.342-292127.221.2.56
    Sculptorbet2146151.4.37B9.5IVpHgMnEu233258.268-37491.6.751.2.16
    Sculptorgam2144441.4.41K1III231849.464-3231551.2.02
    Sculptordel1921671.4.5774.3A0V234855.568-287491.3.25
    Sculptoreps1672751.5.314.9.14F1V14538.774-2531.9.591.2.21
    Sculptoreta1925451.4.81M4III02755.73-33025.781.2.87
    Sculptorthe1923881.5.25F4V01143.972-35758.941.3.61
    Sculptoriot1662071.5.18G5III02131.236-285853.523.2.14
    Sculptorkap 11660831.5.421.4.14F2V0920.993-275916.151.2.64
    Sculptorkap 21661031.5.4146K5III01134.447-274759.211.2.01
    Sculptorlam 11926906.6.140.6A0V04242.887-382747.771.2.76
    Sculptorlam 21927035.9.14K1III0441.12.72-382518.2.141.2.36
    Sculptormu2147011.5.31K1III234038.139-32423.321.2.07
    Sculptorxi1928701.5.59K0III1118.388-385459.051.2.89
    Sculptorpi1932631.5.25K0III1421.8.53-321937.121.2.46
    Sculptorsig1928845.5.14A2V1226.41-31331.7.381.2.46
    Sculptortau1932011.5.690.9F2V1361.8.41-295426.521.2.75
    Scutumalp1424081.3.85K3-III-IIIb18351.12.41-81438.511.2.51
    Scutumbet1426181.4.22G4IIa18471.10.81-44452.41.2.52
    Scutumgam1615204.7.14A3Vn18291.11.63-143357.041.3.46
    Scutumdel1425151.4.7252.6F2IIIpDel Del184216.434-931.9.191.2.72
    Scutumeps1425464.9.1437.6G8IIb184331.271-81630.791.2.59
    Scutumzet1422671.4.68G9-IIIbFe-0.5182339.54-8561.3.411.3.35
    Scutumeta1428381.4.83K2III18571.3.69-55046.261.3.17
    Serpensalp24UNUKALHAI1211571671.2.6558.2K2IIIbCN1154416.092+62532.341.2.75
    Serpensbet281017251.3.6730.6.14A2IV15461.11.76+152518.541.2.36
    Serpensgam411018261.3.85201.5F6V155627.189+153941.981.2.13
    Serpensdel 1131016243173.8.143.9.14F0IV153448.146+103220.951.2.66
    Serpensdel 2131016233.8.143.9.14F0IV153448.099+103214.942.4.14
    Serpenseps371212181.3.71A2Vm155048.965+42839.941.2.66
    Serpenszet571420251.4.62F2IV18028.961-34124.951.2.79
    Serpenseta581422412111.3.26179.7K0III-IV182118.595-25355.681.2.57
    Serpensthe 163ALYA1240681.4.6222.2.14A5V185613.192+4121.12.922.6.14
    Serpensthe 2631240701.4.9822.2.14A5Vn185614.638+4121.7.231.2.86
    Serpensiot211016821.4.520.1A1V154133.074+194013.131.2.79
    Serpenskap351017524.9.14M0.5IIIab154844.397+18829.621.2.57
    Serpenslam271211861.4.43G0-V154626.606+7211.11.431.2.58
    Serpensmu321407871.3.53A0V154937.22-32548.941.2.12
    Serpensnu531604791.4.3346.3A2V172049.657-125048.261.2.22
    Serpensxi551607001.3.5422F0IVDel Sct173735.2-152354.831.2.01
    Serpensomi561607471.4.26A2V174124.888-125230.941.2.81
    Serpenspi44841551.4.83A3V16217.748+224815.661.2.51
    Serpensrho38840371.4.76K5-III155115.916+205840.31.2.97
    Serpenssig501215401.4.82F0V16221.4.55+1144.521.2.05
    Serpenstau 191015451.5.17M1III152547.396+152540.741.2.67
    Serpenstau 2121016001.6.22B9V15321.9.94+16322.341.2.52
    Serpenstau 3151016316.12.14gG8153533.232+173920.4.141.2.32
    Serpenstau 5181016421.5.93F3V153629.258+1671.8.291.2.19
    Serpenstau 6191016786.1.14G8III154059.163+16128.971.2.32
    Serpenstau 7221016861.5.81A2m154154.697+182750.271.2.79
    Serpenstau 8261017121.6.140.1A0V154442.14+171550.791.2.54
    Serpensups311017391.5.71A3V154717.315+14654.871.2.33
    Serpensphi1018341.5.54K1IV155714.574+142451.981.2.47
    Serpenschi201016831.5.33A0pSr154147.43+125050.561.2.62
    Serpenspsi231211521.5.88370G2.5V15441.1.52+23054.451.2.15
    Serpensome341212151.5.23G8III155017.548+21147.11.2.97
    Serpens31209161.5.33K0III15151.11.72+45621.571.2.66
    Serpens41209201.5.63A4V151549.082+02219.971.2.95
    Serpens5MQ7602791209465.6.1411.2.14F8III-IV151918.807+14555.411.2.03
    Serpens61209551.5.353.1.14K3III15211.1.98+04255.021.2.96
    Serpens71015081.6.28A0V152223.258+12341.2.541.2.15
    Serpens81405026.12.14F0V152343.716-1120.661.2.49
    Serpens101210201.5.17A8IV152838.231+15030.8.141.2.09
    Serpens111405961.5.51K0III153257.979-1111.10.491.2.01
    Serpens141406431.6.51G8III+A153633.682-03341.721.2.44
    Serpens161016401.5.26K0III:CN1Ba0.7Sr2153629.605+10035.951.2.34
    Serpens251407405.4.14B8III15461.5.03-14815.721.2.15
    Serpens361408015.11.140.1A3Vnp155115.589-3525.991.2.29
    Serpens391017926.1.1498.3G0VFe-0.515531.12.08+131148.431.2.36
    Serpens40FP7601791212541.6.28A7Vn155440.266+83448.941.2.75
    Serpens431213396.8.1430.8.14G9III16345.653+45912.1.141.2.22
    Serpens451019391.5.63A7V16737.561+95330.181.2.43
    Serpens47FS7601821213831.5.681.5.73M3.5IIIa16828.037+8321.3.142.1.14
    Serpens59D7691041234971.5.213.8.14G0III+A6V18271.12.56+01146.471.2.51
    Serpens601423481.5.39K0III182940.989-1597.12.141.2.14
    Serpens611423721.5.94A4III183156.997-101.10.941.2.93
    Serpens641240891.5.57B9IIIep:Hg:185716.588+2321.7.221.2.22
    Sextansalp151373661.4.49A0III10756.28-02218.2.141.2.92
    Sextansbet301376085.9.14B6V103017.49-03813.241.2.83
    Sextansgam81371995.5.140.4A1V95230.449-8617.6.141.2.29
    Sextansdel291376001.5.21B9.5V102928.703-24420.841.2.03
    Sextanseps221374691.5.24F2III101737.801-848.12.141.2.54
    Sextans41179371.6.24F7Vn95030.074+42036.51.2.49
    Sextans61371836.1.14A8III95114.025-41436.141.2.38
    Sextans71179596.2.14A0V s9521.12.72+22714.531.2.57
    Sextans121180416.7.14F0V95943.074+3231.4.961.2.77
    Sextans131180861.6.45F4V1041.8.24+3121.3.751.2.07
    Sextans141181111.6.21K1III10647.429+53641.221.2.74
    Sextans171373851.5.91A1V10101.7.44-82429.581.2.28
    Sextans181373951.5.65K2III101055.814-8251.6.341.2.55
    Sextans191181641.5.77gK0101248.347+43652.692.9.14
    Sextans23RS7700111182481.6.641.6.68B2.5IV10211.2.11+21722.761.2.31
    Sextans25SS7700191375331.5.941.5.98B9p(Si-Sr-Cr)102326.483-4426.661.2.58
    Sextans331377281.6.26K1IV104124.19-14429.551.2.06
    Sextans351184491.5.796.7.14K3III+K0III104320.922+44451.891.2.35
    Sextans361184731.6.28K4III10451.9.28+22916.511.2.73
    Sextans401378081.6.612.2.14A2IV104917.292-4126.931.2.66
    Sextans411378231.5.7927.3.14A3m105018.057-85351.821.2.18
    Taurusalp87ALDEBARAN94027330.85121.7K5+III43555.243+163033.361.2.65
    Taurusbet112ALNATH77168451.1.6533.4B7III52617.516+283626.631.2.83
    Taurusgam54HYADUM I938681.3.65K0-IIIabCN141947.608+153739.351.2.75
    Taurusdel 161HYADUM II938971.3.76109.6K0-IIICN0.542256.093+173232.981.2.97
    Taurusdel 264939074.8.14143A7V4241.5.68+172638.291.2.24
    Taurusdel 368V0776780776939231.4.291.4.321.5.14A2/3IV/Vm42529.384+175541.261.2.45
    Tauruseps74AIN939541.3.53181.6G9.5IIICN0.542836.999+191049.491.2.96
    Tauruszet12377336513B4IIIpe53738.681+21833.031.2.26
    Tauruseta25ALCYONE76199271.2.87B7IIIe34729.074+24618.331.2.17
    Taurusthe 177939551.3.84337.4K0IIIbFe-0.542834.479+155743.831.2.72
    Taurusthe 278939573.4.14337.4A7III42839.715+155215.231.3.86
    Taurusiot102769201.4.640.1A7V531.5.34+213523.761.2.05
    Tauruskap 165766011.4.220.1A7IV-V42522.12.14+221737.631.2.07
    Tauruskap 267766021.5.280.1A7V42525+221159.191.2.57
    Tauruslam35937191.3.47B3V+A4IV4040.822+122925.331.2.24
    Taurusmu491116961.4.29B3IV41532.068+85332.351.2.88
    Taurusnu381115791.3.91A1V431.9.72+55921.511.2.08
    Taurusxi21111951.3.74B9Vn3271.10.16+94357.761.2.16
    Taurusomi11111723.6.14G6IIIFe-132448.8+9143.841.2.18
    Tauruspi73939351.4.69G7IIIaFe-142636.412+144249.481.2.59
    Taurusrho86940071.4.65A8V43350.899+145039.831.2.04
    Taurussig 191940515.7.14431.2A4m4391.9.29+154759.351.2.51
    Taurussig 292940541.4.69431.2A5Vn43916.493+15551.4.991.2.84
    Taurustau94767211.4.280.1B3V44214.699+225724.811.3.25
    Taurusups69766081.4.28A8Vn42618.442+224848.761.2.34
    Taurusphi52765582811.4.9550K1III42021.251+27211.2.561.2.37
    Tauruschi59765731.5.3719.4.14B9V42234.919+253744.991.2.31
    Tauruspsi42764611.5.23F1V470.475+2901.4.531.2.76
    Taurusome 143937855.5.14K2III491.9.77+193633.21.2.55
    Taurusome 250765321.4.940.1A3m41715.643+203442.921.2.97
    Taurus4934631.5.14A0Vn33024.496+11201.11.181.2.33
    Taurus5934694.11.14K0II-IIIFe-0.533052.389+125612.11.141.2.17
    Taurus61112461.5.77B9IV33235.975+92224.681.3.31
    Taurus7759992751.5.9270.7A3V+A3V33426.632+242752.381.2.98
    Taurus9V0486780486760291.6.651.6.78A0p(Cr-Sr-Eu)33658.025+231239.381.2.91
    Taurus101112921.4.28396F9IV-V33652.374+0245.9.141.2.64
    Taurus11760736.11.14A2IV34046.308+251946.451.2.91
    Taurus121113341.5.57gG633951.134+3324.583.12.14
    Taurus13935571.5.69B9Vne34218.931+19421.8.141.2.16
    Taurus14935681.6.14G8III34347.21+193954.31.2.45
    Taurus16CELAENO761261.5.46B7IV34448.171+241722.9.141.2.59
    Taurus17ELECTRA761313.7.14B6III34452.524+24648.151.2.77
    Taurus18761371.5.640.1B8V3451.9.35+245021.231.2.85
    Taurus19TAYGETA761404.3.14B6IV3451.12.76+24282.5.141.2.58
    Taurus20MAIA761551.3.87B8III34549.595+24221.3.851.2.24
    Taurus21ASTEROPE761591.5.76B8V34554.404+243316.761.2.99
    Taurus22STEROPE II761641.6.430.1A0Vn3461.2.68+243140.532.8.14
    Taurus23MEROPE761721.4.18B6IVe34619.589+235654.061.3.34
    Taurus26762256.6.14F034856.97+235126.141.2.63
    Taurus27ATLAS762281.3.63B8III3491.9.35+2431.12.341.2.16
    Taurus28PLEIONEBU780098762291.4.775.5.14B8Vne3491.11.18+2481.11.961.3.41
    Taurus291114001.5.3566.2B3V34540.428+630.191.2.34
    Taurus30936115.7.149.2.14B3V+F5V34816.288+11836.271.2.58
    Taurus311114691.5.670.6B5V3520.23+6321.5.351.2.28
    Taurus32763391.5.63F2IV35652.057+222841.191.2.28
    Taurus33763436.6.14B9.5IV3571.3.82+231031.561.3.01
    Taurus36764251.5.47G0III+A4V4421.653+24621.261.2.67
    Taurus37764301.4.36137.2K0+III-IIIaFe-0.24441.717+22454.931.2.96
    Taurus39764385.9.14170.1G5V4520.235+22031.541.2.25
    Taurus401115851.5.33B3V4344.609+5268.12.141.2.33
    Taurus41GS780201764551.5.151.5.22B9p(Si)4636.4+273559.611.2.23
    Taurus44IM780230764851.5.371.5.58F2IV-V41049.859+262851.21.2.08
    Taurus451116481.5.72124.1F4V41120.292+53123.9.141.2.93
    Taurus461116721.5.290.1F2V+F5V41333.108+74257.81.2.72
    Taurus471116741.4.841.2.14G5III+A7V?41356.393+91549.351.2.54
    Taurus48938361.6.32151.4F5V41546.294+15241.1.811.2.72
    Taurus51765411.5.650.1F0V41823.193+213445.491.2.99
    Taurus53765481.5.35B9IV41926.123+21832.451.2.88
    Taurus55938706.9.14G041954.863+163120.741.3.31
    Taurus56V0724780724765511.5.365.4.14A0p(Si)41936.718+214624.881.2.98
    Taurus57V0483780483938721.5.551.5.5934.9F0IV41957.688+1421.6.661.2.65
    Taurus58V0696780696938761.5.221.5.28A9/F0IV-V42036.313+15543.461.2.01
    Taurus60V0775780775938921.5.72109.2A3m4221.3.07+14437.61.2.44
    Taurus62765911.6.3629.1.14B3V42359.774+24181.3.721.3.29
    Taurus63939001.5.64A1m42325.046+164638.011.2.49
    Taurus661117915.12.140.3A3V42351.859+92739.381.3.37
    Taurus70939251.6.460.1F7V42537.333+155627.211.2.49
    Taurus71V0777780777939321.4.730.1A8Vn/F0V42620.713+15371.7.871.3.74
    Taurus72766131.5.53B7V42717.486+225946.691.2.96
    Taurus75939501.4.97K2III42826.378+162135.491.2.61
    Taurus76939485.9.14F0IV42823.437+144427.271.3.08
    Taurus79939605.3.14A7V42850.213+13251.51.2.94
    Taurus80939701.5.581.7.14F0V4301.8.93+153817.151.2.04
    Taurus81939781.5.48162A5m43038.891+154130.841.3.15
    Taurus83939795.4.14111.9F0V43037.349+134327.751.2.57
    Taurus84939836.6.14M04311.7.08+15618.561.3.93
    Taurus85939936.2.14F4V43151.752+15511.5.881.3.36
    Taurus88940261.4.2569.7A5m43539.269+10939.121.2.92
    Taurus89940431.5.79140.5F0V4381.9.41+1620.311.2.65
    Taurus90940441.4.27119.8A6V4381.9.44+123039.281.2.49
    Taurus93940631.5.46B8IV4401.3.98+121151.81.2.77
    Taurus95767271.6.13F7IV-V44313.781+24519.821.2.84
    Taurus96941516.8.1429.3.14gK344944.086+155414.931.2.76
    Taurus97V0480780480941645.9.141.5.13177A7IV/V-A9IIIn45122.47+185023.371.2.63
    Taurus98768621.5.8194.6A0V4581.9.22+2531.1.151.2.67
    Taurus99768581.5.79103.5gG845748.691+235655.271.2.36
    Taurus101942486.7.14F545944.348+15551.12.141.2.22
    Taurus103769745.5.1435.3B2V581.6.23+241554.691.2.08
    Taurus1049433250.1G4V5727.014+183841.941.2.41
    Taurus105769721.5.890.3B2Ve5755.488+214217.371.3.48
    Taurus106769715.3.14A5V5748.397+20255.9.141.2.69
    Taurus108770571.6.271.9.14A2V51527.672+22175.8.141.3.13
    Taurus109770971.4.94G8III51916.581+22547.341.2.86
    Taurus110945146.8.14A2IV52337.695+164157.651.2.07
    Taurus111945261.4.9985.7F8V52425.446+17230.441.2.67
    Taurus113945431.6.25B2Vn5261.5.74+16420.761.2.22
    Taurus114771841.4.880.1B2.5IV52738.082+215613.2.141.2.99
    Taurus115945541.5.420.1B5V5271.10.83+175743.711.2.24
    Taurus116945665.5.14B9.5Vn52745.631+155226.8.141.2.09
    Taurus117945731.5.77M1III5281.1.39+171420.351.2.57
    Taurus118772011.5.474.8.14B8.5V52916.514+2591.1.671.2.64
    Taurus119CE780106946281.4.231.4.54M2Iab-Ib5321.12.78+183539.511.2.91
    Taurus120946491.5.69B2IV-Ve53331.621+183224.821.3.31
    Taurus121772851.5.38B2.5IV53527.085+24222.891.3.97
    Taurus122947001.5.54F0V5371.3.61+17225.271.3.66
    Taurus125773601.5.18B3IV53944.251+255349.471.2.21
    Taurus126947591.4.860.4B3IV54117.735+16322.4.141.2.47
    Taurus129948486B8IIIpHgMn:54645.496+154920.821.2.73
    Taurus130948581.5.49F0III54726.189+174344.751.2.54
    Taurus131948551.5.72A3Vn54713.182+142918.181.2.64
    Taurus132775921.4.860.1G8III5490.964+24341.2.581.2.72
    Taurus133948641.5.2924.9.14B2IV-V54742.978+135358.41.2.12
    Taurus134948881.4.9118.9.14B9IV54932.946+12391.4.291.2.48
    Taurus135949041.5.52gG955028.881+141820.441.2.94
    Taurus136776751.4.58A0V55319.654+273643.81.3.04
    Taurus137V0809780809949451.5.59B9p(Si-Eu-Cr)55222.283+141018.261.2.83
    Taurus139777751.4.82B0.5II55759.674+255714.3.141.3.69
    Telescopiumalp2290231.3.51B3IV182658.432-45581.5.881.3.19
    Telescopiumdel 12290921.4.96B6IV183145.389-455453.81.3.24
    Telescopiumdel 22290955.7.14B3III18321.1.82-454526.191.3.41
    Telescopiumeps2287771.4.5321.2.14K0III181113.78-455715.441.3.24
    Telescopiumzet2290471.4.13G8-K0III182849.916-49415.331.3.58
    Telescopiumeta2460555.5.14A0Vn192251.106-542525.1.141.3.21
    Telescopiumiot2297514.9.14K0III19351.12.44-48557.333.4.14
    Telescopiumkap2457721.5.17G8-K0III185239.583-52626.981.3.34
    Telescopiumlam2458341.4.87A0V185827.74-525618.461.3.95
    Telescopiummu2461316.3.14F5V193034.519-55636.321.3.88
    Telescopiumnu2462711.5.35A7III-IV19481.1.01-562145.51.3.26
    Telescopiumxi2464431.4.94M1IIab20723.188-525251.041.3.67
    Telescopiumrho2459211.5.16F7V19619.935-522027.431.4.21
    Triangulumalp2MOTHALLAH749961.3.41222.3F6IV1531.4.99+293443.941.2.42
    Triangulumbet455306183A5III2932.615+345914.161.2.83
    Triangulumgam9554274.1.14A1Vnn21718.869+335050.161.2.43
    Triangulumdel8554201.4.8765.4G0.5V2171.3.24+341327.4.141.3.65
    Triangulumeps3552185.5.144.2.14A2V2257.954+33171.2.361.2.97
    Triangulum5553381.6.23A1m21125.051+313135.071.2.37
    Triangulum6TZ800033553472671.5.193.8.14G5III+G5III:21222.279+30181.10.721.2.27
    Triangulum7553971.5.28A0V21556.249+332131.611.2.28
    Triangulum10752765.3.1457.1A2V21857.019+283833.11.2.21
    Triangulum11555701.5.54gK122727.735+31481.4.761.3.26
    Triangulum12753821.5.29F0III2281.9.79+29401.9.651.2.52
    Triangulum13753911.5.89G0V22848.47+295554.81.2.06
    Triangulum14556351.5.15K5III2321.6.68+36850.291.2.77
    Triangulum15556871.5.35141.3M3IIIa23546.823+344115.421.2.83
    Triangulum AustralealpATRIA2537001821.1.92K2IIb-IIIa164839.936-69139.561.4.96
    Triangulum Australebet2533461681.2.85155F2III15551.8.33-632550.131.3.38
    Triangulum Australegam2530971611.2.89A1V151854.58-684045.981.3.52
    Triangulum Australedel2534741.3.8530G2Ib-IIa161526.267-63411.8.381.3.69
    Triangulum Australeeps2532264.11.1483.2K1-2III153643.185-66191.1.971.3.96
    Triangulum Australezet2535541.4.91F9V162828.12.14-7051.4.181.4.31
    Triangulum Australeeta 12536491.5.91B7IVe164123.299-681746.051.4.83
    Triangulum Australethe2536141.5.52G8-K0III163544.737-652944.431.3.95
    Triangulum Australeiot2535551.5.2719.6.14F4IV162757.25-64328.551.3.47
    Triangulum Australekap2533425.9.14G5IIa155529.525-68361.11.291.3.86
    Tucanaalp2551932431.2.860.1K3III221830.192-601534.531.3.23
    Tucanabet 12482011.4.3727B9V03132.739-625729.311.2.44
    Tucanabet 22482021.4.5427A2V+A7V03133.571-625756.531.2.16
    Tucanabet 32482085.9.140.1A0V03243.848-63152.281.3.17
    Tucanagam2478141.3.99F1III231725.766-58148.11.141.2.59
    Tucanadel2552221.4.486.9.14B9.5V222720.002-645759.311.3.66
    Tucanaeps2556194.5.14B9IV235955.004-653437.61.3.75
    Tucanazet2481631.4.23F9V0201.4.25-645229.291.2.19
    Tucanaeta2556095A1V235735.166-641754.261.2.99
    Tucanathe2556791.6.13A7IV03323.368-711559.291.3.17
    Tucanaiot2483241.5.37G5III1718.676-614630.811.2.13
    Tucanakap2483461.4.865.2.14F6IV11546.123-685233.671.2.01
    Tucanalam 12482691.6.2220.6.14F7IV-V05224.313-693015.551.2.06
    Tucanalam 22482811.5.45K2III0550.26-693137.361.2.82
    Tucananu2552471.4.81M4III22330.035-615856.161.3.91
    Tucanapi2481671.5.51B9V02038.822-693729.921.2.52
    Tucanarho2482371.5.39F6V04228.361-65281.4.521.2.86
    Ursa Majoralp50DUBHE153841091.1.7930.5K0IIIa11343.695+61451.3.171.2.24
    Ursa Majorbet48MERAK278761081.2.37A1V11150.49+562256.571.2.23
    Ursa Majorgam64PHAD281791151.2.44A0Ve115349.835+534141.151.2.79
    Ursa Majordel69MEGREZ283151191.3.31189.6A3V121525.57+57157.351.2.93
    Ursa Majoreps77ALIOTH285531321.1.77A0pCr12541.1.57+555735.551.2.73
    Ursa Majorzet 179MIZAR287371371.2.2713.8.14A1VpSrSi132355.55+545531.391.2.27
    Ursa Majorzet 279287383051.3.9514.4.14A1m132356.416+545518.181.2.26
    Ursa Majoreta85ALKAID447521401.1.86B3V134732.44+491848.061.2.19
    Ursa Majorthe2527289971.3.174.1.14F6IV93251.414+514038.391.3.87
    Ursa Majoriot9TALITHA42630891.3.143.9.14A7IV8591.12.52+48229.761.3.52
    Ursa Majorkap12426613.6.140.3A1Vn9337.529+47923.711.3.05
    Ursa Majorlam33TANIA BOREALIS432681.3.45A2IV10171.5.99+425451.781.2.54
    Ursa Majormu34TANIA AUSTRALIS433101033.5.14M0III102219.744+412958.281.2.36
    Ursa Majornu54ALULA BOREALIS624861.3.487.2.14K3-IIIBa0.3111828.735+33539.41.2.11
    Ursa Majorxi53ALULA AUSTRALIS624842971.4.41133.1.14G0V11181.10.38+313145.241.2.46
    Ursa Majoromi1MUSCIDA145731.3.36143G5III83015.883+60431.5.471.3.72
    Ursa Majorpi 13MUSCIDA146091.5.64G1.5Vb8391.11.48+65115.381.3.45
    Ursa Majorpi 24MUSCIDA146164.6.14K1+IIIb8401.12.45+641940.631.3.52
    Ursa Majorrho8147421.4.76M3III-IIIbCa19232.718+673746.651.3.87
    Ursa Majorsig 111147691.5.14K5III9823.583+665223.861.3.16
    Ursa Majorsig 213147884.8.142.8.14F6IV91023.177+6781.4.521.3.95
    Ursa Majortau14147961.4.6757.2F3-4IIIm vs91055.077+633048.671.3.74
    Ursa Majorups29274013.8.1411.3.14F2IV95059.376+59219.491.3.58
    Ursa Majorphi30274081.4.590.3A3IV9521.6.56+54351.611.3.92
    Ursa Majorchi63438861.3.71K0.5IIIb11461.3.29+474645.831.2.67
    Ursa Majorpsi52436291103.1.14K1III11939.785+442954.651.2.48
    Ursa Majorome45435121.4.71A1V s105358.746+431123.851.2.16
    Ursa Major2145901.5.47A2m83436.235+65842.431.3.73
    Ursa Major5146911.5.73F2III85322.557+615744.351.3.49
    Ursa Major6147031.5.58G7IIIFe-0.585637.533+643614.411.3.92
    Ursa Major15271361.4.48F0IVm vs9852.27+513616.353.8.14
    Ursa Major16148191.5.13F9V91420.65+612523.9.141.3.87
    Ursa Major17271851.5.27K5III91549.886+564428.561.3.04
    Ursa Major18DD830127271915.2.14A5V9161.11.67+54118.671.3.54
    Ursa Major2268981.5.72F7V93453.582+721220.8.141.3.12
    Ursa Major23149081.3.6722.8.14F0IV93131.721+63342.741.3.41
    Ursa Major24DK83013368971.4.56G4III-IV93428.887+694949.421.3.27
    Ursa Major26272984.5.14A2V93449.459+5231.5.311.3.66
    Ursa Major2769361.5.17K0III94257.194+72151.9.281.3.02
    Ursa Major28149801.6.346.4.14F2V94555.43+63391.11.851.3.63
    Ursa Major31SY830025274301.5.27A3III95542.986+49491.11.711.2.53
    Ursa Major32151351.5.82A8III10181.2.65+65630.141.3.52
    Ursa Major35151961.6.32gK2102954.332+653734.211.3.09
    Ursa Major36276701.4.84139F8V103037.578+555850.052.4.14
    Ursa Major37276951.5.16F1V10351.9.02+57457.551.2.26
    Ursa Major38152615.12.14K2III104156.602+654258.671.3.51
    Ursa Major39277485.8.14A0V s104343.339+571157.041.2.35
    Ursa Major41277601.6.34M1III104622.453+572156.661.2.14
    Ursa Major42277931.5.58K2III105123.721+59191.11.831.2.37
    Ursa Major43277911.5.67K2III10511.11.92+563455.931.2.74
    Ursa Major44278155.1.14K3III105334.411+54351.6.411.2.05
    Ursa Major46623145.3.14K1III105544.39+333024.961.2.38
    Ursa Major47435575.5.14G1-VFe-0.5105927.969+402548.911.2.98
    Ursa Major49623545.8.14F0V s11050.385+391243.591.2.11
    Ursa Major516238768.4.14A3III-IV11431.183+381429.141.2.38
    Ursa Major55624911.4.78A1Vp:11191.7.11+38111.7.881.2.81
    Ursa Major56437191.4.99G7.5IIIa:Ba0.3112249.603+432858.031.2.01
    Ursa Major57625721.5.31346.3A2V11291.4.62+392013.1.141.2.52
    Ursa Major58437871.5.94F4V113031.119+431023.581.2.07
    Ursa Major59438371.5.59F2II-III113820.58+433731.5.141.2.97
    Ursa Major60438396.1.14F5III s113833.482+46501.3.721.2.71
    Ursa Major61626551.5.33159.3G8V11411.3.24+34121.5.621.2.58
    Ursa Major62626581.5.7384.3F4V114134.3+314445.311.2.87
    Ursa Major65DN830136439451.6.631.6.7363A3Vn11551.5.67+462836.931.2.47
    Ursa Major65439467.3.1463A1pCrEuSr:11551.11.61+46281.11.151.2.96
    Ursa Major66281911.5.84K1III115558.409+563554.861.2.04
    Ursa Major67DP830138440021.5.21310.5A7m1221.6.38+43244.581.2.22
    Ursa Major68282911.6.43gK5121144.876+57316.12.141.2.35
    Ursa Major70283461.5.55K5III122050.801+575150.431.2.05
    Ursa Major71283751.5.81M3IIIb12251.3.19+564639.491.2.26
    Ursa Major73283945.7.14M2IIIb122735.08+554245.861.2.78
    Ursa Major74284051.5.35A5Del Del122957.328+582420.811.2.58
    Ursa Major75284086.8.14G8III-IV12301.4.87+58461.2.941.2.72
    Ursa Major76158716.7.14A2III124133.89+624246.941.2.82
    Ursa Major78286011.4.931.3.14F2V13043.816+562159.141.2.54
    Ursa Major80ALCOR287514.1.14A5V132513.498+545917.151.2.92
    Ursa Major81288035.6.14A0V13341.7.97+552054.681.2.26
    Ursa Major82288321.5.46A3Vn133930.393+525516.731.2.13
    Ursa Major83288431.4.66M2IIIabBa0.5134044.239+544054.261.2.62
    Ursa Major84CR830118288851.5.655.7.14B9p(Eu-Cr)134635.652+542558.021.2.13
    Ursa Major86289285.7.14A0V135351.005+534343.381.2.65
    Ursa Minoralp 11POLARIS308192.2.1418.4.14F7:Ib-II23148.711+891550.6431.189
    Ursa Minoralp 22618.6.1417.4.1423048+89150371.436
    Ursa Minorbet7KOCAB81021562.8.14209.1K4-III145042.375+74919.740.679
    Ursa Minorgam13PHERKAD82201633.5.14A3II-III152043.726+71501.2.530.932
    Ursa Minordel23YILDUN29371.4.36A1Vn17321.12.83+86351.11.451.11.56
    Ursa Minoreps2227701.4.2376.9G5III164558.124+82214.321.1.88
    Ursa Minorzet1683281.4.32A3Vn15441.3.17+774740.180.352
    Ursa Minoreta2184701.4.95227F5V161730.369+754518.730.669
    Ursa Minorthe1582741.4.96K5III153124.913+772057.630.232
    Ursa Minorlam30201.6.3854.7M1III171656.893+89215.6339.778
    Ursa Minor379531.6.45A7V14656.221+743537.651.1.19
    Ursa Minor479581.4.82K3III14850.92+773250.890.746
    Ursa Minor580241.4.2558.8K4-IIIBa0.3142731.523+754145.570.913
    Ursa Minor11PHERKAD MINOR82075.2.14K4III15171.5.41+714925.970.65
    Ursa Minor1984461.5.48B8V161049.538+755239.240.517
    Ursa Minor2084521.6.39K2IV161232.164+751238.160.366
    Ursa Minor2429401.5.79A2m173048+86585.1.1413
    Velagam 12195011.4.2741.2B1IV8929.292-472044.541.1.48
    Velagam 2SUHAIL AL MUHLIF219504851.1.7841.2WC8+O9I8931.99-472012.4.141.2.08
    Veladel236232871.1.962.2.14A1V84442.239-544229.861.1.37
    Velakap236891942.5.14B2IV-V9221.6.48-55038.521.1.49
    VelalamSUHAIL220878901.2.2118.2.14K4.5Ib-II9759.8-432557.221.2.95
    Velamu2223211061.2.691.7.14G5III+G2V104646.194-49251.12.291.2.57
    VelaomiO2361641.3.62B3IV84017.644-525519.3.141.1.46
    Velaphi2375221.3.5437.2B5Ib95651.753-54341.3.781.2.39
    Velapsi2212343.6.140.7F3IV+F0IV93042.014-40280.161.2.04
    Virgoalp67SPICA1579231380.98B1III-IV+B2V13251.11.01-11940.641.2.18
    Virgobet5ZAVIJAVA1190761.3.61512.3F9V115041.726+14552.91.2.34
    Virgogam 129PORIRIMA1389171291.3.654.1.14F0V124139.598-12657.712.9.14
    Virgogam 23031.3.683F0V124139.6-126582.9.14
    Virgodel43AUVA1196741.3.38164.5M3+III125536.218+32350.712.6.14
    Virgoeps47VINDEMIATRIX1003841341.2.83248.7G8IIIab1321.10.99+105732.981.2.88
    Virgozet79HEZE1394201.3.37A3V133441.593-03545.671.2.41
    Virgoeta15ZANIAH1387211.3.89A2IV121954.366-0400.491.2.92
    Virgothe511391891.4.380.5A1IV s+Am13957.005-53220.361.2.77
    Virgoiot99SYRMA1398244.8.14F6III14160.916-601.1.641.2.29
    Virgokap981584271.4.19K2.5IIIFe-0.5141253.757-101625.361.2.76
    Virgolam1001584891.4.52A2m14191.6.93-132216.5.141.2.62
    Virgomu107RIJL AS AWWA1400901.3.88F2III14431.3.63-53929.631.2.49
    Virgonu31190354.3.14M1IIIab114551.557+63145.631.2.99
    Virgoxi21190291.4.85A4V114517.059+81529.841.2.19
    Virgoomi91192134.12.14G8IIIaCN-1Ba1CH11251.12.43+84358.641.2.36
    Virgopi81191641.4.66A5V12052.388+63651.431.2.02
    Virgorho301002111.4.88A0V124153.075+10141.8.131.2.73
    Virgosig601198554.8.14M1III131736.29+52811.6.141.2.81
    Virgotau931202381.4.26129A3V14138.801+13240.241.2.72
    Virgoups1021398661.5.14G9III141932.49-21555.611.2.24
    Virgophi1051399511.4.815.1.14G2IV14281.12.15-21340.631.2.63
    Virgochi261388921.4.66173.1K2III-IIIbCN1123914.78-75944.321.2.08
    Virgopsi401390331.4.79M3-IIICa-1125421.167-93220.191.2.16
    Virgoome11189651.5.36M4III113827.588+881.3.431.2.98
    Virgo41190581.5.32150.2A1114754.891+81445.361.2.34
    Virgo61191111.5.58gK011551.3.58+82638.291.2.13
    Virgo71191561.5.37A1V115956.916+33918.331.2.25
    Virgo101192451.5.9539.5K3III12941.325+15352.411.2.35
    Virgo111192491.5.72F2-6IIIm vs12101.3.19+54825.341.2.86
    Virgo12999971.5.85A2m121325.921+101543.711.2.95
    Virgo131387105.9.14A5Vn121840.275-04713.9.141.2.82
    Virgo161193411.4.960.6K0-IIIbFe-1122020.993+31845.011.2.62
    Virgo171193606.4.1420.6.14F8V122232.038+51819.531.2.36
    Virgo201001461.6.26G8III12331.2.63+101744.291.2.28
    Virgo211388451.5.48A0V123346.761-9271.6.911.2.93
    Virgo251388731.5.87A3V123647.349-54954.721.2.39
    Virgo27GG8601901002071.6.191.6.3385.5A7V124134.363+102535.031.2.24
    Virgo311195381.5.594A2V124157.136+64823.921.2.19
    Virgo32FM8601761195745.2.141.5.28F0IVm+A7V124537.058+74023.861.2.99
    Virgo331195801.5.67171.5K1III-IV124622.512+93223.621.2.57
    Virgo341002606.7.14139.4A3V124713.638+115729.5.141.2.58
    Virgo351195961.6.41M3IIIb124751.418+33421.641.2.77
    Virgo371196336.2.14gK4125136.897+3324.391.2.61
    Virgo381390226.11.14F5V12531.11.88-3331.10.961.2.03
    Virgo411003221.6.25A7III125349.672+12251.6.651.2.21
    Virgo441390861.5.7920.9.14A3V125939.525-348431.2.95
    Virgo461390961.5.991.1.14K2III13035.906-3221.6.691.2.79
    Virgo481391311.6.590.6F0V13354.409-33947.621.2.61
    Virgo491577391.5.19K2III13753.816-104425.211.2.49
    Virgo501577601.5.94K5III13945.306-101945.761.2.39
    Virgo531577885.4.14235F5III-IV13121.3.45-161155.011.2.87
    Virgo541577981.6.285.4.14B9III131326.846-184936.081.2.41
    Virgo551578061.5.33G6V13141.10.91-195550.891.2.27
    Virgo571578231.5.22K1III-IV131558.779-195635.431.2.26
    Virgo591198471.5.2234.3G0V s131646.526+92526.921.2.69
    Virgo611578441.4.74231.5G6V131824.304-181840.862.1.14
    Virgo631578991.5.37KIII13231.1.38-17441.7.151.2.88
    Virgo641199051.5.87A2m13221.9.33+5916.841.2.49
    Virgo651393081.5.89K3III132318.901-45527.8.141.2.64
    Virgo661393241.5.75F3-4V s132433.249-5950.21.2.18
    Virgo681579381.5.25M0III132643.162-124227.661.2.28
    Virgo691579461.4.76K0-III-IVCN2Fe0.5132727.182-155824.721.2.26
    Virgo701005821.4.98286.4G4V132825.804+134643.481.2.66
    Virgo711005921.5.65K0III132913.009+10491.5.451.2.54
    Virgo721393706.9.1429.8.14F2V133025.708-6281.12.581.2.36
    Virgo73HX8602241579876.1.140.1F0IV-V13321.2.82-184343.971.2.18
    Virgo741393901.4.69M2III133157.92-61520.721.2.04
    Virgo751579981.5.5579.6K1.5IIIb133251.664-152146.931.2.24
    Virgo761394011.5.21K0III133258.086-10953.911.2.24
    Virgo78CW8601231200041.4.911.4.99A1p(Sr-Cr-Eu)13341.7.33+33932.021.3.19
    Virgo801394281.5.73G6III133531.299-52346.41.2.34
    Virgo821394905.1.14M1.5III134136.766-8421.10.931.2.99
    Virgo831581315.6.14G0Ib-IIa134429.825-161044.861.2.69
    Virgo841200821.5.363K2III13431.3.32+33216.561.2.46
    Virgo851581471.6.19A2Vn134535.068-15461.2.891.2.67
    Virgo861581521.5.511.2.14G8III134556.309-122535.511.2.17
    Virgo871581651.5.43M2IIIab134725.378-175135.771.2.79
    Virgo891581861.4.97K0.5III-IIIb134952.295-18831.2.74
    Virgo901396131.5.15K2III135442.194-1301.11.691.2.56
    Virgo921201851.5.91A8V135627.886+132.7.141.2.72
    Virgo951397361.5.46F2IV14642.837-91848.11.2.16
    Virgo961583851.6.47G8III1490.603-10201.4.131.2.52
    Virgo1041399421.6.17A2IV142724.374-6713.3.141.2.05
    Virgo1061399571.5.42K5III142841.723-6542.2.141.2.31
    Virgo1081206421.5.69B9.5V144530.219+0431.2.321.2.55
    Virgo1091206481.3.72A0V144614.948+15333.991.2.71
    Virgo1101208094.4.14K0.5IIIbFe-0.515254.054+2528.221.2.57
    Volansalp2504224A2-3IVm9226.838-662346.241.1.25
    Volansbet2502281.3.77K1III82544.195-66813.251.1.72
    Volansgam 12563731.5.6913.6.14F2V7842.154-702949.650.565
    Volansgam 22563741.3.7813.6.14K0III7844.898-702956.460.232
    Volansdel2498091.3.98F6II71649.765-675726.530.625
    Volanseps2501281.4.356B6IV8755.807-68371.1.891.1.52
    Volanszet 12564381.3.9516.7.14K0III74149.173-723621.750.466
    Volanseta2565051.5.2942.4A0-1IV-V8221.4.63-73241.1.490.143
    Volansthe2565355.2.1445A0V8391.5.43-70231.12.711.1.03
    Volansiot2563445.4.14B7IV65126.916-705748.580.753
    Volanskap 12564971.5.3765B9III-IV81949.05-713053.970.281
    Volanskap 22564991.5.6565A0IVMn8200.713-713018.670.359
    Vulpeculaalp6ANSER872611.4.44413.7M0III192842.336+243953.71.2.35
    Vulpecula1870101.4.7739.1B4IV191613.2.14+212325.781.2.67
    Vulpecula2ES880162870361.5.421.8.14O8IV-B0.5IVeV191743.605+23131.971.2.95
    Vulpecula3871361.5.18B6III192250.862+261544.591.2.15
    Vulpecula41048181.5.1618.9.14K0III192528.615+194754.771.2.39
    Vulpecula51048311.5.63A0V192613.228+20551.851.2.64
    Vulpecula51048391.5.81152.5M0III192628.665+195329.421.2.29
    Vulpecula7872691.6.33B5Vn192920.884+201646.611.2.53
    Vulpecula8872671.5.81K0III192857.016+24461.7.451.2.19
    Vulpecula91049905108.3B8IIIn193434.876+194624.5.141.3.59
    Vulpecula10876331.5.49G8III194342.929+254619.1.141.3.33
    Vulpecula12878131.4.95B2.5Ve19511.4.96+223635.762.11.14
    Vulpecula13878831.4.581B9.5III195327.713+24446.73.3.14
    Vulpecula14880161.5.67F019591.10.27+2361.4.561.2.43
    Vulpecula15NT880295880711.4.621.4.67A4IIIm2016.6.14+274513.151.2.95
    Vulpecula16880981.5.220.8F2III2021.1.34+245616.7.141.2.83
    Vulpecula17882125.7.14B3V20653.399+233652.011.2.05
    Vulpecula18882951.5.52A3III201033.504+265414.941.2.84
    Vulpecula19883301.5.49K3II-III201148.007+264832.271.2.73
    Vulpecula20883391.5.92B7Ve20120.715+262843.571.2.97
    Vulpecula21NU880296883911.5.36A7IVn-shell201414.535+284141.041.2.21
    Vulpecula22QS880327884161.5.15G3Ib-II201530.211+233031.191.2.05
    Vulpecula23884281.4.52K3-IIIFe-1201546.119+274851.391.2.71
    Vulpecula24884511.5.32G8III201647.099+244015.923.5.14
    Vulpecula25885801.5.54B8IIIne20221.3.09+242645.71.2.52
    Vulpecula26888841.6.41A5III20361.8.84+255257.351.2.81
    Vulpecula27889031.5.59B9V20371.4.57+262743.231.2.81
    Vulpecula28889455.4.14B5IV203831.911+24657.831.3.13
    Vulpecula29889441.4.82A0V203831.331+21124.4.141.3.29
    Vulpecula30890841.4.91K2III204452.509+251614.421.2.62
    Vulpecula31892281.4.59G7IIIFe-120521.7.78+27548.951.3.31
    Vulpecula32892725.1.14K4III205433.631+28327.461.2.15
    Vulpecula33893321.5.31K3.5III205816.347+221933.381.2.16
    Vulpecula35897201.5.41A1V212740.067+273630.741.2.21
    +
    + +

    Javascript

    + +
    +
    
    +			
    +

    HTML

    + +
    +
    <table class="tablesorter">
    +	<thead>
    +		<tr>
    +			<th>Constellation</th>
    +			<th>Bayer ref</th>
    +			<th>Flamsteed no</th>
    +			<th>Start name</th>
    +			<th>GCVS ref</th>
    +			<th>GCVS no</th>
    +			<th>SAO no</th>
    +			<th>Star no</th>
    +			<th> Max mag</th>
    +			<th> Min mag</th>
    +			<th>Comp sep</th>
    +			<th>Spectral type</th>
    +			<th>RA hr</th>
    +			<th>RA min</th>
    +			<th>RA sec</th>
    +			<th>DEC +-</th>
    +			<th>DEC deg</th>
    +			<th>DEC min</th>
    +			<th>DEC sec</th>
    +			<th>Pos err</th>
    +		</tr>
    +	</thead>
    +	<tbody>
    +		<tr>
    +			<td>Andromeda</td>
    +			<td>alp</td>
    +			<td>21</td>
    +			<td>ALPHERATZ</td>
    +			<td> </td>
    +			<td> </td>
    +			<td>73765</td>
    +			<td>1</td>
    +			<td>2.6.14</td>
    +			<td> </td>
    +			<td>81.5</td>
    +			<td>B8IVpMnHg</td>
    +			<td>0</td>
    +			<td>8</td>
    +			<td>23.269</td>
    +			<td>+</td>
    +			<td>29</td>
    +			<td>5</td>
    +			<td>25.55</td>
    +			<td>1.3.58</td>
    +		</tr>
    +		<tr>
    +			<td>Andromeda</td>
    +			<td>bet</td>
    +			<td>43</td>
    +			<td>MIRACH</td>
    +			<td> </td>
    +			<td> </td>
    +			<td>54471</td>
    +			<td>11</td>
    +			<td>2.6.14</td>
    +			<td> </td>
    +			<td>80.4</td>
    +			<td>M0+IIIa</td>
    +			<td>1</td>
    +			<td>9</td>
    +			<td>43.942</td>
    +			<td>+</td>
    +			<td>35</td>
    +			<td>37</td>
    +			<td>13.93</td>
    +			<td>1.3.23</td>
    +		</tr>
    +		<!-- and 3K rows more -->
    +	</tbody>
    +</table>
    +
    + + + +
    + + + diff --git a/docs/example-option-digits.html b/docs/example-option-digits.html new file mode 100644 index 0000000..2bb4d7c --- /dev/null +++ b/docs/example-option-digits.html @@ -0,0 +1,153 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Dealing with Digits + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Click on any column header to sort that column.
    • +
    • The alphanumeric sort working in the first column was added in version 2.0.6 (not part of the original plugin).
    • +
    • The above sort was replaced with a natural sort in version 2.2.
    • +
    • This example demonstrates that common table values are auto-detected (including plain text, currency, percentages, and positive & negative numbers), so there is no need to set a specific parser unless you notice an issue with how a column is sorting.
    • +
    • Issues may arise if a column contains mixed data, e.g. "N/A" is located at the top of a numeric column; in this case the column will be detected as a text column and not a numeric column. If issues occur, add a sorter-digit class name to that header cell.
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent182.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56$153.1923%+9
    A256JohnClark44($19.89)25.1%(5)
    A23ElvisPresley24($9.99)50%(22)
    A10FrankCarter40-12.9920%(6)
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-render-header.html b/docs/example-option-render-header.html new file mode 100644 index 0000000..940d97b --- /dev/null +++ b/docs/example-option-render-header.html @@ -0,0 +1,161 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Render Header + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! The span wrapping the header text and the index variable for the function was added in version 2.0.9 (it is not part of the original plugin, but the "onRenderHeader" option was available). +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    CSS

    +
    +
    
    +	
    +

    HTML

    + Before +
    +
    <thead>
    +  <tr>
    +    <th>First Name</th>
    +    <th>Last Name</th>
    +    <th>Age</th>
    +    <th>Total</th>
    +    <th>Discount</th>
    +    <th>Date</th>
    +  </tr>
    +</thead>
    +
    + After +
    +
    <thead>
    +  <tr class="tablesorter-headerRow">
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner roundedCorners header0">First Name <i class="tablesorter-icon"></i></div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner roundedCorners header1">Last Name <i class="tablesorter-icon"></i></div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner roundedCorners header2">Age <i class="tablesorter-icon"></i></div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner roundedCorners header3">Total <i class="tablesorter-icon"></i></div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner roundedCorners header4">Discount <i class="tablesorter-icon"></i></div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner roundedCorners header5">Date <i class="tablesorter-icon"></i></div></th>
    +  </tr>
    +</thead>
    +* Note: the tablesorter-icon was only added for emphasis in this demo, it isn't used at all by the blue template. +
    + + + +
    + + + + diff --git a/docs/example-option-render-template.html b/docs/example-option-render-template.html new file mode 100644 index 0000000..5773da8 --- /dev/null +++ b/docs/example-option-render-template.html @@ -0,0 +1,149 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Header Template & Rendering + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! These options were added in version 2.7 (they are not part of the original plugin). +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    + Before +
    +
    <thead>
    +  <tr>
    +    <th>First Name</th>
    +    <th>Last Name</th>
    +    <th>Age</th>
    +    <th>Total</th>
    +    <th>Discount</th>
    +    <th>Date</th>
    +  </tr>
    +</thead>
    +
    + After +
    +
    <thead>
    +  <tr class="tablesorter-headerRow">
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner"><em>1:</em> <i class="tablesorter-icon"></i>First Name</div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner"><em>2:</em> <i class="tablesorter-icon"></i>Last Name</div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner"><em>3:</em> <i class="tablesorter-icon"></i>Age</div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner"><em>4:</em> <i class="tablesorter-icon"></i>Total</div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner"><em>5:</em> <i class="tablesorter-icon"></i>Discount</div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner"><em>6:</em> <i class="tablesorter-icon"></i>Date</div></th>
    +  </tr>
    +</thead>
    +* Note: the tablesorter-icon was only added for emphasis in this demo, it isn't used at all by the blue template. +
    + + + +
    + + + + diff --git a/docs/example-option-selectorsort.html b/docs/example-option-selectorsort.html new file mode 100644 index 0000000..c4d397a --- /dev/null +++ b/docs/example-option-selectorsort.html @@ -0,0 +1,151 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Using selectorSort + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! Click on any column header link to sort that column. Clicking anywhere else within the header will not initiate a sort. +

    + +

    Demo


    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Account # aaFirst Name bbLast Name ccAge ddTotal eeDiscount ffDiff gg
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent182.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56$153.1923%+9
    A256JohnClark44($19.89)25.1%(5)
    A23ElvisPresley24($9.99)50%(22)
    A10FrankCarter40-12.9920%(6)
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-show-processing.html b/docs/example-option-show-processing.html new file mode 100644 index 0000000..42b1932 --- /dev/null +++ b/docs/example-option-show-processing.html @@ -0,0 +1,1138 @@ + + + + + jQuery plugin: Tablesorter 2.0 - showProcessing & Filter events + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • As of v2.16.3, there is a built-in 500 millisecond delay before the processing icon will show. If the sort has completed within that time, the icon will not appear.
    • +
    • There is an issue with the processing icon not appearing at all, or the animation appears frozen when processing data in very large tables. This is due to javascript only being able to process one thread at-a-time; If you know of a solution or work-around please add a comment or contribute a fix!
    • +
    +

    + +

    Javascript

    +
    +
    
    +	
    + +

    Filter Events

    +
      +
    • Filter events will appear here.
    • +
    •  
    • +
    •  
    • +
    + +

    Demo

    + + + (females majoring in languages with a score >80)
    + (males majoring in languages with a score >80)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Languagesfemale85808080
    student23Mathematicsmale8277079
    student24Languagesfemale100911382
    student25Mathematicsmale22968253
    student26Languagesfemale37295659
    student27Mathematicsmale86826923
    student28Languagesfemale4425431
    student29Mathematicsmale77472238
    student30Languagesfemale19352310
    student31Mathematicsmale90271750
    student32Languagesfemale60753338
    student33Mathematicsmale4313715
    student34Languagesfemale77978144
    student35Mathematicsmale5815195
    student36Languagesfemale70617094
    student37Mathematicsmale6036184
    student38Languagesfemale6339011
    student39Mathematicsmale50463238
    student40Languagesfemale5175253
    student41Mathematicsmale43342878
    student42Languagesfemale11896095
    student43Mathematicsmale48921888
    student44Languagesfemale8225973
    student45Mathematicsmale91733739
    student46Languagesfemale481210
    student47Mathematicsmale8910611
    student48Languagesfemale90322118
    student49Mathematicsmale42494972
    student50Languagesfemale56376754
    student51Mathematicsmale48315563
    student52Languagesfemale38917174
    student53Mathematicsmale26385100
    student54Languagesfemale75811623
    student55Mathematicsmale65521553
    student56Languagesfemale23527994
    student57Mathematicsmale80226112
    student58Languagesfemale5357979
    student59Mathematicsmale96323517
    student60Languagesfemale16766527
    student61Mathematicsmale20572223
    student62Languagesfemale19838778
    student63Mathematicsmale258330
    student64Languagesfemale021993
    student65Mathematicsmale20861396
    student66Languagesfemale28358757
    student67Mathematicsmale36502910
    student68Languagesfemale6090966
    student69Mathematicsmale34614398
    student70Languagesfemale13379183
    student71Mathematicsmale47805782
    student72Languagesfemale69433737
    student73Mathematicsmale54609421
    student74Languagesfemale71143446
    student75Mathematicsmale89963117
    student76Languagesfemale28482994
    student77Mathematicsmale100652024
    student78Languagesfemale11969033
    student79Mathematicsmale53559339
    student80Languagesfemale11008444
    student81Mathematicsmale63789643
    student82Languagesfemale41698235
    student83Mathematicsmale9498139
    student84Languagesfemale94729177
    student85Mathematicsmale71324525
    student86Languagesfemale9896437
    student87Mathematicsmale8917367
    student88Languagesfemale43416879
    student89Mathematicsmale7382237
    student90Languagesfemale94839337
    student91Mathematicsmale8284261
    student92Languagesfemale46413069
    student93Mathematicsmale47198583
    student94Languagesfemale39146462
    student95Mathematicsmale71314628
    student96Languagesfemale90944540
    student97Mathematicsmale468925
    student98Languagesfemale41434799
    student99Mathematicsmale71908973
    student100Languagesfemale31641856
    student101Mathematicsmale52136999
    student102Languagesfemale86398318
    student103Mathematicsmale23659880
    student104Languagesfemale781005766
    student105Mathematicsmale69214397
    student106Languagesfemale2727838
    student107Mathematicsmale86964634
    student108Languagesfemale13846664
    student109Mathematicsmale35959881
    student110Languagesfemale30286254
    student111Mathematicsmale60313585
    student112Languagesfemale19811969
    student113Mathematicsmale6659854
    student114Languagesfemale38804016
    student115Mathematicsmale5849697
    student116Languagesfemale59976954
    student117Mathematicsmale0347949
    student118Languagesfemale1871285
    student119Mathematicsmale9387759
    student120Languagesfemale42232690
    student121Mathematicsmale17396689
    student122Languagesfemale26759018
    student123Mathematicsmale34237780
    student124Languagesfemale5267742
    student125Mathematicsmale5628581
    student126Languagesfemale51356744
    student127Mathematicsmale64644434
    student128Languagesfemale67917982
    student129Mathematicsmale4261579
    student130Languagesfemale7210369
    student131Mathematicsmale9477511
    student132Languagesfemale27958548
    student133Mathematicsmale92114061
    student134Languagesfemale4185660
    student135Mathematicsmale8422652
    student136Languagesfemale7604721
    student137Mathematicsmale51813090
    student138Languagesfemale5861673
    student139Mathematicsmale48383731
    student140Languagesfemale33265660
    student141Mathematicsmale84842975
    student142Languagesfemale7235654
    student143Mathematicsmale31427082
    student144Languagesfemale94875035
    student145Mathematicsmale91528026
    student146Languagesfemale78657979
    student147Mathematicsmale50905971
    student148Languagesfemale15686633
    student149Mathematicsmale17363413
    student150Languagesfemale30956973
    student151Mathematicsmale20534958
    student152Languagesfemale19896060
    student153Mathematicsmale5282203
    student154Languagesfemale66985366
    student155Mathematicsmale5852258
    student156Languagesfemale3443688
    student157Mathematicsmale4309114
    student158Languagesfemale34186731
    student159Mathematicsmale79733452
    student160Languagesfemale15613727
    student161Mathematicsmale74771545
    student162Languagesfemale52621958
    student163Mathematicsmale77602795
    student164Languagesfemale9619357
    student165Mathematicsmale51637519
    student166Languagesfemale32447299
    student167Mathematicsmale82845763
    student168Languagesfemale53128567
    student169Mathematicsmale4916846
    student170Languagesfemale39341665
    student171Mathematicsmale10068884
    student172Languagesfemale14256352
    student173Mathematicsmale74261560
    student174Languagesfemale1158892
    student175Mathematicsmale6247231
    student176Languagesfemale65263242
    student177Mathematicsmale83786924
    student178Languagesfemale14100743
    student179Mathematicsmale2835897
    student180Languagesfemale1483962
    student181Mathematicsmale1442469
    student182Languagesfemale6452722
    student183Mathematicsmale15262785
    student184Languagesfemale9149407
    student185Mathematicsmale87894287
    student186Languagesfemale75766188
    student187Mathematicsmale11486630
    student188Languagesfemale7379272
    student189Mathematicsmale98365815
    student190Languagesfemale8028656
    student191Mathematicsmale3633974
    student192Languagesfemale5923390
    student193Mathematicsmale9461933
    student194Languagesfemale82497242
    student195Mathematicsmale8059830
    student196Languagesfemale89179027
    student197Mathematicsmale4622667
    student198Languagesfemale65757377
    student199Mathematicsmale77975413
    student200Languagesfemale78195796
    student201Mathematicsmale92211180
    student202Languagesfemale45499340
    student203Mathematicsmale74258753
    student204Languagesfemale1571234
    student205Mathematicsmale82979573
    student206Languagesfemale82605898
    student207Mathematicsmale266411100
    student208Languagesfemale6496045
    student209Mathematicsmale96819663
    student210Languagesfemale2439069
    student211Mathematicsmale8664710
    student212Languagesfemale764507
    student213Mathematicsmale59122677
    student214Languagesfemale21259382
    student215Mathematicsmale22186451
    student216Languagesfemale92419828
    student217Mathematicsmale32481417
    student218Languagesfemale62368556
    student219Mathematicsmale33379087
    student220Languagesfemale24436084
    student221Mathematicsmale6593751
    student222Languagesfemale9197576
    student223Mathematicsmale86293227
    student224Languagesfemale63596891
    student225Mathematicsmale57739568
    student226Languagesfemale38545987
    student227Mathematicsmale53627264
    student228Languagesfemale62847273
    student229Mathematicsmale1308358
    student230Languagesfemale35658087
    student231Mathematicsmale76202850
    student232Languagesfemale9176633
    student233Mathematicsmale9229961
    student234Languagesfemale47699839
    student235Mathematicsmale21443882
    student236Languagesfemale19865178
    student237Mathematicsmale28454936
    student238Languagesfemale78194981
    student239Mathematicsmale72694720
    student240Languagesfemale17436656
    student241Mathematicsmale901944
    student242Languagesfemale618251
    student243Mathematicsmale1377213
    student244Languagesfemale8005854
    student245Mathematicsmale8331859
    student246Languagesfemale90992912
    student247Mathematicsmale89238159
    student248Languagesfemale7226283
    student249Mathematicsmale28105047
    student250Languagesfemale8914894
    student251Mathematicsmale15233769
    student252Languagesfemale27821036
    student253Mathematicsmale49456423
    student254Languagesfemale79756374
    student255Mathematicsmale2566475
    student256Languagesfemale36262958
    student257Mathematicsmale17226673
    student258Languagesfemale70919745
    student259Mathematicsmale34307830
    student260Languagesfemale77578677
    student261Mathematicsmale1259687
    student262Languagesfemale11609771
    student263Mathematicsmale12303558
    student264Languagesfemale46152340
    student265Mathematicsmale4481926
    student266Languagesfemale15683215
    student267Mathematicsmale5585098
    student268Languagesfemale42303224
    student269Mathematicsmale781009957
    student270Languagesfemale55338725
    student271Mathematicsmale25972993
    student272Languagesfemale39351843
    student273Mathematicsmale35179958
    student274Languagesfemale86522724
    student275Mathematicsmale97387376
    student276Languagesfemale206198
    student277Mathematicsmale9336947
    student278Languagesfemale423152
    student279Mathematicsmale6118962
    student280Languagesfemale99898794
    student281Mathematicsmale4895900
    student282Languagesfemale60473130
    student283Mathematicsmale64241076
    student284Languagesfemale9937468
    student285Mathematicsmale0986869
    student286Languagesfemale66824959
    student287Mathematicsmale86143717
    student288Languagesfemale27489327
    student289Mathematicsmale8489668
    student290Languagesfemale9902057
    student291Mathematicsmale50967242
    student292Languagesfemale9822792
    student293Mathematicsmale1994287
    student294Languagesfemale9897922
    student295Mathematicsmale75307764
    student296Languagesfemale5198553
    student297Mathematicsmale25958672
    student298Languagesfemale20753735
    student299Mathematicsmale4924111
    student300Languagesfemale2832891
    student301Mathematicsmale4163425
    student302Languagesfemale29167790
    student303Mathematicsmale89415182
    student304Languagesfemale40912434
    student305Mathematicsmale7474978
    student306Languagesfemale6375562
    student307Mathematicsmale30733490
    student308Languagesfemale82919593
    student309Mathematicsmale6247382
    student310Languagesfemale39101257
    student311Mathematicsmale89642067
    student312Languagesfemale56369241
    student313Mathematicsmale99809974
    student314Languagesfemale31796493
    student315Mathematicsmale5327055
    student316Languagesfemale35152960
    student317Mathematicsmale31476960
    student318Languagesfemale88281366
    student319Mathematicsmale65121640
    student320Languagesfemale28171940
    student321Mathematicsmale241004470
    student322Languagesfemale20598352
    student323Mathematicsmale17608291
    student324Languagesfemale95994337
    student325Mathematicsmale30189931
    student326Languagesfemale3478386
    student327Mathematicsmale9863435
    student328Languagesfemale54239846
    student329Mathematicsmale97934518
    student330Languagesfemale2774077
    student331Mathematicsmale9704137
    student332Languagesfemale52377620
    student333Mathematicsmale74186819
    student334Languagesfemale77100339
    student335Mathematicsmale38537718
    student336Languagesfemale18132610
    student337Mathematicsmale90478770
    student338Languagesfemale38493674
    student339Mathematicsmale100641372
    student340Languagesfemale74254152
    student341Mathematicsmale37131613
    student342Languagesfemale24341583
    student343Mathematicsmale2056728
    student344Languagesfemale4522572
    student345Mathematicsmale19117535
    student346Languagesfemale6583115
    student347Mathematicsmale16663611
    student348Languagesfemale1239540
    student349Mathematicsmale752742
    student350Languagesfemale88926055
    student351Mathematicsmale92709145
    student352Languagesfemale74765944
    student353Mathematicsmale63696094
    student354Languagesfemale3685548
    student355Mathematicsmale39962148
    student356Languagesfemale4134275
    student357Mathematicsmale6434733
    student358Languagesfemale95146355
    student359Mathematicsmale701001382
    student360Languagesfemale522410021
    student361Mathematicsmale040869
    student362Languagesfemale024932
    student363Mathematicsmale23108694
    student364Languagesfemale1538649
    student365Mathematicsmale7623310
    student366Languagesfemale35357894
    student367Mathematicsmale294243100
    student368Languagesfemale668510
    student369Mathematicsmale74155683
    student370Languagesfemale7543908
    student371Mathematicsmale4060470
    student372Languagesfemale62421749
    student373Mathematicsmale31464454
    student374Languagesfemale30344787
    student375Mathematicsmale9694152
    student376Languagesfemale85432992
    student377Mathematicsmale7904025
    student378Languagesfemale36407285
    student379Mathematicsmale5368882
    student380Languagesfemale87783879
    student381Mathematicsmale89978338
    student382Languagesfemale21194910
    student383Mathematicsmale47126850
    student384Languagesfemale37124995
    student385Mathematicsmale8408851
    student386Languagesfemale89612748
    student387Mathematicsmale10478761
    student388Languagesfemale1692656
    student389Mathematicsmale57331347
    student390Languagesfemale90357775
    student391Mathematicsmale31474753
    student392Languagesfemale942412
    student393Mathematicsmale6119817
    student394Languagesfemale457577
    student395Mathematicsmale6729212
    student396Languagesfemale516456
    student397Mathematicsmale93147714
    student398Languagesfemale1893427
    student399Mathematicsmale93775791
    student400Languagesfemale67778032
    student401Mathematicsmale5889417
    student402Languagesfemale3056053
    student403Mathematicsmale28253259
    student404Languagesfemale62348164
    student405Mathematicsmale29842623
    student406Languagesfemale7086377
    student407Mathematicsmale8654799
    student408Languagesfemale9381089
    student409Mathematicsmale84214658
    student410Languagesfemale21841849
    student411Mathematicsmale2796340
    student412Languagesfemale9301991
    student413Mathematicsmale31928743
    student414Languagesfemale53259843
    student415Mathematicsmale36758089
    student416Languagesfemale37681254
    student417Mathematicsmale25891253
    student418Languagesfemale922846
    student419Mathematicsmale11286058
    student420Languagesfemale1373517
    student421Mathematicsmale67303885
    student422Languagesfemale68793441
    student423Mathematicsmale72459341
    student424Languagesfemale56464538
    student425Mathematicsmale8621840
    student426Languagesfemale99854119
    student427Mathematicsmale7135389
    student428Languagesfemale22911216
    student429Mathematicsmale1532693
    student430Languagesfemale35463474
    student431Mathematicsmale33839720
    student432Languagesfemale9920326
    student433Mathematicsmale48428318
    student434Languagesfemale4442530
    student435Mathematicsmale78486045
    student436Languagesfemale4757890
    student437Mathematicsmale881210053
    student438Languagesfemale4805160
    student439Mathematicsmale70898516
    student440Languagesfemale71943433
    student441Mathematicsmale68137218
    student442Languagesfemale7539721
    student443Mathematicsmale65366087
    student444Languagesfemale43212434
    student445Mathematicsmale85776528
    student446Languagesfemale61907891
    student447Mathematicsmale9207812
    student448Languagesfemale33306290
    student449Mathematicsmale8616745
    student450Languagesfemale100862423
    student451Mathematicsmale1425645
    student452Languagesfemale86399888
    student453Mathematicsmale72687719
    student454Languagesfemale94523100
    student455Mathematicsmale34678979
    student456Languagesfemale9204745
    student457Mathematicsmale64582698
    student458Languagesfemale439359100
    student459Mathematicsmale82359781
    student460Languagesfemale183524100
    student461Mathematicsmale79804351
    student462Languagesfemale56101767
    student463Mathematicsmale36441485
    student464Languagesfemale2640692
    student465Mathematicsmale59934378
    student466Languagesfemale7884883
    student467Mathematicsmale41378060
    student468Languagesfemale44279777
    student469Mathematicsmale29196482
    student470Languagesfemale50962746
    student471Mathematicsmale49155145
    student472Languagesfemale38353178
    student473Mathematicsmale1802365
    student474Languagesfemale91172376
    student475Mathematicsmale57393563
    student476Languagesfemale33736214
    student477Mathematicsmale96168840
    student478Languagesfemale30631613
    student479Mathematicsmale74393787
    student480Languagesfemale26369479
    student481Mathematicsmale19586512
    student482Languagesfemale73362248
    student483Mathematicsmale7894757
    student484Languagesfemale5951935
    student485Mathematicsmale677110085
    student486Languagesfemale33301546
    student487Mathematicsmale12191637
    student488Languagesfemale80982914
    student489Mathematicsmale70511431
    student490Languagesfemale95381592
    student491Mathematicsmale60317412
    student492Languagesfemale62569068
    student493Mathematicsmale63112991
    student494Languagesfemale4112520
    student495Mathematicsmale6053144
    student496Languagesfemale1135528
    student497Mathematicsmale11964237
    student498Languagesfemale16727974
    student499Mathematicsmale9212266
    student500Languagesfemale34226434
    student501Mathematicsmale50938661
    student502Languagesfemale50224044
    student503Mathematicsmale383917
    student504Languagesfemale98169355
    student505Mathematicsmale86893628
    student506Languagesfemale16531350
    student507Mathematicsmale5757338
    student508Languagesfemale34796977
    student509Mathematicsmale241659
    student510Languagesfemale606299100
    student511Mathematicsmale65525295
    student512Languagesfemale5873941
    student513Mathematicsmale39752876
    student514Languagesfemale4666478
    student515Mathematicsmale5160998
    student516Languagesfemale17201297
    student517Mathematicsmale72179673
    student518Languagesfemale92216227
    student519Mathematicsmale5042433
    student520Languagesfemale5237157
    student521Mathematicsmale58403554
    student522Languagesfemale9385753
    student523Mathematicsmale79201818
    student524Languagesfemale149427
    student525Mathematicsmale95412998
    student526Languagesfemale3459921
    student527Mathematicsmale39664129
    student528Languagesfemale328125
    student529Mathematicsmale33443785
    student530Languagesfemale69255979
    student531Mathematicsmale13504952
    student532Languagesfemale54834531
    student533Mathematicsmale15249751
    student534Languagesfemale7516963
    student535Mathematicsmale9183856
    student536Languagesfemale50137480
    student537Mathematicsmale54757410
    student538Languagesfemale76397046
    student539Mathematicsmale84723940
    student540Languagesfemale10047214
    student541Mathematicsmale426111
    student542Languagesfemale57716561
    student543Mathematicsmale7854134
    student544Languagesfemale14763647
    student545Mathematicsmale15196396
    student546Languagesfemale27823356
    student547Mathematicsmale70239690
    student548Languagesfemale612278
    student549Mathematicsmale22376436
    student550Languagesfemale75969440
    student551Mathematicsmale4382921
    student552Languagesfemale7968718
    student553Mathematicsmale65765244
    student554Languagesfemale41627354
    student555Mathematicsmale25982140
    student556Languagesfemale17709682
    student557Mathematicsmale43912743
    student558Languagesfemale33372433
    student559Mathematicsmale87871031
    student560Languagesfemale48409774
    student561Mathematicsmale63759155
    student562Languagesfemale66825995
    student563Mathematicsmale21955838
    student564Languagesfemale9299745
    student565Mathematicsmale5979420
    student566Languagesfemale64952412
    student567Mathematicsmale70463674
    student568Languagesfemale16259149
    student569Mathematicsmale73332488
    student570Languagesfemale9619527
    student571Mathematicsmale18127646
    student572Languagesfemale61714963
    student573Mathematicsmale46328517
    student574Languagesfemale42421137
    student575Mathematicsmale49764120
    student576Languagesfemale22278012
    student577Mathematicsmale76341866
    student578Languagesfemale96772917
    student579Mathematicsmale62516772
    student580Languagesfemale96672254
    student581Mathematicsmale77112388
    student582Languagesfemale6282433
    student583Mathematicsmale392312100
    student584Languagesfemale10212071
    student585Mathematicsmale11277100
    student586Languagesfemale40349778
    student587Mathematicsmale2518319
    student588Languagesfemale18763025
    student589Mathematicsmale24574681
    student590Languagesfemale2103194
    student591Mathematicsmale91847513
    student592Languagesfemale79449710
    student593Mathematicsmale42606730
    student594Languagesfemale61577535
    student595Mathematicsmale42468171
    student596Languagesfemale92637574
    student597Mathematicsmale86374051
    student598Languagesfemale5210473
    student599Mathematicsmale100281476
    student600Languagesfemale31762043
    student601Mathematicsmale402766
    student602Languagesfemale587921
    student603Mathematicsmale754691
    student604Languagesfemale2830153
    student605Mathematicsmale38939892
    student606Languagesfemale43968991
    student607Mathematicsmale43491483
    student608Languagesfemale50617298
    student609Mathematicsmale4499983
    student610Languagesfemale5367382
    student611Mathematicsmale40849954
    student612Languagesfemale29966569
    student613Mathematicsmale1276599
    student614Languagesfemale4783494
    student615Mathematicsmale3727224
    student616Languagesfemale94394924
    student617Mathematicsmale0752141
    student618Languagesfemale5936418
    student619Mathematicsmale2266133
    student620Languagesfemale4387448
    student621Mathematicsmale100155152
    student622Languagesfemale63719917
    student623Mathematicsmale143444100
    student624Languagesfemale2385727
    student625Mathematicsmale23143240
    student626Languagesfemale34497254
    student627Mathematicsmale21168126
    student628Languagesfemale54693434
    student629Mathematicsmale72116331
    student630Languagesfemale8798947
    student631Mathematicsmale43525358
    student632Languagesfemale5014420
    student633Mathematicsmale89836787
    student634Languagesfemale079916
    student635Mathematicsmale59178458
    student636Languagesfemale94953660
    student637Mathematicsmale39426346
    student638Languagesfemale019610
    student639Mathematicsmale50164171
    student640Languagesfemale8604613
    student641Mathematicsmale45855936
    student642Languagesfemale8335057
    student643Mathematicsmale8306014
    student644Languagesfemale76807338
    student645Mathematicsmale2614582
    student646Languagesfemale9316422
    student647Mathematicsmale85947616
    student648Languagesfemale57453216
    student649Mathematicsmale16169013
    student650Languagesfemale4331887
    student651Mathematicsmale16243244
    student652Languagesfemale5998334
    student653Mathematicsmale73184783
    student654Languagesfemale992510093
    student655Mathematicsmale0739784
    student656Languagesfemale0289475
    student657Mathematicsmale65905863
    student658Languagesfemale84358641
    student659Mathematicsmale4539599
    student660Languagesfemale32103162
    student661Mathematicsmale61285461
    student662Languagesfemale70961454
    student663Mathematicsmale6392298
    student664Languagesfemale41104623
    student665Mathematicsmale81918021
    student666Languagesfemale79716568
    student667Mathematicsmale47691890
    student668Languagesfemale2616700
    student669Mathematicsmale66109335
    student670Languagesfemale66682713
    student671Mathematicsmale86792645
    student672Languagesfemale50532574
    student673Mathematicsmale9753914
    student674Languagesfemale28796942
    student675Mathematicsmale607259
    student676Languagesfemale53213943
    student677Mathematicsmale37654591
    student678Languagesfemale76806027
    student679Mathematicsmale85273455
    student680Languagesfemale66114117
    student681Mathematicsmale27618982
    student682Languagesfemale402613
    student683Mathematicsmale2516695
    student684Languagesfemale63448563
    student685Mathematicsmale97957883
    student686Languagesfemale5121387
    student687Mathematicsmale63928723
    student688Languagesfemale22965959
    student689Mathematicsmale33801523
    student690Languagesfemale34751924
    student691Mathematicsmale36684854
    student692Languagesfemale32362012
    student693Mathematicsmale68917450
    student694Languagesfemale87919637
    student695Mathematicsmale239144
    student696Languagesfemale9462977
    student697Mathematicsmale1474575
    student698Languagesfemale73921990
    student699Mathematicsmale8207978
    student700Languagesfemale763510039
    student701Mathematicsmale27518949
    student702Languagesfemale0647237
    student703Mathematicsmale93469487
    student704Languagesfemale6922172
    student705Mathematicsmale1752113
    student706Languagesfemale1325219
    student707Mathematicsmale75617273
    student708Languagesfemale8437736
    student709Mathematicsmale81194514
    student710Languagesfemale62173927
    student711Mathematicsmale8869681
    student712Languagesfemale53825929
    student713Mathematicsmale83347134
    student714Languagesfemale9552614
    student715Mathematicsmale6715313
    student716Languagesfemale8297825
    student717Mathematicsmale65503146
    student718Languagesfemale27462537
    student719Mathematicsmale98423544
    student720Languagesfemale9014444
    student721Mathematicsmale3168293
    student722Languagesfemale3434370
    student723Mathematicsmale59771421
    student724Languagesfemale16535759
    student725Mathematicsmale7914416
    student726Languagesfemale108199
    student727Mathematicsmale89487916
    student728Languagesfemale8872387
    student729Mathematicsmale17539584
    student730Languagesfemale65523961
    student731Mathematicsmale44309672
    student732Languagesfemale70793233
    student733Mathematicsmale30474611
    student734Languagesfemale761001649
    student735Mathematicsmale39369089
    student736Languagesfemale1941929
    student737Mathematicsmale23737887
    student738Languagesfemale87714464
    student739Mathematicsmale22198220
    student740Languagesfemale94526739
    student741Mathematicsmale14175187
    student742Languagesfemale5663983
    student743Mathematicsmale99924698
    student744Languagesfemale19768388
    student745Mathematicsmale15776881
    student746Languagesfemale48814838
    student747Mathematicsmale2913861
    student748Languagesfemale7163030
    student749Mathematicsmale19683053
    student750Languagesfemale91182762
    student751Mathematicsmale73333836
    student752Languagesfemale99387550
    student753Mathematicsmale55713490
    student754Languagesfemale52409883
    student755Mathematicsmale1463611
    student756Languagesfemale1319496
    student757Mathematicsmale49665592
    student758Languagesfemale0198082
    student759Mathematicsmale2635873
    student760Languagesfemale8287639
    student761Mathematicsmale52118357
    student762Languagesfemale83688425
    student763Mathematicsmale1725670
    student764Languagesfemale1758084
    student765Mathematicsmale7564785
    student766Languagesfemale76329339
    student767Mathematicsmale20758465
    student768Languagesfemale25471289
    student769Mathematicsmale86947945
    student770Languagesfemale65815535
    student771Mathematicsmale62414143
    student772Languagesfemale1446243
    student773Mathematicsmale17557278
    student774Languagesfemale9546356
    student775Mathematicsmale7205648
    student776Languagesfemale30881956
    student777Mathematicsmale42448856
    student778Languagesfemale42695663
    student779Mathematicsmale7857783
    student780Languagesfemale15862498
    student781Mathematicsmale4684369
    student782Languagesfemale67981552
    student783Mathematicsmale33326357
    student784Languagesfemale35951653
    student785Mathematicsmale78545482
    student786Languagesfemale8185914
    student787Mathematicsmale42412314
    student788Languagesfemale591008636
    student789Mathematicsmale1926012
    student790Languagesfemale10034570
    student791Mathematicsmale381217
    student792Languagesfemale3155193
    student793Mathematicsmale11339877
    student794Languagesfemale461786
    student795Mathematicsmale5786727
    student796Languagesfemale5746236
    student797Mathematicsmale57676661
    student798Languagesfemale93888725
    student799Mathematicsmale59966441
    student800Languagesfemale6276923
    student801Mathematicsmale35833255
    student802Languagesfemale42581583
    student803Mathematicsmale41904012
    student804Languagesfemale8143837
    student805Mathematicsmale87773320
    student806Languagesfemale53873037
    student807Mathematicsmale13358516
    student808Languagesfemale20829034
    student809Mathematicsmale5821614
    student810Languagesfemale14282356
    student811Mathematicsmale4997368
    student812Languagesfemale31461163
    student813Mathematicsmale7497643
    student814Languagesfemale42839575
    student815Mathematicsmale2654529
    student816Languagesfemale79596988
    student817Mathematicsmale68182684
    student818Languagesfemale39139915
    student819Mathematicsmale2248716
    student820Languagesfemale12538811
    student821Mathematicsmale33908029
    student822Languagesfemale3795486
    student823Mathematicsmale9178851
    student824Languagesfemale31586731
    student825Mathematicsmale22305098
    student826Languagesfemale55585610
    student827Mathematicsmale56765753
    student828Languagesfemale1129881
    student829Mathematicsmale67926671
    student830Languagesfemale30614449
    student831Mathematicsmale0414461
    student832Languagesfemale72524585
    student833Mathematicsmale60991294
    student834Languagesfemale83587542
    student835Mathematicsmale9505377
    student836Languagesfemale33287062
    student837Mathematicsmale3982755
    student838Languagesfemale411004547
    student839Mathematicsmale81692729
    student840Languagesfemale9012649
    student841Mathematicsmale45382034
    student842Languagesfemale325311
    student843Mathematicsmale55778649
    student844Languagesfemale61609176
    student845Mathematicsmale8085749
    student846Languagesfemale63897371
    student847Mathematicsmale79159742
    student848Languagesfemale99187343
    student849Mathematicsmale30523856
    student850Languagesfemale65866734
    student851Mathematicsmale7343655
    student852Languagesfemale42435173
    student853Mathematicsmale870980
    student854Languagesfemale29411245
    student855Mathematicsmale5739090
    student856Languagesfemale80529654
    student857Mathematicsmale43838246
    student858Languagesfemale7917131
    student859Mathematicsmale6813707
    student860Languagesfemale51441552
    student861Mathematicsmale9170178
    student862Languagesfemale4116578
    student863Mathematicsmale20635585
    student864Languagesfemale5938726
    student865Mathematicsmale4894432
    student866Languagesfemale26679839
    student867Mathematicsmale48793866
    student868Languagesfemale1632153
    student869Mathematicsmale13205085
    student870Languagesfemale4922039
    student871Mathematicsmale8262353
    student872Languagesfemale6607464
    student873Mathematicsmale66483914
    student874Languagesfemale43833100
    student875Mathematicsmale214990
    student876Languagesfemale79807180
    student877Mathematicsmale84252688
    student878Languagesfemale38466660
    student879Mathematicsmale35279851
    student880Languagesfemale5759267
    student881Mathematicsmale7687788
    student882Languagesfemale2140817
    student883Mathematicsmale5046866
    student884Languagesfemale83863092
    student885Mathematicsmale63466694
    student886Languagesfemale7671262
    student887Mathematicsmale7418686
    student888Languagesfemale65774488
    student889Mathematicsmale67326119
    student890Languagesfemale85968541
    student891Mathematicsmale1487705
    student892Languagesfemale81284528
    student893Mathematicsmale9191883
    student894Languagesfemale407024
    student895Mathematicsmale18195189
    student896Languagesfemale70352512
    student897Mathematicsmale7290741
    student898Languagesfemale8417186
    student899Mathematicsmale1423886
    student900Languagesfemale7837601
    student901Mathematicsmale66953168
    student902Languagesfemale23608065
    student903Mathematicsmale76896396
    student904Languagesfemale3469070
    student905Mathematicsmale65449679
    student906Languagesfemale6877865
    student907Mathematicsmale86619943
    student908Languagesfemale88953213
    student909Mathematicsmale531005982
    student910Languagesfemale3579535
    student911Mathematicsmale230177
    student912Languagesfemale9687263
    student913Mathematicsmale23923996
    student914Languagesfemale9497658
    student915Mathematicsmale49312971
    student916Languagesfemale21577957
    student917Mathematicsmale03510089
    student918Languagesfemale64827552
    student919Mathematicsmale16666968
    student920Languagesfemale92951127
    student921Mathematicsmale16888590
    student922Languagesfemale56152698
    student923Mathematicsmale78274017
    student924Languagesfemale95104432
    student925Mathematicsmale99855218
    student926Languagesfemale73317149
    student927Mathematicsmale21791063
    student928Languagesfemale92718012
    student929Mathematicsmale23293388
    student930Languagesfemale4189884
    student931Mathematicsmale97177921
    student932Languagesfemale72409392
    student933Mathematicsmale7558326
    student934Languagesfemale15982728
    student935Mathematicsmale7688806
    student936Languagesfemale84234292
    student937Mathematicsmale71568671
    student938Languagesfemale7395822
    student939Mathematicsmale1555460
    student940Languagesfemale2031308
    student941Mathematicsmale97544181
    student942Languagesfemale83418664
    student943Mathematicsmale7195327
    student944Languagesfemale0273091
    student945Mathematicsmale99751722
    student946Languagesfemale92531090
    student947Mathematicsmale4449432
    student948Languagesfemale0974879
    student949Mathematicsmale97557974
    student950Languagesfemale6598932
    student951Mathematicsmale56733881
    student952Languagesfemale84946150
    student953Mathematicsmale4820770
    student954Languagesfemale39981420
    student955Mathematicsmale4152465
    student956Languagesfemale78229231
    student957Mathematicsmale28382654
    student958Languagesfemale49613554
    student959Mathematicsmale81152817
    student960Languagesfemale5480582
    student961Mathematicsmale7523537
    student962Languagesfemale5565120
    student963Mathematicsmale86427036
    student964Languagesfemale54455480
    student965Mathematicsmale38186992
    student966Languagesfemale33894683
    student967Mathematicsmale4395576
    student968Languagesfemale13261286
    student969Mathematicsmale94228559
    student970Languagesfemale9358610
    student971Mathematicsmale35728536
    student972Languagesfemale37519693
    student973Mathematicsmale71107959
    student974Languagesfemale71317393
    student975Mathematicsmale80268697
    student976Languagesfemale69216769
    student977Mathematicsmale38861039
    student978Languagesfemale48903981
    student979Mathematicsmale9083342
    student980Languagesfemale1919184
    student981Mathematicsmale98255046
    student982Languagesfemale38882116
    student983Mathematicsmale71481843
    student984Languagesfemale79851816
    student985Mathematicsmale51669068
    student986Languagesfemale100956591
    student987Mathematicsmale6742424
    student988Languagesfemale93809435
    student989Mathematicsmale65785794
    student990Languagesfemale27922191
    student991Mathematicsmale77152676
    student992Languagesfemale28845167
    student993Mathematicsmale3786250
    student994Languagesfemale59772074
    student995Mathematicsmale6266875
    student996Languagesfemale88703343
    student997Mathematicsmale73334253
    student998Languagesfemale6410231
    student999Mathematicsmale91931635
    student1000Languagesfemale30689540
    student1001Mathematicsmale2524832
    student1002Languagesfemale50775381
    student1003Mathematicsmale67441065
    student1004Languagesfemale29533486
    student1005Mathematicsmale77692275
    student1006Languagesfemale48829540
    student1007Mathematicsmale30712963
    student1008Languagesfemale4531471
    student1009Mathematicsmale81122044
    student1010Languagesfemale17668242
    student1011Mathematicsmale15113218
    student1012Languagesfemale27345919
    student1013Mathematicsmale18672514
    student1014Languagesfemale24645224
    student1015Mathematicsmale36874846
    student1016Languagesfemale3317068
    student1017Mathematicsmale4826380
    student1018Languagesfemale53638557
    student1019Mathematicsmale5873024
    student1020Languagesfemale8590810
    student1021Mathematicsmale69285276
    student1022Languagesfemale7522752
    + + + +
    + + + + diff --git a/docs/example-option-sort-append.html b/docs/example-option-sort-append.html new file mode 100644 index 0000000..68f79f0 --- /dev/null +++ b/docs/example-option-sort-append.html @@ -0,0 +1,126 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Append a default sorting order + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Click to sort any column header to see the the first column sort is appended to the selected sort order.
    • +
    • This option is part of the original plugin
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jan 18, 2001 9:12 AM
    JohnEvans33$9.9925%Dec 10, 2002 5:14 AM
    ClarkKent22$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$15.8944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jul 6, 2006 8:14 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-sort-empty.html b/docs/example-option-sort-empty.html new file mode 100644 index 0000000..1fee3a9 --- /dev/null +++ b/docs/example-option-sort-empty.html @@ -0,0 +1,198 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Sorting empty cells + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

    +
      +
    • Set the emptyTo selector below: +
        +
      • top - sort empty table cells to the top.
      • +
      • bottom - sort empty table cells to the bottom.
      • +
      • none or zero +
          +
        • Sort empty table cells as if the cell has the value equal to zero
        • +
        • None/zero has a value less than A through Z (in javascript, 0 < 'A' && 0 < 'Z'); so in an alphabetical column, empty cells will sort at the top in an ascending sort & at the bottom in a descending sort.
        • +
        • In numerical columns, empty cells will sort as if their value was zero.
        • +
        +
      • +
      +
      +
    • +
    • Individual columns can be modified by adding the following (they all do the same thing), set in order of priority: +
        +
      • jQuery data data-empty="top".
      • +
      • metadata class="{ empty: 'top'}". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { empty : 'top' } }.
      • +
      • header class name class="empty-top".
      • +
      • Overall emptyTo option.
      • +
      +
      +
    • +
    • emptyToBottom option was added in v2.1.11, then replaced by the emptyTo option in v2.1.16.
    • +
    +

    + +

    Demo

    + +Set emptyTo option: + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    *Account # First NameLast NameAgeTotalDiscountDiff
    A43PeterParker2820.3%+3
    A255Hood19.9925.1%-7
    Clark1815.8944.2%-15
    A1BruceAlmighty45153.19+19
    A102BruceEvans56153.1923%
    A109LarryStevens56153.1923%0
    A99JohnSmithy5615622%
    A119MikeRowe55-53.9913%0
    + * Note The "Account #" column has the "empty-top" class name set which over-rides the emptyTo option (see the order of priority note above). +

    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-sort-force.html b/docs/example-option-sort-force.html new file mode 100644 index 0000000..df0ac06 --- /dev/null +++ b/docs/example-option-sort-force.html @@ -0,0 +1,128 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Force a default sorting order + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Click to sort any column header to see the forcing of the first column sort.
    • +
    • This option is part of the original plugin
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-sort-key.html b/docs/example-option-sort-key.html new file mode 100644 index 0000000..5c4afe2 --- /dev/null +++ b/docs/example-option-sort-key.html @@ -0,0 +1,119 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Change multi-column sorting key + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! Click to sort any column header, then hold down the alt key and select a second column. Continue selecting columns as desired. +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-sort-list.html b/docs/example-option-sort-list.html new file mode 100644 index 0000000..01e3e05 --- /dev/null +++ b/docs/example-option-sort-list.html @@ -0,0 +1,176 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Set an initial table sort + + + + + + + + + + + + + + + + + + +
    +

    Demo

    +

    Set initial sort using the sortList option

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Set initial sort using a data attribute

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + + diff --git a/docs/example-option-sort-order.html b/docs/example-option-sort-order.html new file mode 100644 index 0000000..3cb8691 --- /dev/null +++ b/docs/example-option-sort-order.html @@ -0,0 +1,113 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Set an initial sort order direction + + + + + + + + + + + + + + + + + + +
    +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-option-sortreset-sortrestart.html b/docs/example-option-sortreset-sortrestart.html new file mode 100644 index 0000000..2ee8119 --- /dev/null +++ b/docs/example-option-sortreset-sortrestart.html @@ -0,0 +1,137 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Reset/Restart the sort + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • The default sortInitialOrder for the entire table is set to desc (descending sort).
    • +
    • The last three columns have the initial sort order set in the ascending direction, using the headers option.
    • +
    • Test the sortReset option by clicking on any column at least three times. It should sort in the sortInitialOrder direction on the first click, the opposite direction on the second click, then reset to the original sort order on the third click. This cycle repeats on subsequent sorts.
    • +
    • Test the sortRestart option by clicking on any unsorted column to see that it will always restart from the sortInitialOrder.
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First Name (desc)Last Name (desc)Age (desc)Total (asc)Discount (asc)Date (asc)
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    RobinHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + + diff --git a/docs/example-option-text-extraction.html b/docs/example-option-text-extraction.html new file mode 100644 index 0000000..1590b94 --- /dev/null +++ b/docs/example-option-text-extraction.html @@ -0,0 +1,142 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Dealing with markup inside cells + + + + + + + + + + + + + + + + + + + + +
    +

    + NOTE! +

      +
    • In v2.17.0, the textExtraction column can also be referenced by using a jQuery selector (e.g. class name or ID).
    • +
    • The textExtraction function setting for each column was added in version 2.0.12 (not part of the original plugin).
    • +
    • The "First Name" column is sorting by the contents of the <strong> tag (in red).
    • +
    • Added "table" and "cellIndex" variables to the textExtraction function (v2.1.2).
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    Mr. Peter
    Parker
    28$9.9920%Jul 6, 2006 8:14 AM
    Dr. John
    Hood
    33$19.9925%Dec 10, 2002 5:14 AM
    Rep Clark
    Kent
    18$15.8944%Jan 12, 2003 11:14 AM
    Rev Bruce
    Almighty
    45$153.1944%Jan 18, 2001 9:12 AM
    Capt Bruce
    Evans
    22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + +
    +
    + Next up: Applying widgets ›› +
    + +
    + + + + diff --git a/docs/example-option-textsorter-semver.html b/docs/example-option-textsorter-semver.html new file mode 100644 index 0000000..f0647a3 --- /dev/null +++ b/docs/example-option-textsorter-semver.html @@ -0,0 +1,125 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Semver Sorting + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • This method does not use a parser nor a widget, it uses semver.js to allow the sorting of semantic version numbers.
    • +
    • But this method requires a slightly modified version of semver.js for node. All modifications are signified within the file to ease updating.
    • +
    • The modified semver.js (semver-mod.js) is contained in the new "extras" subfolder. Please include it if you need this specific type of sort.
    • +
    • Invalid version numbers be sorted using a basic text sort, so they will be grouped with their similar version numbers, but not sorted properly; this demo has some extra code to highlight invalid version numbers.
    • +
    • In this demo, when the semver 2.0.0 compliant version column is sorted, the order column will be in sequential order.
    • +
    • Semver example order, from semver.org:
      1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
    • + +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + +
    OrderSemVer 2.0.0 compliant versioning
    61.0.0-beta.2
    81.0.0-rc.1
    21.0.0-alpha.1
    11.0.0-alpha
    101.0.0
    41.0.0-alpha.beta
    31.0.0-alpha.2
    71.0.0-beta.11
    91.0.0-rc.2
    51.0.0-beta
    111.0.0beta
    + +

    Javascript

    +
    +
    
    +	
    +

    CSS

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + +
    + + + diff --git a/docs/example-option-theme-metro-style.html b/docs/example-option-theme-metro-style.html new file mode 100644 index 0000000..2d91b9a --- /dev/null +++ b/docs/example-option-theme-metro-style.html @@ -0,0 +1,194 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Pager plugin + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Only the Windows Metro Dark theme has been included; for other colors: +
        +
      • Create your own dynamically by modifying this demo.
      • +
      • Change the @headerBackground to any valid color (some styles inspired by JTable have been listed in the comments).
      • +
      • If you don't like the look of the style, you might also want to check out this jQuery UI theme builder which creates metro style themes.
      • +
      +
    • +
    • For alternate thead & tfoot row colors, add the class name dark-row. See the HTML below.
    • +
    +

    + +

    Demo

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Table Title

    +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    +
    + + + + + + + +
    +
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Mathematicsmale8277079
    Student24Languagesfemale100911382
    Student25Mathematicsmale22968253
    Student26Languagesfemale37295659
    Student27Mathematicsmale86826923
    Student28Languagesfemale4425431
    Student29Mathematicsmale77472238
    Student30Languagesfemale19352310
    Student31Mathematicsmale90271750
    Student32Languagesfemale60753338
    Student33Mathematicsmale4313715
    Student34Languagesfemale77978144
    Student35Mathematicsmale5815195
    Student36Languagesfemale70617094
    Student37Mathematicsmale6036184
    Student38Languagesfemale6339011
    Student39Mathematicsmale50463238
    Student40Languagesfemale5175253
    Student41Mathematicsmale43342878
    Student42Languagesfemale11896095
    Student43Mathematicsmale48921888
    Student44Languagesfemale8225973
    Student45Mathematicsmale91733739
    Student46Languagesfemale481210
    Student47Mathematicsmale8910611
    Student48Languagesfemale90322118
    Student49Mathematicsmale42494972
    Student50Languagesfemale56376754
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    CSS

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + +
    + + + + diff --git a/docs/example-options-headers-digits-strings.html b/docs/example-options-headers-digits-strings.html new file mode 100644 index 0000000..9fd99a8 --- /dev/null +++ b/docs/example-options-headers-digits-strings.html @@ -0,0 +1,225 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Dealing with text strings in numerical sorts + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • This functionality is new as of version 2.0.10 (not part of the original plugin).
    • +
    • When a column is sorted numerically ( sorter:"digit" ) any text in that column will, by default, be given a zero value. Sort the last column (#9) to see the problem with this method.
    • +
    • Overall stringTo option added in version 2.1.16.
    • +
    • String options changed in version 2.1.16; setting the value to: +
        +
      • "max" will treat any text in that column as a value greater than the max (more positive) value. Renamed from "max+".
      • +
      • "min" will treat any text in that column as a value greater than the min (more negative) value. Renamed from "max-".
      • +
      • "top" will always sort the text to the top of the column.
      • +
      • "bottom" will always sort the text to the bottom of the column.
      • +
      • "none" or "zero" will treat the text as if it has a value of zero.
      • +
      +
    • +
    • Individual columns can be modified by adding the following (they all do the same thing), set in order of priority: +
        +
      • jQuery data data-string="top".
      • +
      • metadata class="{ string: 'top'}". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { string : 'top' } }.
      • +
      • header class name class="string-top".
      • +
      • Overall stringTo option.
      • +
      +
    • +
    • Sort columns three through eight to see how the sort has changed. Note that the text is sorted separately from the numeric values.
    • +
    • The emptyTo option defaults to bottom, so all empty cells will sort at the bottom of the table, except for the second column.
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Account #Difference3: Ratings (max)4: Ratings (min)5: Change (max)6: Change (min)7: Change (top)8: Change (bottom)9: Change (zero)
    A43-350101-.1-.1-.1-.1-.1
    A255330202N/A #1N/A #1N/A #1N/A #1N/A #1
    A3320303N/A #2N/A #2N/A #2N/A #2N/A #2
    A1-50404-8.4-8.4-8.4-8.4-8.4
    A102990505-2.2-2.2-2.2-2.2-2.2
    A10-1060697.497.497.497.497.4
    A020070723.623.623.623.623.6
    A554411.411.411.411.411.4
    A8704NRNR5.25.25.25.25.2
    A012NRNR
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-options-headers-locked.html b/docs/example-options-headers-locked.html new file mode 100644 index 0000000..fb9984b --- /dev/null +++ b/docs/example-options-headers-locked.html @@ -0,0 +1,132 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Lock sort order + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • This option was part of the original plugin, but it was broken.
    • +
    • Sort the first, third and fifth columns to see how the sort is locked.
    • +
    • Columns can be locked using any of the following methods (they all do the same thing), in order of priority (v2.3+): +
        +
      • jQuery data data-lockedorder="asc". (equivalent to data-locked-order="asc").
      • +
      • metadata class="{ lockedOrder: 'asc'}". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { lockedOrder: 'asc' } }.
      • +
      • header class name class="lockedOrder-asc".
      • +
      +
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAge TotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-options-headers-order.html b/docs/example-options-headers-order.html new file mode 100644 index 0000000..e493e17 --- /dev/null +++ b/docs/example-options-headers-order.html @@ -0,0 +1,135 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Set initial sort order + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Adding "sortInitialOrder" inside of the "headers" option was added in version 2.0.8 (not part of the original plugin).
    • +
    • In versions 2.3+, the initial sort order of the columns can be set using any of the following methods (they all do the same thing), in order of priority: +
        +
      • jQuery data data-sort-initial-order="desc" (equivalent to data-sortinitialorder="desc").
      • +
      • metadata class="{ sortInitialOrder: "desc" }". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { sortInitialOrder: "desc" } }.
      • +
      • header class name class="sortInitialOrder-desc".
      • +
      • overall sortInitialOrder option setting.
      • +
      +
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First Name (desc)Last Name (asc)Age (desc)Total (asc)Discount (desc) Date (asc)
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-options-headers-parser.html b/docs/example-options-headers-parser.html new file mode 100644 index 0000000..a466dec --- /dev/null +++ b/docs/example-options-headers-parser.html @@ -0,0 +1,108 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Skip parsing of content + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • In v2.17.1, this parser setting was added to reduce the time needed to process the table content during initialization and updating.
    • +
    • Disabling of the sorting of the same column should be observed as sorting will not work without the parsed data.
    • +
    • Disabling of filtering of the same column may be necessary, especially if the data requires parsing when comparisons of data is required (e.g. looking for dates <, <=, > or >= a certain time).
    • +
    • Use this setting by following any of these methods (they all do the same thing), in order of priority: +
        +
      • jQuery data data-parser="false".
      • +
      • metadata class="{ parser: "false" }". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { parser: "false" } }.
      • +
      • header class name class="parser-false".
      • +
      +
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + +
    NameAgeDate
    Peter Parker28Jul 6, 2006 8:14 AM
    John Hood33Dec 10, 2002 5:14 AM
    Clark Kent18Jan 12, 2003 11:14 AM
    Bruce Almighty45Jan 18, 2001 9:12 AM
    Bruce Evans22Jan 18, 2007 9:12 AM
    + +

    Cached Data

    +
    +
    
    +	
    +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + +
    + + + + diff --git a/docs/example-options-headers.html b/docs/example-options-headers.html new file mode 100644 index 0000000..d320ca1 --- /dev/null +++ b/docs/example-options-headers.html @@ -0,0 +1,140 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Disable sort + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • In tablesorter v2.18.1, you can now target a column by the class name of an element inside of a header; note that the span has the targeted class name in the first name column.
    • +
    • In tablesorter v2.0.5 and older, only the metadata and headers options methods were available.
    • +
    • In versions 2.3+, columns can be disabled using any of the following methods (they all do the same thing), in order of priority: +
        +
      • jQuery data data-sorter="false" (see the Javascript block below on how to set it directly).
      • +
      • metadata class="{ sorter: false }". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { sorter: false } }.
      • +
      • header class name class="sorter-false".
      • +
      +
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-pager-ajax.html b/docs/example-pager-ajax.html new file mode 100644 index 0000000..4f0f9f7 --- /dev/null +++ b/docs/example-pager-ajax.html @@ -0,0 +1,472 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Pager plugin - Ajax + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • In v2.13.3, the "ID" column has a default filter setting of ">30" and a descending sort, but neither is applied as this demo is not connected a server (just a basic JSON file).
    • +
    • In v2.11, the pager now stores any object returned by the `ajaxProcessing` function in `table.config.pager.ajaxData` (see the ajaxProcessing section below for more details).
    • +
    • In v2.10, the ajaxProcessing function was updated to only require a total number of rows to be returned, also instead of returning an array of table rows, you can build the table yourself and just return the jQuery object containing those rows. The addon triggers an update.
    • +
    • {filterList:fcol} was added to the ajaxUrl in version 2.6.
    • +
    • {sortList:col} was added to the ajaxUrl in version 2.4.5.
    • +
    • This update to the pager plugin that interacts with a database via ajax was added in version 2.0.32 and can be applied to the original tablesorter.
    • +
    • The ajaxUrl and ajaxProcessing function are both required options for this interaction to work properly.
    • +
    • The ajaxUrl contains a replaceable string to send the requested page ({page}), block size ({size}) or sort order ({sortList:name}).
    • +
    • The table header and footer text will be updated to match the JSON "header column #" text; but there is an issue with the table rendering improperly if the number of columns in the HTML and the number of columns in the JSON don't match.
    • +
    • Limitations of this demo: +
        +
      • This demo will not work when viewing it locally (except in Firefox) due to communication restrictions between the browser and your desktop.
      • +
      • The record size is limited to 25 records because this demo is not interacting with an actual database, but with four JSON files containing 25 records each.
      • +
      • Sorting of columns is disabled in this demo because no table data is cached when serverSideSorting is enabled. Sorting of columns is enabled in this demo by setting the serverSideSorting option to false after initialization. It only sorts the current table contents because there is no server to return sorted data.
      • +
      • The filters will only update the "Current Ajax url" because again, we're just working with JSON files here.
      • +
      +
    • +
    +

    * If you have a different JSON format and need help with the processing code, please ask the question on StackOverflow or message me directly (gmail; wowmotty). Please don't open an issue for help with code.

    +
    + +

    ajaxProcessing

    +
    + The ajaxProcessing function is needed to convert your custom JSON format into an array usable by the pager plugin (modified in 2.1.3)
    +
    + So, given this custom JSON format (this is only an example): +
    {
    +  "total_rows": 80,
    +
    +  "headers" : [
    +    "ID", "Name", "Country Code", "District", "Population"
    +  ],
    +
    +  "rows" : [{
    +    "ID": 1,
    +    "Name": "Kabul",
    +    "CountryCode": "AFG",
    +    "District": "Kabol",
    +    "Population": 1780000
    +  }, {
    +    "ID": 2,
    +    "Name": "Qandahar",
    +    "CountryCode": "AFG",
    +    "District": "Qandahar",
    +    "Population": 237500
    +  }, {
    +    ...
    +  }, {
    +    "ID": 25,
    +    "Name": "Haarlemmermeer",
    +    "CountryCode": "NLD",
    +    "District": "Noord-Holland",
    +    "Population": 110722
    +  }]
    +}
    +

    OBJECT returned

    +
      +
    • In v2.11, the ajaxProcessing can just return the above object directly (or don't even bother setting an ajaxProcessing function). + So, if an object is returned by the ajaxProcessing function, the data is stored in table.config.pager.ajaxData: +
        +
      • The object should contain attributes for total (numeric), headers (array) and rows (array of arrays).
      • +
      • A replacement output option can also be loaded via this method and must be included in the output attribute (i.e. ajaxData.output).
      • +
      • Additional attributes are also available to the output display by using the attribute key wrapped in curly brackets (e.g. {extra} from ajaxData.extra).
      • +
      • Additional attributes can also be objects or arrays and can be accessed via the output string as {extra:0} (for arrays) or {extra:key} for objects.
      • +
      • The page number is processed first, so it would be possible to use this string {extra:{page}} ({page} is a one-based index), or if you need a different value use {page+1} (zero-based index plus any number), or {page-1} (zero-based index minus any number).
      • +
      • For more details, please see issue #326.
      • +
      +
    • +
    +

    ARRAY returned

    +
      +
    • The ajaxProcessing function can return the data in the following format [ total, rows, headers (optional) ], +
      or in version 2.9+ [ rows, total, headers (optional) ], +
      or in v2.10, return a jQuery object within the array [ total, $rows ], or just [ total ]: +
      [
      +  // total # rows contained in the database
      +  80,
      +  // row data: array of arrays; each internal array has the table cell data for that row
      +  [
      +    [ 1, "Kabul", "AFG", "Kabol", 1780000 ],                 // [ "row1cell1", "row1cell2", ... "row1cellN" ],
      +    [ 2, "Qandahar", "AFG", "Qandahar", 237500 ],            // [ "row2cell1", "row2cell2", ... "row2cellN" ],
      +     ...
      +    [ 25, "Haarlemmermeer", "NLD", "Noord-Holland", 110722 ] // [ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
      +  ],
      +  [ "ID", "Name", "Country Code", "District", "Population" ] // [ "Header1", "Header2", ... "HeaderN" ] (optional)
      +]
    • +
    +
    + +
    + +

    Demo

    +Original Ajax url:
    +Current Ajax url: +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + First + Prev + + Next + Last + +
    12345
    12345
    + First + Prev + + Next + Last + +
    + +

    Javascript

    +
    +
    
    +	
    + +

    CSS

    +
    +
    /* pager wrapper, div */
    +.pager {
    +  padding: 5px;
    +}
    +/* pager wrapper, in thead/tfoot */
    +td.pager {
    +  background-color: #e6eeee;
    +}
    +/* pager navigation arrows */
    +.pager img {
    +  vertical-align: middle;
    +  margin-right: 2px;
    +}
    +/* pager output text */
    +.pager .pagedisplay {
    +  font-size: 11px;
    +  padding: 0 5px 0 5px;
    +  width: 50px;
    +  text-align: center;
    +}
    +
    +/*** loading ajax indeterminate progress indicator ***/
    +#tablesorterPagerLoading {
    +  background: rgba(255,255,255,0.8) url(icons/loading.gif) center center no-repeat;
    +  position: absolute;
    +  z-index: 1000;
    +}
    +
    +/*** css used when "updateArrows" option is true ***/
    +/* the pager itself gets a disabled class when the number of rows is less than the size */
    +.pager.disabled {
    +  display: none;
    +}
    +/* hide or fade out pager arrows when the first or last row is visible */
    +.pager img.disabled {
    +  /* visibility: hidden */
    +  opacity: 0.5;
    +  filter: alpha(opacity=50);
    +}
    +
    + +

    HTML

    +
    +
    <table class="tablesorter">
    +  <thead>
    +    <tr>
    +      <td class="pager" colspan="5">
    +        <img src="../addons/pager/icons/first.png" class="first"/>
    +        <img src="../addons/pager/icons/prev.png" class="prev"/>
    +        <span class="pagedisplay"></span> <!-- this can be any element, including an input -->
    +        <img src="../addons/pager/icons/next.png" class="next"/>
    +        <img src="../addons/pager/icons/last.png" class="last"/>
    +        <select class="pagesize">
    +          <option value="25">25</option>
    +        </select>
    +      </td>
    +    </tr>
    +    <tr>
    +      <th>1 data-value="&gt;30"</th> <!-- thead text will be updated from the JSON; make sure the number of columns matches the JSON data -->
    +      <th>2</th>
    +      <th>3</th>
    +      <th>4</th>
    +      <th>5</th>
    +    </tr>
    +  </thead>
    +  <tfoot>
    +    <tr>
    +      <th>1</th> <!-- tfoot text will be updated at the same time as the thead -->
    +      <th>2</th>
    +      <th>3</th>
    +      <th>4</th>
    +      <th>5</th>
    +    </tr>
    +    <tr>
    +      <td class="pager" colspan="5">
    +        <img src="../addons/pager/icons/first.png" class="first"/>
    +        <img src="../addons/pager/icons/prev.png" class="prev"/>
    +        <span class="pagedisplay"></span> <!-- this can be any element, including an input -->
    +        <img src="../addons/pager/icons/next.png" class="next"/>
    +        <img src="../addons/pager/icons/last.png" class="last"/>
    +        <select class="pagesize">
    +          <option value="25">25</option>
    +        </select>
    +      </td>
    +    </tr>
    +  </tfoot>
    +  <tbody> <!-- tbody will be loaded via JSON -->
    +  </tbody>
    +</table>
    + +
    + + + +
    + + + + + diff --git a/docs/example-pager-filtered.html b/docs/example-pager-filtered.html new file mode 100644 index 0000000..779806d --- /dev/null +++ b/docs/example-pager-filtered.html @@ -0,0 +1,468 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Pager plugin + Filter widget + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! The following are not part of the original plugin: +

      +
    • When using this pager plugin with the filter widget, make sure that the removeRows option is set to false or it won't work.
    • +
    • This combination was not possible in tablesorter versions prior to version 2.4.
    • +
    • This combination can not be applied to the original tablesorter.
    • +
    +

    + +

    Demo

    +
    + +

    +
    + Page: + First + Prev + + Next + Last + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Mathematicsmale8277079
    Student24Languagesfemale100911382
    Student25Mathematicsmale22968253
    Student26Languagesfemale37295659
    Student27Mathematicsmale86826923
    Student28Languagesfemale4425431
    Student29Mathematicsmale77472238
    Student30Languagesfemale19352310
    Student31Mathematicsmale90271750
    Student32Languagesfemale60753338
    Student33Mathematicsmale4313715
    Student34Languagesfemale77978144
    Student35Mathematicsmale5815195
    Student36Languagesfemale70617094
    Student37Mathematicsmale6036184
    Student38Languagesfemale6339011
    Student39Mathematicsmale50463238
    Student40Languagesfemale5175253
    Student41Mathematicsmale43342878
    Student42Languagesfemale11896095
    Student43Mathematicsmale48921888
    Student44Languagesfemale8225973
    Student45Mathematicsmale91733739
    Student46Languagesfemale481210
    Student47Mathematicsmale8910611
    Student48Languagesfemale90322118
    Student49Mathematicsmale42494972
    Student50Languagesfemale56376754
    + +
    + Page: First + Prev + + Next + Last + +
    + +

    Javascript

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-pager.html b/docs/example-pager.html new file mode 100644 index 0000000..402c66c --- /dev/null +++ b/docs/example-pager.html @@ -0,0 +1,454 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Pager plugin + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! The following are not part of the original plugin: +

      +
    • In v2.19.0, added pageAndSize method which allows setting both the pager page & size.
    • +
    • In v2.17.6, added {startRow:input} and {page:input} variables to the output option.
    • +
    • This pager plugin can be applied to the original tablesorter, but there is one exception - setting the removeRows option to false will break the sort.
    • +
    • There have been lots of changes made in version 2.1, please check out the change log.
    • +
    • In v2.11, the savePages option was added to saves the current page size and number (requires storage script).
    • +
    +

    + +

    Triggered Events  

    +
      +
    • Pager events will appear here.
    • +
    •  
    • +
    •  
    • +
    •  
    • +
    •  
    • +
    + +

    Demo

    +
    + +

    +
    + First + Prev + + Next + Last + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Mathematicsmale8277079
    Student24Languagesfemale100911382
    Student25Mathematicsmale22968253
    Student26Languagesfemale37295659
    Student27Mathematicsmale86826923
    Student28Languagesfemale4425431
    Student29Mathematicsmale77472238
    Student30Languagesfemale19352310
    Student31Mathematicsmale90271750
    Student32Languagesfemale60753338
    Student33Mathematicsmale4313715
    Student34Languagesfemale77978144
    Student35Mathematicsmale5815195
    Student36Languagesfemale70617094
    Student37Mathematicsmale6036184
    Student38Languagesfemale6339011
    Student39Mathematicsmale50463238
    Student40Languagesfemale5175253
    Student41Mathematicsmale43342878
    Student42Languagesfemale11896095
    Student43Mathematicsmale48921888
    Student44Languagesfemale8225973
    Student45Mathematicsmale91733739
    Student46Languagesfemale481210
    Student47Mathematicsmale8910611
    Student48Languagesfemale90322118
    Student49Mathematicsmale42494972
    Student50Languagesfemale56376754
    + +
    + First + Prev + + Next + Last + + +
    + +

    Javascript

    +
    +
    
    +	
    + +

    CSS

    +
    +
    /* pager wrapper, div */
    +.tablesorter-pager {
    +  padding: 5px;
    +}
    +/* pager wrapper, in thead/tfoot */
    +td.tablesorter-pager {
    +  background-color: #e6eeee;
    +  margin: 0; /* needed for bootstrap .pager gets a 18px bottom margin */
    +}
    +/* pager navigation arrows */
    +.tablesorter-pager img {
    +  vertical-align: middle;
    +  margin-right: 2px;
    +  cursor: pointer;
    +}
    +
    +/* pager output text */
    +.tablesorter-pager .pagedisplay {
    +  padding: 0 5px 0 5px;
    +  width: 50px;
    +  text-align: center;
    +}
    +
    +/* pager element reset (needed for bootstrap) */
    +.tablesorter-pager select {
    +  margin: 0;
    +  padding: 0;
    +}
    +
    +/*** css used when "updateArrows" option is true ***/
    +/* the pager itself gets a disabled class when the number of rows is less than the size */
    +.tablesorter-pager.disabled {
    +  display: none;
    +}
    +/* hide or fade out pager arrows when the first or last row is visible */
    +.tablesorter-pager .disabled {
    +  /* visibility: hidden */
    +  opacity: 0.5;
    +  filter: alpha(opacity=50);
    +  cursor: default;
    +}
    +
    + +

    HTML

    +
    +
    <table class="tablesorter">
    +<!-- view page source to see the entire table -->
    +</table>
    +
    +<!-- pager -->
    +<div id="pager" class="pager">
    +  <form>
    +    <img src="first.png" class="first"/>
    +    <img src="prev.png" class="prev"/>
    +    <span class="pagedisplay"></span> <!-- this can be any element, including an input -->
    +    <img src="next.png" class="next"/>
    +    <img src="last.png" class="last"/>
    +    <select class="pagesize">
    +      <option value="10">10</option>
    +      <option value="20">20</option>
    +      <option value="30">30</option>
    +      <option value="40">40</option>
    +    </select>
    +  </form>
    +</div>
    + +
    + + +

    Pager Change Log

    + + + + +
    + + + + diff --git a/docs/example-parsers-advanced.html b/docs/example-parsers-advanced.html new file mode 100644 index 0000000..e2abcf2 --- /dev/null +++ b/docs/example-parsers-advanced.html @@ -0,0 +1,154 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Writing custom parsers, advanced use + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • In v2.15.0, the parsed parameter +
        +
      • This parameter is a flag used by the filter widget.
      • +
      • When true, the filter widget will only search through parsed data for matches.
      • +
      • If false (default value), the filter widget will search through the cell text for matches.
      • +
      +
    • +
    • This method of writing custom parsers will NOT work with the original tablesorter 2.0.5b plugin because the format function does not consistently provide the cell and cellIndex parameters.
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name (Last)Originally from...Birthday
    Joe AllenSouth CarolinaJan 15
    Lisa TorresMarylandMarch 2nd
    Peter Louis FranklinCoventryBoxing Day (Dec 26th)
    Maria Consuela de Los Angeles Ortiz Del Toro-JonesTexas10 Mayo
    Mike "the Smasher" BigglesworthRhode Island22nd of June
    Fredrick SmithOhio10th Mar
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-parsers-class-name.html b/docs/example-parsers-class-name.html new file mode 100644 index 0000000..2bba75e --- /dev/null +++ b/docs/example-parsers-class-name.html @@ -0,0 +1,131 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Disable or set the column parser using class names + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • In tablesorter version 2.0.5 and older, only the metadata and headers options methods were available to set the parsers.
    • +
    • In versions 2.0.11+, parsers could be set using class names.
    • +
    • Currently (versions 2.3+), parsers can be set using any of the following methods (they all do the same thing), in order of priority: +
        +
      • jQuery data data-sorter="text" (see the Javascript block below on how to set it directly).
      • +
      • metadata class="{ sorter: "text" }". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { sorter: "text" } }.
      • +
      • header class name class="sorter-text".
      • +
      +
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotal Discount Date
    PeterParker28($9.99)20%Jul 6, 2006 8:14 AM
    John33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent1844%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%
    BruceEvans22N/AJan 18, 2007 9:12 AM
    Evans18$13.1911%Jul 6, 2006 8:14 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-parsers-date-range.html b/docs/example-parsers-date-range.html new file mode 100644 index 0000000..650fcd8 --- /dev/null +++ b/docs/example-parsers-date-range.html @@ -0,0 +1,127 @@ + + + + + jQuery plugin: Tablesorter - Date range parsers + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Added v2.21.0, this parser will allow sorting & filtering a date range.
    • +
    • While processing, the parser will rearrange the range so that it is always saved to the cache as "low - high" (note that the "8/12/2014 - 7/10/2014" row sorts correctly, eventhough the later date is first)
    • +
    • This is almost exactly the same demo as Custom Filter Widget Search Type (example 2), but it was added to demonstrate the other supported date formats.
    • +
    • Click on any of the buttons below to test it out.
    • +
    +

    + +

    Demo

    +
    Find:
    + (mm/dd/yyyy) column
    + (dd/mm/yyyy) column
    + (yyy/mm/dd) column +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Date range (mm/dd/yyyy - mm/dd/yyyy)Date range (dd/mm/yyyy - dd/mm/yyyy)Date range (yyyy/mm/dd - yyyy/mm/dd)
    04/28/2014 - 07/18/201428/04/2014 - 18/07/20142014/04/28 - 2014/07/18
    04/30/2014 - 05/21/201430/04/2014 - 21/05/20142014/04/30 - 2014/05/21
    7/15/201415/7/20142014/7/15
    07/12/2014 - 07/23/201412/07/2014 - 23/07/20142014/07/12 - 2014/07/23
    05/20/2014 - 05/23/201420/05/2014 - 23/05/20142014/05/20 - 2014/05/23
    8/12/2014 - 7/10/201412/8/2014 - 10/7/20142014/8/12 - 2014/7/10
    + +

    HTML

    +
    +
    
    +	
    + +

    Javascript

    +
    +
    
    +	
    + +
    + + + diff --git a/docs/example-parsers-dates.html b/docs/example-parsers-dates.html new file mode 100644 index 0000000..a302067 --- /dev/null +++ b/docs/example-parsers-dates.html @@ -0,0 +1,175 @@ + + + + + jQuery plugin: Tablesorter - Assorted date parsers + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Parse Dates with these parsers +
        +
      • The "Date" column is using the sugar library to parse dates. Make sure to include the sugar library and the sugar-date-parser.
      • +
      • The "Weekday" column uses the included "weekday" parser. You can modify parser to match whatever language you are using.
      • +
      • The "Month" column uses the included "month" parser. You can also modify the month names within the parser to match whatever language you are using.
      • +
      • The "Year" column is just using the included two digit year parser: +
          +
        • Formats for "mmddyy", "ddmmyy" and "yymmdd" are available
        • +
        • Within the parser code is a range variable which is set to 50 years range, which sets the date be within +/- range of the listed two digit year.
        • +
        • So if the current year is 2020, and the listed two digit year is 80 (2080 - 2020 > 50), it becomes 1980.
        • +
        • If the listed two digit year is 50 (2050 - 2020 < 50), then it becomes 2050. I hope that makes it clearer.
        • +
        • Try out the two digit year calculator below the table.
        • +
        • In v2.14.0, the range can be set using the dateRange option (see the initialization code below).
        • +
        +
      • +
      • The "Time" column is using the built-in time parser which has been always been included with tablesorter .
      • +
      +
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + +
    DateWeekdayMonthMM/DD/YY Time
    next fridayFridayAug1/1/1212:00 PM
    todayThursSeptember1/1/1200:00
    last TuesdayFriMar1/1/1018:00
    the day after tomorrowWedJuly1/1/1313:00
    2010-05-25T12:30:40.299+01:00MondayJan1/1/111:30 PM
    May 25th of next yearTuesNov1/1/1114:00
    25 May 2010TuesdayNovember1/1/111:58 PM
    the last day of MarchMonDecember1/1/122:10 PM
    last monthWednesdayApril1/1/1413:50
    one day before yesterdayThursdayFeb1/1/084:00 AM
    + +

    Two digit year calculator:

    +
    two digit year becomes 2020
    +
    + ( + ) +
    + +

    Page Header

    +
    +
    <!-- blue theme stylesheet with additional css styles added in v2.0.17 -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<!-- tablesorter plugin -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- load month, weekday and two digit year parsers -->
    +<script src="../js/parsers/parser-date-month.js"></script>
    +<script src="../js/parsers/parser-date-weekday.js"></script>
    +<script src="../js/parsers/parser-date-two-digit-year.js"></script>
    +
    +<!-- http://sugarjs.com/dates#comparing_dates -->
    +<script src="../js/sugar.js"></script>
    +<script src="../js/parsers/parser-date-sugar.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + + + + + diff --git a/docs/example-parsers-duration.html b/docs/example-parsers-duration.html new file mode 100644 index 0000000..b4076dc --- /dev/null +++ b/docs/example-parsers-duration.html @@ -0,0 +1,164 @@ + + + + + jQuery plugin: Tablesorter - Duration & countdown parsers + + + + + + + + + + + + + + + + + + + + + + + +
    +

    +
    + +
    +

    Notes

    +
    +
      +
    • Both the duration & countdown parsers are contained in the parser-duration.js file.
    • +
    • Neither parser checks for valid time settings, all it does is parse the values to make them sortable.
    • +
    +
    +

    Duration Parser

    +
    +
      +
    • The duration parser will convert a duration time "####y ####d ####h ####m ####s" into a sortable value.
    • +
    • It is not designed to convert 365 days into 1 year, nor perform any other conversions.
    • +
    • Options: +
        +
      • durationLabels +
          +
        • Default: '(?:years|year|y),(?:days|day|d),(?:hours|hour|h),(?:minutes|minute|min|m),(?:seconds|second|sec|s)'
        • +
        • Add more or change the duration labels by modifying this option; separate the labels with a comma.
        • +
        • The label doesn't need to include regex. If you are only using one letter, change the label to 'y,d,h,m,s'
        • +
        +
      • +
      • durationLength +
          +
        • Default: 4
        • +
        • Modify this value so that the max length of values is included.
        • +
        • The default value of 4 will include values up to 9,999
        • +
        • Values less than or equal to 99,999 will require this option to be set to 5
        • +
        • Values less than or equal to 999,999 need this value set to 6, etc.
        • +
        +
      • +
      +
    • +
    +
    +

    Countdown Parser

    +
    +
      +
    • The countdown parser will convert a countdown time "####:####:####" into a sortable value.
    • +
    • It is not designed to deal with invalid times like 65:99 (65 minutes & 99 seconds).
    • +
    • This parser also uses the durantionLength value to set the maximum length of each value used in the countdown. +
        +
      • Default: 4
      • +
      • Modify this value so that the max length of values is included.
      • +
      • The default value of 4 will include values up to 9,999
      • +
      • Values less than or equal to 99,999 will require this option to be set to 5
      • +
      • Values less than or equal to 999,999 need this value set to 6, etc.
      • +
      +
    • +
    +
    +
    + +

    Demo

    + + parsed values within the column + +
    + + + + + + + + + + + + + + + + + + + + + +
    NameDurationCountdown
    Frank1y 23d 12h 44m 9s2:21:16
    Fred12d 12h 14m 20s44:25
    Albert12h 14m 3s1:9:2
    Aaron3d 11h 13m 22s1:5:5
    Oliver3d 11h 14s4:33:33
    Xavier11m 41s59:59
    Henry12m10:22:32
    Lucy23d 12h 44m 10s2:43:52
    Marsha1y 1h 1m 1s3:12:18
    Pat12 days 12hours 44minutes 50 seconds22:51
    George33s1:53:21
    Oscar24d 12h 11m 11s51:12
    + +

    Script

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + + + diff --git a/docs/example-parsers-feet-inch-fraction.html b/docs/example-parsers-feet-inch-fraction.html new file mode 100644 index 0000000..a426ffc --- /dev/null +++ b/docs/example-parsers-feet-inch-fraction.html @@ -0,0 +1,128 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Feet-inch-fraction parser + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    Demo

    + parsed values within the column +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Distance (feet & inches)Fractions
    3'
    11"22/12
    5'
    3"5 ½
    ½"
    5' 11"¾
    10' 11"
    10' 1"5/6
    10' 4"11/16
    5' 9"
    5 1/2'2
    5' 3/4"2⅞
    5' 5/8"3 ¾
    5' 3 1/2"3 ⅛
    10' 3⅛"3/7
    10' 2⅜"3⅜
    10' 3⅝"3 ½
    10' 2⅞"3 ⅝
    5' 3¼"2⅝
    5 ' 2 ½ "2/3
    10' 2¾"5 ⅝
    5' 2 ½"5 ⅜
    5' 2.5"5/16
    5' 2 1/2"2 3/5
    10 ' 1 "3
    +
    + +

    Page Header

    +
    +
    <!-- blue theme stylesheet -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<!-- tablesorter plugin -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- load feet-inch-fraction parser -->
    +<script src="../js/parsers/parser-feet-inch-fraction.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + +
    + + + + + + diff --git a/docs/example-parsers-file-type.html b/docs/example-parsers-file-type.html new file mode 100644 index 0000000..cfe47fd --- /dev/null +++ b/docs/example-parsers-file-type.html @@ -0,0 +1,190 @@ + + + + + jQuery plugin: Tablesorter 2.0 - File Type Parser + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
      +
    • If this parser finds the file type extension within the equivalents list, it will add the equivalents group name to the beginning of the file so that during sorting, those file names will sort by the group they are in.
    • +
    • Please look in the javascript code section below for a full list of default equivalents. This list is by no means extensive, but it can be easily modified or extended as needed.
    • +
    • To add a new group to the equivalents list, just define a new group, before initializing tablesorter, as follows: +
      $.tablesorter.fileTypes.equivalents['xx'] = "A|B|C"
      +
    • +
    • But lets say your table is primarily being used to sort font file names, but you notice "svg" is listed under "vectors" (graphics) so you want to modify the equivalents list. Do it as follows: +
      $.tablesorter.fileTypes.equivalents["Vectors"] = "awg|ai|eps|cdr"; // redefine vectors without "svg"
      +$.tablesorter.fileTypes.equivalents["Fonts"] += '|svg'; // just add it to the end (but first include the vertical bar = shift+\; above the enter key)!
      +
    • +
    • This parser only looks to see if an extension exists within the equivalents list, so any separator can be used (spaces, commas or vertical bars).
    • +
    + +

    Demo

    +
    + + (swap media column between "group-separator-1" & "group-separator-2") + + + + + + + + + + + + + + + + + + + + + + + + +
    Desktop FilesTablesorter FilesMediaMedia Files
    github.urlpackage.jsonMusic Disc #1 - Green Day - Boulevard of Broken DreamsMuse - Supermassive Black Hole.mp3
    tablesorter.zipreadme.mdMusic Disc #1 - Green Day - HolidayGorillaz - Feel Good Inc.mp3
    learn-git.pdfindex.htmlMusic Disc #1 - M83 - Midnight CityM83 - Midnight City.mp4
    pancake-cat.jpgjquery.tablesorter.jsMusic Disc #1 - Bob Marley - Everything is Gonna Be AlrightRadiohead - Creep.ogg
    to-do-list.txttheme.blue.cssMusic Disc #1 - Bob Marley - JammingEllie Goulding - Lights.flv
    css-tips.docxtheme.lessMusic Disc #1 - Bob Marley - Oh, Baby I Love Your WayImagine Dragons - Radioactive.avi
    frisbee-cat.pngblack-asc.gifMusic Disc #1 - Bob Marley - Red Red WineMuse - Supermassive Black Hole.avi
    Diablo.lnkgreen-unsorted.psdMusic Disc #1 - Bob Marley - No Woman No CryAlex Clare - Too Close.wma
    Warcraft.lnkjquery.tablesorter.widgets.jsMusic Disc #2 - Sublime - SanteriaThe XX - Intro.mp3
    google.urlglyphicons-halflings.pngMusic Disc #2 - Sublime - What I GotAWOLNATION - Sail.wmv
    swimming-cat.gifcomponent.jsonMusic Disc #2 - Massive Attack - TeardropOf Monsters and Men - Little Talks.m4a
    photo-album.zipthemes.htmlMusic Disc #2 - Massive Attack - Dissolved GirlNina Simone - Feeling Good.flac
    +
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + + + +
    + + + diff --git a/docs/example-parsers-ignore-articles.html b/docs/example-parsers-ignore-articles.html new file mode 100644 index 0000000..dea5f8c --- /dev/null +++ b/docs/example-parsers-ignore-articles.html @@ -0,0 +1,434 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Ignore leading articles parser + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • In v2.17.8, added a new option ignoreArticlesExcept option which allows ignoring a set pattern.
    • +
    • This parser can not be applied to the original plugin.
    • +
    +
    + +

    Setup

    +
    +
      +
    • Set the language (French shown below; English is set by default) to use by adding any of the following (they all do the same thing), set in order of priority (v2.8.2): +
        +
      • jQuery data data-ignore-articles="fr".
      • +
      • metadata class="{ ignoreArticles : 'fr' }". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { ignoreArticles : 'fr' } }.
      • +
      • header class name class="ignoreArticles-fr".
      • +
      +
      +
    • +
    • In v2.17.8, you can set up a string to ignore, e.g. keep a title intact like "A to Z", as follows: +
        +
      • jQuery data data-ignore-articles-except="a to".
      • +
      • metadata class="{ ignoreArticlesExcept : 'a to' }". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { ignoreArticlesExcept : 'a to' } }.
      • +
      +
    • +
    • To add more than one title to ignore, separate them using a vertical bar (shift+\) +
      headers: {
      +  0: {
      +    ignoreArticles : 'en',
      +    // no special parsing for titles like "A to Z" or "A B C" or "A One"
      +    ignoreArticlesExcept : 'a to|a b |a one'
      +  }
      +}
      Note If your title needs a space (e.g. "A B C") make sure it isn't at the end of the ignoreArticlesExcept string; spaces on either end get stripped away. +
    • +
    +
    + +

    Customizing

    +
    +
      +
    • To add a custom language to the parser, use the following code: +
      $.extend( $.tablesorter.ignoreArticles, {
      +  "xx" : "a, l'_, de la"
      +});
      +
      +$('table').tablesorter({
      +  headers: {
      +    2: {
      +      sorter: 'ignoreArticles',
      +      ignoreArticles : 'xx',
      +      ignoreArticlesExcept : 'a to'
      +    }
      +  }
      +});
      +
        +
      • where xx is the ignoreArticles id (abbreviation for the language)
      • +
      • Each leading article must be separated by a comma and will be case-insensitive.
      • +
      • Leading articles will only be removed if they are followed by a space; spaces are automatically included when parsed unless the article definition is followed by an underscore. See the l'_ note below.
      • +
      • a is an example of a leading article which will be removed. So, "A Fistfull of Dollars" will only parse "Fistfull of Dollars" and will sort with the other words that start with an "F".
      • +
      • l'_ includes an underscore (_); this tells the parser to not add a space after the word. So a title like "l'enfant" will parse as "enfant".
      • +
      • de la is an example showing that the parser can remove a multiple-word article.
      • +
      +
    • +
    • Some languages have been included by default. The information below was obtained from this wikipedia page, so if you discover any errors, or if you want to contribute another language, please open an issue. +
      $.tablesorter.ignoreArticles = {
      +  "en" : "the, a, an",
      +  "de" : "der, die, das, des, dem, den, ein, eine, einer, eines, einem, einen",
      +  "nl" : "de, het, de, een",
      +  "es" : "el, la, lo, los, las, un, una, unos, unas",
      +  "pt" : "o, a, os, as, um, uma, uns, umas",
      +  "fr" : "le, la, l'_, les, un, une, des",
      +  "it" : "il, lo, la, l'_, i, gli, le, un', uno, una, un",
      +  "hu" : "a, az, egy"
      +};
    • +
    +
    + +
    + +

    Demo

    +
    +

    IMDB top 250 movies (3/27/2013)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankRatingTitle Votes
    1.9.2The Shawshank Redemption (1994)941,067
    2.9.2The Godfather (1972)673,484
    3.9.0The Godfather: Part II (1974)434,176
    4.8.9Pulp Fiction (1994)732,799
    5.8.9The Good, the Bad and the Ugly (1966)286,482
    6.8.912 Angry Men (1957)231,572
    7.8.9The Dark Knight (2008)917,028
    8.8.9Schindler's List (1993)483,623
    9.8.8The Lord of the Rings: The Return of the King (2003)672,581
    10.8.8Fight Club (1999)716,995
    11.8.8Star Wars: Episode V - The Empire Strikes Back (1980)462,561
    12.8.8The Lord of the Rings: The Fellowship of the Ring (2001)697,724
    13.8.8One Flew Over the Cuckoo's Nest (1975)393,499
    14.8.7Inception (2010)732,630
    15.8.7Goodfellas (1990)411,044
    16.8.7Star Wars (1977)518,660
    17.8.7Seven Samurai (1954)146,754
    18.8.7Forrest Gump (1994)617,489
    19.8.7The Matrix (1999)679,951
    20.8.7The Lord of the Rings: The Two Towers (2002)603,969
    21.8.7City of God (2002)308,820
    22.8.6Se7en (1995)547,794
    23.8.6The Silence of the Lambs (1991)459,251
    24.8.6Once Upon a Time in the West (1968)129,773
    25.8.6Casablanca (1942)252,435
    26.8.6The Usual Suspects (1995)431,028
    27.8.6Raiders of the Lost Ark (1981)394,043
    28.8.6Rear Window (1954)190,219
    29.8.6It's a Wonderful Life (1946)163,164
    30.8.6Psycho (1960)239,467
    31.8.6Léon: The Professional (1994)399,997
    32.8.5Sunset Blvd. (1950)85,756
    33.8.5American History X (1998)433,917
    34.8.5Memento (2000)495,175
    35.8.5Apocalypse Now (1979)276,646
    36.8.5Terminator 2: Judgment Day (1991)425,770
    37.8.5Saving Private Ryan (1998)482,123
    38.8.5Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb (1964)226,703
    39.8.5City Lights (1931)54,820
    40.8.5Alien (1979)319,629
    41.8.5Django Unchained (2012)263,202
    42.8.5North by Northwest (1959)139,339
    43.8.5Spirited Away (2001)211,121
    44.8.5Modern Times (1936)69,431
    45.8.5Citizen Kane (1941)197,473
    46.8.5The Dark Knight Rises (2012)568,024
    47.8.5The Shining (1980)333,295
    48.8.5Back to the Future (1985)377,606
    49.8.4The Pianist (2002)260,234
    50.8.4The Departed (2006)478,100
    51.8.4Life Is Beautiful (1997)206,585
    52.8.4M (1931)62,112
    53.8.4Vertigo (1958)145,330
    54.8.4American Beauty (1999)495,829
    55.8.4Paths of Glory (1957)70,416
    56.8.4Taxi Driver (1976)285,135
    57.8.4Double Indemnity (1944)59,206
    58.8.4Aliens (1986)289,891
    59.8.4Toy Story 3 (2010)277,784
    60.8.4WALL·E (2008)376,223
    61.8.4The Lives of Others (2006)147,553
    62.8.4Gladiator (2000)528,198
    63.8.4The Green Mile (1999)390,685
    64.8.4The Intouchables (2011)164,584
    65.8.4A Clockwork Orange (1971)318,549
    66.8.4Amélie (2001)314,747
    67.8.4The Great Dictator (1940)68,287
    68.8.4The Prestige (2006)432,239
    69.8.4Lawrence of Arabia (1962)117,981
    70.8.4To Kill a Mockingbird (1962)128,498
    71.8.4Reservoir Dogs (1992)369,352
    72.8.4Das Boot (1981)106,465
    73.8.4The Third Man (1949)73,465
    74.8.4Requiem for a Dream (2000)336,877
    75.8.3Cinema Paradiso (1988)81,418
    76.8.3The Treasure of the Sierra Madre (1948)49,807
    77.8.3Eternal Sunshine of the Spotless Mind (2004)389,500
    78.8.3The Lion King (1994)313,388
    79.8.3Once Upon a Time in America (1984)129,414
    80.8.3Star Wars: Episode VI - Return of the Jedi (1983)361,397
    81.8.3Full Metal Jacket (1987)270,902
    82.8.3L.A. Confidential (1997)264,295
    83.8.3Chinatown (1974)130,976
    84.8.3Braveheart (1995)426,632
    85.8.3Oldboy (2003)189,333
    86.8.3Monty Python and the Holy Grail (1975)239,427
    87.8.3Singin' in the Rain (1952)89,152
    88.8.3Some Like It Hot (1959)107,775
    89.8.3Metropolis (1927)66,774
    90.8.3Amadeus (1984)162,968
    91.8.3Bicycle Thieves (1948)50,266
    92.8.3Rashomon (1950)61,981
    93.8.32001: A Space Odyssey (1968)246,317
    94.8.3All About Eve (1950)51,722
    95.8.3Unforgiven (1992)169,421
    96.8.3The Sting (1973)104,985
    97.8.3Indiana Jones and the Last Crusade (1989)298,740
    98.8.3The Apartment (1960)62,712
    99.8.3Raging Bull (1980)144,339
    100.8.3The Bridge on the River Kwai (1957)92,073
    101.8.3Witness for the Prosecution (1957)31,562
    102.8.3Grave of the Fireflies (1988)65,417
    103.8.3Die Hard (1988)349,451
    104.8.3Batman Begins (2005)535,306
    105.8.3A Separation (2011)79,685
    106.8.3Yojimbo (1961)44,988
    107.8.3Snatch. (2000)344,587
    108.8.3Inglourious Basterds (2009)436,200
    109.8.3For a Few Dollars More (1965)83,738
    110.8.3Downfall (2004)149,623
    111.8.3Pan's Labyrinth (2006)277,965
    112.8.2The Great Escape (1963)98,813
    113.8.2Mr. Smith Goes to Washington (1939)49,357
    114.8.2Up (2009)319,413
    115.8.2On the Waterfront (1954)62,092
    116.8.2Toy Story (1995)319,895
    117.8.2The Elephant Man (1980)98,958
    118.8.2The Seventh Seal (1957)66,074
    119.8.2Heat (1995)261,142
    120.8.2The General (1926)31,115
    121.8.2The Maltese Falcon (1941)73,450
    122.8.2Blade Runner (1982)293,867
    123.8.2Gran Torino (2008)316,184
    124.8.2Rebecca (1940)54,605
    125.8.2The Kid (1921)30,188
    126.8.2Wild Strawberries (1957)36,922
    127.8.2Scarface (1983)301,908
    128.8.2Fargo (1996)256,474
    129.8.2The Big Lebowski (1998)308,325
    130.8.2Touch of Evil (1958)47,592
    131.8.2Ran (1985)50,064
    132.8.2The Deer Hunter (1978)145,262
    133.8.2Cool Hand Luke (1967)75,625
    134.8.2The Gold Rush (1925)36,715
    135.8.1Lock, Stock and Two Smoking Barrels (1998)244,635
    136.8.1Sin City (2005)415,871
    137.8.1No Country for Old Men (2007)353,912
    138.8.1It Happened One Night (1934)38,738
    139.8.1Strangers on a Train (1951)56,857
    140.8.1The Avengers (2012)475,869
    141.8.1Jaws (1975)236,363
    142.8.1The Sixth Sense (1999)422,262
    143.8.1Platoon (1986)180,937
    144.8.1Casino (1995)192,252
    145.8.1The Thing (1982)155,679
    146.8.1Trainspotting (1996)273,789
    147.8.1High Noon (1952)51,097
    148.8.1Butch Cassidy and the Sundance Kid (1969)91,992
    149.8.1The Wizard of Oz (1939)169,985
    150.8.1Hotel Rwanda (2004)161,201
    151.8.1Kill Bill: Vol. 1 (2003)419,696
    152.8.1Good Will Hunting (1997)312,846
    153.8.1Warrior (2011)159,949
    154.8.1The Secret in Their Eyes (2009)63,447
    155.8.1Annie Hall (1977)112,605
    156.8.1Gone with the Wind (1939)133,071
    157.8.1Notorious (1946)47,266
    158.8.1The Grapes of Wrath (1940)37,590
    159.8.1Into the Wild (2007)226,286
    160.8.1My Neighbor Totoro (1988)74,354
    161.8.1V for Vendetta (2005)445,345
    162.8.1Life of Brian (1979)163,492
    163.8.1Finding Nemo (2003)351,617
    164.8.1How to Train Your Dragon (2010)207,521
    165.8.1Dial M for Murder (1954)57,132
    166.8.1The King's Speech (2010)247,037
    167.8.1There Will Be Blood (2007)224,943
    168.8.1Ben-Hur (1959)95,091
    169.8.1The Terminator (1984)334,304
    170.8.1The Big Sleep (1946)42,449
    171.8.1Network (1976)61,922
    172.8.1The Night of the Hunter (1955)39,940
    173.8.1Million Dollar Baby (2004)267,944
    174.8.1Stand by Me (1986)159,982
    175.8.1Groundhog Day (1993)250,675
    176.8.1Donnie Darko (2001)358,003
    177.8.1The Hobbit: An Unexpected Journey (2012)260,350
    178.8.1Twelve Monkeys (1995)282,004
    179.8.1Dog Day Afternoon (1975)111,658
    180.8.1Black Swan (2010)325,866
    181.8.1Amores Perros (2000)108,303
    182.8.1The 400 Blows (1959)40,671
    183.8.1Mary and Max (2009)57,268
    184.8.1The Bourne Ultimatum (2007)285,964
    185.8.1Life of Pi (2012)156,722
    186.8.1Gandhi (1982)96,275
    187.8.1Persona (1966)31,689
    188.8.0Howl's Moving Castle (2004)104,225
    189.8.0The Killing (1956)39,702
    190.8.0The Graduate (1967)133,213
    191.8.0The Princess Bride (1987)186,593
    192.8.0A Beautiful Mind (2001)296,347
    193.8.0 (1963)48,845
    194.8.0Slumdog Millionaire (2008)373,963
    195.8.0The Hustler (1961)38,935
    196.8.0Who's Afraid of Virginia Woolf? (1966)33,649
    197.8.0La strada (1954)28,752
    198.8.0Rocky (1976)193,474
    199.8.0The Manchurian Candidate (1962)48,813
    200.8.0Anatomy of a Murder (1959)28,092
    201.8.0The Artist (2011/I)113,331
    202.8.0The Wild Bunch (1969)46,187
    203.8.0The Exorcist (1973)188,999
    204.8.0Stalag 17 (1953)30,022
    205.8.0Rope (1948)57,554
    206.8.0The Man Who Shot Liberty Valance (1962)35,292
    207.8.0Barry Lyndon (1975)62,239
    208.8.0Sleuth (1972)26,820
    209.8.0Stalker (1979)38,428
    210.8.0Infernal Affairs (2002)57,096
    211.8.0In the Name of the Father (1993)54,640
    212.8.0The Truman Show (1998)345,615
    213.8.0Roman Holiday (1953)55,590
    214.8.0Memories of Murder (2003)27,373
    215.8.0Pirates of the Caribbean: The Curse of the Black Pearl (2003)457,277
    216.8.0District 9 (2009)332,916
    217.8.0Monsters, Inc. (2001)277,654
    218.8.0A Fistful of Dollars (1964)71,024
    219.8.0Ip Man (2008)70,724
    220.8.0The Diving Bell and the Butterfly (2007)61,322
    221.8.0Ratatouille (2007)274,240
    222.8.0Harry Potter and the Deathly Hallows: Part 2 (2011)257,398
    223.8.0Star Trek (2009)291,734
    224.8.0A Streetcar Named Desire (1951)54,316
    225.8.0The Perks of Being a Wallflower (2012)98,357
    226.8.0La Haine (1995)54,972
    227.8.0Beauty and the Beast (1991)163,508
    228.8.0Shutter Island (2010)370,474
    229.8.03 Idiots (2009)63,883
    230.8.0All Quiet on the Western Front (1930)34,318
    231.8.0Rosemary's Baby (1968)91,657
    232.8.0Nausicaä of the Valley of the Wind (1984)45,761
    233.8.0Rain Man (1988)235,025
    234.8.0Harvey (1950)33,525
    235.8.0Incendies (2010)29,047
    236.8.0Like Stars on Earth (2007)28,610
    237.8.0Mystic River (2003)225,582
    238.8.0Jurassic Park (1993)290,452
    239.8.0Manhattan (1979)68,578
    240.8.0Papillon (1973)53,163
    241.8.0Spring, Summer, Fall, Winter... and Spring (2003)36,974
    242.8.0The Wrestler (2008)187,480
    243.8.0Nosferatu (1922)47,665
    244.8.0The Help (2011)150,081
    245.8.0In the Mood for Love (2000)43,683
    246.8.0Big Fish (2003)253,904
    247.7.9The Untouchables (1987)146,540
    248.7.9Arsenic and Old Lace (1944)41,392
    249.7.9Castle in the Sky (1986)47,537
    250.7.9Rio Bravo (1959)29,442
    + +
    + +

    Page Header

    +
    +
    <!-- tablesorter -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- load ignore-articles parser -->
    +<script src="../js/parsers/parser-ignore-articles.js"></script>
    +<script>
    +$(function() {
    +
    +  $('table').tablesorter({
    +    theme: 'blue',
    +    widgets: ['zebra'],
    +    sortList: [[2, 0]],
    +    headers: {
    +      2: {
    +        sorter: 'ignoreArticles',
    +        ignoreArticles : 'fr',
    +        ignoreArticlesExcept : ''
    +      }
    +    }
    +  });
    +
    +});
    +</script>
    +
    + +
    + + \ No newline at end of file diff --git a/docs/example-parsers-ip-address.html b/docs/example-parsers-ip-address.html new file mode 100644 index 0000000..734032e --- /dev/null +++ b/docs/example-parsers-ip-address.html @@ -0,0 +1,137 @@ + + + + + jQuery plugin: Tablesorter 2.0 - IP address parsers + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • This parser can be applied to the original plugin.
    • +
    • The default "ipAdress" parser (IPv4) is included with the original tablesorter; it was moved to the parser-network.js file in v2.18.0.
    • +
    • A parser for IPv6 was added in v2.12 and named "ipv6Address": +
        +
      • Unlike some other custom parsers, this one will auto-detect & check for a valid IPv6 address since the same address can be represented in many different ways. Some examples are shown in the demo table below.
      • +
      • IPv6 addresses are stored in the cache in their canonical decimal form, without the colons, for faster & easier numerical sorting.
      • +
      • Extensive unit tests are included with this parser.
      • +
      +
    • +
    • If the parser doesn't auto-detect which column has IPv6 addresses, use the headers sorter option to set it: +
      $(function(){
      +  $('table').tablesorter({
      +    headers: {
      +      1: { sorter: 'MAC' },
      +      // 2: { sorter: 'ipAddress' }, this parser is auto-detected
      +      3: { sorter: 'ipv6Address' }
      +    }
      +  });
      +});
      +
    • +
    +

    + +

    Demo

    + +
    +
    + + + + + + + + + + + + + + + + + + + + +
    NameMACIPv4IPv6
    Fred12:06:D2:8E:56:BF1.2.3.4f0f0::1
    Ginger546F.5903.3C9B1.1.1.1f0::1
    Mike3c-cf-44-cd-6e-d62.222.33.441:2:3:4:5::7:8
    Georgeff-68-3d-e8-b4-0d255.255.255.255::2:3:4
    Harryf566.6dfd.2df2251.2.33.4f0f0:f::1
    Frank12:69:13:D8:FA:61251.002.31.4::
    KristyA031.5FED.43BC2.221.003.40:0:0:0:0:0:0:0
    Lily82-2D-FF-FA-CD-6C251.02.32.4f0f0::f:1
    Maria125c395f08f21.2.3.441:2:3:4:5:6:1.2.3.4
    + +
    + +

    Page Header

    +
    +
    <!-- tablesorter -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- load ipv6 parser -->
    +<script src="../js/parsers/parser-network.js"></script>
    +<script>
    +$(function() {
    +
    +  $('table').tablesorter({
    +    theme: 'blue',
    +    widgets: ['zebra'],
    +    sortList: [[1, 0]],
    +    headers: {
    +      1: { sorter: 'MAC' },
    +      // 2: { sorter: 'ipAddress' }, this parser is auto-detected
    +      3: { sorter: 'ipv6Address' }
    +    }
    +  });
    +
    +});
    +</script>
    +
    + +
    + + + + + \ No newline at end of file diff --git a/docs/example-parsers-jquery-data.html b/docs/example-parsers-jquery-data.html new file mode 100644 index 0000000..c192123 --- /dev/null +++ b/docs/example-parsers-jquery-data.html @@ -0,0 +1,125 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Disable or set the column parser using data + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! This functionality was added in version 2.2.3 (it is not part of the original plugin). +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotal Discount Date
    PeterParker28($9.99)20%Jul 6, 2006 8:14 AM
    John33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent1844%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%
    BruceEvans22N/AJan 18, 2007 9:12 AM
    Evans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-parsers-metric.html b/docs/example-parsers-metric.html new file mode 100644 index 0000000..638c888 --- /dev/null +++ b/docs/example-parsers-metric.html @@ -0,0 +1,123 @@ + + + + + jQuery plugin: Tablesorter - Metric Parser + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • This parser will convert numbers with metric prefixes ("Mega", "Giga", etc) into appropriate values so they are sorted correctly.
    • +
    • The base name must be included in the header: +
        +
      • The base is the unit of measure, such as "byte", "meter", "liter", etc.
      • +
      • When saving the base, include both the abbreviation and full name of the base separated by a vertical bar (shift-\) b|byte.
      • +
      • Store this information within the header's data-attribute (data-metric-name="b|byte").
      • +
      • If no base information is found, it will default to m|meter.
      • +
      +
    • +
    • Because metric prefixes can be applied to binary values, the parser will calculate the cached value based on the binary multiple, i.e. "1 kb" is actually "1024 bytes". See this article for more details.
    • +
    • This parser does not (yet) support the IEC recommendations for binary prefixes (i.e. "kibibyte (Kib)", "mebibyte (MiB)", etc).
    • +
    • Supported prefixes include: Yotta (1024), Zetta (1021), Exa (1018), Peta (1015), Tera (1012), Giga (109), Mega (106), kilo (103), hecto (102), deka (101), deci (10-1), centi (10-2), milli (10-3), micro (10-6), nano (10-9), pico (10-12), femto (10-15), atto (10-18), zepto (10-21) and yocto (10-24).
    • +
    • This demo includes the stored metric values within the table cells, toggle the view using the button below.
    • +
    +

    + +

    Demo

    + +
    + + + + + + + + + + + + + + + + + + + +
    Metric (binary) SizeMetric Length
    1 byte1 nm
    1 kb1 kilometer
    1 Gigabyte1 Gm
    10 Mb1 Tm
    1 Mb1,000 mm
    1 Tb1 meter
    1 Petabyte1 hm
    1 Zb1 dam
    1,025 Mb1 Mm
    1,000 kilobytes1 dm
    1 Eb1 µm
    1023 Mb1 pm
    + +

    Page Header

    +
    +
    <!-- blue theme stylesheet with additional css styles added in v2.0.17 -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<!-- tablesorter plugin -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- load metric parser -->
    +<script src="../js/parsers/parser-metric.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + + + diff --git a/docs/example-parsers-named-numbers.html b/docs/example-parsers-named-numbers.html new file mode 100644 index 0000000..ee58507 --- /dev/null +++ b/docs/example-parsers-named-numbers.html @@ -0,0 +1,157 @@ + + + + + jQuery plugin: Tablesorter - Named Numbers Parser + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • In v2.22.0, this parser will now ignore commas, periods and quotes adjacent to the named number word (e.g. "10 million, three...").
    • +
    • This parser will convert named numbers into appropriate values so they are sorted correctly.
    • +
    • Named numbers include values: +
        +
      • zero to twenty; by one ("one", "two", "three", ..., "nineteen", "twenty")
      • +
      • twenty to hundred; by ten ("twenty", "thirty", "forty", ... "ninety", "hundred")
      • +
      • thousand (1e3) to duotrigintillion (1e99); by 10^(3n+3) value ("thousand", "million", "billion", ... "untrigintillion", "duotrigintillion")
      • +
      • googl (1e100)
      • +
      +
    • +
    • Even bigger named values will need to be manually added to the parser code; see this wikipedia page for more names.
    • +
    +

    + +

    Demo

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NumbersLarge Numbers
    5 hundredone hundred and fifty two million
    four hundred thousand five hundred fourty three710,231,000
    one hundred and fifty five10 million, three hundred sixty five thousand, four hundred and ninety one
    negative twelve10 million and three
    minus three hundred and fifty seven thousand four hundred and two6 billion eight thousand
    zero3 hundred quadrillion
    three hundred twenty145 decillion
    forty-two700 thousand
    ninety-nine thousand nine hundred and ninety-nine2.3 million
    2.3 thousand2.3 googl
    minus one8 hundred thousand
    seven hundred fifty two9 hundred-million
    one hundred and thirty-threeTwenty-three trillion
    + +

    Page Header

    +
    +
    <!-- blue theme stylesheet with additional css styles added in v2.0.17 -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<!-- tablesorter plugin -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- load metric parser -->
    +<script src="../js/parsers/parser-named-numbers.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + +
    + + + + + + diff --git a/docs/example-parsers-roman.html b/docs/example-parsers-roman.html new file mode 100644 index 0000000..8d38cd1 --- /dev/null +++ b/docs/example-parsers-roman.html @@ -0,0 +1,239 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Roman Numeral Parser + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • This parser (added v2.17.3) will convert roman numerals into their decimal equivalent so the table column can be sorted correctly.
    • +
    • There are actually 3 separate parsers included with this script. +
        +
      • They are very similar, but were written to cover different use cases.
      • +
      • Refer to each in their separate sections below.
      • +
      +
    • +
    • This demo includes the stored roman numeral values within the table cells, toggle the view using the button directly above the table.
    • +
    +
    + +

    "roman" parser

    +
    +
      +
    • This parser is optimized for columns that contain only roman numerals.
    • +
    • In the demo below, this parser is used for the "Short" and "Long" columns.
    • +
    • This parser has no option settings.
    • +
    +
    $(function() {
    +
    +	$("table").tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		headers: {
    +			0 : { sorter: 'roman' },
    +			1 : { sorter: 'roman' }
    +		}
    +	});
    +
    +});
    + +
    + +

    "roman-ignore" parser

    +
    + This parser is designed to use the roman_ignore option to either: + +

    Ignore The Last "X" Characters

    + For content that contains a roman number followed by an alphabetical character, such as "Ia" or "IIb", this parser can be set to ignore the last character (spaces are trimmed automatically): +
    $(function() {
    +
    +	$("table").tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		headers: {
    +			2 : { sorter: 'roman-ignore' }
    +		},
    +		// roman numeral parser option
    +		// ignore the last (1) character(s) in column 2 (zero-based index)
    +		// the two zeros in the array are just placeholders ( [ , , 1 ] works as well )
    +		roman_ignore: [ 0, 0, 1 ]
    +
    +	});
    +
    +});
    + +

    Remove Non-Roman Numerals

    + For cells that contain a bit more complex layout, you can define a regular expression to ignore (remove) certain parts of the content.
    +
    + The value obtained from the roman_ignore option array is used within a javascript replace function, so it can be either a regular expression or a string.
    +
    + In this example (see the "Ignore regex" column in the demo below), content at the beginning of the cell is set to be ignored. This should leave the roman numeral string to be parsed by this script (spaces are trimmed automatically). +
    $(function() {
    +
    +	$("table").tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		headers: {
    +			3 : { sorter: 'roman-ignore' }
    +		},
    +		// roman numeral parser option
    +		// ignore any words at the beginning of column 3 (zero-based index) using a regular expression
    +		// additionally, if all column content contains the same character to ignore, a string can be
    +		// passed within this option, e.g. "Chapter "
    +		// the three zeros in the array are just placeholders ( [ , , , /^(\w+\s)/ ] works as well )
    +		roman_ignore: [ 0, 0, 0, /^(\w+\s)/ ]
    +
    +	});
    +
    +});
    +
    + +

    "roman-extract" parser

    +
    +
      +
    • This parser will attempt to extract out a roman numeral block from the cell content.
    • +
    • It's not perfect. If the content contains two blocks of roman numerals, they will be combined. For example, +
        +
      • If a cell contains X plus VII, the parser will extract out XVII and return a value of 17.
      • +
      • Or worse yet, if a cell contains VI minus X, the parser will extract out VIX which is not a valid roman numeral, so it will instead return the initial value of VI minus X. If this is the case, use the "roman-ignore" parser instead.
      • +
      +
    • +
    +
    $(function() {
    +
    +	$("table").tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		headers: {
    +			4 : { sorter: 'roman-extract' }
    +		}
    +	});
    +
    +});
    +
    + +
    + +

    Demo

    + + parsed values within the column + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Pure Roman NumeralsIgnore Non-Roman NumeralsExtract Roman Numerals
    ShortLongIgnore last (1) character *Ignore regex (/^(\w+\s)/)Extract
    IMDLXXXViiiaMark I2000 XXVII Sydney
    MXIMDCLXVIiiibMark IV2012 XXX London
    XIIMMDCCCLVIIIiaMark V2020 XXXII Tokyo
    CXIMMCCIvaMark VII2004 XXVIII Athens
    XXIMDCCCXLvi bMk III1980 XXII Moscow
    XIIIMMMCXXIXivaMod X1972 XX Munich
    VDLXXVIIviaMod IV2016 XXXI Rio de Janeiro
    XMDCLXVxiaMk VIII1996 XXVI Atlanta
    XIMDXVIIIxiizMod XII1976 XXI Montreal
    CLXIMDCCCLXxdMk 01992 XXV Barcelona
    CCCCXCIiiicMk VI1988 XXIV Seoul
    LVMLXXXxxfMk II1984 XXIII Los Angeles
    IXDCCLVIIligMod L2008 XXIX Beijing
    + * Ignoring the last letter (set number to ignore in roman_ignore option array; notice that "vi b" sorts before "via" - spaces do matter!)

    + +

    Page Header

    +
    +
    <!-- blue theme stylesheet with additional css styles added in v2.0.17 -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<!-- tablesorter plugin; requires jQuery -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- load roman numeral parser -->
    +<script src="../js/parsers/parser-roman.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + +
    + + + + + diff --git a/docs/example-parsers.html b/docs/example-parsers.html new file mode 100644 index 0000000..8554621 --- /dev/null +++ b/docs/example-parsers.html @@ -0,0 +1,171 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Writing custom parsers + + + + + + + + + + + + + + + + + + + + + +
    + +
    + Notes about the addParser template: +
      +
    • The id block is required and must be unique.
    • +
    • The is block will allow the parser to be used for autodetecting the parser +
        +
      • Most custom parsers are made for a specific set of data/column, so the is block usually just returns false telling the plugin that the parser doesn't match any columns.
      • +
      • If so desired, the function provides four parameters: s contains the text from the cell, table is the table DOM element, cell is the current cell DOM element and $cell is the current cell as a jQuery object (added v2.18.0).
      • +
      • This function must return true before the plugin will use the custom parser's format block to process the column content.
      • +
      • In version 2.7.4, the is block became optional because most parsers just return false.
      • +
      +
    • +
    • The format block is used to normalize your data and return it to the plugin for sorting +
        +
      • Within this function, modify the given text from the cell (s) or obtain parameters and/or other data from the cell (cell) then return this data to the plugin.
      • +
      • As an example, the date parser takes the date string (e.g. "12/25/2013") and converts it into a numeric value (1387951200000; ref) to make sorting and comparing dates easier.
      • +
      • Use the cellIndex if the cells within columns contain different data - see this demo for an example.
      • +
      +
    • +
    • The parsed block (added v2.15.0) +
        +
      • This parameter is a flag used by the filter widget.
      • +
      • When true, the filter widget will only search through parsed data for matches.
      • +
      • If false (default value), the filter widget will search through the cell text for matches.
      • +
      • Currently, only the parsers for inputs, checkboxes and selects have this parameter set to true.
      • +
      +
    • +
    • The type block sets the type of sort to use: +
        +
      • Set it to either "text" or "numeric".
      • +
      • This tells the plugin the type of sorter to use.
      • +
      • Text type sorting uses a natural sort and is a tiny bit slower than a pure numeric sort.
      • +
      +
    • +
    +
    + +

    Add Parser Template

    +
    $.tablesorter.addParser({
    +  // use a unique id
    +  id: 'myparser',
    +  is: function(s, table, cell, $cell) {
    +    // s is the text from the cell
    +    // table is the current table (as a DOM element; not jQuery object)
    +    // cell is the current table cell (DOM element)
    +    // $cell is the current table cell (jQuery object; added v2.18.0)
    +    // return false if you don't want this parser to be auto detected
    +    return false;
    +  },
    +  format: function(s, table, cell, cellIndex) {
    +    // s is the text from the cell
    +    // table is the current table (as a DOM element; not jQuery object)
    +    // cell is the current table cell (DOM element)
    +    // cellIndex is the current cell's column index
    +    // format your data for normalization
    +    // (i.e. do something to get and/or modify your data, then return it)
    +    return s;
    +  },
    +  // flag for filter widget (true = ALWAYS search parsed values; false = search cell text)
    +  parsed: false,
    +  // set the type to either numeric or text (text uses a natural sort function
    +  // so it will work for everything, but numeric is faster for numbers
    +  type: 'numeric'
    +});
    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + +
    NameMajorGenderEnglishJapaneseCalculusOverall grades
    Student01Languagesmale807075medium
    Student02Mathematicsmale9088100good
    Student03Languagesfemale859580good
    Student04Languagesmale205065bad
    Student05Mathematicsfemale707870medium
    Student06Mathematicsmale446560bad
    + +

    Javascript

    +

    Grades Parser Code

    +
    +
    
    +	
    +

    HTML

    +

    + NOTE! Assigning the parser using a class name was added in version 2.0.11 (it is not part of the original plugin; use the headers option in older versions). +

    +

    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-trigger-sort.html b/docs/example-trigger-sort.html new file mode 100644 index 0000000..354ca8f --- /dev/null +++ b/docs/example-trigger-sort.html @@ -0,0 +1,230 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Sort table using a link outside the table + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Demo

    + +

    + NOTE! +

      +
    • In v2.22.0, a "click" event can be triggered on the header cell to toggle the sort.
    • +
    • In v2.17.0, added sorton values (a)scending, (d)escending, (n)ext, (s)ame & (o)pposite. Use the demo below help understand how to use these settings.
    • +
    • In v2.9, a "sort" event can be triggered on the header cell to toggle the sort.
    • +
    +

    + +

    + + +
    +
    + + +

    Sort Ascending/Descending

    + Use 0 or "a" for ascending sorts, and 1 or "d" for descending sorts*
    +
    + ([[0,0]]) ([[0,"a"],[1,"d"]])
    + ([[0,1]]) ([[0,"d"],[1,"a"]]) +
    $("#table1").trigger("sorton", [ [] ]);
    + * "a" & "d" values added v2.17.0. +
    +
    + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    +
    +
    +
    + + +
    +
    + + +

    Toggle sort (Next)

    + Either trigger a "sort" on the desired column, or "sorton" on the table using the "n" value*.
    + Toggle the option (false), then try these sorts (click a third time).
    + +
    + Trigger "sort" event: (v2.9) +
    $("#table2").find("th:contains(Discount)").trigger("sort");
    + + ([[0,"n"]])
    + ([[0,"n"],[1,"n"]]; columns are independent) +
    $("#table2").trigger("sorton", [ [] ]);
    + * "n" value added v2.17.0. +
    +
    + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    +
    +
    +
    + + +
    +
    + +

    Sort Same/Opposite

    + The same ("s") or opposite ("o") sort values always set the column sort based on the primary column*.
    + Toggle the option (false), then try these sorts (click a third time).
    +
    + ([[0,"s"]]; always defaults to Asc sort if set on primary column)
    + ([[0,0],[1,"s"]])
    + ([[0,1],[1,"s"]])
    + ([[0,"n"],[1,"s"]])
    + ([[0,"n"],[1,"o"]])
    + ([[0,"n"],[1,"o"],[2,"n"]])
    + ([[0,"n"],[1,"o"],[2,"s"]])
    + ([[0,"n"],[1,"o"],[2,"s"],[3,"o"]]) +
    $("#table3").trigger("sorton", [ [] ]);
    + * "s" & "o" values added v2.17.0. +
    +
    + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    +
    +
    +
    + +
    + +
    + + + diff --git a/docs/example-triggers.html b/docs/example-triggers.html new file mode 100644 index 0000000..e1d267d --- /dev/null +++ b/docs/example-triggers.html @@ -0,0 +1,1111 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Triggers sortStart and sortEnd + + + + + + + + + + + + + + + + + + + + +
    + +

    Javascript

    +
    +
    
    +	
    + +

    Sort Events

    +
      +
    • Sort events will appear here.
    • +
    •  
    • +
    •  
    • +
    + +

    Demo

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Languagesfemale85808080
    student23Mathematicsmale8277079
    student24Languagesfemale100911382
    student25Mathematicsmale22968253
    student26Languagesfemale37295659
    student27Mathematicsmale86826923
    student28Languagesfemale4425431
    student29Mathematicsmale77472238
    student30Languagesfemale19352310
    student31Mathematicsmale90271750
    student32Languagesfemale60753338
    student33Mathematicsmale4313715
    student34Languagesfemale77978144
    student35Mathematicsmale5815195
    student36Languagesfemale70617094
    student37Mathematicsmale6036184
    student38Languagesfemale6339011
    student39Mathematicsmale50463238
    student40Languagesfemale5175253
    student41Mathematicsmale43342878
    student42Languagesfemale11896095
    student43Mathematicsmale48921888
    student44Languagesfemale8225973
    student45Mathematicsmale91733739
    student46Languagesfemale481210
    student47Mathematicsmale8910611
    student48Languagesfemale90322118
    student49Mathematicsmale42494972
    student50Languagesfemale56376754
    student51Mathematicsmale48315563
    student52Languagesfemale38917174
    student53Mathematicsmale26385100
    student54Languagesfemale75811623
    student55Mathematicsmale65521553
    student56Languagesfemale23527994
    student57Mathematicsmale80226112
    student58Languagesfemale5357979
    student59Mathematicsmale96323517
    student60Languagesfemale16766527
    student61Mathematicsmale20572223
    student62Languagesfemale19838778
    student63Mathematicsmale258330
    student64Languagesfemale021993
    student65Mathematicsmale20861396
    student66Languagesfemale28358757
    student67Mathematicsmale36502910
    student68Languagesfemale6090966
    student69Mathematicsmale34614398
    student70Languagesfemale13379183
    student71Mathematicsmale47805782
    student72Languagesfemale69433737
    student73Mathematicsmale54609421
    student74Languagesfemale71143446
    student75Mathematicsmale89963117
    student76Languagesfemale28482994
    student77Mathematicsmale100652024
    student78Languagesfemale11969033
    student79Mathematicsmale53559339
    student80Languagesfemale11008444
    student81Mathematicsmale63789643
    student82Languagesfemale41698235
    student83Mathematicsmale9498139
    student84Languagesfemale94729177
    student85Mathematicsmale71324525
    student86Languagesfemale9896437
    student87Mathematicsmale8917367
    student88Languagesfemale43416879
    student89Mathematicsmale7382237
    student90Languagesfemale94839337
    student91Mathematicsmale8284261
    student92Languagesfemale46413069
    student93Mathematicsmale47198583
    student94Languagesfemale39146462
    student95Mathematicsmale71314628
    student96Languagesfemale90944540
    student97Mathematicsmale468925
    student98Languagesfemale41434799
    student99Mathematicsmale71908973
    student100Languagesfemale31641856
    student101Mathematicsmale52136999
    student102Languagesfemale86398318
    student103Mathematicsmale23659880
    student104Languagesfemale781005766
    student105Mathematicsmale69214397
    student106Languagesfemale2727838
    student107Mathematicsmale86964634
    student108Languagesfemale13846664
    student109Mathematicsmale35959881
    student110Languagesfemale30286254
    student111Mathematicsmale60313585
    student112Languagesfemale19811969
    student113Mathematicsmale6659854
    student114Languagesfemale38804016
    student115Mathematicsmale5849697
    student116Languagesfemale59976954
    student117Mathematicsmale0347949
    student118Languagesfemale1871285
    student119Mathematicsmale9387759
    student120Languagesfemale42232690
    student121Mathematicsmale17396689
    student122Languagesfemale26759018
    student123Mathematicsmale34237780
    student124Languagesfemale5267742
    student125Mathematicsmale5628581
    student126Languagesfemale51356744
    student127Mathematicsmale64644434
    student128Languagesfemale67917982
    student129Mathematicsmale4261579
    student130Languagesfemale7210369
    student131Mathematicsmale9477511
    student132Languagesfemale27958548
    student133Mathematicsmale92114061
    student134Languagesfemale4185660
    student135Mathematicsmale8422652
    student136Languagesfemale7604721
    student137Mathematicsmale51813090
    student138Languagesfemale5861673
    student139Mathematicsmale48383731
    student140Languagesfemale33265660
    student141Mathematicsmale84842975
    student142Languagesfemale7235654
    student143Mathematicsmale31427082
    student144Languagesfemale94875035
    student145Mathematicsmale91528026
    student146Languagesfemale78657979
    student147Mathematicsmale50905971
    student148Languagesfemale15686633
    student149Mathematicsmale17363413
    student150Languagesfemale30956973
    student151Mathematicsmale20534958
    student152Languagesfemale19896060
    student153Mathematicsmale5282203
    student154Languagesfemale66985366
    student155Mathematicsmale5852258
    student156Languagesfemale3443688
    student157Mathematicsmale4309114
    student158Languagesfemale34186731
    student159Mathematicsmale79733452
    student160Languagesfemale15613727
    student161Mathematicsmale74771545
    student162Languagesfemale52621958
    student163Mathematicsmale77602795
    student164Languagesfemale9619357
    student165Mathematicsmale51637519
    student166Languagesfemale32447299
    student167Mathematicsmale82845763
    student168Languagesfemale53128567
    student169Mathematicsmale4916846
    student170Languagesfemale39341665
    student171Mathematicsmale10068884
    student172Languagesfemale14256352
    student173Mathematicsmale74261560
    student174Languagesfemale1158892
    student175Mathematicsmale6247231
    student176Languagesfemale65263242
    student177Mathematicsmale83786924
    student178Languagesfemale14100743
    student179Mathematicsmale2835897
    student180Languagesfemale1483962
    student181Mathematicsmale1442469
    student182Languagesfemale6452722
    student183Mathematicsmale15262785
    student184Languagesfemale9149407
    student185Mathematicsmale87894287
    student186Languagesfemale75766188
    student187Mathematicsmale11486630
    student188Languagesfemale7379272
    student189Mathematicsmale98365815
    student190Languagesfemale8028656
    student191Mathematicsmale3633974
    student192Languagesfemale5923390
    student193Mathematicsmale9461933
    student194Languagesfemale82497242
    student195Mathematicsmale8059830
    student196Languagesfemale89179027
    student197Mathematicsmale4622667
    student198Languagesfemale65757377
    student199Mathematicsmale77975413
    student200Languagesfemale78195796
    student201Mathematicsmale92211180
    student202Languagesfemale45499340
    student203Mathematicsmale74258753
    student204Languagesfemale1571234
    student205Mathematicsmale82979573
    student206Languagesfemale82605898
    student207Mathematicsmale266411100
    student208Languagesfemale6496045
    student209Mathematicsmale96819663
    student210Languagesfemale2439069
    student211Mathematicsmale8664710
    student212Languagesfemale764507
    student213Mathematicsmale59122677
    student214Languagesfemale21259382
    student215Mathematicsmale22186451
    student216Languagesfemale92419828
    student217Mathematicsmale32481417
    student218Languagesfemale62368556
    student219Mathematicsmale33379087
    student220Languagesfemale24436084
    student221Mathematicsmale6593751
    student222Languagesfemale9197576
    student223Mathematicsmale86293227
    student224Languagesfemale63596891
    student225Mathematicsmale57739568
    student226Languagesfemale38545987
    student227Mathematicsmale53627264
    student228Languagesfemale62847273
    student229Mathematicsmale1308358
    student230Languagesfemale35658087
    student231Mathematicsmale76202850
    student232Languagesfemale9176633
    student233Mathematicsmale9229961
    student234Languagesfemale47699839
    student235Mathematicsmale21443882
    student236Languagesfemale19865178
    student237Mathematicsmale28454936
    student238Languagesfemale78194981
    student239Mathematicsmale72694720
    student240Languagesfemale17436656
    student241Mathematicsmale901944
    student242Languagesfemale618251
    student243Mathematicsmale1377213
    student244Languagesfemale8005854
    student245Mathematicsmale8331859
    student246Languagesfemale90992912
    student247Mathematicsmale89238159
    student248Languagesfemale7226283
    student249Mathematicsmale28105047
    student250Languagesfemale8914894
    student251Mathematicsmale15233769
    student252Languagesfemale27821036
    student253Mathematicsmale49456423
    student254Languagesfemale79756374
    student255Mathematicsmale2566475
    student256Languagesfemale36262958
    student257Mathematicsmale17226673
    student258Languagesfemale70919745
    student259Mathematicsmale34307830
    student260Languagesfemale77578677
    student261Mathematicsmale1259687
    student262Languagesfemale11609771
    student263Mathematicsmale12303558
    student264Languagesfemale46152340
    student265Mathematicsmale4481926
    student266Languagesfemale15683215
    student267Mathematicsmale5585098
    student268Languagesfemale42303224
    student269Mathematicsmale781009957
    student270Languagesfemale55338725
    student271Mathematicsmale25972993
    student272Languagesfemale39351843
    student273Mathematicsmale35179958
    student274Languagesfemale86522724
    student275Mathematicsmale97387376
    student276Languagesfemale206198
    student277Mathematicsmale9336947
    student278Languagesfemale423152
    student279Mathematicsmale6118962
    student280Languagesfemale99898794
    student281Mathematicsmale4895900
    student282Languagesfemale60473130
    student283Mathematicsmale64241076
    student284Languagesfemale9937468
    student285Mathematicsmale0986869
    student286Languagesfemale66824959
    student287Mathematicsmale86143717
    student288Languagesfemale27489327
    student289Mathematicsmale8489668
    student290Languagesfemale9902057
    student291Mathematicsmale50967242
    student292Languagesfemale9822792
    student293Mathematicsmale1994287
    student294Languagesfemale9897922
    student295Mathematicsmale75307764
    student296Languagesfemale5198553
    student297Mathematicsmale25958672
    student298Languagesfemale20753735
    student299Mathematicsmale4924111
    student300Languagesfemale2832891
    student301Mathematicsmale4163425
    student302Languagesfemale29167790
    student303Mathematicsmale89415182
    student304Languagesfemale40912434
    student305Mathematicsmale7474978
    student306Languagesfemale6375562
    student307Mathematicsmale30733490
    student308Languagesfemale82919593
    student309Mathematicsmale6247382
    student310Languagesfemale39101257
    student311Mathematicsmale89642067
    student312Languagesfemale56369241
    student313Mathematicsmale99809974
    student314Languagesfemale31796493
    student315Mathematicsmale5327055
    student316Languagesfemale35152960
    student317Mathematicsmale31476960
    student318Languagesfemale88281366
    student319Mathematicsmale65121640
    student320Languagesfemale28171940
    student321Mathematicsmale241004470
    student322Languagesfemale20598352
    student323Mathematicsmale17608291
    student324Languagesfemale95994337
    student325Mathematicsmale30189931
    student326Languagesfemale3478386
    student327Mathematicsmale9863435
    student328Languagesfemale54239846
    student329Mathematicsmale97934518
    student330Languagesfemale2774077
    student331Mathematicsmale9704137
    student332Languagesfemale52377620
    student333Mathematicsmale74186819
    student334Languagesfemale77100339
    student335Mathematicsmale38537718
    student336Languagesfemale18132610
    student337Mathematicsmale90478770
    student338Languagesfemale38493674
    student339Mathematicsmale100641372
    student340Languagesfemale74254152
    student341Mathematicsmale37131613
    student342Languagesfemale24341583
    student343Mathematicsmale2056728
    student344Languagesfemale4522572
    student345Mathematicsmale19117535
    student346Languagesfemale6583115
    student347Mathematicsmale16663611
    student348Languagesfemale1239540
    student349Mathematicsmale752742
    student350Languagesfemale88926055
    student351Mathematicsmale92709145
    student352Languagesfemale74765944
    student353Mathematicsmale63696094
    student354Languagesfemale3685548
    student355Mathematicsmale39962148
    student356Languagesfemale4134275
    student357Mathematicsmale6434733
    student358Languagesfemale95146355
    student359Mathematicsmale701001382
    student360Languagesfemale522410021
    student361Mathematicsmale040869
    student362Languagesfemale024932
    student363Mathematicsmale23108694
    student364Languagesfemale1538649
    student365Mathematicsmale7623310
    student366Languagesfemale35357894
    student367Mathematicsmale294243100
    student368Languagesfemale668510
    student369Mathematicsmale74155683
    student370Languagesfemale7543908
    student371Mathematicsmale4060470
    student372Languagesfemale62421749
    student373Mathematicsmale31464454
    student374Languagesfemale30344787
    student375Mathematicsmale9694152
    student376Languagesfemale85432992
    student377Mathematicsmale7904025
    student378Languagesfemale36407285
    student379Mathematicsmale5368882
    student380Languagesfemale87783879
    student381Mathematicsmale89978338
    student382Languagesfemale21194910
    student383Mathematicsmale47126850
    student384Languagesfemale37124995
    student385Mathematicsmale8408851
    student386Languagesfemale89612748
    student387Mathematicsmale10478761
    student388Languagesfemale1692656
    student389Mathematicsmale57331347
    student390Languagesfemale90357775
    student391Mathematicsmale31474753
    student392Languagesfemale942412
    student393Mathematicsmale6119817
    student394Languagesfemale457577
    student395Mathematicsmale6729212
    student396Languagesfemale516456
    student397Mathematicsmale93147714
    student398Languagesfemale1893427
    student399Mathematicsmale93775791
    student400Languagesfemale67778032
    student401Mathematicsmale5889417
    student402Languagesfemale3056053
    student403Mathematicsmale28253259
    student404Languagesfemale62348164
    student405Mathematicsmale29842623
    student406Languagesfemale7086377
    student407Mathematicsmale8654799
    student408Languagesfemale9381089
    student409Mathematicsmale84214658
    student410Languagesfemale21841849
    student411Mathematicsmale2796340
    student412Languagesfemale9301991
    student413Mathematicsmale31928743
    student414Languagesfemale53259843
    student415Mathematicsmale36758089
    student416Languagesfemale37681254
    student417Mathematicsmale25891253
    student418Languagesfemale922846
    student419Mathematicsmale11286058
    student420Languagesfemale1373517
    student421Mathematicsmale67303885
    student422Languagesfemale68793441
    student423Mathematicsmale72459341
    student424Languagesfemale56464538
    student425Mathematicsmale8621840
    student426Languagesfemale99854119
    student427Mathematicsmale7135389
    student428Languagesfemale22911216
    student429Mathematicsmale1532693
    student430Languagesfemale35463474
    student431Mathematicsmale33839720
    student432Languagesfemale9920326
    student433Mathematicsmale48428318
    student434Languagesfemale4442530
    student435Mathematicsmale78486045
    student436Languagesfemale4757890
    student437Mathematicsmale881210053
    student438Languagesfemale4805160
    student439Mathematicsmale70898516
    student440Languagesfemale71943433
    student441Mathematicsmale68137218
    student442Languagesfemale7539721
    student443Mathematicsmale65366087
    student444Languagesfemale43212434
    student445Mathematicsmale85776528
    student446Languagesfemale61907891
    student447Mathematicsmale9207812
    student448Languagesfemale33306290
    student449Mathematicsmale8616745
    student450Languagesfemale100862423
    student451Mathematicsmale1425645
    student452Languagesfemale86399888
    student453Mathematicsmale72687719
    student454Languagesfemale94523100
    student455Mathematicsmale34678979
    student456Languagesfemale9204745
    student457Mathematicsmale64582698
    student458Languagesfemale439359100
    student459Mathematicsmale82359781
    student460Languagesfemale183524100
    student461Mathematicsmale79804351
    student462Languagesfemale56101767
    student463Mathematicsmale36441485
    student464Languagesfemale2640692
    student465Mathematicsmale59934378
    student466Languagesfemale7884883
    student467Mathematicsmale41378060
    student468Languagesfemale44279777
    student469Mathematicsmale29196482
    student470Languagesfemale50962746
    student471Mathematicsmale49155145
    student472Languagesfemale38353178
    student473Mathematicsmale1802365
    student474Languagesfemale91172376
    student475Mathematicsmale57393563
    student476Languagesfemale33736214
    student477Mathematicsmale96168840
    student478Languagesfemale30631613
    student479Mathematicsmale74393787
    student480Languagesfemale26369479
    student481Mathematicsmale19586512
    student482Languagesfemale73362248
    student483Mathematicsmale7894757
    student484Languagesfemale5951935
    student485Mathematicsmale677110085
    student486Languagesfemale33301546
    student487Mathematicsmale12191637
    student488Languagesfemale80982914
    student489Mathematicsmale70511431
    student490Languagesfemale95381592
    student491Mathematicsmale60317412
    student492Languagesfemale62569068
    student493Mathematicsmale63112991
    student494Languagesfemale4112520
    student495Mathematicsmale6053144
    student496Languagesfemale1135528
    student497Mathematicsmale11964237
    student498Languagesfemale16727974
    student499Mathematicsmale9212266
    student500Languagesfemale34226434
    student501Mathematicsmale50938661
    student502Languagesfemale50224044
    student503Mathematicsmale383917
    student504Languagesfemale98169355
    student505Mathematicsmale86893628
    student506Languagesfemale16531350
    student507Mathematicsmale5757338
    student508Languagesfemale34796977
    student509Mathematicsmale241659
    student510Languagesfemale606299100
    student511Mathematicsmale65525295
    student512Languagesfemale5873941
    student513Mathematicsmale39752876
    student514Languagesfemale4666478
    student515Mathematicsmale5160998
    student516Languagesfemale17201297
    student517Mathematicsmale72179673
    student518Languagesfemale92216227
    student519Mathematicsmale5042433
    student520Languagesfemale5237157
    student521Mathematicsmale58403554
    student522Languagesfemale9385753
    student523Mathematicsmale79201818
    student524Languagesfemale149427
    student525Mathematicsmale95412998
    student526Languagesfemale3459921
    student527Mathematicsmale39664129
    student528Languagesfemale328125
    student529Mathematicsmale33443785
    student530Languagesfemale69255979
    student531Mathematicsmale13504952
    student532Languagesfemale54834531
    student533Mathematicsmale15249751
    student534Languagesfemale7516963
    student535Mathematicsmale9183856
    student536Languagesfemale50137480
    student537Mathematicsmale54757410
    student538Languagesfemale76397046
    student539Mathematicsmale84723940
    student540Languagesfemale10047214
    student541Mathematicsmale426111
    student542Languagesfemale57716561
    student543Mathematicsmale7854134
    student544Languagesfemale14763647
    student545Mathematicsmale15196396
    student546Languagesfemale27823356
    student547Mathematicsmale70239690
    student548Languagesfemale612278
    student549Mathematicsmale22376436
    student550Languagesfemale75969440
    student551Mathematicsmale4382921
    student552Languagesfemale7968718
    student553Mathematicsmale65765244
    student554Languagesfemale41627354
    student555Mathematicsmale25982140
    student556Languagesfemale17709682
    student557Mathematicsmale43912743
    student558Languagesfemale33372433
    student559Mathematicsmale87871031
    student560Languagesfemale48409774
    student561Mathematicsmale63759155
    student562Languagesfemale66825995
    student563Mathematicsmale21955838
    student564Languagesfemale9299745
    student565Mathematicsmale5979420
    student566Languagesfemale64952412
    student567Mathematicsmale70463674
    student568Languagesfemale16259149
    student569Mathematicsmale73332488
    student570Languagesfemale9619527
    student571Mathematicsmale18127646
    student572Languagesfemale61714963
    student573Mathematicsmale46328517
    student574Languagesfemale42421137
    student575Mathematicsmale49764120
    student576Languagesfemale22278012
    student577Mathematicsmale76341866
    student578Languagesfemale96772917
    student579Mathematicsmale62516772
    student580Languagesfemale96672254
    student581Mathematicsmale77112388
    student582Languagesfemale6282433
    student583Mathematicsmale392312100
    student584Languagesfemale10212071
    student585Mathematicsmale11277100
    student586Languagesfemale40349778
    student587Mathematicsmale2518319
    student588Languagesfemale18763025
    student589Mathematicsmale24574681
    student590Languagesfemale2103194
    student591Mathematicsmale91847513
    student592Languagesfemale79449710
    student593Mathematicsmale42606730
    student594Languagesfemale61577535
    student595Mathematicsmale42468171
    student596Languagesfemale92637574
    student597Mathematicsmale86374051
    student598Languagesfemale5210473
    student599Mathematicsmale100281476
    student600Languagesfemale31762043
    student601Mathematicsmale402766
    student602Languagesfemale587921
    student603Mathematicsmale754691
    student604Languagesfemale2830153
    student605Mathematicsmale38939892
    student606Languagesfemale43968991
    student607Mathematicsmale43491483
    student608Languagesfemale50617298
    student609Mathematicsmale4499983
    student610Languagesfemale5367382
    student611Mathematicsmale40849954
    student612Languagesfemale29966569
    student613Mathematicsmale1276599
    student614Languagesfemale4783494
    student615Mathematicsmale3727224
    student616Languagesfemale94394924
    student617Mathematicsmale0752141
    student618Languagesfemale5936418
    student619Mathematicsmale2266133
    student620Languagesfemale4387448
    student621Mathematicsmale100155152
    student622Languagesfemale63719917
    student623Mathematicsmale143444100
    student624Languagesfemale2385727
    student625Mathematicsmale23143240
    student626Languagesfemale34497254
    student627Mathematicsmale21168126
    student628Languagesfemale54693434
    student629Mathematicsmale72116331
    student630Languagesfemale8798947
    student631Mathematicsmale43525358
    student632Languagesfemale5014420
    student633Mathematicsmale89836787
    student634Languagesfemale079916
    student635Mathematicsmale59178458
    student636Languagesfemale94953660
    student637Mathematicsmale39426346
    student638Languagesfemale019610
    student639Mathematicsmale50164171
    student640Languagesfemale8604613
    student641Mathematicsmale45855936
    student642Languagesfemale8335057
    student643Mathematicsmale8306014
    student644Languagesfemale76807338
    student645Mathematicsmale2614582
    student646Languagesfemale9316422
    student647Mathematicsmale85947616
    student648Languagesfemale57453216
    student649Mathematicsmale16169013
    student650Languagesfemale4331887
    student651Mathematicsmale16243244
    student652Languagesfemale5998334
    student653Mathematicsmale73184783
    student654Languagesfemale992510093
    student655Mathematicsmale0739784
    student656Languagesfemale0289475
    student657Mathematicsmale65905863
    student658Languagesfemale84358641
    student659Mathematicsmale4539599
    student660Languagesfemale32103162
    student661Mathematicsmale61285461
    student662Languagesfemale70961454
    student663Mathematicsmale6392298
    student664Languagesfemale41104623
    student665Mathematicsmale81918021
    student666Languagesfemale79716568
    student667Mathematicsmale47691890
    student668Languagesfemale2616700
    student669Mathematicsmale66109335
    student670Languagesfemale66682713
    student671Mathematicsmale86792645
    student672Languagesfemale50532574
    student673Mathematicsmale9753914
    student674Languagesfemale28796942
    student675Mathematicsmale607259
    student676Languagesfemale53213943
    student677Mathematicsmale37654591
    student678Languagesfemale76806027
    student679Mathematicsmale85273455
    student680Languagesfemale66114117
    student681Mathematicsmale27618982
    student682Languagesfemale402613
    student683Mathematicsmale2516695
    student684Languagesfemale63448563
    student685Mathematicsmale97957883
    student686Languagesfemale5121387
    student687Mathematicsmale63928723
    student688Languagesfemale22965959
    student689Mathematicsmale33801523
    student690Languagesfemale34751924
    student691Mathematicsmale36684854
    student692Languagesfemale32362012
    student693Mathematicsmale68917450
    student694Languagesfemale87919637
    student695Mathematicsmale239144
    student696Languagesfemale9462977
    student697Mathematicsmale1474575
    student698Languagesfemale73921990
    student699Mathematicsmale8207978
    student700Languagesfemale763510039
    student701Mathematicsmale27518949
    student702Languagesfemale0647237
    student703Mathematicsmale93469487
    student704Languagesfemale6922172
    student705Mathematicsmale1752113
    student706Languagesfemale1325219
    student707Mathematicsmale75617273
    student708Languagesfemale8437736
    student709Mathematicsmale81194514
    student710Languagesfemale62173927
    student711Mathematicsmale8869681
    student712Languagesfemale53825929
    student713Mathematicsmale83347134
    student714Languagesfemale9552614
    student715Mathematicsmale6715313
    student716Languagesfemale8297825
    student717Mathematicsmale65503146
    student718Languagesfemale27462537
    student719Mathematicsmale98423544
    student720Languagesfemale9014444
    student721Mathematicsmale3168293
    student722Languagesfemale3434370
    student723Mathematicsmale59771421
    student724Languagesfemale16535759
    student725Mathematicsmale7914416
    student726Languagesfemale108199
    student727Mathematicsmale89487916
    student728Languagesfemale8872387
    student729Mathematicsmale17539584
    student730Languagesfemale65523961
    student731Mathematicsmale44309672
    student732Languagesfemale70793233
    student733Mathematicsmale30474611
    student734Languagesfemale761001649
    student735Mathematicsmale39369089
    student736Languagesfemale1941929
    student737Mathematicsmale23737887
    student738Languagesfemale87714464
    student739Mathematicsmale22198220
    student740Languagesfemale94526739
    student741Mathematicsmale14175187
    student742Languagesfemale5663983
    student743Mathematicsmale99924698
    student744Languagesfemale19768388
    student745Mathematicsmale15776881
    student746Languagesfemale48814838
    student747Mathematicsmale2913861
    student748Languagesfemale7163030
    student749Mathematicsmale19683053
    student750Languagesfemale91182762
    student751Mathematicsmale73333836
    student752Languagesfemale99387550
    student753Mathematicsmale55713490
    student754Languagesfemale52409883
    student755Mathematicsmale1463611
    student756Languagesfemale1319496
    student757Mathematicsmale49665592
    student758Languagesfemale0198082
    student759Mathematicsmale2635873
    student760Languagesfemale8287639
    student761Mathematicsmale52118357
    student762Languagesfemale83688425
    student763Mathematicsmale1725670
    student764Languagesfemale1758084
    student765Mathematicsmale7564785
    student766Languagesfemale76329339
    student767Mathematicsmale20758465
    student768Languagesfemale25471289
    student769Mathematicsmale86947945
    student770Languagesfemale65815535
    student771Mathematicsmale62414143
    student772Languagesfemale1446243
    student773Mathematicsmale17557278
    student774Languagesfemale9546356
    student775Mathematicsmale7205648
    student776Languagesfemale30881956
    student777Mathematicsmale42448856
    student778Languagesfemale42695663
    student779Mathematicsmale7857783
    student780Languagesfemale15862498
    student781Mathematicsmale4684369
    student782Languagesfemale67981552
    student783Mathematicsmale33326357
    student784Languagesfemale35951653
    student785Mathematicsmale78545482
    student786Languagesfemale8185914
    student787Mathematicsmale42412314
    student788Languagesfemale591008636
    student789Mathematicsmale1926012
    student790Languagesfemale10034570
    student791Mathematicsmale381217
    student792Languagesfemale3155193
    student793Mathematicsmale11339877
    student794Languagesfemale461786
    student795Mathematicsmale5786727
    student796Languagesfemale5746236
    student797Mathematicsmale57676661
    student798Languagesfemale93888725
    student799Mathematicsmale59966441
    student800Languagesfemale6276923
    student801Mathematicsmale35833255
    student802Languagesfemale42581583
    student803Mathematicsmale41904012
    student804Languagesfemale8143837
    student805Mathematicsmale87773320
    student806Languagesfemale53873037
    student807Mathematicsmale13358516
    student808Languagesfemale20829034
    student809Mathematicsmale5821614
    student810Languagesfemale14282356
    student811Mathematicsmale4997368
    student812Languagesfemale31461163
    student813Mathematicsmale7497643
    student814Languagesfemale42839575
    student815Mathematicsmale2654529
    student816Languagesfemale79596988
    student817Mathematicsmale68182684
    student818Languagesfemale39139915
    student819Mathematicsmale2248716
    student820Languagesfemale12538811
    student821Mathematicsmale33908029
    student822Languagesfemale3795486
    student823Mathematicsmale9178851
    student824Languagesfemale31586731
    student825Mathematicsmale22305098
    student826Languagesfemale55585610
    student827Mathematicsmale56765753
    student828Languagesfemale1129881
    student829Mathematicsmale67926671
    student830Languagesfemale30614449
    student831Mathematicsmale0414461
    student832Languagesfemale72524585
    student833Mathematicsmale60991294
    student834Languagesfemale83587542
    student835Mathematicsmale9505377
    student836Languagesfemale33287062
    student837Mathematicsmale3982755
    student838Languagesfemale411004547
    student839Mathematicsmale81692729
    student840Languagesfemale9012649
    student841Mathematicsmale45382034
    student842Languagesfemale325311
    student843Mathematicsmale55778649
    student844Languagesfemale61609176
    student845Mathematicsmale8085749
    student846Languagesfemale63897371
    student847Mathematicsmale79159742
    student848Languagesfemale99187343
    student849Mathematicsmale30523856
    student850Languagesfemale65866734
    student851Mathematicsmale7343655
    student852Languagesfemale42435173
    student853Mathematicsmale870980
    student854Languagesfemale29411245
    student855Mathematicsmale5739090
    student856Languagesfemale80529654
    student857Mathematicsmale43838246
    student858Languagesfemale7917131
    student859Mathematicsmale6813707
    student860Languagesfemale51441552
    student861Mathematicsmale9170178
    student862Languagesfemale4116578
    student863Mathematicsmale20635585
    student864Languagesfemale5938726
    student865Mathematicsmale4894432
    student866Languagesfemale26679839
    student867Mathematicsmale48793866
    student868Languagesfemale1632153
    student869Mathematicsmale13205085
    student870Languagesfemale4922039
    student871Mathematicsmale8262353
    student872Languagesfemale6607464
    student873Mathematicsmale66483914
    student874Languagesfemale43833100
    student875Mathematicsmale214990
    student876Languagesfemale79807180
    student877Mathematicsmale84252688
    student878Languagesfemale38466660
    student879Mathematicsmale35279851
    student880Languagesfemale5759267
    student881Mathematicsmale7687788
    student882Languagesfemale2140817
    student883Mathematicsmale5046866
    student884Languagesfemale83863092
    student885Mathematicsmale63466694
    student886Languagesfemale7671262
    student887Mathematicsmale7418686
    student888Languagesfemale65774488
    student889Mathematicsmale67326119
    student890Languagesfemale85968541
    student891Mathematicsmale1487705
    student892Languagesfemale81284528
    student893Mathematicsmale9191883
    student894Languagesfemale407024
    student895Mathematicsmale18195189
    student896Languagesfemale70352512
    student897Mathematicsmale7290741
    student898Languagesfemale8417186
    student899Mathematicsmale1423886
    student900Languagesfemale7837601
    student901Mathematicsmale66953168
    student902Languagesfemale23608065
    student903Mathematicsmale76896396
    student904Languagesfemale3469070
    student905Mathematicsmale65449679
    student906Languagesfemale6877865
    student907Mathematicsmale86619943
    student908Languagesfemale88953213
    student909Mathematicsmale531005982
    student910Languagesfemale3579535
    student911Mathematicsmale230177
    student912Languagesfemale9687263
    student913Mathematicsmale23923996
    student914Languagesfemale9497658
    student915Mathematicsmale49312971
    student916Languagesfemale21577957
    student917Mathematicsmale03510089
    student918Languagesfemale64827552
    student919Mathematicsmale16666968
    student920Languagesfemale92951127
    student921Mathematicsmale16888590
    student922Languagesfemale56152698
    student923Mathematicsmale78274017
    student924Languagesfemale95104432
    student925Mathematicsmale99855218
    student926Languagesfemale73317149
    student927Mathematicsmale21791063
    student928Languagesfemale92718012
    student929Mathematicsmale23293388
    student930Languagesfemale4189884
    student931Mathematicsmale97177921
    student932Languagesfemale72409392
    student933Mathematicsmale7558326
    student934Languagesfemale15982728
    student935Mathematicsmale7688806
    student936Languagesfemale84234292
    student937Mathematicsmale71568671
    student938Languagesfemale7395822
    student939Mathematicsmale1555460
    student940Languagesfemale2031308
    student941Mathematicsmale97544181
    student942Languagesfemale83418664
    student943Mathematicsmale7195327
    student944Languagesfemale0273091
    student945Mathematicsmale99751722
    student946Languagesfemale92531090
    student947Mathematicsmale4449432
    student948Languagesfemale0974879
    student949Mathematicsmale97557974
    student950Languagesfemale6598932
    student951Mathematicsmale56733881
    student952Languagesfemale84946150
    student953Mathematicsmale4820770
    student954Languagesfemale39981420
    student955Mathematicsmale4152465
    student956Languagesfemale78229231
    student957Mathematicsmale28382654
    student958Languagesfemale49613554
    student959Mathematicsmale81152817
    student960Languagesfemale5480582
    student961Mathematicsmale7523537
    student962Languagesfemale5565120
    student963Mathematicsmale86427036
    student964Languagesfemale54455480
    student965Mathematicsmale38186992
    student966Languagesfemale33894683
    student967Mathematicsmale4395576
    student968Languagesfemale13261286
    student969Mathematicsmale94228559
    student970Languagesfemale9358610
    student971Mathematicsmale35728536
    student972Languagesfemale37519693
    student973Mathematicsmale71107959
    student974Languagesfemale71317393
    student975Mathematicsmale80268697
    student976Languagesfemale69216769
    student977Mathematicsmale38861039
    student978Languagesfemale48903981
    student979Mathematicsmale9083342
    student980Languagesfemale1919184
    student981Mathematicsmale98255046
    student982Languagesfemale38882116
    student983Mathematicsmale71481843
    student984Languagesfemale79851816
    student985Mathematicsmale51669068
    student986Languagesfemale100956591
    student987Mathematicsmale6742424
    student988Languagesfemale93809435
    student989Mathematicsmale65785794
    student990Languagesfemale27922191
    student991Mathematicsmale77152676
    student992Languagesfemale28845167
    student993Mathematicsmale3786250
    student994Languagesfemale59772074
    student995Mathematicsmale6266875
    student996Languagesfemale88703343
    student997Mathematicsmale73334253
    student998Languagesfemale6410231
    student999Mathematicsmale91931635
    student1000Languagesfemale30689540
    student1001Mathematicsmale2524832
    student1002Languagesfemale50775381
    student1003Mathematicsmale67441065
    student1004Languagesfemale29533486
    student1005Mathematicsmale77692275
    student1006Languagesfemale48829540
    student1007Mathematicsmale30712963
    student1008Languagesfemale4531471
    student1009Mathematicsmale81122044
    student1010Languagesfemale17668242
    student1011Mathematicsmale15113218
    student1012Languagesfemale27345919
    student1013Mathematicsmale18672514
    student1014Languagesfemale24645224
    student1015Mathematicsmale36874846
    student1016Languagesfemale3317068
    student1017Mathematicsmale4826380
    student1018Languagesfemale53638557
    student1019Mathematicsmale5873024
    student1020Languagesfemale8590810
    student1021Mathematicsmale69285276
    student1022Languagesfemale7522752
    + + + +
    + + + + diff --git a/docs/example-update-all.html b/docs/example-update-all.html new file mode 100644 index 0000000..f9873eb --- /dev/null +++ b/docs/example-update-all.html @@ -0,0 +1,114 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Update headers & table body (updateAll) + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • This demo uses the updateAll method (v2.8).
    • +
    • This method allows you to update the cache with data from both the thead and tbody of the table.
    • +
    • The update method only updates the cache from the tbody.
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + +
    First NameLast NameValueTotalDiscountDate
    PeterParkerx28$9.9920%Jul 6, 2006 8:14 AM
    JohnHoody33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKenty18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmightyx45$153.1944%Jan 18, 2001 9:12 AM
    + +Modify the entire value column +
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    + + +
    + + + diff --git a/docs/example-update-cell.html b/docs/example-update-cell.html new file mode 100644 index 0000000..74befcf --- /dev/null +++ b/docs/example-update-cell.html @@ -0,0 +1,138 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Updating a table cell + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • Click on any value in the Total column to change it to a random amount.
    • +
    • This option is part of the original plugin.
    • +
    • Automatic resorting after "updateCell" is triggered was added in version 2.0.14.
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-widget-align-character.html b/docs/example-widget-align-character.html new file mode 100644 index 0000000..514f410 --- /dev/null +++ b/docs/example-widget-align-character.html @@ -0,0 +1,455 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Align Character Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • In v2.19.0, if there is nothing to the right of the set align character, then the align character will not be added; this prevents hanging decimals like 3000..

    • +
    • This widget will only work in tablesorter version 2.8+ and jQuery version 1.7+.
    • +
    • Make sure to include the CSS shown below to maintain the alignment.
    • +
    • *NOTE* if the table cell becomes too narrow, the alignment will not be maintained & some content may overflow into the next/previous cell (the widget css does include overflow:hidden on the wrapper, so some content will be hidden instead of overflowing).
    • +
    • Until the day that text-align: '.'; becomes standard (ref), if ever, this widget might prove useful.
    • +
    +
    + +

    Options

    +
    +

    Align Character (alignChar) widget default options (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the Option column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    '' + This option allows you to wrap the alignment character in any HTML: +
    +
    + When the widget completes the alignment, it is basically splitting the content of the table cell into two halves, and wrapping it in a span element. Below is an example of a modified cell showing all contents; it's from the "Animals" column (the cell that contains "Ox = stinky") +
    <td>
    +	<span class="ts-align-wrap">
    +		<span class="ts-align-left" style="min-width:37%">Ox&nbsp;</span>
    +		<span class="ts-align-right" style="min-width:63%">=&nbsp;stinky</span>
    +	</span>
    +</td>
    + When this option is set with some HTML: +
    alignChar_wrap : '<i/>'
    + it results in this layout: +
    <td>
    +	<span class="ts-align-wrap">
    +		<span class="ts-align-left" style="min-width:37%">Ox&nbsp;</span>
    +		<span class="ts-align-right" style="min-width:63%">
    +			<i>=</i>&nbsp;stinky
    +		</span>
    +	</span>
    +</td>
    +
    +
    'data-align-char' + This option points to the header data-attribute which contains the desired alignment character. +
    +
    + Add it to the header as follows: +
    <th data-align-char=".">Numeric</th>
    + The data-align-char data-attribute contains the actual character to align. There is no default alignment character, so if this data-attribute is undefined, the column will be ignored.
    +
    + *NOTE* if wanting to align the content on a space (see the "AlphaNumeric" column), use &nbsp; instead of a regular space because all spaces within the content are replaced by non-breaking spaces. +
    <th data-align-char="&nbsp;">AlphaNumeric</th>
    +
    +
    'data-align-index'This option points to the header data-attribute which contains the desired alignment character index (one-based index). +
    +
      +
    • What that means is if your data has multiple periods, like in the URLs of the sites column below, you can tell the widget which period to line-up on.
    • +
    • The alignment may seem to act incorrectly, if your data doesn't have enough periods to line up on, but it's doing the best it can! For example, in the sites column below, a table cell contains "rental.nytimes.com/index.html". This URL has three periods, while all other cells in that column only contain two. When the data-align-index is set to "3", the widget aligns the content on that third period. All of the other columns only have two, so they all align on their last period. Does that make it clear?
    • +
    • Try adjusting the sliders in this demo to change the data-align-index of the "Animals" and "Sites" columns to see how this works.
    • +
    + Add this attribute to the header as follows: +
    <th data-align-char="=" data-align-index="1">Animals</th>
    + The data-align-index data-attribute contains the actual character index. The index defaults to "1" if this data-attribute is undefined. +
    +
    'data-align-adjust'This option allows you to tweak the horizontal position of the aligned cell content. +
    +
      +
    • Here is an example of a modified cell showing its contents; it's from the "Numeric" column (the cell that contains "87.20000"): +
      <td>
      +		<span class="ts-align-wrap">
      +			<span class="ts-align-left" style="min-width:36%">87</span>
      +			<span class="ts-align-right" style="min-width:64%">.20000</span>
      +		</span>
      +	</td>
      As you can see, the "87" (integer-part) is in a "ts-align-left" span, set with a text-align: right; (it's on the left, but right aligned)
      + The ".20000" (fractional-part) is in a "ts-align-right" span, set with a text-align: left; (opposite of the other one)!
      +
    • +
    • So in the above example, the left side is set to a width of "36%" and the right to "64%" (adding up to 100%), which "sort-of" centers the aligned character.
    • +
    • If you don't want to move the position of the aligned character, you can set the data-align-adjust data-attribute with a percentage change. This value (positive or negative) will be added to the "ts-align-left" span, and subtracted from the "ts-align-right" span.
    • +
    • Try adjusting the sliders in this demo to change the data-align-adjust of the "Sites" column to see how this works.
    • +
    + Add this attribute to the header as follows: +
    <th data-align-char="." data-align-adjust="10">Numeric</th>
    + The data-align-adjust data-attribute contains a percentage value (without the percent sign). The adjustment defaults to "0" if this data-attribute is undefined. +
    +
    +
    + +

    CSS

    +
    + The following is *required* css. Without it, the alignment will be all wrong. +
    +
    
    +			
    +
    + +
    + +

    + +

    Demo

    + +Animals align index:
    1 (only indexes of 1 or 2 will work)
    +Sites align index:
    1 (only indexes of 1 - 3 will work
    +Sites adjust value:
    0 + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AlphaNumericNumericAnimalsSites
    abc 123.423475Koala = cute = cudleysearch.google.com
    abc 123.4Ox = stinkymail.yahoo.com
    abc 91.0Girafee = tallhttp://www.facebook.com
    zyx 247.67Bison = burgerhttp://internship.whitehouse.gov/
    abc 113000Chimp = banana loverabout.ucla.edu/
    abc 256.5Elephant = unforgetablehttp://www.wikipedia.org/
    abc 915.5Lion = rawrrental.nytimes.com/index.html
    ABC 1087.20000Zebra = stripeyhttp://android.google.com
    zyx 1999.1Koala = cute, again!http://irsmrt.mit.edu/
    zyx 12.2Llama = llove ithttp://aliens.nasa.gov/
    + +

    Page Header

    +
    +
    <!-- Tablesorter: required -->
    +<link href="../css/theme.blue.css" rel="stylesheet">
    +<script src="../js/jquery.tablesorter.js"></script>
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +
    +<!-- Align Character widget -->
    +<script src="../js/widgets/widget-alignChar.js"></script>
    +
    + +

    Script

    +
    +
    
    +	
    + +

    CSS

    +
    +
    
    +	
    + +

    HTML

    +
    +
    <table class="tablesorter">
    +  <thead>
    +    <tr>
    +      <th data-align-char="&nbsp;">AlphaNumeric</th>
    +      <th data-align-char="." data-align-adjust="0">Numeric</th>
    +      <th data-align-char="=" data-align-index="1">Animals</th>
    +      <th data-align-char="." data-align-index="1">Sites</th>
    +    </tr>
    +  </thead>
    +  <tbody>
    +    <tr>
    +      <td>abc 123</td>
    +      <td>.423475</td>
    +      <td>Koala = cute = cudley</td>
    +      <td>search.google.com</td>
    +    </tr>
    +    <tr>
    +      <td>abc 1</td>
    +      <td>23.4</td>
    +      <td>Ox = stinky</td>
    +      <td>mail.yahoo.com</td>
    +    </tr>
    +    <tr>
    +      <td>abc 9</td>
    +      <td>1.0</td>
    +      <td>Girafee = tall</td>
    +      <td>http://www.facebook.com</td>
    +    </tr>
    +    <tr>
    +      <td>zyx 24</td>
    +      <td>7.67</td>
    +      <td>Bison = burger</td>
    +      <td>http://internship.whitehouse.gov/</td>
    +    </tr>
    +    <tr>
    +      <td>abc 11</td>
    +      <td>3000</td>
    +      <td>Chimp = banana lover</td>
    +      <td>about.ucla.edu/</td>
    +    </tr>
    +    <tr>
    +      <td>abc 2</td>
    +      <td>56.5</td>
    +      <td>Elephant = unforgetable</td>
    +      <td>http://www.wikipedia.org/</td>
    +    </tr>
    +    <tr>
    +      <td>abc 9</td>
    +      <td>15.5</td>
    +      <td>Lion = rawr</td>
    +      <td>rental.nytimes.com/index.html</td>
    +    </tr>
    +    <tr>
    +      <td>ABC 10</td>
    +      <td>87.20000</td>
    +      <td>Zebra = stripey</td>
    +      <td>http://android.google.com</td>
    +    </tr>
    +    <tr>
    +      <td>zyx 1</td>
    +      <td>999.1</td>
    +      <td>Koala = cute, again!</td>
    +      <td>http://irsmrt.mit.edu/</td>
    +    </tr>
    +    <tr>
    +      <td>zyx 12</td>
    +      <td>0.2</td>
    +      <td>Llama = llove it</td>
    +      <td>http://aliens.nasa.gov/</td>
    +    </tr>
    +  </tbody>
    +</table>
    +
    + +
    + + + + + + diff --git a/docs/example-widget-bootstrap-theme-v2.html b/docs/example-widget-bootstrap-theme-v2.html new file mode 100644 index 0000000..e04de0b --- /dev/null +++ b/docs/example-widget-bootstrap-theme-v2.html @@ -0,0 +1,295 @@ + + + + + jQuery plugin: Tablesorter 2.0 - jQuery UITheme Widget (Bootstrap v2.x) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • This demo uses Bootstrap v2.x (v2.3.2 specifically).
    • +
    • Hover over the thick grey bar under the header to reveal the filter row.
    • +
    • For more information like revision history of this theme & why there is a button to enable/disable the zebra widget, please see the Bootstrap v3.x demo.
    • +
    +

    + +

    Demo

    + +
    + Reset filter : +
    + Zebra widget : +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    + + + + + + + +
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Mathematicsmale8277079
    Student24Languagesfemale100911382
    Student25Mathematicsmale22968253
    Student26Languagesfemale37295659
    Student27Mathematicsmale86826923
    Student28Languagesfemale4425431
    Student29Mathematicsmale77472238
    Student30Languagesfemale19352310
    Student31Mathematicsmale90271750
    Student32Languagesfemale60753338
    Student33Mathematicsmale4313715
    Student34Languagesfemale77978144
    Student35Mathematicsmale5815195
    Student36Languagesfemale70617094
    Student37Mathematicsmale6036184
    Student38Languagesfemale6339011
    Student39Mathematicsmale50463238
    Student40Languagesfemale5175253
    Student41Mathematicsmale43342878
    Student42Languagesfemale11896095
    Student43Mathematicsmale48921888
    Student44Languagesfemale8225973
    Student45Mathematicsmale91733739
    Student46Languagesfemale481210
    Student47Mathematicsmale8910611
    Student48Languagesfemale90322118
    Student49Mathematicsmale42494972
    Student50Languagesfemale56376754
    + +

    Page Header

    +
    +
    <!-- Bootstrap stylesheet -->
    +<link rel="stylesheet" href="css/bootstrap.min.css">
    +<!-- bootstrap widget theme -->
    +<link rel="stylesheet" href="css/theme.bootstrap_2.css">
    +
    +<!-- tablesorter plugin -->
    +<script src="js/jquery.tablesorter.js"></script>
    +<!-- tablesorter widget file - loaded after the plugin -->
    +<script src="js/jquery.tablesorter.widgets.js"></script>
    +
    +<!-- pager plugin -->
    +<link rel="stylesheet" href="css/jquery.tablesorter.pager.css">
    +<script src="js/jquery.tablesorter.pager.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-widget-bootstrap-theme.html b/docs/example-widget-bootstrap-theme.html new file mode 100644 index 0000000..eafd3a2 --- /dev/null +++ b/docs/example-widget-bootstrap-theme.html @@ -0,0 +1,329 @@ + + + + + jQuery plugin: Tablesorter 2.0 - jQuery UITheme Widget (Bootstrap v3.x) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • New!In tablesorter v2.11+, The bootstrap theme now works with Bootstrap 3 and older versions. +
        +
      • Note the changes to the sorting icons in the $.tablesorter.themes.bootstrap defaults below.
      • +
      • Just use the appropriate icon class name (icon-{name} for Bootstrap v2, and glyphicon glyphicon-{name} for Bootstrap v3.
      • +
      • And of course include the necessary Bootstrap image or font).
      • +
      • Wrapped all of the pager controls in the tfoot within a div (don't use the class name pager as it adds a lot of padding) to keep the controls from being centered.
      • +
      • Pager control buttons in the tfoot have class names needed for both Bootstrap v2+ and v3, so there's no need for you to use both, just use the ones you need.
      • +
      +
    • +
    • As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
    • +
    • Make sure to include the {icon} in the headerTemplate to add a sorting arrow to the headers.
    • +
    • Added in v2.7! +
        +
      • You will need to modify the headerTemplate option to include the bootstrap icon! See the example in the code.
      • +
      • Setting theme option to "Bootstrap" will now override/ignore the uitheme value in the widgetOptions.
      • +
      +
    • +
    • In tablesorter v2.4, the uitheme option has changed to indicate the theme instead of an array of icons to use: +
        +
      • All theme class names are now contained within $.tablesorter.themes with the Bootstrap theme saved to $.tablesorter.themes.bootstrap.
      • +
      • The themes variable allows you to modify the class names for the table, header, sort icons, active state, hover state, filter inputs and zebra striping. See the code below on how to extend these variables.
      • +
      • Set the uitheme widget theme option (changed in v2.7) to "bootstrap" to set the widget to use the Bootstrap theme. See the jQuery UI demo for another example.
      • +
      +
    • +
    • This demo shows how to get around an issue with the filter widget: +
        +
      • The zebra widget button below was added to show that when bootstrap's "table-striped" class is applied, the css defined zebra striping will not apply correctly because table rows are hidden but still accounted for by the css nth-child() selector.
      • +
      • To better understand this issue, disable the zebra widget (using the toggle button). Now in the "Calculus" column.
      • +
      • Try other filter searches with the zebra widget disabled, like in the "Sex" column.
      • +
      • To solve this issue, just enable the zebra widget and the "even" and "odd" row class names will should over-ride the nth-child() styling.
        NOTE! This doesn't seem to work in the latest Bootstrap version, so you'll have to remove the "table-striped" class completely from the table.
      • +
      • The only down side is that for custom bootstrap themes, you'll need to edit the "theme.bootstrap.css" file for bootstrap.
      • +
      +
    • +
    • This demo uses HTML5 data attributes and therefore needs jQuery 1.4+.
    • +
    +

    + +

    Demo

    + +
    + Reset filter : +
    + Zebra widget : +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    + + + + + + + +
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Mathematicsmale8277079
    Student24Languagesfemale100911382
    Student25Mathematicsmale22968253
    Student26Languagesfemale37295659
    Student27Mathematicsmale86826923
    Student28Languagesfemale4425431
    Student29Mathematicsmale77472238
    Student30Languagesfemale19352310
    Student31Mathematicsmale90271750
    Student32Languagesfemale60753338
    Student33Mathematicsmale4313715
    Student34Languagesfemale77978144
    Student35Mathematicsmale5815195
    Student36Languagesfemale70617094
    Student37Mathematicsmale6036184
    Student38Languagesfemale6339011
    Student39Mathematicsmale50463238
    Student40Languagesfemale5175253
    Student41Mathematicsmale43342878
    Student42Languagesfemale11896095
    Student43Mathematicsmale48921888
    Student44Languagesfemale8225973
    Student45Mathematicsmale91733739
    Student46Languagesfemale481210
    Student47Mathematicsmale8910611
    Student48Languagesfemale90322118
    Student49Mathematicsmale42494972
    Student50Languagesfemale56376754
    + +

    Page Header

    +
    +
    <!-- Bootstrap stylesheet -->
    +<link rel="stylesheet" href="css/bootstrap.min.css">
    +<!-- bootstrap widget theme -->
    +<link rel="stylesheet" href="css/theme.bootstrap.css">
    +
    +<!-- tablesorter plugin -->
    +<script src="js/jquery.tablesorter.js"></script>
    +<!-- tablesorter widget file - loaded after the plugin -->
    +<script src="js/jquery.tablesorter.widgets.js"></script>
    +
    +<!-- pager plugin -->
    +<link rel="stylesheet" href="css/jquery.tablesorter.pager.css">
    +<script src="js/jquery.tablesorter.pager.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-widget-build-table.html b/docs/example-widget-build-table.html new file mode 100644 index 0000000..d9220e4 --- /dev/null +++ b/docs/example-widget-build-table.html @@ -0,0 +1,873 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Build Table Widget + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +

    Notes

    +
    +
      +
    • Build a table starting with an assortment of data types ( array, text (CSV, HTML) or object (json) ).
    • +
    • This widget isn't really a widget because it is run and does it's processing before tablesorter has initialized; but the options for it are contained within the tablesorter widgetOptions.
    • +
    • Using the core build options: +
        +
      • The build_type tells the widget which type of data processing to use on the data.
      • +
      • The build_source points the widget to the data source.
      • +
      • Once the data is obtained from the build_source, you can do whatever processing that needs to be done on it using the build_processing option. +
          +
        • For example, if the table data is within a larger JSON, you can just return that portion of the JSON to the widget: build_processing : function(data, wo) { return data.all_info_tables.table_of_contents; }
        • +
        • Anoter example is to use the processing option to split a string into an array (see the "Array (from string w/processing)" section below)
        • +
        +
      • +
      +
    • +
    • An extra option named build_numbers has been included: +
        +
      • This option only applies to array and csv source table builds.
      • +
      • Set the build_numbers.addColumn option to true (or a string with the column name "#") to add a row number column on the far left of the table.
      • +
      • Set the build_numbers.sortable option to true to make the added number column sortable. This option only applies if the addColumn option is true.
      • +
      +
    • +
    +
    + +

    Options

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    widgetOptionTypeDefaultDescription
    Core Options
    String"" + Indicate the data result type that needs to be processed +

    + Options include: "array", "csv", "object", "json" or "html".
    + Default is "" (an empty string). +
    +
    String"" + Contains the data stored as an array, object, jQuery object or ajax settings used to obtain ajax data (include any desired ajax options). +

    + Options include: an array, object, jQuery Object ($('.csv')) or ajax settings( { url: 'mysite.com/data.json', dataType: 'json' } ). +
    +
    Functionnull + Add a function that returns a useable build_type. (e.g. string to array) +

    + The function receives two parameters: data which contains the obtained data and wo which is the widget options (table.config.widgetOptions).
    + Example: build_processing: function(data, wo){ return data.split(';'); } +
    +
    build_completeString"tablesorter-build-complete"Contains the name of the event to trigger when a table build has completed.
    CSV & Array Options
    build_headers.rowsNumeric1Number of header rows contained within the csv
    build_headers.classesArray[]Array of header class names to add while building the table header.
    Array[]Array of header cell names to add while building the table header. +

    + Any value contained within this option will override any header text obtained from the CSV data. +
    +
    build_headers.widthsArray[]Array of header cell widths which are added to a <col> within a <colgroup>.
    build_footers.rowsNumeric1Number of footer rows contained within the csv
    build_footers.classesArray[]Array of footer class names to add while building the table footer.
    Array[]Array of footer cell names to add while building the table footer. +

    + Any value contained within this option will override any footer text obtained from the CSV data. +
    +
    BooleanfalseInclude a row numbering column. +

    + Only works with csv or array data. +
    +
    BooleanfalseMake the included row number column sortable. +

    + Only works when the build_numbers.addColumn is true and when csv or array data is used. +
    +
    CSV Only Options
    build_csvStartLineNumeric0The line within the csv data to start building the table
    build_csvSeparatorString"," (comma)The separator used within the text file (comma or tab)
    Object Only Options
    build_objectRowKeyString"rows"Object key which contains row data
    build_objectCellKeyString"cells"Object key which contains the table cells, within the row data
    build_objectHeaderKeyString"headers"Object key which contains the table headers data
    build_objectFooterKeyString"footers"Object key which contains the table footers data
    + +
    + +

    Setup - Common (document head)

    +
    + Add the following required scripts and css files into the document <head> +
    <!-- jQuery -->
    +<script src="js/jquery-latest.min.js"></script>
    +
    +<!-- Tablesorter: required -->
    +<link rel="stylesheet" href="../css/theme.blue.css"> <!-- choose any theme -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- build table widget -->
    +<script type="text/javascript" src="../js/widgets/widget-build-table.js"></script>
    +
    + +

    Setup - Array (javascript variable)

    +
    + +

    Notes

    +
      +
    • The array is set up such that it is an array of arrays. The outer array contains each row array, and within each row array is the cell text.
    • +
    • Using an array is limiting, so addtional options have been added: +
        +
      • (build_headers & build_footers) have been added allowing customizing the headers and/or footers.
      • +
      • The rows option sets the number of headers rows to include from the data source. Zero is not an option since tablesorter requires a thead in place before it will initialize.
      • +
      • The classes array sets each header cell (th) class name.
      • +
      • The text array within these options will override any text obtained from the data source.
      • +
      • The widths array, only in the build_headers option, sets column widths by building <col> elements within a <colgroup.
      • +
      • Adding class names to the tbody rows or cells isn't easily accomplished, but you can bind to the build complete event ('tablesorter-build-complete') and add them yourself.
      • +
      +
    • +
    + +

    HTML

    +
    <div id="array2Table"></div>
    +

    Javascript

    +
    $(function() {
    +	var arry = [
    +		[ 'ID', 'Name', 'Age', 'Date' ], // header
    +		[ 'A42b', 'Parker', 28, 'Jul 6, 2006 8:14 AM' ],  // row 1
    +		[ 'A255', 'Hood', 33, 'Dec 10, 2002 5:14 AM' ],   // row 2
    +		[ 'A33', 'Kent', 18, 'Jan 12, 2003 11:14 AM' ],   // row 3
    +		[ 'A1', 'Franklin', 45, 'Jan 18, 2001 9:12 AM' ], // row 4
    +		[ 'A102', 'Evans', 22, 'Jan 18, 2007 9:12 AM' ],  // row 5
    +		[ 'A42a', 'Everet', 22, 'Jan 18, 2007 9:12 AM' ], // row 6
    +		[ 'ID', 'Name', 'Age', 'Date' ]  // footer
    +	];
    +
    +	$('#array2Table').tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		widgetOptions : {
    +			// build_type   : 'array', // can sometimes be detected if undefined
    +			build_source : arry,
    +			build_headers : {
    +				rows    : 1,  // Number of header rows from the csv
    +				classes : [], // Header classes to apply to cells
    +				text    : [], // Header cell text
    +				widths  : [ '15%', '30%', '15%', '40%' ] // set header cell widths
    +			},
    +			build_footers : {
    +				rows    : 1,   // Number of header rows from the csv
    +				classes : [],  // Footer classes to apply to cells
    +				text    : [ 'ID (a###)', 'Last Name', 'Age (joined)', 'Date (joined)' ] // Footer cell text
    +			}
    +		}
    +	});
    +});
    +

    Result

    +
    +
    + +

    Setup - Array (from string w/processing)

    +
    + +

    Notes

    +
      +
    • We start out with a string and split it into a useable array of arrays.
    • +
    • The settings are similair to the Array (javascript variable) code above with the exception of using the build_processing function to create the array. +
        +
      • The string is set up to separate each row by a semi-colon, then each cell by a comma.
      • +
      • The first split is needed to create an array of rows .split(';')
      • +
      • The second split can be accomplished using .split(',') on each row of the array, but instead we use the build table widget function $.tablesorter.buildTable.splitCSV(cells, ','); to ensure that the split doesn't occur if the separator is within double quotes (note the footer text).
      • +
      • Then just return this newly built array back to the build table widget (see the full code below).
      • +
      +
    • +
    + +

    HTML

    +
    <div id="string2Table"></div>
    +

    Javascript

    +
    $(function() {
    +	$('#string2Table').tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		widgetOptions: {
    +			build_type   : 'array',
    +			build_source : 'header 1,header 2,header 3;r1c1,r1c2,r1c3;r2c1,r2c2,r2c3;r3c1,r3c2,r3c3;"footer, 1","footer, 2","footer, 3"',
    +			build_processing : function(data, wo) {
    +				var rows = data.split(';');
    +				return $.each(rows, function(i,cells) {
    +					// similar to using rows[i] = cells.split(',') but the splitCSV script
    +					// doesn't split the cell if the separator (comma) is within double quotes
    +					rows[i] = $.tablesorter.buildTable.splitCSV(cells, ',');
    +				});
    +			}
    +		}
    +	});
    +});
    +

    Result

    +
    +
    + +

    Setup - CSV (txt within DOM element)

    +
    + +

    Notes

    +
      +
    • A jQuery object targeting the CSV text can be passed to the build_source option.
    • +
    • The widget detects that a jQuery object was passed to it, and grabs the HTML (not text) of the element. +
        +
      • Make sure not include HTML tags, or at least use the build_processing function to reformat the data.
      • +
      • The row of csv data is trimmed of extra tabs and spaces (only from the beginning & end of each row).
      • +
      • Building a table from CSV or array use the same script, so the same addtional options are available: +
          +
        • (build_headers & build_footers) have been added allowing customizing the headers and/or footers.
        • +
        • The rows option sets the number of headers rows to include from the data source. Zero is not an option since tablesorter requires a thead in place before it will initialize.
        • +
        • The classes array sets each header cell (th) class name.
        • +
        • The text array within these options will override any text obtained from the data source.
        • +
        • The widths array, only in the build_headers option, sets column widths by building <col> elements within a <colgroup.
        • +
        • Adding class names to the tbody rows or cells isn't easily accomplished, but you can bind to the build complete event ('tablesorter-build-complete') and add them yourself.
        • +
        +
      • +
      • CSV data has two additional options used during data processing: +
          +
        • build_csvStartLine (default is 0) tells the csv build script which line in the csv data to start using to build the table. This is added in case comments or other data is above the table data.
        • +
        • build_csvSeparator (default is ",") + +
        • +
        +
      • +
      • In this demo, the build_numbers sub-options addColumn and sortable are set to add a numeric column on the left side. +
          +
        • The addColumn option contains the name of the numeric column to be added to the header. Otherwise, set this option to false to not build this numeric column.
        • +
        • The sortable option makes that numeric column sortable.
        • +
        +
      • +
      +
    • +
    + +

    HTML

    +
    <!--
    + Note: if the csv data contains commas ("10,000 days") wrap it in quotes
    +-->
    +<div class="csv" style="display:none;">
    +	Album,Artist,Price (USD)
    +	Lateralus,Tool,$13.00
    +	Aenima,Tool,$12.00
    +	"10,000 days",Tool,$14.00
    +	Down In It,Nine Inch Nails,$3.00
    +	Broken,Nine Inch Nails,$6.00
    +	Muse,Black Holes and Revelations,$7.00
    +	Anon,"fake album, with comma", $1.00
    +	Album,Artist,Price (USD)
    +</div>
    +
    +<div id="csv2Table"></div>
    +

    Javascript

    +
    $(function() {
    +	$('#csv2Table').tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		widgetOptions: {
    +			// *** build widget core ***
    +			build_type      : 'csv',
    +			build_source    : $('.csv'),
    +			build_complete  : 'tablesorter-build-complete', // triggered event when build completes
    +
    +			// *** CSV & array ***
    +			build_headers   : {
    +				rows    : 1,   // Number of header rows from the csv
    +				classes : [],  // Header classes to apply to cells
    +				text    : [],  // Header cell text
    +				widths  : ['3%', '27%', '50%', '20%'] // set header cell widths
    +			},
    +			build_footers : {
    +				rows    : 1,   // Number of header rows from the csv
    +				classes : [],  // Footer classes to apply to cells
    +				text    : []   // Footer cell text
    +			},
    +			build_numbers : {
    +				addColumn : "#", // include row numbering column?
    +				sortable  : true // make column sortable?
    +			},
    +
    +			// *** CSV options ***
    +			build_csvStartLine : 0,  // line within the csv to start adding to table
    +			build_csvSeparator : "," // csv separator
    +		}
    +	});
    +});
    +

    Result

    +
    + +
    + +

    Setup - CSV (txt file via ajax)

    +
    + +

    Notes

    +
      +
    • If the csv data is obtained via ajax instead of from a DOM element, only the build_source option needs to change, everything else stays the same. +
        +
      • Set the build_source to contain any ajax settings required to load the data.
      • +
      • In this case the csv file is contained within a text file (build.txt), so a url option is set to point to the file and the dataType option (set to html) is set so that ajax knows the type of file to access.
      • +
      • The remaining default settings were left out of the example below.
      • +
      +
    • +
    • Please note that browsers like Chrome will not allow you to access locally hosted (desktop) files. Test it with Firefox instead.
    • +
    + +

    Build.txt file

    +
    Album,Artist,Price ($)
    +Lateralus,Tool,$13.00
    +Aenima,Tool,$12.00
    +"10,000 days",Tool,$14.00
    +Down In It,Nine Inch Nails,$3.00
    +Broken,Nine Inch Nails,$6.00
    +Muse,Black Holes and Revelations,$7.00
    +Anon,"fake album, with comma", $1.00
    +Album,Artist,Price ($)
    +

    HTML

    +
    <div id="csv2Table2"></div>
    +

    Javascript

    +
    $(function() {
    +	$('#csv2Table2').tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		widgetOptions: {
    +			// *** build widget core ***
    +			build_type      : 'csv',
    +			build_source    : { url: 'assets/csv.txt', dataType: 'text' },
    +			build_headers   : {
    +				widths  : ['30%', '50%', '20%'] // set header cell widths
    +			}
    +		}
    +	});
    +});
    +

    Result

    +
    + +
    + +

    Setup - Object (javascript variable)

    +
    +

    Notes

    +
    +

    Definitions - General:

    +
    + These are definitions to words as used within this documentation. +
      +
    • A key-value pair (or attribute): Within an object, the way to assign a value is by using a key-value pair ("name" : "Fred"; which is like saying name = "Fred" or x = 1 outside of an object).
    • +
    • A block is essentially the "value" portion of a key-value pair; specifically when referring to the value of the header, footer, row and cell blocks.
    • +
    • An array is a list or group of values (i.e. ['x','y','z']).
    • +
    • An array of arrays is an array that contains more arrays (i.e. [ ['a','b','c'], ['d','e','f' ] ]). This applies to the header, row and footer blocks.
    • +
    • Any build table widget object: +
        +
      • These objects are a grouping of key-value pairs used to define a tbody, row or cell.
      • +
      • These objects contains all of the attributes which are to be added to a table element while building the table.
      • +
      • The keys used in these attributes will look familiar - class (see row 7 below), colspan (see row 4 below), data-attributes (see row 7 cell 3 below), etc.
      • +
      • Depending on where an object is located (tbody, row or cell), it will have a special key word or words which are significant (see the Objects section below).
      • +
      +
    • +
    +
    + +

    Blocks:

    +
    + (row #), or (row # cell #) in these descriptions refer to the demo object code below +
      +
    • header block: +
        +
      • This block will contain an array of rows. The rows can be defined as another array of cell text (row 1-3,5-6), or row objects (row 0, 4 & 7).
      • +
      • The header object key name can be modified by changing the widget build_objectHeaderKey option.
      • +
      +
    • +
    • footers block: +
        +
      • This block can contain all of the same data as the header block.
      • +
      • This block has one additional setting, it can also contain a very specific string: "clone". When this setting is used, the footer will be created by making a clone of the header.
      • +
      • The footers object key name can be modified by changing the widget build_objectFooterKey option.
      • +
      +
    • +
    • rows block: +
        +
      • This block will contain an array of rows. The rows can be defined as another array of cell text, or as a row object (same as the header & footer blocks).
      • +
      • In addition, this block can contain a tbody object (tbody 2 & tbody 3; see the tbody object section below for more details).
      • +
      • The rows object key name can be modified by changing the widget build_objectRowKey option.
      • +
      +
    • +
    • cells block: +
        +
      • This block will contain an array of cells. The cells can be defined as cell text (string), or cell objects.
      • +
      • The cells object key name can be modified by changing the widget build_objectCellKey option.
      • +
      +
    • +
    +
    + +

    Object Content

    +
    +
      +
    • tbody object +
        +
      • The tbody object contains all of the attributes that are to be applied to a particular table tbody (tbody).
      • +
      • The tbody object requires a newTbody key set to true. It is the ONLY way the build widget can differeniate a row object from a "new" tbody object.
      • +
      • If the newTbody attribute is true, the build widget will place all remaining rows into a new tbody; or all rows, until it encounters another valid tbody object, into a new tbody.
      • +
      • If the newTbody attribute is false, the build widget will assume the object is for a row and add it as a row.
      • +
      • See "TBODY 2" and "TBODY 3" tbody objects in the code example below.
      • +
      +
    • +
    • row object +
        +
      • The row object contains all of the attributes that are to be applied to a particular table row (tr).
      • +
      • The row object requires a cells attribute.
      • +
      • The cells attribute will contain all table cell data for the cells within that table row.
      • +
      • This attribute can be changed by modifying the build table widget's build_objectCellKey (default is "cells").
      • +
      • See row 4 and row 7 in the demo code below.
      • +
      +
    • +
    • row array +
        +
      • A row array can contain either the text for a table cell (row 0 cell 2 & 4), or a cell object (row 0 cell 1,3,5,6) contains.
      • +
      • It can also contain all cell text (row 1-3,5-6) or all cell objects (almost row 7) for cells within that row.
      • +
      • This method does not allow adding any row (tr) attributes, (i.e. class or data-attributes).
      • +
      +
    • + +
    • cell object +
        +
      • The cell object contains all of the attributes that are to be applied to a particular table cell (th (thead or tfoot) or td (tbody).
      • +
      • This object requires either a text (row 0 & row 7) or html (row 4) attribute to add content into the cell.
      • +
      • Within the first header row only, if a width attribute is defined, it will be applied to a <col> element and placed within a <colgroup> before the header.
      • +
      • See row 0 (header), row 4 and row 7 (rows) in the demo code below.
      • +
      +
    • +
    • cell text +
        +
      • Within a row array or object, only the cell text can be included (row 0 cell 2,4; row 1-3,5-6; row 7 cell 5).
      • +
      • Within the header only, whenever cell content is added as a string, the widget will check the widgetOptions.build_headers.classes & wo.build_headers.widths (first row only) and apply any values it finds for that column to those cells.
      • +
      +
    • + +
    +
    +
    + +

    HTML

    +
    <div id="object2Table"></div>
    +

    Javascript

    +
    $(function() {
    +	// object or JSON
    +	var dataObject = {
    +		headers : [
    +			[
    +				// each object/string is a cell
    +				{ text: 'First Name', class: 'fname', width: '10%' }, // row 0 cell 1
    +				'Last Name',                                          // row 0 cell 2
    +				{ text: 'Age', class: 'age', 'data-sorter' : false }, // row 0 cell 3
    +				'Total',                                              // row 0 cell 4
    +				{ text: 'Discount', class : 'sorter-false' },         // row 0 cell 5
    +				{ text: 'Date', class : 'date' }                      // row 0 cell 6
    +			]
    +		],
    +		footers : 'clone', // clone headers or assign array like headers
    +		rows : [
    +			// TBODY 1
    +			[ 'Peter', 'Parker',   28, '$9.99',   '20%', 'Jul 6, 2006 8:14 AM'   ], // row 1
    +			[ 'John',  'Hood',     33, '$19.99',  '25%', 'Dec 10, 2002 5:14 AM'  ], // row 2
    +			[ 'Clark', 'Kent',     18, '$15.89',  '44%', 'Jan 12, 2003 11:14 AM' ], // row 3
    +
    +			// TBODY 2
    +			{ newTbody: true, class: 'tablesorter-infoOnly' },
    +			{ cells : [ { html: 'Info Row', colSpan: 6 } ] },      // row 4
    +
    +			// TBODY 3
    +			{ newTbody: true },
    +			[ 'Bruce', 'Evans',    22, '$13.19',  '11%', 'Jan 18, 2007 9:12 AM'  ], // row 5
    +			[ 'Bruce', 'Almighty', 45, '$153.19', '44%', 'Jan 18, 2001 9:12 AM'  ], // row 6
    +
    +			{ class: 'specialRow',                                                  // row 7
    +				cells: [
    +					// each object/string is a cell
    +					{ text: 'Fred', class: 'fname' },                                   // row 7 cell 1
    +					{ text: 'Smith', class: 'lname' },                                  // row 7 cell 2
    +					{ text: 18, class: 'age', 'data-info': "fake ID!, he's only 16" },  // row 7 cell 3
    +					{ text: '$22.44', class: 'total' },                                 // row 7 cell 4
    +					'8%',                                                               // row 7 cell 5
    +					{ text: 'Aug 20, 2012 10:15 AM', class: 'date' }                    // row 7 cell 6
    +				],
    +				'data-info' : 'This row likes turtles'
    +			}
    +		]
    +	};
    +
    +	$('#object2Table').tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		data : dataObject, // same as using build_source (build_source would override this)
    +		widgetOptions : {
    +			// *** build object options ***
    +			build_objectRowKey    : 'rows',    // object key containing table rows
    +			build_objectCellKey   : 'cells',   // object key containing table cells (within the rows object)
    +			build_objectHeaderKey : 'headers', // object key containing table headers
    +			build_objectFooterKey : 'footers'  // object key containing table footers
    +		}
    +	});
    +
    +});
    +

    Result

    +
    +
    + +

    Setup - Object (json file via ajax)

    +
    + +

    Notes

    +
      +
    • The important difference between this demo and the javascript variable demo above is that this one retrieves a JSON file: +
        +
      • Set the build_source option to contain any ajax settings to load the json.
      • +
      • To load the json file, set the url option to point to the json file and the dataType set to "json".
      • +
      • The remaining default settings were left out of the example below.
      • +
      +
    • +
    • Please see the "Object (javascript variable)" section above for more details on how to set up the JSON for this demo.
    • +
    • Note that JSON formatting is very specific - only double quotes (") can be used to wrap attributes, all keys must be wrapped in quotes, no comments, etc.
    • +
    • Always verify that the JSON is valid (use JSONLint) and realize that browsers like Chrome will not allow you to access locally hosted (desktop) JSON files. Test it with Firefox instead.
    • +
    + +

    Javascript

    +
    $(function() {
    +	$('#object2Table2').tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra'],
    +		widgetOptions: {
    +			build_type   : 'json',
    +			build_source : { url: 'assets/build.json', dataType: 'json' }
    +		}
    +	});
    +});
    + +

    Build.json file

    +
    {
    +	"headers": [
    +		[
    +			{ "text": "First Name", "class": "fname", "width": "20%" },
    +			"Last Name",
    +			{ "text": "Age", "class": "age", "data-sorter": false },
    +			"Total",
    +			{ "text": "Discount", "class": "sorter-false" },
    +			{ "text": "Date", "class": "date", "width": "20%" }
    +		]
    +	],
    +	"footers": "clone",
    +	"rows": [
    +		[ "Peter", "Parker", 28, "$9.99",  "20%", "Jul 6, 2006 8:14 AM"   ],
    +		[ "John",  "Hood",   33, "$19.99", "25%", "Dec 10, 2002 5:14 AM"  ],
    +		[ "Clark", "Kent",   18, "$15.89", "44%", "Jan 12, 2003 11:14 AM" ],
    +
    +		{ "newTbody": true, "class": "tablesorter-infoOnly" },
    +		{ "cells": [ { "html": "JSON Info Row", "colspan": 6 } ] },
    +
    +		{ "newTbody": true },
    +		[ "Bruce", "Evans",    22, "$13.19",  "11%", "Jan 18, 2007 9:12 AM"  ],
    +		[ "Brice", "Almighty", 45, "$153.19", "44%", "Jan 18, 2001 9:12 AM"  ],
    +
    +		{ "class": "specialRow",
    +			"cells": [
    +				{ "text": "Fred", "class": "fname" },
    +				{ "text": "Smith", "class": "lname" },
    +				{ "text": 18, "class": "age", "data-info": "fake ID!, he's only 16" },
    +				{ "text": "$22.44", "class": "total" },
    +				"8%",
    +				{ "text": "Aug 20, 2012 10:15 AM", "class": "date" }
    +			],
    +			"data-info": "This row likes turtles"
    +		}
    +	]
    +}
    +

    HTML (before)

    +
    <div id="object2Table2"></div>
    + +

    HTML (after)

    +
    <div id="object2Table2">
    +	<table class="tablesorter tablesorter-blue" role="grid">
    +		<colgroup>
    +			<col style="width: 20%;">
    +			<col>
    +			<col>
    +			<col>
    +			<col>
    +			<col style="width: 20%;">
    +		</colgroup>
    +		<thead>
    +			<tr>
    +				<th class="fname">First Name</th>
    +				<th>Last Name</th>
    +				<th class="age" data-sorter="false">Age</th>
    +				<th>Total</th>
    +				<th class="sorter-false">Discount</th>
    +				<th class="date">Date</th>
    +			</tr>
    +		</thead>
    +		<tbody>
    +			<tr>
    +				<td>Peter</td>
    +				<td>Parker</td>
    +				<td>28</td>
    +				<td>$9.99</td>
    +				<td>20%</td>
    +				<td>Jul 6, 2006 8:14 AM</td>
    +			</tr>
    +			<tr>
    +				<td>John</td>
    +				<td>Hood</td>
    +				<td>33</td>
    +				<td>$19.99</td>
    +				<td>25%</td>
    +				<td>Dec 10, 2002 5:14 AM</td>
    +			</tr>
    +			<tr>
    +				<td>Clark</td>
    +				<td>Kent</td>
    +				<td>18</td>
    +				<td>$15.89</td>
    +				<td>44%</td>
    +				<td>Jan 12, 2003 11:14 AM</td>
    +			</tr>
    +		</tbody>
    +		<tbody class="tablesorter-infoOnly">
    +			<tr>
    +				<td colspan="6">
    +					<strong>JSON Info Row</strong>
    +				</td>
    +			</tr>
    +		</tbody>
    +		<tbody>
    +			<tr>
    +				<td>Bruce</td>
    +				<td>Evans</td>
    +				<td>22</td>
    +				<td>$13.19</td>
    +				<td>11%</td>
    +				<td>Jan 18, 2007 9:12 AM</td>
    +			</tr>
    +			<tr>
    +				<td>Brice</td>
    +				<td>Almighty</td>
    +				<td>45</td>
    +				<td>$153.19</td>
    +				<td>44%</td>
    +				<td>Jan 18, 2001 9:12 AM</td>
    +			</tr>
    +			<tr class="specialRow" data-info="This row likes turtles">
    +				<td class="fname">Fred</td>
    +				<td class="lname">Smith</td>
    +				<td class="age" data-info="fake ID!, he's only 16">18</td>
    +				<td class="total">$22.44</td>
    +				<td>8%</td>
    +				<td class="date">Aug 20, 2012 10:15 AM</td>
    +			</tr>
    +		</tbody>
    +		<tfoot>
    +			<tr>
    +				<th class="fname">First Name</th>
    +				<th>Last Name</th>
    +				<th class="age" data-sorter="false">Age</th>
    +				<th>Total</th>
    +				<th class="sorter-false">Discount</th>
    +				<th class="date">Date</th>
    +			</tr>
    +		</tfoot>
    +	</table>
    +</div>
    + + +

    Result

    +
    + +
    + +
    + +
    + + + + + \ No newline at end of file diff --git a/docs/example-widget-chart.html b/docs/example-widget-chart.html new file mode 100644 index 0000000..4bda00a --- /dev/null +++ b/docs/example-widget-chart.html @@ -0,0 +1,704 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Chart Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    +
    +
    + +

    Notes

    +
    +
      +
    • This widget will only work in tablesorter version 2.16+ and jQuery version 1.7+.
    • +
    • It only provides data for charts.
    • +
    • Currently it provides data for the following chart libraries: + + More details are available within the named "Setup" sections below. +
    • +
    +
    + +

    Options

    +
    +
    + TIP! Click on the link in the function column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    'filtered' *Select which rows to include in the chart. +
    +

    + This option allows you to select which rows to include in the chart data: +
      +
    • 'a' - Include all rows, even if the table has been filtered or partially hidden by the pager.
    • +
    • 'v' - Include only visible rows, whether they are hidden by the pager or filter.
    • +
    • 'f' - Include only filtered rows, even if the pager is only showing a select few rows.
    • +
    + * Only the first letter is required, but the option will accept the full word (e.g. 'filtered' instead of 'f') +
    +
    falseUse the columnSelector widget in place of the chart_ignoreColumns option. +
    +

    + Set this option to true if using the columnSelector widget. +

    + If using a custom column selector, then set this option to false and use the custom selector to update the chart_ignoreColumns option dynamically. +
    +
    [ ]Array of zero-based column indexes of columns to ignore. +
    +

    + This option is used when the chart_useSelector option is false or if the columnSelector is set to "auto" mode. +

    + Update this option dynamically, if using a custom method to hide/indicate which columns are to be ignored when gathering data for the chart. +
    +
    [ ]Array of zero-based column indexes of columns that must used parsed data for charting. +
    +

    + Parsed data is gathered from the table cache, which is parsed the designated parser for that column. +

    + This option can be updated dynamically. +
    +
    { 0: 'string' }Object containing the format needed by the chart for each column. +
    +

    + By default, all columns will have their values converted to numbers. Prior to sending the value to tablesorter's formatFloat function, the value will have all non-digit characters stripped out. +

    + Set the zero-based column index of the desired column to 's' (only the first letter is needed) to pass the cell value to the chart as a string. +

    + This option can be updated dynamically. +
    +
    0Set a zero-based column index for the column to be used as a chart label. +
    +

    + The chart label (independent variable) is usually the first array value in each nested array (at least for Google charts). In this demo, it is the Year. +
    +
    [ [ 0,0 ] ]Sort a specific column of data using the same format as tablesorter's sortList option; but for a single column. +
    +

    + Set this value to be an array contained within an array using the following format: [[ column, direction ]] +

    + * Note * It would be best to sort the same column as the chart_labelCol to keep the axis ordered properly; but that is up to you ;) +

    +
      +
    • column - zero-based index of the column to sort.
    • +
    • direction - sort direction; 0 indicates an ascending sort, and 1 indicates a descending sort is to be used.
    • +
    + * Note * Anything other than 1 as the sort direction will set an ascending sort. +
    +
    'chartData'The chart data will be updated when this event is triggered on the table. +
    +

    + Trigger a chart data update, then get the data as follows: +
    var $table = $('table').trigger('chartData'),
    +	data = $table[0].config.chart.data;
    +chartData( data ); // custom function to chart the data
    +
    +
    +
    + +

    Setup - Google Charts

    +
    + The data used by Google charts is an array of arrays in this format: +
    [
    +	[ "Year", "Sales", "Expenses" ],
    +	[ "2004", 1000, 400  ],
    +	[ "2005", 1170, 460  ],
    +	[ "2006", 660,  1120 ],
    +	[ "2007", 1030, 540  ]
    +]
    + Access the data as follows: +
    var $table = $('table').trigger('chartData'),
    +	options = { /* set up options here */ },
    +	rawdata = $table[0].config.chart.data,
    +	data = google.visualization.arrayToDataTable( rawdata ),
    +	// bar chart example
    +	chart = new google.visualization.BarChart( $('#chart')[0] );
    +chart.draw(data, options);
    +
    +
    + +

    Setup - Highcharts

    +
    + The data used by Highcharts is an array of objects in this format: +
    // categories
    +[ '2004', '2005', '2006', '2007' ]
    +
    +// series
    +[{
    +	name: 'Sales',
    +	data: [ 1000, 1170, 660, 1030 ]
    +}, {
    +	name: 'Expenses',
    +	data: [ 400, 460, 1120, 540 ]
    +}]
    + Access the data as follows: +
    var $table = $('table').trigger('chartData');
    +
    +$('#chart').highcharts({
    +	chart: { type: 'column' },
    +	xAxis: { categories: $table[0].config.chart.categories },
    +	series: $table[0].config.chart.series
    +});
    +
    +
    + +

    Setup - FusionCharts

    +
    + The data used by FusionCharts is an array of objects in this format: +
    // category
    +[
    +	{"label": "2004"},
    +	{"label": "2005"},
    +	{"label": "2006"},
    +	{"label": "2007"}
    +]
    +// dataset
    +[{
    +	"seriesname": "Sales",
    +	"data": [
    +		{"value": "1000"},
    +		{"value": "1170"},
    +		{"value": "660"},
    +		{"value": "1030"}
    +	]
    +},{
    +	"seriesname": "Expenses",
    +	"data": [
    +		{"value": "400"},
    +		{"value": "600"},
    +		{"value": "1120"},
    +		{"value": "540"}
    +	]
    +}]
    + Access the data as follows: +
    var $table = $('table');
    +$table.trigger('chartData');
    +
    +FusionCharts.ready(function () {
    +	var analysisChart = new FusionCharts({
    +		dataFormat: 'json',
    +		dataSource: {
    +			"chart": {
    +				// ...
    +			},
    +			"categories": [{
    +				"category": $table[0].config.chart.category
    +			}],
    +			"dataset": $table[0].config.chart.dataset,
    +		},
    +		// other options
    +	}).render();
    +});
    +
    + +
    +

    + +

    Google Charts Demo

    +
    +
    +

    +
    + + + + + + + + +
    +

    +
    + + + + + + + +
    + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    YearSalesExpensesProfit
    2000$ 1,420$ 470$ 330
    2001$ 1,070$ 420$ 190
    2002$ 1,010$ 270$ 270
    2003$ 1,220$ 430$ 460
    2004$ 1,000$ 400$ 600
    2005$ 1,170$ 460$ 710
    2006$ 660$ 1,120($ 460)
    2007$ 1,030$ 540$ 490
    2008$ 2,150$ 240$ 410
    2009$ 230$ 660$ 110
    2010$ 1,110$ 390$ 520
    2011$ 733$ 110$ 210
    2012$ 870$ 300$ 190
    2013$ 1,320$ 490$ 290
    2014$ 950$ 210$ 140
    + + +
    +
    +
    + +
    + + +
    + +
    + + +
    + +
    +
    +
    +
    + +

    Page Header

    +
    +
    <!-- Google charts -->
    +<script src="//www.google.com/jsapi"></script>
    +
    +<!-- jQuery -->
    +<script src="js/jquery-latest.min.js"></script>
    +
    +<!-- Demo stuff -->
    +<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css">
    +<!-- buttons -->
    +<link rel="stylesheet" href="css/bootstrap.min.css">
    +<script src="js/bootstrap.min.js"></script>
    +
    +<!-- Tablesorter: required -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<script src="../js/jquery.tablesorter.js"></script>
    +<script src="../js/widgets/widget-chart.js"></script>
    +
    +<!-- Tablesorter: optional -->
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +<script src="../js/widgets/widget-cssStickyHeaders.js"></script>
    +<script src="../js/widgets/widget-columnSelector.js"></script>
    +<script src="../js/widgets/widget-pager.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    CSS

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + +
    + + + + + + + + diff --git a/docs/example-widget-column-selector.html b/docs/example-widget-column-selector.html new file mode 100644 index 0000000..da2308b --- /dev/null +++ b/docs/example-widget-column-selector.html @@ -0,0 +1,611 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Column Selector Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • In v2.19.0, the refreshColumnSelector method has been updated to allow passing a parameter. Pass an array of zero-based column indexes of columns to show, or any non-array to enable auto mode (if available).
    • +
    • In v2.18.4, added columnSelector_cssChecked option which contains the class name added to checked inputs. This helps fix an issue in Chrome that rears it's ugly head when trying to use input:checked to change a Font Awesome icon. See this demo by TheSin which uses this option to change the checkbox style.
    • +
    • + In v2.17.0, a method to refresh the column selector was added.
      +
      +
    • +
    • This widget will only work in tablesorter version 2.8+ and jQuery version 1.7+.
    • +
    • This widget may not work properly if the table contains rows with rowspan or colspan settings.
    • +
    • The responsive part of this widget: +
        +
      • Uses similar parameters as those used by jQuery mobile to set column priority.
      • +
      • The column priorities range from 1 to 6, with 1 having the highest priority. As the browser window shrinks, lower priority (higher numbers) columns will be hidden first until all numbered priority columns are hidden.
      • +
      • Any named data-priority, other than the numbers 1 - 6, (e.g. "critical" or "persistent") will be treated as a column which will not be included in the column selector.
      • +
      • Note that this widget uses media queries, which will not work in IE8 and older browsers.
      • +
      +
    • +
    • The selector code uses css selectors, for optimal speed, to hide/show columns. These selectors will not work in IE8 and older browsers.
    • +
    • The column button & popup is completely customizable, and in this demo it includes css that may not work properly in older versions of IE.
    • +
    +
    + +

    Options

    +
    +

    Column selector widget default options (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the "Option" column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDescription
    + Target an element within the current page where the column selector will be inserted. +
    +
    +
      +
    • This setting is optional. If not set, you can use the following function to attach it to another element - see the Bootstrap example below +
      $.tablesorter.columnSelector.attachTo( $('table'), '.selector-target' );
      +
    • +
    • This can be either a jQuery selector string ( e.g. '#columnSelector' )
    • +
    • or, a jQuery object ( e.g. $('#columnSelector') ).
    • +
    + Default value: null +
    +
    + Assigns a column status for each selector +
    +
    +
      +
    • To disable, or remove a column from the column selector, include the key word "disable" - this is one of many ways to remove a column from the column selector popup
    • +
    • Set a column status to true to initially display a column. This is the default for undefined columns.
    • +
    • Set a column status to false to initially hide a column.
    • +
    • Examples: +
      widgetOptions : {
      +  columnSelector_columns : {
      +    0 : "disable", /* disable; i.e. remove column from selector */
      +    1 : false,     /* start with column hidden */
      +    2 : true,      /* start with column visible; default for undefined columns */
      +  }
      +}
    • +
    • + *NOTE* Prior to v2.15.6, using these extra methods and setting a column to "false" would remove it from the selector. Now, it is more consistent with this columns option - set the appropriate method to "disable" to remove a column, "false" to initially hide a column and "true" to keep the column in an initially visible state.
      +
      + In v2.15.6, the following methods in order of priority are now available (set to true, false or disable): +
        +
      • jQuery data data-columnSelector="true" or data-columnSelector="false".
      • +
      • metadata class="{ columnSelector : true }" or class="{ columnSelector : false }".
      • +
      • headers option headers : { 0 : { columnSelector: true } } or headers : { 0 : { columnSelector: false } }.
      • +
      • header class name class="columnSelector-true" or class="columnSelector-false".
      • +
      +
    • +
    + *NOTE* Setting a column to initially be visible (true) or invisible (false) will be overridden by the users saved selections if the columnSelector_saveColumns option is true.
    +
    + Default value: {}; empty object +
    +
    Save the current manually set column status and the table's responsive ("auto") state (v2.15.7). +
    +
    + This option requires the storage utility contained within the tablesorter widgets file (jquery.tablesorter.widgets.js).
    +
    + Default value: true +
    +
    + This option defines the markup used for each column selector within the popup. +
    +
    + The only available parameter is the {name} string which will be replaced with the appropriate column name/title.
    +
    + An <input type="checkbox"> is required within this setting! The label element is optional.
    +
    + Default value: '<label><input type="checkbox">{name}</label>' +
    +
    + The data-attribute within the table header cell which contains an alternate column selector name. +
    +
    +
      +
    • If the header cell does not have this attribute defined, the column selector name will be taken from the header cell internal text.
    • +
    • If defined, the text contained within this attribute will replace the {name} string within the layout option above.
    • +
    + Default value: 'data-selector-name' +
    +
    Set this option to add (true) or not add (false) the media query functionality of this widget. +
    +
    + When true, an "auto" checkbox is included along with the column checkboxes: +
      +
    • When the "auto" checkbox is checked, all column checkboxes are disabled and media queries are active (columns will hide or show based on the browser width).
    • +
    • If "auto" is unchecked, media queries are disabled and column (non-critial/not disabled) visibility is based on the column checkbox setting.
    • +
    + Default value: true +
    +
    When the media query checkbox is added (it also uses the columnSelector_layout markup), this is the name that is added. +
    +
    + Set as "Auto" to signify to the user that columns disappearing and/or reappearing is automatically done.
    +
    + Default value: 'Auto: ' +
    +
    Set this option to false to start with the media query disabled (manual column selection mode). +
    +
    + Default value: true +
    +
    This option defines the media query breakpoints with which to use when a column with the associated priority is hidden or revealed. +
    +
    +
      +
    • For example, the last entry "70em" (1,120px) is assigned to data-priority 6. When the browser width is below this dimension, all columns with a data-priority of six will be hidden. Then when a browser width less than "60em" (960px) is reached, all columns of data-priority 5 and above will be hidden. At "50em" (800px), all columns of data-priority 4 and above are hidden, etc.
    • +
    • Adjust these values as desired, but a maximum of six data-priorities is set.
    • +
    + Default value: [ "20em", "30em", "40em", "50em", "60em", "70em" ] +
    +
    + This is the assigned data-attribute which contains the defined data priority for a table column +
    +
    +
      +
    • Values of 1 through 6 set the breakpoints of that particular column.
    • +
    • A value of 1 has the highest priority, meaning it is the last column(s) to be hidden when the browser width goes below "20em" (320px).
    • +
    • A value of 7 has the lowest priority, meaning it is the first column(s) to be hidden when the browser width goes below "70em" (1,120px).
    • +
    • Any named priority value, (e.g. "critical" or "persistent") will flag the widget to remove that column from the selector list.
    • +
    • Undefined priorities will default to a priority value of 1.
    • +
    + Default value: 'data-priority' +
    +
    + This class name is added to the input checkbox when it is checked +
    +
    + This was added because we found an issue in the latest version of Chrome where the css selector input:checked was not correctly modifying the displayed Font Awesome replacement icon when the checkbox was toggled.
    +
    + Use input.checked (or whatever value setting this class name option contains to get around this issue). See this demo by TheSin which uses this option to change the checkbox style.
    +
    + Default value: 'checked' +
    +
    + +
    + +

    Methods

    +
    + Refresh the breakpoints and selected columns using this method (v2.17.0): +

    +
    $('table').trigger('refreshColumnSelector');
    +
    + In v2.19.0, this method will now accept a parameter. +

    +
      +
    • + The parameter can be either an array of zero-based column indexes to toggle columns on and off: +
      $('table').trigger('refreshColumnSelector', [ [2,3,4] ]);
      + Note +
        +
      • Passing an array will turn "auto" mode off.
      • +
      • Make sure to wrap the array inside another array.
      • +
      • Columns marked as "critical" or "disable" will never get toggled off using this method.
      • +
      +

      +
    • +
    • + Or, set the parameter to any non-array value to turn the "auto" mode on - this only works if the columnSelector_mediaquery is set to true: +
      $('table').trigger('refreshColumnSelector', true);
      +
    • +
    +
    + +

    Removing a column from the selector

    +
    + This is probably overkill, but there are numerous ways to remove a column from the selection popup (v2.15.6): +
      +
    • Setting the data-priority to any non-numerical name (e.g. "critical" or "persistent").
    • +
    • Setting the column selector widget columns option columnSelector_columns : { 0 : 'disable' }.
    • +
    • The following methods, added to the header cell, in order of priority: +
        +
      • jQuery data data-columnSelector="disable".
      • +
      • metadata class="{ columnSelector : disable }" (requires the metadata plugin).
      • +
      • headers option headers : { 0 : { columnSelector: 'disable' } }.
      • +
      • header class name class="columnSelector-disable".
      • +
      +
    • +
    + * *NOTE* Prior to v2.15.6, setting these methods to "false" would remove it from the selector. Now, they must be set to "disable" to remove the column from the selector, this was done to make it more consistent with the columnSelector_columns setting. +
    +
    + +

    + +

    Demo

    + +

    CSS only popup

    + +
    + + +
    + +
    +
    (When "Auto" is set, the table becomes responsive; resize the browser window to see it work) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    + +

    Bootstrap Popover

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankFirst NameLast NameAgeTotalDiscountDate
    1Philip Aaron WongJohnson Sr Esq25$5.9522%Jun 26, 2004 7:22 AM
    11AaronHibert12$2.995%Aug 21, 2009 12:21 PM
    12Brandon ClarkHenry Jr51$42.2918%Oct 13, 2000 1:15 PM
    111PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    21JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    013ClarkKent Sr.18$15.8944%Jan 12, 2003 11:14 AM
    005BruceAlmighty Esq45$153.1944%Jan 18, 2021 9:12 AM
    10AlexDumass13$5.294%Jan 8, 2012 5:11 PM
    16JimFranco24$14.1914%Jan 14, 2004 11:23 AM
    166Bruce LeeEvans22$13.1911%Jan 18, 2007 9:12 AM
    100Brenda DexterMcMasters18$55.2015%Feb 12, 2010 7:23 PM
    55DennisBronson65$123.0032%Jan 20, 2001 1:12 PM
    9MarthadelFuego25$22.0917%Jun 11, 2011 10:55 AM
    + +

    Css

    +
    +
    
    +	
    + +

    HTML

    +
    +
    <h3>CSS only popup</h3>
    +<!-- This selector markup is completely customizable -->
    +<div class="columnSelectorWrapper">
    +	<input id="colSelect1" type="checkbox" class="hidden">
    +	<label class="columnSelectorButton" for="colSelect1">Column</label>
    +	<div id="columnSelector" class="columnSelector">
    +		<!-- this div is where the column selector is added -->
    +	</div>
    +</div>
    +
    +<table class="tablesorter custom-popup">
    +	<thead>
    +		<tr>
    +			<th data-priority="critical">Name</th>
    +			<!-- Remove column from selection popup by including -->
    +			<!-- data-priority="Anything other than 1-6" OR data-column-selector="disable" OR  class="columnSelector-disable" -->
    +			<th class="columnSelector-disable">Major</th>
    +			<!-- columnSelector-false will initially hide the column -->
    +			<th class="columnSelector-false" data-priority="6" data-selector-name="Gender">Sex</th>
    +			<th data-priority="4">English</th>
    +			<th data-priority="5">Japanese</th>
    +			<th data-priority="3">Calculus</th>
    +			<th data-priority="2">Geometry</th>
    +		</tr>
    +	</thead>
    +	<tfoot>
    +		<tr><th>Name</th><th>Major</th><th>Sex</th><th>English</th><th>Japanese</th><th>Calculus</th><th>Geometry</th></tr>
    +	</tfoot>
    +	<tbody>
    +		<!-- ... -->
    +	</tbody>
    +</table>
    +
    +<h3>Bootstrap Popover</h3>
    +<!-- Bootstrap popover button -->
    +<button id="popover" type="button" class="btn btn-default">
    +	Select Column
    +</button>
    +
    +<div class="hidden">
    +	<div id="popover-target"></div>
    +</div>
    +
    +<table class="tablesorter bootstrap-popup">
    +	<thead>
    +		<tr>
    +			<th data-priority="critical">Rank</th>
    +			<th data-priority="3">First Name</th>
    +			<th data-priority="critical">Last Name</th>
    +			<th data-priority="4">Age</th>
    +			<th data-priority="4">Total</th>
    +			<th data-priority="5">Discount</th>
    +			<th data-priority="6">Date</th>
    +		</tr>
    +	</thead>
    +	<tbody>
    +		<!-- ... -->
    +	</tbody>
    +</table>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +
    + + + + diff --git a/docs/example-widget-columns.html b/docs/example-widget-columns.html new file mode 100644 index 0000000..869686c --- /dev/null +++ b/docs/example-widget-columns.html @@ -0,0 +1,227 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Columns Style Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
    • +
    • Older versions of this widget can be applied to the original plugin. The code is in the "jquery.tablesorter.widgets.js" file.
    • +
    • The original "widgetColumns" option has been replaced by "widgetOptions.columns". See the javascript block below for more details (v2.1).
    • +
    • Table header and footer rows now get updated with the columns widget classes. Check out the "grey" theme to see (v2.4).
    • +
    • This demo page is running jQuery v1.2.6.
    • +
    +

    + +

    Demo

    + Choose Theme: + +

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Page Header

    +
    +
    <!-- blue theme stylesheet with additional css styles added in v2.0.17 -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<!-- tablesorter plugin -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- tablesorter widget file - loaded after the plugin -->
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    CSS

    +
    +
    /*
    + This css is part of the blue/style.css theme, shown as an example
    + To work with the zebra widget, include the .odd and .even color definitions as well
    + as definitions for the "primary", "secondary" and "tertiary" sorts.
    +*/
    +/* Column Widget - column sort colors */
    +table.tablesorter-blue td.primary,
    +table.tablesorter-blue tr.odd td.primary {
    +	background-color: #99b3e6;
    +}
    +table.tablesorter-blue tr.even td.primary {
    +	background-color: #c2d1f0;
    +}
    +
    +table.tablesorter-blue td.secondary,
    +table.tablesorter-blue tr.odd td.secondary {
    +	background-color: #c2d1f0;
    +}
    +table.tablesorter-blue tr.even td.secondary {
    +	background-color: #d6e0f5;
    +}
    +
    +table.tablesorter-blue td.tertiary,
    +table.tablesorter-blue tr.odd td.tertiary {
    +	background-color: #d6e0f5;
    +}
    +table.tablesorter-blue tr.even td.tertiary {
    +	background-color: #ebf0fa;
    +}
    +
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-widget-css-sticky-header.html b/docs/example-widget-css-sticky-header.html new file mode 100644 index 0000000..f7debb5 --- /dev/null +++ b/docs/example-widget-css-sticky-header.html @@ -0,0 +1,537 @@ + + + + + jQuery plugin: Tablesorter 2.0 - CSS Sticky Header Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • In v2.18.4, added a Magnific popup example to this page.
    • +
    • In v2.18.1, cssStickyHeaders_addCaption issue fixed & nested tables in IE now work properly.
    • +
    • This demo uses the CSS Sticky Headers widget which uses CSS transforms to reposition the table head.
    • +
    • CSS transforms are supported by most modern browsers (not IE8 and older).
    • +
    • The jQuery UI themed table does not stick to the top of the page due to the extra padding. Adjust the cssStickyHeaders_offset option as desired. I didn't bother in this demo because it includes more than just the jQuery UI theme.

    • +
    • This widget will not work with the original tablesorter, but works optimally with tablesorter v2.8+ (Added v2.14.1; Updated v2.18.1)
    • +
    +
    + +

    Change log

    +
    +
      +
    • v2.18.1: +
        +
      • Nested css sticky headers in IE now work as expected
      • +
      • Fixed an issue in Chrome where the height of the caption was still included even though the cssStickyHeaders_addCaption was set to false.
      • +
      +
    • +
    • v2.18.0: +
        +
      • Nested css sticky headers now stack; except in IE
      • +
      • Removed cssStickyHeaders_zIndex because the headers are not positioned.
      • +
      +
    • +
    • v2.16.4: +
        +
      • Added the cssStickyHeaders_filteredToTop option. +
          +
        • When true the table top will scroll into view after being filtered.
        • +
        • This is done because if the sticky header is active, and a filter results in say only one row, the table will scroll up out of the browser viewport.
        • +
        • If set to false, no scrolling is done.
        • +
        +
      • +
      +
    • +
    • v2.14.4: +
        +
      • Added cssStickyHeaders_attachTo (default set to null). Setting this option with either a jQuery selector string (".wrapper") or jQuery object ($(".wrapper")) to attach the sticky header to this element - see the second example below.
      • +
      • Removed cssStickyHeaders_offsetX option.
      • +
      • Renamed cssStickyHeaders_offsetY to cssStickyHeaders_offset as the horizontal offset is not required.
      • +
      +
    • +
    • v2.14.1: Created css Sticky Headers widget
    • +
    +
    + +
    +

    + +

    CSS

    +
    +
    
    +	
    + +

    Javascript

    +
    +
    
    +	
    + +

    Demo

    + Choose Theme: +

    + Include Caption: +

    + +

    Sticky headers in a popup window

    + Show table in Magnific popup window + + + +

    + +

    Attach sticky header to browser window

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Student Grades
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Languagesfemale85808080
    student23Mathematicsmale8277079
    student24Languagesfemale100911382
    student25Mathematicsmale22968253
    student26Languagesfemale37295659
    student27Mathematicsmale86826923
    student28Languagesfemale4425431
    student29Mathematicsmale77472238
    student30Languagesfemale19352310
    student31Mathematicsmale90271750
    student32Languagesfemale60753338
    student33Mathematicsmale4313715
    student34Languagesfemale77978144
    student35Mathematicsmale5815195
    student36Languagesfemale70617094
    student37Mathematicsmale6036184
    student38Languagesfemale6339011
    student39Mathematicsmale50463238
    student40Languagesfemale5175253
    student41Mathematicsmale43342878
    student42Languagesfemale11896095
    student43Mathematicsmale48921888
    student44Languagesfemale8225973
    student45Mathematicsmale91733739
    student46Languagesfemale481210
    student47Mathematicsmale8910611
    student48Languagesfemale90322118
    student49Mathematicsmale42494972
    student50Languagesfemale56376754
    + +

    Attach sticky header to its parent

    +
    + + + + + + + + + + + + + + + + + + + + + + +
    Student Grades
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent1815.4944.2%-13
    A11BruceAlmighty45153.1944%+19
    A102BruceEvans56153.1923%+9
    A23MikePeters225.6920.3%+2
    A55LeslieKent3315.9925.1%-3
    A3FrankMint4412.5944.2%-12
    A21JoeThomas4515.2544%+12
    A12TessEvans6613.5923%+4
    A21PeterDunn122.9921.1%+2
    A33HarryJones1319.4922.2%-6
    A13JohnJames1613.8942.1%-13
    A71NickParker4513.8944%+29
    A21CharlesDunn1915.4922%+3
    +
    + +

    Nested sticky header tables

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Main table header
    Main table - row 1
    Main table - row 2
    + Main table - row 3 (with nested table 1) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Header for the nested table 1
    Second header row for nested table 1
    data in the nested table 1 - row 1
    data in the nested table 1 - row 2
    data in the nested table 1 - row 3
    data in the nested table 1 - row 4
    data in the nested table 1 - row 5
    + data in the nested table 1 - row 6 (with nested table 2) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Nested table 2 caption
    Header for the nested table 2
    Second header row for nested table 2
    data in the nested table 2 - row 1
    data in the nested table 2 - row 2
    data in the nested table 2 - row 3
    data in the nested table 2 - row 4
    data in the nested table 2 - row 5
    data in the nested table 2 - row 6
    data in the nested table 2 - row 7
    data in the nested table 2 - row 8
    data in the nested table 2 - row 9
    data in the nested table 2 - row 10
    data in the nested table 2 - row 11
    data in the nested table 2 - row 12
    data in the nested table 2 - row 13
    data in the nested table 2 - row 14
    data in the nested table 2 - row 15
    data in the nested table 2 - row 16
    data in the nested table 2 - row 17
    data in the nested table 2 - row 18
    data in the nested table 2 - row 19
    data in the nested table 2 - row 20
    +
    data in the nested table 1 - row 7
    data in the nested table 1 - row 8
    data in the nested table 1 - row 9
    data in the nested table 1 - row 10
    data in the nested table 1 - row 11
    data in the nested table 1 - row 12
    data in the nested table 1 - row 13
    data in the nested table 1 - row 14
    data in the nested table 1 - row 15
    data in the nested table 1 - row 16
    data in the nested table 1 - row 17
    data in the nested table 1 - row 18
    data in the nested table 1 - row 19
    data in the nested table 1 - row 20
    data in the nested table 1 - row 21
    +
    Main table - row 4
    + Main table - row 5 (with nested table 3) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Nested table 3 caption
    Header for the nested table 3
    data in the nested table 3 - row 1
    data in the nested table 3 - row 2
    data in the nested table 3 - row 3
    data in the nested table 3 - row 4
    data in the nested table 3 - row 5
    data in the nested table 3 - row 6
    data in the nested table 3 - row 7
    data in the nested table 3 - row 8
    data in the nested table 3 - row 9
    data in the nested table 3 - row 10
    data in the nested table 3 - row 11
    data in the nested table 3 - row 12
    data in the nested table 3 - row 13
    data in the nested table 3 - row 14
    data in the nested table 3 - row 15
    data in the nested table 3 - row 16
    data in the nested table 3 - row 17
    data in the nested table 3 - row 18
    data in the nested table 3 - row 19
    data in the nested table 3 - row 20
    +
    Main table - row 6
    + +
    +
    + + + + diff --git a/docs/example-widget-editable.html b/docs/example-widget-editable.html new file mode 100644 index 0000000..aa9c051 --- /dev/null +++ b/docs/example-widget-editable.html @@ -0,0 +1,579 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Content Editable + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • This widget can not be applied to the original plugin and requires jQuery 1.7+ and a browser that supports contenteditable attributes (almost all modern browsers).
    • +
    • Important: In Internet Explorer, please wrap the cell content with a DIV or SPAN as it is not possible to make table cells directly contenteditable. Wrapping the content in the markup is much more efficient than using javascript to do it for you (especially in IE).

    • +
    • In v2.22.0, +
        +
      • The cell content now only automatically updates when the user hovers over the table header. Prior to this version, the automatic update would occur when the mouse left the tbody of the table. The reason this is necessary is because initiating a sort would change the row indexing set prior to the cell content being updated, so the cache would end up not matching the table content.
      • +
      • Modified the editable_trimContent option to only trim content when set.
      • +
      • The widget now works with the contenteditable html (using jQuery's .html()); previously, the widget would only manipulate the text (using jQuery .text()), so any HTML would get stripped out.
        + *Note* Because of this change, if the user presses Enter, a <div> will be automatically inserted by the browser (not the widget) and any content entered will be added inside this "new line" div. If this is undesirable, use the editable_blur callback to modify the content.
      • +
      • If the cell content is already wrapped in a div or span, that element will be made contenteditable. Otherwise any direct children of the table cell will be made contenteditable; prior to this update, all direct child elements (including <br>s were made contenteditable by mistake).
      • +
      +
    • +
    • Updated v2.17.6, +
        +
      • Fixed the editable_enterToAccept option to do what it was meant to do, accept when the user presses enter.
      • +
      • Added editable_autoAccept option, so that when it is true the original behavior of accepting content changes will be maintained.
      • +
      • Added editable_validate option, to allow validating the edited content.
      • +
      • Focus is now maintained within the contenteditable element after updating. This makes it easier to tab through the table while editing. This change also fixes this Stackoverflow issue.
      • +
      • The editComplete event now passes the table config variable to make it easier to access tablesorter variables.
      • +
      +
    • +
    • Updated v2.13.2, because of the limitation in IE, if a table cell contains any DIV or SPAN immediately inside the cell, it will be targeted instead of the table cell itself and made content editable. So, if you don't care about IE support, there is no need to include the extra markup.
    • +
    • In some browsers, additional CSS is needed to highlight a focused editable table cell. See the CSS block below.
    • +
    • Pressing escape while editing will cancel any changes.
    • +
    • In the demo below, click in any of the first three columns to edit the content, except for the cell containing "Peter".
    • +
    • To prevent a table cell from becoming editable, add the class name "no-edit" to the cell. Set by the editable_noEdit option.
    • +
    +
    + +

    When Content Changes are Accepted

    +
    + + + + + + + + + + + + + + + + + + +
    editable_enterToAccept
    truefalse
    editable_autoAccepttrue +
      +
    • Pressing alt-enter
    • +
    • Pressing enter
    • +
    • Clicking outside of the current editable content.
    • +
    • Moving the mouse outside of the current tbody (this is done because if the content editable is still active when the user clicks on the header to sort the column, all sorts of bad things happen).
    • +
    +
    +
      +
    • Pressing alt-enter
    • +
    • Clicking outside of the current editable content.
    • +
    • Moving the mouse outside of the current tbody.
    • +
    +
    false +
      +
    • Pressing alt-enter
    • +
    • Pressing enter
    • +
    +
    +
      +
    • Pressing alt-enter
    • +
    +
    + * Note The content is only accepted when the editable_validation function does not return false. +
    + +

    Options

    +
    +

    Editable widget default options (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the function column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDescription
    Accepts any changes made to the table cell automatically v2.17.6 +
    +
    + If the user clicks outside or tabs out of the edited cell, or moves the mouse out of the current tbody, any changes to the cell will be accepted
    +
    + The only time the content is not accepted is if the user presses the escape key.
    +
    + if false, the acceptance behavior follows the editable_enterToAccept setting.
    +
    + Default value: true +
    +
    Contains an array (or range string) of columns numbers you want to have editable content (zero-based index). +
    +
      +
    • In tablesorter core v2.14.2, this widget was updated to allow passing a range string in this option, i.e. "0-2" instead of [0,1,2].
    • +
    • contenteditable="true" is added to cells within these columns.
    • +
    + Default value: [] (empty array) +
    +
    Makes the user press enter to accept the content within the editable table cell +
    +
    + if false, clicking outside the cell will accept the content.
    +
    + Default value: true +
    +
    If true, the column will resort (only if already sorted) after the content has been changed. +
    +
    + Default value: false +
    +
    Class name on table cells to search for that are not to become editable. +
    +
    + The search is only done within the columns set by the editable_columns option.
    +
    + Default value: 'no-edit' +
    +
    Event fired after the table content has been edited +
    +
    +
    $(function(){
    +
    +  $('#table')
    +    .tablesorter({
    +      widgets : ['editable'],
    +      widgetOptions : {
    +        editable_editComplete : 'giterdone'
    +      }
    +    })
    +    // use delegated event binding
    +    .on('giterdone', 'td', function(event, config){
    +      // this = td; the event bubble up
    +      console.log( 'new content = ' + $(this).text() );
    +    });
    +
    +});
    + Default value: 'editComplete' +
    +
    Callback function that is executeed when the contenteditable cell is focused (v2.17.8) +
    +
    + Set this function to manipulate or adjust the content when the content editable is focused +
    $(function(){
    +
    +  $('#table').tablesorter({
    +    widgets : ['editable'],
    +    widgetOptions : {
    +      editable_focused : function(txt, columnIndex, $element){
    +        // note $element is the div inside of the table cell, so use $element.closest('td') to get the cell
    +        $element.closest('td').addClass('focused');
    +      },
    +      editable_blur : function(txt, columnIndex, $element){
    +        $element.closest('td').removeClass('focused');
    +      }
    +    }
    +  });
    +
    +});
    + Default value: null +
    +
    Callback function that is executeed when the contenteditable cell is no longer focused (v2.17.8) +
    +
    + Set this function to manipulate or adjust the content when the content editable is blurred +
    $(function(){
    +
    +  $('#table').tablesorter({
    +    widgets : ['editable'],
    +    widgetOptions : {
    +      editable_focused : function(txt, columnIndex, $element){
    +        // note $element is the div inside of the table cell, so use $element.closest('td') to get the cell
    +        $element.closest('td').addClass('focused');
    +      },
    +      editable_blur : function(txt, columnIndex, $element){
    +        $element.closest('td').removeClass('focused');
    +      }
    +    }
    +  });
    +
    +});
    + Default value: null +
    +
    Set to automatically select all content when the contenteditable cell is focused (v2.17.8) +
    +
    + Set this option to a boolean, or a function that returns a boolean: +
      +
    • When true, all of the text within the current contenteditable element will be selected.
    • +
    • When false, no selection is made.
    • +
    • When this option contains a function, return either true to select all of the text within the element, or false to not select any text.
    • +
    +
    $(function(){
    +
    +  $('#table').tablesorter({
    +    widgets : ['editable'],
    +    widgetOptions : {
    +      editable_selectAll : function(txt, columnIndex, $element){
    +        // note $element is the div inside of the table cell, so use $element.closest('td') to get the cell
    +        // only select everthing within the element when the content starts with the letter "B"
    +        return /^b/i.test(txt) && columnIndex === 0;
    +      }
    +    }
    +  });
    +
    +});
    + Default value: null +
    +
    Validate the content change (v2.17.8) +
    +
    + Use this function to validate and/or modify the content before it is accepted.
    +
    + In v2.17.8: +
      +
    • Set this option to be a global function, or an object containing a column index, or class name of the desired column
    • +
    • A columnIndex is now included in the function parameters
    • +
    • A $element parameter has been included which contains the contenteditable element. To get the table cell, use $element.closest('td');
    • +
    + This function must return either a string containing the modified content or false to revert the content back to it's original value. Example: +
    $(function(){
    +
    +  $('#table1').tablesorter({
    +    widgets : ['editable'],
    +    widgetOptions : {
    +      // global validate function
    +      editable_validate : function(txt, orig, columnIndex, $element){
    +        // only allow one word
    +        var t = /\s/.test(txt) ? txt.split(/\s/)[0] : txt;
    +        return t ? t : false;
    +      }
    +    }
    +  });
    +
    +  $('#table2').tablesorter({
    +    widgets : ['editable'],
    +    widgetOptions : {
    +      // validate function per column
    +      editable_validate : {
    +        0 : function(txt, orig, columnIndex, $element){
    +          // allow up to two words
    +          var t = txt.split(' ');
    +          return t.length > 2 ? t[0] + (t[1] ? ' ' + t[1] : '') : txt;
    +        },
    +        '.price' : function(txt, orig, columnIndex, $element) {
    +          // make sure the price column(s) are using a number
    +          return isNaN( txt.replace(/[$,\s]/g, '') ) ? false : txt;
    +        }
    +      }
    +    }
    +  });
    +
    +});
    + Default value: null +
    +
    Trim the content within the editable cell (v2.17.8) +
    +
    + When a table cell is formatted as follows: +
    <td>
    +	John
    +</td>
    Carriage returns and tab(s) at the beginning & end of the contenteditable table cells will be removed initially and after editing.
    +
    + If this option is true, this widget will trim content upon initialization; this is necessary if you need cleaned it up content before editing, like with an autocomplete script.
    +
    + Use this option as follows: +
    $(function(){
    +
    +  $('#table').tablesorter({
    +    widgets : ['editable'],
    +    widgetOptions : {
    +      editable_trimContent : true
    +    }
    +  });
    +
    +});
    + Default value: true +
    +
    Wrap the editable cell content with this element (v2.17.8) +
    +
    + Internally, the widget uses jQuery's wrapInner to wrap the cell contents, using the following rules: +
      +
    • If this option is set to false or an empty string (''), then no wrapping will occur. The "contenteditable" attribute will be applied to the table cell.
    • +
    • If the table cell has no children, then the content is wrapped using this option, and the wrapping element will have the "contentediable" attribute enabled.
    • +
    • If the cell already has children (one or more) immediately inside of the table cell, no wrapping occurs and the child element(s) that don't have the class name set in editable_noEdit, will have the "contenteditable" attribute enabled.
    • +
    + Note: that this option uses jQuery's wrapInner, so this option can be set to a html string or selector, jQuery object, DOM element, or a function (jQuery 1.4+) +
    $(function(){
    +
    +  $('#table').tablesorter({
    +    widgets : ['editable'],
    +    widgetOptions : {
    +      editable_wrap : '<div>'
    +    }
    +  });
    +
    +});
    + Default value: '<div>' +
    +
    +
    + +
    + +

    +

    Demo

    + + editable_autoAccept    : true
    + editable_enterToAccept : true +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    CSS

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + +
    + + + + + + diff --git a/docs/example-widget-filter-any-match.html b/docs/example-widget-filter-any-match.html new file mode 100644 index 0000000..eeb2389 --- /dev/null +++ b/docs/example-widget-filter-any-match.html @@ -0,0 +1,207 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Filter Widget External Search + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • In v2.22.0, AnyMatch searches for specific columns will no longer save filter data to each targeted column. See the "AnyMatch Searches" section below.
    • +
    • In v2.20.0, @MasksimProgr added a method to allow targeting a specific column using the anyMatch filter. Find more details in the AnyMatch section below.
    • +
    • In v2.18.0, the external search data column can be set to multiple columns (data-column="0-2,4,6-7"). Please see the Filter Widget External Inputs demo for more details.
    • +
    • In v2.17.8, added a default fuzzy search to the "First Name" column.
    • +
    • This is a demo of the filter_external option (added v2.15).
    • +
    • In v2.15 +
        +
      • The filter_anyMatch option has been removed (added v2.13.3; removed in v2.15)
      • +
      • A new option filter_external has been added. It is set to a jQuery selector string ('.search') or jQuery object ($('.search')) targeting an external input.
      • +
      • So now a table can include both a filter row (filter_columnFilters is true, i.e. the internal table filters) and any number of external search inputs (as set by the filter_external option).
      • +
      • The external search results must have a data-column="#" attribute set, where # is the index of the column (zero-based) that the input targets, to have an input search all table content, set the data column attribute to "all" to match any column.
      • +
      • The $.tablesorter.bindSearch function (see demo) does exactly the same thing as the filter_external option. The major difference is seen when using ajax to populate the table, the initial filter values can be set before tablesorter initialization when using the filter_external option; whereas, the bind search function can not set initial filter values and is usually executed after tablesorter initialization.
      • +
      +
    • +
    +
    + +

    AnyMatch Searches

    +
    +
      +
    • In v2.20.0, the anyMatch filter can target specific columns using the following format: +
      #:{query}
      +
        +
      • where # is the column one-based index (non-developers count from one)
      • +
      • and {query} is the specific column query.
      • +
      +
      + You can disable this type of search by setting the new filter_columnAnyMatch option to false. +

      Examples

      +
        +
      • Find values > 30 in the age column
      • +
      • Include a fuzzy search (see filter_defaultFilter setting) and look for "aa" in the first name column (four results should show).
      • +
      • Find ranks with a "5" in them and find dates with a "12"
      • +
      • This column specific anyMatch does not support using an OR column search like 1:5|7:12
      • +
      +

      + * NOTE * Fixed in v2.22.0. When a AnyMatch search of this type is active, it adds filter queries to specific columns, so if the filters are saved and you reload the page, the specified column filters will become populated along with the AnyMatch search. +
    • +
    +
    + +

    Limitations

    +
    +
      +
    • The any-match search method has limitations applied. It does not support all of the per column search features! So, at this time, the following types of queries are not allowed as the results will cause confusion: +
        +
      • Search operators - A search for values equal, greater or less than values (> >= <= <) is not allowed because tables that contain both numbers and text (in separate columns). For example: +
        "Fred" > "1"  // true*
        +"Fred" < "10" // false
        +"Fred" > 1    // false (numeric comparisons occur with parsed table data)
        +"Fred" > 1    // false
        +"Fred" < 10   // false
        * For comparisons, letters have a greater ASCII value than numbers. +
      • +
      • Range query - A search for any number range (1 - 10) is not allowed because, if any columns contain text, then no rows will result. The examples are the same as the search operators examples above.
      • +
      • Not Match query - A search for not matches (!a) is not allowed because tables that contain both numbers and text (in separate columns) will always show all rows. For example: +
        "Frank".search("a")    //  2 (a match, so this row "may" be hidden)
        +"Fred".search("a")      // -1 (a not match! so this row will always show)
        +"25".search("a")        // -1 (a not match! so this row will always show)
        +"1/1/2014".search("a")  // -1 (a not match! so this row will always show)
        +
      • +
      • Allowed filters include plain text matching, fuzzy search (~), exact match ("), wild card matches( ? or *), regex (/\d/g), and logical and (a && b)/or (a|b) matches.
      • +
      +
    • +
    • Setting this option should work properly with or without the column filters. The only issue you would have is if you triggered a search on the table using an array with undefined or null array values, like this: +
      // apply "2?%" filter to the fifth column (zero-based index)
      +var columns = [];
      +columns[5] = '2?%';
      +// anyMatch will kick in on undefined column filters,
      +// unless the array looks like this: columns = [ '', '', '', '', '', '2?%' ]
      +$('table').trigger('search', [ columns ]);
      +
    • +
    +
    +
    +
    + +

    Demo

    + +
    (Match any column)
    + (First Name; fuzzy search... try "be")
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankFirst NameLast NameAgeTotalDiscountDate
    1Philip AaronJohnson Sr Esq25$5.9522%Jun 26, 2004 7:22 AM
    11AaronHibert12$2.995%Aug 21, 2009 12:21 PM
    12Brandon ClarkHenry Jr51$42.2918%Oct 13, 2000 1:15 PM
    111PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    21JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    013ClarkKent Sr.18$15.8944%Jan 12, 2003 11:14 AM
    005BruceAlmighty Esq45$153.1944%Jan 18, 2021 9:12 AM
    10AlexDumass13$5.294%Jan 8, 2012 5:11 PM
    16JimFranco24$14.1914%Jan 14, 2004 11:23 AM
    166Bruce LeeEvans22$13.1911%Jan 18, 2007 9:12 AM
    100Brenda LeeMcMasters18$55.2015%Feb 12, 2010 7:23 PM
    55DennisBronson65$123.0032%Jan 20, 2001 1:12 PM
    9MarthadelFuego25$22.0917%Jun 11, 2011 10:55 AM
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-widget-filter-custom-search.html b/docs/example-widget-filter-custom-search.html new file mode 100644 index 0000000..6c3605f --- /dev/null +++ b/docs/example-widget-filter-custom-search.html @@ -0,0 +1,298 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Custom Filter Widget Search Types + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • In v2.22.0, additional values were added to the data parameter as it is now provided as a parameter to all filter_functions. See the "How to add Custom filter types" section below to review the new additions.
    • +
    • Notice! In version v2.17.8, some drastic changes were made to the way variables are passed to the filters. Please check out the "How to add Custom Filter types" section below.
    • +
    • This demo was added in v2.17.5, but modification using these instructions works for v2.13.3+; when the filter widget was restructured to allow the adding of custom filter search types.
    • +
    • In this demo, two additional search types have been added as an example +
        +
      • Start a search from beginning of the content using the ^ designator.
      • +
      • Search for a specific ending in the content using the $ designator.
      • +
      +
    • +
    • Please review the following sections for more details.
    • +
    +
    + +

    Built-in Filters

    +
    + The built-in filter search types include: + + + + + + + + + + + + + + + +
    PriorityTypeDesignatorFunction
    1regex/./mig$.tablesorter.filter.types.regex
    2operators< <= >= >$.tablesorter.filter.types.operators
    3not! or !=$.tablesorter.filter.types.notMatch
    4exact" or =$.tablesorter.filter.types.exact
    5and &&  or  and $.tablesorter.filter.types.and
    6range -  or  to $.tablesorter.filter.types.range
    7wild* or ?$.tablesorter.filter.types.wild
    7or| or  or $.tablesorter.filter.types.wild (built-into wild)
    8fuzzy~$.tablesorter.filter.types.fuzzy
    +
    + +

    How to add Custom filter types

    +
    +
      +
    • The first step is to decide what you want your filter to do.
    • +
    • Should it look for a symbol at the beginning, middle or end of the filter?
    • +
    • Does the designator need spaces around it (e.g. " and " or " or ") to prevent problems? You wouldn't be able to find the country of "Andorra" if the "and" or "or" designators didn't require spaces.
    • +
    • Make sure to name your filter so that it doesn't interfere with already existing ones, unless your filter is meant to replace an existing one. See the "Built-in Filters" section for a full list of filter function names.
    • +
    • Changed in v2.17.8, only two parameters are passed to the filter type function: +
      $.tablesorter.filter.types.myNewFilter = function( config, data ) { /* ... */ }
      +
        +
      • config - tablesorter config containing all variables (table.config)
      • +
      • data - filter data containing all filter variables. All variables are listed below.
      • +
      +
      +
    • +
    • Within your filter, first test for your designator symbol. +
        +
      • If it exists within the filter, then do your comparison and return a boolean of true or false.
      • +
      • The following arguments are passed within the data parameter to both the filter_function & filter type function (changed in v2.22.0): +
          +
        • data.$row - The jQuery object of the current row being processed by the filter widget; added v2.22.0.
        • +
        • data.$cells - A jQuery object containing all the table cells in the current row being processed; added v2.22.0.
        • +
        • data.filters - Array of filters for all columns (some array values may be undefined); added v2.22.0.

        • + +
        • data.filter - The exact text from the filter input (e.g. ^h).
        • +
        • data.iFilter - The text from the filter in all lower case for case insensitive searches, if table.config.widgetOptions.filter_ignoreCase is true.
        • +
        • data.exact - The exact (or parsed) text from the current table cell, or the entire row if data.anyMatch is true; the parsed text is passed when the column has a "filter-parsed" class name set.
        • +
        • data.iExact - The exact (or parsed) text in all lower case for case insensitive searches, if table.config.widgetOptions.filter_ignoreCase is true.

        • +
        • data.index - The current column index (zero-based) being filtered. When performing an "any match", this index is equal to config.columns which is the last column of the table plus one.
        • +
        • data.cache - The parsed text from the current table cell, or the entire row if data.anyMatch is true. This value will be in all lower case if config.ignoreCase is true.

        • + +
        • data.anyMatch - This is a boolean value indicating when the data.exact and data.iExact parameters contain data from the entire row instead of one cell. This value will always be false if the table does not include an associated any match filter.

        • + +
        • data.rawArray - An array of raw content extracted from each table cell in the row being processed; added v2.22.0.
        • +
        • data.rowArray - An array of the modified exact text from each table cell in the current row being processed. The content will be in all lower case, if the table.config.ignoreCase option is true & accents replaced if the table.config.sortLocaleCompare option is true).
        • +
        • data.cacheArray - An array of parsed content from each table cell in the row being processed.
        • +
        • data.childRowText - contains all text from any associated child rows.
        • + +
        • data.parsed - An array of boolean flags that indicate if the column data should be obtained from parsed values, or not; obtained from filter_useParsedData setting or filter-parsed classes on the header cells. +
        • +
        +
        +
      • +
      • If your designator doesn't exist, you *must* return null to allow comparisons with other filter types.
      • +
      +
      +
    • +
    • Here is a basic example with extensive comments: +
      // search for a match from the beginning of a string
      +// "^l" matches "lion" but not "koala"
      +$.tablesorter.filter.types.start = function( config, data ) {
      +	// test for filter type designator. In this example, "^" must be at the beginning of the filter
      +	// for this test, the use of the case insensitive "iFilter" variable
      +	// doesn't matter since we are only looking at the symbol
      +	if ( /^\^/.test( data.iFilter ) ) {
      +		// test the table content (exact or parsed) against the filter
      +		// * Don't forget to remove the designator first ( the substring(1) part ), so "^h".substring(1) becomes "h"
      +		// * In this case, we do care about using "iFilter" since we're comparing it with "iExact"
      +		// * We use "indexOf" so that we know the match starts from the beginning of the string.
      +		// * Your function should return a boolean indicating a match, or not.
      +		return data.iExact.indexOf( data.iFilter.substring(1) ) === 0;
      +	}
      +	// ALWAYS return null if your custom filter type doesn't match
      +	return null;
      +};
      +
    • +
    +
    + +

    How to remove filter types

    +
    +
      +
    • If one of the built-in search types is interfering or bothersome to your users, then you can remove it using the following command (using fuzzy search as an example): +
      $(function(){
      +
      +	// Remove fuzzy search
      +	delete $.tablesorter.filter.types.fuzzy;
      +
      +	$('table').tablesorter({
      +		theme: 'blue',
      +		widgets: ['filter']
      +	});
      +
      +});
    • +
    • The full list of built-in filter type functions can be found in the "Built-in Filters" section.
    • +
    +
    + +

    Localization

    +
    + You can change the language of the searches used within the filter widget. This only applies to the "and", "or" and "to" (range) searches. For example, to change the localization to French, do the following: +
    // add French support
    +$.extend($.tablesorter.language, {
    +	to  : 'à',
    +	or  : 'ou',
    +	and : 'et'
    +});
    This results in searches that can be performed as follows: +
      +
    • "and" search: Pierre et Franc or Pierre && Franc.
    • +
    • "or" search: Marie ou Claudette or Marie|Claudette
    • +
    • "to" search: 10 à 20 or 10 - 20
    • +
    + Note the symbolic searches never changed ( && , | and  - ) +
    + Important Even though the language settings don't include spaces, the user is still required to enter spaces in the filter to perform these searches, e.g. 1 à 10 (shows rows with numbers between 1 and 10). +
    + If you want to support multiple languages, separate the language variables with a vertical bar (|, Shift + \): +
    // add French & Spanish support
    +$.extend($.tablesorter.language, {
    +	to  : 'à|a',
    +	or  : 'ou|o',
    +	and : 'et|y'
    +});
    + +
    + +

    Demo

    +
    (beginning of word)
    + (end of word)
    +
    + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameCityAgeTotalDiscountDate
    AaronJohnson SrAtlanta35$5.9522%Jun 26, 2004 7:22 AM
    AaronJohnsonYuma12$2.995%Aug 21, 2009 12:21 PM
    ClarkHenry JrTampa51$42.2918%Oct 13, 2000 1:15 PM
    DenniHenryNew York28$9.9920%Jul 6, 2006 8:14 AM
    JohnHoodBoston33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent SrLos Angeles18$15.8944%Jan 12, 2003 11:14 AM
    PeterKent EsqSeattle45$153.1944%Jan 18, 2021 9:12 AM
    PeterJohnsMilwaukee13$5.294%Jan 8, 2012 5:11 PM
    AaronEvanChicago24$14.1914%Jan 14, 2004 11:23 AM
    BruceEvansUpland22$13.1911%Jan 18, 2007 9:12 AM
    ClarkMcMastersPheonix18$55.2015%Feb 12, 2010 7:23 PM
    DennisMastersIndianapolis65$123.0032%Jan 20, 2001 1:12 PM
    JohnHoodFort Worth25$22.0917%Jun 11, 2011 10:55 AM
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-widget-filter-custom-search2.html b/docs/example-widget-filter-custom-search2.html new file mode 100644 index 0000000..7385086 --- /dev/null +++ b/docs/example-widget-filter-custom-search2.html @@ -0,0 +1,157 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Custom Filter Widget Search Type (example 2) + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • In v2.21.0 +
        +
      • The "insideRange" function was updated to use the column parser and moved into a separate file "widget-filter-type-insideRange.js"
      • +
      • This change would allow the sorting of dates, if using it along with one of the date-range parsers (added v2.21.0).
      • +
      +
    • +
    • This is another example of how to add a custom filter search type - see this page for details on how to add your own.
    • +
    • This "insideRange" search type does the following: +
        +
      • This search type was not included with the other built-in search types as it might be a little slower than the other search types because it has a bit more calculation to do than the others.
      • +
      • It looks for a dash surrounded by spaces ( - ) within the filter before activating.
      • +
      • So if you look for just in the "Delivery" column, the exact match of 4 will still be included.
      • +
      • Test out some more examples: +
          +
        • Try or in the Delivery column
        • +
        • in the "Price Range" column.
        • +
        • in the "Date Range" column; this column is processed using the "date-range-mdy" parser (added v2.21.0).
        • +
        +
      • +
      +
    • +
    • Entering a range (e.g. will switch the query to the range search type which will only look at the first number of the range within each cell.
    • +
    +

    + +

    Demo

    +Filters: + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankNameDelivery (days)Price RangeDate Range
    1Widget2 - 10$5.95 - $13.2004/28/2014 - 07/13/2014
    11Doodad1 - 4$2.99 - $8.4004/28/2014 - 05/13/2014
    12Whatchamacallit3 - 7$4.29 - $15.997/15/2014
    15Thingy5 - 6$9.99 - $13.2007/12/2014 - 07/23/2014
    21Cube2 - 7$6.99 - $14.9905/22/2014 - 05/23/2014
    13It5 - 12$15.89 - $18.228/12/2014 - 7/10/2014
    5Fred20 - 30$13.19 - $15.546/12/2014 - 6/14/2014
    10FuBar4$5.506/13/2014 - 6/22/2014
    16Otto2 - 4$6.30 - $14.195/10/2014 - 5/20/2014
    21Betsy7$5.67 - $8.256/2/2014 - 6/13/2014
    18Clyde5 - 10$11.20 - $15.456/13/2014
    7Brick5 - 7$12.00 - $14.307/2/2014 - 7/25/2014
    9Gadget10 - 20$7.09 - $13.205/23/2014 - 6/12/2014
    + +

    Page Head

    +
    +
    <!-- jQuery -->
    +<script src="js/jquery-latest.min.js"></script>
    +
    +<!-- tablesorter -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<script src="../js/jquery.tablesorter.js"></script>
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +<!-- inside range filter type -->
    +<script src="../js/widgets/widget-filter-type-insideRange.js"></script>
    +<!-- parse date ranges -->
    +<script src="../js/parsers/parser-date-range.js"></script>
    +
    + + +

    Javascript

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-widget-filter-custom.html b/docs/example-widget-filter-custom.html new file mode 100644 index 0000000..5f6a463 --- /dev/null +++ b/docs/example-widget-filter-custom.html @@ -0,0 +1,486 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Custom Filter Widget Functions + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • In v2.22.0, +
        +
      • An additional data parameter was added to the filter functions. It is an object which contains all data provided to the filter type functions (see all the data values here).
      • +
      • *WARNING* In a future update, the filter function parameters will change to clean up the code (I know, it's messy)! +
        filter_functions : {
        +  // function(e, n, f, i, $r, c, data) {} <- current parameters
        +  0 : function(c, data) {} // planned change (version undetermined)
        +}
        The e (exact table cell text), n (normalized table cell text), f (filter input value), i (column index) and $r (current row; jQuery object) are all already included in the data object.

      • +
      +
    • +
    • In v2.21.0, the filter functions provide an additional parameter c which is the table.config.
    • +
    • In v2.17.0, the filter_functions column can also be referenced by using a jQuery selector (e.g. class name or ID).
    • +
    • In v2.16.3, +
        +
      • When a default filter select is added to a column, it is now parsed from the assigned parser, then sorted using the textSorter setting, and falls back to an alphanumeric sort.
      • +
      • Adding a class of "filter-select-nosort" will now leave the select options unsorted.
      • +
      +
    • +
    • In v2.14, the filter_saveFilters option was added (default set to false); this demo has it set to true to provide an example.
    • +
    • In v2.11, the filter functions provide an additional parameter $r providing a jQuery object of the current row being searched by the filter.
    • +
    • For v2.10.8, the Age column includes the new data-value set to <30 which sets the default (starting) filter value (see filter_defaultAttrib for more details).
    • +
    • As of tablesorter v2.9, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
    • +
    • Custom filter widget option filter_functions was added in version 2.3.6.
    • +
    • jQuery v1.4.3+ required.
    • +
    +
    + +

    Default Select ("First Name" column)

    +
    +
      +
    • To enable this type of select, set the filter_functions option for the column to true,
      filter_functions : {
      +
      +  // Add select menu to this column
      +  // set the column value to true, and/or add "filter-select" class name to header
      +  '.first-name' : true
      +
      +}
      or add a "filter-select" class to the column header cell (see code below).
    • +
    • The default option text, "Select a name", is obtained from the header data-placeholder attribute of the column header cell. And when active, it will show all table rows.
      <th class="filter-select" data-placeholder="Select a name">First Name</th>
    • +
    • Add a "filter-match" class to only match instead of exactly match the selected value. Click on the "Match" button below to see the difference.
      <th class="filter-select filter-match" data-placeholder="Select a name">First Name</th>
    • +
    • The select is populated by the column text contents with repeated content combined (i.e. There are three "Aaron"'s in the first column, but only one in the dropdown.
    • +
    • Select options are automatically alphanumerically (new in v2.4) sorted. Changed in v2.16.3: +
        +
      • The select contents are now parsed from the assigned parser, then sorted using the textSorter option
      • +
      • Add a class name of "filter-select-nosort" to prevent sorting the select options (v2.16.3).
      • +
      +
    • +
    • Please check out what the "filter-onlyAvail" class name does by reviewing the details below (in the "Discount" column) (v2.10.1).
    • +
    +
    + +

    Custom Filter Function ("Last Name" column)

    +
    +
      +
    • To enable this type of filter, add your custom function to the filter_functions option following this example:
      filter_functions : {
      +
      +  // Exact match only
      +  1 : function(e, n, f, i, $r, c, data) {
      +    return e === f;
      +  }
      +
      +}
    • +
    • The example shows you how to show only exact matches. The problem with this is that you can't see the matches while typing unless you set the filter_searchDelay option to be a bit longer.
    • +
    • Also, the example only checks for an exact match (===) meaning the filter_ignoreCase option is ignored, but other comparisons can be made using regex and the insensitive "i" flag.
    • +
    • *NOTE* If using an exact match function like this, consider setting the filter_searchFiltered option to false. If it were set to true, the filter widget wouldn't know to search through the entire contents of the column if the content were only slightly different. To see this problem, search for in the "Last Name" column, then add an "s" to the end to find "Evans". No results will show up, unless the search filtered option is false.
    • +
    • See the filter function information below for more details about the function parameters.
    • +
    +
    + +

    Custom Select ("City" or "Total" column)

    +
    +
      +
    • To enable this type of select, add your custom options within the filter_functions option.
    • +
    • Each option is set as a "key:value" pair where the "key" is the actual text of the option and the "value" is the function associated with the option.
    • +
    • Here is an example using alphabetical comparisons (using regular expressions):
      filter_functions : {
      +
      +  // Add these options to the select dropdown (regex example)
      +  2 : {
      +    "A - D" : function(e, n, f, i, $r, c, data) { return /^[A-D]/.test(e); },
      +    "E - H" : function(e, n, f, i, $r, c, data) { return /^[E-H]/.test(e); },
      +    "I - L" : function(e, n, f, i, $r, c, data) { return /^[I-L]/.test(e); },
      +    "M - P" : function(e, n, f, i, $r, c, data) { return /^[M-P]/.test(e); },
      +    "Q - T" : function(e, n, f, i, $r, c, data) { return /^[Q-T]/.test(e); },
      +    "U - X" : function(e, n, f, i, $r, c, data) { return /^[U-X]/.test(e); },
      +    "Y - Z" : function(e, n, f, i, $r, c, data) { return /^[Y-Z]/.test(e); }
      +  }
      +
      +}
    • +
    • Here is an example using numerical comparisons:
      filter_functions : {
      +  // Add these options to the select dropdown (numerical comparison example)
      +  // Note that only the normalized (n) value will contain numerical data
      +  // If you use the exact text, you'll need to parse it (parseFloat or parseInt)
      +  4 : {
      +    "< $10"      : function(e, n, f, i, $r, c, data) { return n < 10; },
      +    "$10 - $100" : function(e, n, f, i, $r, c, data) { return n >= 10 && n <=100; },
      +    "> $100"     : function(e, n, f, i, $r, c, data) { return n > 100; }
      +  }
      +}
    • +
    • See the "Filter function information" section below for more details about the function parameters.
    • +
    +
    + +

    Default Select with only available options ("Discount" column)

    +
    +
      +
    • This column uses the same method as the "First Name" column with one exception, it also includes the "filter-onlyAvail" class name in the header + cell:
      <th class="filter-select filter-onlyAvail">Discount</th>
    • +
    • To see how this works, do the following: +
        +
      • First, filter the "First Name" column by selecting the name "Clark"
      • +
      • Now use the "Discount" filter select box, you'll notice that only the values associated with the first name of Clark are showing as options.
      • +
      +
    • +
    • Conversely, if you reset the filters, select "44%" in the "Discount" column, then look at the "First Name" filter selector, you'll notice that it still contains all of the original options; because the "filter-onlyAvail" class name is not included in that column's header cell.
    • +
    • Sorry, this functionality only works for default select filters.
    • +
    • This funcitonality was added in v2.10.1.
    • +
    +
    + +

    Filter function information

    +
    +
      +
    • The custom function must return a boolean value. If true is returned, the row will be shown if all other filters match; and if false is returned, the row will be hidden. +
      function(e, n, f, i, $r, c, data) { return test; /* test should be a Boolean (true or false) */ }
      +
    • +
    • The exact text (e) of the table cell is a variable passed to the function. Note that numbers will need to be parsed to make comparisons.
    • +
    • Normalized table cell data (n) is the next varibale passed to the function. +
        +
      • This data has been parsed by the assigned column parser, so make sure the same type of data is being compared as parsed data may not be what you expect.
      • +
      • Normalized numerical values within the table will be of numeric type and not of string type, as the sorter needs to use mathematical comparisons while sorting.
      • +
      • The data will be in lower-case if the filter_ignoreCase option is true.
      • +
      • Dates like in the last column of the table below will store the time in seconds since 1970 (using javascript's .getTime() function).
      • +
      • The percentage column will only store the number and not percentage sign.
      • +
      +
    • +
    • The filter input value (f) is the exact text entered by the user. If numerical, it will need to be parsed using parseFloat() or parseInt() to allow for making comparisons.
    • +
    • The column index (i) might be useful for obtaining more information from header, or something.
    • +
    • The row ($r) is the current table row (jQuery object) being searched (or filtered). +
        +
      • This allows access to any extra information within. To access the current cell, just use $r.children().eq(i).
      • +
      • * NOTE * The row object provided is not attached to the table, so using something like .parent() or .closest() will not work!
      • +
      • For this reason, the next parameter (c) was added.
      • +
      +
    • +
    • The config (c) is the table.config (added v2.21.0).
    • +
    • The data parameter is the same data passed to the filter types (see all the data values here; added v2.22.0).
    • +
    +
    +
    + +

    Demo

    + false "filter-match" class name on the "First Name" column
    + filter_searchFiltered : true (if true, the search is performed on already filtered rows, with some exceptions)
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameCityAgeTotalDiscountDate
    AaronJohnson SrAtlanta35$5.9522%Jun 26, 2004 7:22 AM
    AaronJohnsonYuma12$2.995%Aug 21, 2009 12:21 PM
    ClarkHenry JrTampa51$42.2918%Oct 13, 2000 1:15 PM
    DenniHenryNew York28$9.9920%Jul 6, 2006 8:14 AM
    JohnHoodBoston33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent SrLos Angeles18$15.8944%Jan 12, 2003 11:14 AM
    PeterKent EsqSeattle45$153.1944%Jan 18, 2021 9:12 AM
    PeterJohnsMilwaukee13$5.294%Jan 8, 2012 5:11 PM
    AaronEvanChicago24$14.1914%Jan 14, 2004 11:23 AM
    BruceEvansUpland22$13.1911%Jan 18, 2007 9:12 AM
    ClarkMcMastersPheonix18$55.2015%Feb 12, 2010 7:23 PM
    DennisMastersIndianapolis65$123.0032%Jan 20, 2001 1:12 PM
    JohnHoodFort Worth25$22.0917%Jun 11, 2011 10:55 AM
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-widget-filter-external-inputs.html b/docs/example-widget-filter-external-inputs.html new file mode 100644 index 0000000..e9d85e4 --- /dev/null +++ b/docs/example-widget-filter-external-inputs.html @@ -0,0 +1,180 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Filter Widget External Inputs + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • As of v2.18.0, +
        +
      • An external input data-column can now target multiple columns: +
          +
        • When designating a column for an external input, you can now set multiple columns and/or a range of columns (e.g. data-column="0-2,4,6-7".
        • +
        • This type of search acts essentially the same as when the column is set to "all" in that "range", "notMatch" and "operators" searches are ignored.
        • +
        • The last search performed using either multiple columns or "all" columns will override all other queries; meaning the other inputs won't clear or update (e.g. performing a search for "foo" in an "all" column search input will override any previous searchs, and the input with a data-column="0-2,4,6-7" will not change its value) - this might be confusing to the user if multiple inputs are visible on the page (placeholder text won't help).
        • +
        • The selector in the demo below has two additional options: "Columns 0,3" and "Columns 1-2"; as you can see, switching the column to search between "all", "0,3" and "1-2" does not change the query.
        • +
        +
      • +
      +
    • +
    • As of v2.15, +
        +
      • A new filter widget filter_external option has been added that essentially does the same thing as the $.tablesorter.bindSearch function.
      • +
      • Use either to bind external search inputs.
      • +
      • To change an input from searching one column (or all columns) to search any other column, call the $.tablesorter.bindSearch function to update the external inputs, even if the inputs are set using the filter_external option. Pass an additional false flag as the last parameter to force the inputs to update. +
        $.tablesorter.bindSearch( $('table'), $('.search'), false );
        +
      • +
      • This demo shows how to use multiple external search filters to filter the table, and how to make one input dynamically change to filter any or all columns.
      • +
      +
    • +
    • The $.tablesorter.filter.bindSearch function allows binding multiple external search filters
    • +
    • The advantage of using this function over your own is: +
        +
      • Inputs behave the same as internal filters; searches adhere to the filter_liveSearch and filter_searchDelay options.
      • +
      • When pressing the Esc key, the filter resets.
      • +
      +
    • +
    • Include a data-column="#" attribute to specify to which column the search should apply; or data-column="all" to search all columns.
    • +
    +
    +
    + +

    Demo

    + +
    + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankFirst NameLast NameAgeTotalDiscountDate
    1Philip AaronJohnson Sr Esq25$5.9522%Jun 26, 2004 7:22 AM
    11AaronHibert12$2.995%Aug 21, 2009 12:21 PM
    12Brandon ClarkHenry Jr51$42.2918%Oct 13, 2000 1:15 PM
    111PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    21JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    013ClarkKent Sr.18$15.8944%Jan 12, 2003 11:14 AM
    005BruceAlmighty Esq45$153.1944%Jan 18, 2021 9:12 AM
    10AlexDumass13$5.294%Jan 8, 2012 5:11 PM
    16JimFranco24$14.1914%Jan 14, 2004 11:23 AM
    166Bruce LeeEvans22$13.1911%Jan 18, 2007 9:12 AM
    100Brenda LeeMcMasters18$55.2015%Feb 12, 2010 7:23 PM
    55DennisBronson65$123.0032%Jan 20, 2001 1:12 PM
    9MarthadelFuego25$22.0917%Jun 11, 2011 10:55 AM
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-widget-filter-formatter-1.html b/docs/example-widget-filter-formatter-1.html new file mode 100644 index 0000000..59a3461 --- /dev/null +++ b/docs/example-widget-filter-formatter-1.html @@ -0,0 +1,638 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Custom Filter Widget Formatter (jQuery UI widgets) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • Oct 27, 2014 - added a demo to the home wiki page showing how to apply jQuery's selectmenu widget to a filter cell without using the filter formatter functions.
    • +
    • As of v2.17.5, if writing a custom filterFormatter function, you'll need to call an additional function after initialization has completed so the "filterInit" event isn't triggered prematurely. See the "Custom Filter Formatter Function Information" section below for more details.
    • +
    • In v2.17.0, the filter_formatter column can also be referenced by using a jQuery selector (e.g. class name or ID).
    • +
    • In v2.16.0, the filter_placeholder option was added. See the jQuery UI Datepicker Range Selector section for more details.
    • +
    • In v2.15.0, the following changes were made: +
        +
      • These updated filter widget functions are not completely backward compatible with older versions of the filter widget. Please update both!
      • +
      • Added compare & selected options: +
          +
        • These options allow the adding of a comparison operator selector to the cell (e.g. >, >=, <, <=, etc).
        • +
        • If any cellText is included, it is now wrapped in a label with a class name of "compare-select-label" and "compare-select-label#" (where "#" is the column index).
        • +
        • The selector has a class name of "compare-select" and "compare-select#" (where "#" is the column index)
        • +
        • Whichever type of input that is added to the cell is then wrapped in a div with class "compare-select-wrapper" and "compare-select-wrapper#" (where "#" is the column index).
        • +
        • These class names allow styling of an individual filter to keep elements in line, or however you wish to style it. +
          <!-- rendered filter cell (first column) -->
          +<td>
          +	<!-- cellText -->
          +	<label class="compare-select-label compare-select-label0">Rank:</label>
          +	<!-- compare: [ '=', '>=', '<=' ] -->
          +	<select class="compare-select compare-select0">
          +		<option>=</option>
          +		<option>&gt;=</option>
          +		<option selected>&lt;=</option>
          +	</select>
          +	<!-- wrapped selector element -->
          +	<div class="compare-select-wrapper compare-select-wrapper0">
          +		<div class="slider slider0><!-- jQuery UI Slider gets added here --></div>
          +	</div>
          +	<!-- hidden input -->
          +	<input class="filter tablesorter-filter" type="hidden" value="" data-column="0">
          +</td>
          +
        • +
        +
      • +
      • Filter reset now sets these filters to their default values, not an empty string.
      • +
      • Updated to now properly restore saved filters.
      • +
      • Added endOfDay option for jQuery UI Datepicker. +
          +
        • When true search dates will include all times from the date chosen when a comparison is made of dates "less than" the set date.
        • +
        • Example 1: if a table entry has a date of "Jan 14, 2014 11:23 AM" and the filter search is set to , the table entry will be included in the search; the default set time would otherwise be "1/14/2014 00:00:00" and not include the entry from "11:23 AM". So, the endOfDay option sets the time to "23:59:59".
        • +
        • Example 2: if searching for one specific date, this option will now search for all times within that day. For example, searching for , and the results will include dates from 1/20/2014 00:00:00 to 1/20/2014 23:59:59.
        • +
        • When comparing dates greater than the set date, the time will be set to midnight; so this option will not be applied.
        • +
        • Example 3: in two date inputs, the endOfDay time is only applied to the "to" input; search for
        • +
        • This option is available in both the comparison (one input) and range (two inputs; "to" date input only) date pickers.
        • +
        +
      • +
      +
    • +
    • As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
    • +
    • This page shows you how to add a few jQuery UI widgets to interact with the filter widget using the filter_formatter option.
    • +
    • Custom filter widget option filter_formatter was added in version 2.7.7.
    • +
    • jQuery v1.4.3+ required.
    • +
    +
    + +

    jQuery UI Single Slider ("Rank" and "Age" columns)

    +
    +
      +
    • In v2.15.0 the compare option was updated to allow adding a selector along with the input. The selected option allows choosing the default setting.
    • +
    • In v2.10.1 the compare option was added. This allows comparing the slider's value to the column value. The slider in the Age column is selecting values greater than or equal to itself.
    • +
    • A search delay was added in v2.7.11 (time set by filter_searchDelay option). It can be disabled by setting the delayed option to false.

    • +
    • This example shows how you can add a jQuery UI slider to filter column content.
    • +
    • The filter_formatter function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.
    • +
    • Make sure to include all values within the selected range, otherwise rows outside of this range will be forever hidden.
    • +
    • Add the following code to apply a slider to filter a column:
      $(function() {
      +
      +  $("table").tablesorter({
      +    theme: 'jui',
      +    // hidden filter input/selects will resize the columns, so try to minimize the change
      +    widthFixed : true,
      +    // initialize zebra striping and filter widgets
      +    widgets: ["zebra", "filter", "uitheme"],
      +    widgetOptions : {
      +      // jQuery selector string of an element used to reset the filters
      +      filter_reset : 'button.reset',
      +      // add custom selector elements to the filter row
      +      filter_formatter : {
      +
      +        // Rank (jQuery selector added v2.17.0)
      +        'th:contains("Rank")' : function($cell, indx){
      +          return $.tablesorter.filterFormatter.uiSlider( $cell, indx, {
      +            // filterFormatter options
      +            cellText : 'Rank:',
      +            delayed: true,        // delay search (set by filter_searchDelay)
      +            valueToHeader: false, // add current slider value to the header cell
      +            exactMatch: true,     // exact (true) or match (false)
      +            allText: 'all',       // text shown when the slider is at the minimum value
      +            compare : [ '=', '>=', '<=' ], // any comparison would override the exactMatch option
      +            selected : 2,         // zero-based index of compare starting selected value
      +
      +            // add any of the jQuery UI Slider options here (http://api.jqueryui.com/slider/)
      +            value: 100,           // starting value
      +            min: 0,               // minimum value
      +            max: 100              // maximum value
      +          });
      +        },
      +
      +        // Age
      +        1 : function($cell, indx){
      +          return $.tablesorter.filterFormatter.uiSlider( $cell, indx, {
      +            delayed: false,       // delay search (set by filter_searchDelay)
      +            valueToHeader: false, // add current slider value to the header cell
      +            exactMatch: false,    // exact (true) or match (false)
      +            allText: 'all',       // text shown when slider is at the minimum value; ignored when compare has a value
      +            compare: [ '=', '>=', '<=' ], // search values greater/less than selected value; overrides exactMatch
      +            selected : 1,         // zero-based index of compare starting selected value
      +
      +            // add any of the jQuery UI Slider options here (http://api.jqueryui.com/slider/)
      +            value: 1,             // starting value
      +            min: 1,               // minimum value
      +            max: 65               // maximum value
      +          });
      +        }
      +
      +      }
      +    }
      +  });
      +
      +});
    • +
    • The tooltip above the slider is added using pure css, which is included in the "filter.formatter.css" file, but it won't work in IE7 and older. But, you set the valueToHeader option to true to add the slider value to the header cell above the filter.
    • +
    • Another option named exactMatch was added to allow exact or general matching of column content.
    • +
    • Notice that the left-most value, zero in this case, will clear the column filter to allow a method to show all column content. You can modify the "all" text using the allText option.
    • +
    +
    + +

    jQuery UI Range Slider ("Total" column)

    +
    +
      +
    • This example shows how you can add a jQuery UI range slider to filter column content.
    • +
    • The filter_formatter function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.
    • +
    • Make sure to include all values within the selected range, otherwise rows outside of this range will be forever hidden.
    • +
    • The range slider is actually the same as the single slider described above, but was built to handle a range of values.
    • +
    • Add the following code to apply a range slider to filter a column:
      $(function() {
      +
      +  $("table").tablesorter({
      +    theme: 'jui',
      +    // hidden filter input/selects will resize the columns, so try to minimize the change
      +    widthFixed : true,
      +    // initialize zebra striping and filter widgets
      +    widgets: ["zebra", "filter", "uitheme"],
      +    widgetOptions : {
      +      // jQuery selector string of an element used to reset the filters
      +      filter_reset : 'button.reset',
      +      // add custom selector elements to the filter row
      +      filter_formatter : {
      +
      +        // Total column (jQuery selector added v2.17.0)
      +        '.total' : function($cell, indx){
      +          return $.tablesorter.filterFormatter.uiRange( $cell, indx, {
      +            delayed: true,        // delay search (set by filter_searchDelay)
      +            valueToHeader: false, // add current slider value to the header cell
      +
      +            // add any of the jQuery UI Slider options (for range selection) here (http://api.jqueryui.com/slider/)
      +            values: [1, 160],     // starting range
      +            min: 1,               // minimum value
      +            max: 160              // maximum value
      +          });
      +        }
      +
      +      }
      +    }
      +  });
      +
      +});
    • +
    • The tooltip above the slider is added using pure css, which is included in the "filter.formatter.css" file, but it won't work in IE7 and older. But, you set the valueToHeader option to true to add the slider value to the header cell above the filter.
    • +
    • Another option named exactMatch was added to allow exact or general matching of column content.
    • +
    • A search delay was added in v2.7.11 (time set by filter_searchDelay option). It can be disabled by setting the delayed option to false.
    • +
    +
    + +

    jQuery UI Spinner ("Discount" column)

    +
    +
      +
    • In v2.15.0 the compare option was updated to allow adding a selector along with the input. The selected option allows choosing the default setting.

    • +
    • This example shows how you can add a jQuery UI spinner to filter column content.
    • +
    • The filter_formatter function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.
    • +
    • Add the following code to apply a spinner to filter a column:
      $(function() {
      +
      +  $("table").tablesorter({
      +    theme: 'jui',
      +    // hidden filter input/selects will resize the columns, so try to minimize the change
      +    widthFixed : true,
      +    // initialize zebra striping and filter widgets
      +    widgets: ["zebra", "filter", "uitheme"],
      +    widgetOptions : {
      +      // jQuery selector string of an element used to reset the filters
      +      filter_reset : 'button.reset',
      +      // add custom selector elements to the filter row
      +      filter_formatter : {
      +
      +        // Discount column
      +        3 : function($cell, indx){
      +          return $.tablesorter.filterFormatter.uiSpinner( $cell, indx, {
      +            delayed: true,    // delay search (set by filter_searchDelay)
      +            addToggle: false, // add a toggle switch to activate/deactive the search
      +            exactMatch: true, // exact (true) or match (false)
      +            compare : [ '', '=', '>=', '<=' ], // search values greater/less than selected value; overrides exactMatch
      +            selected : 2,     // zero-based index of compare starting selected value
      +
      +            // add any of the jQuery UI Spinner options here (http://api.jqueryui.com/spinner/)
      +            min : 0,
      +            max : 45,
      +            value: 1,
      +            step: 1
      +          });
      +        }
      +      }
      +    }
      +  });
      +
      +});
    • +
    • This is the only jQuery UI widget that includes a toggle button. The toggle button is added by default, but if you don't want it, set the addToggle option to false. Without the toggle button, the filter is always active.
    • +
    • Another option named exactMatch was added to allow exact or general matching of column content.
    • +
    • A search delay was added in v2.7.11 (time set by filter_searchDelay option). It can be disabled by setting the delayed option to false.
    • +
    +
    + +

    jQuery UI Datepicker Comparison ("Date (one input)" column)

    +
    +
      +
    • In v2.15.0 +
        +
      • The compare option was updated to allow adding a selector along with the input. The selected option allows choosing the default setting.
      • +
      • A endOfDay option was added, which when a <= comparison is made, will include all times within the selected day. Try searching for ; it basically sets the time of the selected day to end at 23:59:59.
      • +
      • Additionally, when endOfDay option is true and using an exact (=) comparison, all times within that selected day will be included - try searching for to note that the day include various times.
      • +
      +
      +
    • +
    • This example shows how you can add a jQuery UI Datepicker to compare to filter column content.
    • +
    • The filter_formatter function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.
    • +
    • This code follows the default functionality example from the jQuery UI docs.
    • +
    • Add the following code to apply a datepicker comparison selector to the filter row:
      $(function() {
      +
      +  $("table").tablesorter({
      +    theme: 'jui',
      +    // hidden filter input/selects will resize the columns, so try to minimize the change
      +    widthFixed : true,
      +    // initialize zebra striping and filter widgets
      +    widgets: ["zebra", "filter", "uitheme"],
      +    widgetOptions : {
      +      // jQuery selector string of an element used to reset the filters
      +      filter_reset : 'button.reset',
      +      // add custom selector elements to the filter row
      +      filter_formatter : {
      +
      +        // Date (one input)
      +        4 : function($cell, indx){
      +          return $.tablesorter.filterFormatter.uiDateCompare( $cell, indx, {
      +            cellText : 'Dates', // text added before the input
      +            compare : [ '', '=', '>=', '<=' ], // search values greater/less than selected value; overrides exactMatch
      +            selected : 3,       // zero-based index of compare starting selected value
      +
      +            // add any of the jQuery UI Datepicker options here (http://api.jqueryui.com/datepicker/)
      +            // defaultDate : '1/1/2014', // default date
      +            changeMonth : true,
      +            changeYear : true
      +          });
      +        }
      +      }
      +    }
      +  });
      +
      +});
    • +
    • There is one issue with this comparison script, and that is with dates that contain a time: +
        +
      • Table data that contains dates with times will be parsed into values that include time.
      • +
      • So if the compare option is set to =, it may not show any filtered table rows as none match that date at midnight. To fix this, either remove times from the table data, use a column parser that ignores the time, or use the Datepicker range selector and set the "from" input to the desired day and the "to" input to be the next day (at midnight).
      • +
      • Using a compare of <= will only show filtered dates from the selected day at midnight with earlier dates; i.e. a cell with the selected date but a time set to noon will not be visible. As of v2.10/8, the comparison of dates less than the selected date, now adds a time of 11:59:59 so it will include times within the selected date.
      • +
      +
    • +
    +
    + +

    jQuery UI Datepicker Range Selector ("Date (two inputs)" column)

    +
    +
      +
    • In v2.16.0, a filter_placeholder option was added: +
        +
      • The option adds a search input placeholder and select (first option) text, but it also includes placeholder text for both the "from" and "to" inputs
      • +
      • Set it as follows: +
        filter_placeholder : {
        +	search : '', // any default search inputs including the datepicker comparison
        +	from   : 'Date from...', // datepicker range "from" placeholder
        +	to     : 'Date to...'  // datepicker range "to" placeholder
        +}
        +
      • +
      • Note The browser must support the placeholder attribute before this text will be visible.
      • +
      +
    • +
    • In v2.15.0, an endOfDay option was added, which when true and searching within one day, all times within that selected day will be included - try searching for to note that the day include various times.
    • +
    • This example shows how you can add a jQuery UI Datepicker range to filter column content.
    • +
    • The filter_formatter function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.
    • +
    • This code follows the date range example from the jQuery UI docs.
    • +
    • Updated two input functions so that if the "to" input is empty, all dates greater than the "from" date are shown. If the "from" input is empty, all dates less than the "to" input date are shown (v2.10.1).
    • +
    • Add the following code to apply a datepicker range selector to the filter row:
      $(function() {
      +
      +  $("table").tablesorter({
      +    theme: 'jui',
      +    // hidden filter input/selects will resize the columns, so try to minimize the change
      +    widthFixed : true,
      +    // initialize zebra striping and filter widgets
      +    widgets: ["zebra", "filter", "uitheme"],
      +    widgetOptions : {
      +      // jQuery selector string of an element used to reset the filters
      +      filter_reset : 'button.reset',
      +      // add custom selector elements to the filter row
      +      filter_formatter : {
      +
      +        // Date (two inputs)
      +        5 : function($cell, indx){
      +          return $.tablesorter.filterFormatter.uiDatepicker( $cell, indx, {
      +            // add any of the jQuery UI Datepicker options here (http://api.jqueryui.com/datepicker/)
      +            // from : '8/1/2013', // starting date
      +            // to   : '1/18/2014',  // ending date
      +            textFrom: 'from',   // "from" label text
      +            textTo: 'to',       // "to" label text
      +            changeMonth: true,
      +            changeYear : true
      +          });
      +        }
      +      }
      +    }
      +  });
      +
      +});
    • +
    • Note that the datepicker options are slightly different from the default datepicker options: +
        +
      • Instead of using the defaultDate option of the datepicker widget, it has a from and to option to fullfill that purpose.
      • +
      • The options added to this function will be applied to both the from and to datepicker inputs.
      • +
      • As of v2.10.8, the comparison of dates less than the selected "to" date, now adds a time of 11:59:59 so it will include times within the selected dates.
      • +
      +
    • +
    +
    + +

    Custom Filter Formatter Function Information

    +
    + If you want to write your own custom filter formatter function, there are certain requirements that should be met: +
      +
    • Required input element: +
        +
      • If your selector isn't an input (e.g. jQuery UI Slider), then you'll need to return an input of type hidden which gets updated by the selector with the filter query for the column. +
        filter_formatter : {
        +  0 : function($cell, indx) {
        +    var $input = $('<input type="hidden">').appendTo($cell);
        +    // add your selector code here
        +    return $input;
        +  }
        +}
      • +
      • If the input contains a value that doesn't match a standard filter syntax, then you'll need to return an input of type hidden with the correct format.
      • +
      • This returned input element should to be attached to the $cell.
      • +
      • The returned input should have a "search" event triggered upon it after being updated.
      • +
      +
    • +
    • Some method should be added to show the user the current value of the selector - update a data attribute for css3 tooltips, or update the header cell.
    • +
    • A reset function needs to also be included; bind to the filterReset event and clear out or disable your custom selector when triggered. +
      $cell.closest('table').bind('filterReset', function(){ /* update the input here */ });
      +
    • +
    • In v2.15.0, in order to update your custom input with any saved filter searches, you will need to bind to the filterFomatterUpdate event to get the saved filter value from the hidden input and apply it to your custom input. +
      $cell.closest('table').bind('filterFomatterUpdate', function(){
      +	var savedSearch = $cell.find('input[type=hidden]').val();
      +	// apply this saved search to your custom input
      +	$.tablesorter.filter.formatterUpdated($cell, indx); // new v2.17.5
      +});
      As of v2.17.5, you need to call $.tablesorter.filter.formatterUpdated($cell, indx); so the filter widget knows when all inputs have completed initialization, and fire the "filterInit" event.

    • +
    • If your selector needs a parsed value to work with, add the filter-parsed class name to the header cell above the filter, use this code to do that: +
      $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
      +
    • +
    • Since, by default, the filter only matches cell content, a 1 in the filter will show all rows with a one no matter where it is located. So, if you need an exact match, add an equal sign to the end of the value (1=). This forces the filter to exactly match the value in the search input.
    • +
    • To include a search delay, trigger the search on the hidden input and pass a boolean. If true or undefined, the search will be delayed and not delayed if false; modify the delay time set by changing the filter_searchDelay option. +
      $input.val( newVal ).trigger('search', false); // no search delay
      +
    • + +
    +
    + +
    + +

    Demo

    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankAgeTotal (range)DiscountDate (one input)Date (two inputs; range)
    125$5.9522%Jun 26, 2013 7:22 AMJun 26, 2013 7:22 AM
    1112$82.995%Aug 21, 2013 12:21 PMAug 21, 2013 12:21 PM
    1251$99.2918%Oct 13, 2013 1:15 PMOct 13, 2013 1:15 PM
    5128$9.9920%Jul 6, 2013 8:14 AMJul 6, 2013 8:14 AM
    2133$19.9925%Dec 10, 2012 5:14 AMDec 10, 2012 5:14 AM
    01318$65.8945%Jan 12, 2013 11:14 AMJan 12, 2013 11:14 AM
    00545$153.1945%Jan 18, 2014 9:12 AMJan 18, 2014 9:12 AM
    103$5.294%Jan 8, 2013 5:11 PMJan 8, 2013 5:11 PM
    1624$14.1914%Jan 14, 2014 11:23 AMJan 14, 2014 11:23 AM
    6622$13.1911%Jan 18, 2013 9:12 AMJan 18, 2013 9:12 AM
    10018$55.2015%Feb 12, 2013 7:23 PMFeb 12, 2013 7:23 PM
    5565$123.0032%Jan 20, 2014 1:12 PMJan 20, 2014 1:12 PM
    925$22.0917%Jun 11, 2013 10:55 AMJun 11, 2013 10:55 AM
    1312$19.9918%Jan 20, 2014 7:45 PMJan 20, 2014 7:45 PM
    7358$129.1939%Jan 20, 2014 10:11 AMJan 20, 2014 10:11 AM
    + +

    Page Header

    +
    +
    <!-- jQuery UI for range slider -->
    +<link rel="stylesheet" href="css/jquery-ui.min.css">
    +<script src="js/jquery-ui.min.js"></script>
    +
    +<!-- tablesorter plugin -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<script src="../js/jquery.tablesorter.js"></script>
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +
    +<!-- filter formatter code -->
    +<link rel="stylesheet" href="../css/filter.formatter.css">
    +<script src="../js/widgets/widget-filter-formatter-jui.js"></script>
    +
    + +

    CSS

    +
    +
    
    +	
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-widget-filter-formatter-2.html b/docs/example-widget-filter-formatter-2.html new file mode 100644 index 0000000..3310388 --- /dev/null +++ b/docs/example-widget-filter-formatter-2.html @@ -0,0 +1,352 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Custom Filter Widget Formatter (HTML5 Elements) + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • In v2.17.0, the filter_formatter column can also be referenced by using a jQuery selector (e.g. class name or ID).
    • +
    • As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
    • +
    • At this time, these widgets do not work with the sticky header widget.
    • +
    • This page shows you how to add a few default HTML5 elements to interact with the filter widget.
    • +
    • If the HTML5 elements are not supported by your browser, you'll just see an input.
    • +
    • Custom filter widget option filter_formatter was added in version 2.7.7.
    • +
    • jQuery v1.4.3+ required.
    • +
    +
    + +

    HTML Range ("Rank" and "Total" columns)

    +
    +
      +
    • In v2.15.0 the compare option was updated to allow adding a selector along with the input. The selected option allows choosing the default setting.
    • +
    • This example shows how you can add an HTML5 range input slider to filter column content.
    • +
    • The filter_formatter function provided in the extra "widget-filter-formatter-html5.js" file is used to add this custom control within the filter row.
    • +
    • Make sure to include all values within the selected range, otherwise rows outside of this range will be forever hidden.
    • +
    • Add the following code to apply an HTML5 range slider to the filter row:
      $(function() {
      +
      +  $("table").tablesorter({
      +    theme: 'blue',
      +    // initialize zebra striping and filter widgets
      +    widgets: ["zebra", "filter"],
      +    widgetOptions : {
      +      // jQuery selector string of an element used to reset the filters
      +      filter_reset : 'button.reset',
      +      // add custom selector elements to the filter row
      +      filter_formatter : {
      +
      +        // Rank
      +        0 : function($cell, indx){
      +          return $.tablesorter.filterFormatter.html5Range( $cell, indx, {
      +            value: 0,
      +            min: 0,
      +            max: 100,
      +            delayed: true,
      +            valueToHeader: true,
      +            compare : [ '=', '>=', '<=' ],
      +            selected: 1
      +          });
      +        },
      +
      +        // Total
      +        4 : function($cell, indx){
      +          return $.tablesorter.filterFormatter.html5Range( $cell, indx, {
      +            value: 0,
      +            min: 0,
      +            max: 150,
      +            delayed: true,
      +            valueToHeader: true,
      +            compare : '>='
      +          });
      +        }
      +
      +      }
      +    }
      +  });
      +
      +});
    • +
    • By default, this code has the valueToHeader option set to true to add the slider value to the header cell above the filter.
    • +
    • The tooltip above the slider is NOT added in this example because the slider handle is not a separate element. But if you are interested, you can use this code by Chris Coyier to animate a range slider bubble.
    • +
    • Another option named exactMatch was added to allow exact or general matching of column content.
    • +
    • Notice that the left-most value, zero in this case, will clear the column filter to allow a method to show all column content. You can modify the "all" text using the allText option.
    • +
    • A search delay option was added in v2.7.11 (time set by filter_searchDelay option). It can be disabled by setting the delayed option to false.
    • +
    +
    + +

    HTML5 color input ("Color" column)

    +
    +
      +
    • This example shows how you can add an HTML5 color input to filter column content.
    • +
    • The filter_formatter function is used to add a custom control within the filter row, but a hidden input is still required to store the filter value.
    • +
    • Add the following code to apply a color input to the filter row:
      $(function() {
      +
      +  $("table").tablesorter({
      +    theme: 'blue',
      +    // hidden filter input/selects will resize the columns, so try to minimize the change
      +    widthFixed : true,
      +    // initialize zebra striping and filter widgets
      +    widgets: ["zebra", "filter"],
      +    widgetOptions : {
      +      // jQuery selector string of an element used to reset the filters
      +      filter_reset : 'button.reset',
      +      // add custom selector elements to the filter row
      +      filter_formatter : {
      +
      +        // Color
      +        1 : function($cell, indx){
      +          return $.tablesorter.filterFormatter.html5Color( $cell, indx, {
      +            value: '#000000',
      +            addToggle: true,
      +            exactMatch: true,
      +            valueToHeader: false
      +          });
      +        }
      +
      +      }
      +    }
      +  });
      +
      +});
    • +
    • This color selector will only output the color as a hex value with a hash followed by six characters (#000000).
    • +
    • By default, this code has the valueToHeader option set to false. The currently selected color is added to a span within the cell by default.
    • +
    • Another option named exactMatch was added to allow exact or general matching of column content, in case you have multiple colors in one cell.
    • +
    • This selector includes a toggle button. The toggle button is added by default, but if you don't want it, set the addToggle option to false. Without the toggle button, the filter is always active.
    • +
    +
    + +

    HTML5 Number Selector ("Age" and "Discount" columns)

    +
    +
      +
    • In v2.15.0 the compare option was updated to allow adding a selector along with the input. The selected option allows choosing the default setting.
    • +
    • This example shows how you can add an HTML5 number spinner to the filter column content.
    • +
    • The filter_formatter function provided in the extra "widget-filter-formatter-html5.js" file is used to add this custom control within the filter row.
    • +
    • Add the following code to apply an HTML spinner to filter a column:
      $(function() {
      +
      +  $("table").tablesorter({
      +    theme: 'blue',
      +    // hidden filter input/selects will resize the columns, so try to minimize the change
      +    widthFixed : true,
      +    // initialize zebra striping and filter widgets
      +    widgets: ["zebra", "filter"],
      +    widgetOptions : {
      +      // jQuery selector string of an element used to reset the filters
      +      filter_reset : 'button.reset',
      +      // add custom selector elements to the filter row
      +      filter_formatter : {
      +
      +        // Age
      +        3: function($cell, indx){
      +          return $.tablesorter.filterFormatter.html5Number( $cell, indx, {
      +            value: 1,
      +            min: 1,
      +            max: 65,
      +            delayed: true,
      +            addToggle: true,
      +            exactMatch: true,
      +            compare: ''
      +          });
      +        },
      +
      +        // Discount
      +        5: function($cell, indx){
      +          return $.tablesorter.filterFormatter.html5Number( $cell, indx, {
      +            value: 1,
      +            min: 1,
      +            max: 44,
      +            delayed: true,
      +            addToggle: false,
      +            compare: [ '<=', '=', '>=' ],
      +            selected: 2
      +          });
      +        }
      +
      +      }
      +    }
      +  });
      +
      +});
    • +
    • This is spinner includes a toggle button. The toggle button is added by default, but if you don't want it, set the addToggle option to false. Without the toggle button, the filter is always active.
    • +
    • Another option named exactMatch was added to allow exact or general matching of column content.
    • +
    • A search delay option was added in v2.7.11 (time set by filter_searchDelay option). It can be disabled by setting the delayed option to false.
    • +
    +
    + +
    + +

    Demo

    + +
    + + + + + + + + + + + + + + + + + + +
    RankColorNameAgeTotalDiscountDate
    1#ff0000Johnson25$5.9522%Jun 26, 2013 7:22 AM
    11#00ff00Hibert12$2.995%Aug 21, 2013 12:21 PM
    12#0000ffHenry51$42.2918%Oct 13, 2013 1:15 PM
    51#00ff00Parker28$9.9920%Jul 6, 2013 8:14 AM
    21#ffffffHood33$19.9925%Dec 10, 2012 5:14 AM
    013#ff0000Kent18$15.8944%Jan 12, 2013 11:14 AM
    005#00ff00Bruce45$153.1944%Jan 18, 2014 9:12 AM
    10#000000Alex3$5.294%Jan 8, 2013 5:11 PM
    16#ff0000Franco24$14.1914%Jan 14, 2014 11:23 AM
    66#000000Evans22$13.1911%Jan 18, 2013 9:12 AM
    100#ffffffBrenda18$55.2015%Feb 12, 2013 7:23 PM
    55#000000Bronson65$123.0032%Jan 20, 2014 1:12 PM
    9#000000Martha25$22.0917%Jun 11, 2013 10:55 AM
    + +

    Page Header

    +
    +
    <!-- jQuery UI for range slider -->
    +<link rel="stylesheet" href="css/jquery-ui.min.css">
    +<script src="js/jquery-ui.min.js"></script>
    +
    +<!-- tablesorter plugin -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<script src="../js/jquery.tablesorter.js"></script>
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +
    +<!-- filter formatter code -->
    +<link rel="stylesheet" href="../css/filter.formatter.css">
    +<script src="../js/widgets/widget-filter-formatter-html5.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-widget-filter-formatter-select2.html b/docs/example-widget-filter-formatter-select2.html new file mode 100644 index 0000000..ef97752 --- /dev/null +++ b/docs/example-widget-filter-formatter-select2.html @@ -0,0 +1,231 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Filter Formatter: select2 (beta) + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • Updated in v2.19.0 to properly escape regexp characters. See issue #796 for details.
    • +
    • Updated in v2.16.3 to allow adding an initial value to the select2 plugin.
    • +
    • This is a demo of the select2 filter formatter code.
    • +
    • It requires jQuery 1.7.2+, tablesorter 2.16+, the filter widget 2.16+ and Select2 v3.4.6+ (not tested on older select2 versions)
    • +
    • This demo uses the new filter_selectSource option which is only available in tablesorter v2.16+
    • +
    +
    + +

    Options

    +
    + There are only two filter formatter options, the rest are all select2 plugin options (defaults shown below): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    Select2 FilterFormatter options
    cellText''Text added within a <label> before the input.
    matchtrueAdds a "filter-match" class name to the header & modifies the search
    value[ ]Set the initial select2 values within this array. These values are restored when the filters are reset.
    Select2 plugin (modified defaults)
    multipletrueAllow multiple selections. This option can be modified.
    width'100%'Reduce this width if you add anything cellText, or the text and the input will be on separate lines.
    + + This is an example of how to set these options: +
    filter_formatter : {
    +  // default settings on first column
    +  0 : function($cell, indx){
    +    return $.tablesorter.filterFormatter.select2( $cell, indx, {
    +      // *** select2 filter formatter options ***
    +      cellText : '',    // Text (wrapped in a label element)
    +      match    : true,  // adds "filter-match" to header & modifies search
    +      value    : [],    // initial select2 values
    +
    +      // *** ANY select2 options can be included below ***
    +      // (showing default settings for this formatter code)
    +      multiple : true,  // allow multiple selections
    +      width    : '100%' // reduce this width if you add cellText
    +    });
    +  }
    +}
    +
    +
    + +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    AlphaNumeric (match)AlphaNumeric (exact; only available)NumericAnimalsSites
    abc 123abc 12310Koalahttp://www.google.com
    abc 1abc 134Oxhttp://www.yahoo.com
    abc 9abc 910Girafeehttp://www.facebook.com
    zyx 24zyx 2467Bisonhttp://www.whitehouse.gov/
    abc 11abc 113Chimphttp://www.ucla.edu/
    def 2def 256Elephanthttp://www.wikipedia.org/
    abc 9abc 975Lionhttp://www.nytimes.com/
    def 10def 1087Zebrahttp://www.google.com
    zyx 1zyx 199Koalahttp://www.mit.edu/
    zyx 12zyx 120Llamahttp://www.nasa.gov/
    + +

    Header

    +
    +
    <!-- jQuery -->
    +<script src="js/jquery-latest.min.js"></script>
    +
    +<!-- Tablesorter: required -->
    +<link href="../css/theme.blue.css" rel="stylesheet">
    +<script src="../js/jquery.tablesorter.js"></script>
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +
    +<!-- Select2 code -->
    +<link href="http://cdnjs.cloudflare.com/ajax/libs/select2/3.4.6/select2.min.css" rel="stylesheet">
    +<script src="http://cdnjs.cloudflare.com/ajax/libs/select2/3.4.6/select2.min.js"></script>
    +<script src="../js/widgets/widget-filter-formatter-select2.js"></script>
    +
    + +

    HTML

    +
    +
    
    +	
    + +

    Javascript

    +
    +
    
    +	
    + +
    + + + diff --git a/docs/example-widget-filter.html b/docs/example-widget-filter.html new file mode 100644 index 0000000..c6485e9 --- /dev/null +++ b/docs/example-widget-filter.html @@ -0,0 +1,842 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Filter Widget + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • In v2.22.0 +
        +
      • Regex filter searches now cache the created regex object for each query to optimize speed & a regex search now properly uses case-sensitive content.
      • +
      • Add data parameter to filter_functions (get more details).
      • +
      • Any match searches which target specific columns will no longer save each filter to its respective column; see "AnyMatch Searches" documentation.
      • +
      • Operator filter searchs now ignore empty strings (because "" < 10 is true).
      • +
      • Added filter_childByColumn option which allows the filtering columns in both the parent & child rows. Demo added to the filtered child rows demo
      • +
      +
    • +
    • In v2.18.0, added filter_cellFilter & the ability to set multiple "any" match columns for an external search (see the external inputs demo for more details).
    • +
    + +
    +

    Older Notes

    +
    +
      +
    • In v2.17.8, filter selects will default to exact matches unless the header cell has a "filter-match" class added.
    • +
    • In v2.17.1, added a not exact match (!=) filter type.
    • +
    • In v2.16+, +
        +
      • When a default filter select is added to a column, it is now parsed from the assigned parser, then sorted using the textSorter setting, and falls back to an alphanumeric sort (v2.16.3).
      • +
      • Adding a class of "filter-select-nosort" will now leave the select options unsorted (v2.16.3).
      • +
      • Added filter_placeholder option (v2.16.0).
      • +
      • Added filter_selectSource option (v2.16.3).
      • +
      • updated filter_reset option (v2.16.3).
      • +
      +
    • +
    • In v2.15, +
        +
      • The filter_anyMatch widget option was completely removed. Sorry for not deprecating this option, but the filter any match code was completely rewritten.
      • +
      • Added a filter_external widget option to only accept a jQuery selector string/object; please see the updated filter any match demo for more details.
      • +
      +
    • +
    • Added & set filter_saveFilters to true (default is false) in this demo (v2.14).
    • +
    +
    +
    + +
      +
    • *NOTE* If using a custom theme, make sure to add the class set in the filter_filteredRow option (set to filtered by default) in the css, and set it to display:none. When filtering rows, the filter widget adds the "filtered" class to hide the row; all available themes include this definition.
    • +
    • Hover over the grey bar below the table header to open the filter row. Disable this by setting filter_hideFilters option to false.
    • +
    • This widget uses jQuery's .nextUntil() function which is only available is jQuery version 1.4+.
    • +
    • This widget does NOT work with tablesorter v2.0.5.
    • +
    • Using the built-in filters (learn how to customize them here - demo created v2.17.5): + + + + + + + + + + + + + + + + + + + + + +
      Type (1)(2)DescriptionExamples
      textAny text entered in the filter will match text found within the columnabc (finds "abc", "abcd", "abcde", etc); (finds "Aaron" and "Philip Aaron Wong")
      /\d/Add any regex to the query to use in the query ("mig" flags can be included /\w/mig)/b[aeiou]g/i (finds "bag", "beg", "BIG", "Bug", etc); (matches text that ends with an "r")
      < <= >= >Find alphabetical or numerical values less than or greater than or equal to the filtered query (2). (find values greater than or equal to 10)
      ! or !=Not operator, or not exactly match. Filter the column with content that do not match the query. Include an equal (=), single (') or double quote (") to exactly not match a filter (v2.17.1).!fe (hide rows with "female" in that column, but shows rows with "male"); (find text that doesn't contain an "a"); (find content that does not exactly match "Bruce")
      " or =To exactly match the search query, add a quote, apostrophe or equal sign to the beginning and/or end of the queryabc" or abc= (exactly match "abc"); or (exactly match "John")
       &&  or  AND Logical "and". Filter the column for content that matches text from either side of the operator.box && bat (matches a column cell that contains both "box" and "bat"); (Find text that contains both "br" and "c")
       -  or  to Find a range of values. Make sure there is a space before and after the dash (or the word "to") (4). or (match values between 10 and 30)
      ?Wildcard for a single, non-space character.J?n (finds "Jan" and "Jun", but not "Joan"); (finds "Dumass" and "Evans", but not "McMasters")
      *Wildcard for zero or more non-space characters.B*k (matches "Black" and "Book"); (matches "Dumass", "Evans" and "McMasters")
      | or  OR Logical "or" (Vertical bar). Filter the column for content that matches text from either side of the bar (3).box|bat (matches a column cell with either "box" or "bat"); (Find text that contains either "Alex" or "Peter")
      ~Perform a fuzzy search (matches sequential characters) by adding a tilde to the beginning of the query (v2.13.3) (matches "Bruce Lee" and "Brenda Dexter"), or (matches "Philip Aaron Wong")
      + (1) You cannot combine these operators with each other (except for the wildcards).
      + (2) The filter order (or precendence) of how searches are checked is as follows: regex (/\d/) > operators (< <= >= >) > not match (!) > exact (") > and ( AND ) > range ( - ) > wild/or (?, * and  OR ) > fuzzy (~); so an exact match will override "and", "or" and "range" searches (*NOTE* order changed in v2.15, operators prioritized before exact; see issue #465; order changed again in v2.17.1 to move "not match" before "exact" and allow for exact not matches; see issue #628)
      + (3) Logical "or" comparisons can now show exact matches (by default; v2.10.1) or just match cell contents.
      + (4) In tablesorter v2.10, comparisons can be made in date columns (if properly parsed). +
    • +
    +
    + +

    Options

    +
    +

    Filter widget defaults (added inside of tablesorter widgetOptions)

    +
    This table includes very basic information about the filter options. For more extensive information & links to demos, see the main page Widget & Pager Options section.
    +
    + TIP! Click on the link in the function column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    filter_childRowsfalseif true, filter includes child row content in the search.
    falseif true, queries will search child row content by column (v2.22.0). +
    +
    + The filter_childRows option must be true for this option to work.
    +
    + If false, and the filter_childRows option is true, then queries in any column will search all child content, as before this option was added. +
    +
    filter_columnFilterstrueif true, a filter will be added to the top of each table column.
    trueif true, allows using "#:{query}" in anyMatch searches (v2.20.0). +
    +
    + Users can use the anymatch input to target a specific column, using a one-based index. +

    + For example: In the table below, searching for 2:aa in an anymatch filter will result in "Phillip Aaron Wong" and "Aaron" showing in the First Name column. +

    + See live examples in the Filter Widget External Search demo. +
    +
    ''Extra css class name (string or array) added to the filter element (input or select) (v2.18.0) +
    +
    + The filter cell (<td>) is not to be confused with the filter_cssFilter option which adds an extra class name to the filter inputs (<input>). +
    '' + Extra css class name(s) applied to the table row containing the filters & the inputs within that row (v2.15). +
    +
    + This option can either be a string (class applied to all filters) or an array (class applied to indexed filter). +
    +
    filter_defaultAttrib'data-value'this option contains the name of the data-attribute which contains the default (starting) filter value.
    filter_defaultFilter{ }Set a default filter for a set column (v2.17.8).
    filter_excludeFilter{ }Set a column to exclude the chosen filter types (range, exact, notMatch, etc) (v2.17.8).
    '' + Set to a jQuery selector (or object) pointing to an input to be used to match the contents of any column (v2.15). +
    +
    + Please refer to the updated filter-any-match demo for the limitations of this setting. +
    +
    filter_filteredRow'filtered'Css class name added to filtered rows (rows that are not showing); needed by pager plugin.
    null + Add custom filter element(s) to the filter row +
    +
    + Custom filter elements include: + +
    +
    null + Add custom filter functions using this option. +
    +
    + See the custom filter widget functions demo for more details and numerous examples. +
    +
    filter_hideEmptytrueHide filter row when the table is empty (v2.15).
    filter_hideFiltersfalseIf true, filters are hidden initially, but can be revealed by hovering over the filter row, or giving a filter input focus (tabbing down the page).
    filter_ignoreCasetrueIf true, all searches are case-insensitive.
    filter_onlyAvail'filter-onlyAvail'A header with a select dropdown & this class name set, will only show available (visible) options within that drop down.
    filter_placeholder{ search : '', select : '' }Default placeholder text (overridden by any header "data-placeholder" setting; v2.16).
    filter_resetnulljQuery selector string of an element used to reset the filters (v2.4; v2.16.0).
    filter_saveFiltersfalseUses the $.tablesorter.storage utility to save the most recent filters.
    filter_searchDelay300Typing delay in milliseconds before starting a search.
    filter_searchFilteredtrueAllow searching through already filtered rows in special circumstances; will speed up searching in large tables if true.
    filter_selectSourcenullInclude a function to return an array of values to be added to the column filter select (v2.16.0).
    filter_selectSourceSeparatornullfilter_selectSource array text left of the separator is added to the option value, right into the option text.
    filter_serversideFilteringfalseIf true, filter will be done server-side. The client-side filtering will be disabled, but the ui and events will still be used.
    filter_startsWithfalseIf true, filter start from the beginning of the cell contents.
    filter_useParsedDatafalseFilter all data using parsed content.
    Removed options
    filter_anyMatchnulljQuery selector string (or jQuery object) of external anyMatch filter (removed in v2.15; please see the demo for more details)
    +
    + +

    Classes

    +
    + Class names that can be added to the th header cells: +
      +
    • filter-false - disable the filter for a specific header column.
    • +
    • filter-select - build a default select box for a column (shows unique column content). See the custom filter widget demo for an example.
    • +
    • filter-select-nosort - when a default select box is built, this option prevents the sorting of select options leaving them in their original table order (v2.16.3).
    • +
    • filter-match - applies to "filter-select" columns and columns where the user can use the logical "or" search. Makes the filter/select match the column contents instead of exactly matching.
    • +
    • filter-parsed - set a column to filter through parsed data instead of the actual table cell content.
    • +
    • filter-onlyAvail +
        +
      • Show only available (visible) options within a default select box.
      • +
      • This class name is set by the filter_onlyAvail option.
      • +
      • See the custom filter widget demo "Discount" column for an example.
      • +
      +
    • +
    +
    + +

    Methods

    +
    +

    Set Filter Placeholder Text

    +
    + Set a data-placeholder attribute on the associated table header with your desired placeholder text +
    <th data-placeholder="Enter Something">Name</th>
    + or, set the header cell's jQuery data +
    $('.tablesorter th:eq(0)').data('placeholder', 'Search for...')
    +
    + +

    Set Filter Initial Searches

    +
    + Set a data-value attribute (data-attribute name set by the filter_defaultAttrib option) on the associated table header with the desired initial search value. +
    <th data-value="<=100">Price</th>
    + or, set the header cell's jQuery data +
    $('.tablesorter th:eq(0)').data('value', '<=100')
    +
    + +

    filterReset

    +
    + Use the filterReset method to reset (clear) all of the current filters using this method +
    $('table').trigger('filterReset');
    + or, just add an element to your page and point to it by setting the filter_reset option, to allow user interaction. +

    + *NOTE* delegated event bindings are used so these "reset" elements can be dynamically added and removed from the document. +
    + +

    Search

    +
    + With this method, you can pass an array of filter values: +
    // apply "2?%" filter to the fifth column (zero-based index)
    +var columns = [];
    +columns[5] = '2?%';
    +// or define the array this way var columns = [ '', '', '', '', '', '2?%' ]
    +$('table').trigger('search', [ columns ]);
    + or, just pass false to refresh the current search: +
    $('table').trigger('search', false);
    + * Note: using this search method will update the contents of the filters within the filter row.
    +
    + In v2.15, one additional parameter can be added to the array to perform an "any-match" of the table; Warning! please note that if no external input (with a data-column="all" is attached using bindSearch function) is visible, the user will not know that a filter has been applied.
    // in a table with 4 columns; set the 5th parameter to any-match
    +$('table').trigger( 'search', [['', '', '', '', 'orange']] ); // find orange in any column
    +
    + +

    Get current filters

    +
    + Get an array of the currently applied filters (v2.9). +
    $.tablesorter.getFilters( $('table') ); // or $('table.hasFilters')
    + This method returns an array of filter values or false if the selected table does not contain a filter row.
    +
    + Internally, the get filters functions returns the filters stored within this table data $('table').data('lastSearch'), unless an additional parameter of true is passed to the function: +
    $.tablesorter.getFilters( $('table'), true ); // get current input values instead of data stored filters
    + As of v2.15, if an external "any-match" filter (see filter_external widget option) is included, one additional array parameter will be returned in the filter - the value of the any match search. +
    // in a table with six columns, this function will return an array with seven
    +// parameters; something like this: [ '', '', '', '', '', '', '11' ],
    +// where the "11" will be obtained from the "any-match" input
    +var filters = $.tablesorter.getFilters( $('table') );
    +
    + +

    Set current filters

    +
    + Set the values of the actual filters using this method; include a true boolean to actually apply the search (v2.9). +
    // update filters, but don't apply the search
    +$.tablesorter.setFilters( $('table'), [ '', '', '', '', '', '2?%' ] );
    +
    +// update filters, AND apply the search
    +$.tablesorter.setFilters( $('table'), [ '', '', '', '', '', '2?%' ], true );
    + This method returns true if the filters were sucessfully applied, or false if the table does have a filter row.
    +
    + As of v2.15, if an external "any-match" filter (see filter_external widget option) is included, add an additional array parameter to set that filter; so if a table has six columns, add the any-match search as the seventh value. +
    // in a table with 6 columns, the 7th filter will apply
    +// to the any-match filter & match any table column with "11"
    +$.tablesorter.setFilters( $('table'), [ '', '', '', '', '', '', '11' ], true );
    +
    + +

    Bind external filter

    +
    + Use this method to bind external search filters +
      +
    • Include a data-attribute data-column with the column index to target
    • +
    • Or, use data-column="all" to preform an "any-match" search on all of the table columns (v2.15).
    • +
    • Or, add multiple columns data-column="0-2,4,6-8" to perform an "any-match" search on selected columns (v2.18.0).
    • +
    + If no data-column is added to the input, the input will be ignored. +
    <!-- will perform an "any-match" type of search (matches any column) -->
    +<input type="search" class="search" data-column="all">
    +<!-- will only search the first column (zero-based index) -->
    +<input type="search" class="search" data-column="0">
    +
    // Target the $('.search') input using built in functioning
    +// this binds to the search using "search" and "keyup" and allows using filter_liveSearch
    +// or delayed search & pressing escape to cancel the search
    +// pass an optional third parameter (false boolean) to force the inputs to update
    +// this allows changing the data-column for an input dynamically
    +$.tablesorter.filter.bindSearch( $table, $('.search'), false );
    + If you don't care about the enhanced search filter, then bind to both the "keyup" and "search" events +
    // Basic search binding, alternate to the above
    +// bind to search - pressing enter and clicking on "x" to clear (Webkit)
    +// keyup allows dynamic searching
    +$(".search").bind('search keyup', function (e) {
    +  $('table').trigger('search', [ [this.value] ]);
    +});
    +
    + +
    + +

    Events

    +
    +
      +
    • filterEnd - Event triggered when the filter widget has finished processing the search.
    • +
    • filterInit - Event triggered when the filter widget has finished initializing.
    • +
    • filterStart - Event triggered when the filter widget has started processing the search.
    • +
    +
    + +

    Changes

    +
    + Moved to the wiki pages - filter change log. +
    + +

    Localization

    +
    + You can now change the language of the searches used within the filter widget. For example, to change the localization to French, do the following: +
    // add French support
    +$.extend($.tablesorter.language, {
    +	to  : 'à',
    +	or  : 'ou',
    +	and : 'et'
    +});
    If you want to support multiple languages, separate the language variables with a vertical bar (|, Shift + \): +
    // add French & Spanish support
    +$.extend($.tablesorter.language, {
    +	to  : 'à|a',
    +	or  : 'ou|o',
    +	and : 'et|y'
    +});
    Note These changes still require the user to enter spaces in the filter to perform the search, e.g. 1 à 10 (shows rows with numbers between 1 and 10). +
    + +
    + +

    Demo

    + filter_startsWith : false (if true, search from beginning of cell content only)
    + filter_ignoreCase : true (if false, the search will be case sensitive)
    + filter-match (if class name added to the "First Name" column, all "or" searches will only match the content; Search in the First Name column (2.10.1). +
    + +
    Search in the Discount column
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankFirst Name ( filter-match )Last NameAgeTotalDiscount Date
    1Philip Aaron WongJohnson Sr Esq25$5.9522%Jun 26, 2004 7:22 AM
    11AaronHibert12$2.995%Aug 21, 2009 12:21 PM
    12Brandon ClarkHenry Jr51$42.2918%Oct 13, 2000 1:15 PM
    111PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    21JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    013ClarkKent Sr.18$15.8944%Jan 12, 2003 11:14 AM
    005BruceAlmighty Esq45$153.1944%Jan 18, 2021 9:12 AM
    10AlexDumass13$5.294%Jan 8, 2012 5:11 PM
    16JimFranco24$14.1914%Jan 14, 2004 11:23 AM
    166Bruce LeeEvans22$13.1911%Jan 18, 2007 9:12 AM
    100Brenda DexterMcMasters18$55.2015%Feb 12, 2010 7:23 PM
    55DennisBronson65$123.0032%Jan 20, 2001 1:12 PM
    9MarthadelFuego25$22.0917%Jun 11, 2011 10:55 AM
    + +

    Page Header

    +
    +
    <!-- blue theme stylesheet -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<!-- tablesorter plugin -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- tablesorter widget file - loaded after the plugin -->
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    CSS

    +
    +
    /* This css is already contained within each theme file */
    +/* filter row */
    +.tablesorter-filter-row td {
    +  background: #eee;
    +  line-height: normal;
    +  text-align: center; /* center the input */
    +  -webkit-transition: line-height 0.1s ease;
    +  -moz-transition: line-height 0.1s ease;
    +  -o-transition: line-height 0.1s ease;
    +  transition: line-height 0.1s ease;
    +}
    +/* optional disabled input styling */
    +.tablesorter-filter-row .disabled {
    +  opacity: 0.5;
    +  filter: alpha(opacity=50);
    +  cursor: not-allowed;
    +}
    +
    +/* hidden filter row */
    +.tablesorter-filter-row.hideme td {
    +  /*** *********************************************** ***/
    +  /*** change this padding to modify the thickness     ***/
    +  /*** of the closed filter row (height = padding x 2) ***/
    +  padding: 2px;
    +  /*** *********************************************** ***/
    +  margin: 0;
    +  line-height: 0;
    +  cursor: pointer;
    +}
    +.tablesorter-filter-row.hideme * {
    +  height: 1px;
    +  min-height: 0;
    +  border: 0;
    +  padding: 0;
    +  margin: 0;
    +  /* don't use visibility: hidden because it disables tabbing */
    +  opacity: 0;
    +  filter: alpha(opacity=0);
    +}
    +
    +/* filters */
    +.tablesorter-filter {
    +  width: 95%;
    +  height: inherit;
    +  margin: 4px;
    +  padding: 4px;
    +  background-color: #fff;
    +  border: 1px solid #bbb;
    +  color: #333;
    +  -webkit-box-sizing: border-box;
    +  -moz-box-sizing: border-box;
    +  box-sizing: border-box;
    +  -webkit-transition: height 0.1s ease;
    +  -moz-transition: height 0.1s ease;
    +  -o-transition: height 0.1s ease;
    +  transition: height 0.1s ease;
    +}
    +
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-widget-formatter.html b/docs/example-widget-formatter.html new file mode 100644 index 0000000..3f03758 --- /dev/null +++ b/docs/example-widget-formatter.html @@ -0,0 +1,241 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Formatter Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • This widget will only work in tablesorter version 2.16+ and jQuery version 1.7+.
    • +
    • It allows you to add custom formatting to table columns.
    • +
    • You have the option of storing the original cell text within the table cell data-attribute to maintain the sort order.
    • +
    • This widget is not optimized for large tables; but it only runs on initialization and after any updates have occurred.
    • +
    +
    + +

    Options

    +
    +

    Formatter widget default options (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the function column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + +
    OptionDescription
    Assign a formatting function by column index or column header class name; these functions only apply to the tbody cells. +
    +
    + Set up the formatter to return the HTML for the table cell. +
    formatter_column: {
    +	'.emphasize' : function( text, data ) {
    +		return '' + text + '';
    +	}
    +}
    + If the text in the cell is to be changed, but you don't want the sort to be effected, then add the original text into the data-attribute as follows: +
    formatter_column: {
    +	'.makesearch' : function( text, data ) {
    +		// don't make a link if there is no text in the cell
    +		if ( text === '' ) { return ''; }
    +		// add text to data-attribute; this overrides the parser
    +		data.$cell.attr( data.config.textAttribute, text );
    +		// then replace text with a link
    +		return 'Get Definition';
    +	}
    +}
    + The data parameter provided to the formatter_column function contains the following information: +
    data = {
    +	config      : table.config,
    +	wo          : table.config.widgetOptions,
    +	$header     : $('th'),  // the header cell of the current column
    +	$row        : $('tr'),  // jQuery object of the row currently being processed
    +	$cell       : $('td'),  // jQuery object of the cell currently being processed
    +	text        : 'Batman', // the text from the current cell
    +	columnIndex : 0         // the column index of the current cell
    +}
    +
    +
    The formatter will update when this event is triggered on the table. +
    +
    + The default setting is 'applyFormatter' +

    + The formatter is set up to run again after an "updateComplete" or "pagerComplete" event fires; this option allows setting a custom-named event to force the formatter to update in addition to the complete events. +

    + * NOTE * So, if the text in the cell gets modified by the formatter, make sure your code saves the original text into the data-attribute or it will get lost. +

    + Force an update as follows: +
    $('table').trigger('applyFormatter');
    +
    +
    +
    + +
    + +

    +

    Demo

    + +
    + + + + + + + + + + + + + + + + + +
    Super HeroSuper CarImage LinksAdded
    SupermanBugatti VeyronDuckie1/1/2015
    FlashHennessey VenomHorse12/22/2014
    BatmanKoenigsegg AgeraElephant3/10/2010
    Green LanternSSC Ultimate AeroCow5/5/2012
    Howard the DuckKoenigsegg CCXPizza1/1/2005
    Wonder WomanMcLaren F1Tiger3/1/2013
    + +

    Javascript

    +
    +
    
    +	
    +

    CSS

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + +
    + + + diff --git a/docs/example-widget-grouping-filter-childrows.html b/docs/example-widget-grouping-filter-childrows.html new file mode 100644 index 0000000..df40409 --- /dev/null +++ b/docs/example-widget-grouping-filter-childrows.html @@ -0,0 +1,194 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Grouping + Filter widget with child rows + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • As of v2.15.12, +
        +
      • Parents of child rows now have a tablesorter-hasChildRow class name added.
      • +
      • NOTE! A new css definition was added to every default theme; the "filtered" class name (set by the filter_filteredRow widgetOption) has been added to properly hide/show child rows when filtered.
      • +
      +
    • +
    +

    + +

    Demo

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OrderStatusPriorityPrice
    Good ToysUSA80%
    1561651finish0$5
    558815finish0$55
    Cycle ClearanceFRANCE25%
    21485213in progress2$7
    12547854finish0$18
    Cycle Initial Bike CompanyUSA36%
    12574521in progress1$5
    7895452in progress2$78
    1542021finish0$28
    4489885finish0$18
    Sports StoreUSA90%
    18915in progress2$5
    5402574in progress2$78
    26478finish0$28
    25682finish0$18
    Locks CompanyUK24%
    18915in progress2$5
    5402574in progress1$78
    26478finish0$28
    25682finish0$18
    Famous Bike ShopUK12%
    185406in progress2$5
    541265in progress2$78
    +
    + +

    Script

    +
    +
    
    +	
    + +

    CSS

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + +
    + + + diff --git a/docs/example-widget-grouping.html b/docs/example-widget-grouping.html new file mode 100644 index 0000000..1a75510 --- /dev/null +++ b/docs/example-widget-grouping.html @@ -0,0 +1,597 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Grouping Rows Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • This widget will only work in tablesorter version 2.8+ and jQuery version 1.7+.
    • +
    • Please do not use this widget in very large tables (it might be really slow) or when your table includes multiple tbodies.

    • +
    • In v2.22.0, group headers are now keyboard accessible using Tab; and pressing Enter while the header has focus will toggle the group header, or use Shift + Enter to toggle all groups.
    • +
    • In v2.21.0 +
        +
      • Added group_checkbox option to allow setting the parsed text from the "parser-input-select.js" checkbox parser.
      • +
      • Fixed an issue with the filter widget overriding the "group-hidden" class name.
      • +
      +
    • +
    • In v2.15.6, added group_saveGroups & group_saveReset options. More details are included in the "Options" section.
    • +
    • In v2.14, added group_dateString option. More details are included in the "Options" section.
    • +
    • In v2.13, added group_separator option & group-separator-# header class name. To see this in action, check out the file type parser demo.
    • +
    • In v2.12, added group_callback & group_complete options. See options section below for details.
    • +
    • In v2.11: +
        +
      • The grouping widget now works across multiple tbodies.
      • +
      • Added group-false header option which disables the grouping widget for a specific column.
      • +
      • Added the group_collapsed option - get more details in the options block below.
      • +
      • You can now toggle all group rows by holding down the Shift key while clicking on a group header.
      • +
      • This widget now works properly with the pager addon (pager addon updated).
      • +
      +
    • +
    • Clicking on any of the sortable header cells will cause the column below it to sort and add a group header.
    • +
    +
    + +

    Options

    +
    +

    Group widget default options (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the option column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    group_collapsibletrue + when true, the group headers become clickable and collapse the rows below it. +
    group_collapsedfalse + when true and group_collapsible is also true, all groups will start collapsed (v2.11) +
    trueRemember collapsed groups (v2.15.6) +
    +
      +
    • This option saves the currently collapsed groups, using the group name.
    • +
    • Collapsed groups are saved by column and group class name, so that the groups can be dynamically changed and still remember the correct collapsed groups. Try changing the group names (using the sliders) in the demo below & then collapsing some groups several times; go back to previous groups and it will remember which groups were collapsed.
    • +
    • Because the group name is saved, groups with a number range (e.g. "group-number-10"; see the "Numeric" column below) will show a different range depending on sort direction; in this situation, each sort direction is saved independently.
    • +
    • This option requires the $.tablesorter.storage utility contained within the jquery.tablesorter.widgets.js file.
    • +
    +
    +
    nullElement used to clear saved collapsed groups (v2.15.6) +
    +
      +
    • This option should contain a jQuery selector string or jQuery object pointing to an element to be used to reset (clear) the list of collapsed groups.
    • +
    • You can also clear the saved collapsed groups by calling this function: $.tablesorter.grouping.clearSavedGroups(table); (table would be either the table DOM or table jQuery object).
    • +
    • This option requires the $.tablesorter.storage utility contained within the jquery.tablesorter.widgets.js file.
    • +
    +
    +
    group_count" ({num})" + Allows you to add custom formatting, or remove, the group count within the group header. Set it to false or an empty string to remove the count. +
    "-" + When the group-separator class name is added, it uses the setting from this option to split the table cell content for grouping v2.13.
    +
    +
    + If your content has mixed separators (e.g. images/cats/burger-time.jpg), you can set this option to use a regular expression: +
    // the above example becomes: ["images", "cats", "burger-time", "jpg"]
    +group_separator : /[/.]/
    +
    +
    null + Use this function to modify the group header text before it gets applied. +
    +
    + It provides various parameters (txt, col, table, c, wo) to make it work for any of the table columns and data. See the comments in the example below for more details. +
      +
    • txt - current text of the group header.
    • +
    • col - current table column being grouped (zero-based index).
    • +
    • table - current table (DOM).
    • +
    • c - table configuration data from table.config.
    • +
    • wo - table widget options from table.config.widgetOptions.
    • +
    +
    group_formatter : function(txt, col, table, c, wo) {
    +  // If there are empty cells, name the group "Empty"
    +  return txt === "" ? "Empty" : txt;
    +}
    +
    +
    null + Use this function to further modify the group header to include more information (i.e. group totals). Parameters include ($cell, $rows, column, table). See the example below for more details v2.12. +
    +
      +
    • $cell - current group header table cell (jQuery object).
    • +
    • $rows - current group rows (jQuery object).
    • +
    • column - current table column being grouped (zero-based index).
    • +
    • table - current table (DOM).
    • +
    +
    group_callback : function($cell, $rows, column, table){
    +  $cell.find('.group-name').append(' group'); // adds "group" to the end of the group name
    +}
    +
    +
    "groupingComplete" + Event triggered on the table when the grouping widget has finished work v2.12. +
    +
    $('table').on('groupingComplete', function(){
    +  // always hide empty groups ("Empty" can be added by the group_formatter function)
    +  $(this).find('.group-header:contains("Empty")').trigger('toggleGroup');
    +});
    +
    +
    see description) + Set checkbox parser text (v2.21.0) +
    +
    + The checkbox parser in the "parser-input-select.js" file will use this option to set the group header text displayed for a checkbox state. +

    + Defaults are: [ "checked", "unchecked" ] +
    +
    +
    + group_week
    + group_time +
    (see description) + Name arrays included so that the language of the date groups can be modified easily. Defaults (English): +
      +
    • group_months: ([ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]) - Month names.
    • +
    • group_week: ([ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]) - Named days of the week.
    • +
    • group_time: ([ "AM", "PM" ]) - Time of day.
    • +
    +
    (see description) + When the "group-date" class name is set on a column, this function is used to format the date string. This is the default function: +
    +
    // you can just return date, date.toLocaleString(), date.toLocaleDateString() or d.toLocaleTimeString()
    +group_dateString : function(date) {
    +  return date.toLocaleString();
    +}
    + Other functions that can be used are date (alone), date.toLocaleString(), date.toLocaleDateString() or d.toLocaleTimeString(). See this reference for more details. +
    +
    +
    + +

    Header Class Names

    +
    +

    Group header class names (when changing the grouping, notice that the sort doesn't change, just the position and names of the group headers):

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Group typeGroup class nameDescription
    Disable"group-false"Disable grouping of rows for a column (v2.11).
    Text"group-word"Group the rows using the first word it finds in the column's parsed data (same as "group-word-1").
    "group-word-n"*Group the rows using the nth word in the column ("n" can be any number).
    "group-letter"Group the rows using the first letter it finds in the column's parsed data (same as "group-letter-1").
    "group-letter-n"*Group the rows using letters 1 through n (if n = 2, then it's the first 2 letters) in the column's parsed data ("n" can be any number).
    Number"group-number"Group the rows by the number it finds in the column (step of one; same as "group-number-1").
    "group-number-n"*Group the rows into blocks of every n values. So, if n = 10, the groups will be 0-9, 10-19, 20-29, etc ("n" can be any number).
    Separator"group-separator"Group the rows using the text between the start and first separator that it finds in the column's parsed data (same as "group-separator-1") (v2.13).
    "group-separator-n"*Group the rows using the nth separated group in the column ("n" can be any number) (v2.13).
    Date"group-date"Group the rows by full date (this shows the current UTC time corrected for your time zone).
    "group-date-year"*Group the rows by year.
    "group-date-month"*Group the rows by month.
    "group-date-monthyear"*Group the rows by month & year.
    "group-date-week"*Group the rows by day of the week.
    "group-date-day"*Group the rows by month/day.
    "group-date-time"*Group the rows by time.
    + * When sorting some columns, different group headers with the same group name may exist (try "group-date-week" and "group-date-time"). To make these columns sort specifically by the group you want, you'll need to modify the parser. +
    +
    + +

    + +

    Demo

    + +Numeric column:
    (includes subtotals)
    +Animals column:

    +Date column:
    +

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Quality (number) Numeric (every 10)Priority (letter)Animals (first letter)Natural Sort (first word)Inputs (second word)Date (Full)
    QualityNumericPriorityAnimalsNatural SortInputsDate
    110Koalaabc 1231/13/2013 12:01 AM
    329Kangarooabc 11/15/2013
    210Antabc 91/13/2013
    381Beezyx 241/11/2013
    321Aardwolfzyx 551/13/2013 03:30 AM
    13Bearabc 111/15/2013
    412Armadillozyx 21/15/2013 12:30 PM
    256Aardvarkabc 21/22/2013
    155Lionabc 92/15/2013
    487AnteaterABC 101/3/2013
    298Lemurzyx 11/11/2013
    120Llamazyx 1212/13/2012
    +
    + +

    Page Header

    +
    +
    <!-- Tablesorter: required -->
    +<link href="../css/theme.blue.css" rel="stylesheet">
    +<script src="../js/jquery.tablesorter.js"></script>
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +
    +<!-- Grouping widget -->
    +<script src="../js/parsers/parser-input-select.js"></script>
    +<script src="../js/widgets/widget-grouping.js"></script>
    +
    + +

    Script

    +
    +
    
    +	
    + +

    CSS

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-widget-header-titles.html b/docs/example-widget-header-titles.html new file mode 100644 index 0000000..997ab27 --- /dev/null +++ b/docs/example-widget-header-titles.html @@ -0,0 +1,321 @@ + + + + + jQuery plugin: Tablesorter 2.0 - headerTitles widget + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • In 2.15.7, +
        +
      • Sorry for all of these breaking changes, I should have left this widget in beta.
      • +
      • The headerTitle_prefix, headerTitle_text, headerTitle_numeric options has been replaced, in lieu of the new ouput options; sorry for no deprecation notice.
      • +
      • Added headerTitle_useAria, headerTitle_tooltip, headerTitle_output_sorted, headerTitle_output_unsorted, headerTitle_output_nosort, headerTitle_cur_text, headerTitle_cur_numeric, headerTitle_nxt_text, headerTitle_nxt_numeric, headerTitle_type & headerTitle_callback options. See the options section below for more details.
      • +
      • Added "refreshHeaderTitle" method to force the widget to update.
      • +
      +
    • +
    • This widget adds a title to the table headers when they are sorted.
    • +
    • Click on any header. You may have to move the mouse off, then back on the header to see the title appear.
    • +
    • This widget will not work with the original tablesorter plugin (v2.0.5).
    • +
    • The examples uses the tipsy jQuery plugin
    • +
    +
    + +

    Options

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    headerTitle_useAriafalse + When true, the headers titles are extracted from the aria-label. The text in that label is built from the $.tablesorter.language option. +
    headerTitle_tooltip"" + Add a (tooltip) class name to the header, yeah you could have used the cssHeader option to do the same thing, but this option allows adding classes using an array. +
    headerTitle_tooltip : [ 'tooltip-text', 'tooltip-text', 'tooltip-numeric', 'tooltip-numeric', '', 'tooltip-text']
    +
    + headerTitle_cur_text
    + headerTitle_cur_numeric +
    (see description) + When any of the header title output options use the {current} tag, it is replaced by values from either the current ("cur") text or numeric option array as determined by the column unsorted state or sort direction.
    +
    + The array must contain text for ascending, descending and unsorted state (in that order). Defaults: +
    headerTitle_cur_text     : [ ' sort: A - Z', ' sort: Z - A', 'ly unsorted' ],
    +headerTitle_cur_numeric  : [ ' sort: 0 - 9', ' sort: 9 - 0', 'ly unsorted' ]
    +
    + headerTitle_nxt_text
    + headerTitle_nxt_numeric +
    (see description) + When any of the header title output options use the {next} tag, it is replaced by values from either the next ("nxt") text or numeric option array as determined by the column unsorted state or sort direction.
    +
    + The array must contain text for when the next state is ascending, descending and unsorted (in that order). Defaults: +
    headerTitle_nxt_text     : [ ' sort: A - Z', ' sort: Z - A', 'remove sort' ],
    +headerTitle_nxt_numeric  : [ ' sort: 0 - 9', ' sort: 9 - 0', 'remove sort' ]
    +
    + headerTitle_output_sorted
    + headerTitle_output_unsorted
    + headerTitle_output_nosort +
    (see description) + Set the output string for each sort condition: sorted, unsorted or sorting disabled.
    +
    + Each of these option strings can include a {name}, {current} and {next} tag. +
      +
    • The {name} tag is replaced by the header text.
    • +
    • The {current} tag is replaced by the type-appropriate text from either the headerTitle_cur_text or headerTitle_cur_numeric option.
    • +
    • The {next} tag is replaced by the type-appropriate text from either the headerTitle_nxt_text or headerTitle_nxt_numeric option.
    • +
    + Defaults: +
    headerTitle_output_sorted   : 'current{current}; activate to {next}',
    +headerTitle_output_unsorted : 'current{current}; activate to {next} ',
    +headerTitle_output_nosort   : 'No sort available'
    + Note: the reason "activate" is used instead of "click" is because the user can also Tab to the header cell and press Enter to initiate a sort. +
    headerTitle_type[]Each column type is determined by the parser type value. So, if you want to override a column default type, set this option with an array with the specified column changed to either "text" or "numeric". This is useful when a date column shows as a numeric sort, but you want your users to see it as a text sort.
    +
    + As seen in the second table initialization code below, if an array element is undefined or an empty string, it will not override the default type. +
    headerTitle_type : ['', '', '', '', '', 'text']
    +
    headerTitle_callbacknull + This callback function is executed after the title text string has completed processing. Any additional changes, or modifications can be done within this function. This function has two parameters $cell (the header cell as a jQuery object), and the processed text (txt). The function must return the text! +
    headerTitle_callback : function($cell, txt) {
    +    return txt;
    +}
    In this demo, you will notice that this function is used to dynamically update the tooltip. +
    +
    + +

    Method

    +
    +

    Force headerTitle widget update

    + If you need to programmically force the header title to update, trigger a refreshHeaderTitle event on the table: +
    $('table').trigger('refreshHeaderTitle');
    + In this demo, this method is used when switching between the default header title and aria-label text. +
    + +
    + +

    Demo

    +
    + +

    Tooltip plugin using togglable aria-label text

    + : true + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jan 18, 2001 9:12 AM
    JohnEvans33$9.9925%Dec 10, 2002 5:14 AM
    ClarkKent22$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$15.8944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jul 6, 2006 8:14 AM
    + +

    Tooltip plugin with alternative titles

    + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jan 18, 2001 9:12 AM
    JohnEvans33$9.9925%Dec 10, 2002 5:14 AM
    ClarkKent22$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$15.8944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jul 6, 2006 8:14 AM
    + +

    No Tooltip Plugin

    + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jan 18, 2001 9:12 AM
    JohnEvans33$9.9925%Dec 10, 2002 5:14 AM
    ClarkKent22$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$15.8944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jul 6, 2006 8:14 AM
    + +
    + +

    Javascript

    +
    +
    
    +	
    + +
    + + + + diff --git a/docs/example-widget-math.html b/docs/example-widget-math.html new file mode 100644 index 0000000..2f9ad93 --- /dev/null +++ b/docs/example-widget-math.html @@ -0,0 +1,646 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Math Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • In v2.22.0, +
        +
      • Fixed an issue with a sum column encountering a cell without a defined "data-math" attribute returning an empty string instead of zero. See issue #873.
      • +
      • Fixed a javascript error occurring on empty tables & now all updates will reapply column indexing to tbody cells - I know this isn't ideal as it would be slow on larger tables.
      • +
      +
    • +
    • In v2.19.1, added math_event option & fixed an issue with event unbinding in jQuery version < 1.9.
    • +
    • In v2.17.1, +
        +
      • Values added to the data-attribute set by the textAttribute option will now be used in the calculation instead of the actual cell content.
      • +
      • The Grand Total cells now shows a higher precision value to emphasize this point.
      • +
      +
    • +
    • In v2.16.4, added: +
        +
      • Two new options: math_prefix and math_suffix, which will be added before or after the prefix or suffix, respectively.
      • +
      • Added "Mask Examples" section with examples, and how to use the $.tablesorter.formatMask function.
      • +

      +
    • +
    • This widget will only work in tablesorter version 2.16+ and jQuery version 1.7+.
    • +
    • It adds basic math capabilities. A full list of default formulas is listed in the "Attribute Settings" section.
    • +
    • Add your own custom formulas which manipulating an array of values gathered from the table by row, column or a column block (above).
    • +
    • This is by no means a comprehensive widget that performs like a spreadsheet, but you can customize the data gathering "type" and available "formula", as desired.
    • +
    • The widget will update the calculations based on filtered rows, and will update if any data within the table changes (using update events).
    • +
    • This widget is not optimized for very large tables, for two reasons: +
        +
      • On initialization, it cycles through every table row, calculates the column index, and adds a data-column attribute.
      • +
      • It uses the update method whenever it recalculates values to make the results sortable. This occurs when any of the update methods are used and after the table is filtered.
      • +
      +
    • +
    • When setting tablesorter's debug option to true, this widget will output each {type}-{formula} value found, the array of numbers used and the result.
    • +
    +
    + +

    Options

    +
    +

    Math widget default options (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the option column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    math_data'math' + Set this option to point to the named data-attribute. For example, when set to 'math', the widget looks for settings within the data-math attribute. +
    math_event'recalculate' + Set this option change the name of the event that the widget listens for to perform an update. +
    [ ] + Set this option the column index of columns of data to ignore. +
    +
    + To ignore the first and second columns in a table, set this option using zero-based column indexs as follows: +
    // column index(es) to ignore
    +math_ignore : [0,1]
    +
    +
    '#,##0.00' + Set this option with an output formatting mask to use * +
    + As of v2.16.2, you can set a mask for each math cell by adding a data-math-mask data-attribute (the math part of the data-attribute is obtained from the math_data setting). +
    <th data-math="all-sum" data-math-mask="##0.00">all-sum</th>
    +
    +

    Javascript-number-formatter details

    +

    Features

    +
      +
    • Short, fast, flexible yet standalone. Only 75 lines including MIT license info, blank lines & comments.
    • +
    • Accept standard number formatting like #,##0.00 or with negation -000.####.
    • +
    • Accept any country format like # ##0,00, #,###.##, #'###.## or any type of non-numbering symbol.
    • +
    • Accept any numbers of digit grouping. #,##,#0.000 or #,###0.## are all valid.
    • +
    • Accept any redundant/fool-proof formatting. ##,###,##.# or 0#,#00#.###0# are all OK.
    • +
    • Auto number rounding.
    • +
    • Include a prefix & suffix with the mask
    • +
    • Simple interface, just supply mask & value like this: $.tablesorter.formatMask( "0.0000", 3.141592, "prefix ", " suffix" ); +
      $.tablesorter.formatMask( "$ 0.0000 USD", 1234.567, "prefix ", " suffix" );
      +// prefix $ 1234.5670 USD suffix
      +
    • +
    +

    Limitation

    +
      +
    • No scientific/engineering formatting.
    • +
    • Not for date or phone formation.
    • +
    • No color control.
    • +
    • No prefix or suffix is allowed except leading negation symbol. So $#,##0.00 or #,###.##USD will not yield expected outcome. Use '$'+ $.tablesorter.formatMask('#,##0.00', 123.45) or $.tablesorter.formatMask('#,##0.00', 456.789) + 'USD'
    • +
    • The prefix or suffix can not include any numbers (0-9), hashes (#), dashes (-), or plus signs (+)
    • +
    +

    Note

    +
      +
    • When there's only one symbol is supplied, system will always treat the single symbol as Decimal. For instance, $.tablesorter.formatMask( '#,###', 1234567.890) will output 1234567,890.
    • +
    • To force a single symbol as Separator, add a trailing dot to the end like this: $.tablesorter.formatMask( '#,###.', 1234567.890) which will then output 1,234,567.
    • +
    • Original plugin demo
    • +
    + * The number formatter code was copied from javascript-number-formatter (MIT) - now forked on GitHub. +
    +
    null + This function is called after each calculation is made to allow re-formatting, adding prefixes, suffixes, etc to the result. +
    +
    + Use this option as follows: +
    // complete executed after each function
    +math_complete : function($cell, wo, result, value, arry){
    +    return '$ ' + result + $cell.attr('data-suffix');
    +}
    +
      +
    • $cell - the target cell (jQuery object)
    • +
    • wo - tablesorter's widget options (from table.config.widgetOptions).
    • +
    • result - the formatted result of the calculation.
    • +
    • value - an unformatted result of the calculation.
    • +
    • arry - the array of values gathered by the widget.
    • +
    + In this function, if a anything is returned, it will be automatically added to the $cell as html. Or, return false and no change is made to the cell contents; use this method if you manipulate the $cell contents and don't want the widget to do it.
    +
    + If you need to format the data output after manipulating the value, you can use wo.math_mask, or a different mask, by using the $.tablesorter.formatMask( mask, value ); function. For example: +
    math_complete : function($cell, wo, result, value, arry){
    +    var percent = Math.round( value * 1e4 ) / 100; // percent with two decimal places
    +    return $.tablesorter.formatMask( wo.math_mask, percent ) + ' %';
    +}
    + More details can be found in the math_mask description. +
    +
    [ 'row', 'above', 'col' ] + This is the order of calculations. +
    +
      +
    • By default, the widget cycles through the calculated cells as follows: +
        +
      • Search all non-informational tbodies for data-math table cells (data-attribute set by math_data option).
      • +
      • Cycle through these cells by priority: row, above, col (set by this option).
      • +
      • Search all informational tbodies, and tfoot for data-math table cells.
      • +
      • Cycle through these cells by priority: row, above, col (set by this option).
      • +
      • Search the entire table for data-math cells of the "all" type.
      • +
      +
    • +
    • So, all row calculations are made first, followed by "above" calculations then "col" (column) calculations.
    • +
    • The "all" type calculations are always performed last, and therefore the type is not included in this list.
    • +
    • Change this order if the order of calculations needs to be made column first, followed by rows.
    • +
    • For more details about the differences between "col" and "above" types, see the next section.
    • +
    +
    +
    '' + Add content before the value formatted by the math_mask option (v2.16.4). +
    +
      +
    • This option adds content before the mask.
    • +
    • If the mask includes any content for the prefix, then this value is added before it.
    • +
    • If this option contains a {content} tag, the prefix within the mask will replace this tag. +
      math_mask   : '$ #,##0.00',
      +math_prefix : '{content}'
      +
      +// result of the value 12345.67
      +// <span class="blue">$ </span>12,345.67
      + You can experiment with this option in the "Mask Examples" section. +
    • +
    +
    +
    '' + Add content after the value formatted by the math_mask option (v2.16.4). +
    +
      +
    • This option adds content after the mask.
    • +
    • If the mask includes any content for the suffix, then this value is added after it.
    • +
    • If this option contains a {content} tag, the suffix within the mask will replace this tag. +
      math_mask   : '#,##0.00 USD',
      +math_suffix : '{content}!'
      +
      +// result of the value 12345.67
      +// 12,345.67 USD<span class="red">!</span>
      + You can experiment with this option in the "Mask Examples" section. +
    • +
    +
    +
    +
    + +

    Attribute Settings

    +
    + The math widget data-attibute setting requires two parts: type & formula +
    <td data-math="{type}-{formula}"></td>
    + When set, the data is gathered based on the math type ("row", "column", "above" or "all") and passed to the formula as an array. +

    {type} (data gathering)

    +
      +
    • row - gather the table cell values from the same row as the data-math attribute.
    • +
    • above - gather the table cell values from the same column as the data-math attribute, but stop when the first table cell is reached, or when another cell with a data-attribute with an "above" type is reached; see the first table demo below to see why this is useful.
    • +
    • col - gather the table cell values from the same column as the data-math attribute.
    • +
    • all - gather all table cell values with a data-math attribute that start with "all".
    • +
    +

    {formula} (defaults)

    +
      +
    • count - returns the count (length) of the data set.
    • +
    • sum - returns the sum of all values in the data set.
    • +
    • max - returns the maximum value in the data set.
    • +
    • min - returns the minimum values in the data set.
    • +
    • mean - returns the mean (average) of all values in the data set; it uses the sum formula in part of the calculation.
    • +
    • median - returns the median (middle value) of the data set.
    • +
    • mode - returns an array of the mode(s) (most frequent value or values) in the data set; an array is always returned, even if only one mode exists (see the second demo below).
    • +
    • range - returns the range (highest minus lowest value) of the data set.
    • +
    • varp - returns the variance of the data set (population).
    • +
    • vars - returns the variance of the data set (sample).
    • +
    • stdevp - returns the standard deviation of the data set (population).
    • +
    • stdevs - returns the standard deviation of the data set (sample).
    • +
    • custom (not a default) +
        +
      • Custom formulas can have any name
      • +
      • Return your result after making whatever calculation from the array of data passed to the formula
      • +
      • For example: +
        // adding a custom equation... named "product"
        +// access from data-math="row-product" (or "above-product", or "col-product")
        +$.tablesorter.equations['product'] = function(arry) {
        +    // multiple all array values together
        +    var product = 1;
        +    $.each(arry, function(i,v){
        +        // oops, we shouldn't have any zero values in the array
        +        if (v !== 0) {
        +            product *= v;
        +        }
        +    });
        +    return product;
        +};
        +
      • +
      +
    • +
    +

    Ignoring cells

    +
      +
    • Entire row: if the <tr> math data-attribute contains the keyword "ignore" then that entire row of cells will be skipped when building the array of data to be used for calculations. +
      <tr data-math="ignore"><td>1</td><td>2</td><td>3</td></tr>
      +
    • +
    • Cell: if the table cell math data-attribute contains the keyword "ignore" then that cell will be skipped when building the array of data to be used for calculations. +
      <td data-math="ignore">1</td>
      +
    • +
    • Column: set the widget math_ignore option with an array of zero-based column indexes of columns to ignore or skip when building the array of data for calculations. +
      math_ignore : [0,1]
      +
    • +
    +
    + +

    Mask Examples

    +
    + The formatting function can be used separately from the math widget: +
    // $.tablesorter.formatMask(mask, value, prefix, suffix);
    +$.tablesorter.formatMask('$#,##0.00 USD', 12345.678, 'prefix ', ' suffix');
    +// result: "prefix $12,345.68 USD suffix"
    +
      +
    • The $.tablesorter.formatMask function has the following parameters: +
        +
      • mask - please refer to the math_mask option for more details.
      • +
      • value - number to be formatted.
      • +
      • prefix - please refer to the math_prefix option for more details (v2.16.4).
      • +
      • suffix - please refer to the math_suffix option for more details (v2.16.4).
      • +
      +
    • +
    + +

    Experiment with the mask:

    + +
    
    +		
    + Value to use:
    + Prefix: ( add {content} to include the mask prefix )
    + Suffix: ( add {content} to include the mask suffix )
    + +
    + +
    + +

    + +

    Demo

    + +

    Row & Column Sums

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RegionSalesmanFastCarRapidZooSuperGlueGrand Total
    Column Totalscol-sumcol-sumcol-sumcol-sum
    Grand Totalall-sum
    MiddleJoseph$ 423$ 182$ 255row-sum
    MiddleLawrence$ 5,908$ 4,642$ 4,593row-sum
    MiddleMaria$ 6,502$ 3,969$ 5,408row-sum
    MiddleMatt$ 4,170$ 6,093$ 5,039row-sum
    Middle Totalabove-sumabove-sumabove-sumabove-sum
    NorthJoseph$ 3,643$ 5,846$ 6,574row-sum
    NorthLawrence$ 4,456$ 6,658$ 7,685row-sum
    NorthMaria$ 6,235$ 4,616.99$ 3,612.33row-sum
    NorthMatt$ 3,868$ 3,926$ 3,254row-sum
    North Totalabove-sumabove-sumabove-sumabove-sum
    WestJoseph$ 5,507$ 5,186$ 4,882row-sum
    WestLawrence$ 4,082$ 5,272$ 6,124row-sum
    WestMaria$ 5,520$ 5,461$ 4,872row-sum
    WestMatt$ 6,737$ 4,598$ 4,233row-sum
    West Totalabove-sumabove-sumabove-sumabove-sum
    + + +

    Math Formulas

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FormulaABCDEFResult (expected result)
    Default Formulas
    Count (row-count)101010102020
    Sum (row-sum)102010103020
    Max (row-max)20603015305
    Min (row-min)20603015305
    Mean (row-mean)102030103020
    Median (row-median)1053443
    Mode (row-mode)122232
    Mode (row-mode)122134
    Range (row-range)1-22460
    Variance [population] (row-varp)274554
    Standard Deviation [population] (row-stdevp)274554
    Variance [sample] (row-vars)274554
    Standard Deviation [sample] (row-stdevs)274554
    Custom Formulas
    Custom ( (A+B+C)*D - (E/F)*100 )5232012
    Product ( A*B*C*D*E*F )1234510
    + +

    Javascript

    +
    +
    
    +	
    + +

    Javascript

    +
    +
    
    +	
    + +

    CSS

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + +
    + + + + diff --git a/docs/example-widget-output.html b/docs/example-widget-output.html new file mode 100644 index 0000000..9bc2cf1 --- /dev/null +++ b/docs/example-widget-output.html @@ -0,0 +1,1035 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Output Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    + +

    Changes

    +
      +
    • In v2.22.2, +
        +
      • The data-attribute used by the output_dataAttrib can now be an empty string.
      • +
      • Update output_saveRows option, it now includes the ability to set a jQuery filter selector. +
          +
        • For example, if you want to only output rows with an active checkbox, set this option to '.checked' (default class added by the checkbox parser contained in the "parser-input-select.js" file).
        • +
        • To output only visible active checkboxes, set this option to '.checked:visible'.
        • +
        • To output rows without an active checkbox, set this option to ':not(.checked)', etc.
        • +
        • More details can be found in the options section.
        • +
        +
      • +
      • Fix issue with output_hiddenColumns causing an empty output.
      • +
      +
    • +
    • In v2.22.0, +
        +
      • Added the BOM back to the UTF-8 csv downloadable file to support unicode characters in Excel.
      • +
      • Add output_hiddenColumns which includes hidden columns in the output when true.
      • +
      +
    • +
    • In v2.21.0, added the output_includeFooter option.
    • +
    • In v2.17.5, the need to modify the server's content disposition no longer exists.
    • +
    • In v2.17.0, +
        +
      • Added the output_ignoreColumns option & modified the output_callback parameters.
      • +
      • Added output_duplicateSpans option to duplicate (when true) colspan & rowspan content across cells.
      • +
      +
    • +
    • In v2.16.4, added the output_encoding option.
    • +
    + +

    Requirements

    +
      +
    • This widget will only work in tablesorter version 2.8+ and jQuery version 1.7+.
    • +
    • To download a file with the set filename and extension, the server's Content-disposition needs to be set
    • +
    • This widget now uses a method available in modern browsers (IE10+) to download files without the need for server side modifications
    • +
    • Support in older browsers (IE9 and older) have not been throughly tested.
    • +
    + +

    Features & Usage

    +
      +
    • This widget can output the table data to: +
        +
      • JSON
      • +
      • Array of arrays
      • +
      • Text with any separator (comma, tab, etc).
      • +
      +
    • +
    • Rowspan and colspan are supported by this widget. Please take note of additional information in the "Rowspan and colspan" section below.
    • +
    • This demo uses Bootstrap to create the download button dropdown for each table allowing the user to choose the settings +
        +
      • Using Bootstrap was kind of a pain in the butt... any click inside would close the dropdown.
      • +
      • I am sure there are better alternatives as the download button and popup are all completely customizable.
      • +
      • The download dropdown code is probably overly complicated because it is set up for two tables & allows modifying almost all of the options.
      • +
      • The only thing needed to output the table code (download or open a popup) is to trigger the following event after all of your widget options are set as desired:
        $table.trigger('outputTable');
      • +
      +
    • +
    +

    Known Issues

    +
      +
    • Some versions of Safari do not fully support direct downloading, nor will you be able to save the file with the set file name; for more details please refer to this issue.
    • +
    +

    Credit

    + +
    + +

    Basic Setup

    +
    + Using the default settings of this widget will: +
      +
    • Output csv to a popup window.
    • +
    • Only include the last header row (if there are more than one rows).
    • +
    • Only include filtered rows (all rows will be included, even if the filter widget isn't being used).
    • +
    • Will only output the table cell text (ignoring any HTML).
    • +
    + Of course, all of the above behavior can be modified using the options.
    + This is an example of how to setup a table using only the default settings: +

    HTML

    +
    <button class="download">Get CSV</button>
    +<table class="tablesorter">
    +    <!-- .... -->
    +</table>
    +

    Script

    +
    $(function () {
    +    var $table = $('table');
    +
    +    $('.download').click(function(){
    +        // tell the output widget do it's thing
    +        $table.trigger('outputTable');
    +    });
    +
    +    $table.tablesorter({
    +        theme: 'blue',
    +        widgets: ['zebra', 'output']
    +    });
    +});
    + Modification of the .htaccess is no longer required +
    +

    .htaccess

    + The Content-disposition headers may need to be set in order to make downloads work properly in IE. So .htaccess can look like: +
    <FilesMatch "\.(?i:csv|txt)$">
    +	    ForceType application/octet-stream
    +	    Header set Content-Disposition attachment
    +	</FilesMatch>
    +
    +
    + +

    Setup Example (php)

    +
    + Thanks to TheSin- for sharing this setup which includes the necessary php to allow file download with the proper filename and extension (original Gist) +

    + +
    + +

    Rowspan and colspan

    +
    +
      +
    • Even though tablesorter does not currently support rowspan and colspan within the tbody (except in child rows), this widget does support them.

    • +
    • When the widget encounters a colspan: +
        +
      • The colspan will be processed such that the data will be applied to each cell as if the colspan did not exist. So a header row that looks like this: +
        <th>data</th><th colspan="2">values</th>
        + will produce an output like this: +
        data, values, values
        +
      • +
      • Important But, if a JSON output is chosen, the resulting object for a row cannot contain duplicate keys.
        +
        +
        [{ "data" : "0", "values" : "1", "values" : "2" }]
        +// becomes [{ "data" : "0", "values" : "2" }]
        + So, in order to fix this, any key (header name) with a colspan will have the column index added to the end (see the output_callbackJSON option). So the same HTML above will produce the following output: +
        [{ "data" : "0", "values" : "1", "values(2)" : "2" }]
        +
      • +
      +
      +
    • +
    • When the widget encounters a rowspan: +
        +
      • The rowspan will be processed such that the data will be applied to each cell as if the rowspan did not exist. So if two header rows looks like this: +
        <tr>
        +  <th rowspan="2">line</th>
        +  <th colspan="3">values</th>
        +</tr>
        +<tr>
        +  <th>value1</th>
        +  <th>value2</th>
        +  <th>value3</th>
        +</tr>
        + And the output_headerRows is true, the output will look like this: +
        line,values,values,values
        +line,value1,value2,value3
        +1,1.1,1.2,1.3
        +1,1.4,1.5,1.5
        +
      • +
      • + Important But, if a JSON output is chosen, and output_headerRows is set to false, only header names from the last row will be applied to the output. The HTML above will produce this output:
        +
        +
        [
        +  { "line" : "1", "value1" : "1.1", "value2" : "1.2", "value3" : "1.3" },
        +  { "line" : "1", "value1" : "1.4", "value2" : "1.5", "value3" : "1.5" }
        +]
        + If the output_headerRows is set to true, the header names from the second row will be applied to alternating rows and the header with a colspan will get uniques names using the output_callbackJSON option. So the same HTML above will produce the following output: +
        [
        +  { "line" : "1", "values" : "1.1", "values(2)" : "1.2", "values(3)" : "1.3" },
        +  { "line" : "1", "value1" : "1.4", "value2"    : "1.5", "value3"    : "1.5" }
        +]
        +
      • +
      +
    • + +
    +
    + +

    Options

    +
    +

    Output widget default options (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the option column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    ',' + This option allows you to set the output as JSON, Array, or change the separator between cell data with text output: +
    +
    + When the output is created, and it this option doesn't match either "json" or "array", each block of table cell data will be separated by this setting.
    +
    + This is the result with this option set to "," and with the table filtered with Rank : +
    +
    Rank,First,Last,Age,Total,Discount,Date
    +111,Peter,Parker,28,$9.99,20%,"Jul 6, 2006 8:14 AM"
    +166,Bruce Lee,Evans,22,$13.19,11%,"Jan 18, 2007 9:12 AM"
    + When this option is set to "array", this will be the resulting output: +
    [
    +    [ "Rank", "First", "Last", "Age", "Total", "Discount", "Date" ],
    +    [ "111", "Peter", "Parker", "28", "$9.99", "20%", "Jul 6, 2006 8:14 AM" ],
    +    [ "166", "Bruce Lee", "Evans", "22", "$13.19", "11%", "Jan 18, 2007 9:12 AM" ],
    +]
    Note this requires JSON.stringify, or the result will be a flattened array.
    +
    + And when this option is set to "json", the resulting output will be a valid JSON format:
    +
    [
    +    {
    +        "Rank" : "111",
    +        "First": "Peter",
    +        "Last": "Parker",
    +        "Age": "28",
    +        "Total": "$9.99",
    +        "Discount": "20%",
    +        "Date": "Jul 6, 2006 8:14 AM"
    +    }, {
    +        "Rank": "166",
    +        "First": "Bruce Lee",
    +        "Last": "Evans",
    +        "Age": "22",
    +        "Total": "$13.19",
    +        "Discount": "11%",
    +        "Date": "Jan 18, 2007 9:12 AM"
    +    }
    +]
    Note this also requires JSON.stringify, or the result will show [ [object Object], ... ] in the output. +
    +
    [ ] + Add the zero-based column index to this array to ignore specific columns (v2.17.0) +
    +
    + For example, to use this option to hide the first column, set it as follows: +
    output_ignoreColumns : [ 0 ]
    +
    + Note This option will work properly with tables that contain rowspans & colspans. +
    +
    output_hiddenColumnsfalse + Include hidden columns (using display: none) in the output (v2.22.0). +
    output_includeFooterfalse + Change this option to true to include the <tfoot> rows in the output (v2.21.0) +
    'data-name' + This option allows you to override any table cell (thead or tbody) text with the contents of this data-attribute (v2.22.2) +
    +
    +

    In the below example, the header text is obtained from this set data-attribute. If the data-attribute doesn't exist, then the header name is obtained from the actual header text.

    +

    The data-attribute can be an empty string (v2.22.2).

    +
    <thead>
    +	<tr>
    +		<th>Rank</th>
    +		<th data-name="First">First Name</th>
    +		<th data-name="Last">Last Name</th>
    +		<th>Age</th>
    +		<th>Total</th>
    +		<th>Discount</th>
    +		<th>Date</th>
    +	</tr>
    +</thead>
    +

    Notice in this output that the "First" and "Last" columns match the contents of the data-name attribute and not the header text:

    +
    Rank,First,Last,Age,Total,Discount,Date
    + * NOTE * The core plugin uses the data-text attribute for text extraction. If you want to use the same data for both, make the data-attributes match! +
    +
    false + Setting this option to true will include all header rows while processing a JSON output. +
    +
    + If this option is set to false, only the last row of the table header will be used as a key names for the tbody values; this does assume that the last table row in the header contains all of the header cell names & does not contain any colspan. +
    +
    'popup' + Change this option to either 'popup' or 'download' to set the destination of the output. +
    +
    + When setting this option, only the first letter is required ('p' or 'd') : +
    +
    output_delivery : 'p'
    +
    +
    'filtered' + Change this option to either 'filtered', 'visible', 'all' or (v2.22.2) a jQuery filter selector to set to match rows to be added to the output. +
    +
    +
      +
    • 'filtered' - output rows that have not been filtered by the filter widget (i.e. rows that do not have the "filtered" class applied; this class name is set by the filter_filteredRow widget option).
    • +
    • 'visible' - only output rows that are currently visible; rows hidden by pagination will not be included.
    • +
    • jQuery filter selector - output all rows that match the jQuery filter. +
        +
      • For example, '.checked', '.checked:visible' or :not(.checked) can be used; these examples match the class set by the checkbox parser table.config.checkboxClass class setting.
      • +
      • For reference, internally, the rows are filtered using this setting: $rows.filter( wo.output_saveRows ).
      • +
      • Instead of checking to see if output_saveRows works as a filter, the option is checked to see if it contains any of the following characters before it is used as a filter: +
          +
        • '.' (class selector)
        • +
        • '#' (id selector)
        • +
        • ':' (filter selectors, e.g. ':visible' or ':not()')
        • +
        • [ (start of an attribute selector)
        • +
        +
      • +
      +
    • +
    • 'all' - output all rows even if they are hidden. When the pager removeRows option is true, rows not visible do not exist in the DOM and therefore will not be included.
    • +
    +

    Even if this option is set to 'filtered' and the filter widget is not being used, all of the rows will be added to the output.

    +

    *NOTE* When setting this option,

    +
      +
    • Only the first letter is required for filtered ('f') or visible ('v') rows. +
      output_saveRows : 'f'
      +
    • +
    • If using a jQuery selector, it won't be recognized as a selector unless one of the characters (.#:[) is contained in the setting; if your filter is not working, or uses a charater not listed, then please contact me for support.
    • +
    • If no matches are found, all rows will be sent to the output.
    • +
    +
    +
    true + When true, colspan & rowspan content is duplicated in the output +
    +
    + By default, any tbody cells that are included in the colspan or rowspan will have the cell's content duplicated in the output. When set to false, the cells within the colspan or rowspan will be empty.
    + Here is an example of the second table output with this option set to false: +
    line,values,values,values
    +line,value1,value2,value3
    +1,1.1,1.2,1.3
    +,1.4,1.5,
    +2,2.1,2.2,2.3
    +,2.4,2.5,
    +3,3.1,3.2,3.3
    +,3.4,3.5,
    +4,4.1,,4.2
    +,,,4.3
    This option does not affect thead cells, they will always have duplicated content. +
    +
    '\u201c;' + When a table cell contains a quote, it needs to be modified to differentiate it from cell content that is wrapped in quotes. +
    +
    + Quotes are necessary to maintain the integrity of the output data when any cell content contains either the separator or carriage returns. In order to do this, this widget replaces any quotes within cell content with this character.
    +
    + By default, this replacement character is a left double quote (, shown as it's unicode equivalent '\u201c;'). +
    output_replaceQuote : '\u201c;' // left double quote
    + In the demo below, additional examples of a single quote (') and escaped double quote (\") are added as selectable buttons. + +
    Rank,First,Last,Age,Total,Discount,Date
    +1,Philip Aaron Wong,Johnson Sr Esq,25,$5.95,22%,"Jun 26, 2004 7:22 AM"
    +21,John,“Robin“\n\tHood,33,$19.99,25%,"Dec 10, 2002 5:14 AM"
    +013,Clark,“Old man“ Kent Sr.,18,$15.89,44%,"Jan 12, 2003 11:14 AM"
    +16,Jim,“Jimmy“ Franco,24,-$14.19,24%,"Jan 14, 2004 11:23 AM"
    +55,Dennis,“Charley“ Bronson,65,$123.00,32%,"Jan 20, 2001 1:12 PM"
    +
    +
    false + This option, if true tells the widget to include any HTML within the table cells. +
    +
    + Only cells within the table body will include HTML. The table header has a lot of extra markup for the sorting arrows, so it is automatically stripped of HTML. +
    +
    true + This option, if true tells the widget to remove any leading and trailing (white)space characters +
    +
    + Leading and trailing whitespace characters include newlines, spaces, non-breaking spaces and tabs. Any of these whitespace characters in the middle of the table cell will always be preserved.
    +
    + *NOTE* carriage returns in the middle of the table cell content will be stripped out if this option is set to true. +
    +
    false + This option, if true wrap the output of all table cell content in quotes. +
    +
    + This is the output of the widget when the age column is filtered for results in the range . +
    "Rank","First","Last","Age","Total","Discount","Date"
    +"1","Philip Aaron Wong","Johnson Sr Esq","25","$5.95","22%","Jun 26, 2004 7:22 AM"
    +"111","Peter","Parker","28","$9.99","20%","Jul 6, 2006 8:14 AM"
    +"21","John","'Robin'\n\tHood","33","$19.99","25%","Dec 10, 2002 5:14 AM"
    +"9","Martha","delFuego","25","$22.09","12%","Jun 11, 2011 10:55 AM"
    + Notice that every block of data is wrapped in a quote. When this option is false, only blocks that contain a newline or separator (comma, by default) will be wrapped in quotes. Here is the same data set without this option set: +
    Rank,First,Last,Age,Total,Discount,Date
    +1,Philip Aaron Wong,Johnson Sr Esq,25,$5.95,22%,"Jun 26, 2004 7:22 AM"
    +111,Peter,Parker,28,$9.99,20%,"Jul 6, 2006 8:14 AM"
    +21,John,'Robin'\n\tHood,33,$19.99,25%,"Dec 10, 2002 5:14 AM"
    +9,Martha,delFuego,25,$22.09,12%,"Jun 11, 2011 10:55 AM"
    + Only the dates, which contain commas, are wrapped in quotes. +
    +
    'width=500,height=300'If the data is sent to a popup window, the features set by this option are applied (do not include any spaces). +
    +
    + Set the desired popup window features within this string. For a full list of features, please refer to the Mozilla Developer Network: Window.open documentation page (look for strWindowFeatures parameters).
    +
    + The <textarea> within the popup window is set with 100% width and height. +
    +
    output_saveFileName'mytable.csv'When downloading, this option sets the filename of the output.
    {see description}Return true in this callback to continue the download or open the popup (v2.17.0). +
    +
    + As of v2.17.0, the callback function was modified to pass two parameters: +
      +
    • config - the table.config settings.
    • +
    • data - the output data as a string
    • +
    + Default setting: +
    function(config, data){ return true; }
    + After table processing has completed, this callback function is exectued. If true is not returned, the processed data will not open a popup, nor download the data. +
    output_callback : function(config, data) {
    +    // send output to the console only
    +    console.log(data);
    +    return false;
    +}
    +
    +
    {see description}JSON callback executed when a colspan is encountered in the header. +
    +
    + Default setting & how to use this option: +
    output_callbackJSON : function($cell, txt, cellIndex) {
    +    return txt + '(' + (cellIndex + col) + ')';
    +}
    For more details on why this option is necessary, see the "Rowspan and colspan" section above. +
    +
    {see description}Default encoding setting (2.16.4; 2.17.5) +
    +
    + As of 2.17.5, this option no longer needs to be modified to specifically make this widget download files that will work in Excel.
    +
    + The method used to download has been completely changed. The downloads still need an encoding setting, but this option is now set to a default of +
    output_encoding : 'data:application/octet-stream;charset=utf8,'
    +
    + The information below is no longer relavant: +
    + With the default settings (utf-8 no BOM), Excel does not properly encode accented characters unless the csv file is imported. Depending on the characters used, there are various methods which will allow proper encoding, but no one method is ideal. So this option can be set to allow the user to try different encodings. Set it as follows: +
    // output data type (with BOM or Windows-1252 is needed for excel)
    +// NO BOM   : 'data:text/csv;charset=utf8,'
    +// With BOM : 'data:text/csv;charset=utf8,%EF%BB%BF'
    +// WIN 1252 : 'data:text/csv;charset=windows-1252,' // ANSI (subset of ISO-8859-1)
    +output_encoding : 'data:text/csv;charset=utf8,'
    Note The commas are important! +
    +
    +
    + Note If you need to change the carriage return and/or the tab replacement strings, modify them as follows (changed in v2.21.2): +
    +
    $.tablesorter.output.replaceCR = '\x0d\x0a';
    +$.tablesorter.output.replaceTab = '\x09';
    +
    +
    + +
    + +

    + +

    Demo

    +
    + Search in the Discount column
    +
    + +
    +

    Table showing filter & pager support

    +
    + + + +
    + + + +
    +
    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankFirst NameLast NameAgeTotalDiscountDate
    RankFirst NameLast NameAgeTotalDiscountDate
    1Philip Aaron WongJohnson Sr Esq25$5.9522%Jun 26, 2004 7:22 AM
    11Aaron"doc" Hibert12$2.995%Aug 21, 2009 12:21 PM
    12Brandon ClarkHenry Jr51$42.2918%Oct 13, 2000 1:15 PM
    111PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    21John "Robin"
    Hood
    33$19.9925%Dec 10, 2002 5:14 AM
    013Clark"Old man" Kent Sr.18$15.8944%Jan 12, 2003 11:14 AM
    005BruceAlmighty Esq45$153.1944%Jan 18, 2021 9:12 AM
    10AlexDumass13$5.294%Jan 8, 2012 5:11 PM
    16Jim"Jimmy" Franco24-$14.1924%Jan 14, 2004 11:23 AM
    166Bruce LeeEvans22$13.1911%Jan 18, 2007 9:12 AM
    100Brenda DexterMcMasters18$55.2015%Feb 12, 2010 7:23 PM
    55Dennis"Charley" Bronson65$123.0032%Jan 20, 2001 1:12 PM
    9MarthadelFuego25$22.0912%Jun 11, 2011 10:55 AM
    +
    + +
    +

    Table showing output widget rowspan & colspan support

    +
    + + + +
    + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    linevalues
    value1value2value3
    11.11.21.3
    1.41.5
    22.12.22.3
    2.42.5
    33.13.23.3
    3.43.5
    44.14.2
    4.3
    +
    +
    + +

    Script

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + +
    + + + diff --git a/docs/example-widget-pager-ajax.html b/docs/example-widget-pager-ajax.html new file mode 100644 index 0000000..b55ed12 --- /dev/null +++ b/docs/example-widget-pager-ajax.html @@ -0,0 +1,378 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Pager Widget - Ajax + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • This pager WIDGET can not be applied to the original tablesorter.
    • +
    • Do not use this widget along with the pager plugin.
    • +
    • The pager.css file also works with this pager widget.
    • +
    • This widget is still in development as it has not been throughly tested.
    • +
    • Extensive documentation has not been included, as all functioning is essentially identical to the pager addon, but here are some important differences: +
        +
      • All of the options are now set within the widgetOptions.
      • +
      • Most option names have only been modified by adding pager_ as a prefix.
      • +
      • Exceptions include moving all applied css class names into a pager_css option and all selectors into pager_selectors, including the original container option.
      • +
      • See the Javascript code below for a full example of how to use this widget with ajax.
      • +
      +
    • +
    • The "ID" column has a default filter setting of ">30" and a descending sort, but neither is applied as this demo is not connected a server (just a basic JSON file).
    • +
    +

    + +

    Demo

    +Original Ajax url:
    +Current Ajax url: +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + First + Prev + + Next + Last + +
    12345
    12345
    + First + Prev + + Next + Last + +
    + +

    Javascript

    +
    +
    
    +	
    + +

    CSS

    +
    +
    /* pager wrapper, div */
    +.pager {
    +  padding: 5px;
    +}
    +/* pager wrapper, in thead/tfoot */
    +td.pager {
    +  background-color: #e6eeee;
    +}
    +/* pager navigation arrows */
    +.pager img {
    +  vertical-align: middle;
    +  margin-right: 2px;
    +}
    +/* pager output text */
    +.pager .pagedisplay {
    +  font-size: 11px;
    +  padding: 0 5px 0 5px;
    +  width: 50px;
    +  text-align: center;
    +}
    +
    +/*** loading ajax indeterminate progress indicator ***/
    +#tablesorterPagerLoading {
    +  background: rgba(255,255,255,0.8) url(icons/loading.gif) center center no-repeat;
    +  position: absolute;
    +  z-index: 1000;
    +}
    +
    +/*** css used when "updateArrows" option is true ***/
    +/* the pager itself gets a disabled class when the number of rows is less than the size */
    +.pager.disabled {
    +  display: none;
    +}
    +/* hide or fade out pager arrows when the first or last row is visible */
    +.pager img.disabled {
    +  /* visibility: hidden */
    +  opacity: 0.5;
    +  filter: alpha(opacity=50);
    +}
    +
    + +

    HTML

    +
    +
    <!-- jQuery -->
    +<script src="js/jquery-latest.min.js"></script>
    +
    +<!-- Tablesorter: required -->
    +<link href="css/theme.blue.css" rel="stylesheet">
    +<script src="js/jquery.tablesorter.js"></script>
    +<script src="js/jquery.tablesorter.widgets.js"></script>
    +
    +<!-- Tablesorter: pager widget -->
    +<link href="css/jquery.tablesorter.pager.css" rel="stylesheet">
    +<script src="js/widget-pager.js"></script>
    +
    +<table class="tablesorter">
    +  <thead>
    +    <tr>
    +      <td class="pager" colspan="5">
    +        <img src="../addons/pager/icons/first.png" class="first"/>
    +        <img src="../addons/pager/icons/prev.png" class="prev"/>
    +        <span class="pagedisplay"></span> <!-- this can be any element, including an input -->
    +        <img src="../addons/pager/icons/next.png" class="next"/>
    +        <img src="../addons/pager/icons/last.png" class="last"/>
    +        <select class="pagesize">
    +          <option value="25">25</option>
    +        </select>
    +      </td>
    +    </tr>
    +    <tr>
    +      <th>1</th> <!-- thead text will be updated from the JSON; make sure the number of columns matches the JSON data -->
    +      <th>2</th>
    +      <th>3</th>
    +      <th>4</th>
    +      <th>5</th>
    +    </tr>
    +  </thead>
    +  <tfoot>
    +    <tr>
    +      <th>1</th> <!-- tfoot text will be updated at the same time as the thead -->
    +      <th>2</th>
    +      <th>3</th>
    +      <th>4</th>
    +      <th>5</th>
    +    </tr>
    +    <tr>
    +      <td class="pager" colspan="5">
    +        <img src="../addons/pager/icons/first.png" class="first"/>
    +        <img src="../addons/pager/icons/prev.png" class="prev"/>
    +        <span class="pagedisplay"></span> <!-- this can be any element, including an input -->
    +        <img src="../addons/pager/icons/next.png" class="next"/>
    +        <img src="../addons/pager/icons/last.png" class="last"/>
    +        <select class="pagesize">
    +          <option value="25">25</option>
    +        </select>
    +      </td>
    +    </tr>
    +  </tfoot>
    +  <tbody> <!-- tbody will be loaded via JSON -->
    +  </tbody>
    +</table>
    + +
    + + + +
    + + + + + diff --git a/docs/example-widget-pager.html b/docs/example-widget-pager.html new file mode 100644 index 0000000..e2880bd --- /dev/null +++ b/docs/example-widget-pager.html @@ -0,0 +1,468 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Pager Widget + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • In v2.19.0, added pageAndSize method which allows setting both the pager page & size.
    • +
    • In v2.17.6, added {startRow:input} and {page:input} variables to the output option.

    • + +
    • This pager WIDGET can not be applied to the original tablesorter.
    • +
    • Do not use this widget along with the pager plugin.
    • +
    • The pager.css file also works with this pager widget.
    • +
    • This widget is still in development as it has not been throughly tested.
    • +
    • Extensive documentation has not been included, as all functioning is essentially identical to the pager addon, but here are some important differences: +
        +
      • All of the options are now set within the widgetOptions.
      • +
      • Pager events (pagerChange pagerComplete pagerInitialized pageMoved) now return table.config instead of table.config.pager.
      • +
      • Most option names have only been modified by adding pager_ as a prefix.
      • +
      • Exceptions include moving all applied css class names into a pager_css option and all selectors into pager_selectors, including the original container option.
      • +
      • Because I stopped trying so hard to make widgets compatible with jQuery v1.2.6, this widget requires at least v1.3+.
      • +
      • See the Javascript code below for a full example.
      • +
      +
    • +
    +

    + +

    Triggered Events

    +
      +
    • Pager events will appear here.
    • +
    •  
    • +
    •  
    • +
    + +

    Demo

    +
    + +

    +
    + First + Prev + + Next + Last + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Mathematicsmale8277079
    Student24Languagesfemale100911382
    Student25Mathematicsmale22968253
    Student26Languagesfemale37295659
    Student27Mathematicsmale86826923
    Student28Languagesfemale4425431
    Student29Mathematicsmale77472238
    Student30Languagesfemale19352310
    Student31Mathematicsmale90271750
    Student32Languagesfemale60753338
    Student33Mathematicsmale4313715
    Student34Languagesfemale77978144
    Student35Mathematicsmale5815195
    Student36Languagesfemale70617094
    Student37Mathematicsmale6036184
    Student38Languagesfemale6339011
    Student39Mathematicsmale50463238
    Student40Languagesfemale5175253
    Student41Mathematicsmale43342878
    Student42Languagesfemale11896095
    Student43Mathematicsmale48921888
    Student44Languagesfemale8225973
    Student45Mathematicsmale91733739
    Student46Languagesfemale481210
    Student47Mathematicsmale8910611
    Student48Languagesfemale90322118
    Student49Mathematicsmale42494972
    Student50Languagesfemale56376754
    + +
    + First + Prev + + Next + Last + + +
    + +

    Javascript

    +
    +
    
    +	
    + +

    CSS

    +
    +
    /* pager wrapper, div */
    +.tablesorter-pager {
    +  padding: 5px;
    +}
    +/* pager wrapper, in thead/tfoot */
    +td.tablesorter-pager {
    +  background-color: #e6eeee;
    +  margin: 0; /* needed for bootstrap .pager gets a 18px bottom margin */
    +}
    +/* pager navigation arrows */
    +.tablesorter-pager img {
    +  vertical-align: middle;
    +  margin-right: 2px;
    +  cursor: pointer;
    +}
    +
    +/* pager output text */
    +.tablesorter-pager .pagedisplay {
    +  padding: 0 5px 0 5px;
    +  width: 50px;
    +  text-align: center;
    +}
    +
    +/* pager element reset (needed for bootstrap) */
    +.tablesorter-pager select {
    +  margin: 0;
    +  padding: 0;
    +}
    +
    +/*** css used when "updateArrows" option is true ***/
    +/* the pager itself gets a disabled class when the number of rows is less than the size */
    +.tablesorter-pager.disabled {
    +  display: none;
    +}
    +/* hide or fade out pager arrows when the first or last row is visible */
    +.tablesorter-pager .disabled {
    +  /* visibility: hidden */
    +  opacity: 0.5;
    +  filter: alpha(opacity=50);
    +  cursor: default;
    +}
    +
    + +

    HTML

    +
    +
    <!-- jQuery -->
    +<script src="js/jquery-latest.min.js"></script>
    +
    +<!-- Tablesorter: required -->
    +<link href="css/theme.blue.css" rel="stylesheet">
    +<script src="js/jquery.tablesorter.js"></script>
    +<script src="js/jquery.tablesorter.widgets.js"></script>
    +
    +<!-- Tablesorter: pager widget -->
    +<link href="css/jquery.tablesorter.pager.css" rel="stylesheet">
    +<script src="js/widget-pager.js"></script>
    +
    +<table class="tablesorter">
    +<!-- view page source to see the entire table -->
    +</table>
    +
    +<!-- pager -->
    +<div id="pager" class="pager">
    +  <form>
    +    <img src="first.png" class="first"/>
    +    <img src="prev.png" class="prev"/>
    +    <span class="pagedisplay"></span> <!-- this can be any element, including an input -->
    +    <img src="next.png" class="next"/>
    +    <img src="last.png" class="last"/>
    +    <select class="pagesize">
    +      <option value="10">10</option>
    +      <option value="20">20</option>
    +      <option value="30">30</option>
    +      <option value="40">40</option>
    +    </select>
    +  </form>
    +</div>
    + +
    + + +

    Pager Change Log

    + + + + +
    + + + + diff --git a/docs/example-widget-print.html b/docs/example-widget-print.html new file mode 100644 index 0000000..b02c947 --- /dev/null +++ b/docs/example-widget-print.html @@ -0,0 +1,324 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Print Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • In v2.17.2, the print popup window now closes with the dialog window & jQuery version requirement was changed from v1.7+ to v1.2+.
    • +
    • + In v2.17.0, added the print_callback option.
      +
      +
    • +
    • This widget will only work in tablesorter version 2.8+ and jQuery version 1.7+ 1.2.6+ (v2.17.2; but filter & columnSelector widgets still require jQuery 1.7+).
    • +
    • The user can print all, visible or filtered rows. And, choose to print all or selected columns (using the columnSelector widget).
    • +
    • By default, the widget is set to only print filtered rows & visible columns.
    • +
    +
    + +

    Options

    +
    +

    Print widget default options (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the option column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    +
    + +

    Method

    +
    +
      +
    • To make the print widget work programmatically, trigger a "printTable" event. +
      $('.print').click(function(){
      +	$('.tablesorter').trigger('printTable');
      +});
      +
    • +
    +
    + +
    + +

    + +

    Demo

    +
    Print
    + +
    + + +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameCityAgeTotalDiscountDate
    AaronJohnson SrAtlanta35$5.9522%Jun 26, 2004 7:22 AM
    AaronJohnsonYuma12$2.995%Aug 21, 2009 12:21 PM
    ClarkHenry JrTampa51$42.2918%Oct 13, 2000 1:15 PM
    DenniHenryNew York28$9.9920%Jul 6, 2006 8:14 AM
    JohnHoodBoston33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent SrLos Angeles18$15.8944%Jan 12, 2003 11:14 AM
    PeterKent EsqSeattle45$153.1944%Jan 18, 2021 9:12 AM
    PeterJohnsMilwaukee13$5.294%Jan 8, 2012 5:11 PM
    AaronEvanChicago24$14.1914%Jan 14, 2004 11:23 AM
    BruceEvansUpland22$13.1911%Jan 18, 2007 9:12 AM
    ClarkMcMastersPheonix18$55.2015%Feb 12, 2010 7:23 PM
    DennisMastersIndianapolis65$123.0032%Jan 20, 2001 1:12 PM
    JohnHoodFort Worth25$22.0917%Jun 11, 2011 10:55 AM
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + +
    + + + diff --git a/docs/example-widget-reflow.html b/docs/example-widget-reflow.html new file mode 100644 index 0000000..2347110 --- /dev/null +++ b/docs/example-widget-reflow.html @@ -0,0 +1,719 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Table Reflow Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • This widget will only work in tablesorter version 2.8+ and jQuery version 1.7+.
    • +
    • The required css, shown below, is needed to make this widget work, but is completely customizable.
    • +
    • This demo sets the reflow breakpoint to 35em; so you'll need to resize your browser window to see this widget in action.
    • +
    • This widget is compatible with the column selector widget; but please note: +
        +
      • When a column is hidden, it will not show up when the table reflow occurs
      • +
      • For an example, see the second demo "Reflow + columnSelector widget" below.
      • +
      • The column selector widget, by default, has an additional breakpoint at "30em". So if the column selector is set to "Auto" and you continue to reduce the browser width after the table reflows, you'll see "Geometry" row disappear.
      • +
      +
    • +
    • It may not have been necessary to create two versions of this widget, but it was done because: +
        +
      • The first "reflow" widget does not add additional content to the tbody table cells, but it did not work well when attempting to add multiple content rows within the data-attribute. It would work if the css explicitly has the content set with a break like this (ref): +
        content: "row1 \A row2";
        + But sadly, this method does not work when a data-attribute with the same content is used: +
        content: attr(data-title);
        + The second method ignores the backslash and shows "row1 \A row2" +
      • +
      • Update: After some discussion in bugzilla, I discovered that it is possible to add multiple lines of content usigin a data-attribute by setting a white-space: pre; css definition and using &#10 instead of \A (demo), but I think I'll keep the second reflow version because it actually allows styling.
      • +
      • Adding bold elements to every table tbody cell is the method used by jQuery Mobile; so, a second reflow widget "reflow2" was created to do the same, and work properly with a thead containing multiple rows.
      • +
      +
    • +
    • + If you do not want the sortable headers to show when the table reflows, include this css within the media query:
      +
      +
      table.ui-table-reflow thead { display: none; }
      +
    • +
    +
    + +

    Reflow Widget

    +
    +
      +
    • This version adds a data-title attribute (modifiable by the reflow_dataAttrib option), to every table body cell.
    • +
    • The required css shows the contents of this data-attribute when the browser width reaches the set break point.
    • +
    • So, this widget does not add any additional content to the table cells; which might be preferred if the table content should not be changed.
    • +
    • Do not use this version of the widget for a table with more than one header row.
    • +
    + +

    Reflow widget default options (added inside of tablesorter widgetOptions)

    + + + + + + + + + + + + + + + + + + + + +
    OptionDescription
    reflow_className + This class name is added to the table to make it responsive. The class name is the same as that used by jQuery Mobile.
    +
    +
    <table class="tablesorter tablesorter-blue ui-table-reflow">...</table>
    +
    + Default value: "ui-table-reflow" +
    reflow_headerAttrib + Set this option to use your desired data-attribute. The set data-attribute contains the alternative header title added to every table body cell when the table reflows.
    +
    + For example, the "Sex" column below is renamed to "Gender" within the reflow cells: +
    <th data-name="Gender">Sex</th>
    +
    + Default value: "data-name" +
    reflow_dataAttrib + Set this option to use your desired data-attribute which is added to every table body cell. It will contain the header name which is shown once the table reflows.
    +
    + For example, all of table body cells will show the contents from the set data-attribute when the table reflows: +
    <td data-title="Gender">female</td>
    +
    + Default value: "data-title" +
    +
    + +

    Reflow2 Widget

    +
    +
      +
    • This version of the reflow widget adds a bold element (<b>), containing the header cell name, to every table body cell.
    • +
    • The required css shows these elements when the browser width reaches the set break point.
    • +
    • Use this version of the widget for a table with more than one header row.
    • +
    • So, this widget does add additional content to the table tbody cells; this might not be preferred if the table content should not be changed.
    • +
    • If an update occurs, this widget will remove all cell elements, and replace them, even if the headers have changed.
    • +
    • In very large tables, initialization of the table may be slightly delayed.
    • +
    + +

    Reflow2 widget default options (added inside of tablesorter widgetOptions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDescription
    reflow2_className + This class name is added to the table to make it responsive. The class name is the same as that used by jQuery Mobile.
    +
    +
    <table class="tablesorter tablesorter-blue ui-table-reflow">...</table>
    +
    + Default value: "ui-table-reflow" +
    reflow2_classIgnore + Set this option to use your desired class name. Any header cell with this class name will have it's contents ignored.
    +
    + For example, this is the "Paris" header cell in table3 below: +
    <th class="ui-table-reflow-ignore sorter-false">Paris</th>
    +
    + Default value: "ui-table-reflow-ignore" +
    reflow2_headerAttrib + Set this option to use your desired data-attribute. The set data-attribute contains the alternative header title added to every table body cell when the table reflows.
    +
    + For example, the "Sex" column below is renamed to "Gender" within the reflow cells: +
    <th data-name="Gender">Sex</th>
    +
    + Default value: "data-name" +
    reflow2_labelClass + Set this option to use your desired class name.
    +
    + When the table reflows, the bold element (<b>) with this class name will be revealed; it must also be defined within the media query to display this element as an "inline-block", so it shares the row with the cell content +

    CSS

    +
    /* additional selectors needed to increase css specificity */
    +table.ui-table-reflow .ui-table-cell-label {
    +  padding: .4em;
    +  min-width: 30%;
    +  display: inline-block;
    +  margin: -.4em 1em -.4em -.4em;
    +}
    +

    HTML

    +
    <th>
    +	<b class="remove-me ui-table-cell-label">Month</b>
    +	Jaunuary
    +</th>
    +
    + Default value: "ui-table-cell-label" +
    reflow2_labelTop + Set this option to use your desired class name.
    +
    + When the table reflows, the all upper header cell content is also included in every corresponding column table cell within a bold element (<b>); it must also be defined within the media query to display this element as a "block" +

    CSS

    +
    /* additional selectors needed to increase css specificity */
    +table.ui-table-reflow .ui-table-cell-label.ui-table-cell-label-top {
    +  display: block;
    +  padding: .4em 0;
    +  margin: .4em 0;
    +  text-transform: uppercase;
    +  font-size: .9em;
    +  font-weight: 400;
    +}
    +

    HTML

    +
    <td>
    +	<b class="remove-me ui-table-cell-label ui-table-cell-label-top">Average Temperatures (C)</b>
    +	<b class="remove-me ui-table-cell-label">Minimum Temp</b>
    +	3
    +</td>
    +
    +
    + Default value: "ui-table-cell-label-top" +
    + +
    + +

    Required CSS

    +
    + The reflow widgets require the following css to hide/show header cell content within each table cell. Remove the css for whichever reflow widget that is not being used, as desired.
    +
    +
    /* REQUIRED CSS: change your reflow breakpoint here (35em below) */
    +@media ( max-width: 35em ) {
    +
    +	/* uncomment out the line below if you don't want the sortable headers to show */
    +	/* table.ui-table-reflow thead { display: none; } */
    +
    +	/* css for reflow & reflow2 widgets */
    +	.ui-table-reflow td,
    +	.ui-table-reflow th {
    +		-webkit-box-sizing: border-box;
    +		-moz-box-sizing: border-box;
    +		box-sizing: border-box;
    +		float: right;
    +		/* if not using the stickyHeaders widget (not the css3 version)
    +		 * the "!important" flag, and "height: auto" can be removed */
    +		width: 100% !important;
    +		height: auto !important;
    +	}
    +
    +	/* reflow widget only */
    +	.ui-table-reflow tbody td[data-title]:before {
    +		color: #469;
    +		font-size: .9em;
    +		content: attr(data-title);
    +		float: left;
    +		width: 50%;
    +		white-space: pre-wrap;
    +		text-align: bottom;
    +		display: inline-block;
    +	}
    +
    +	/* reflow2 widget only */
    +	table.ui-table-reflow .ui-table-cell-label.ui-table-cell-label-top {
    +		display: block;
    +		padding: .4em 0;
    +		margin: .4em 0;
    +		text-transform: uppercase;
    +		font-size: .9em;
    +		font-weight: 400;
    +	}
    +	table.ui-table-reflow .ui-table-cell-label {
    +		padding: .4em;
    +		min-width: 30%;
    +		display: inline-block;
    +		margin: -.4em 1em -.4em -.4em;
    +	}
    +
    +} /* end media query */
    +
    +/* reflow2 widget */
    +.ui-table-reflow .ui-table-cell-label {
    +	display: none;
    +}
    +
    + +
    + +

    + +

    Demo (Pick a table width or resize the browser window)

    +

    Reflow widget only

    + Set table width: +
      +
    • Auto
    • +
    • +
    • +
    • +
    • +
    • +
    + +
    + +
    + +

    Reflow + columnSelector widget

    + Set table width: +
      +
    • Auto
    • +
    • +
    • +
    • +
    • +
    • +
    + +
    + +
    + +

    Reflow2 widget (multiple thead rows)

    + Set table width: +
      +
    • Auto
    • +
    • +
    • +
    • +
    • +
    • +
    + +
    + +
    + +
    + +

    HTML

    +
    +
    <h3>Reflow widget only</h3>
    +<table id="table1">
    +  <thead>
    +    <tr>
    +      <th>Rank</th>
    +      <th>Age</th>
    +      <th>Total</th>
    +      <th>Discount</th>
    +      <th>Date</th>
    +    </tr>
    +  </thead>
    +  <tbody>
    +    <tr><td>1</td><td>25</td><td>$5.95</td><td>22%</td><td>Jun 26, 2013 7:22 AM</td></tr>
    +    <tr><td>11</td><td>12</td><td>$82.99</td><td>5%</td><td>Aug 21, 2013 12:21 PM</td></tr>
    +    <tr><td>12</td><td>51</td><td>$99.29</td><td>18%</td><td>Oct 13, 2013 1:15 PM</td></tr>
    +    <tr><td>51</td><td>28</td><td>$9.99</td><td>20%</td><td>Jul 6, 2013 8:14 AM</td></tr>
    +    <tr><td>21</td><td>33</td><td>$19.99</td><td>25%</td><td>Dec 10, 2012 5:14 AM</td></tr>
    +    <tr><td>013</td><td>18</td><td>$65.89</td><td>45%</td><td>Jan 12, 2013 11:14 AM</td></tr>
    +    <tr><td>005</td><td>45</td><td>$153.19</td><td>45%</td><td>Jan 18, 2014 9:12 AM</td></tr>
    +    <tr><td>10</td><td>3</td><td>$5.29</td><td>4%</td><td>Jan 8, 2013 5:11 PM</td></tr>
    +    <tr><td>16</td><td>24</td><td>$14.19</td><td>14%</td><td>Jan 14, 2014 11:23 AM</td></tr>
    +    <tr><td>66</td><td>22</td><td>$13.19</td><td>11%</td><td>Jan 18, 2013 9:12 AM</td></tr>
    +    <tr><td>100</td><td>18</td><td>$55.20</td><td>15%</td><td>Feb 12, 2013 7:23 PM</td></tr>
    +    <tr><td>55</td><td>65</td><td>$123.00</td><td>32%</td><td>Jan 20, 2014 1:12 PM</td></tr>
    +    <tr><td>9</td><td>25</td><td>$22.09</td><td>17%</td><td>Jun 11, 2013 10:55 AM</td></tr>
    +    <tr><td>13</td><td>12</td><td>$19.99</td><td>18%</td><td>Jan 20, 2014 7:45 PM</td></tr>
    +    <tr><td>73</td><td>58</td><td>$129.19</td><td>39%</td><td>Jan 20, 2014 10:11 AM</td></tr>
    +  </tbody>
    +</table>
    +
    +<h3>Reflow   columnSelector widget</h3>
    +<!-- This selector markup is completely customizable -->
    +<div class="columnSelectorWrapper">
    +  <input id="colSelect1" type="checkbox" class="hidden">
    +  <label class="columnSelectorButton" for="colSelect1">Column</label>
    +  <div id="columnSelector" class="columnSelector">
    +    <!-- this div is where the column selector is added -->
    +  </div>
    +</div> (When "Auto" is set, the table becomes responsive; resize the browser window to see it work)
    +
    +<table id="table2">
    +  <thead>
    +    <tr>
    +      <th data-priority="critical">Name</th>
    +      <th data-priority="critical">Major</th>
    +      <th data-priority="6" data-name="Gender">Sex</th>
    +      <th data-priority="4">English</th>
    +      <th data-priority="5">Japanese</th>
    +      <th data-priority="3">Calculus</th>
    +      <th data-priority="2">Geometry</th>
    +    </tr>
    +  </thead>
    +  <tfoot>
    +    <tr><th>Name</th><th>Major</th><th>Sex</th><th>English</th><th>Japanese</th><th>Calculus</th><th>Geometry</th></tr>
    +  </tfoot>
    +  <tbody>
    +    <tr><td>Student03</td><td>Languages</td><td>female</td><td>85</td><td>95</td><td>80</td><td>85</td></tr>
    +    <tr><td>Student04</td><td>Languages</td><td>male</td><td>60</td><td>55</td><td>100</td><td>100</td></tr>
    +    <tr><td>Student05</td><td>Languages</td><td>female</td><td>68</td><td>80</td><td>95</td><td>80</td></tr>
    +    <tr><td>Student12</td><td>Mathematics</td><td>female</td><td>100</td><td>75</td><td>70</td><td>85</td></tr>
    +    <tr><td>Student13</td><td>Languages</td><td>female</td><td>100</td><td>80</td><td>100</td><td>90</td></tr>
    +    <tr><td>Student14</td><td>Languages</td><td>female</td><td>50</td><td>45</td><td>55</td><td>90</td></tr>
    +    <tr><td>Student15</td><td>Languages</td><td>male</td><td>95</td><td>35</td><td>100</td><td>90</td></tr>
    +    <tr><td>Student16</td><td>Languages</td><td>female</td><td>100</td><td>50</td><td>30</td><td>70</td></tr>
    +    <tr><td>Student17</td><td>Languages</td><td>female</td><td>80</td><td>100</td><td>55</td><td>65</td></tr>
    +    <tr><td>Student18</td><td>Mathematics</td><td>male</td><td>30</td><td>49</td><td>55</td><td>75</td></tr>
    +    <tr><td>Student19</td><td>Languages</td><td>male</td><td>68</td><td>90</td><td>88</td><td>70</td></tr>
    +    <tr><td>Student20</td><td>Mathematics</td><td>male</td><td>40</td><td>45</td><td>40</td><td>80</td></tr>
    +    <tr><td>Student01</td><td>Languages</td><td>male</td><td>80</td><td>70</td><td>75</td><td>80</td></tr>
    +    <tr><td>Student02</td><td>Mathematics</td><td>male</td><td>90</td><td>88</td><td>100</td><td>90</td></tr>
    +    <tr><td>Student06</td><td>Mathematics</td><td>male</td><td>100</td><td>99</td><td>100</td><td>90</td></tr>
    +    <tr><td>Student07</td><td>Mathematics</td><td>male</td><td>85</td><td>68</td><td>90</td><td>90</td></tr>
    +    <tr><td>Student08</td><td>Languages</td><td>male</td><td>100</td><td>90</td><td>90</td><td>85</td></tr>
    +    <tr><td>Student09</td><td>Mathematics</td><td>male</td><td>80</td><td>50</td><td>65</td><td>75</td></tr>
    +    <tr><td>Student10</td><td>Languages</td><td>male</td><td>85</td><td>100</td><td>100</td><td>90</td></tr>
    +    <tr><td>Student11</td><td>Languages</td><td>male</td><td>86</td><td>85</td><td>100</td><td>100</td></tr>
    +  </tbody>
    +</table>
    +
    +<h3>Reflow2 widget (multiple thead rows)</h3>
    +<table id="table3">
    +  <thead>
    +    <tr>
    +      <th class="ui-table-reflow-ignore sorter-false">Paris</th>
    +      <th colspan="2">Average Temperatures (C)</th>
    +      <th colspan="2">Average Rainfall</th>
    +    </tr>
    +    <tr>
    +      <th>Month</th>
    +      <th>Minimum Temp</th>
    +      <th>Maximum Temp</th>
    +      <th>Precipitaion (mm)</th>
    +      <th>Rainfall Days</th>
    +    </tr>
    +  </thead>
    +  <tbody>
    +    <tr><th>Jaunuary</th><td>3</td><td>8</td><td>17.8</td><td>10</td></tr>
    +    <tr><th>February</th><td>2</td><td>9</td><td>21.7</td><td>9</td></tr>
    +    <tr><th>March</th><td>4</td><td>13</td><td>24.2</td><td>10</td></tr>
    +    <tr><th>April</th><td>6</td><td>15</td><td>24.6</td><td>11</td></tr>
    +    <tr><th>May</th><td>10</td><td>20</td><td>26.2</td><td>10</td></tr>
    +    <tr><th>June</th><td>13</td><td>23</td><td>25.1</td><td>9</td></tr>
    +    <tr><th>July</th><td>15</td><td>25</td><td>21.7</td><td>7</td></tr>
    +    <tr><th>August</th><td>15</td><td>25</td><td>21.4</td><td>7</td></tr>
    +    <tr><th>September</th><td>11</td><td>21</td><td>15.6</td><td>8</td></tr>
    +    <tr><th>October</th><td>9</td><td>17</td><td>25.3</td><td>11</td></tr>
    +    <tr><th>November</th><td>5</td><td>11</td><td>22.4</td><td>12</td></tr>
    +    <tr><th>December</th><td>3</td><td>8</td><td>26.6</td><td>12</td></tr>
    +  </tbody>
    +</table>
    +
    + +

    Javascript

    +
    +
    $(function() {
    +
    +	// simple reflow widget (table with 1 header row)
    +	$("#table1").tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra', 'reflow'],
    +		widgetOptions : {
    +			// class name added to make it responsive (class name within media query)
    +			reflow_className    : 'ui-table-reflow',
    +			// header attribute containing modified header name
    +			reflow_headerAttrib : 'data-name',
    +			// data attribute added to each tbody cell
    +			// it contains the header cell text, visible upon reflow
    +			reflow_dataAttrib   : 'data-title'
    +		}
    +	});
    +
    +	// simple reflow widget + columnSelector & stickyHeaders widgets
    +	$("#table2").tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra', 'reflow', 'columnSelector', 'stickyHeaders'],
    +		widgetOptions : {
    +			// target the column selector markup
    +			columnSelector_container : $('#columnSelector'),
    +			// data attribute containing column name to use in the selector container
    +			// make it use the same as reflow_headerAttrib
    +			columnSelector_name : 'data-name',
    +
    +			// header attribute containing modified header name
    +			reflow_headerAttrib : 'data-name'
    +		}
    +	});
    +
    +	// reflow2 widget (table with multiple header rows)
    +	$("#table3").tablesorter({
    +		theme: 'blue',
    +		widgets: ['zebra', 'reflow2'],
    +		widgetOptions: {
    +			// class name added to make it responsive (class name within media query)
    +			reflow2_className    : 'ui-table-reflow',
    +			// ignore header cell content with this class name
    +			reflow2_classIgnore  : 'ui-table-reflow-ignore',
    +			// header attribute containing modified header name
    +			reflow2_headerAttrib : 'data-name',
    +			// class name applied to thead labels
    +			reflow2_labelClass   : 'ui-table-cell-label',
    +			// class name applied to first row thead label
    +			reflow2_labelTop     : 'ui-table-cell-label-top'
    +		}
    +	});
    +
    +});
    +
    + +
    + + + diff --git a/docs/example-widget-reflow1.html b/docs/example-widget-reflow1.html new file mode 100644 index 0000000..c61e498 --- /dev/null +++ b/docs/example-widget-reflow1.html @@ -0,0 +1,104 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Table Reflow Widget (beta) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankAgeTotalDiscountDate
    125$5.9522%Jun 26, 2013 7:22 AM
    1112$82.995%Aug 21, 2013 12:21 PM
    1251$99.2918%Oct 13, 2013 1:15 PM
    5128$9.9920%Jul 6, 2013 8:14 AM
    2133$19.9925%Dec 10, 2012 5:14 AM
    01318$65.8945%Jan 12, 2013 11:14 AM
    00545$153.1945%Jan 18, 2014 9:12 AM
    103$5.294%Jan 8, 2013 5:11 PM
    1624$14.1914%Jan 14, 2014 11:23 AM
    6622$13.1911%Jan 18, 2013 9:12 AM
    10018$55.2015%Feb 12, 2013 7:23 PM
    5565$123.0032%Jan 20, 2014 1:12 PM
    925$22.0917%Jun 11, 2013 10:55 AM
    1312$19.9918%Jan 20, 2014 7:45 PM
    7358$129.1939%Jan 20, 2014 10:11 AM
    + + + \ No newline at end of file diff --git a/docs/example-widget-reflow2.html b/docs/example-widget-reflow2.html new file mode 100644 index 0000000..15553d1 --- /dev/null +++ b/docs/example-widget-reflow2.html @@ -0,0 +1,250 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Table Reflow Widget (beta) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + +
    +
    (When "Auto" is set, the table becomes responsive; resize the browser window to see it work) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    + + + \ No newline at end of file diff --git a/docs/example-widget-reflow3.html b/docs/example-widget-reflow3.html new file mode 100644 index 0000000..14afd2f --- /dev/null +++ b/docs/example-widget-reflow3.html @@ -0,0 +1,125 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Table Reflow Widget (beta) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParisAverage Temperatures (C)Average Rainfall
    MonthMinimum TempMaximum TempPrecipitaion (mm)Rainfall Days
    Jaunuary3817.810
    February2921.79
    March41324.210
    April61524.611
    May102026.210
    June132325.19
    July152521.77
    August152521.47
    September112115.68
    October91725.311
    November51122.412
    December3826.612
    + + + diff --git a/docs/example-widget-resizable.html b/docs/example-widget-resizable.html new file mode 100644 index 0000000..6e5fb09 --- /dev/null +++ b/docs/example-widget-resizable.html @@ -0,0 +1,373 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Resizable Columns Widget + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +

    +
    +
    + +

    Notes

    +
    +
      +
    • IMPORTANT If using jQuery versions older than 1.8, css box-sizing for the table MUST be set as box-sizing: content-box; or the resizable widget will not work properly.
    • +
    • IMPORTANT The resize div ends up with a zero height if the header cell is empty. Please include at least a &nbsp; in the cell to allow it to render properly (ref).

    • + +
    • In v2.21.5, this widget now works with the columnSelector widget & tables with margins (see issue #864).
    • +
    • In v2.21.3 +
        +
      • Performed a major overhaul on the resizable widget to add resizable handles outside of the table, so now the resizable handles can be used over the entire height of the table!
      • +
      • This change allows the resizable widget to work seemlessly with the stickyHeaders widget (included in this demo); sadly, to make it work with the scroller widget will require more work.
      • +
      +
    • +
    • In v2.17.4, modified the bindings so the mouse move will now work on the document instead of only within the table header; this makes interaction consistent with what the user expects.
    • +
    • In v2.15.12, added resizable_widths option which allows the setting of default & reset header widths.
    • +
    • As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
    • +
    • This widget now saves all changed column widths to local storage, or it falls back to a cookie! (v2.1)
    • +
    • Column width saving requires the new "$.tablesorter.storage()" function included with the "jquery.tablesorter.widgets.js" file (v2.1).
    • +
    • Right clicking (opening the context menu) will now reset the resized columns (v2.4).
    • +
    • Holding down the shift key while resizing will force the last column or the table to resize instead of the next column, but only if the table is full width (v2.7.4).
    • +
    • Prevent resizing a column by adding any of the following (they all do the same thing), set in order of priority (v2.7.4): +
        +
      • jQuery data data-resizable="false".
      • +
      • metadata class="{ resizable: 'false'}". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { resizable : 'false' } }.
      • +
      • header class name class="resizable-false".
      • +
      +
    • +
    • Setting the resizable widget option to false, will only prevent the saving of resized columns, it has nothing to do with preventing a column from being resized.
    • +
    • Because this widget uses jQuery's closest() (jQuery 1.3+) and index() (jQuery 1.4+) functions, it requires these newer versions of jQuery in order to work.
    • +
    • In order to save the resized widths, jQuery version 1.4.1+ should be used because jQuery's parseJson() function is needed.
    • +
    • Setting the resizable_addLastColumn widget option to true will add the resizable handle to the last column, see the "non-full" width table below (v2.9.0).
    • +
    +
    + +

    Options

    +
    +

    Resizable widget defaults (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the function column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    trueWhen true and the storage widget is included, all column widths will be saved to storage. +
    +

    This means that when the page is reloaded, any adjusted column widths will be restored.

    +

    The adjusted column sizes can be reset at any time by right-clicking on the table header.

    +
    +
    falseWhen true, the last column of the table is made resizable. +
    +

    If the table is full width, adjusting the right edge would actually shrink or stretch all columns without moving the right border.

    +

    On narrower tables, the table width will be adjusted.

    +
    +
    [ ]Set any default column widths within this zero-based-column-indexed array +
    +

    This option allows the setting of column widths initially (before any resizing occurs, or if there are no saved column widths) and when resetting (right-click on the column header).

    +

    The array may contain any css allowed width definitions (e.g. percentage, pixels, em, etc).

    +

    Undefined column widths to not add a specified width to the column

    +

    Here is an example from the second table in this demo showing how to set this option:

    +
    // Note that the "Age" column is not resizable,
    +// but the width can still be set to 40px here
    +resizable_widths : [ '10%', '10%', '40px', '10%', '100px' ]
    +
    +
    falseWhen this option is set to a number, or true, the resizing event from the window is throttled. +
    +

    Essentially, throttling the resize event limits the number of times the javascript is executed while resizing the window.

    +

    Without any throttling, slower browsers may lag while the javascript adjusts the column widths of the table.

    +

    With excessive throttling, the user will notice the table column width lag (while will be seen as the width jumping sporatically to catch up to the mouse) behind the mouse movement.

    +

    When this option is set to true, a default of 5 (milliseconds) is used.

    +

    If setting a number, try to keep this number in the 0 to 10 range.

    +
    +
    falseWhen true, the last column will be targeted for resizing. +
    +

    When true, resizing a column will change the size of the selected column, and the last column, not the selected column's neighbor.

    +

    When false, resizing a column will move the column border between it's neighbors.

    +

    Also, in a full width table, if this option is false, the same behavior as when this option is true can be seen when resizing a column while holding down the Shift key on the keyboard - the last column is resized.

    +
    +
    +
    + +
    + +

    Demo

    +
    +

    + Non-full width table + + (individual columns resize) +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + Resized values for this table are saved to session storage - values are lost once the browser is closed. + +

    + +

    + Full width table + + (use shift to force last column to resize) +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + Resized values for this table are saved to local storage - values are not lost once the browser is closed. +
    +

    + +

    Page Header

    +
    +
    <!-- blue theme stylesheet with additional css styles added in v2.0.17 -->
    +<link rel="stylesheet" href="../css/theme.blue.css">
    +<!-- tablesorter plugin -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +
    +<!-- tablesorter widget file - loaded after the plugin -->
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +
    + +

    CSS

    +
    +
    
    +	
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    <!-- The Age column is set to not be resizable -->
    +<table class="tablesorter" style="width:auto">
    +  <thead>
    +    <tr>
    +      <th>First Name</th>
    +      <th>Last Name</th>
    +      <th class="resizable-false">Age</th>
    +      <th>Total</th>
    +      <th>Discount</th>
    +      <th>Date</th>
    +    </tr>
    +  </thead>
    +  <tbody>
    +    ...
    +  </tbody>
    +</table>
    +
    + + + +
    + + + + diff --git a/docs/example-widget-savesort.html b/docs/example-widget-savesort.html new file mode 100644 index 0000000..bb21593 --- /dev/null +++ b/docs/example-widget-savesort.html @@ -0,0 +1,196 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Save Sort Widget + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
    • +
    • Sort one or more columns, then reload the page to see that this widget remembers the last table sort.
    • +
    • Sort saving requires the new "$.tablesorter.storage()" function included with the "jquery.tablesorter.widgets.js" file (v2.1).
    • +
    • Because this widget uses jQuery's parseJson() function, it requires jQuery version 1.4.1+.
    • +
    • Added a saveSortReset method which only clears the stored information (v2.7.11).
    • +
    +

    + +

    Demo

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent1815.8944.2%-15
    A1BruceAlmighty45153.1944%+19
    A102BruceEvans56153.1923%+9
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankRatingTitleVotes
    1.9.2The Shawshank Redemption (1994)734,327
    2.9.2The Godfather (1972)548,857
    3.9.0The Godfather: Part II (1974)346,072
    4.8.9Pulp Fiction (1994)577,426
    5.8.9The Good, the Bad and the Ugly (1966)229,564
    + +

    Page Header

    +
    +
    +<link rel="stylesheet" href="css/blue/style.css">
    +<script src="js/jquery-latest.min.js"></script>
    +<script src="js/jquery.tablesorter.min.js"></script>
    +<script src="js/jquery.tablesorter.widgets.min.js"></script>
    +
    +

    Javascript

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-widget-scroller.html b/docs/example-widget-scroller.html new file mode 100644 index 0000000..2f80a9e --- /dev/null +++ b/docs/example-widget-scroller.html @@ -0,0 +1,698 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Scroller Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • In v2.22.2, +
        +
      • Add support for multiple tbodies in fixed columns: +
          +
        • *WARN* colspans within information only tbodies are still problematic!
        • +
        • If a colspan is to be used with fixed columns, then split it so that the colspan splits at the edge of fixed column; please see this comment for more details & a demo.
        • +
        +
      • +
      • The horizontal scrollbar no longer appears under the fixed column: +
          +
        • There is now a gap visible below the content when scrolled to the bottom.
        • +
        • This gap is filled by a div and can be styled by targeting the tablesorter-scroller-bar-spacer class name. See the css code block for an example.
        • +
        +
      • +
      • Removed: +
          +
        • The automatic setting of the widthFixed option to true.
        • +
        • Extra colgroup which were copied into each table clone.
        • +
        • Extra hidden elements in the fixed column.
        • +
        +
      • +
      • Updated RTL (right-to-left) support: +
          +
        • Changed the default class from tablesorter-scroller-rtl to ts-scroller-rtl, which is added to the table element to indicate where the fixed column is placed.
        • +
        • RTL support does require the direction: rtl css setting to be applied to the table wrapper.
        • +
        +
      • +
      • Fixed slow mousewheel scrolling when a fixed column is active in Firefox & older versions of Internet Explorer.
      • +
      • Fixed filtering of table content causing the fixed column to misalign; especially when few to no results are found.
      • +
      • Added compatibility to the following widgets: +
          +
        • pager
        • +
        • columnSelector
        • +
        +
      • +
      • Thanks to TheSin- for all the work he put into updating this widget... he really didn't like that scrollbar under the fixed column LOL.
      • +
      +
    • +
    • In v2.22.0, +
        +
      • Horizontal scrollbar now only appears on overflow.
      • +
      • border-box is now applied to all tables with scroller widget applied.
      • +
      • Fixed columns no longer have pointer events disabled.
      • +
      • Fixed column vertical scrollbar is now hidden in IE9 & older.
      • +
      • Fixed tabbing through fixed column header cells & inputs.
      • +
      • The "setFixedColumnSize" can now be called with no set size to refresh the fixed column.
      • +
      • Add scroller_addFixedOverlay option which when true, adds an overlay on the fixed columns for styling.
      • +
      • Refresh column sizes after update.
      • +
      +
    • +
    + +
    +

    Older Notes

    +
    +
      +
    • In v2.21.3 +
        +
      • * NOTE * Prior to v2.21.3, this widget would work with jQuery v1.4.4+, now it requires jQuery v1.7+.
      • +
      • The scroller widget was almost completely rewritten! The functionality is the same, but it now allows the adding of fixed columns!
      • +
      • Added scroller_fixedColumns which allows setting the number of fixed columns to add to the scroller (see options section for more details).
      • +
      • Added scroller_rowHighlight which adds a hover highlight class name to the row in both the fixed column and main table (see options section for more details).
      • +
      • Note: +
          +
        • Yes, there are some alignment & padding issues when using the jQuery UI theme with a fixed column, I'll look into resolving this; all other themes are nearly pixel perfect.
        • +
        • The fixed column widget includes extra css to prevent tbody cell content from wrapping (see the css code below); it was for demo purposes only, it is not a requirement.
        • +
        • This update does not include optimizations to allow this widget to work with very large tables; so please be conscious of this fact.
        • +
        • A lot of Firefox tweaks were needed to make it work! I need to investigate why the mousewheel scrolling is so slow (at least in Firefox for Windows) when a fixed column is included.
        • +
        • There were lots of other tweaks to the core and other widgets (e.g. zebra & filter widgets) to get these changes to work seamlessly, so please make sure to update everything!
        • +
        +
      • +
      +
    • +
    • In v2.21.1, columns now line up, especially while scrolling horizontally. It may not be pixel perfect, but it looks pretty good if table css "box-sizing" is set to "border-box".
    • +
    • In v2.21.0 +
        +
      • This widget was updated to include the tfoot rows.
      • +
      • To maintain the column widths across all copied tables: +
          +
        • The widthFixed options is now forcibly set to true; I apologize if this causes any inconvience.
        • +
        • This option adds a <colgroup> containing percentage width <col> elements to each section of the scroller.
        • +
        • If this option does cause issues, use css to set each column width as a percentage.
        • +
        +
      • +
      +
    • +
    • In v2.17+ +
        +
      • The scroller widget will now work properly with predefined column widths.
      • +
      • Shrinking the browser window will now hide the header overflow.
      • +
      • Horizontal scrolling of the table body will now properly horizontally scroll the header.
      • +
      • Changed the default scroll bar width from 17 to 18.
      • +
      • Added scroller_upAfterSort option.
      • +
      +
    • +
    +
    +
    +
      +
    • This widget can not be applied to the original plugin and requires jQuery version 1.7+ to function properly; if you need to make it work with older versions of jQuery and the plugin, please use this version of the widget.
    • +
    • This widget was originally written by Connell & Associates, Inc. and is dual-licensed under the MIT and GPL licenses. It has been modified to work with tablesorter version 2.9+.
    • +
    +
    + +

    Options

    +
    +

    Scroller widget defaults (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the function column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    scroller_height300Set the height of the scroll window in pixels.
    nullSet the width of the scroll bar in pixels (v2.19.0) +
    +
    + As of v2.19.0, this option's default was changed to null because internal code was added to detect the scroll bar width which changes dramatically depending on the browser window zoom level.
    +
    + If you are using a custom scroll bar plugin, this option will still accept a scroll bar width value which overrides the scroll bar width auto-detection. +
    +
    true +
    +
    + When true, the scroller automatically scrolls the inner window back to the top after sorting.
    +
    + Set this option to false to prevent this behaviour, or to stop the window from scrolling after interacting with a table cell (e.g. clicking on a checkbox); new in v2.17.3 +
    +
    trueBring the header into view while scrolling. +
    +

    When true, this option makes the table header jump into view when the table body is not scolled to the top and while scrolling up the page. It's not perfect, but it works. Disable it as desired.

    +

    * To see the difference, toggle the button in the demo below, then scroll down & up the page using a mouse wheel with the cursor at the horizontal center of the page and about 100 pixels from the top, so the cursor is within the table body.

    +
    +
    0This allows setting the number of fixed columns to add to the scroller (v2.21.3; v2.22.2). +
    +

    If the content is set a RTL direction, add a class name of ts-scroller-rtl (name set in $.tablesorter.css.scrollerRtl) to the table to align the fixed header on the right.

    +

    default value changed in v2.22.2 because tablesorter is set up to assume a theme name has already been added to the table when it encounters a class name starting with tablesorter-; if the original tablesorter-scroller-rtl class were added, the theme option setting would be ignored (because a theme named scroller-rtl is already set), and would require the developer to add the class name to the table (e.g. tablesorter-blue).

    +

    To change this method internally would require a breaking change where all css files would need to be updated and all theme classes would start with tablesorter-theme-; this will be planned for the Abelt update.

    +
    +
    falseSetting this to true will add a fixed overlay which can be used for styling (v2.22.0). +
    +

    A class name of "tablesorter-scroller-fixed-panel" is added to the overlay.

    +

    Here is are two examples:

    +

    Semi-transparent overlay*

    +
    div.tablesorter-scroller-fixed-panel {
    +  background-color: rgba( 0, 0, 0, 0.4);
    +  z-index: 2;
    +  opacity: 0.15;
    +  margin-top: 10px;
    +  margin-bottom: 15px;
    +}
    +

    Black border*

    +
    div.tablesorter-scroller-fixed-panel {
    +  margin-top: 10px;
    +  margin-bottom: 15px;
    +  border-right: 2px solid black;
    +}
    +

    * Demos by TheSin- from issue 887.

    +

    *WARNING* interacting with elements under this overlay requires that the browser supports pointer-events.

    +
    +

    *NOTE* Personally, I would not recommend setting this option to true because of the interference from the overlay - the following css will add a border to the fixed column using css3 :after to acheive the same effect.

    +
    /* add border to right side (LTR pages) of fixed column */
    +.tablesorter-scroller-fixed:after {
    +  content: '';
    +  border-right: 2px solid black;
    +  width: 2px;
    +  position: absolute;
    +  top: 0;
    +  bottom: 0;
    +  z-index: 2;
    +  /* change this to zero for non-jquery ui themes; and use "left" here for RTL pages */
    +  right: -1px;
    +  /* match the margins set to the table to keep the border the same height as the table */
    +  margin: 10px 0 15px;
    +}
    +
    +
    "hover"Set this to a class name to use when hovering over a fixed column row (v2.21.3). +
    +

    This option adds a hover highlight class name to the hovered row in both the fixed column and main table to ensure the hover highlight shows up in both areas.

    +

    If this highlighting causes unnecessary lag, it can be disabled by setting this option to an empty string.

    +

    All current themes have been updated to use this class name for row highlighting; adjust any custom themes as necessary.

    +
    +
    Deprecated/Removed Options
    "s_"This option contains a prefix string which is added to a random number (Removed). +
    +
    + This option was been completely removed in v2.18.0 as the id is now obtained from the unique namespace. +
    +
    +
    + +

    Methods

    +
    +

    Change Fixed Column Size Dynamically

    +
    + Set the number of fixed columns on any table with a scroller widget applied as follows: +
    $( 'table' ).trigger( 'setFixedColumnSize', size );
    +

    Where size is a value between zero and one less than the total number of columns.

    + If size is: +
      +
    • A non-integer, it will be rounded down.
    • +
    • Zero or less, no fixed columns will be applied.
    • +
    • Undefined, the current number of fixed columns will be refreshed.
    • +
    +
    +
    +
    + +

    CSS

    +
    +
    
    +	
    + +

    Javascript

    +
    +
    
    +	
    + +

    Demo

    +

    Fixed columns | Full-width | Half-width

    + + Choose Theme: +
    +
    + scroller_jumpToHeader : true (see the note above)* +
    + scroller_upAfterSort : true +

    + +

    + Fixed Column Demo
    + (Shrink the browser window if the horizontal scrollbar is not visible) +

    + +
    + Set number of fixed columns: 2
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    IndexFirst NameLast NameIDAddressStateZipTelephoneEmailNotes
    IndexFirst NameLast NameIDAddressStateZipTelephoneEmailNotes
    1SherryMills2233792 Sit RdNE69836(627) 124-8760DRamirez@massa.lysagittis amet mattis facilisis vitae molestie nec dolor id sed
    2MarkellaLessenberry8955979 Sit LnVA97761(768) 233-5399SPeltier@pulvinar.netelementum nullam lacus elit magna libero sed dolor pulvinar orci
    3LeeTrenkelbach7195656 Adipiscing AveID30972(149) 293-0691LSheppard@lectus.netvestibulum at rutrum molestie convallis vestibulum nec egestas consequat vitae
    4SherryeLlc9082348 Pharetra StUT50740(772) 682-4268MAltar@turpis.iosit elit consequat amet elit consectetur vestibulum vel quis consequat
    5JuanitoLindall5345181 Lacus LnID71689(528) 174-6999CKeen@augue.lydui porttitor vestibulum mattis ipsum nunc et morbi dolor ipsum
    6AndreFuller7168224 Pulvinar AveWY12382(654) 593-0007AMelvin@sed.netdolor curabitur nec molestie lacus odio id velit sed neque
    7SajidCattanach9973762 Ac RdWA16719(425) 909-2771BMaas@ac.orgmorbi tincidunt ac sollicitudin nec ac orci vitae donec non
    8HeidiRush7381425 Porta RdSD14708(341) 095-7183DSchrag@sapien.netnullam sed aliquam turpis et sagittis libero sed tellus dui
    9GaneshComeau3852641 Hendrerit DrMT66612(201) 977-9765SBurks@ipsum.lysit vestibulum ac pretium eget augue sit augue sagittis tellus
    10RegineMarina4796204 Ac RdWI55667(824) 223-9924VPeschke@pharetra.orgamet fringilla vitae tortor vestibulum egestas eget eget amet sed
    11WichayaThomas487861 Risus DrKY63224(599) 823-8970BMohamed@adipiscing.lyplacerat dolor pulvinar nec morbi amet porta sagittis lacus magna
    12DouglassHolliday4888829 Sit AveIA86970(113) 897-8276CLieb@convallis.iodolor magna id amet lorem eros ipsum magna non aliquam
    13PrinceSchwartzberg7901757 Sit CtIL94739(299) 471-3039DFavus@quis.orgmagna tincidunt ipsum hendrerit ac vitae tortor consequat magna elit
    14LolaHensley4868159 Dui RdMN88877(788) 031-7392MBradley@scelerisque.orgsuspendisse donec placerat nec suspendisse lacus ipsum elementum at lorem
    15DainiusFinn3556072 Massa DrVT75787(638) 345-2650MWilcox@velit.lymorbi pretium dui dolor elit sed non vestibulum sit dui
    16AishaSchuhmann3289709 Sagittis LnND44161(147) 281-5251GDech@mi.commassa sed placerat libero egestas at massa sagittis libero orci
    17MariaPeacock2692241 Amet AveMO81339(656) 079-5964POliva@tincidunt.orgac hendrerit molestie ipsum facilisis massa odio fringilla hendrerit neque
    18OtiliaDenbesten7781965 Nunc CtSC98692(985) 745-0452SWieber@porttitor.netaliquam orci odio id ac magna magna aenean sagittis lectus
    19JianSanchez7966439 Sit LnOR24879(168) 754-6725AVrtis@porttitor.netsapien ipsum nullam pretium quis tincidunt tincidunt sit mattis porttitor
    20TannyWieland8147331 Et RdSD65216(414) 322-1606ACasariego@et.orgodio augue in id lacus tincidunt morbi tempor orci tincidunt
    21AlejandroSidaway9958125 Placerat RdVA98301(202) 112-1194RHaag@nullam.lylacus aliquam et sagittis etiam aenean lorem ipsum non facilisis
    22YolandaSwanson530276 Amet CtVT42999(621) 796-4436TDenard@lectus.govlacus vitae quis dui orci ipsum odio pulvinar et nunc
    23AzraFilleul443499 Sagittis DrOK59700(485) 530-0532LSwetland@consectetur.netmagna mattis sollicitudin placerat vel facilisis sed ac non et
    24CassandraLabrucherie6066849 Tellus CtSC44245(960) 044-9381WLafave@lectus.ioac nullam magna ante sapien tellus tincidunt eros magna sagittis
    25TheodoreSaver1505 Tincidunt AveIL58210(152) 001-4978KTorres@sed.ioac tincidunt nec rutrum pulvinar id aliquam placerat pharetra placerat
    26SusiMurphy9001614 Hendrerit StAZ80212(532) 030-5050ZRingling@sit.ioquis odio et sapien sit amet eros et augue turpis
    27CorazonLawrence5773571 Facilisis RdCA35195(318) 200-2692REckhart@scelerisque.iotincidunt sit dolor mi donec magna massa vel suspendisse placerat
    28KhosrowFisher8024323 Tortor LnAK38949(493) 277-9670FHarmati@magna.lylectus tortor ac ipsum sagittis lacus dolor ac fringilla nec
    29MelgemaLopez8931738 Vestibulum LnMS32638(953) 255-2707ABurgin@tortor.lymolestie at vel at placerat pharetra consequat dolor nunc placerat
    30ChunLester9289681 Vestibulum CtND21333(474) 719-0476ETierney@pulvinar.govvestibulum ipsum tincidunt placerat eros turpis morbi ipsum sit malesuada
    31DwayneBalasubramanian4183129 Pharetra DrSD57558(457) 589-4620ESyner@aenean.comamet sit nec amet lectus augue consequat consectetur vel sed
    32JoshuaWilliamson7026313 Vestibulum StNJ39057(346) 084-7444VFeldman@elit.lysit tempor at lacus libero lorem sit nullam tempor aliquam
    33ShawnDartmann1244892 Aliquam RdIA17745(500) 390-3779RNesbitt@massa.netsit sapien magna libero augue consectetur fringilla orci ac tortor
    34RupaHelgren5945944 Sed AveCO96680(174) 841-4348FShebish@morbi.netat elementum neque ac in consequat elementum magna vitae mattis
    35GiaMarks6352519 Convallis DrGA66324(188) 657-9140SForsyth@adipiscing.govpharetra pulvinar amet dui elementum suspendisse et odio tellus amet
    36TyethaAhn5439900 Eros CtPA53390(482) 686-6141LHobbs@non.iopulvinar lorem quis fringilla eget velit sed augue rutrum augue
    37GregoryChristine527751 Ipsum RdAK44543(258) 666-2073HCrooker@donec.commassa vitae dolor sollicitudin consectetur sollicitudin malesuada massa velit egestas
    38YelenaShanoski6461612 Donec AveKY30729(905) 301-3407JMcmenamin@massa.govsapien rutrum adipiscing et sed sollicitudin vestibulum pharetra at neque
    39ThursdayHelm6665568 Nec RdNE94390(487) 403-7019RMorin@sed.orgrisus hendrerit sollicitudin vestibulum placerat lorem eros consequat lorem magna
    40MelindaOliva5256973 Rutrum CtIA38519(964) 234-5172FStephens@in.comdolor lacus nec odio in etiam facilisis lorem ipsum et
    41LatashaSlocum2108374 Fringilla StNV23913(678) 453-4263JWelchert@id.govdonec massa dolor elementum scelerisque risus lacus id lorem in
    42KennethZazzara2693364 Tempor DrMO30642(874) 633-3017TGarayan@tincidunt.lysollicitudin nullam egestas aenean molestie velit nec sed tincidunt scelerisque
    43FrancineDaniels3662141 Amet RdOH90786(856) 781-7309SIngham@pretium.lyegestas amet vel ac pretium lacus nec tortor facilisis et
    44MarieKrebs1244229 Sit LnDE41786(572) 023-1295EClagg@curabitur.iolacus elit sagittis quis nec vestibulum malesuada mattis morbi etiam
    45StanleyZehnacker4564610 Odio StVT70223(257) 234-6755HPennell@morbi.govvel aliquam mattis libero sed pharetra donec malesuada pharetra lectus
    46FurdellaToffoli9518366 Placerat RdAZ20381(740) 422-8726YEarls@morbi.netnon aliquam neque tortor egestas pulvinar tempor amet molestie lorem
    47TalathaNye8086884 Dolor DrMS97282(589) 157-7730DAcosta@rutrum.govipsum turpis vestibulum at convallis sit neque elementum sed adipiscing
    48BrentVollrath4795362 Eget DrMO74989(664) 642-4525YMarina@sollicitudin.netmassa elementum elit pretium malesuada mi vestibulum non aliquam neque
    49MelissaQuintana4051302 Lacus DrPA38853(354) 903-9363AMarrinson@lacus.iomorbi quis neque placerat malesuada tincidunt morbi risus at tortor
    50GuadalupeEseltine2065495 Rutrum CtAR37546(540) 500-5816TLester@morbi.comporttitor sit massa ipsum ac massa ac hendrerit vitae malesuada
    + +

    Full-width demo

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Languagesfemale85808080
    student23Mathematicsmale8277079
    student24Languagesfemale100911382
    student25Mathematicsmale22968253
    student26Languagesfemale37295659
    student27Mathematicsmale86826923
    student28Languagesfemale4425431
    student29Mathematicsmale77472238
    student30Languagesfemale19352310
    student31Mathematicsmale90271750
    student32Languagesfemale60753338
    student33Mathematicsmale4313715
    student34Languagesfemale77978144
    student35Mathematicsmale5815195
    student36Languagesfemale70617094
    student37Mathematicsmale6036184
    student38Languagesfemale6339011
    student39Mathematicsmale50463238
    student40Languagesfemale5175253
    student41Mathematicsmale43342878
    student42Languagesfemale11896095
    student43Mathematicsmale48921888
    student44Languagesfemale8225973
    student45Mathematicsmale91733739
    student46Languagesfemale481210
    student47Mathematicsmale8910611
    student48Languagesfemale90322118
    student49Mathematicsmale42494972
    student50Languagesfemale56376754
    + +

    Half-width demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDiff
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent1815.4944.2%-13
    A11BruceAlmighty45153.1944%+19
    A102BruceEvans56153.1923%+9
    A23MikePeters225.6920.3%+2
    A55LeslieKent3315.9925.1%-3
    A3FrankMint4412.5944.2%-12
    A21JoeThomas4515.2544%+12
    A12TessEvans6613.5923%+4
    A21PeterDunn122.9921.1%+2
    A33HarryJones1319.4922.2%-6
    A13JohnJames1613.8942.1%-13
    A71NickParker4513.8944%+29
    A21CharlesDunn1915.4922%+3
    +
    + +
    + +
    + + + diff --git a/docs/example-widget-static-row.html b/docs/example-widget-static-row.html new file mode 100644 index 0000000..a7fc937 --- /dev/null +++ b/docs/example-widget-static-row.html @@ -0,0 +1,283 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Static Row Widget + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    +
    + +

    Notes

    +
    +
      +
    • + In v2.19.1, the staticRow_event option was added. +

      +
    • +
    • This widget will only work in tablesorter version 2.8+.
    • +
    • The widget was modified from Tablesorter-Static-Row-Plugin by ascii-soup (MIT license).
    • +
    • It has been updated to work in tables with multiple tbodies, but not within information-only tbodies.
    • +
    • This widget was not tested, nor was it meant to be used with the pager.
    • +
    • Note This demo was updated to allow toggling of static rows.
    • +
    +
    + +

    Options

    +
    +

    Group widget default options (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the option column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    staticRow_class".static" + Set a class name to use to lock a row in place, include a period. +
    staticRow_data"static-index" + Set the jQuery data name to use with the row element. This data name saves the row index, and is only available as an option to avoid conflicts. +
    staticRow_event"staticRowsRefresh" + Set the event that the widget listens for to perform a refresh. +
    "row-index" + Use this data-attribute to set the desired static row location +
    +
    + Set the desired location using either of these two methods: +
      +
    • + Use a zero-based index of the row +
      <tr data-row-index="5">...</tr>
      + Note setting this index to much more than the number of table rows ensures that it will stay at the bottom when adding new rows.
      +
      +
    • +
    • + Use a percentage if total rows within it's tbody +
      <tr data-row-index="50%">...</tr>
      +
    • +
    + These values take priority over the actual row index, so as shown in the "Single tbody" demo below, the header row is set to 50%, but initially, it is located at the top of the table.
    +
    + If these values are changed dynamically, the static row location can be updated +
    +
    +
    + +

    Methods / Events

    +
    +

    Method

    + If adding or removing rows from the table, using any of the update methods will automatically refresh the static row indexes. Use the "Add Row" button below to test this.
    +
    + To modify or refresh the static row indexing without updating, trigger a staticRowsRefresh event on the table: +
    var $row = $("tr:contains('Iguana')");
    +// move Iguana row down one (remember, this only works on static rows)
    +$row.data('row-index', $row.data('row-index') + 1);
    +$(table).trigger('staticRowsRefresh');
    + this allows moving a static row dynamically; try the Move "Ignuana" row buttons above the "Single tbody" demo. +

    Event

    + A staticRowsComplete event is triggered after the static rows widget has completed moving the static rows back into place. Use it as follows: +
    $(table).bind('staticRowsComplete', function(table){
    +	console.log('static rows applied to ' + table.id);
    +});
    +
    + +
    + +

    Demo

    + Note Make any row static or normal by toggling the static class name using Ctrl + left click ( + click on Mac)
    +

    Single tbody

    +

    Move "Iguana" row:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Column 1Column 2Column 3
    Column 1Column 2Column 3
    D4Dog
    E5Emu
    F6Frog
    G7Goat
    A1Anteater
    B2Bear
    C3Cat
    H8Horse
    I9Iguana
    J10Jellyfish
    V22Vole
    W23Walrus
    X24Xantis
    K11Koala
    L12Lemur
    Q17Quail
    R18Rhino
    S19Seal
    M13Mink
    N14Nightingale
    O15Octopus
    P16Pig
    T20Tiger
    U21Urchin
    Y25Yak
    Z26Zebra
    Total CountLots! 
    + +

    Multiple tbody

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RankFirst NameLast NameAgeTotalDiscountDate
    1Philip Aaron WongJohnson Sr Esq25$5.9522%Jun 26, 2004 7:22 AM
    11AaronHibert12$2.995%Aug 21, 2009 12:21 PM
    12Brandon ClarkHenry Jr51$42.2918%Oct 13, 2000 1:15 PM
    111PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    21JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    013ClarkKent Sr.18$15.8944%Jan 12, 2003 11:14 AM
    Second tbody
    005BruceAlmighty Esq45$153.1944%Jan 18, 2021 9:12 AM
    10AlexDumass13$5.294%Jan 8, 2012 5:11 PM
    16JimFranco24$14.1914%Jan 14, 2004 11:23 AM
    166Bruce LeeEvans22$13.1911%Jan 18, 2007 9:12 AM
    100Brenda DexterMcMasters18$55.2015%Feb 12, 2010 7:23 PM
    55DennisBronson65$123.0032%Jan 20, 2001 1:12 PM
    9MarthadelFuego25$22.0917%Jun 11, 2011 10:55 AM
    + +
    + +

    Javascript

    +
    +
    
    +	
    +

    CSS

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + +
    + + + \ No newline at end of file diff --git a/docs/example-widget-sticky-header.html b/docs/example-widget-sticky-header.html new file mode 100644 index 0000000..f931da4 --- /dev/null +++ b/docs/example-widget-sticky-header.html @@ -0,0 +1,719 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Sticky Header Widget + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + +

    Notes

    +
    +
      +
    • In v2.18.4, added a Magnific popup example to this page. Note Please take note of the extra css needed to keep the sticky header aligned.
    • +
    • In v2.18.0, +
        +
      • Nested tables with sticky headers now stack properly. See the new example added to the bottom of this demo page.
      • +
      • Added stickyHeaders_xScroll and stickyHeaders_yScroll widget options.
      • +
      • Any defined onRenderHeader function is now executed on the cloned sticky header table cells; the onRenderTemplate function is not! See the change log section for more details.
      • +
      +
      +
    • + +
    • Note To access the added sticky table content from your code without worrying about using the ID, you can use table.config.widgetOptions.$sticky.
    • +
    • Note Add the class name sticky-false to any header rows you don't want to become sticky (v2.1.18).

    • + +
    • You will need to modify the headerTemplate option to include the jQuery UI icon! See the example in the code (v2.7).
    • +
    • Scroll down the page to see the headers stick. Then sort the columns using the sticky headers!
    • +
    • Multiple rows in the header, including the filter row, will become sticky.
    • + +
    • As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
    • +
    • Because of the limitations of Internet Explorer version 7 and older, this widget will not work.
    • + +
    +
    + +

    Options

    +
    +

    stickyHeaders widget defaults (added inside of tablesorter widgetOptions)

    +
    + TIP! Click on the link in the function column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    ''Include any extra class name to be added to the sticky header table (v2.1; v2.18.0) +
    +
    + Note prior to v2.18.0, this class was applied to the sticky table thead; after v2.18.0, the thead and caption are wrapped in a div that is made sticky, with this class name.
    +
    + Modified in v2.11 so that "tablesorter-stickyHeader" class is always added and this option only adds additional classes. +
    +
    stickyHeaders_offset0Set this to a number (in pixels) or jquery selector targeting the position:fixed element in which to place the sticky header below while scrolling.
    '-sticky'If the original table has an ID, then the value from this option is added to the end of the cloned table to maintain a unique ID (v2.9). +
    +
      +
    • It contains a suffix to add to any table id.
    • +
    • Its default value is -sticky
    • +
    +
    +
    stickyHeaders_addResizeEventtrueWhen true, the $.tablesorter.addHeaderResizeEvent function is applied to the table header cells so a "resize" event is triggered and the sticky headers widget can then properly resize the cloned table header cells to match the originals.
    stickyHeaders_includeCaptiontrueIf false and a table caption exist, it won't be included in the sticky header.
    stickyHeaders_zIndex2Adjust the zIndex of the stickyHeaders element as desired.
    nullSet this option as a jQuery selector or object where the sticky header will be attached (v2.14.4). +
    +
      +
    • Setting this option with either a jQuery selector string (".wrapper") or jQuery object ($(".wrapper")).
    • +
    • This option contains the target to which the sticky header will attach - see the second example below.
    • +
    +
    +
    trueScroll table top into view after filtering (v2.16.2) +
    +
    + This is needed when the user choses to filter the table which results in fewer rows than are currently visible in the browser viewport. So, the sticky header may still exist, but the table body may not be seen. Setting this option to true forces the original table header to scroll back into view. +
    +
    nulljQuery selector or object that will be used to monitor horizontal scroll position(v2.18.0) +
    +
    + Defaults: xScroll > attachTo > window
    +
    + Indicate the element (jQuery selector or obect) in which to monitor for changes in scroll position; If undefined (null by default), the window is monitored. +
    +
    nulljQuery selector or object that will be used to monitor vertical scroll position (v2.18.0) +
    +
    + Defaults: yScroll > attachTo > window
    +
    + Indicate the element (jQuery selector or obect) in which to monitor for changes in scroll position; If undefined (null by default), the window is monitored. +
    +
    +
    + +

    Change log

    +
    +
      +
    • v2.18.0: +
        +
      • Nested tables with sticky headers now stack properly. See the new example added to the bottom of this demo page.
      • +
      • Added stickyHeaders_xScroll and stickyHeaders_yScroll options to indicate the element (jQuery selector or obect) in which to monitor for changes in scroll position; If undefined (null by default), the window is monitored.
      • +
      • Any defined onRenderHeader function is now executed on the cloned sticky header table cells. There are now 3 parameters available to this function: +
          +
        • index - header cell index; this is not the column index!
        • +
        • config - the table.config settings for the table.
        • +
        • $table - the target of this parameter changes: +
            +
          • For the original table header cells, this parameter is a jQuery object pointing to the original table; this table has the class name hasStickyHeaders.
          • +
          • When the sticky table header cells are processed, this parameter is a jQuery object pointing to a copy of the table that is used as a sticky header; this table has the class name containsStickyHeaders.
          • +
          +
        • +
        + Note Any defined onRenderTemplate function is not called on the sticky header because it is a clone of the already rendered header cell; instead use onRenderHeader to attach event listeners, etc. +
      • +
      • Removed jQuery UI theme from the theme selector in this demo to accomodate adding the accordion. With the current setup, changing the table theme would continue to show the jQuery UI class names on the table (uitheme is not removed when switching themes), so the tables became a chimera of jQuery UI and the selected theme, and the accordion would become un-styled; it was a real mess.
        +
        +
      • +
      +
    • +
    • v2.14.4: Added cssStickyHeaders_attachTo option (default set to null). +
        +
      • Setting this option with either a jQuery selector string (".wrapper") or jQuery object ($(".wrapper")).
      • +
      • This option contains the target to which the sticky header will attach - see the second example below.
      • +
      +
    • +
    • v2.9: +
        +
      • As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
      • +
      • Added a widget option named stickyHeaders_cloneId +
          +
        • It contains a suffix to add to any table id.
        • +
        • Its default value is -sticky
        • +
        +
      • +
      • Table captions and any additional rows (filter widget row) will also be included in the sticky header.
      • +
      +
    • +
    • v2.7: You will need to modify the headerTemplate option to include the jQuery UI icon! See the example in the code.
    • +
    • v2.1.18: Add the class name sticky-false to any header rows you don't want to become sticky.
    • +
    • v2.1.17: Multiple rows in the header will become sticky.
    • +
    • v2.1 (updated v2.11): Added a widget option named stickyHeaders option which contains the css class name applied to the actual sticky header. Modified in v2.11 so that "tablesorter-stickyHeader" class is always added and this option only adds additional classes.
    • +
    +
    + +
    + +

    CSS

    +
    +
    
    +	
    + +

    Javascript

    +
    +
    
    +	
    + +

    Demo

    + Choose Theme: + +

    + Include Caption: +

    + +

    Sticky headers in a popup window

    + + + + +

    Attach sticky header to browser window

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Student Grades
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Languagesfemale85808080
    student23Mathematicsmale8277079
    student24Languagesfemale100911382
    student25Mathematicsmale22968253
    student26Languagesfemale37295659
    student27Mathematicsmale86826923
    student28Languagesfemale4425431
    student29Mathematicsmale77472238
    student30Languagesfemale19352310
    student31Mathematicsmale90271750
    student32Languagesfemale60753338
    student33Mathematicsmale4313715
    student34Languagesfemale77978144
    student35Mathematicsmale5815195
    student36Languagesfemale70617094
    student37Mathematicsmale6036184
    student38Languagesfemale6339011
    student39Mathematicsmale50463238
    student40Languagesfemale5175253
    student41Mathematicsmale43342878
    student42Languagesfemale11896095
    student43Mathematicsmale48921888
    student44Languagesfemale8225973
    student45Mathematicsmale91733739
    student46Languagesfemale481210
    student47Mathematicsmale8910611
    student48Languagesfemale90322118
    student49Mathematicsmale42494972
    student50Languagesfemale56376754
    + +
    + +

    Attach sticky header to its parent

    +
    + + + + + + + + + + + + + + + + + + + + + + +
    Student Grades
    Account #First NameLast NameAgeTotalDiscountDiff
    A43PeterParker289.9920.3%+3
    A255JohnHood3319.9925.1%-7
    A33ClarkKent1815.4944.2%-13
    A11BruceAlmighty45153.1944%+19
    A102BruceEvans56153.1923%+9
    A23MikePeters225.6920.3%+2
    A55LeslieKent3315.9925.1%-3
    A3FrankMint4412.5944.2%-12
    A21JoeThomas4515.2544%+12
    A12TessEvans6613.5923%+4
    A21PeterDunn122.9921.1%+2
    A33HarryJones1319.4922.2%-6
    A13JohnJames1613.8942.1%-13
    A71NickParker4513.8944%+29
    A21CharlesDunn1915.4922%+3
    +
    + +
    +

    Nested sticky header tables

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Main table header
    Main table - row 1
    Main table - row 2
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Header for the nested table 1
    Second header row for nested table 1
    data in the nested table 1 - row 1
    data in the nested table 1 - row 2
    data in the nested table 1 - row 3
    data in the nested table 1 - row 4
    data in the nested table 1 - row 5
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Nested table 2 caption
    Header for the nested table 2
    Second header row for nested table 2
    data in the nested table 2 - row 1
    data in the nested table 2 - row 2
    data in the nested table 2 - row 3
    data in the nested table 2 - row 4
    data in the nested table 2 - row 5
    data in the nested table 2 - row 6
    data in the nested table 2 - row 7
    data in the nested table 2 - row 8
    data in the nested table 2 - row 9
    data in the nested table 2 - row 10
    data in the nested table 2 - row 11
    data in the nested table 2 - row 12
    data in the nested table 2 - row 13
    data in the nested table 2 - row 14
    data in the nested table 2 - row 15
    data in the nested table 2 - row 16
    data in the nested table 2 - row 17
    data in the nested table 2 - row 18
    data in the nested table 2 - row 19
    data in the nested table 2 - row 20
    +
    data in the nested table 1 - row 6
    data in the nested table 1 - row 7
    data in the nested table 1 - row 8
    data in the nested table 1 - row 9
    data in the nested table 1 - row 10
    data in the nested table 1 - row 11
    data in the nested table 1 - row 12
    data in the nested table 1 - row 13
    data in the nested table 1 - row 14
    data in the nested table 1 - row 15
    data in the nested table 1 - row 16
    data in the nested table 1 - row 17
    data in the nested table 1 - row 18
    data in the nested table 1 - row 19
    data in the nested table 1 - row 20
    +
    Main table - row 3
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Nested table 3 caption
    Header for the nested table 3
    data in the nested table 3 - row 1
    data in the nested table 3 - row 2
    data in the nested table 3 - row 3
    data in the nested table 3 - row 4
    data in the nested table 3 - row 5
    data in the nested table 3 - row 6
    data in the nested table 3 - row 7
    data in the nested table 3 - row 8
    data in the nested table 3 - row 9
    data in the nested table 3 - row 10
    data in the nested table 3 - row 11
    data in the nested table 3 - row 12
    data in the nested table 3 - row 13
    data in the nested table 3 - row 14
    data in the nested table 3 - row 15
    data in the nested table 3 - row 16
    data in the nested table 3 - row 17
    data in the nested table 3 - row 18
    data in the nested table 3 - row 19
    data in the nested table 3 - row 20
    +
    Main table - row 4
    + +
    + + +
    + + + + diff --git a/docs/example-widget-ui-theme.html b/docs/example-widget-ui-theme.html new file mode 100644 index 0000000..dea7c9c --- /dev/null +++ b/docs/example-widget-ui-theme.html @@ -0,0 +1,236 @@ + + + + + jQuery plugin: Tablesorter 2.0 - jQuery UITheme Widget (jQuery UI) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • In v2.19.0, this widget allows dynamic changing of themes; including switching from jQuery UI or Bootstrap to any other theme. To change a theme, do the following: +
      var $table = $('table');
      +$table[0].config.theme = 'grey';
      +$table.trigger('applyWidgets');
      + To see this work, check out the scroller widget demo. +
    • + +
    • As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.
    • +
    • You will need to modify the headerTemplate option to include the bootstrap icon! See the example in the code (v2.7).
    • +
    • The original "widgetUitheme" option has been replaced by "widgetOptions.uitheme". See the javascript block below for more details (v2.1).
    • +
    • In tablesorter v2.4, the uitheme option has changed to indicate the theme instead of an array of icons to use: +
        +
      • All theme class names are now contained within $.tablesorter.themes with the jQuery UI theme saved to $.tablesorter.themes.jui
      • +
      • The themes variable allows you to modify the class names for the table, header, sort icons, active state, hover state, filter inputs and zebra striping. See the code below on how to extend these variables.
      • +
      • Set the uitheme widget option to "jui" to set the widget to use the jQuery UI theme. See the bootstrap demo for another example.
      • +
      +
    • +
    • Earlier widget versions required jQuery 1.4+. The UITheme widget for tablesorter 2.4+ requires jQuery 1.2.6+.
    • +
    +

    + +

    Demo

    +
    + jQuery UI Theme: +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Some interesting caption
    First NameLast NameAgeTotalDiscountDate
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + + +

    Page Header

    +
    +
    <!-- ui theme stylesheet - contents shown below -->
    +<link rel="stylesheet" href="../css/theme.jui.css">
    +<!-- jQuery UI theme (cupertino example here) -->
    +<link rel="stylesheet" href="css/jquery-ui.min.css">
    +
    +<!-- tablesorter plugin -->
    +<script src="../js/jquery.tablesorter.js"></script>
    +<!-- tablesorter widget file - loaded after the plugin -->
    +<script src="../js/jquery.tablesorter.widgets.js"></script>
    +
    + +

    Javascript

    +
    +
    
    +	
    + +

    HTML

    +
    +
    
    +	
    + + + +
    + + + diff --git a/docs/example-widget-zebra.html b/docs/example-widget-zebra.html new file mode 100644 index 0000000..7ecec59 --- /dev/null +++ b/docs/example-widget-zebra.html @@ -0,0 +1,146 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Zebra Stripe Widget + + + + + + + + + + + + + + + + + + + + + + + +
    + +

    + NOTE! +

      +
    • This widget is part of the plugin, but has been modified from the original.
    • +
    • The original "widgetZebra" option has been replaced by "widgetOptions.zebra". See the javascript block below for more details (v2.1).
    • +
    • If the "widgetZebra" option exists, it will over-ride this newer "widgetOptions.zebra" option in order to maintain backwards compatibility.
    • +
    +

    + +

    Demo

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First NameLast NameAgeTotalDiscountDate
    PeterParker28$9.9920%Jul 6, 2006 8:14 AM
    JohnHood33$19.9925%Dec 10, 2002 5:14 AM
    ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
    BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
    BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
    + +

    Javascript

    +
    +
    
    +	
    +

    CSS

    +
    +
    
    +	
    +

    HTML

    +
    +
    
    +	
    + + + +
    + + + + diff --git a/docs/example-widgets.html b/docs/example-widgets.html new file mode 100644 index 0000000..d38721b --- /dev/null +++ b/docs/example-widgets.html @@ -0,0 +1,252 @@ + + + + + jQuery plugin: Tablesorter 2.0 - Writing custom widgets + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + Notes about the addWidget template: +
      +
    • The id block: +
        +
      • The widget id, or name, must be unique!
      • +
      • The id, or name, can contain special characters and/or spaces.
      • +
      • This setting is required.
      • +
      +
    • +
    • The priority block (added v2.9): +
        +
      • Set the widget priority using any number; think of it like setting the css z-index.
      • +
      • This tells the plugin the order in which to run the widgets, lowest number priority first.
      • +
      • The default widgets have priorities set in intervals of 10 (see the widget priority table), so to run your custom widget before a specific widget, set your widget priority to less than that number.
      • +
      • This block is not supported in older versions!
      • +
      • This setting is optional, but if no priority is specified, it defaults to 10.
      • +
      +
    • +
    • The options block (added v2.8): +
        +
      • Include any widget options to be automatically be extended with any set widgetOptions (from table.config.widgetOptions).
      • +
      • As of v2.8, no included widgets will be using this to maintain backwards compatibility with older versions. This changed when v2.9 was released.
      • +
      • This block is not supported in older versions!
      • +
      • This block is optional.
      • +
      +
    • +
    • The init block (added v2.0.28): +
        +
      • This code is called only after tablesorter has initialized, but before initial sort and before any of the widgets are applied (via the format block); it is only run once.
      • +
      • Since, v2.0.28, only the saveSort widget uses this block to ensure that the stored sort is applied before; but some of the newer widgets (post v2.9) are using this code block.
      • +
      • This block is not supported in older versions.
      • +
      • This block is optional.
      • +
      +
    • +
    • The format block (modified v2.0.23): +
        +
      • This block is part of the original addWidget template and is required.
      • +
      • In the original template, only the table parameter is provided. After v2.0.28, config and widgetOptions were provided as additional parameters (sorry the previous docs were incorrect).
      • +
      • The initFlag is correctly set in v2.8+.
      • +
      +
    • +
    • The remove block (added v2.4): +
        +
      • In v2.19.0 the refreshing parameter was added: +
          +
        • It is a parameter used to indicate that the refreshWidgets method was triggered.
        • +
        • When widgets are refreshed, the remove method is called, then the widget init function is immediately called to reapply the widget.
        • +
        • In this update, this parameter is used by the filter widget to retain filtered rows and prevent a "flash" of showing all rows, then returning to its previous state after applying the filter again.
        • +
        +
      • +
      • This code is called when either the refreshWidgets or destroy methods are called.
      • +
      • The code contained within this block must remove all additional content/elements added by the widget. Also, any rows or content that is hidden must be restored.
      • +
      • If additional rows are added to the table, make sure to include the class name within the selectorRemove option.
      • +
      • This block was added in v2.4, and not supported in older versions.
      • +
      • This block is optional.
      • +
      +
    • +
    +
    + +

    addWidget Template

    +
    +
    // addWidget Template
    +// *******************
    +// parameters:
    +// table = table object (DOM)
    +// config = config object (from table.config)
    +// widgetOptions = all widget options (from table.config.widgetOptions)
    +$.tablesorter.addWidget({
    +  id: 'myWidget',
    +  // set the priority of the widget (optional)
    +  priority: 10,
    +  // widget options (added v2.8) - added to table.config.widgetOptions
    +  options: {
    +    myWidget_option1 : 'setting1',
    +    myWidget_option2 : 'setting2'
    +  },
    +  // The init function (added v2.0.28) is called only after tablesorter has
    +  // initialized, but before initial sort & before any of the widgets are applied.
    +  init: function(table, thisWidget, config, widgetOptions){
    +    // widget initialization code - this is only *RUN ONCE*
    +    // but in this example, only the format function is called to from here
    +    // to keep the widget backwards compatible with the original tablesorter
    +    thisWidget.format(table, config, widgetOptions, true);
    +  },
    +  format: function(table, config, widgetOptions, initFlag) {
    +    // widget code to apply to the table *AFTER EACH SORT*
    +    // set the initFlag to true when this format is called from the init
    +    // function above otherwise initFlag is undefined
    +    // * see the saveSort widget for a full example *
    +  },
    +  remove: function(table, config, widgetOptions, refreshing){
    +    // do what ever needs to be done to remove stuff added by your widget
    +    // unbind events, restore hidden content, etc.
    +    // refreshing flag is true when the refreshWidgets method is triggered, meaning
    +    // the widget will be removed, then immediately reapplied
    +  }
    +});
    +
    + +

    Demo

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameMajorSexEnglishJapaneseCalculusGeometry
    NameMajorSexEnglishJapaneseCalculusGeometry
    Student12Mathematicsfemale100757085
    Student13Languagesfemale1008010090
    Student14Languagesfemale50455590
    Student15Languagesmale953510090
    Student16Languagesfemale100503070
    Student17Languagesfemale801005565
    Student18Mathematicsmale30495575
    Student19Languagesmale68908870
    Student20Mathematicsmale40454080
    Student21Languagesmale5045100100
    Student22Mathematicsmale1009910090
    Student23Languagesfemale85808080
    Student01Languagesmale80707580
    Student02Mathematicsmale908810090
    Student03Languagesfemale85958085
    Student04Languagesmale6055100100
    Student05Languagesfemale68809580
    Student06Mathematicsmale1009910090
    Student07Mathematicsmale85689090
    Student08Languagesmale100909085
    Student09Mathematicsmale80506575
    Student10Languagesmale8510010090
    Student11Languagesmale8685100100
    Student24Languagesfemale100911382
    + +

    Javascript

    +

    Repeat Headers Widget

    + +
    +
    
    +	
    + +
    +
    + Next up: Pager plugin ›› +
    + +
    + + + + diff --git a/docs/fonts/glyphicons-halflings-regular.eot b/docs/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..b93a4953fff68df523aa7656497ee339d6026d64 GIT binary patch literal 20127 zcma%hV{j!vx9y2-`@~L8?1^pLwlPU2wr$&<*tR|KBoo`2;LUg6eW-eW-tKDb)vH%` z^`A!Vd<6hNSRMcX|Cb;E|1qflDggj6Kmr)xA10^t-vIc3*Z+F{r%|K(GyE^?|I{=9 zNq`(c8=wS`0!RZy0g3{M(8^tv41d}oRU?8#IBFtJy*9zAN5dcxqGlMZGL>GG%R#)4J zDJ2;)4*E1pyHia%>lMv3X7Q`UoFyoB@|xvh^)kOE3)IL&0(G&i;g08s>c%~pHkN&6 z($7!kyv|A2DsV2mq-5Ku)D#$Kn$CzqD-wm5Q*OtEOEZe^&T$xIb0NUL}$)W)Ck`6oter6KcQG9Zcy>lXip)%e&!lQgtQ*N`#abOlytt!&i3fo)cKV zP0BWmLxS1gQv(r_r|?9>rR0ZeEJPx;Vi|h1!Eo*dohr&^lJgqJZns>&vexP@fs zkPv93Nyw$-kM5Mw^{@wPU47Y1dSkiHyl3dtHLwV&6Tm1iv{ve;sYA}Z&kmH802s9Z zyJEn+cfl7yFu#1^#DbtP7k&aR06|n{LnYFYEphKd@dJEq@)s#S)UA&8VJY@S2+{~> z(4?M();zvayyd^j`@4>xCqH|Au>Sfzb$mEOcD7e4z8pPVRTiMUWiw;|gXHw7LS#U< zsT(}Z5SJ)CRMXloh$qPnK77w_)ctHmgh}QAe<2S{DU^`!uwptCoq!Owz$u6bF)vnb zL`bM$%>baN7l#)vtS3y6h*2?xCk z>w+s)@`O4(4_I{L-!+b%)NZcQ&ND=2lyP+xI#9OzsiY8$c)ys-MI?TG6 zEP6f=vuLo!G>J7F4v|s#lJ+7A`^nEQScH3e?B_jC&{sj>m zYD?!1z4nDG_Afi$!J(<{>z{~Q)$SaXWjj~%ZvF152Hd^VoG14rFykR=_TO)mCn&K$ z-TfZ!vMBvnToyBoKRkD{3=&=qD|L!vb#jf1f}2338z)e)g>7#NPe!FoaY*jY{f)Bf>ohk-K z4{>fVS}ZCicCqgLuYR_fYx2;*-4k>kffuywghn?15s1dIOOYfl+XLf5w?wtU2Og*f z%X5x`H55F6g1>m~%F`655-W1wFJtY>>qNSdVT`M`1Mlh!5Q6#3j={n5#za;!X&^OJ zgq;d4UJV-F>gg?c3Y?d=kvn3eV)Jb^ zO5vg0G0yN0%}xy#(6oTDSVw8l=_*2k;zTP?+N=*18H5wp`s90K-C67q{W3d8vQGmr zhpW^>1HEQV2TG#8_P_0q91h8QgHT~8=-Ij5snJ3cj?Jn5_66uV=*pq(j}yHnf$Ft;5VVC?bz%9X31asJeQF2jEa47H#j` zk&uxf3t?g!tltVP|B#G_UfDD}`<#B#iY^i>oDd-LGF}A@Fno~dR72c&hs6bR z2F}9(i8+PR%R|~FV$;Ke^Q_E_Bc;$)xN4Ti>Lgg4vaip!%M z06oxAF_*)LH57w|gCW3SwoEHwjO{}}U=pKhjKSZ{u!K?1zm1q? zXyA6y@)}_sONiJopF}_}(~}d4FDyp|(@w}Vb;Fl5bZL%{1`}gdw#i{KMjp2@Fb9pg ziO|u7qP{$kxH$qh8%L+)AvwZNgUT6^zsZq-MRyZid{D?t`f|KzSAD~C?WT3d0rO`0 z=qQ6{)&UXXuHY{9g|P7l_nd-%eh}4%VVaK#Nik*tOu9lBM$<%FS@`NwGEbP0&;Xbo zObCq=y%a`jSJmx_uTLa{@2@}^&F4c%z6oe-TN&idjv+8E|$FHOvBqg5hT zMB=7SHq`_-E?5g=()*!V>rIa&LcX(RU}aLm*38U_V$C_g4)7GrW5$GnvTwJZdBmy6 z*X)wi3=R8L=esOhY0a&eH`^fSpUHV8h$J1|o^3fKO|9QzaiKu>yZ9wmRkW?HTkc<*v7i*ylJ#u#j zD1-n&{B`04oG>0Jn{5PKP*4Qsz{~`VVA3578gA+JUkiPc$Iq!^K|}*p_z3(-c&5z@ zKxmdNpp2&wg&%xL3xZNzG-5Xt7jnI@{?c z25=M>-VF|;an2Os$Nn%HgQz7m(ujC}Ii0Oesa(y#8>D+P*_m^X##E|h$M6tJr%#=P zWP*)Px>7z`E~U^2LNCNiy%Z7!!6RI%6fF@#ZY3z`CK91}^J$F!EB0YF1je9hJKU7!S5MnXV{+#K;y zF~s*H%p@vj&-ru7#(F2L+_;IH46X(z{~HTfcThqD%b{>~u@lSc<+f5#xgt9L7$gSK ziDJ6D*R%4&YeUB@yu@4+&70MBNTnjRyqMRd+@&lU#rV%0t3OmouhC`mkN}pL>tXin zY*p)mt=}$EGT2E<4Q>E2`6)gZ`QJhGDNpI}bZL9}m+R>q?l`OzFjW?)Y)P`fUH(_4 zCb?sm1=DD0+Q5v}BW#0n5;Nm(@RTEa3(Y17H2H67La+>ptQHJ@WMy2xRQT$|7l`8c zYHCxYw2o-rI?(fR2-%}pbs$I%w_&LPYE{4bo}vRoAW>3!SY_zH3`ofx3F1PsQ?&iq z*BRG>?<6%z=x#`NhlEq{K~&rU7Kc7Y-90aRnoj~rVoKae)L$3^z*Utppk?I`)CX&& zZ^@Go9fm&fN`b`XY zt0xE5aw4t@qTg_k=!-5LXU+_~DlW?53!afv6W(k@FPPX-`nA!FBMp7b!ODbL1zh58 z*69I}P_-?qSLKj}JW7gP!la}K@M}L>v?rDD!DY-tu+onu9kLoJz20M4urX_xf2dfZ zORd9Zp&28_ff=wdMpXi%IiTTNegC}~RLkdYjA39kWqlA?jO~o1`*B&85Hd%VPkYZT z48MPe62;TOq#c%H(`wX5(Bu>nlh4Fbd*Npasdhh?oRy8a;NB2(eb}6DgwXtx=n}fE zx67rYw=(s0r?EsPjaya}^Qc-_UT5|*@|$Q}*|>V3O~USkIe6a0_>vd~6kHuP8=m}_ zo2IGKbv;yA+TBtlCpnw)8hDn&eq?26gN$Bh;SdxaS04Fsaih_Cfb98s39xbv)=mS0 z6M<@pM2#pe32w*lYSWG>DYqB95XhgAA)*9dOxHr{t)er0Xugoy)!Vz#2C3FaUMzYl zCxy{igFB901*R2*F4>grPF}+G`;Yh zGi@nRjWyG3mR(BVOeBPOF=_&}2IWT%)pqdNAcL{eP`L*^FDv#Rzql5U&Suq_X%JfR_lC!S|y|xd5mQ0{0!G#9hV46S~A` z0B!{yI-4FZEtol5)mNWXcX(`x&Pc*&gh4k{w%0S#EI>rqqlH2xv7mR=9XNCI$V#NG z4wb-@u{PfQP;tTbzK>(DF(~bKp3;L1-A*HS!VB)Ae>Acnvde15Anb`h;I&0)aZBS6 z55ZS7mL5Wp!LCt45^{2_70YiI_Py=X{I3>$Px5Ez0ahLQ+ z9EWUWSyzA|+g-Axp*Lx-M{!ReQO07EG7r4^)K(xbj@%ZU=0tBC5shl)1a!ifM5OkF z0w2xQ-<+r-h1fi7B6waX15|*GGqfva)S)dVcgea`lQ~SQ$KXPR+(3Tn2I2R<0 z9tK`L*pa^+*n%>tZPiqt{_`%v?Bb7CR-!GhMON_Fbs0$#|H}G?rW|{q5fQhvw!FxI zs-5ZK>hAbnCS#ZQVi5K0X3PjL1JRdQO+&)*!oRCqB{wen60P6!7bGiWn@vD|+E@Xq zb!!_WiU^I|@1M}Hz6fN-m04x=>Exm{b@>UCW|c8vC`aNbtA@KCHujh^2RWZC}iYhL^<*Z93chIBJYU&w>$CGZDRcHuIgF&oyesDZ#&mA;?wxx4Cm#c0V$xYG?9OL(Smh}#fFuX(K;otJmvRP{h ze^f-qv;)HKC7geB92_@3a9@MGijS(hNNVd%-rZ;%@F_f7?Fjinbe1( zn#jQ*jKZTqE+AUTEd3y6t>*=;AO##cmdwU4gc2&rT8l`rtKW2JF<`_M#p>cj+)yCG zgKF)y8jrfxTjGO&ccm8RU>qn|HxQ7Z#sUo$q)P5H%8iBF$({0Ya51-rA@!It#NHN8MxqK zrYyl_&=}WVfQ?+ykV4*@F6)=u_~3BebR2G2>>mKaEBPmSW3(qYGGXj??m3L zHec{@jWCsSD8`xUy0pqT?Sw0oD?AUK*WxZn#D>-$`eI+IT)6ki>ic}W)t$V32^ITD zR497@LO}S|re%A+#vdv-?fXsQGVnP?QB_d0cGE+U84Q=aM=XrOwGFN3`Lpl@P0fL$ zKN1PqOwojH*($uaQFh8_)H#>Acl&UBSZ>!2W1Dinei`R4dJGX$;~60X=|SG6#jci} z&t4*dVDR*;+6Y(G{KGj1B2!qjvDYOyPC}%hnPbJ@g(4yBJrViG1#$$X75y+Ul1{%x zBAuD}Q@w?MFNqF-m39FGpq7RGI?%Bvyyig&oGv)lR>d<`Bqh=p>urib5DE;u$c|$J zwim~nPb19t?LJZsm{<(Iyyt@~H!a4yywmHKW&=1r5+oj*Fx6c89heW@(2R`i!Uiy* zp)=`Vr8sR!)KChE-6SEIyi(dvG3<1KoVt>kGV=zZiG7LGonH1+~yOK-`g0)r#+O|Q>)a`I2FVW%wr3lhO(P{ksNQuR!G_d zeTx(M!%brW_vS9?IF>bzZ2A3mWX-MEaOk^V|4d38{1D|KOlZSjBKrj7Fgf^>JyL0k zLoI$adZJ0T+8i_Idsuj}C;6jgx9LY#Ukh;!8eJ^B1N}q=Gn4onF*a2vY7~`x$r@rJ z`*hi&Z2lazgu{&nz>gjd>#eq*IFlXed(%$s5!HRXKNm zDZld+DwDI`O6hyn2uJ)F^{^;ESf9sjJ)wMSKD~R=DqPBHyP!?cGAvL<1|7K-(=?VO zGcKcF1spUa+ki<`6K#@QxOTsd847N8WSWztG~?~ z!gUJn>z0O=_)VCE|56hkT~n5xXTp}Ucx$Ii%bQ{5;-a4~I2e|{l9ur#*ghd*hSqO= z)GD@ev^w&5%k}YYB~!A%3*XbPPU-N6&3Lp1LxyP@|C<{qcn&?l54+zyMk&I3YDT|E z{lXH-e?C{huu<@~li+73lMOk&k)3s7Asn$t6!PtXJV!RkA`qdo4|OC_a?vR!kE_}k zK5R9KB%V@R7gt@9=TGL{=#r2gl!@3G;k-6sXp&E4u20DgvbY$iE**Xqj3TyxK>3AU z!b9}NXuINqt>Htt6fXIy5mj7oZ{A&$XJ&thR5ySE{mkxq_YooME#VCHm2+3D!f`{) zvR^WSjy_h4v^|!RJV-RaIT2Ctv=)UMMn@fAgjQV$2G+4?&dGA8vK35c-8r)z9Qqa=%k(FU)?iec14<^olkOU3p zF-6`zHiDKPafKK^USUU+D01>C&Wh{{q?>5m zGQp|z*+#>IIo=|ae8CtrN@@t~uLFOeT{}vX(IY*;>wAU=u1Qo4c+a&R);$^VCr>;! zv4L{`lHgc9$BeM)pQ#XA_(Q#=_iSZL4>L~8Hx}NmOC$&*Q*bq|9Aq}rWgFnMDl~d*;7c44GipcpH9PWaBy-G$*MI^F0 z?Tdxir1D<2ui+Q#^c4?uKvq=p>)lq56=Eb|N^qz~w7rsZu)@E4$;~snz+wIxi+980O6M#RmtgLYh@|2}9BiHSpTs zacjGKvwkUwR3lwTSsCHlwb&*(onU;)$yvdhikonn|B44JMgs*&Lo!jn`6AE>XvBiO z*LKNX3FVz9yLcsnmL!cRVO_qv=yIM#X|u&}#f%_?Tj0>8)8P_0r0!AjWNw;S44tst zv+NXY1{zRLf9OYMr6H-z?4CF$Y%MdbpFIN@a-LEnmkcOF>h16cH_;A|e)pJTuCJ4O zY7!4FxT4>4aFT8a92}84>q0&?46h>&0Vv0p>u~k&qd5$C1A6Q$I4V(5X~6{15;PD@ ze6!s9xh#^QI`J+%8*=^(-!P!@9%~buBmN2VSAp@TOo6}C?az+ALP8~&a0FWZk*F5N z^8P8IREnN`N0i@>O0?{i-FoFShYbUB`D7O4HB`Im2{yzXmyrg$k>cY6A@>bf7i3n0 z5y&cf2#`zctT>dz+hNF&+d3g;2)U!#vsb-%LC+pqKRTiiSn#FH#e!bVwR1nAf*TG^ z!RKcCy$P>?Sfq6n<%M{T0I8?p@HlgwC!HoWO>~mT+X<{Ylm+$Vtj9};H3$EB}P2wR$3y!TO#$iY8eO-!}+F&jMu4%E6S>m zB(N4w9O@2=<`WNJay5PwP8javDp~o~xkSbd4t4t8)9jqu@bHmJHq=MV~Pt|(TghCA}fhMS?s-{klV>~=VrT$nsp7mf{?cze~KKOD4 z_1Y!F)*7^W+BBTt1R2h4f1X4Oy2%?=IMhZU8c{qk3xI1=!na*Sg<=A$?K=Y=GUR9@ zQ(ylIm4Lgm>pt#%p`zHxok%vx_=8Fap1|?OM02|N%X-g5_#S~sT@A!x&8k#wVI2lo z1Uyj{tDQRpb*>c}mjU^gYA9{7mNhFAlM=wZkXcA#MHXWMEs^3>p9X)Oa?dx7b%N*y zLz@K^%1JaArjgri;8ptNHwz1<0y8tcURSbHsm=26^@CYJ3hwMaEvC7 z3Wi-@AaXIQ)%F6#i@%M>?Mw7$6(kW@?et@wbk-APcvMCC{>iew#vkZej8%9h0JSc? zCb~K|!9cBU+))^q*co(E^9jRl7gR4Jihyqa(Z(P&ID#TPyysVNL7(^;?Gan!OU>au zN}miBc&XX-M$mSv%3xs)bh>Jq9#aD_l|zO?I+p4_5qI0Ms*OZyyxA`sXcyiy>-{YN zA70%HmibZYcHW&YOHk6S&PQ+$rJ3(utuUra3V0~@=_~QZy&nc~)AS>v&<6$gErZC3 zcbC=eVkV4Vu0#}E*r=&{X)Kgq|8MGCh(wsH4geLj@#8EGYa})K2;n z{1~=ghoz=9TSCxgzr5x3@sQZZ0FZ+t{?klSI_IZa16pSx6*;=O%n!uXVZ@1IL;JEV zfOS&yyfE9dtS*^jmgt6>jQDOIJM5Gx#Y2eAcC3l^lmoJ{o0T>IHpECTbfYgPI4#LZq0PKqnPCD}_ zyKxz;(`fE0z~nA1s?d{X2!#ZP8wUHzFSOoTWQrk%;wCnBV_3D%3@EC|u$Ao)tO|AO z$4&aa!wbf}rbNcP{6=ajgg(`p5kTeu$ji20`zw)X1SH*x zN?T36{d9TY*S896Ijc^!35LLUByY4QO=ARCQ#MMCjudFc7s!z%P$6DESz%zZ#>H|i zw3Mc@v4~{Eke;FWs`5i@ifeYPh-Sb#vCa#qJPL|&quSKF%sp8*n#t?vIE7kFWjNFh zJC@u^bRQ^?ra|%39Ux^Dn4I}QICyDKF0mpe+Bk}!lFlqS^WpYm&xwIYxUoS-rJ)N9 z1Tz*6Rl9;x`4lwS1cgW^H_M*)Dt*DX*W?ArBf?-t|1~ge&S}xM0K;U9Ibf{okZHf~ z#4v4qc6s6Zgm8iKch5VMbQc~_V-ZviirnKCi*ouN^c_2lo&-M;YSA>W>>^5tlXObg zacX$k0=9Tf$Eg+#9k6yV(R5-&F{=DHP8!yvSQ`Y~XRnUx@{O$-bGCksk~3&qH^dqX zkf+ZZ?Nv5u>LBM@2?k%k&_aUb5Xjqf#!&7%zN#VZwmv65ezo^Y4S#(ed0yUn4tFOB zh1f1SJ6_s?a{)u6VdwUC!Hv=8`%T9(^c`2hc9nt$(q{Dm2X)dK49ba+KEheQ;7^0) ziFKw$%EHy_B1)M>=yK^=Z$U-LT36yX>EKT zvD8IAom2&2?bTmX@_PBR4W|p?6?LQ+&UMzXxqHC5VHzf@Eb1u)kwyfy+NOM8Wa2y@ zNNDL0PE$F;yFyf^jy&RGwDXQwYw6yz>OMWvJt98X@;yr!*RQDBE- zE*l*u=($Zi1}0-Y4lGaK?J$yQjgb+*ljUvNQ!;QYAoCq@>70=sJ{o{^21^?zT@r~hhf&O;Qiq+ ziGQQLG*D@5;LZ%09mwMiE4Q{IPUx-emo*;a6#DrmWr(zY27d@ezre)Z1BGZdo&pXn z+);gOFelKDmnjq#8dL7CTiVH)dHOqWi~uE|NM^QI3EqxE6+_n>IW67~UB#J==QOGF zp_S)c8TJ}uiaEiaER}MyB(grNn=2m&0yztA=!%3xUREyuG_jmadN*D&1nxvjZ6^+2 zORi7iX1iPi$tKasppaR9$a3IUmrrX)m*)fg1>H+$KpqeB*G>AQV((-G{}h=qItj|d zz~{5@{?&Dab6;0c7!!%Se>w($RmlG7Jlv_zV3Ru8b2rugY0MVPOOYGlokI7%nhIy& z-B&wE=lh2dtD!F?noD{z^O1~Tq4MhxvchzuT_oF3-t4YyA*MJ*n&+1X3~6quEN z@m~aEp=b2~mP+}TUP^FmkRS_PDMA{B zaSy(P=$T~R!yc^Ye0*pl5xcpm_JWI;@-di+nruhqZ4gy7cq-)I&s&Bt3BkgT(Zdjf zTvvv0)8xzntEtp4iXm}~cT+pi5k{w{(Z@l2XU9lHr4Vy~3ycA_T?V(QS{qwt?v|}k z_ST!s;C4!jyV5)^6xC#v!o*uS%a-jQ6< z)>o?z7=+zNNtIz1*F_HJ(w@=`E+T|9TqhC(g7kKDc8z~?RbKQ)LRMn7A1p*PcX2YR zUAr{);~c7I#3Ssv<0i-Woj0&Z4a!u|@Xt2J1>N-|ED<3$o2V?OwL4oQ%$@!zLamVz zB)K&Ik^~GOmDAa143{I4?XUk1<3-k{<%?&OID&>Ud%z*Rkt*)mko0RwC2=qFf-^OV z=d@47?tY=A;=2VAh0mF(3x;!#X!%{|vn;U2XW{(nu5b&8kOr)Kop3-5_xnK5oO_3y z!EaIb{r%D{7zwtGgFVri4_!yUIGwR(xEV3YWSI_+E}Gdl>TINWsIrfj+7DE?xp+5^ zlr3pM-Cbse*WGKOd3+*Qen^*uHk)+EpH-{u@i%y}Z!YSid<}~kA*IRSk|nf+I1N=2 zIKi+&ej%Al-M5`cP^XU>9A(m7G>58>o|}j0ZWbMg&x`*$B9j#Rnyo0#=BMLdo%=ks zLa3(2EinQLXQ(3zDe7Bce%Oszu%?8PO648TNst4SMFvj=+{b%)ELyB!0`B?9R6aO{i-63|s@|raSQGL~s)9R#J#duFaTSZ2M{X z1?YuM*a!!|jP^QJ(hAisJuPOM`8Y-Hzl~%d@latwj}t&0{DNNC+zJARnuQfiN`HQ# z?boY_2?*q;Qk)LUB)s8(Lz5elaW56p&fDH*AWAq7Zrbeq1!?FBGYHCnFgRu5y1jwD zc|yBz+UW|X`zDsc{W~8m$sh@VVnZD$lLnKlq@Hg^;ky!}ZuPdKNi2BI70;hrpvaA4+Q_+K)I@|)q1N-H zrycZU`*YUW``Qi^`bDX-j7j^&bO+-Xg$cz2#i##($uyW{Nl&{DK{=lLWV3|=<&si||2)l=8^8_z+Vho-#5LB0EqQ3v5U#*DF7 zxT)1j^`m+lW}p$>WSIG1eZ>L|YR-@Feu!YNWiw*IZYh03mq+2QVtQ}1ezRJM?0PA< z;mK(J5@N8>u@<6Y$QAHWNE};rR|)U_&bv8dsnsza7{=zD1VBcxrALqnOf-qW(zzTn zTAp|pEo#FsQ$~*$j|~Q;$Zy&Liu9OM;VF@#_&*nL!N2hH!Q6l*OeTxq!l>dEc{;Hw zCQni{iN%jHU*C;?M-VUaXxf0FEJ_G=C8)C-wD!DvhY+qQ#FT3}Th8;GgV&AV94F`D ztT6=w_Xm8)*)dBnDkZd~UWL|W=Glu!$hc|1w7_7l!3MAt95oIp4Xp{M%clu&TXehO z+L-1#{mjkpTF@?|w1P98OCky~S%@OR&o75P&ZHvC}Y=(2_{ib(-Al_7aZ^U?s34#H}= zGfFi5%KnFVCKtdO^>Htpb07#BeCXMDO8U}crpe1Gm`>Q=6qB4i=nLoLZ%p$TY=OcP z)r}Et-Ed??u~f09d3Nx3bS@ja!fV(Dfa5lXxRs#;8?Y8G+Qvz+iv7fiRkL3liip}) z&G0u8RdEC9c$$rdU53=MH`p!Jn|DHjhOxHK$tW_pw9wCTf0Eo<){HoN=zG!!Gq4z4 z7PwGh)VNPXW-cE#MtofE`-$9~nmmj}m zlzZscQ2+Jq%gaB9rMgVJkbhup0Ggpb)&L01T=%>n7-?v@I8!Q(p&+!fd+Y^Pu9l+u zek(_$^HYFVRRIFt@0Fp52g5Q#I`tC3li`;UtDLP*rA{-#Yoa5qp{cD)QYhldihWe+ zG~zuaqLY~$-1sjh2lkbXCX;lq+p~!2Z=76cvuQe*Fl>IFwpUBP+d^&E4BGc{m#l%Kuo6#{XGoRyFc%Hqhf|%nYd<;yiC>tyEyk z4I+a`(%%Ie=-*n z-{mg=j&t12)LH3R?@-B1tEb7FLMePI1HK0`Ae@#)KcS%!Qt9p4_fmBl5zhO10n401 zBSfnfJ;?_r{%R)hh}BBNSl=$BiAKbuWrNGQUZ)+0=Mt&5!X*D@yGCSaMNY&@`;^a4 z;v=%D_!K!WXV1!3%4P-M*s%V2b#2jF2bk!)#2GLVuGKd#vNpRMyg`kstw0GQ8@^k^ zuqK5uR<>FeRZ#3{%!|4X!hh7hgirQ@Mwg%%ez8pF!N$xhMNQN((yS(F2-OfduxxKE zxY#7O(VGfNuLv-ImAw5+h@gwn%!ER;*Q+001;W7W^waWT%@(T+5k!c3A-j)a8y11t zx4~rSN0s$M8HEOzkcWW4YbKK9GQez2XJ|Nq?TFy;jmGbg;`m&%U4hIiarKmdTHt#l zL=H;ZHE?fYxKQQXKnC+K!TAU}r086{4m}r()-QaFmU(qWhJlc$eas&y?=H9EYQy8N$8^bni9TpDp zkA^WRs?KgYgjxX4T6?`SMs$`s3vlut(YU~f2F+id(Rf_)$BIMibk9lACI~LA+i7xn z%-+=DHV*0TCTJp~-|$VZ@g2vmd*|2QXV;HeTzt530KyK>v&253N1l}bP_J#UjLy4) zBJili9#-ey8Kj(dxmW^ctorxd;te|xo)%46l%5qE-YhAjP`Cc03vT)vV&GAV%#Cgb zX~2}uWNvh`2<*AuxuJpq>SyNtZwzuU)r@@dqC@v=Ocd(HnnzytN+M&|Qi#f4Q8D=h ziE<3ziFW%+!yy(q{il8H44g^5{_+pH60Mx5Z*FgC_3hKxmeJ+wVuX?T#ZfOOD3E4C zRJsj#wA@3uvwZwHKKGN{{Ag+8^cs?S4N@6(Wkd$CkoCst(Z&hp+l=ffZ?2m%%ffI3 zdV7coR`R+*dPbNx=*ivWeNJK=Iy_vKd`-_Hng{l?hmp=|T3U&epbmgXXWs9ySE|=G zeQ|^ioL}tveN{s72_&h+F+W;G}?;?_s@h5>DX(rp#eaZ!E=NivgLI zWykLKev+}sHH41NCRm7W>K+_qdoJ8x9o5Cf!)|qLtF7Izxk*p|fX8UqEY)_sI_45O zL2u>x=r5xLE%s|d%MO>zU%KV6QKFiEeo12g#bhei4!Hm+`~Fo~4h|BJ)%ENxy9)Up zOxupSf1QZWun=)gF{L0YWJ<(r0?$bPFANrmphJ>kG`&7E+RgrWQi}ZS#-CQJ*i#8j zM_A0?w@4Mq@xvk^>QSvEU|VYQoVI=TaOrsLTa`RZfe8{9F~mM{L+C`9YP9?OknLw| zmkvz>cS6`pF0FYeLdY%>u&XpPj5$*iYkj=m7wMzHqzZ5SG~$i_^f@QEPEC+<2nf-{ zE7W+n%)q$!5@2pBuXMxhUSi*%F>e_g!$T-_`ovjBh(3jK9Q^~OR{)}!0}vdTE^M+m z9QWsA?xG>EW;U~5gEuKR)Ubfi&YWnXV;3H6Zt^NE725*`;lpSK4HS1sN?{~9a4JkD z%}23oAovytUKfRN87XTH2c=kq1)O5(fH_M3M-o{{@&~KD`~TRot-gqg7Q2U2o-iiF}K>m?CokhmODaLB z1p6(6JYGntNOg(s!(>ZU&lzDf+Ur)^Lirm%*}Z>T)9)fAZ9>k(kvnM;ab$ptA=hoh zVgsVaveXbMpm{|4*d<0>?l_JUFOO8A3xNLQOh%nVXjYI6X8h?a@6kDe5-m&;M0xqx z+1U$s>(P9P)f0!{z%M@E7|9nn#IWgEx6A6JNJ(7dk`%6$3@!C!l;JK-p2?gg+W|d- ziEzgk$w7k48NMqg$CM*4O~Abj3+_yUKTyK1p6GDsGEs;}=E_q>^LI-~pym$qhXPJf z2`!PJDp4l(TTm#|n@bN!j;-FFOM__eLl!6{*}z=)UAcGYloj?bv!-XY1TA6Xz;82J zLRaF{8ayzGa|}c--}|^xh)xgX>6R(sZD|Z|qX50gu=d`gEwHqC@WYU7{%<5VOnf9+ zB@FX?|UL%`8EIAe!*UdYl|6wRz6Y>(#8x92$#y}wMeE|ZM2X*c}dKJ^4NIf;Fm zNwzq%QcO?$NR-7`su!*$dlIKo2y(N;qgH@1|8QNo$0wbyyJ2^}$iZ>M{BhBjTdMjK z>gPEzgX4;g3$rU?jvDeOq`X=>)zdt|jk1Lv3u~bjHI=EGLfIR&+K3ldcc4D&Um&04 z3^F*}WaxR(ZyaB>DlmF_UP@+Q*h$&nsOB#gwLt{1#F4i-{A5J@`>B9@{^i?g_Ce&O z<<}_We-RUFU&&MHa1#t56u_oM(Ljn7djja!T|gcxSoR=)@?owC*NkDarpBj=W4}=i1@)@L|C) zQKA+o<(pMVp*Su(`zBC0l1yTa$MRfQ#uby|$mlOMs=G`4J|?apMzKei%jZql#gP@IkOaOjB7MJM=@1j(&!jNnyVkn5;4lvro1!vq ztXiV8HYj5%)r1PPpIOj)f!>pc^3#LvfZ(hz}C@-3R(Cx7R427*Fwd!XO z4~j&IkPHcBm0h_|iG;ZNrYdJ4HI!$rSyo&sibmwIgm1|J#g6%>=ML1r!kcEhm(XY& zD@mIJt;!O%WP7CE&wwE3?1-dt;RTHdm~LvP7K`ccWXkZ0kfFa2S;wGtx_a}S2lslw z$<4^Jg-n#Ypc(3t2N67Juasu=h)j&UNTPNDil4MQMTlnI81kY46uMH5B^U{~nmc6+ z9>(lGhhvRK9ITfpAD!XQ&BPphL3p8B4PVBN0NF6U49;ZA0Tr75AgGw7(S=Yio+xg_ zepZ*?V#KD;sHH+15ix&yCs0eSB-Z%D%uujlXvT#V$Rz@$+w!u#3GIo*AwMI#Bm^oO zLr1e}k5W~G0xaO!C%Mb{sarxWZ4%Dn9vG`KHmPC9GWZwOOm11XJp#o0-P-${3m4g( z6~)X9FXw%Xm~&99tj>a-ri})ZcnsfJtc10F@t9xF5vq6E)X!iUXHq-ohlO`gQdS&k zZl})3k||u)!_=nNlvMbz%AuIr89l#I$;rG}qvDGiK?xTd5HzMQkw*p$YvFLGyQM!J zNC^gD!kP{A84nGosi~@MLKqWQNacfs7O$dkZtm4-BZ~iA8xWZPkTK!HpA5zr!9Z&+icfAJ1)NWkTd!-9`NWU>9uXXUr;`Js#NbKFgrNhTcY4GNv*71}}T zFJh?>=EcbUd2<|fiL+H=wMw8hbX6?+_cl4XnCB#ddwdG>bki* zt*&6Dy&EIPluL@A3_;R%)shA-tDQA1!Tw4ffBRyy;2n)vm_JV06(4Or&QAOKNZB5f(MVC}&_!B>098R{Simr!UG}?CW1Ah+X+0#~0`X)od zLYablwmFxN21L))!_zc`IfzWi`5>MxPe(DmjjO1}HHt7TJtAW+VXHt!aKZk>y6PoMsbDXRJnov;D~Ur~2R_7(Xr)aa%wJwZhS3gr7IGgt%@;`jpL@gyc6bGCVx!9CE7NgIbUNZ!Ur1RHror0~ zr(j$^yM4j`#c2KxSP61;(Tk^pe7b~}LWj~SZC=MEpdKf;B@on9=?_n|R|0q;Y*1_@ z>nGq>)&q!;u-8H)WCwtL&7F4vbnnfSAlK1mwnRq2&gZrEr!b1MA z(3%vAbh3aU-IX`d7b@q`-WiT6eitu}ZH9x#d&qx}?CtDuAXak%5<-P!{a`V=$|XmJ zUn@4lX6#ulB@a=&-9HG)a>KkH=jE7>&S&N~0X0zD=Q=t|7w;kuh#cU=NN7gBGbQTT z;?bdSt8V&IIi}sDTzA0dkU}Z-Qvg;RDe8v>468p3*&hbGT1I3hi9hh~Z(!H}{+>eUyF)H&gdrX=k$aB%J6I;6+^^kn1mL+E+?A!A}@xV(Qa@M%HD5C@+-4Mb4lI=Xp=@9+^x+jhtOc zYgF2aVa(uSR*n(O)e6tf3JEg2xs#dJfhEmi1iOmDYWk|wXNHU?g23^IGKB&yHnsm7 zm_+;p?YpA#N*7vXCkeN2LTNG`{QDa#U3fcFz7SB)83=<8rF)|udrEbrZL$o6W?oDR zQx!178Ih9B#D9Ko$H(jD{4MME&<|6%MPu|TfOc#E0B}!j^MMpV69D#h2`vsEQ{(?c zJ3Lh!3&=yS5fWL~;1wCZ?)%nmK`Eqgcu)O6rD^3%ijcxL50^z?OI(LaVDvfL0#zjZ z2?cPvC$QCzpxpt5jMFp05OxhK0F!Q`rPhDi5)y=-0C} zIM~ku&S@pl1&0=jl+rlS<4`riV~LC-#pqNde@44MB(j%)On$0Ko(@q?4`1?4149Z_ zZi!5aU@2vM$dHR6WSZpj+VboK+>u-CbNi7*lw4K^ZxxM#24_Yc`jvb9NPVi75L+MlM^U~`;a7`4H0L|TYK>%hfEfXLsu1JGM zbh|8{wuc7ucV+`Ys1kqxsj`dajwyM;^X^`)#<+a~$WFy8b2t_RS{8yNYKKlnv+>vB zX(QTf$kqrJ;%I@EwEs{cIcH@Z3|#^S@M+5jsP<^`@8^I4_8MlBb`~cE^n+{{;qW2q z=p1=&+fUo%T{GhVX@;56kH8K_%?X=;$OTYqW1L*)hzelm^$*?_K;9JyIWhsn4SK(| zSmXLTUE8VQX{se#8#Rj*lz`xHtT<61V~fb;WZUpu(M)f#;I+2_zR+)y5Jv?l`CxAinx|EY!`IJ*x9_gf_k&Gx2alL!hK zUWj1T_pk|?iv}4EP#PZvYD_-LpzU!NfcLL%fK&r$W8O1KH9c2&GV~N#T$kaXGvAOl)|T zuF9%6(i=Y3q?X%VK-D2YIYFPH3f|g$TrXW->&^Ab`WT z7>Oo!u1u40?jAJ8Hy`bv}qbgs8)cF0&qeVjD?e+3Ggn1Im>K77ZSpbU*08 zfZkIFcv?y)!*B{|>nx@cE{KoutP+seQU?bCGE`tS0GKUO3PN~t=2u7q_6$l;uw^4c zVu^f{uaqsZ{*a-N?2B8ngrLS8E&s6}Xtv9rR9C^b`@q8*iH)pFzf1|kCfiLw6u{Z%aC z!X^5CzF6qofFJgklJV3oc|Qc2XdFl+y5M9*P8}A>Kh{ zWRgRwMSZ(?Jw;m%0etU5BsWT-Dj-5F;Q$OQJrQd+lv`i6>MhVo^p*^w6{~=fhe|bN z*37oV0kji)4an^%3ABbg5RC;CS50@PV5_hKfXjYx+(DqQdKC^JIEMo6X66$qDdLRc z!YJPSKnbY`#Ht6`g@xGzJmKzzn|abYbP+_Q(v?~~ z96%cd{E0BCsH^0HaWt{y(Cuto4VE7jhB1Z??#UaU(*R&Eo+J`UN+8mcb51F|I|n*J zJCZ3R*OdyeS9hWkc_mA7-br>3Tw=CX2bl(=TpVt#WP8Bg^vE_9bP&6ccAf3lFMgr` z{3=h@?Ftb$RTe&@IQtiJfV;O&4fzh)e1>7seG; z=%mA4@c7{aXeJnhEg2J@Bm;=)j=O=cl#^NNkQ<{r;Bm|8Hg}bJ-S^g4`|itx)~!LN zXtL}?f1Hs6UQ+f0-X6&TBCW=A4>bU0{rv8C4T!(wD-h>VCK4YJk`6C9$by!fxOYw- zV#n+0{E(0ttq_#16B} ze8$E#X9o{B!0vbq#WUwmv5Xz6{(!^~+}sBW{xctdNHL4^vDk!0E}(g|W_q;jR|ZK< z8w>H-8G{%R#%f!E7cO_^B?yFRKLOH)RT9GJsb+kAKq~}WIF)NRLwKZ^Q;>!2MNa|} z-mh?=B;*&D{Nd-mQRcfVnHkChI=DRHU4ga%xJ%+QkBd|-d9uRI76@BT(bjsjwS+r) zvx=lGNLv1?SzZ;P)Gnn>04fO7Culg*?LmbEF0fATG8S@)oJ>NT3pYAXa*vX!eUTDF ziBrp(QyDqr0ZMTr?4uG_Nqs6f%S0g?h`1vO5fo=5S&u#wI2d4+3hWiolEU!=3_oFo zfie?+4W#`;1dd#X@g9Yj<53S<6OB!TM8w8})7k-$&q5(smc%;r z(BlXkTp`C47+%4JA{2X}MIaPbVF!35P#p;u7+fR*46{T+LR8+j25oduCfDzDv6R-hU{TVVo9fz?^N3ShMt!t0NsH)pB zRK8-S{Dn*y3b|k^*?_B70<2gHt==l7c&cT>r`C#{S}J2;s#d{M)ncW(#Y$C*lByLQ z&?+{dR7*gpdT~(1;M(FfF==3z`^eW)=5a9RqvF-)2?S-(G zhS;p(u~_qBum*q}On@$#08}ynd0+spzyVco0%G6;<-i5&016cV5UKzhQ~)fX03|>L z8ej+HzzgVr6_5ZUpa4HW0Ca!=r1%*}Oo;2no&Zz8DfR)L!@r<5 z2viSZpmvo5XqXyAz{Ms7`7kX>fnr1gi4X~7KpznRT0{Xc5Cfz@43PjBMBoH@z_{~( z(Wd}IPJ9hH+%)Fc)0!hrV+(A;76rhtI|YHbEDeERV~Ya>SQg^IvlazFkSK(KG9&{q zkPIR~EeQaaBmwA<20}mBO?)N$(z1@p)5?%}rM| zGF()~Z&Kx@OIDRI$d0T8;JX@vj3^2%pd_+@l9~a4lntZ;AvUIjqIZbuNTR6@hNJoV zk4F;ut)LN4ARuyn2M6F~eg-e#UH%2P;8uPGFW^vq1vj8mdIayFOZo(tphk8C7hpT~ z1Fv8?b_LNR3QD9J+!v=p%}# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/glyphicons-halflings-regular.ttf b/docs/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1413fc609ab6f21774de0cb7e01360095584f65b GIT binary patch literal 45404 zcmd?Sd0-pWwLh*qi$?oCk~i6sWlOeWJC3|4juU5JNSu9hSVACzERcmjLV&P^utNzg zIE4Kr1=5g!SxTX#Ern9_%4&01rlrW`Z!56xXTGQR4C z3vR~wXq>NDx$c~e?;ia3YjJ*$!C>69a?2$lLyhpI!CFfJsP=|`8@K0|bbMpWwVUEygg0=0x_)HeHpGSJagJNLA3c!$EuOV>j$wi! zbo{vZ(s8tl>@!?}dmNHXo)ABy7ohD7_1G-P@SdJWT8*oeyBVYVW9*vn}&VI4q++W;Z+uz=QTK}^C75!`aFYCX# zf7fC2;o`%!huaTNJAB&VWrx=szU=VLhwnbT`vc<#<`4WI6n_x@AofA~2d90o?1L3w z9!I|#P*NQ)$#9aASijuw>JRld^-t)Zhmy|i-`Iam|IWkguaMR%lhi4p~cX-9& zjfbx}yz}s`4-6>D^+6FzihR)Y!GsUy=_MWi_v7y#KmYi-{iZ+s@ekkq!@Wxz!~BQwiI&ti z>hC&iBe2m(dpNVvSbZe3DVgl(dxHt-k@{xv;&`^c8GJY%&^LpM;}7)B;5Qg5J^E${ z7z~k8eWOucjX6)7q1a%EVtmnND8cclz8R1=X4W@D8IDeUGXxEWe&p>Z*voO0u_2!! zj3dT(Ki+4E;uykKi*yr?w6!BW2FD55PD6SMj`OfBLwXL5EA-9KjpMo4*5Eqs^>4&> z8PezAcn!9jk-h-Oo!E9EjX8W6@EkTHeI<@AY{f|5fMW<-Ez-z)xCvW3()Z#x0oydB zzm4MzY^NdpIF9qMp-jU;99LjlgY@@s+=z`}_%V*xV7nRV*Kwrx-i`FzI0BZ#yOI8# z!SDeNA5b6u9!Imj89v0(g$;dT_y|Yz!3V`i{{_dez8U@##|X9A};s^7vEd!3AcdyVlhVk$v?$O442KIM1-wX^R{U7`JW&lPr3N(%kXfXT_`7w^? z=#ntx`tTF|N$UT?pELvw7T*2;=Q-x@KmDUIbLyXZ>f5=y7z1DT<7>Bp0k;eItHF?1 zErzhlD2B$Tm|^7DrxnTYm-tgg`Mt4Eivp5{r$o9e)8(fXBO4g|G^6Xy?y$SM*&V52 z6SR*%`%DZC^w(gOWQL?6DRoI*hBNT)xW9sxvmi@!vI^!mI$3kvAMmR_q#SGn3zRb_ zGe$=;Tv3dXN~9XuIHow*NEU4y&u}FcZEZoSlXb9IBOA}!@J3uovp}yerhPMaiI8|SDhvWVr z^BE&yx6e3&RYqIg;mYVZ*3#A-cDJ;#ms4txEmwm@g^s`BB}KmSr7K+ruIoKs=s|gOXP|2 zb1!)87h9?(+1^QRWb(Vo8+@G=o24gyuzF3ytfsKjTHZJ}o{YznGcTDm!s)DRnmOX} z3pPL4wExoN$kyc2>#J`k+<67sy-VsfbQ-1u+HkyFR?9G`9r6g4*8!(!c65Be-5hUg zZHY$M0k(Yd+DT1*8)G(q)1&tDl=g9H7!bZTOvEEFnBOk_K=DXF(d4JOaH zI}*A3jGmy{gR>s}EQzyJa_q_?TYPNXRU1O;fcV_&TQZhd{@*8Tgpraf~nT0BYktu*n{a~ub^UUqQPyr~yBY{k2O zgV)honv{B_CqY|*S~3up%Wn%7i*_>Lu|%5~j)}rQLT1ZN?5%QN`LTJ}vA!EE=1`So z!$$Mv?6T)xk)H8JTrZ~m)oNXxS}pwPd#);<*>zWsYoL6iK!gRSBB{JCgB28C#E{T? z5VOCMW^;h~eMke(w6vLlKvm!!TyIf;k*RtK)|Q>_@nY#J%=h%aVb)?Ni_By)XNxY)E3`|}_u}fn+Kp^3p4RbhFUBRtGsDyx9Eolg77iWN z2iH-}CiM!pfYDIn7;i#Ui1KG01{3D<{e}uWTdlX4Vr*nsb^>l0%{O?0L9tP|KGw8w z+T5F}md>3qDZQ_IVkQ|BzuN08uN?SsVt$~wcHO4pB9~ykFTJO3g<4X({-Tm1w{Ufo zI03<6KK`ZjqVyQ(>{_aMxu7Zm^ck&~)Q84MOsQ-XS~{6j>0lTl@lMtfWjj;PT{nlZ zIn0YL?kK7CYJa)(8?unZ)j8L(O}%$5S#lTcq{rr5_gqqtZ@*0Yw4}OdjL*kBv+>+@ z&*24U=y{Nl58qJyW1vTwqsvs=VRAzojm&V zEn6=WzdL1y+^}%Vg!ap>x%%nFi=V#wn# zUuheBR@*KS)5Mn0`f=3fMwR|#-rPMQJg(fW*5e`7xO&^UUH{L(U8D$JtI!ac!g(Ze89<`UiO@L+)^D zjPk2_Ie0p~4|LiI?-+pHXuRaZKG$%zVT0jn!yTvvM^jlcp`|VSHRt-G@_&~<4&qW@ z?b#zIN)G(}L|60jer*P7#KCu*Af;{mpWWvYK$@Squ|n-Vtfgr@ZOmR5Xpl;0q~VILmjk$$mgp+`<2jP z@+nW5Oap%fF4nFwnVwR7rpFaOdmnfB$-rkO6T3#w^|*rft~acgCP|ZkgA6PHD#Of| zY%E!3tXtsWS`udLsE7cSE8g@p$ceu*tI71V31uA7jwmXUCT7+Cu3uv|W>ZwD{&O4Nfjjvl43N#A$|FWxId! z%=X!HSiQ-#4nS&smww~iXRn<-`&zc)nR~js?|Ei-cei$^$KsqtxNDZvl1oavXK#Pz zT&%Wln^Y5M95w=vJxj0a-ko_iQt(LTX_5x#*QfQLtPil;kkR|kz}`*xHiLWr35ajx zHRL-QQv$|PK-$ges|NHw8k6v?&d;{A$*q15hz9{}-`e6ys1EQ1oNNKDFGQ0xA!x^( zkG*-ueZT(GukSnK&Bs=4+w|(kuWs5V_2#3`!;f}q?>xU5IgoMl^DNf+Xd<=sl2XvkqviJ>d?+G@Z5nxxd5Sqd$*ENUB_mb8Z+7CyyU zA6mDQ&e+S~w49csl*UePzY;^K)Fbs^%?7;+hFc(xz#mWoek4_&QvmT7Fe)*{h-9R4 zqyXuN5{)HdQ6yVi#tRUO#M%;pL>rQxN~6yoZ)*{{!?jU)RD*oOxDoTjVh6iNmhWNC zB5_{R=o{qvxEvi(khbRS`FOXmOO|&Dj$&~>*oo)bZz%lPhEA@ zQ;;w5eu5^%i;)w?T&*=UaK?*|U3~{0tC`rvfEsRPgR~16;~{_S2&=E{fE2=c>{+y} zx1*NTv-*zO^px5TA|B```#NetKg`19O!BK*-#~wDM@KEllk^nfQ2quy25G%)l72<> zzL$^{DDM#jKt?<>m;!?E2p0l12`j+QJjr{Lx*47Nq(v6i3M&*P{jkZB{xR?NOSPN% zU>I+~d_ny=pX??qjF*E78>}Mgts@_yn`)C`wN-He_!OyE+gRI?-a>Om>Vh~3OX5+& z6MX*d1`SkdXwvb7KH&=31RCC|&H!aA1g_=ZY0hP)-Wm6?A7SG0*|$mC7N^SSBh@MG z9?V0tv_sE>X==yV{)^LsygK2=$Mo_0N!JCOU?r}rmWdHD%$h~~G3;bt`lH& zAuOOZ=G1Mih**0>lB5x+r)X^8mz!0K{SScj4|a=s^VhUEp#2M=^#WRqe?T&H9GnWa zYOq{+gBn9Q0e0*Zu>C(BAX=I-Af9wIFhCW6_>TsIH$d>|{fIrs&BX?2G>GvFc=<8` zVJ`#^knMU~65dWGgXcht`Kb>{V2oo%<{NK|iH+R^|Gx%q+env#Js*(EBT3V0=w4F@W+oLFsA)l7Qy8mx_;6Vrk;F2RjKFvmeq} zro&>@b^(?f))OoQ#^#s)tRL>b0gzhRYRG}EU%wr9GjQ#~Rpo|RSkeik^p9x2+=rUr}vfnQoeFAlv=oX%YqbLpvyvcZ3l$B z5bo;hDd(fjT;9o7g9xUg3|#?wU2#BJ0G&W1#wn?mfNR{O7bq747tc~mM%m%t+7YN}^tMa24O4@w<|$lk@pGx!;%pKiq&mZB z?3h<&w>un8r?Xua6(@Txu~Za9tI@|C4#!dmHMzDF_-_~Jolztm=e)@vG11bZQAs!tFvd9{C;oxC7VfWq377Y(LR^X_TyX9bn$)I765l=rJ%9uXcjggX*r?u zk|0!db_*1$&i8>d&G3C}A`{Fun_1J;Vx0gk7P_}8KBZDowr*8$@X?W6v^LYmNWI)lN92yQ;tDpN zOUdS-W4JZUjwF-X#w0r;97;i(l}ZZT$DRd4u#?pf^e2yaFo zbm>I@5}#8FjsmigM8w_f#m4fEP~r~_?OWB%SGWcn$ThnJ@Y`ZI-O&Qs#Y14To( zWAl>9Gw7#}eT(!c%D0m>5D8**a@h;sLW=6_AsT5v1Sd_T-C4pgu_kvc?7+X&n_fct znkHy(_LExh=N%o3I-q#f$F4QJpy>jZBW zRF7?EhqTGk)w&Koi}QQY3sVh?@e-Z3C9)P!(hMhxmXLC zF_+ZSTQU`Gqx@o(~B$dbr zHlEUKoK&`2gl>zKXlEi8w6}`X3kh3as1~sX5@^`X_nYl}hlbpeeVlj#2sv)CIMe%b zBs7f|37f8qq}gA~Is9gj&=te^wN8ma?;vF)7gce;&sZ64!7LqpR!fy)?4cEZposQ8 zf;rZF7Q>YMF1~eQ|Z*!5j0DuA=`~VG$Gg6B?Om1 z6fM@`Ck-K*k(eJ)Kvysb8sccsFf@7~3vfnC=<$q+VNv)FyVh6ZsWw}*vs>%k3$)9| zR9ek-@pA23qswe1io)(Vz!vS1o*XEN*LhVYOq#T`;rDkgt86T@O`23xW~;W_#ZS|x zvwx-XMb7_!hIte-#JNpFxskMMpo2OYhHRr0Yn8d^(jh3-+!CNs0K2B!1dL$9UuAD= zQ%7Ae(Y@}%Cd~!`h|wAdm$2WoZ(iA1(a_-1?znZ%8h72o&Mm*4x8Ta<4++;Yr6|}u zW8$p&izhdqF=m8$)HyS2J6cKyo;Yvb>DTfx4`4R{ zPSODe9E|uflE<`xTO=r>u~u=NuyB&H!(2a8vwh!jP!yfE3N>IiO1jI>7e&3rR#RO3_}G23W?gwDHgSgekzQ^PU&G5z&}V5GO? zfg#*72*$DP1T8i`S7=P;bQ8lYF9_@8^C(|;9v8ZaK2GnWz4$Th2a0$)XTiaxNWfdq z;yNi9veH!j)ba$9pke8`y2^63BP zIyYKj^7;2don3se!P&%I2jzFf|LA&tQ=NDs{r9fIi-F{-yiG-}@2`VR^-LIFN8BC4 z&?*IvLiGHH5>NY(Z^CL_A;yISNdq58}=u~9!Ia7 zm7MkDiK~lsfLpvmPMo!0$keA$`%Tm`>Fx9JpG^EfEb(;}%5}B4Dw!O3BCkf$$W-dF z$BupUPgLpHvr<<+QcNX*w@+Rz&VQz)Uh!j4|DYeKm5IC05T$KqVV3Y|MSXom+Jn8c zgUEaFW1McGi^44xoG*b0JWE4T`vka7qTo#dcS4RauUpE{O!ZQ?r=-MlY#;VBzhHGU zS@kCaZ*H73XX6~HtHd*4qr2h}Pf0Re@!WOyvres_9l2!AhPiV$@O2sX>$21)-3i+_ z*sHO4Ika^!&2utZ@5%VbpH(m2wE3qOPn-I5Tbnt&yn9{k*eMr3^u6zG-~PSr(w$p> zw)x^a*8Ru$PE+{&)%VQUvAKKiWiwvc{`|GqK2K|ZMy^Tv3g|zENL86z7i<c zW`W>zV1u}X%P;Ajn+>A)2iXZbJ5YB_r>K-h5g^N=LkN^h0Y6dPFfSBh(L`G$D%7c` z&0RXDv$}c7#w*7!x^LUes_|V*=bd&aP+KFi((tG*gakSR+FA26%{QJdB5G1F=UuU&koU*^zQA=cEN9}Vd?OEh| zgzbFf1?@LlPkcXH$;YZe`WEJ3si6&R2MRb}LYK&zK9WRD=kY-JMPUurX-t4(Wy{%` zZ@0WM2+IqPa9D(^*+MXw2NWwSX-_WdF0nMWpEhAyotIgqu5Y$wA=zfuXJ0Y2lL3#ji26-P3Z?-&0^KBc*`T$+8+cqp`%g0WB zTH9L)FZ&t073H4?t=(U6{8B+uRW_J_n*vW|p`DugT^3xe8Tomh^d}0k^G7$3wLgP& zn)vTWiMA&=bR8lX9H=uh4G04R6>C&Zjnx_f@MMY!6HK5v$T%vaFm;E8q=`w2Y}ucJ zkz~dKGqv9$E80NTtnx|Rf_)|3wxpnY6nh3U9<)fv2-vhQ6v=WhKO@~@X57N-`7Ppc zF;I7)eL?RN23FmGh0s;Z#+p)}-TgTJE%&>{W+}C`^-sy{gTm<$>rR z-X7F%MB9Sf%6o7A%ZHReD4R;imU6<9h81{%avv}hqugeaf=~^3A=x(Om6Lku-Pn9i zC;LP%Q7Xw*0`Kg1)X~nAsUfdV%HWrpr8dZRpd-#%)c#Fu^mqo|^b{9Mam`^Zw_@j@ zR&ZdBr3?@<@%4Z-%LT&RLgDUFs4a(CTah_5x4X`xDRugi#vI-cw*^{ncwMtA4NKjByYBza)Y$hozZCpuxL{IP&=tw6ZO52WY3|iwGf&IJCn+u(>icK zZB1~bWXCmwAUz|^<&ysd#*!DSp8}DLNbl5lRFat4NkvItxy;9tpp9~|@ z;JctShv^Iq4(z+y7^j&I?GCdKMVg&jCwtCkc4*@O7HY*veGDBtAIn*JgD$QftP}8= zxFAdF=(S>Ra6(4slk#h%b?EOU-96TIX$Jbfl*_7IY-|R%H zF8u|~hYS-YwWt5+^!uGcnKL~jM;)ObZ#q68ZkA?}CzV-%6_vPIdzh_wHT_$mM%vws9lxUj;E@#1UX?WO2R^41(X!nk$+2oJGr!sgcbn1f^yl1 z#pbPB&Bf;1&2+?};Jg5qgD1{4_|%X#s48rOLE!vx3@ktstyBsDQWwDz4GYlcgu$UJ zp|z_32yN72T*oT$SF8<}>e;FN^X&vWNCz>b2W0rwK#<1#kbV)Cf`vN-F$&knLo5T& z8!sO-*^x4=kJ$L&*h%rQ@49l?7_9IG99~xJDDil00<${~D&;kiqRQqeW5*22A`8I2 z(^@`qZoF7_`CO_e;8#qF!&g>UY;wD5MxWU>azoo=E{kW(GU#pbOi%XAn%?W{b>-bTt&2?G=E&BnK9m0zs{qr$*&g8afR_x`B~o zd#dxPpaap;I=>1j8=9Oj)i}s@V}oXhP*{R|@DAQXzQJekJnmuQ;vL90_)H_nD1g6e zS1H#dzg)U&6$fz0g%|jxDdz|FQN{KJ&Yx0vfuzAFewJjv`pdMRpY-wU`-Y6WQnJ(@ zGVb!-8DRJZvHnRFiR3PG3Tu^nCn(CcZHh7hQvyd7i6Q3&ot86XI{jo%WZqCPcTR0< zMRg$ZE=PQx66ovJDvI_JChN~k@L^Pyxv#?X^<)-TS5gk`M~d<~j%!UOWG;ZMi1af< z+86U0=sm!qAVJAIqqU`Qs1uJhQJA&n@9F1PUrYuW!-~IT>l$I!#5dBaiAK}RUufjg{$#GdQBkxF1=KU2E@N=i^;xgG2Y4|{H>s` z$t`k8c-8`fS7Yfb1FM#)vPKVE4Uf(Pk&%HLe z%^4L>@Z^9Z{ZOX<^e)~adVRkKJDanJ6VBC_m@6qUq_WF@Epw>AYqf%r6qDzQ~AEJ!jtUvLp^CcqZ^G-;Kz3T;O4WG45Z zFhrluCxlY`M+OKr2SeI697btH7Kj`O>A!+2DTEQ=48cR>Gg2^5uqp(+y5Sl09MRl* zp|28!v*wvMd_~e2DdKDMMQ|({HMn3D%%ATEecGG8V9>`JeL)T0KG}=}6K8NiSN5W< z79-ZdYWRUb`T}(b{RjN8>?M~opnSRl$$^gT`B27kMym5LNHu-k;A;VF8R(HtDYJHS zU7;L{a@`>jd0svOYKbwzq+pWSC(C~SPgG~nWR3pBA8@OICK$Cy#U`kS$I;?|^-SBC zBFkoO8Z^%8Fc-@X!KebF2Ob3%`8zlVHj6H;^(m7J35(_bS;cZPd}TY~qixY{MhykQ zV&7u7s%E=?i`}Ax-7dB0ih47w*7!@GBt<*7ImM|_mYS|9_K7CH+i}?*#o~a&tF-?C zlynEu1DmiAbGurEX2Flfy$wEVk7AU;`k#=IQE*6DMWafTL|9-vT0qs{A3mmZGzOyN zcM9#Rgo7WgB_ujU+?Q@Ql?V-!E=jbypS+*chI&zA+C_3_@aJal}!Q54?qsL0In({Ly zjH;e+_SK8yi0NQB%TO+Dl77jp#2pMGtwsgaC>K!)NimXG3;m7y`W+&<(ZaV>N*K$j zLL~I+6ouPk6_(iO>61cIsinx`5}DcKSaHjYkkMuDoVl>mKO<4$F<>YJ5J9A2Vl}#BP7+u~L8C6~D zsk`pZ$9Bz3teQS1Wb|8&c2SZ;qo<#F&gS;j`!~!ADr(jJXMtcDJ9cVi>&p3~{bqaP zgo%s8i+8V{UrYTc9)HiUR_c?cfx{Yan2#%PqJ{%?Wux4J;T$#cumM0{Es3@$>}DJg zqe*c8##t;X(4$?A`ve)e@YU3d2Balcivot{1(ahlE5qg@S-h(mPNH&`pBX$_~HdG48~)$x5p z{>ghzqqn_t8~pY<5?-To>cy^6o~mifr;KWvx_oMtXOw$$d6jddXG)V@a#lL4o%N@A zNJlQAz6R8{7jax-kQsH6JU_u*En%k^NHlvBB!$JAK!cYmS)HkLAkm0*9G3!vwMIWv zo#)+EamIJHEUV|$d|<)2iJ`lqBQLx;HgD}c3mRu{iK23C>G{0Mp1K)bt6OU?xC4!_ zZLqpFzeu&+>O1F>%g-%U^~yRg(-wSp@vmD-PT#bCWy!%&H;qT7rfuRCEgw67V!Qob z&tvPU@*4*$YF#2_>M0(75QxqrJr3Tvh~iDeFhxl=MzV@(psx%G8|I{~9;tv#BBE`l z3)_98eZqFNwEF1h)uqhBmT~mSmT8k$7vSHdR97K~kM)P9PuZdS;|Op4A?O<*%!?h` zn`}r_j%xvffs46x2hCWuo0BfIQWCw9aKkH==#B(TJ%p}p-RuIVzsRlaPL_Co{&R0h zQrqn=g1PGjQg3&sc2IlKG0Io#v%@p>tFwF)RG0ahYs@Zng6}M*d}Xua)+h&?$`%rb z;>M=iMh5eIHuJ5c$aC`y@CYjbFsJnSPH&}LQz4}za9YjDuao>Z^EdL@%saRm&LGQWXs*;FzwN#pH&j~SLhDZ+QzhplV_ij(NyMl z;v|}amvxRddO81LJFa~2QFUs z+Lk zZck)}9uK^buJNMo4G(rSdX{57(7&n=Q6$QZ@lIO9#<3pA2ceDpO_340B*pHlh_y{>i&c1?vdpN1j>3UN-;;Yq?P+V5oY`4Z(|P8SwWq<)n`W@AwcQ?E9 zd5j8>FT^m=MHEWfN9jS}UHHsU`&SScib$qd0i=ky0>4dz5ADy70AeIuSzw#gHhQ_c zOp1!v6qU)@8MY+ zMNIID?(CysRc2uZQ$l*QZVY)$X?@4$VT^>djbugLQJdm^P>?51#lXBkdXglYm|4{L zL%Sr?2f`J+xrcN@=0tiJt(<-=+v>tHy{XaGj7^cA6felUn_KPa?V4ebfq7~4i~GKE zpm)e@1=E;PP%?`vK6KVPKXjUXyLS1^NbnQ&?z>epHCd+J$ktT1G&L~T)nQeExe;0Z zlei}<_ni ztFo}j7nBl$)s_3odmdafVieFxc)m!wM+U`2u%yhJ90giFcU1`dR6BBTKc2cQ*d zm-{?M&%(={xYHy?VCx!ogr|4g5;V{2q(L?QzJGsirn~kWHU`l`rHiIrc-Nan!hR7zaLsPr4uR zG{En&gaRK&B@lyWV@yfFpD_^&z>84~_0Rd!v(Nr%PJhFF_ci3D#ixf|(r@$igZiWw za*qbXIJ_Hm4)TaQ=zW^g)FC6uvyO~Hg-#Z5Vsrybz6uOTF>Rq1($JS`imyNB7myWWpxYL(t7`H8*voI3Qz6mvm z$JxtArLJ(1wlCO_te?L{>8YPzQ})xJlvc5wv8p7Z=HviPYB#^#_vGO#*`<0r%MR#u zN_mV4vaBb2RwtoOYCw)X^>r{2a0kK|WyEYoBjGxcObFl&P*??)WEWKU*V~zG5o=s@ z;rc~uuQQf9wf)MYWsWgPR!wKGt6q;^8!cD_vxrG8GMoFGOVV=(J3w6Xk;}i)9(7*U zwR4VkP_5Zx7wqn8%M8uDj4f1aP+vh1Wue&ry@h|wuN(D2W;v6b1^ z`)7XBZ385zg;}&Pt@?dunQ=RduGRJn^9HLU&HaeUE_cA1{+oSIjmj3z+1YiOGiu-H zf8u-oVnG%KfhB8H?cg%@#V5n+L$MO2F4>XoBjBeX>css^h}Omu#)ExTfUE^07KOQS znMfQY2wz?!7!{*C^)aZ^UhMZf=TJNDv8VrrW;JJ9`=|L0`w9DE8MS>+o{f#{7}B4P z{I34>342vLsP}o=ny1eZkEabr@niT5J2AhByUz&i3Ck0H*H`LRHz;>3C_ru!X+EhJ z6(+(lI#4c`2{`q0o9aZhI|jRjBZOV~IA_km7ItNtUa(Wsr*Hmb;b4=;R(gF@GmsRI`pF+0tmq0zy~wnoJD(LSEwHjTOt4xb0XB-+ z&4RO{Snw4G%gS9w#uSUK$Zbb#=jxEl;}6&!b-rSY$0M4pftat-$Q)*y!bpx)R%P>8 zrB&`YEX2%+s#lFCIV;cUFUTIR$Gn2%F(3yLeiG8eG8&)+cpBlzx4)sK?>uIlH+$?2 z9q9wk5zY-xr_fzFSGxYp^KSY0s%1BhsI>ai2VAc8&JiwQ>3RRk?ITx!t~r45qsMnj zkX4bl06ojFCMq<9l*4NHMAtIxDJOX)H=K*$NkkNG<^nl46 zHWH1GXb?Og1f0S+8-((5yaeegCT62&4N*pNQY;%asz9r9Lfr;@Bl${1@a4QAvMLbV6JDp>8SO^q1)#(o%k!QiRSd0eTmzC< zNIFWY5?)+JTl1Roi=nS4%@5iF+%XztpR^BSuM~DX9q`;Mv=+$M+GgE$_>o+~$#?*y zAcD4nd~L~EsAjXV-+li6Lua4;(EFdi|M2qV53`^4|7gR8AJI;0Xb6QGLaYl1zr&eu zH_vFUt+Ouf4SXA~ z&Hh8K@ms^`(hJfdicecj>J^Aqd00^ccqN!-f-!=N7C1?`4J+`_f^nV!B3Q^|fuU)7 z1NDNT04hd4QqE+qBP+>ZE7{v;n3OGN`->|lHjNL5w40pePJ?^Y6bFk@^k%^5CXZ<+4qbOplxpe)l7c6m%o-l1oWmCx%c6@rx85hi(F=v(2 zJ$jN>?yPgU#DnbDXPkHLeQwED5)W5sH#-eS z%#^4dxiVs{+q(Yd^ShMN3GH)!h!@W&N`$L!SbElXCuvnqh{U7lcCvHI#{ZjwnKvu~ zAeo7Pqot+Ohm{8|RJsTr3J4GjCy5UTo_u_~p)MS&Z5UrUc|+;Mc(YS+ju|m3Y_Dvt zonVtpBWlM718YwaN3a3wUNqX;7TqvAFnVUoD5v5WTh~}r)KoLUDw%8Rrqso~bJqd> z_T!&Rmr6ebpV^4|knJZ%qmzL;OvG3~A*loGY7?YS%hS{2R0%NQ@fRoEK52Aiu%gj( z_7~a}eQUh8PnyI^J!>pxB(x7FeINHHC4zLDT`&C*XUpp@s0_B^!k5Uu)^j_uuu^T> z8WW!QK0SgwFHTA%M!L`bl3hHjPp)|wL5Var_*A1-H8LV?uY5&ou{hRjj>#X@rxV>5%-9hbP+v?$4}3EfoRH;l_wSiz{&1<+`Y5%o%q~4rdpRF0jOsCoLnWY5x?V)0ga>CDo`NpqS) z@x`mh1QGkx;f)p-n^*g5M^zRTHz%b2IkLBY{F+HsjrFC9_H(=9Z5W&Eymh~A_FUJ} znhTc9KG((OnjFO=+q>JQZJbeOoUM77M{)$)qQMcxK9f;=L;IOv_J>*~w^YOW744QZ zoG;!b9VD3ww}OX<8sZ0F##8hvfDP{hpa3HjaLsKbLJ8 z0WpY2E!w?&cWi7&N%bOMZD~o7QT*$xCRJ@{t31~qx~+0yYrLXubXh2{_L699Nl_pn z6)9eu+uUTUdjHXYs#pX^L)AIb!FjjNsTp7C399w&B{Q4q%yKfmy}T2uQdU|1EpNcY zDk~(h#AdxybjfzB+mg6rdU9mDZ^V>|U13Dl$Gj+pAL}lR2a1u!SJXU_YqP9N{ose4 zk+$v}BIHX60WSGVWv;S%zvHOWdDP(-ceo(<8`y@Goy%4wDu>57QZNJc)f>Ls+}9h7 z^N=#3q3|l?aG8K#HwiW2^PJu{v|x5;awYfahC?>_af3$LmMc4%N~JwVlRZa4c+eW2 zE!zosAjOv&UeCeu;Bn5OQUC=jtZjF;NDk9$fGbxf3d29SUBekX1!a$Vmq_VK*MHQ4)eB!dQrHH)LVYNF%-t8!d`@!cb z2CsKs3|!}T^7fSZm?0dJ^JE`ZGxA&a!jC<>6_y67On0M)hd$m*RAzo_qM?aeqkm`* zXpDYcc_>TFZYaC3JV>{>mp(5H^efu!Waa7hGTAts29jjuVd1vI*fEeB?A&uG<8dLZ z(j6;-%vJ7R0U9}XkH)1g>&uptXPHBEA*7PSO2TZ+dbhVxspNW~ZQT3fApz}2 z_@0-lZODcd>dLrYp!mHn4k>>7kibI!Em+Vh*;z}l?0qro=aJt68joCr5Jo(Vk<@i) z5BCKb4p6Gdr9=JSf(2Mgr=_6}%4?SwhV+JZj3Ox^_^OrQk$B^v?eNz}d^xRaz&~ zKVnlLnK#8^y=If2f1zmb~^5lPLe?%l}>?~wN4IN((2~U{e9fKhLMtYFj)I$(y zgnKv?R+ZpxA$f)Q2l=aqE6EPTK=i0sY&MDFJp!vQayyvzh4wee<}kybNthRlX>SHh z7S}9he^EBOqzBCww^duHu!u+dnf9veG{HjW!}aT7aJqzze9K6-Z~8pZAgdm1n~aDs z8_s7?WXMPJ3EPJHi}NL&d;lZP8hDhAXf5Hd!x|^kEHu`6QukXrVdLnq5zbI~oPo?7 z2Cbu8U?$K!Z4_yNM1a(bL!GRe!@{Qom+DxjrJ!B99qu5b*Ma%^&-=6UEbC+S2zX&= zQ!%bgJTvmv^2}hhvNQg!l=kbapAgM^hruE3k@jTxsG(B6d=4thBC*4tzVpCYXFc$a zeqgVB^zua)y-YjpiibCCdU%txXYeNFnXcbNj*D?~)5AGjL+!!ij_4{5EWKGav0^={~M^q}baAFOPzxfUM>`KPf|G z&hsaR*7(M6KzTj8Z?;45zX@L#xU{4n$9Q_<-ac(y4g~S|Hyp^-<*d8+P4NHe?~vfm z@y309=`lGdvN8*jw-CL<;o#DKc-%lb0i9a3%{v&2X($|Qxv(_*()&=xD=5oBg=$B0 zU?41h9)JKvP0yR{KsHoC>&`(Uz>?_`tlLjw1&5tPH3FoB%}j;yffm$$s$C=RHi`I3*m@%CPqWnP@B~%DEe;7ZT{9!IMTo1hT3Q347HJ&!)BM2 z3~aClf>aFh0_9||4G}(Npu`9xYY1*SD|M~9!CCFn{-J$u2&Dg*=5$_nozpoD2nxqq zB!--eA8UWZlcEDp4r#vhZ6|vq^9sFvRnA9HpHch5Mq4*T)oGbruj!U8Lx_G%Lby}o zTQ-_4A7b)5A42vA0U}hUJq6&wQ0J%$`w#ph!EGmW96)@{AUx>q6E>-r^Emk!iCR+X zdIaNH`$}7%57D1FyTccs3}Aq0<0Ei{`=S7*>pyg=Kv3nrqblqZcpsCWSQl^uMSsdj zYzh73?6th$c~CI0>%5@!Ej`o)Xm38u0fp9=HE@Sa6l2oX9^^4|Aq%GA z3(AbFR9gA_2T2i%Ck5V2Q2WW-(a&(j#@l6wE4Z`xg#S za#-UWUpU2U!TmIo`CN0JwG^>{+V#9;zvx;ztc$}@NlcyJr?q(Y`UdW6qhq!aWyB5xV1#Jb{I-ghFNO0 zFU~+QgPs{FY1AbiU&S$QSix>*rqYVma<-~s%ALhFyVhAYepId1 zs!gOB&weC18yhE-v6ltKZMV|>JwTX+X)Y_EI(Ff^3$WTD|Ea-1HlP;6L~&40Q&5{0 z$e$2KhUgH8ucMJxJV#M%cs!d~#hR^nRwk|uuCSf6irJCkSyI<%CR==tftx6d%;?ef zYIcjZrP@APzbtOeUe>m-TW}c-ugh+U*RbL1eIY{?>@8aW9bb1NGRy@MTse@>= za%;5=U}X%K2tKTYe9gjMcBvX%qrC&uZ`d(t)g)X8snf?vBe3H%dG=bl^rv8Z@YN$gd9yveHY0@Wt0$s zh^7jCp(q+6XDoekb;=%y=Wr8%6;z0ANH5dDR_VudDG|&_lYykJaiR+(y{zpR=qL3|2e${8 z2V;?jgHj7}Kl(d8C9xWRjhpf_)KOXl+@c4wrHy zL3#9U(`=N59og2KqVh>nK~g9>fX*PI0`>i;;b6KF|8zg+k2hViCt}4dfMdvb1NJ-Rfa7vL2;lPK{Lq*u`JT>S zoM_bZ_?UY6oV6Ja14X^;LqJPl+w?vf*C!nGK;uU^0GRN|UeFF@;H(Hgp8x^|;ygh? zIZx3DuO(lD01ksanR@Mn#lti=p28RTNYY6yK={RMFiVd~k8!@a&^jicZ&rxD3CCI! zVb=fI?;c#f{K4Pp2lnb8iF2mig)|6JEmU86Y%l}m>(VnI*Bj`a6qk8QL&~PFDxI8b z2mcsQBe9$q`Q$LfG2wdvK`M1}7?SwLAV&)nO;kAk`SAz%x9CDVHVbUd$O(*aI@D|s zLxJW7W(QeGpQY<$dSD6U$ja(;Hb3{Zx@)*fIQaW{8<$KJ&fS0caI2Py^clOq9@Irt z7th7F?7W`j{&UmM==Lo~T&^R7A?G=K_e-zfTX|)i`pLitlNE(~tq*}sS1x2}Jlul6 z5+r#4SpQu8h{ntIv#qCVH`uG~+I8l+7ZG&d`Dm!+(rZQDV*1LS^WfH%-!5aTAxry~ z4xl&rot5ct{xQ$w$MtVTUi6tBFSJWq2Rj@?HAX1H$eL*fk{Hq;E`x|hghRkipYNyt zKCO=*KSziiVk|+)qQCGrTYH9X!Z0$k{Nde~0Wl`P{}ca%nv<6fnYw^~9dYxTnTZB&&962jX0DM&wy&8fdxX8xeHSe=UU&Mq zRTaUKnQO|A>E#|PUo+F=Q@dMdt`P*6e92za(TH{5C*2I2S~p?~O@hYiT>1(n^Lqqn zqewq3ctAA%0E)r53*P-a8Ak32mGtUG`L^WVcm`QovX`ecB4E9X60wrA(6NZ7z~*_DV_e z8$I*eZ8m=WtChE{#QzeyHpZ%7GwFHlwo2*tAuloI-j2exx3#x7EL^&D;Re|Kj-XT- zt908^soV2`7s+Hha!d^#J+B)0-`{qIF_x=B811SZlbUe%kvPce^xu7?LY|C z@f1gRPha1jq|=f}Se)}v-7MWH9)YAs*FJ&v3ZT9TSi?e#jarin0tjPNmxZNU_JFJG z+tZi!q)JP|4pQ)?l8$hRaPeoKf!3>MM-bp06RodLa*wD=g3)@pYJ^*YrwSIO!SaZo zDTb!G9d!hb%Y0QdYxqNSCT5o0I!GDD$Z@N!8J3eI@@0AiJmD7brkvF!pJGg_AiJ1I zO^^cKe`w$DsO|1#^_|`6XTfw6E3SJ(agG*G9qj?JiqFSL|6tSD6vUwK?Cwr~gg)Do zp@$D~7~66-=p4`!!UzJDKAymb!!R(}%O?Uel|rMH>OpRGINALtg%gpg`=}M^Q#V5( zMgJY&gF)+;`e38QHI*c%B}m94o&tOfae;og&!J2;6ENW}QeL73jatbI1*9X~y=$Dm%6FwDcnCyMRL}zo`0=y7=}*Uw zo3!qZncAL{HCgY!+}eKr{P8o27ye+;qJP;kOB%RpSesGoHLT6tcYp*6v~Z9NCyb6m zP#qds0jyqXX46qMNhXDn3pyIxw2f_z;L_X9EIB}AhyC`FYI}G3$WnW>#NMy{0aw}nB%1=Z4&*(FaCn5QG(zvdG^pQRU25;{wwG4h z@kuLO0F->{@g2!;NNd!PfqM-;@F0;&wK}0fT9UrH}(8A5I zt33(+&U;CLN|8+71@g z(s!f-kZZZILUG$QXm9iYiE*>2w;gpM>lgM{R9vT3q>qI{ELO2hJHVi`)*jzOk$r)9 zq}$VrE0$GUCm6A3H5J-=Z9i*biw8ng zi<1nM0lo^KqRY@Asucc#DMmWsnCS;5uPR)GL3pL=-IqSd>4&D&NKSGHH?pG;=Xo`w zw~VV9ddkwbp~m>9G0*b?j7-0fOwR?*U#BE#n7A=_fDS>`fwatxQ+`FzhBGQUAyIRZ??eJt46vHBlR>9m!vfb6I)8!v6TmtZ%G6&E|1e zOtx5xy%yOSu+<9Ul5w5N=&~4Oph?I=ZKLX5DXO(*&Po>5KjbY7s@tp$8(fO|`Xy}Y z;NmMypLoG7r#Xz4aHz7n)MYZ7Z1v;DFHLNV{)to;(;TJ=bbMgud96xRMME#0d$z-S z-r1ROBbW^&YdQWA>U|Y>{whex#~K!ZgEEk=LYG8Wqo28NFv)!t!~}quaAt}I^y-m| z8~E{9H2VnyVxb_wCZ7v%y(B@VrM6lzk~|ywCi3HeiSV`TF>j+Ijd|p*kyn;=mqtf8&DK^|*f+y$38+9!sis9N=S)nINm9=CJ<;Y z!t&C>MIeyou4XLM*ywT_JuOXR>VkpFwuT9j5>667A=CU*{TBrMTgb4HuW&!%Yt`;#md7-`R`ouOi$rEd!ErI zo#>qggAcx?C7`rQ2;)~PYCw%CkS(@EJHZ|!!lhi@Dp$*n^mgrrImsS~(ioGak>3)w zvop0lq@IISuA0Ou*#1JkG{U>xSQV1e}c)!d$L1plFX5XDXX5N7Ns{kT{y5|6MfhBD+esT)e7&CgSW8FxsXTAY=}?0A!j_V9 zJ;IJ~d%av<@=fNPJ9)T3qE78kaz64E>dJaYab5uaU`n~Zdp2h{8DV%SKE5G^$LfuOTRRjB;TnT(Jk$r{Pfe4CO!SM_7d)I zquW~FVCpSycJ~c*B*V8?Qqo=GwU8CkmmLFugfHQ7;A{yCy1OL-+X=twLYg9|H=~8H znnN@|tCs^ZLlCBl5wHvYF}2vo>a6%mUWpTds_mt*@wMN4-r`%NTA%+$(`m6{MNpi@ zMx)8f>U4hd!row@gM&PVo&Hx+lV@$j9yWTjTue zG9n0DP<*HUmJ7ZZWwI2x+{t3QEfr6?T}2iXl=6e0b~)J>X3`!fXd9+2wc1%cj&F@Z zgYR|r5Xd5jy9;YW&=4{-0rJ*L5CgDPj9^3%bp-`HkyBs`j1iTUGD4?WilZ6RO8mIE z+~Joc?GID6K96dyuv(dWREK9Os~%?$$FxswxQsoOi8M?RnL%B~Lyk&(-09D0M?^Jy zWjP)n(b)TF<-|CG%!Vz?8Fu&6iU<>oG#kGcrcrrBlfZMVl0wOJvsq%RL9To%iCW@)#& zZAJWhgzYAq)#NTNb~3GBcD%ZZOc43!YWSyA7TD6xkk)n^FaRAz73b}%9d&YisBic(?mv=Iq^r%Ug zzHq-rRrhfOOF+yR=AN!a9*Rd#sM9ONt5h~w)yMP7Dl9lfpi$H0%GPW^lS4~~?vI8Z z%^ToK#NOe0ExmUsb`lLO$W*}yXNOxPe@zD*90uTDULnH6C?InP3J=jYEO2d)&e|mP z1DSd0QOZeuLWo*NqZzopA+LXy9)fJC00NSX=_4Mi1Z)YyZVC>C!g}cY(Amaj%QN+bev|Xxd2OPD zk!dfkY6k!(sDBvsFC2r^?}hb81(WG5Lt9|riT`2?P;B%jaf5UX<~OJ;uAL$=Ien+V zC!V8u0v?CUa)4*Q+Q_u zkx{q;NjLcvyMuU*{+uDsCQ4U{JLowYby-tn@hatL zy}X>9y08#}oytdn^qfFesF)Tt(2!XGw#r%?7&zzFFh2U;#U9XBO8W--#gOpfbJ`Ey z|M8FCKlWQrOJwE;@Sm02l9OBr7N}go4V8ur)}M@m2uWjggb)DC4s`I4d7_8O&E(j; z?3$9~R$QDxNM^rNh9Y;6P7w+bo2q}NEd6f&_raor-v`UCaTM3TT8HK2-$|n{N@U>_ zL-`P7EXoEU5JRMa)?tNUEe8XFis+w8g9k(QQ)%?&Oac}S`2V$b?%`DwXBgja&&fR@ zH_XidF$p1wA)J|Wk1;?lCl?fgc)=TB3>Y8;BoMqHwJqhL)Tgydv9(?(TBX)fq%=~C zmLj!iX-kn7QA(9snzk0LRf<%SzO&~IhLor6A3f*U^UcoAygRe!H#@UCv$JUP&vPxs zeDj$1%#<2T1!e|!7xI+~_VXLl5|jHqvOhU7ZDUGee;HnkcPP=_k_FFxPjXg*9KyI+ zIh0@+s)1JDSuKMeaDZ3|<_*J8{TUFDLl|mXmY8B>Wj_?4mC#=XjsCKPEO=p0c&t&Z zd1%kHxR#o9S*C?du*}tEHfAC7WetnvS}`<%j=o7YVna)6pw(xzkUi7f#$|^y4WQ{7 zu@@lu=j6xr*11VEIY+`B{tgd(c3zO8%nGk0U^%ec6h)G_`ki|XQXr!?NsQkxzV6Bn1ea9L+@ z(Zr7CU_oXaW>VOdfzENm+FlFQ7Se0ROrNdw(QLvb6{f}HRQ{$Je>(c&rws#{dFI^r zZ4^(`J*G0~Pu_+p5AAh>RRpkcbaS2a?Fe&JqxDTp`dIW9;DL%0wxX5;`KxyA4F{(~_`93>NF@bj4LF!NC&D6Zm+Di$Q-tb2*Q z&csGmXyqA%Z9s(AxNO3@Ij=WGt=UG6J7F;r*uqdQa z?7j!nV{8eQE-cwY7L(3AEXF3&V*9{DpSYdyCjRhv#&2johwf{r+k`QB81%!aRVN<& z@b*N^xiw_lU>H~@4MWzgHxSOGVfnD|iC7=hf0%CPm_@@4^t-nj#GHMug&S|FJtr?i z^JVrobltd(-?Ll>)6>jwgX=dUy+^n_ifzM>3)an3iOzpG9Tu;+96TP<0Jm_PIqof3 zMn=~M!#Ky{CTN_2f7Y-i#|gW~32RCWKA4-J9sS&>kYpTOx#xVNLCo)A$LUme^fVNH z@^S7VU^UJ0YR8?Oy$^IYuG*bm|g;@aX~i60%`7XLy*AYpYvZ^F^U(!|RW z*C!rJ@+7TGdL=nNd1gv^%B+;Fcr$y)i0!GRsZXRHPs>QVGVR{9r_#&Qd(wL|5;H;> zD>HUw=4CF++&{7$<8G@j*nGjhEO%BQYfjeItp4mPvY*JYb1HKd!{HJ9*)(3%BR%{Pp?AM&*yHAJsW({ivOzj*qS!-7|XEn6@zo z3L*tBT%<4RxoAh>q{0n_JBmgW6&8hx?kL(_^k%VL>?xjAyrKBmSl`$=V|SK}ELl}@ zd|d0eo#RfG`bw9SK3%r4Y+rdvc}w}~ixV%tqawbdqvE-WcgE+BUpxMT%F@btm76MG zn=oQRWWuTm+a{dy)Oc2V4yX(@M{QAkx>(QB59*`dLT`Pz3Lsj9iB=HSHAiCq()ns|Cr)1*c605Cx}3V&x}Lg?b+6Q?)z7Kl zQh&1Hx`y6JY-Cwvd*ozeps}a1xAA0CR+Da;+O(i)P1C;SjOI}Dtmf6tPqo-Bl`U78 zv$kYgPntPp@G)n1an9tEoL*Vumu9`>_@I(;+5+fBa-*?fEx=mTEjZ7wq}#@Gd5_cW z!mP{N=yqEntDo)|>oy6{9cu+-3*GTnmb^`O0^FzRPO^&aG`f@F_R*aQ_e{F+_9%NW z4KG_B`@X3EVV9L>?_RNDMddA>w=e0KfAiw5?#i1NFT%Zz#nuv(&!yIU>lVxmzYKQ` zzJ*0w9<&L4aJ6A;0j|_~i>+y(q-=;2Xxhx2v%CYY^{} z^J@LO()eLo|7!{ghQ+(u$wxO*xY#)cL(|miH2_ck2yN{mu4O9=hBW*pM_()-_YdH#Ru{JtwJ^R2}3?!>>m1pohh zrn(!xCjE0Q&EH1QK?zA%sxVh&H99cObJUY$veZhQ)MLu-h%`!*G)s$2k;~+A z)Kk->Ri?`oGDEJEtI*wijm(s5f$W78FH{+qBxiU{~kq((J3uK{m z$|C8K#j-?hm8H@x%VfFqpnvu@xn1s%J7uNZC9C99a<_b1J|mx%)$%!6gPU|~<@2&m zz99GDp`|a%m*iggvfL;4%X;~WY>)@!tMWB@P`)k?$;0x9JSrRI8?s3rlgH(o@`OAo zn{f*gZ#t2u6K??hx|aElOM`Xd0t+SAIUEHvFw%?Wsm$s zUXq{6UU?a>Nc@@Xlb_2k9M1Ctr<#+O?yd}rv z_wu&=_t$!Yngd@N_AUj}T; z#*Ce|%XZr_sQcsWcsl{pCnnj+c8ZNIMmx<;w=-g$Q>BU;9k;w|zQ;4!W32Xg2Cd?{ zvmO3kuKQ^Hv;o>6ZHP8ZJ2`4~Bx?N;cf<0fi=!*G^^WzbTF3e$b&d^qqB{>nqLG81 zs94bBh%|Vj+hLu=!8(b9brJ>ZBns9^6s(gdSVyP9qnu2_I{Sg8j-rloG6{d`De5We zDe5WeY3ga}Y3ga}Y3ga}Y3ga}Y3ga}d8y~6o|k%F>UpW>rJk31Ug~+N=cS&HdOqs; zsOO`ek9t1p`Kafko{xGy>iMbXr=FjBxZMYc8a#gL`Kjlpo}YSt>iMY`pk9DF0qO*( z6QE9jIsxhgs1u-0kUBx8D@eT{^@7w3QZGooAoYUO3sNscy%6<6)C*BBM7L`dk$Xk%6}eZQXgo#!75P`>Uy*-B{uTLGUy*-B{uTLGUy*-B{uTLG))v8{5gt_uj9!t5)^yb-JtjRGrhi zYInOUNJxNyf_yKX01)K=WP|Si>HqEj|B{eUl?MR<)%<1&{(~)D+NPwKxWqT-@~snp zg9KCz1VTZDiS?UH`PRk1VPM{29cgT9=D?!Wc_@}qzggFv;gb@2cJQAYWWtpEZ7?y@jSVqjx${B5UV@SO|wH<<0; z{><1KdVI%Ki}>~<`46C0AggwUwx-|QcU;iiZ{NZu`ur>hd*|Hb(|6veERqxu=b@5Bab=rqptGxd{QJg!4*-i_$sES~)AB46}Fjg|ea#e@?J}z%CUJ zOsLWRQR1#ng^sD)A4FDuY!iUhzlgfJh(J@BRqd&P#v2B`+saBx>m+M&q7vk-75$NH%T5pi%m z5FX?`2-5l53=a&GkC9^NZCLpN5(DMKMwwab$FDIs?q>4!!xBS}75gX_5;(luk;3Vl zLCLd5a_8`Iyz}K}+#RMwu6DVk3O_-}n>aE!4NaD*sQn`GxY?cHe!Bl9n?u&g6?aKm z-P8z&;Q3gr;h`YIxX%z^o&GZZg1=>_+hP2$$-DnL_?7?3^!WAsY4I7|@K;aL<>OTK zByfjl2PA$T83*LM9(;espx-qB%wv7H2i6CFsfAg<9V>Pj*OpwX)l?^mQfr$*OPPS$ z=`mzTYs{*(UW^ij1U8UfXjNoY7GK*+YHht(2oKE&tfZuvAyoN(;_OF>-J6AMmS5fB z^sY6wea&&${+!}@R1f$5oC-2J>J-A${@r(dRzc`wnK>a7~8{Y-scc|ETOI8 zjtNY%Y2!PI;8-@a=O}+{ap1Ewk0@T`C`q!|=KceX9gK8wtOtIC96}-^7)v23Mu;MH zhKyLGOQMujfRG$p(s`(2*nP4EH7*J57^=|%t(#PwCcW7U%e=8Jb>p6~>RAlY4a*ts=pl}_J{->@kKzxH|8XQ5{t=E zV&o`$D#ZHdv&iZWFa)(~oBh-Osl{~CS0hfM7?PyWUWsr5oYlsyC1cwULoQ4|Y5RHA2*rN+EnFPnu z`Y_&Yz*#550YJwDy@brZU>0pWV^RxRjL221@2ABq)AtA%Cz?+FG(}Yh?^v)1Lnh%D zeM{{3&-4#F9rZhS@DT0E(WRkrG!jC#5?OFjZv*xQjUP~XsaxL2rqRKvPW$zHqHr8Urp2Z)L z+)EvQeoeJ8c6A#Iy9>3lxiH3=@86uiTbnnJJJoypZ7gco_*HvKOH97B? zWiwp>+r}*Zf9b3ImxwvjL~h~j<<3shN8$k-$V1p|96I!=N6VBqmb==Bec|*;HUg?) z4!5#R*(#Fe)w%+RH#y{8&%%!|fQ5JcFzUE;-yVYR^&Ek55AXb{^w|@j|&G z|6C-+*On%j;W|f8mj?;679?!qY86c{(s1-PI2Wahoclf%1*8%JAvRh1(0)5Vu37Iz z`JY?RW@qKr+FMmBC{TC7k@}fv-k8t6iO}4K-i3WkF!Lc=D`nuD)v#Na zA|R*no51fkUN3^rmI;tty#IK284*2Zu!kG13!$OlxJAt@zLU`kvsazO25TpJLbK&;M8kw*0)*14kpf*)3;GiDh;C(F}$- z1;!=OBkW#ctacN=je*Pr)lnGzX=OwgNZjTpVbFxqb;8kTc@X&L2XR0A7oc!Mf2?u9 zcctQLCCr+tYipa_k=;1ETIpHt!Jeo;iy^xqBES^Ct6-+wHi%2g&)?7N^Yy zUrMIu){Jk)luDa@7We5U!$$3XFNbyRT!YPIbMKj5$IEpTX1IOtVP~(UPO2-+9ZFi6 z-$3<|{Xb#@tABt0M0s1TVCWKwveDy^S!!@4$s|DAqhsEv--Z}Dl)t%0G>U#ycJ7cy z^8%;|pg32=7~MJmqlC-x07Sd!2YX^|2D`?y;-$a!rZ3R5ia{v1QI_^>gi(HSS_e%2 zUbdg^zjMBBiLr8eSI^BqXM6HKKg#@-w`a**w(}RMe%XWl3MipvBODo*hi?+ykYq)z ziqy4goZw0@VIUY65+L7DaM5q=KWFd$;W3S!Zi>sOzpEF#(*3V-27N;^pDRoMh~(ZD zJLZXIam0lM7U#)119Hm947W)p3$%V`0Tv+*n=&ybF&}h~FA}7hEpA&1Y!BiYIb~~D z$TSo9#3ee02e^%*@4|*+=Nq6&JG5>zX4k5f?)z*#pI-G(+j|jye%13CUdcSP;rNlY z#Q!X%zHf|V)GWIcEz-=fW6AahfxI~y7w7i|PK6H@@twdgH>D_R@>&OtKl}%MuAQ7I zcpFmV^~w~8$4@zzh~P~+?B~%L@EM3x(^KXJSgc6I=;)B6 zpRco2LKIlURPE*XUmZ^|1vb?w*ZfF}EXvY13I4af+()bAI5V?BRbFp`Sb{8GRJHd* z4S2s%4A)6Uc=PK%4@PbJ<{1R6+2THMk0c+kif**#ZGE)w6WsqH z`r^DL&r8|OEAumm^qyrryd(HQ9olv$ltnVGB{aY?_76Uk%6p;e)2DTvF(;t=Q+|8b zqfT(u5@BP);6;jmRAEV057E*2d^wx@*aL1GqWU|$6h5%O@cQtVtC^isd%gD7PZ_Io z_BDP5w(2*)Mu&JxS@X%%ByH_@+l>y07jIc~!@;Raw)q_;9oy@*U#mCnc7%t85qa4? z%_Vr5tkN^}(^>`EFhag;!MpRh!&bKnveQZAJ4)gEJo1@wHtT$Gs6IpznN$Lk-$NcM z3ReVC&qcXvfGX$I0nfkS$a|Pm%x+lq{WweNc;K>a1M@EAVWs2IBcQPiEJNt}+Ea8~WiapASoMvo(&PdUO}AfC~>ZGzqWjd)4no( ziLi#e3lOU~sI*XPH&n&J0cWfoh*}eWEEZW%vX?YK!$?w}htY|GALx3;YZoo=JCF4@ zdiaA-uq!*L5;Yg)z-_`MciiIwDAAR3-snC4V+KA>&V%Ak;p{1u>{Lw$NFj)Yn0Ms2*kxUZ)OTddbiJM}PK!DM}Ot zczn?EZXhx3wyu6i{QMz_Ht%b?K&-@5r;8b076YDir`KXF0&2i9NQ~#JYaq*}Ylb}^ z<{{6xy&;dQ;|@k_(31PDr!}}W$zF7Jv@f%um0M$#=8ygpu%j(VU-d5JtQwT714#f0z+Cm$F9JjGr_G!~NS@L9P;C1? z;Ij2YVYuv}tzU+HugU=f9b1Wbx3418+xj$RKD;$gf$0j_A&c;-OhoF*z@DhEW@d9o zbQBjqEQnn2aG?N9{bmD^A#Um6SDKsm0g{g_<4^dJjg_l_HXdDMk!p`oFv8+@_v_9> zq;#WkQ!GNGfLT7f8m60H@$tu?p;o_It#TApmE`xnZr|_|cb3XXE)N^buLE`9R=Qbg zXJu}6r07me2HU<)S7m?@GzrQDTE3UH?FXM7V+-lT#l}P(U>Fvnyw8T7RTeP`R579m zj=Y>qDw1h-;|mX-)cSXCc$?hr;43LQt)7z$1QG^pyclQ1Bd!jbzsVEgIg~u9b38;> zfsRa%U`l%did6HzPRd;TK{_EW;n^Ivp-%pu0%9G-z@Au{Ry+EqEcqW=z-#6;-!{WA z;l+xC6Zke>dl+(R1q7B^Hu~HmrG~Kt575mzve>x*cL-shl+zqp6yuGX)DDGm`cid! znlnZY=+a5*xQ=$qM}5$N+o!^(TqTFHDdyCcL8NM4VY@2gnNXF|D?5a558Lb*Yfm4) z_;0%2EF7k{)i(tTvS`l5he^KvW%l&-suPwpIlWB_Za1Hfa$@J!emrcyPpTKKM@NqL z?X_SqHt#DucWm<3Lp}W|&YyQE27zbGP55=HtZmB(k*WZA79f##?TweCt{%5yuc+Kx zgfSrIZI*Y57FOD9l@H0nzqOu|Bhrm&^m_RK6^Z<^N($=DDxyyPLA z+J)E(gs9AfaO`5qk$IGGY+_*tEk0n_wrM}n4G#So>8Dw6#K7tx@g;U`8hN_R;^Uw9JLRUgOQ?PTMr4YD5H7=ryv)bPtl=<&4&% z*w6k|D-%Tg*F~sh0Ns(h&mOQ_Qf{`#_XU44(VDY8b})RFpLykg10uxUztD>gswTH} z&&xgt>zc(+=GdM2gIQ%3V4AGxPFW0*l0YsbA|nFZpN~ih4u-P!{39d@_MN)DC%d1w z7>SaUs-g@Hp7xqZ3Tn)e z7x^sC`xJ{V<3YrmbB{h9i5rdancCEyL=9ZOJXoVHo@$$-%ZaNm-75Z-Ry9Z%!^+STWyv~To>{^T&MW0-;$3yc9L2mhq z;ZbQ5LGNM+aN628)Cs16>p55^T^*8$Dw&ss_~4G5Go63gW^CY+0+Z07f2WB4Dh0^q z-|6QgV8__5>~&z1gq0FxDWr`OzmR}3aJmCA^d_eufde7;d|OCrKdnaM>4(M%4V`PxpCJc~UhEuddx9)@)9qe_|i z)0EA%&P@_&9&o#9eqZCUCbh?`j!zgih5sJ%c4(7_#|Xt#r7MVL&Q+^PQEg3MBW;4T zG^4-*8L%s|A}R%*eGdx&i}B1He(mLygTmIAc^G(9Si zK7e{Ngoq>r-r-zhyygK)*9cj8_%g z)`>ANlipCdzw(raeqP-+ldhyUv_VOht+!w*>Sh+Z7(7(l=9~_Vk ztsM|g1xW`?)?|@m2jyAgC_IB`Mtz(O`mwgP15`lPb2V+VihV#29>y=H6ujE#rdnK` zH`EaHzABs~teIrh`ScxMz}FC**_Ii?^EbL(n90b(F0r0PMQ70UkL}tv;*4~bKCiYm zqngRuGy`^c_*M6{*_~%7FmOMquOEZXAg1^kM`)0ZrFqgC>C%RJvQSo_OAA(WF3{euE}GaeA?tu5kF@#62mM$a051I zNhE>u>!gFE8g#Jj95BqHQS%|>DOj71MZ?EYfM+MiJcX?>*}vKfGaBfQFZ3f^Q-R1# znhyK1*RvO@nHb|^i4Ep_0s{lZwCNa;Ix<{E5cUReguJf+72QRZIc%`9-Vy)D zWKhb?FbluyDTgT^naN%l2|rm}oO6D0=3kfXO2L{tqj(kDqjbl(pYz9DykeZlk4iW5 zER`)vqJxx(NOa;so@buE!389-YLbEi@6rZG0#GBsC+Z0fzT6+d7deYVU;dy!rPXiE zmu73@Jr&~K{-9MVQD}&`)e>yLNWr>Yh8CXae9XqfvVQ&eC_;#zpoaMxZ0GpZz7xjx z`t_Q-F?u=vrRPaj3r<9&t6K=+egimiJ8D4gh-rUYvaVy zG($v+3zk5sMuOhjxkH7bQ}(5{PD3Mg?!@8PkK&w>n7tO8FmAmoF30_#^B~c(Q_`4L zYWOoDVSnK|1=p{+@`Fk^Qb81Xf89_S`RSTzv(a4ID%71nll%{Wad$!CKfeTKkyC?n zCkMKHU#*nz_(tO$M)UP&ZfJ#*q(0Gr!E(l5(ce<3xut+_i8XrK8?Xr7_oeHz(bZ?~8q5q~$Rah{5@@7SMN zx9PnJ-5?^xeW2m?yC_7A#WK*B@oIy*Y@iC1n7lYKj&m7vV;KP4TVll=II)$39dOJ^czLRU>L> z68P*PFMN+WXxdAu=Hyt3g$l(GTeTVOZYw3KY|W0Fk-$S_`@9`K=60)bEy?Z%tT+Iq z7f>%M9P)FGg3EY$ood+v$pdsXvG? zd2q3abeu-}LfAQWY@=*+#`CX8RChoA`=1!hS1x5dOF)rGjX4KFg!iPHZE2E=rv|A} zro(8h38LLFljl^>?nJkc+wdY&MOOlVa@6>vBki#gKhNVv+%Add{g6#-@Z$k*ps}0Y zQ=8$)+Nm||)mVz^aa4b-Vpg=1daRaOU)8@BY4jS>=5n#6abG@(F2`=k-eQ9@u# zxfNFHv=z2w@{p1dzSOgHokX1AUGT0DY4jQI@YMw)EWQ~q5wmR$KQ}Y;(HPMSQCwzu zdli|G?bj(>++CP)yQ4s6YfpDc3KqPmquQSxg%*EnTWumWugbDW5ef%8j-rT#3rJu? z)5n;4b2c*;2LIW%LmvUu6t1~di~}0&Svy}QX#ER|hDFZwl!~zUP&}B1oKAxIzt~so zb!GaJYOb#&qRUjEI1xe_`@7qv_-LggQ$JE8+{ryT4%ldwC5ete+{G3C#g@^oxfY3#F zcLlj(l2G8>tC<5XWV|6_DZQZ7ow?MD8EZ9mM2oV~WoV-uoExmbwpzc6eMV}%J_{3l zW(4t2a-o}XRlU|NSiYn!*nR(Sc>*@TuU*(S77gfCi7+WR%2b;4#RiyxWR3(u5BIdf zo@#g4wQjtG3T$PqdX$2z8Zi|QP~I^*9iC+(!;?qkyk&Q7v>DLJGjS44q|%yBz}}>i z&Ve%^6>xY<=Pi9WlwpWB%K10Iz`*#gS^YqMeV9$4qFchMFO}(%y}xs2Hn_E}s4=*3 z+lAeCKtS}9E{l(P=PBI;rsYVG-gw}-_x;KwUefIB@V%RLA&}WU2XCL_?hZHoR<7ED zY}4#P_MmX(_G_lqfp=+iX|!*)RdLCr-1w`4rB_@bI&Uz# z!>9C3&LdoB$r+O#n);WTPi;V52OhNeKfW6_NLnw zpFTuLC^@aPy~ZGUPZr;)=-p|b$-R8htO)JXy{ecE5a|b{{&0O%H2rN&9(VHxmvNly zbY?sVk}@^{aw)%#J}|UW=ucLWs%%j)^n7S%8D1Woi$UT}VuU6@Sd6zc2+t_2IMBxd zb4R#ykMr8s5gKy=v+opw6;4R&&46$V+OOpDZwp3iR0Osqpjx))joB*iX+diVl?E~Q zc|$qmb#T#7Kcal042LUNAoPTPUxF-iGFw>ZFnUqU@y$&s8%h-HGD`EoNBbe#S>Y-4 zlkeAP>62k~-N zHQqXXyN67hGD6CxQIq_zoepU&j0 zYO&}<4cS^2sp!;5))(aAD!KmUED#QGr48DVlwbyft31WlS2yU<1>#VMp?>D1BCFfB z_JJ-kxTB{OLI}5XcPHXUo}x~->VP%of!G_N-(3Snvq`*gX3u0GR&}*fFwHo3-vIw0 zeiWskq3ZT9hTg^je{sC^@+z3FAd}KNhbpE5RO+lsLgv$;1igG7pRwI|;BO7o($2>mS(E z$CO@qYf5i=Zh6-xB=U8@mR7Yjk%OUp;_MMBfe_v1A(Hqk6!D})x%JNl838^ZA13Xu zz}LyD@X2;5o1P61Rc$%jcUnJ>`;6r{h5yrEbnbM$$ntA@P2IS1PyW^RyG0$S2tUlh z8?E(McS?7}X3nAAJs2u_n{^05)*D7 zW{Y>o99!I9&KQdzgtG(k@BT|J*;{Pt*b|?A_})e98pXCbMWbhBZ$t&YbNQOwN^=F) z_yIb_az2Pyya2530n@Y@s>s>n?L79;U-O9oPY$==~f1gXro5Y z*3~JaenSl_I}1*&dpYD?i8s<7w%~sEojqq~iFnaYyLgM#so%_ZZ^WTV0`R*H@{m2+ zja4MX^|#>xS9YQo{@F1I)!%RhM{4ZUapHTKgLZLcn$ehRq(emb8 z9<&Nx*RLcS#)SdTxcURrJhxPM2IBP%I zf1bWu&uRf{60-?Gclb5(IFI*!%tU*7d`i!l@>TaHzYQqH4_Y*6!Wy0d-B#Lz7Rg3l zqKsvXUk9@6iKV6#!bDy5n&j9MYpcKm!vG7z*2&4G*Yl}iccl*@WqKZWQSJCgQSj+d ze&}E1mAs^hP}>`{BJ6lv*>0-ft<;P@`u&VFI~P3qRtufE11+|#Y6|RJccqo27Wzr}Tp|DH z`G4^v)_8}R24X3}=6X&@Uqu;hKEQV^-)VKnBzI*|Iskecw~l?+R|WKO*~(1LrpdJ? z0!JKnCe<|m*WR>m+Qm+NKNH<_yefIml z+x32qzkNRrhR^IhT#yCiYU{3oq196nC3ePkB)f%7X1G^Ibog$ZnYu4(HyHUiFB`6x zo$ty-8pknmO|B9|(5TzoHG|%>s#7)CM(i=M7Nl=@GyDi-*ng6ahK(&-_4h(lyUN-oOa$` zo+P;C4d@m^p9J4c~rbi$rq9nhGxayFjhg+Rqa{l#`Y z!(P6K7fK3T;y!VZhGiC#)|pl$QX?a)a9$(4l(usVSH>2&5pIu5ALn*CqBt)9$yAl; z-{fOmgu><7YJ5k>*0Q~>lq72!XFX6P5Z{vW&zLsraKq5H%Z26}$OKDMv=sim;K?vsoVs(JNbgTU8-M%+ zN(+7Xl}`BDl=KDkUHM9fLlV)gN&PqbyX)$86!Wv!y+r*~kAyjFUKPDWL3A)m$@ir9 zjJ;uQV9#3$*`Dqo1Cy5*;^8DQcid^Td=CivAP+D;gl4b7*xa9IQ-R|lY5tIpiM~9- z%Hm9*vDV@_1FfiR|Kqh_5Ml0sm?abD>@peo(cnhiSWs$uy&$RYcd+m`6%X9FN%?w}s~Q=3!pJzbN~iJ}bbM*PPi@!E0eN zhKcuT=kAsz8TQo76CMO+FW#hr6da({mqpGK2K4T|xv9SNIXZ}a=4_K5pbz1HE6T}9 zbApW~m0C`q)S^F}B9Kw5!eT)Bj_h9vlCX8%VRvMOg8PJ*>PU>%yt-hyGOhjg!2pZR4{ z=VR_*?Hw|aai##~+^H>3p$W@6Zi`o4^iO2Iy=FPdEAI58Ebc~*%1#sh8KzUKOVHs( z<3$LMSCFP|!>fmF^oESZR|c|2JI3|gucuLq4R(||_!8L@gHU8hUQZKn2S#z@EVf3? zTroZd&}JK(mJLe>#x8xL)jfx$6`okcHP?8i%dW?F%nZh=VJ)32CmY;^y5C1^?V0;M z<3!e8GZcPej-h&-Osc>6PU2f4x=XhA*<_K*D6U6R)4xbEx~{3*ldB#N+7QEXD^v=I z+i^L+V7_2ld}O2b-(#bmv*PyZI4|U#Q5|22a(-VLOTZc3!9ns1RI-? zA<~h|tPH0y*bO1#EMrsWN>4yJM7vqFZr?uw$H8*PhiHRQg1U9YoscX-G|gck+SSRX!(e7@~eeUEw+POsT;=W9J&=EV`cUc{PIg_#TQVGnZsQbCs7#Q-)v#BicxLw#Fb?#)8TYbu zN)5R=MI1i7FHhF|X}xEl=sW~`-kf;fOR^h1yjthSw?%#F{HqrY2$q>7!nbw~nZ8q9 zh{vY! z%i=H!!P&wh z7_E%pB7l5)*VU>_O-S~d5Z!+;f{pQ4e86*&);?G<9*Q$JEJ!ZxY;Oj5&@^eg0Zs!iLCAR`2K?MSFzjX;kHD6)^`&=EZOIdW>L#O`J zf~$M4}JiV}v6B-e{NUBGFgj-*H%NG zfY0X(@|S8?V)drF;2OQcpDl2LV=~=%gGx?_$fbSsi@%J~taHcMTLLpjNF8FkjnjyM zW;4sSf6RHaa~LijL#EJ0W2m!BmQP(f=%Km_N@hsBFw%q#7{Er?y1V~UEPEih87B`~ zv$jE%>Ug9&=o+sZVZL7^+sp)PSrS;ZIJac4S-M>#V;T--4FXZ*>CI7w%583<{>tb6 zOZ8gZ#B0jplyTbzto2VOs)s9U%trre`m=RlKf{I_Nwdxn(xNG%zaVNurEYiMV3*g| z``3;{j7`UyfFrjlEbIJN{0db|r>|LA@=vX9CHFZYiexnkn$b%8Rvw0TZOQIXa;oTI zv@j;ZP+#~|!J(aBz9S{wL7W%Dr1H)G-XUNt9-lP?ijJ-XEj1e*CI~-Xz@4(Xg;UoG z{uzBf-U+(SHe}6oG%;A*93Zb=oE>uTb^%qsL>|bQf?7_6=KIiPU`I|r;YcZ!YG7y~ zQu@UldAwz$^|uoz3mz1;An-WVBtefSh-pv<`n&TU3oM!hrEI?l@v8A4#^$4t&~T32 zl*J=1q~h+60sNc43>0aVvhzyfjshgPYZoQ(OOh>LbUIoblb@1z~zp?))n?^)q6WGuDh}gMUaA9|X z3qq-XlcNldy5==T4rq*~g@XVY!9sYZjo#R7 zr{n)r5^S{9+$+8l7IVB*3_k5%-TBY@C%`P@&tZf>82sm#nfw7L%92>nN$663yW!yt zhS>EfLcE_Z)gv-Y^h1;xj(<4nD4GY{C-nWUgQc9cMmH{qpa!uEznrGF^?bbJHApScQ$j>$JZHAX80DdXu z--AMgrA0$Otdd#N9#!cg2Z~N8&lj1d+wDh+^ZObWJ$J)_h(&2#msu>q0B$DEERy{1 zCJN{7M@%#E@8pda`@u!v@{gcT3bA*>g*xYLXlbb&o@1vX*x+l}Voys6o~^_7>#GB| z*r!R%kA9k%J`?m>1tMHB9x$ZRe0$r~ui}X}jOC)9LH=Po*2SLdtf3^4?VKnu2ox&mV~0oDgi` z;9d}P$g~9%ThTK8s}5ow2V4?(-lU*ed8ro|}mU}pk% z;bqB0bx3AOk<0Joeh}Vl@_7Po&C`Cg>>gff>e7fu41U3Ic{JQu1W%+!Gvz3GDO2ixKd;KF6UEw8F_cDAh08gB>@ zaRH2Q96sBJ>`4aXvrF0xPtIWoA1pPsRQtU~xDtnEfTJnl{A9u5pR^K8=UdNq%T8F$)FbN> zgK+_(BF#D>R>kK!M#OT~=@@}3yAYqm33?{Bv?2iBr|-aRK0@uapzuXI)wE0=R@m^7 zQ`wLBn(M*wg!mgmQT1d!@3<2z>~rmDW)KG0*B4>_R6LjiI0^9QT8gtDDT|Lclxppm z+OeL6H3QpearJAB%1ellZ6d*)wBQ(hPbE=%?y6i^uf%`RXm*JW*WQ%>&J+=V(=qf{ zri~yItvTZbII+7S0>4Q0U9@>HnMP$X>8TqAfD(vAh};2P{QK)ik`a6$W$nG<{bR2Ufd!^iE z#1K58$gW!xpeYHeehuhQCXZ9p%N8m zB+l~T_u-Ycr!U>!?xu!!*6rNxq37{`DhMMfY6NpD3Jw zkYQDstvt30Hc_SaZuuMP2YrdW@HsPMbf^Y9lI<9$bnMil2X7`Ba-DGLbzgqP>mxwe zf1&JkDH54D3nLar2KjJ3z`*R+rUABq4;>>4Kjc2iQEj7pVLcZYZ~pteAG4rm1{>PQy=!QiV5G|tVk)53 zP?Azw+N)Yq3zZ`dW7Q9Bq@Y*jSK0<1f`HM;_>GH57pf_S%Ounz_yhTY8lplQSM`xx zU{r-Deqs+*I~sLI$Oq`>i`J1kJ(+yNOYy$_>R3Jfi680<|^u#J@aY%Q>O zqfI~sCbk#3--^zMkV&Yj0D(R^rK}+_npgPr_4^kYuG=pO%$C_7v{s@-{M-P@RL3^<`kO@b=YdKMuccfO1ZW# zeRYE%D~CMAgPlo?T!O6?b|pOZv{iMWb;sN=jF%=?$Iz_5zH?K;aFGU^8l7u%zHgiy z%)~y|k;Es-7YX69AMj^epGX#&^c@pp+lc}kKc`5CjPN4Z$$e58$Yn*J?81%`0~A)D zPg-db*pj-t4-G9>ImW4IMi*v#9z^9VD9h@9t;3jMAUVxt=oor+16yHf{lT|G4 zya6{4#BxFw!!~UTRwXXawKU4iz$$GMY6=Z8VM{2@0{=5A0+A#p6$aT3ubRyWMWPq9 zCEH5(Il0v4e4=Yxg(tDglfYAy!UpC>&^4=x7#6_S&Ktds)a8^`^tp6RnRd{KImB^o z2n=t#>iKx<*evmvoE{+fH#@WXGWs$)Uxrtf?r>AaxV0?kf0o@oDboJ6z0cgP@A$;k>SK1UqC?Q_ zk_I?j74;}uNXhOf_5ZxQSgB4otDEb9JJrX1kq`-o%T>g%M5~xXf!2_4P~K64tKgXq z&KHZ0@!cPvUJG4kw-0;tPo$zJrU-Nop>Uo65Pm|yaNvKjhi7V1g98;^N1~V3% zTR>yWa+X2FJ_wpPwz3i^6AGwOa_VMS-&`*KoKgF2&oR10Jn6{!pvVG@n=Jk@vjNuY zL~P7aDGhg~O9G^!bHi$8?G9v9Gp0cmekYkK;(q=47;~gI>h-kx-ceM{ml$#8KI$4ltyjaqP zki^cyDERloAb)dcDBU4na9C(pfD{P@eBGA}0|Rb)p{ISqi60=^FUEdF!ok{Gs;vb) zfj9(#1QA64w*ud^YsN5&PeiI>c`VioE8h)e}W%S9NMA55Gs zrWL6l+@3CKd@8(UQLTwe12SGWMqRn+j)QZRj*g)Xua)%ayzpqs{pD(WWESJYL3{M$ z%qkpM`jFoqLYVv6{IbCkL?fEiJj$VG=$taup&RL9e{s(Sgse2xVJlw0h74EXJKt2eX|dxz{->0)3W`JN7Bv!rLvRZc z0tAOZ2yVe4g9iq826qXAg`f!*+}(o1;1FDb>kKexumFS40KvK0yH1_@Z=LgWZ+}(Y zwYsa;OLz6tTA%gS=>8$=Z7pLh>|K2QElL)E=Q*(n*H`8R`8={-@4mTD-SWBOYRxV? zmF(-rJB8^Wlp?319rTrh^?QEP?|Msxrv?WbJ-+id+V#F2Y4(JPJ6U9bv+U1cIIH^W z)lg$_=g^Ma>2~Pyd_YOAv29Cb-U6DJO?NxnW7~QP*SmYi*vdUVuW#LWQ_u0`hymZi zaQS3Nb^4`ro$>0G%zbXmr5|D|iq0R<;S@?kr0j5Ruq87-Z1>crx%EzVZ9#U;{?}ti zW2W%*9MQg3Nbh%Ti6LhDd|-aFSgXoPG`mHlUU1iCHr>ru>DX?W_#13(`u*!Plu2OP z6jk=2>BC0l)aw;HCmxoYD1i4b%m$1`DYC_^L~ zIEAnFcHvad=-aO3(_MI=9#`z6-9*_!&$?<%meb5;jGd5Qp=MGf z6BD{%`L#TAOq%z%@*ib95Ey7NbUF=BlszVk3Iu3imD&*91N-ij%hW?W@~2TtdHTfP z#n0@Xd7X8Dyu36n{k#PwQ~T~X7mAO^cNV+z<HO@3X-# z_@rAn$k~(l@kciCC;&Qd*fWRI>=;fL{UPlciNDWyj$bX<#r^(r;EE8wwUVQm&7~QY zCXRj!**r^xybAEPq>h3W$uvI1j=yNIyzkE_D7fpGw)OV{U*Uwm{xB;mEg2(|y|ICd zMdQVqzMb-=XM6|E-a9kNh)^9lY`-DjhhHD1w5lufRcy+QLgJ47!fFne86#F; zX{ufroVBEZJOY?rDo!;Te6aOZ^1SO!dYRxQ*2njyA~dCWawn)>!*k7~>8Ikt&e*0>>V5ZbO|*1+2LFOqVe zXHb!aMk03^h%&9L8GMy7UDI2Kev>V@(R}*Iu6x+!Hn4~D@wj`P%#Hdbf(lK{+DD7f zJ&(v*mhn_e(R$^5L#bM^^Q@-!*b!l|+Xrb(q*MRFJYnrE7*xko!SJOy9LngR2|q5k zY`Ioiu+YBfzF{Labszk-E#*BYQk>$()=xWEGZRKwY)*UxP}0dGuPLZOkNJDI9Hy zFjfwiK6RjhH#rHW#B0(MW}i%V`943<6@Z*Nd^JEP5uZonXm=u%AM>{H^U@&Jy*i0s za_Da^xI6pMtXzHc{e~_ZcnKP*;=YL2Z^RmzDl{dJTk7*}E_h*NvgnhnxVKB59Duh~ zqouS_WoOR*{UvUw_K#OWz;gMracr%8>QQ&V*jv!8)ho;U8}9~8EU{N<=Z_gR%IpMT zbkePUG_afm=#|iIfFmdqkpLMGxY5D$`?I}&T7>TexU@v zkBx09kG)O;09ckj#(_Uov6vv{{HOcr-%H#DUQ@*GzF8Zh{iSM13%fuB%>wjdU@3Nf zlnYE!GTyNrqes|;nLFXfWU*Wg-9wmr=NBd$nCk+H?iwNvcd0Wab^3CT9a`>3V~oWI z9=_H+N-Q=MQ(io4u4mpdQ;k&5FXnKV5M7R`@WJ9h(GrAirO#XXOU{qQpk^B^Vd=Dt{wiqT zg-#j9J~@o%H2;W9mg)o6@*Vo;BSs2*4HAHpDk02mndAsov08R_48zJZ@J)s7+hyCo zy*0L#y)?AqZt-wX%+_Vx`8*A95OLHvs1$k~{h-_N_vov_gHJE=`X>L?5K+ zD?u59=mjtImMvd1GsDytuYp{IyUkW&?h zF>$#`n$~bZ)KN0B$XGeMYh&`;g8 zo_2-koaO6+8O!+L>SpIQbG(i;QW9UJi{Ecewlo?s&D!^>i$|#jaW}#HJuxt|W48=? zb^Y&O$a1s5ddr8DIt!sD!t=y1g(d4GR(s;s-HfV$GXl&m;+sAAxB^rk(3_NjE$p#L z*t4em?tA0d+XwRxN^OQwzbDZMuSE0J1)Ky{mq)^t4bnSl*)s>zNM@mMdtd78&ebHN z`!(|lE5q-p+TsRaNnMXwALaN5QIZ2IUi^Z22tsN5>nvIO+YU}Q*xh6}ee6@rR~<&1 z(PB4z>9ZBUMXZwSMmd9-aKKsmJeJq^G|#JclOh*xf0?^e0(`40nsg1z)(48;4}B_( zGwPI)yo|{oX{dVDL-5-aMGr;~vU1cPtJP5JM(sswz&Q`e<@0?y{YhsO9YK8EYJA;L z>7oG_Mts+(wCBC*Md82#XdKw&J*IizR?9k^rf1r{Ot-&>V^ke{9nI9zavlcNkIJtN z7T>?o|4rENk-?|lewZ(EfdR;%BUrzKJ^UkCpsM)EA9QHBVV8trT&*O(9?FO{MLTFL z=5P0H+T6C^jAuX0k4U;~GM!x`!X2N~3_n?qXY$HI>x@(DHEy&Q3ucT1R6fj28wX!I zC=&d$@bJ_v^%?W2Ngl}e8ww`b%BrN-PzGH;$@B2Ky1?%GMkm#~Okj(-Admyy;qya| zOi73kr_pwt?5Nj3p=&H>81!w#>Agj z(QXx{j0r=pTl>micAI_5vUw<3`Sht?Z}-j2Wx~F8DKCUQrsXl2?W8hur42(F_ zsSJ)_36&x6A|YkY6c<2a94SXbv~d>4CC4nkDPvf9Z5Fys^6^5r0j5=E>Cgy_Dk@tS z%?c}9!qB?t6t8(XMH%le8UeNWp@Nsma~Ql+^3Bo%_npMryeQJz4V=BAqE~T?dejng z3ge{fjCHoNAfYBvsfq;G%VL|j7t z`X0sy1EEgpyD;)tS1x+fnv-?C@glP0{RCW}Ma?3qpoq_&IJAYOy3G#s`rsh5=3>`K zkj``=;|*x5HSjZC zXNvPLh372q;=+6ja|SC!R-`JcL}}wwskajjTUGTpL(1zkN-p?BA2lmf+J3WsB7!k`0Brx8^cLTF9h)r+LZ$vsZo}`OpOs)?c6$hclR!R#MAeh|_DY|9r zy+_3c%IO9h9X?ksp?an&>Lw;QeQ`T-Ku6HaK~H?E9-Z5$cZu{YU;1+-6B$|JD;%!^ zt(4l>F8}a-UkC4YtOxFHckhl4VKr6P$P_O*U!)IDory%}Wz`YeFx6TO{y2Y${SBm?H9cTWV=WWJ z`_*CGso!ZN>l@~_jkeXtV}fczfA{TUkyeD>)i3|NFGcCsBmK3HXp&ol_@GVs7PIpfULy!hi zs+%KYgS%(n7_z_}6)hblk~W#LZ@&2)fwm6xkFP%&Ju|MFWbNiTwy{{g-pV1RK`L&=RE2D z4|g;~vd8xd|teYS%w!IlT4W$&FTrk-hcTADX!P?*f1YWEIRwq$Ys%^(Z9w&HT$>} zsMD#6Df=uJrX!JHP7<>Or;e_Cf=}`!`qR=i8fBj)$6Lxx{HRzd8Tnzd0p>kSps{OG zKJkml>bUj8$u|F=``l(-aMxWBC@CGZ#FXClQZ<4|&%jN}Tkg#q8z)=>Ly{$i0`rjU zvt|QddO&i=91e?h3>s~i;+6{ z8X4i6a1wDLrSuE#W(zhan+U*Zq+8p3a))JFVF4ffaV51K^YgTso~3;Y*NmM; zx8T?y-N0uyWY(8=me-HUC9xtABvX5~%yg+Cp&XF$Bq=OcK6T*D7eZ2EmIoCFWm{$S z1PNw8HDpe5hHeCusN8kdeb&f2#=3M^A~7YwJ7FRrhq*)PG9x?JIAaC{MV}5}g#7R$-Ly%)4=IUkRCGOR|XTMjn&okRmFjaO^YF5^* z@)#MCBOBezD)*xQNxydlUyN?dW{fS(s-T`gv*0BEnk}`BdmrbmPO8q8y(X$AA}*RH%I7Av!~84pudHb&%Q5-j zt?=6x(iR?<^_7X0v6Ys#VAL}dKk^hcjI=|EY;kPcZ_w<*H`_*|N7SacaM1ERD@6ab zg`!iTm7$URV+lpW_{V$ruR&A>jrX68k4x2wo$45}&wf7o<|o(@B!u-L@bKyQBAGwy z4#}UrRAu>^>Vb6k2-th^>WjvP;Nl|i3WrjWv3ISkj{m{eAcQIW^_ndxSX@|8T(ASJ z?_$fcP2u*6uOBk-{d>^ z0vWlfGQMvysI%R=iE|A+!!Nw?C917EU*_$`;;)px?s83CRd3i_jBN)k#nR5t$dJ(+ z_sP;wG@Ad)^(3LRj7q}0b2O(b`|i0~5SYb%Sjk^*5ISZ-Ab+}DGu$-X1n^TF1Ndw_ zF|e*1)cI2%`TR&AW~XpqpFb!=3cHbS>np9hYD_Mr5}y5Y`SY^r7isA2Q4(z zazRQEqWDKT2zIEbjSYdCPi1ZOGz80Nsl}gxO^DWMY0AV<2K&OL{&^6#@L1?lXu#6xSMh%3^5c*}oM6DQGY#(a^@z<&D zF(43I9e&5`h|A$5!+UFuOH0>F3$shBV4`0#M4RSB8=6F0ZgIbq<2LQ$Hh^(kAJu=! zt8ZGXTacD{(3W{V1$j_{Jc)Ka7t6u}ho`4kF+4@t_0!mCBn z)}o%eA}L)_L?=jw6BIfll7tb3n}?*yLt&XADa=rW>qz=_6s9ziOd5sXjil>FVFx3r zf>Feewk0v#W9>Gp4GacTRr>Sd2T6dWi-{YX`v!D)kCWzG5xQB=?es5ON(%nkwUhNl zV>@xkWWWv*N+{e$(SrExvN6BXzU(Hxlx27{VYHf+LpIbTO+Yu(ltMk<;)3A(LU@ytVYFkYvTa79idMtUFhfxx?P!)2F`prNWW#Fub#l>N2s@nh&n_ zA4{#}|AIs9|A4P0ZF%fy=hDN!t#ifH<)4u2kirK~JUpjQ-J+~cXOZI&dIts;P}UeXslP6zKvpEKSN-$y>kJ^nw2tC9bv zo(|lT@?vZ!{_l|d^8Yh)eEBh*5ABh+Lzjw+?V)o z#P-W7361>E(Y4;@`sv;VKn G`u_lkUM?>H literal 0 HcmV?d00001 diff --git a/docs/fonts/glyphicons-halflings-regular.woff2 b/docs/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..64539b54c3751a6d9adb44c8e3a45ba5a73b77f0 GIT binary patch literal 18028 zcmV(~K+nH-Pew8T0RR9107h&84*&oF0I^&E07eM_0Rl|`00000000000000000000 z0000#Mn+Uk92y`7U;vDA2m}!b3WBL5f#qcZHUcCAhI9*rFaQJ~1&1OBl~F%;WnyLq z8)b|&?3j;$^FW}&KmNW53flIFARDZ7_Wz%hpoWaWlgHTHEHf()GI0&dMi#DFPaEt6 zCO)z0v0~C~q&0zBj^;=tv8q{$8JxX)>_`b}WQGgXi46R*CHJ}6r+;}OrvwA{_SY+o zK)H-vy{l!P`+NG*`*x6^PGgHH4!dsolgU4RKj@I8Xz~F6o?quCX&=VQ$Q{w01;M0? zKe|5r<_7CD z=eO3*x!r$aX2iFh3;}xNfx0v;SwBfGG+@Z;->HhvqfF4r__4$mU>Dl_1w;-9`~5rF~@!3;r~xP-hZvOfOx)A z#>8O3N{L{naf215f>m=bzbp7_(ssu&cx)Qo-{)!)Yz3A@Z0uZaM2yJ8#OGlzm?JO5gbrj~@)NB4@?>KE(K-$w}{};@dKY#K3+Vi64S<@!Z{(I{7l=!p9 z&kjG^P~0f46i13(w!hEDJga;*Eb z`!n|++@H8VaKG<9>VDh(y89J#=;Z$ei=GnD5TesW#|Wf)^D+9NKN4J3H5PF_t=V+Z zdeo8*h9+8&Zfc?>>1|E4B7MAx)^uy$L>szyXre7W|81fjy+RZ1>Gd}@@${~PCOXo) z$#HZd3)V3@lNGG%(3PyIbvyJTOJAWcN@Uh!FqUkx^&BuAvc)G}0~SKI`8ZZXw$*xP zum-ZdtPciTAUn$XWb6vrS=JX~f5?M%9S(=QsdYP?K%Odn0S0-Ad<-tBtS3W06I^FK z8}d2eR_n!(uK~APZ-#tl@SycxkRJ@5wmypdWV{MFtYBUY#g-Vv?5AEBj1 z`$T^tRKca*sn7gt%s@XUD-t>bij-4q-ilku9^;QJ3Mpc`HJ_EX4TGGQ-Og)`c~qm51<|gp7D@ zp#>Grssv^#A)&M8>ulnDM_5t#Al`#jaFpZ<#YJ@>!a$w@kEZ1<@PGs#L~kxOSz7jj zEhb?;W)eS}0IQQuk4~JT30>4rFJ3!b+77}>$_>v#2FFEnN^%(ls*o80pv0Q>#t#%H z@`Yy-FXQ9ULKh{Up&oA_A4B!(x^9&>i`+T|eD!&QOLVd(_avv-bFX~4^>o{%mzzrg_i~SBnr%DeE|i+^}|8?kaV(Z32{`vA^l!sp15>Z72z52FgXf z^8ZITvJ9eXBT1~iQjW|Q`Fac^ak$^N-vI^*geh5|*CdMz;n16gV_zk|Z7q8tFfCvU zJK^Pptnn0Rc~egGIAK}uv99VZm2WLPezQQ5K<`f zg{8Ll|GioPYfNheMj-7-S87=w4N0WxHP`1V6Y)0M&SkYzVrwp>yfsEF7wj&T0!}dB z)R~gGfP9pOR;GY_e0~K^^oJ-3AT+m~?Al!{>>5gNe17?OWz)$)sMH*xuQiB>FT2{i zQ>6U_8}Ay~r4li;jzG+$&?S12{)+<*k9 z<^SX#xY|jvlvTxt(m~C7{y{3g>7TX#o2q$xQO|fc<%8rE@A3=UW(o?gVg?gDV!0q6O!{MlX$6-Bu_m&0ms66 znWS&zr{O_4O&{2uCLQvA?xC5vGZ}KV1v6)#oTewgIMSnBur0PtM0&{R5t#UEy3I9) z`LVP?3f;o}sz*7g5qdTxJl^gk3>;8%SOPH@B)rmFOJ)m6?PlYa$y=RX%;}KId{m9R#2=LNwosF@OTivgMqxpRGe}5=LtAn?VVl6VWCFLD z7l#^^H8jY~42hR)OoVF#YDW(md!g(&pJ;yMj|UBAQa}UH?ED@%ci=*(q~Opn>kE2Q z_4Kgf|0kEA6ary41A;)^Ku(*nirvP!Y>{FZYBLXLP6QL~vRL+uMlZ?jWukMV*(dsn zL~~KA@jU)(UeoOz^4Gkw{fJsYQ%|UA7i79qO5=DOPBcWlv%pK!A+)*F`3WJ}t9FU3 zXhC4xMV7Z%5RjDs0=&vC4WdvD?Zi5tg4@xg8-GLUI>N$N&3aS4bHrp%3_1u9wqL)i z)XQLsI&{Hd&bQE!3m&D0vd!4D`l1$rt_{3NS?~lj#|$GN5RmvP(j3hzJOk=+0B*2v z)Bw133RMUM%wu_+$vbzOy?yk#kvR?xGsg-ipX4wKyXqd zROKp5))>tNy$HByaEHK%$mqd>-{Yoj`oSBK;w>+eZ&TVcj^DyXjo{DDbZ>vS2cCWB z(6&~GZ}kUdN(*2-nI!hvbnVy@z2E#F394OZD&Jb04}`Tgaj?MoY?1`{ejE2iud51% zQ~J0sijw(hqr_Ckbj@pm$FAVASKY(D4BS0GYPkSMqSDONRaFH+O2+jL{hIltJSJT~e)TNDr(}=Xt7|UhcU9eoXl&QZRR<9WomW%&m)FT~j zTgGd3-j}Uk%CRD;$@X)NNV9+RJbifYu>yr{FkO;p>_&njI> zyBHh_72bW;8}oGeY0gpHOxiV597j7mY<#?WMmkf5x~Kfk*re(&tG_mX<3&2cON*2u%V29tsXUv{#-ijs2>EuNH-x3) zPBpi+V6gI=wn}u164_j8xi-y(B?Au2o;UO=r6&)i5S3Mx*)*{_;u}~i4dh$`VgUS- zMG6t*?DXDYX0D2Oj31MI!HF>|aG8rjrOPnxHu4wZl;!=NGjjDoBpXf?ntrwt^dqxm zs(lE@*QB3NH)!`rH)5kks-D89g@UX&@DU9jvrsY)aI=9b4nPy3bfdX_U;#?zsan{G>DKob2LnhCJv8o}duQK)qP{7iaaf2=K`a-VNcfC582d4a z>sBJA*%S|NEazDxXcGPW_uZ&d7xG`~JB!U>U(}acUSn=FqOA~(pn^!aMXRnqiL0;? zebEZYouRv}-0r;Dq&z9>s#Rt1HL`0p4bB)A&sMyn|rE_9nh z?NO*RrjET8D4s(-`nS{MrdYtv*kyCnJKbsftG2D#ia@;42!8xd?a3P(&Y?vCf9na< zQ&Ni*1Qel&Xq{Z?=%f0SRqQt5m|Myg+8T=GDc)@^};=tM>9IDr7hdvE9-M@@<0pqv45xZTeNecbL- zWFQt4t`9>j8~X%lz}%We>Kzh_=`XO}!;4!OWH?=p*DOs#Nt({k^IvtBEL~Qafn)I^ zm*k{y7_bIs9YE}0B6%r`EIUH8US+MGY!KQA1fi-jCx9*}oz2k1nBsXp;4K<_&SN}}w<)!EylI_)v7}3&c)V;Cfuj*eJ2yc8LK=vugqTL><#65r6%#2e| zdYzZ)9Uq7)A$ol&ynM!|RDHc_7?FlWqjW>8TIHc`jExt)f5W|;D%GC#$u!%B*S%Z0 zsj&;bIU2jrt_7%$=!h4Q29n*A^^AI8R|stsW%O@?i+pN0YOU`z;TVuPy!N#~F8Z29 zzZh1`FU(q31wa>kmw{$q=MY>XBprL<1)Py~5TW4mgY%rg$S=4C^0qr+*A^T)Q)Q-U zGgRb9%MdE-&i#X3xW=I`%xDzAG95!RG9)s?v_5+qx`7NdkQ)If5}BoEp~h}XoeK>kweAMxJ8tehagx~;Nr_WP?jXa zJ&j7%Ef3w*XWf?V*nR)|IOMrX;$*$e23m?QN` zk>sC^GE=h6?*Cr~596s_QE@>Nnr?{EU+_^G=LZr#V&0fEXQ3IWtrM{=t^qJ62Sp=e zrrc>bzX^6yFV!^v7;>J9>j;`qHDQ4uc92eVe6nO@c>H=ouLQot``E~KLNqMqJ7(G+?GWO9Ol+q$w z!^kMv!n{vF?RqLnxVk{a_Ar;^sw0@=+~6!4&;SCh^utT=I zo&$CwvhNOjQpenw2`5*a6Gos6cs~*TD`8H9P4=#jOU_`%L!W;$57NjN%4 z39(61ZC#s7^tv`_4j}wMRT9rgDo*XtZwN-L;Qc$6v8kKkhmRrxSDkUAzGPgJ?}~_t zkwoGS4=6lsD`=RL|8L3O9L()N)lmEn-M15fRC{dhZ}7eYV%O-R^gsAp{q4 z!C1}_T8gy^v@SZ5R&Li5JMJy+K8iZw3LOGA0pN1~y@w7RRl#F()ii6Y5mr~Mdy@Kz z@FT4cm^I&#Fu_9IX(HAFP{XLbRALqm&)>m_we>a`hfv?eE|t z?YdDp2yAhj-~vuw^wzVDuj%w?exOcOT(ls(F*ceCe(C5HlN{lcQ;}|mRPqFDqLEzw zR7ldY+M6xe$$qLwekmk{Z&5cME$gpC?-8)f0m$rqaS|mj9ATNJvvyCgs(f2{r;2E!oy$k5{jik#(;S>do<#m0wVcU<}>)VtYmF9O0%(C>GDzPgh6X z9OkQLMR~y7=|MtaU!LDPPY7O)L{X#SC+M|v^X2CZ?$GS>U_|aC(VA(mIvCNk+biD| zSpj>gd(v>_Cbq>~-x^Y3o|?eHmuC?E&z>;Ij`%{$Pm$hI}bl0Kd`9KD~AchY+goL1?igDxf$qxL9< z4sW@sD)nwWr`T>e2B8MQN|p*DVTT8)3(%AZ&D|@Zh6`cJFT4G^y6`(UdPLY-&bJYJ z*L06f2~BX9qX}u)nrpmHPG#La#tiZ23<>`R@u8k;ueM6 znuSTY7>XEc+I-(VvL?Y>)adHo(cZ;1I7QP^q%hu#M{BEd8&mG_!EWR7ZV_&EGO;d(hGGJzX|tqyYEg2-m0zLT}a{COi$9!?9yK zGN7&yP$a|0gL`dPUt=4d^}?zrLN?HfKP0_gdRvb}1D73Hx!tXq>7{DWPV;^X{-)cm zFa^H5oBDL3uLkaFDWgFF@HL6Bt+_^g~*o*t`Hgy3M?nHhWvTp^|AQDc9_H< zg>IaSMzd7c(Sey;1SespO=8YUUArZaCc~}}tZZX80w%)fNpMExki-qB+;8xVX@dr; z#L52S6*aM-_$P9xFuIui;dN#qZ_MYy^C^hrY;YAMg;K`!ZpKKFc z9feHsool)`tFSS}Su|cL0%F;h!lpR+ym|P>kE-O`3QnHbJ%gJ$dQ_HPTT~>6WNX41 zoDEUpX-g&Hh&GP3koF4##?q*MX1K`@=W6(Gxm1=2Tb{hn8{sJyhQBoq}S>bZT zisRz-xDBYoYxt6--g2M1yh{#QWFCISux}4==r|7+fYdS$%DZ zXVQu{yPO<)Hn=TK`E@;l!09aY{!TMbT)H-l!(l{0j=SEj@JwW0a_h-2F0MZNpyucb zPPb+4&j?a!6ZnPTB>$t`(XSf-}`&+#rI#`GB> zl=$3HORwccTnA2%>$Nmz)u7j%_ywoGri1UXVNRxSf(<@vDLKKxFo;5pTI$R~a|-sQ zd5Rfwj+$k1t0{J`qOL^q>vZUHc7a^`cKKVa{66z?wMuQAfdZBaVVv@-wamPmes$d! z>gv^xx<0jXOz;7HIQS z4RBIFD?7{o^IQ=sNQ-k!ao*+V*|-^I2=UF?{d>bE9avsWbAs{sRE-y`7r zxVAKA9amvo4T}ZAHSF-{y1GqUHlDp4DO9I3mz5h8n|}P-9nKD|$r9AS3gbF1AX=2B zyaK3TbKYqv%~JHKQH8v+%zQ8UVEGDZY|mb>Oe3JD_Z{+Pq%HB+J1s*y6JOlk`6~H) zKt)YMZ*RkbU!GPHzJltmW-=6zqO=5;S)jz{ zFSx?ryqSMxgx|Nhv3z#kFBTuTBHsViaOHs5e&vXZ@l@mVI37<+^KvTE51!pB4Tggq zz!NlRY2ZLno0&6bA|KHPYOMY;;LZG&_lzuLy{@i$&B(}_*~Zk2 z>bkQ7u&Ww%CFh{aqkT{HCbPbRX&EvPRp=}WKmyHc>S_-qbwAr0<20vEoJ(!?-ucjE zKQ+nSlRL^VnOX0h+WcjGb6WI(8;7bsMaHXDb6ynPoOXMlf9nLKre;w*#E_whR#5!! z!^%_+X3eJVKc$fMZP;+xP$~e(CIP1R&{2m+iTQhDoC8Yl@kLM=Wily_cu>7C1wjVU z-^~I0P06ZSNVaN~A`#cSBH2L&tk6R%dU1(u1XdAx;g+5S^Hn9-L$v@p7CCF&PqV{Z?R$}4EJi36+u2JP7l(@fYfP!=e#76LGy^f>~vs0%s*x@X8`|5 zGd6JOHsQ=feES4Vo8%1P_7F5qjiIm#oRT0kO1(?Z_Dk6oX&j=Xd8Klk(;gk3S(ZFnc^8Gc=d;8O-R9tlGyp=2I@1teAZpGWUi;}`n zbJOS_Z2L16nVtDnPpMn{+wR9&yU9~C<-ncppPee`>@1k7hTl5Fn_3_KzQ)u{iJPp3 z)df?Xo%9ta%(dp@DhKuQj4D8=_!*ra#Ib&OXKrsYvAG%H7Kq|43WbayvsbeeimSa= z8~{7ya9ZUAIgLLPeuNmSB&#-`Je0Lja)M$}I41KHb7dQq$wgwX+EElNxBgyyLbA2* z=c1VJR%EPJEw(7!UE?4w@94{pI3E%(acEYd8*Wmr^R7|IM2RZ-RVXSkXy-8$!(iB* zQA`qh2Ze!EY6}Zs7vRz&nr|L60NlIgnO3L*Yz2k2Ivfen?drnVzzu3)1V&-t5S~S? zw#=Sdh>K@2vA25su*@>npw&7A%|Uh9T1jR$mV*H@)pU0&2#Se`7iJlOr$mp79`DKM z5vr*XLrg7w6lc4&S{So1KGKBqcuJ!E|HVFB?vTOjQHi)g+FwJqX@Y3q(qa#6T@3{q zhc@2T-W}XD9x4u+LCdce$*}x!Sc#+rH-sCz6j}0EE`Tk*irUq)y^za`}^1gFnF)C!yf_l_}I<6qfbT$Gc&Eyr?!QwJR~RE4!gKVmqjbI+I^*^ z&hz^7r-dgm@Mbfc#{JTH&^6sJCZt-NTpChB^fzQ}?etydyf~+)!d%V$0faN(f`rJb zm_YaJZ@>Fg>Ay2&bzTx3w^u-lsulc{mX4-nH*A(32O&b^EWmSuk{#HJk}_ULC}SB(L7`YAs>opp9o5UcnB^kVB*rmW6{s0&~_>J!_#+cEWib@v-Ms`?!&=3fDot`oH9v&$f<52>{n2l* z1FRzJ#yQbTHO}}wt0!y8Eh-0*|Um3vjX-nWH>`JN5tWB_gnW%; zUJ0V?_a#+!=>ahhrbGvmvObe8=v1uI8#gNHJ#>RwxL>E^pT05Br8+$@a9aDC1~$@* zicSQCbQcr=DCHM*?G7Hsovk|{$3oIwvymi#YoXeVfWj{Gd#XmnDgzQPRUKNAAI44y z{1WG&rhIR4ipmvBmq$BZ*5tmPIZmhhWgq|TcuR{6lA)+vhj(cH`0;+B^72{&a7ff* zkrIo|pd-Yxm+VVptC@QNCDk0=Re%Sz%ta7y{5Dn9(EapBS0r zLbDKeZepar5%cAcb<^;m>1{QhMzRmRem=+0I3ERot-)gb`i|sII^A#^Gz+x>TW5A& z3PQcpM$lDy`zb%1yf!e8&_>D02RN950KzW>GN6n@2so&Wu09x@PB=&IkIf|zZ1W}P zAKf*&Mo5@@G=w&290aG1@3=IMCB^|G4L7*xn;r3v&HBrD4D)Zg+)f~Ls$7*P-^i#B z4X7ac=0&58j^@2EBZCs}YPe3rqgLAA1L3Y}o?}$%u~)7Rk=LLFbAdSy@-Uw6lv?0K z&P@@M`o2Rll3GoYjotf@WNNjHbe|R?IKVn*?Rzf9v9QoFMq)ODF~>L}26@z`KA82t z43e!^z&WGqAk$Ww8j6bc3$I|;5^BHwt`?e)zf|&+l#!8uJV_Cwy-n1yS0^Q{W*a8B zTzTYL>tt&I&9vzGQUrO?YIm6C1r>eyh|qw~-&;7s7u1achP$K3VnXd8sV8J7ZTxTh z5+^*J5%_#X)XL2@>h(Gmv$@)fZ@ikR$v(2Rax89xscFEi!3_;ORI0dBxw)S{r50qf zg&_a*>2Xe{s@)7OX9O!C?^6fD8tc3bQTq9}fxhbx2@QeaO9Ej+2m!u~+u%Q6?Tgz{ zjYS}bleKcVhW~1$?t*AO^p!=Xkkgwx6OTik*R3~yg^L`wUU9Dq#$Z*iW%?s6pO_f8 zJ8w#u#Eaw7=8n{zJ}C>w{enA6XYHfUf7h)!Qaev)?V=yW{b@-z`hAz;I7^|DoFChP z1aYQnkGauh*ps6x*_S77@z1wwGmF8ky9fMbM$dr*`vsot4uvqWn)0vTRwJqH#&D%g zL3(0dP>%Oj&vm5Re%>*4x|h1J2X*mK5BH1?Nx_#7( zepgF`+n)rHXj!RiipusEq!X81;QQBXlTvLDj=Qub(ha&D=BDx3@-V*d!D9PeXUY?l zwZ0<4=iY!sUj4G>zTS+eYX7knN-8Oynl=NdwHS*nSz_5}*5LQ@=?Yr?uj$`C1m2OR zK`f5SD2|;=BhU#AmaTKe9QaSHQ_DUj1*cUPa*JICFt1<&S3P3zsrs^yUE;tx=x^cmW!Jq!+hohv_B> zPDMT0D&08dC4x@cTD$o1$x%So1Ir(G3_AVQMvQ13un~sP(cEWi$2%5q93E7t{3VJf%K? zuwSyDke~7KuB2?*#DV8YzJw z&}SCDexnUPD!%4|y~7}VzvJ4ch)WT4%sw@ItwoNt(C*RP)h?&~^g##vnhR0!HvIYx z0td2yz9=>t3JNySl*TszmfH6`Ir;ft@RdWs3}!J88UE|gj_GMQ6$ZYphUL2~4OY7} zB*33_bjkRf_@l;Y!7MIdb~bVe;-m78Pz|pdy=O*3kjak63UnLt!{^!!Ljg0rJD3a~ z1Q;y5Z^MF<=Hr}rdoz>yRczx+p3RxxgJE2GX&Si)14B@2t21j4hnnP#U?T3g#+{W+Zb z5s^@>->~-}4|_*!5pIzMCEp|3+i1XKcfUxW`8|ezAh>y{WiRcjSG*asw6;Ef(k#>V ztguN?EGkV_mGFdq!n#W)<7E}1#EZN8O$O|}qdoE|7K?F4zo1jL-v}E8v?9qz(d$&2 zMwyK&xlC9rXo_2xw7Qe0caC?o?Pc*-QAOE!+UvRuKjG+;dk|jQhDDBe?`XT7Y5lte zqSu0t5`;>Wv%|nhj|ZiE^IqA_lZu7OWh!2Y(627zb=r7Ends}wVk7Q5o09a@ojhH7 zU0m&h*8+j4e|OqWyJ&B`V`y=>MVO;K9=hk^6EsmVAGkLT{oUtR{JqSRY{Qi{kKw1k z6s;0SMPJOLp!som|A`*q3t0wIj-=bG8a#MC)MHcMSQU98Juv$?$CvYX)(n`P^!`5| zv3q@@|G@6wMqh;d;m4qvdibx2Yjml}vG9mDv&!0ne02M#D`Bo}xIB0VWh8>>WtNZQ z$&ISlJX;*ORQIO;k62qA{^6P%3!Z=Y1EbmY02{w^yB$`;%!{kur&XTGDiO2cjA)lr zsY^XZWy^DSAaz;kZ_VG?uWnJR7qdN18$~)>(kOoybY0~QYu9||K#|$Mby{3GduV~N zk9H7$7=RSo+?CUYF502`b76ytBy}sFak&|HIwRvB=0D|S`c#QCJPq zP)uOWI)#(n&{6|C4A^G~%B~BY21aOMoz9RuuM`Ip%oBz+NoAlb7?#`E^}7xXo!4S? zFg8I~G%!@nXi8&aJSGFcZAxQf;0m}942=i#p-&teLvE{AKm7Sl2f}Io?!IqbC|J;h z`=5LFOnU5?^w~SV@YwNZx$k_(kLNxZDE z3cf08^-rIT_>A$}B%IJBPcN^)4;90BQtiEi!gT#+EqyAUZ|}*b_}R>SGloq&6?opL zuT_+lwQMgg6!Cso$BwUA;k-1NcrzyE>(_X$B0HocjY~=Pk~Q08+N}(|%HjO_i+*=o z%G6C6A30Ch<0UlG;Zdj@ed!rfUY_i9mYwK8(aYuzcUzlTJ1yPz|Bb-9b33A9zRhGl>Ny-Q#JAq-+qtI@B@&w z$;PJbyiW=!py@g2hAi0)U1v=;avka`gd@8LC4=BEbNqL&K^UAQ5%r95#x%^qRB%KLaqMnG|6xKAm}sx!Qwo}J=2C;NROi$mfADui4)y(3wVA3k~{j^_5%H)C6K zlYAm1eY**HZOj($)xfKIQFtIVw$4&yvz9>(Crs>Gh{ zya6-FG7Dgi92#K)64=9Csj5?Zqe~_9TwSI!2quAwa1w-*uC5!}xY`?tltb0Hq740< zsq2QelPveZ4chr$=~U3!+c&>xyfvA1`)owOqj=i4wjY=A1577Gwg&Ko7;?il9r|_* z8P&IDV_g2D{in5OLFxsO!kx3AhO$5aKeoM|!q|VokqMlYM@HtsRuMtBY%I35#5$+G zpp|JOeoj^U=95HLemB04Yqv{a8X<^K9G2`&ShM_6&Bi1n?o?@MXsDj9Z*A3>#XK%J zRc*&SlFl>l)9DyRQ{*%Z+^e1XpH?0@vhpXrnPPU*d%vOhKkimm-u3c%Q^v3RKp9kx@A2dS?QfS=iigGr7m><)YkV=%LA5h@Uj@9=~ABPMJ z1UE;F&;Ttg5Kc^Qy!1SuvbNEqdgu3*l`=>s5_}dUv$B%BJbMiWrrMm7OXOdi=GOmh zZBvXXK7VqO&zojI2Om9};zCB5i|<210I{iwiGznGCx=FT89=Ef)5!lB1cZ6lbzgDn07*he}G&w7m!;|E(L-?+cz@0<9ZI~LqYQE7>HnPA436}oeN2Y(VfG6 zxNZuMK3Crm^Z_AFeHc~CVRrSl0W^?+Gbteu1g8NGYa3(8f*P{(ZT>%!jtSl6WbYVv zmE(37t0C8vJ6O-5+o*lL9XRcFbd~GSBGbGh3~R!67g&l)7n!kJlWd)~TUyXus#!&G6sR%(l(h1$xyrR5j_jM1zj#giA&@(Xl26@n<9>folx!92bQ z24h570+<)4!$!IQ(5yOU|4_E6aN@4v0+{Kx~Z z;q7fp%0cHziuI%!kB~w}g9@V+1wDz0wFlzX2UOvOy|&;e;t!lAR8tV2KQHgtfk8Uf zw;rs!(4JPODERk4ckd5I2Vq|0rd@@Mwd8MID%0^fITjYIQom^q;qhP8@|eJx{?5xX zc1@Fj*kDknlk{c-rnCloQ3hGh7OU+@efO3>fkRMcM>J?AeVP& zlfzX%cdp=N+4S#E*%^=BQ+N`A7C}|k%$|QUn0yI6S3$MS-NjO!4hm55uyju)Q6e!} z*OVO@A#-mfC9Pha6ng((Xl^V7{d+&u+yx)_B1{~t7d5e8L^i4J>;x<7@5;+l7-Gge zf#9diXJ$&v^rbN5V(ee%q0xBMEgS6%qZm7hNUP%G;^J44I!BmI@M*+FWz0!+s;+iQ zU4CuI+27bvNK8v>?7PZnVxB=heJ&_ymE0nN^W#-rqB%+JXkYGDuRw>JM_LdtLkiq* z6%%3&^BX$jnM@2bjiGc-DymKly)wVkA-pq;jSWL#7_*moZZ4I|-N}o8SK?sIv)p|c zu~9-B%tMc=!)YMFp*SiC0>kfnH8+X5>;+FFVN{~a9YVdIg1uGkZ~kegFy{^PU(4{( z`CbY`XmVA3esai686Yw8djCEyF7`bfB^F1)nwv+AqYLZ&Zy=eFhYT2uMd@{sP_qS4 zbJ&>PxajjZt?&c<1^!T|pLHfX=E^FJ>-l_XCZzvRV%x}@u(FtF(mS+Umw$e+IA74e>gCdTqi;6&=euAIpxd=Y3I5xWR zBhGoT+T`V1@91OlQ}2YO*~P4ukd*TBBdt?Plt)_ou6Y@Db`ss+Q~A-48s>?eaJYA2 zRGOa8^~Em}EFTmKIVVbMb|ob)hJJ7ITg>yHAn2i|{2ZJU!cwt9YNDT0=*WO7Bq#Xj zg@FjEaKoolrF8%c;49|`IT&25?O$dq8kp3#la9&6aH z6G|{>^C(>yP7#Dr$aeFyS0Ai_$ILhL43#*mgEl(c*4?Ae;tRL&S7Vc}Szl>B`mBuI zB9Y%xp%CZwlH!3V(`6W4-ZuETssvI&B~_O;CbULfl)X1V%(H7VSPf`_Ka9ak@8A=z z1l|B1QKT}NLI`WVTRd;2En5u{0CRqy9PTi$ja^inu){LJ&E&6W%JJPw#&PaTxpt?k zpC~gjN*22Q8tpGHR|tg~ye#9a8N<%odhZJnk7Oh=(PKfhYfzLAxdE36r<6a?A;rO&ELp_Y?8Pdw(PT^Fxn!eG_|LEbSYoBrsBA|6Fgr zt5LntyusI{Q2fdy=>ditS;}^B;I2MD4=(>7fWt0Jp~y=?VvfvzHvQhj6dyIef46J$ zl4Xu7U9v_NJV?uBBC0!kcTS0UcrV7+@~is?Fi+jrr@l3XwD|uG zr26jUWiv>Ju48Y^#qn7r9mwIH-Pv6Y|V|V-GZ&+&gQ?S?-`&ts{@5GXPqbmyZjUACC&oVXfNwUX0}ba(v978 zp8z!v9~8Zx8qB@7>oFPDm^iR@+yw`79YF)w^OHB_N;&&x7c3l^3!)IY#)}x)@D(iNaOm9 zC=^*!{`7={3*S=%iU=KsPXh=DDZcc``Ss>057i{pdW8M@4q+Ba@Tt%OytH!4>rbIbQw^-pR zGGYNPzw@n=PV@)b7yVbFr;glF*Qq3>F9oBN5PUXt!?2mdGcpv^o1?Thp`jP10G2Yi z(c93td3F3SW!Le5DUwdub!aDKoVLU6g!O?Ret21l$qOC;kdd@L#M&baVu&JZGt&<6 z!VCkvgRaav6QDW2x}tUy4~Y5(B+#Ej-8vM?DM-1?J_*&PntI3E96M!`WL#<&Z5n2u zo`P!~vBT$YOT~gU9#PB)%JZ zcd_u=m^LYzC!pH#W`yA1!(fA;D~b zG#73@l)NNd;n#XrKXZEfab;@kQRnOFU2Th-1m<4mJzlj9b3pv-GF$elX7ib9!uILM_$ke zHIGB*&=5=;ynQA{y7H93%i^d)T}y@(p>8vVhJ4L)M{0Q*@D^+SPp`EW+G6E%+`Z;u zS3goV@Dic7vc5`?!pCN44Ts@*{)zwy)9?B||AM{zKlN4T}qQRL2 zgv+{K8bv7w)#xge16;kI1fU87!W4pX)N&|cq8&i^1r`W|Hg4366r(?-ecEJ9u&Eaw zrhyikXQB>C9d>cpPGiu=VU3Z-u4|0V_iap!_J3o+K_R5EXk@sfu~zHwwYkpncVh!R zqNe7Cmf_|Wmeq4#(mIO&(wCK@b4(x0?W1Qtk(`$?+$uCJCGZm_%k?l32vuShgDFMa ztc`{$8DhB9)&?~(m&EUc=LzI1=qo#zjy#2{hLT_*aj<618qQ7mD#k2ZFGou&69;=2 z1j7=Su8k}{L*h&mfs7jg^PN&9C1Z@U!p6gXk&-7xM~{X`nqH#aGO`;Xy_zbz^rYacIq0AH%4!Oh93TzJ820%ur)8OyeS@K?sF1V(iFO z37Nnqj1z#1{|v7=_CX`lQA|$<1gtuNMHGNJYp1D_k;WQk-b+T6VmUK(x=bWviOZ~T z|4e%SpuaWLWD?qN2%`S*`P;BQBw(B__wTD6epvGdJ+>DBq2oVlf&F*lz+#avb4)3P1c^Mf#olQheVvZ|Z5 z>xXfgmv!5Z^SYn+_x}K5B%G^sRwiez&z9|f!E!#oJlT2kCOV0000$L_|bHBqAarB4TD{W@grX1CUr72@caw0faEd7-K|4L_|cawbojjHdpd6 zI6~Iv5J?-Q4*&oF000000FV;^004t70Z6Qk1Xl{X9oJ{sRC2(cs?- literal 0 HcmV?d00001 diff --git a/docs/img/external.png b/docs/img/external.png new file mode 100644 index 0000000000000000000000000000000000000000..419c06fb960b0b665791c90044a78621616a4cb8 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2VGmzZ%#=aj&i3a$DxTeiKV?6WB%rpNP(#|lX z{f7XTR~%D;3fN16{DL7O3{u|AZa^UmPZ!4!iE!1^jzSC$EX7 z>#2$@InOtpuqyg8<+R}9g-+|v&13&5`dCp`{|95_8^+nQkC>(b&0z3!^>bP0l+XkK DO07OF literal 0 HcmV?d00001 diff --git a/docs/img/link.png b/docs/img/link.png new file mode 100644 index 0000000000000000000000000000000000000000..cd5caec621511e4cad175203fbbed8638293937c GIT binary patch literal 704 zcmV;x0zdtUP)(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZ;MoC0LRCwA%lF3gKVH`kz-#0T|Y-<<6LMzgRtq2%R#Y3$@v<455xDl1ag9o>p z7~@ILCVDVlj9wIj#%dtI0gN#QA~eBLlpw8QX_Zn+T1q#%%yj0f2e+5Jzu-M|^G*r= zqM!h#(ivFDaiABgDwg8zXVIv~Ayd}QSgRaY7>s5xg#hS3A^^Y$14T(pUsv8uMkCV> zb-6W|%`98pi?833lCT@Iqy#xaAS)0+2mmA08Vn52CF1jDOT(E9?WX-r2OGLB7r3~} z_2bPD9#3V#8C!+t@d&IVfN(0@4s3=t)}OvsNuy*Um6cX1w?ES94~!Kyyavn?0vsSn z32gIF(0g4jH@xbxT`~Zhw7j3bKbT}Q=Vp^!>q^LV1h$$Zn5GyI(b9S@H0cib$L^^l zOzdaaeKqKHUM$nMjj*&h5nAY*0-+!RwdE8oqNL>;OCtkJAtqMr*wZsQ-`~r}mu{Eo zY#*vkN6&tldm7+KmNwRPbP9Nji(*ao(RA$dKAFMR*`{sw`+P$$wL1F*V{jZ_&90^M zTuQ00XnfFXY#DBnDuK$CRXtJb>~334+YP$NZ|3E-v)eRv-~8VG$6PU8$!N^CG?d8K zC@+Ui0e}{(>piLHoOQjT<-|HI8(gE&V%Yb>B_U~fv##T=QnnKmK!7E`fa5RARK6DJbz54HZK&HC%Qqbmic; zWpK}xiOE9b;{g#Fg-d6OEDmI<>7Vgoe{^O~SHf|w1GZdWweR>SswxDioc5XF{;;lf z=1PV|Gu~MVa2@NsaW=)#=rfaMS`mY3%;7|}8;cY6PfAmhzHnytjx!+*pJo=!J~?CN zMIbQqWw<%_+0&7^W}b0)E0i*mQ&^K>(wlPT75UFXFP)v^c;Zaj zrL#P0DbGS=($+OGuWEfBn{2VeyJ_Z*N3x4!loV^XnKH{JPE>3->!atWvY}za%oz;E zXFp3QH!=$tFI`YsthloBGn-2Osir?QXKz@DyTmWqz{AN2p$hE>< l<$(usWlo(tbg0RIf#F$A0Hc(u?+Z{QdAjJ^b~bBabKQ*-0}nFnW8sIEHu}KYQJKQ?r7IYoN#np$P@v z=l&f3^=QA(1@T44*0ibaeJd^?8^2=7q3)Q6+XRjja%gK<3;7?KICYoDg`ZP<)VC{Z zPxS~`aAfnHnnh9y#tYYnv#GRBKUE|*b+=aM#jYuVmCi!>p|fJA3hlL8KgnxzfKbC{ zE$J^waZ3gL&$v$wIqt?cD`IklV(i6Lv%IyGADk#V!5FlrU|av>=^;!SM;0(#v7h>l zT`O{KyyVk+UO;N)oqMNdlZu+Yb<@MVV$P-A^-BKQ ze;lX&e71jAc3a^Jw{^z6hZjw%+4;bKzGCDj6X&R7EAnn<_1uWteJfz9RJgQ>`>O=` zrg_RQ4o#gMqI*+SqO&v4s;AQ=Snaj=pRJ)A_UC_+f2$E + + + +jQuery plugin: Tablesorter 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +

    + Original Author: Christian Bach
    + Maintainer of this fork: Rob Garrison (Mottie)
    + Version: 2.1+ (changelog)  + + +
    + Licence: + Dual licensed under MIT + or GPL licenses.
    +

    + + +

    Contents

    +
      +
    1. Introduction
    2. +
    3. Demo
    4. +
    5. Getting started
    6. +
    7. Examples
    8. +
    9. Configuration
    10. +
    11. Widget & Pager Options (v2.1)
    12. +
    13. Methods
    14. +
    15. Events
    16. +
    17. API
    18. +
    19. Download
    20. +
    21. Compatibility
    22. +
    23. Support
    24. +
    25. Credits
    26. +
    + + +

    Introduction

    +

    + tablesorter is a jQuery plugin for turning a + standard HTML table with THEAD and TBODY tags into a sortable table without page refreshes. + tablesorter can successfully parse and sort many types of data including linked data in a cell. + It has many useful features including: +

    + +

      +
    • Multi-column sorting
    • +
    • Multi-tbody sorting - see the options table below
    • +
    • Parsers for sorting text, URIs, integers, currency, floats, IP addresses, dates (ISO, long and short formats), time. Add your own easily
    • +
    • Support secondary "hidden" sorting (e.g., maintain alphabetical sort when sorting on other criteria)
    • +
    • Extensibility via widget system
    • +
    • Cross-browser: IE 6.0+, FF 2+, Safari 2.0+, Opera 9.0+
    • +
    • Works with jQuery 1.2.6+ (jQuery 1.4.1+ needed with some widgets).
    • +
    • Works with jQuery 1.9+ ($.browser.msie was removed; needed in the original version).
    • +
    • Small code size
    • +
    + + +

    Demo

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Account #First NameLast NameAgeTotalDiscountDifferenceDate
    A42bPeterParker28$9.9920.9%+12.1Jul 6, 2006 8:14 AM
    A255BruceJones33$13.1925%+12Dec 10, 2002 5:14 AM
    A33ClarkEvans18$15.8944%-26Jan 12, 2003 11:14 AM
    A1BruceAlmighty45$153.1944.7%+77Jan 18, 2001 9:12 AM
    A102BruceEvans22$13.1911%-100.9Jan 18, 2007 9:12 AM
    A42aBruceEvans22$13.1911%0Jan 18, 2007 9:12 AM
    + +

    + TIP! Sort multiple columns simultaneously by holding down the Shift key and clicking a second, third or even fourth column header! +

    + + +

    Getting started

    +

    + To use the tablesorter plugin, include the jQuery + library and the tablesorter plugin inside the <head> tag + of your HTML document: +

    + +

    <!-- choose a theme file -->
    +<link rel="stylesheet" href="/path/to/theme.default.css">
    +<!-- load jQuery and tablesorter scripts -->
    +<script type="text/javascript" src="/path/to/jquery-latest.js"></script>
    +<script type="text/javascript" src="/path/to/jquery.tablesorter.js"></script>
    +
    +<!-- tablesorter widgets (optional) -->
    +<script type="text/javascript" src="/path/to/jquery.tablesorter.widgets.js"></script>
    +
    + +

    tablesorter works on standard HTML tables. You must include THEAD and TBODY tags:

    + +

    <table id="myTable" class="tablesorter">
    +  <thead>
    +    <tr>
    +      <th>Last Name</th>
    +      <th>First Name</th>
    +      <th>Email</th>
    +      <th>Due</th>
    +      <th>Web Site</th>
    +    </tr>
    +  </thead>
    +  <tbody>
    +    <tr>
    +      <td>Smith</td>
    +      <td>John</td>
    +      <td>jsmith@gmail.com</td>
    +      <td>$50.00</td>
    +      <td>http://www.jsmith.com</td>
    +    </tr>
    +    <tr>
    +      <td>Bach</td>
    +      <td>Frank</td>
    +      <td>fbach@yahoo.com</td>
    +      <td>$50.00</td>
    +      <td>http://www.frank.com</td>
    +    </tr>
    +    <tr>
    +      <td>Doe</td>
    +      <td>Jason</td>
    +      <td>jdoe@hotmail.com</td>
    +      <td>$100.00</td>
    +      <td>http://www.jdoe.com</td>
    +    </tr>
    +    <tr>
    +      <td>Conway</td>
    +      <td>Tim</td>
    +      <td>tconway@earthlink.net</td>
    +      <td>$50.00</td>
    +      <td>http://www.timconway.com</td>
    +    </tr>
    +  </tbody>
    +</table>
    + +

    Start by telling tablesorter to sort your table when the document is loaded:

    + +

    $(function(){
    +  $("#myTable").tablesorter();
    +});
    + +

    + Click on the headers and you'll see that your table is now sortable! You can + also pass in configuration options when you initialize the table. This tells + tablesorter to sort on the first and second column in ascending order. +

    + +

    $(function(){
    +  $("#myTable").tablesorter({ sortList: [[0,0], [1,0]] });
    +});
    + +

    + NOTE! tablesorter will auto-detect most data types including numbers, dates, ip-adresses for more information see Examples +

    + + +

    Examples

    +

    + These examples will show what's possible with tablesorter. You need Javascript enabled to + run these samples, just like you and your users will need Javascript enabled to use tablesorter. +

    + +

    +

    Basic

    +

    Sorting

    + + +

    Theming

    + +

    + +

    Using Parsers / Extracting Content

    + + +
    +

    Advanced

    + +

    Parsers / Extracting Content

    + + +

    Widgets / Plugins

    + + +

    Adding / Removing Content

    + + +

    Change Header Style

    + + +
    +

    Other

    + +

    Options & Events

    + + +

    Metadata - setting inline options

    + + +
    + +
    + +

    Demos

    + +

    Playgrounds & Other demos

    + + +

    Plugins / Widgets
    + these widgets are included in the jquery.tablesorter.widgets.js file (except for extra filter formatter functions) +
    + this widget is included with the plugin core. +

    + + + +

    Custom Parsers

    + + +

    Work-in-progress

    + + +
    +
    + + +

    Configuration

    + +
    +

    + tablesorter has many options you can pass in at initialization to achieve different effects
    + TIP! Click on the link in the property column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PropertyTypeDefaultDescriptionLink
    PropertyTypeDefaultDescriptionLink
    cancelSelectionBooleantrueIndicates if tablesorter should disable selection of text in the table header (TH). Makes header behave more like a button.
    String"checked"Used by the "checkbox" parser in the parser-input-select.js file (v2.22.2). +
    +

    When using the checkbox parser, this class name is added to the row along with this class name plus the column index when the targeted checkbox is checked.

    +

    For example, if the named parser file has been loaded & "sorter-checkbox" class is added to the first column header, then any checked checkbox in the first column will have "checked checked-0" class names added to the row.

    + Checkboxes in any other column, not targeted by the parser, will be ignored and no extra row class names will be added. +
    +
    Example
    String""Additional CSS class applied to style the header with a ascending sort (v2.11). +

    + Changed to empty string ("") in v2.11, as the "tablesorter-headerAsc" class will always be added to a header cell with an ascending sort; this option now contains any additional class names to add. + +

    Example from the blue theme:

    +
    .tablesorter-blue .tablesorter-headerAsc {
    +  background-color: #9fbfdf;
    +  background-image: url(black-asc.gif);
    +}
    + Default changed v2.5 to "tablesorter-headerAsc". Default changed v2.1.7 to "tablesorter-headerSortUp". Original default: "headerSortUp"
    +
    cssChildRowString"tablesorter-childRow"Add this css class to a child row that should always be attached to its parent. Click on the "cssChildRow" link to toggle the view on the attached child row. Previous default was "expand-child" (Modified v2.4). + 1 + 2 +
    This is an entirely new row, but attached to the row above while sorting
    + cssChildRow Example HTML: +
    <table width="100%" border="1">
    +  <thead>
    +    <tr>
    +      <th>Item #</th>
    +      <th>Name</th>
    +      <th>Available</th>
    +    </tr>
    +  </thead>
    +  <tbody>
    +    <tr>
    +      <td>12345</td>
    +      <td>Toy Car</td>
    +      <td>5</td>
    +    </tr>
    +    <tr class="tablesorter-childRow"> <!-- this row will remain attached to the above row, and not sort separately -->
    +      <td colspan="3">
    +        It's a toy car!
    +      </td>
    +    </tr>
    +    <tr>
    +      <td>23456</td>
    +      <td>Toy Plane</td>
    +      <td>2</td>
    +    </tr>
    +    <tr class="tablesorter-childRow"> <!-- this row will remain attached to the above row, and not sort separately -->
    +      <td colspan="3">
    +        It's a toy plane!
    +      </td>
    +    </tr>
    +    <tr class="tablesorter-childRow"> <!-- this row will remain attached to the above two rows, and not sort separately -->
    +      <td colspan="3">
    +        and it flies!
    +      </td>
    +    </tr>
    +  </tbody>
    +</table>
    +
    String""Additional CSS class applied to style the header with a descending sort (v2.11). +

    + Changed to empty string in v2.11, as the "tablesorter-headerDesc" class will always be added to a header cell with a descending sort; this option now contains any additional class names to add. +

    Example from the blue theme:

    +
    .tablesorter-blue .tablesorter-headerDesc {
    +  background-color: #8cb3d9;
    +  background-image: url(black-desc.gif);
    +}
    + Default changed v2.5 to "tablesorter-headerDesc". Default changed v2.1.7 to "tablesorter-headerSortDown". Original default: "headerSortDown"
    +
    String""Additional CSS class applied to style the headers (v2.11). +

    + Changed to empty string in v2.11, as the "tablesorter-header" class will always be added to the table headers; this option now contains any additional class names to add. +

    Example from the blue theme:

    +
    .tablesorter-blue .tablesorter-header {
    +  background-color: #99bfe6;
    +  background-repeat: no-repeat;
    +  background-position: center right;
    +  padding: 4px 20px 4px 4px;
    +  white-space: normal;
    +  cursor: pointer;
    +}
    + Default changed v2.1.7 to "tablesorter-header". Original default: "header"
    +
    String""Additional CSS class applied to style the header row (v2.11). +

    + Changed to empty string in v2.11, as the "tablesorter-headerRow" class will always be added to a table header row; this option now contains any additional class names to add.
    +

    This CSS style was added in v2.4, prior to that the row would get the same class as the header cells. This class was added to make it easier to determine what element was being targeted in the plugin.

    +
    +
    String"tablesorter-icon"The CSS style used to style the header cell icon (modified v2.7; v2.21.1). +

    + In v2.21.1, adding multiple class names to this option is now properly supported.
    +
    + As of v2.7, the icon will only be added to the header if both the cssIcon option is set AND the headerTemplate option includes the icon tag ({icon}).
    +
    + In v2.4, an <i> element, with this class name, is automatically appended to the header cells. To prevent the plugin from adding an <i> element to the headers, set the cssIcon option to an empty string.
    +
    +
    String""The CSS style added to the header cell icon when the column has an ascending sort (v2.18.3). +

    + This class is only applied when the headerTemplate option includes a {icon} tag or an HTML element with the class name from the cssIcon option. +
    +
    String""The CSS style used to style the header cell icon when the column has a descending sort (v2.18.3) +

    + This class is only applied when the headerTemplate option includes a {icon} tag or an HTML element with the class name from the cssIcon option. +
    +
    String""The CSS style used to style the header cell icon when the column does not have a sort applied (v2.18.3) +

    + This class is only applied when the headerTemplate option includes a {icon} tag or an HTML element with the class name from the cssIcon option. +
    +
    String""Additional CSS class applied to style the header when no sort is applied (v2.15). +

    + A "tablesorter-headerUnSorted" class will always be added to an unsorted header cell; this option contains any additional class names to add. Currently, no themes use this class name. +
    +
    String""Additional CSS class applied to style the header cell while it is being sorted or filtered (v2.4; v2.11). +

    + Changed to empty string in v2.11, as the "tablesorter-processing" class will always be added to a table cells during processing; this option now contains any additional class names to add.
    +

    This class name is added to the header cell that is currently being sorted or filted. To prevent this class name from being added, set the showProcessing option to false.

    +
    +
    String"tablesorter-infoOnly"All tbodies with this class name will not have its contents sorted. (v2.2). +
    +
    + With the addition of multiple tbody sorting in v2.2, you can now insert a non-sorting tbody within the table by adding this class to the tbody. +
    <tbody class="tablesorter-infoOnly">
    +  <tr>
    +    <th>The contents of this tbody</th>
    +  </tr>
    +  <tr>
    +    <td>will not be sorted</td>
    +  </tr>
    +</tbody>
    + As an example, I've split up this options table into three (3) tbodies. The first contains the active options, the second is the info block with a row that only contains the text "Deprecated Options", and the last tbody contains the deprecated options. Sort the table to see how each tbody sorts separately. +
    +

    + NOTE! The pager plugin will only be applied to the first tbody, as always. I may work on modifying this behavior in the future, if I can figure out the best implementation. +

    +
    +
    cssNoSortString"tablesorter-noSort"Class name added to element inside header. Clicking on that element, or any elements within it won't cause a sort. (v2.20.0).
    String"tablesorter-ignoreRow"Class name to add to a table header row if you want all cells within this row to be ignored (v2.18.4). +
    +
    + Header rows with this class name will not be added into the table.config.$headers variable.
    +
    + This class name should be added to header rows that contain custom HTML, like for the pager controls, custom filter row or table toolbar. +
    +
    String"mmddyyyy"Set the date format. Here are the available options. (Modified v2.0.23). +
    +
      +
    • "mmddyyyy" (default)
    • +
    • "ddmmyyyy"
    • +
    • "yyyymmdd"
    • +
    + In previous versions, this option was set as "us", "uk" or "dd/mm/yy". This option was modified to better fit needed date formats. It will only work with four digit years!
    +
    + The sorter should be set to "shortDate" and the date format can be set in the "dateFormat" option or set for a specific columns within the "headers" option. + See the demo page to see it working. +
    $(function(){
    +  $("table").tablesorter({
    +
    +    dateFormat : "mmddyyyy", // default date format
    +
    +    // or to change the format for specific columns,
    +    // add the dateFormat to the headers option:
    +    headers: {
    +      0: { sorter: "shortDate" }, // "shortDate" with the default dateFormat above
    +      1: { sorter: "shortDate", dateFormat: "ddmmyyyy" }, // day first format
    +      2: { sorter: "shortDate", dateFormat: "yyyymmdd" }  // year first format
    +    }
    +
    +  });
    +});
    + Individual columns can be modified by adding the following (they all do the same thing), set in order of priority (Modified v2.3.1): +
      +
    • jQuery data data-dateFormat="mmddyyyy".
    • +
    • metadata class="{ dateFormat: 'mmddyyyy'}". This requires the metadata plugin.
    • +
    • headers option headers : { 0 : { dateFormat : 'mmddyyyy' } }.
    • +
    • header class name class="dateFormat-mmddyyyy".
    • +
    • Overall dateFormat option.
    • +
    +
    +
    Example
    debugBooleanfalse + Boolean flag indicating if tablesorter should display debuging information useful for development. + Example
    delayInitBooleanfalse + Setting this option to true will delay parsing of all table cell data until the user initializes a sort. This speeds up the initialization process of very large tables, but the data still needs to be parsed, so the delay is still present upon initial sort. + Example
    String"bottom" + Option indicating how tablesorter should deal with empty table cells. (Modified v2.1.16, v2.16.2). +
    +
      +
    • bottom - sort empty table cells to the bottom.
    • +
    • top - sort empty table cells to the top.
    • +
    • none or zero - sort empty table cells as if the cell has the value equal to zero.
    • +
    • emptyMax - sort empty table cells as having a value greater than the max (more positive) value (v2.16.2).
    • +
    • emptyMin - sort empty table cells as having a value greater than the min (more negative) value (v2.16.2).
    • +
    + Individual columns can be modified by adding the following (they all do the same thing), set in order of priority: +
      +
    • jQuery data data-empty="top".
    • +
    • metadata class="{ empty: 'top'}". This requires the metadata plugin.
    • +
    • headers option headers : { 0 : { empty : 'top' } }.
    • +
    • header class name class="empty-top".
    • +
    • Overall emptyTo option.
    • +
    + emptyToBottom option was added in v2.1.11, then replaced by the emptyTo option in v2.1.16. +
    +
    Example
    Objectnull + An object of instructions for per-"header cell" controls in the format: headers: { 0: { option: setting }, ... } + (v2.17.1) +
    +
    + For example, to disable sorting on the first two columns of a table: headers: { 0: { sorter: false}, 1: {sorter: false} }.
    +
    + The plugin attempts to detect the type of data that is contained in a column, but if it can't figure it out then it defaults to alphanumeric. You can easily override this by setting the header argument (or column parser). + See the full list of default parsers here or write your own. +
    $(function(){
    +  $("table").tablesorter({
    +    headers: {
    +
    +      // See example - Disable first header cell; parser false skips extracting content
    +      0: { sorter: false, parser: false },
    +
    +      // See example 2: Sort column numerically & treat any text as if its value is:
    +      1: { sorter: "digit", empty:  "top" }, // zero; sort empty cells to the top
    +      2: { sorter: "digit", string: "max" }, // maximum positive value
    +      3: { sorter: "digit", string: "min" }, // maximum negative value
    +
    +      // Sort the fifth column by date & set the format
    +      4: { sorter: "shortDate", dateFormat: "yyyymmdd" }, // year first format
    +
    +      // See example 3: lock the sort order
    +      // this option will not work if added as metadata
    +      5: { lockedOrder: "asc" },
    +
    +      // See Example 4: Initial sort order direction of seventh header cell
    +      6: { sortInitialOrder: "desc" },
    +
    +      // Set filter widget options for this column
    +      // See the "Applying the filter widget" demo
    +      7: { filter: false },    // disable filter widget for this column
    +      8: { filter: "parsed" }, // use parsed data for this column in the filter search
    +
    +      // Set resizable widget options for this column
    +      9: { resizable: false } // prevent resizing of header cell 9
    +
    +    }
    +  });
    +});
    + Please note that the headers index values corresponds to the table header cells index (zero-based) and not the actual columns. For example, given the following table thead markup, the header-index counts the header th cells and does not actually match the data-column index when extra rows and/or colspan or rowspan are included in any of the header cells: +
    <thead>
    +	<tr>
    +		<th colspan="4" data-column="0">header-index 0</th>
    +	</tr>
    +	<tr>
    +		<th data-column="0">header-index 1</th>
    +		<th data-column="1">header-index 2</th>
    +		<th data-column="2">header-index 3</th>
    +		<th data-column="3">header-index 4</th>
    +	</tr>
    +	<tr>
    +		<th colspan="2" data-column="0">header-index 5</th>
    +		<th colspan="2" data-column="2">header-index 6</th>
    +	</tr>
    +</thead>
    + So, in the above example, to disable the sort of the second table column (data-column index of 1), the header cell of index 2 needs to be set as follows: 2 : { sorter : false }.
    +
    + In v2.17.0, you can reference the column(s) using a class name, id or column index. +
    headers : {
    +    '.first-name' : { sorter: 'text' },
    +    '.disabled'   : { sorter: false }
    +}
    + Warning What won't work is if you try to target the header using a filtering selector that uses an index, e.g. "th:eq()", ":gt()", ":lt()", ":first", ":last", ":even" or ":odd", ":first-child", ":last-child", ":nth-child()", ":nth-last-child()", etc. +
    +
    + 1 + 2 + 3 + 4 + 5 +
    String"{content}"This is a template string which allows adding additional content to the header while it is being built (v2.7; v2.17.8). +

    + In v2.17.8, if this option is set to an empty string (''), an inner div will no longer be wrapped around the header content.
    +
    + This template string has two modifying tags: {content} and {icon}.
    + {content} will be replaced by the current header HTML content.
    + {icon} will be replaced by <i class="tablesorter-icon"></i>, but only if a class name is defined in the cssIcon option.
    +
    + This template string may also contain HTML, e.g ('<em>{content}</em> {icon}')
    +
    + After the template string is built, the onRenderTemplate function is called to allow further manipulation. Please read more about this onRenderTemplate function and/or check out the example (link to the right). +
    +
    Example
    ignoreCaseBooleantrueWhen true, text sorting will ignore the character case. If false, upper case characters will sort before lower case. (v2.2).
    String"alt" + Used by the image parser to grab the image attribute content (v2.17.5; moved to tablesorter core in v2.18.0; see config.parsers). +

    + Change this setting to grab a different image attribute to be used for sorting: +
    $(function(){
    +  $('table').tablesorter({
    +    // parse image title (value to be used while sorting & filtering)
    +    imgAttr : 'title',
    +    headers : {
    +      0 : { sorter: 'image' } // this parser is auto-detected, but will only work on the first image
    +    }
    +  });
    +});
    +
    +
    FunctionnullThis callback fires when tablesorter has completed initialization. (v2.2). +
    +
    $(function(){
    +
    +  // bind to tablesorter-initialized event BEFORE initializing tablesorter*
    +  $("table")
    +    .bind("tablesorter-initialized",function(e, table) {
    +      // do something after tablesorter has initialized
    +    });
    +
    +  // initialize the tablesorter plugin
    +  $("table").tablesorter({
    +    // this is equivalent to the above bind method
    +    initialized : function(table){
    +      // do something after tablesorter has initialized
    +    }
    +  });
    +
    +});
    * Note: bind to all initialization events before initializing tablesorter; because most of the time, if bound after, the events will fire before the binding occurs.
    +
    BooleantrueApply widgets after table initializes (v2.3.5). +
    + When true, all widgets set by the widgets option will apply after tablesorter has initialized, this is the normal behavior.
    +
    + If false, the each widget set by the widgets option will be initialized, meaning the "init" function is run, but the format function will not be run. This is useful when running the pager plugin after the table is set up. The pager plugin will initialize, then apply all set widgets.
    +
    + Why you ask? Well, lets say you have a table with 1000 rows that will have the pager plugin applied to it. Before this option, the table would finish its setup, all widgets would be applied to the 1000 rows, pager plugin initializes and reapplies the widgets on the say 20 rows showing; making the widget application to 100 rows unnecessary and a waste of time. So, when this option is false, widgets will only be applied to the table after the pager is set up. +
    +
    String'widget-{name}'When the table has a class name that matches the template and a widget id that matches the {name}, the widget will automatically be added to the table (v2.18.0) +
    +
    + By default, this option is set to 'widget-{name}'. So if the table has a class name of widget-zebra the zebra widget will be automatically added to the config.widgets option and applied to the table.
    +
    + Some widget ID's with special characters may not be detected; ID's with letters, numbers, underscores and/or dashes will be correctly detected.
    +
    + The template string *must* contain the {name} tag. +
    +
    Functionnull + This function is called after content is to the TH tags (after the template is procressed and added). You can use this to modify the HTML in each header tag for additional styling (v2.18.0). +
    +
    + In versions 2.0.6+, all TH text is wrapped in a div with a class name of "tablesorter-inner" by default. In the example below, the header cell (TH) div is given a class name (source).
    + Function parameters: +
      +
    • index - zero-based index of the current table header cell; this value is not indicative of the column index, as it is simply a count of header cells. So it will be effected by rowspan, colspan and multiple rows in the header.
    • +
    • config - The current table.config.
    • +
    • $table - This value is the current table jQuery object. If this function is being applied to cloned headers, as is does in the stickyHeaders widget, then this value will contain the sticky header clone added after the current table, and not the main table (v2.18.0).
    • +
    +
    $(function(){
    +  $("table").tablesorter({
    +    headerTemplate: '{content}',
    +    onRenderHeader: function (index, config, $table){
    +      $(this).find('div').addClass('roundedCorners');
    +    }
    +  });
    +});
    and you'll end up with this HTML (only the thead is shown)
    <thead>
    +  <tr>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner roundedCorners">Column 1</div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner roundedCorners">Column 2</div></th>
    +  </tr>
    +</thead>
    + * Note: this function adds additional rendering time to the table if any DOM manipulation is done. Because this time will be on top of the processing time already added by the template. +
    +
    Example
    Functionnull + This function is called after the template string has been built, but before the template string is applied to the header and before the onRenderHeader function is called (v2.7). +
    +
    + The onRenderTemplate function receives a column index and template string parameters. The template string, from the headerTemplate option, will already have the {icon} and {content} tags replaced; it's just a string of formatted HTML. When done manipulating this string, return it. Here is an example: +
    $(function(){
    +  $("table").tablesorter({
    +    headerTemplate: '{icon}{content}',
    +    onRenderTemplate: function (index, template){
    +      return '<em>' + (index + 1) + ':</em> ' + template;
    +    }
    +  });
    +});
    The template parameter can be manipulated as a string, or if you prefer, turn it into a jQuery object (var $t = $(template)) to find and replace content as desired. Just make sure you return a string (return $t.html())
    +
    +From the example function above, you'll end up with something similar to this HTML (only the thead is shown)
    <thead>
    +  <tr>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner"><em>1:</em> <i class="tablesorter-icon"></i>First Name</div></th>
    +    <th class="tablesorter-header"><div class="tablesorter-header-inner"><em>2:</em> <i class="tablesorter-icon"></i>Last Name</div></th>
    +  </tr>
    +</thead>
    + * Note: If the cssIcon option is an empty string, the {icon} tag will also become an empty string. +
    +
    Example
    String"> thead th, > thead td"jQuery selectors used to find cells in the header. +
    + You can change this, but the table will still need the required thead and tbody before this plugin will work properly. +
    Added > to the selector in v2.3 to prevent targeting nested table headers. It was modified again in v2.4 to include td cells within the thead. +
    +
    String"tr.remove-me"This CSS class name can be applied to all rows that are to be removed prior to triggering a table update. (v2.1). +
    +
    + It was necessary to add this option because some widgets add table rows for styling (see the writing custom widgets demo) and if a table update is triggered ($('table').trigger('update');) those added rows will automatically become incorporated into the table. +
    +
    selectorSortString"th, td"jQuery selector of content within selectorHeaders that is clickable to trigger a sort (v2.4).Example
    BooleantrueWhen this option is true any applied sort on the table will be reapplied after an update method (v2.19.0). +
    +
    + Specifically, this option applies to the "updateAll", "update", "addRows" and "updateCell" methods and is checked after the method has completed updating the internal cache.
    +
    + If false, the widgets will still be refreshed for all but the "updateCell" method - this "updateCell" behavior was added in v2.19.0.
    +
    + Note when triggering one of the above methods, and passing a defined resort parameter, it will override this setting.
    +
    + Note if a sort is not reapplied, problems with some widgets may occur namely the grouping widget. +
    +
    serverSideSortingBooleanfalseSet to true if the server is performing the sorting. The ui and events will still be used (v2.5.3).
    showProcessingBooleanfalseShow an indeterminate timer icon in the header when the table is sorted or filtered. Please note that due to javascript processing, the icon may not show as being animated. I'm looking into this further and would appreciate any feedback or suggestions with the coding (v2.4).Example
    ArraynullUse to add an additional forced sort that is prepended to sortList. +
    +
    + For example, sortForce: [[0,0]] will sort the first column in ascending order. After the forced sort, the user selected column(s), or during initialzation, the sorting order defined in the sortList will follow. And lastly, the sort defined in the sortAppend option will be applied. More explicitly:
    +
    + There are three options to determine the sort order and this is the order of priority: +
      +
    1. sortForce forces the user to have this/these column(s) sorted first (null by default).
    2. +
    3. SortList is the initial sort order of the columns.
    4. +
    5. SortAppend is the default sort that is added to the end of the users sort selection (null by default).
    6. +
    + The value of these sort options is an array of arrays and can include one or more columns. The format is an array of instructions for per-column sorting and direction in the format: [[columnIndex, sortDirection], ... ] where columnIndex is a zero-based index for your columns left-to-right and sortDirection is 0 for Ascending and 1 for Descending. A valid argument that sorts ascending first by column 1 and then column 2 looks like: [[0,0],[1,0]]. +
    $(function(){
    +  $("table").tablesorter({
    +    sortForce  : [[0,0]],        // Always sort first column first
    +    sortList   : [[1,0], [2,0]], // initial sort columns (2nd and 3rd)
    +    sortAppend : [[3,0]]         // Always add this sort on the end (4th column)
    +  });
    +});
    +
    Example
    ArraynullUse to add an initial sort to the table. +
    +
    + The value contains an array of instructions for per-column sorting and direction in the format: [[columnIndex, sortDirection], ... ] where columnIndex is a zero-based index for your columns left-to-right and sortDirection is 0 for Ascending and 1 for Descending. A valid argument that sorts ascending first by column 1 and then column 2 looks like: [[0,0],[1,0]]. Please see sortForce for more details on other sort order options.
    +
    $(function(){
    +  $("table").tablesorter({
    +    sortList : [[1,0], [2,0]] // initial sort columns (2nd and 3rd)
    +  });
    +});
    + This option can also be set using data-attributes (v2.3.1), jQuery data or metadata on the table: + + + + + + + + +
    ** Note: data-sortlist data is not supported in jQuery versions older than 1.4.
    jQuery data<table data-sortlist="[[0,0],[4,0]]"> **
    Meta data<table class="tablesorter {sortlist: [[0,0],[4,0]]}">
    +
    +
    Example
    ArraynullUse to add an additional forced sort that will be appended to the dynamic selections by the user. +
    +
    + For example, can be used to sort people alphabetically after some other user-selected sort that results in rows with the same value like dates or money due. It can help prevent data from appearing as though it has a random secondary sort.
    +
    + The value contains an array of instructions for per-column sorting and direction in the format: [[columnIndex, sortDirection], ... ] where columnIndex is a zero-based index for your columns left-to-right and sortDirection is 0 for Ascending and 1 for Descending. A valid argument that sorts ascending first by column 1 and then column 2 looks like: [[0,0],[1,0]]. Please see sortForce for more details on other sort order options. +
    +
    Example
    String"asc" + This sets the direction a column will sort when clicking on the header for the first time. Valid arguments are "asc" for Ascending or "desc" for Descending.
    +
    +
    + This order can also be set by desired column using the headers option (v2.0.8).
    +
    + Individual columns can be modified by adding the following (they all do the same thing), set in order of priority (modified v2.3.1): +
      +
    • jQuery data data-sortInitialOrder="asc".
    • +
    • metadata class="{ sortInitialOrder: 'asc'}". This requires the metadata plugin.
    • +
    • headers option headers : { 0 : { sortInitialOrder : 'asc' } }.
    • +
    • header class name class="sortInitialOrder-asc".
    • +
    • Overall sortInitialOrder option.
    • +
    +
    +
    + 1 + 2 +
    Booleanfalse + Boolean flag indicating if certain accented characters within the table will be replaced with their equivalent characters. (Modified v2.2). +
    +
      +
    • This option no longer switches the sort to use the String.localeCompare method.
    • +
    • When this option is true, the text parsed from table cells will convert accented characters to their equivalent to allow the alphanumeric sort to properly sort.
    • +
    • If false (default), any accented characters are treated as their value in the standard unicode order.
    • +
    • The following characters are replaced for both upper and lower case (information obtained from sugar.js sorting equivalents table): +
        +
      • áàâãä replaced with a
      • +
      • ç replaced with c
      • +
      • éèêë replaced with e
      • +
      • íìİîï replaced with i
      • +
      • óòôõöō replaced with o
      • +
      • úùûü replaced with u
      • +
      • ß replaced with S
      • +
      +
    • +
    • Please see the example page for instrcutions on how to modify the above equivalency table.
    • +
    • If you would like to continue using the String.localeCompare method, then set the sortLocaleCompare option to false and use the new textSorter option as follows: +
      $('table').tablesorter({
      +  textSorter: function(a,b) {
      +    return a.localeCompare(b);
      +  }
      +});
    • +
    +

    + NOTE! See the Language wiki page for language specific examples and how to extend the character equivalent tables seen in the sortLocaleCompare demo. +

    + Boolean flag indicating whenever to use javascript String.localeCompare method or not.
    + This is only used when comparing text with international character strings. A sort using localeCompare will sort accented characters the same as their unaccented counterparts.
    +
    +
    Example
    Booleanfalse + Setting this option to true will allow you to click on the table header a third time to reset the sort direction. (v2.0.27). +
    +
    Don't confuse this option with the sortReset method. This option only resets the column sort after a third click, while the method immediately resets the entire table sort. +
    +
    Example
    sortResetKeyString"ctrlKey"The key used to reset sorting on the entire table. Defaults to the control key. The other options are "shiftKey" or "altKey" (reference).
    sortRestartBooleanfalse + Setting this option to true will start the sort with the sortInitialOrder when clicking on a previously unsorted column. (v2.0.31). + Example
    Booleanfalse + Setting this option to true and sorting two rows with exactly the same content, the original sort order is maintained (v2.14). +

    + This isn't exactly a stable sort because the sort order maintains the original unsorted order when sorting the column in an ascending direction. When sorting the column in a descending order, the opposite of the original unsorted order is returned. If that doesn't make any sense, please refer to issue #419. +
    +
    sortMultiSortKeyString"shiftKey"The key used to select more than one column for multi-column sorting. Defaults to the Shift key. The other options are "ctrlKey" or "altKey" (reference).Example
    String"max" + A key word indicating how tablesorter should deal with text inside of numerically sorted columns. (v2.1.16). +

    + String options was initially set in the header options only. Overall option added and values changed in version 2.1.16; setting the value to: +
      +
    • "max" will treat any text in that column as a value greater than the max (more positive) value. Renamed from "max+".
    • +
    • "min" will treat any text in that column as a value greater than the min (more negative) value. Renamed from "max-".
    • +
    • "top" will always sort the text to the top of the column.
    • +
    • "bottom" will always sort the text to the bottom of the column.
    • +
    • "none" or "zero" will treat the text as if it has a value of zero.
    • +
    + Individual columns can be modified by adding the following (they all do the same thing), set in order of priority: +
      +
    • jQuery data data-string="top".
    • +
    • metadata class="{ string: 'top'}". This requires the metadata plugin.
    • +
    • headers option headers : { 0 : { string : 'top' } }.
    • +
    • header class name class="string-top".
    • +
    • Overall stringTo option.
    • +
    +
    +
    Example
    tabIndexBooleantrueAdd a tabindex to the headers for keyboard accessibility; this was previously always applied (v2.14).
    String""Additional CSS class applied to style the table (v2.11). +

    + Changed to empty string in v2.11, as the "tablesorter" class will always be added to the table; this option now contains any additional class names to add. +

    This class was required in the default markup in version 2.0.5. But in version 2.0.6, it was added as an option.

    + Modify this option if you are not using the default css, or if you are using a completely custom stylesheet. +
    +
    String"default"This option will add a theme css class name to the table "tablesorter-{theme}" for styling (v2.4; v2.18.0). +
    +
    When changing this theme option, make sure that the appropriate css theme file has also been loaded. Included theme files include: + see all themes
    + + +
    +

    uitheme widget

    +

    You will need to use the uitheme widget to extend the theme to apply css from jQuery UI, Bootstrap or other css libraries.

    +

    Modify a theme

    +

    If you want to modify the existing themes ("jui" and "bootstrap"), it can be done as follows:

    +

    Modify the class names by extending from the $.tablesorter.themes variable

    +

    Note there is no need to extend from the entire list of class names, just include the key:value pairs that are being changed:

    +
    // Extend a theme to modify any of the default class names
    +$.extend($.tablesorter.themes.jui, {
    +  // change default jQuery uitheme icons - find the full list of icons
    +  // here: http://jqueryui.com/themeroller/ (hover over them for their name)
    +  table      : 'ui-widget ui-widget-content ui-corner-all', // table classes
    +  header     : 'ui-widget-header ui-corner-all ui-state-default', // header classes
    +  footerRow  : '',
    +  footerCells: '',
    +  icons      : 'ui-icon', // icon class added to the <i> in the header
    +  sortNone   : 'ui-icon-carat-2-n-s',
    +  sortAsc    : 'ui-icon-carat-1-n',
    +  sortDesc   : 'ui-icon-carat-1-s',
    +  active     : 'ui-state-active', // applied when column is sorted
    +  hover      : 'ui-state-hover',  // hover class
    +  filterRow  : '',
    +  even       : 'ui-widget-content', // even row zebra striping
    +  odd        : 'ui-state-default'   // odd row zebra striping
    +});
    + +

    Custom theme

    + To add a new uitheme, define it as follows (replace "custom" with the name of your theme): +
    $.tablesorter.themes.custom = {
    +  table      : 'table',       // table classes
    +  header     : 'header',      // header classes
    +  footerRow  : '',
    +  footerCells: '',
    +  icons      : 'icon',        // icon class added to the <i> in the header
    +  sortNone   : 'sort-none',   // unsorted header
    +  sortAsc    : 'sort-asc',    // ascending sorted header
    +  sortDesc   : 'sort-desc',   // descending sorted header
    +  active     : 'sort-active', // applied when column is sorted
    +  hover      : 'hover',       // hover class
    +  filterRow  : 'filters',     // class added to the filter row
    +  even       : 'even',        // even row zebra striping
    +  odd        : 'odd'          // odd row zebra striping
    +}
    + Then use it by adding the name of your theme to the theme option: +
    $(function(){
    +  $("table").tablesorter({
    +    // set the new theme name from $.tablesorter.themes here
    +    theme   : 'custom',
    +    // add {icon} to template (if needed)
    +    headerTemplate: '{content}{icon}',
    +    // make sure to initialize uitheme widget
    +    widgets : ["uitheme"]
    +  });
    +});
    +
    +
    Example
    String"data-text"This data-attribute can be added to any tbody cell and can contains alternate cell text (v2.16.0). +
    +
    + This option contains the name of the data-attribute used by the textExtraction function. Add it to the cell(s) as follows: +
    <td data-text="1">First repository</td>
    + Note This option only works when the textExtraction option is set to "basic". +
    +
    Multiple*"basic"Defines which method is used to extract data from a table cell for sorting (v2.19.0) +
    +
    + * Note This option accepts multiple types (String, Object or Function); see below for further details. +

    + In v2.19.0, the code was further optimized. When set to "basic" (the default), the textExtraction code will check for data-attributes, otherwise, any other string value setting will skip the data-attribute value check; because of this change, there is a noticable lessening of initialization time in Internet Explorer. +

    + In v2.17.0, the textExtraction column can also be referenced by using a jQuery selector (e.g. class name, id or column index) that points to a table header cell.
    +
    textExtraction : {
    +    // 'jQuery thead cell selector' : function ( new method )
    +    '.styled' : function(node, table, cellIndex) {
    +        return $(node).find('strong').text();
    +    },
    +    // columnIndex : function ( original method )
    +    2 : function(node, table, cellIndex) {
    +        return $(node).find('img').attr('title');
    +    }
    +}
    + Warning What won't work is if you try to target the header using a filtering selector that uses an index, e.g. "th:eq()", ":gt()", ":lt()", ":first", ":last", ":even" or ":odd", ":first-child", ":last-child", ":nth-child()", ":nth-last-child()", etc.
    +
    + As of version 2.16.0, +
      +
    • The default text extraction method has been renamed and updated to get data from a data-attribute (set by the textAttribute option).
    • +
    • If you need to support older versions of IE, this may add a significant delay to the table initialization especially for large tables; in this case, set the textExtraction option to any name other than "basic".
    • +
    • Also, this option can now be set using a data-attribute named "data-text-extraction" on the table.
    • +
    + You can customize the text extraction by writing your own text extraction function "myTextExtraction" which you define like: +
    var myTextExtraction = function(node, table, cellIndex){
    +  // extract data from markup and return it
    +  // originally: return node.childNodes[0].childNodes[0].innerHTML;
    +  return $(node).find('selector').text();
    +}
    +$(function(){
    +  $("#myTable").tablesorter( { textExtraction: myTextExtraction } );
    +});
    + tablesorter will pass the current table cell object for you to parse and return. Thanks to Josh Nathanson for the examples; updated to a jQuery example by Rob G (Mottie). +

    Now if the text you are finding in the script above is say a number, then just include the headers sorter option to specify how to sort it. Also in this example, we will specify that the special textExtraction code is only needed for the second column (1 because we are using a zero-based index). All other columns will ignore this textExtraction function.

    +

    Added table and cellIndex variables to the textExtraction function in version 2.1.2 (this is not part of the original plugin).

    +
    $(function(){
    +  $("table").tablesorter({
    +    textExtraction: {
    +      1: function(node, table, cellIndex) {
    +           return $(node).find("span:last").text();
    +      }
    +    },
    +    headers: {
    +      1: { sorter : "digit" }
    +    }
    +  });
    +});
    + The built-in option is "basic" (modified v2.16.0) which is the equivalent of doing this inside of the textExtraction function: $(node).text();. +
    +
    Example
    Stringundefined + This option should contain a unique namespace for each table; it is used when binding to event listeners (v2.15.7). +
    +
    + Notes about this namespace option: +
      +
    • If a namesspace is not defined, a (hopefully) unique random namespace will be generated.
    • +
    • If defined, any "non-word" characters (anything not "a-z", "0-9" or "_") within the namespace will be removed.
    • +
    • Added or not, the namespace will be saved with a leading period (e.g. ".myuniquetableid")
    • +
    +
    $(function(){
    +  $("#mytable").tablesorter({
    +    // if table id = "mytable", this namespace is saved as ".mytable"
    +    namespace : $('#mytable')[0].id;
    +  });
    +});
    +
    +
    Functionnull + Replace the default number sorting algorithm with a custom one using this option (v2.12). +
    +
    + Here is an example: +
    $(function(){
    +  $("table").tablesorter({
    +    numberSorter : function(a, b, direction, maxColumnValue){
    +      // direction; true = ascending; false = descending
    +      // maxColumnValue = the maximum value of that column (ignoring its sign)
    +      return a - b;
    +    }
    +  });
    +});
    The direction parameter (boolean) is merely for informational purposes as the plugin automatically switches a and b depending on the sort direction ( i.e. there's no need to worry about reverse sorting, it's taken care of by the plugin ). +
    +
    String"click"Use this option to change the click event (v2.22.0) +
    +

    Change this option if want to change the click event that is bound to the table headers. Add multiple events separated by spaces.

    + Warning If this option is set to fire multiple events (e.g. 'mouseup pointerup'), sorting may be initialized twice in rapid succession and make it appear that nothing changed. +
    +
    String"mousedown"Use this option to change the pointer down event (v2.22.0) +
    +

    Change this option if you're using pointer events (or the pointer events polyfill). Add multiple events separated by spaces.

    + Warning If this option is set to fire multiple events (e.g. 'mousedown pointerdown'), sorting may be initialized twice in rapid succession and make it appear that nothing changed. +
    +
    String"mouseup"Use this option to change the pointer up event (v2.22.0) +
    +

    Change this option if you're using pointer events (or the pointer events polyfill). Add multiple events separated by spaces.

    + Warning If this option is set to fire multiple events (e.g. 'mouseup pointerup'), sorting may be initialized twice in rapid succession and make it appear that nothing changed. +
    +
    Functionnull + Replace the default sorting algorithm with a custom one using this option (v2.12) - *NOTE* The parameters have changed!!. +
    +
    + Include a script like naturalSort.js as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    textSorter : naturalSort
    +  });
    +});
    + or use the localeCompare sort +
    $(function(){
    +  $("table").tablesorter({
    +    // replace the OVERALL text sorter function
    +    textSorter: function(a, b, direction, columnIndex, table){
    +      // direction: true = ascending; false = descending
    +      // columnIndex: zero-based index of the current table column being sorted
    +      // table: table DOM element (access options by using table.config)
    +      return a.localeCompare(b);
    +    }
    +  });
    +});
    In v2.12, the textSorter option will now accept a text sorter per column: +
    $(function(){
    +  $("table").tablesorter({
    +    textSorter : {
    +      // replace INDIVIDUAL COLUMN text sorter functions
    +      0 : function(a, b, direction, columnIndex, table){
    +        // same as $.tablesorter.sortText (basic alphabetical sort)
    +        // direction: true = ascending; false = descending
    +        // columnIndex: zero-based index of the current table column being sorted
    +        // table: table DOM element (access options by using table.config)
    +        return a > b ? 1 : (a < b ? -1 : 0);
    +      },
    +      1 : $.tablesorter.sortText,    // same as the function in column 0 above (modified in v2.12)
    +      2 : $.tablesorter.sortNatural, // renamed v2.12 from $.tablesorter.sortText - performs natural sort
    +      3 : Array.AlphanumericSort     // alphanumeric sort from sugar (http://sugarjs.com/arrays#sorting)
    +    }
    +  });
    +});
    The direction parameter (boolean) is merely for informational purposes as the plugin automatically switches a and b depending on the sort direction ( i.e. there's no need to worry about reverse sorting, it's taken care of by the plugin ). +
    +
    + 1 + 2 +
    Booleantrue + Indicates how tablesorter should deal with a numerical format: (v2.1.3). +
    + + + + + + + + + + + +
    trueU.S.1,234,567.89
    falseGerman:
    French:
    1.234.567,89
    1 234 567,89
    +
    +
    Example
    widgetsArray[ ] (empty array) + Initialize widgets using this option ( e.g. widgets : ['zebra'], or custom widgets widgets: ['zebra', 'myCustomWidget'];, see this demo on how to write your own custom widget ). + Example
    Booleanfalse + Indicates if tablesorter should apply fixed percentage-based widths to the table columns (modified v2.4). +
    + Prior to v2.4, this option set pixel widths to added colgroups to fix the column widths. This is useful for the Pager companion. +
    + Requires the jQuery dimension plugin to work. This is now part of the jQuery core. +
    +
    Example
    Object{ } + In version 2.1, all widget options have been moved into this option. This is a move to store all widget specific options in one place so as not to polute the main table options. All current widgets have been modified to use this new option. (v2.1). +
    +
    + Previously documented widget options widgetZebra, widgetColumns and widgetUitheme will be retained for backwards compatibility.
    +
    + Use the widgetOptions option as follows, please note that each option is followed by a comma (except the last one): +
    $(function(){
    +  $("table").tablesorter({
    +
    +    // initialize a bunch of widgets (the order doesn't matter)
    +    widgets: ["zebra", "uitheme", "columns", "filter", "resizable", "stickyHeaders"],
    +
    +    widgetOptions: {
    +
    +      // *** columns widget ***
    +      // change the default column class names
    +      columns : [ "primary", "secondary", "tertiary" ],
    +      // include thead when adding class names
    +      columns_thead : true,
    +      // include tfoot when adding class names
    +      columns_tfoot : true,
    +
    +      // *** filter widget ***
    +      // jQuery selector string (or jQuery object) of external anyMatch filter
    +      // filter_anyMatch   : null, // THIS OPTION WAS REMOVED IN V2.15
    +      // Include child rows content in the search
    +      filter_childRows     : false,
    +      // filter child row content by column, if true; filter_childRows must also be true!
    +      filter_childByColumn : false,
    +      // show column filters
    +      filter_columnFilters : true,
    +      // extra css class name (string or array) added to the filter element (input or select)
    +      filter_cellFilter    : '',
    +      // css class applied to the filter row inputs/select
    +      filter_cssFilter     : '',
    +      // data attribute in the header cell that contains the default filter value
    +      filter_defaultAttrib : 'data-value',
    +      // add a default column filter type "~{query}" to make fuzzy searches default; "{q1} AND {q2}" to make all searches use a logical AND.
    +      filter_defaultFilter : {},
    +      // filters to exclude, per column
    +      filter_excludeFilter : {},
    +      // jQuery selector string (or jQuery object) of external search inputs
    +      filter_external      : '',
    +      // class added to filtered rows; needed by pager plugin
    +      filter_filteredRow   : 'filtered',
    +      // add custom filter elements to the filter row
    +      filter_formatter     : null,
    +      // add custom filter functions using this option.
    +      filter_functions     : null,
    +      // hide filter row when table is empty
    +      filter_hideEmpty     : true,
    +      // if true, the filter row is hidden initially until hovered/focused.
    +      filter_hideFilters   : false,
    +      // if true, make all searches case-insensitive.
    +      filter_ignoreCase    : true,
    +      // if true, search column content while the user types (with a delay)
    +      filter_liveSearch    : true,
    +      // a selector in a header with this class name will only show selected options in the drop down
    +      filter_onlyAvail     : 'filter-onlyAvail',
    +      // default placeholder text (overridden by any header "data-placeholder" setting)
    +      filter_placeholder   : { search : '', select : '' },
    +      // jQuery selector string of an element used to reset the filters.
    +      filter_reset         : null,
    +      // Use the $.tablesorter.storage utility to save the most recent filters
    +      filter_saveFilters   : false,
    +      // typing delay in milliseconds before starting a search.
    +      filter_searchDelay   : 300,
    +      // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true
    +      filter_searchFiltered: true,
    +      // include a function to return an array of values to be added to the column filter select
    +      filter_selectSource  : null,
    +      // filter_selectSource array text left of the separator is added to the option value, right into the option text
    +      filter_selectSourceSeparator : '|',
    +      // if true, filter start from the beginning of the cell contents.
    +      filter_startsWith    : false,
    +      // filter all data using parsed content.
    +      filter_useParsedData : false,
    +      // Set to true for server-side filtering
    +      filter_serversideFiltering :  false,
    +
    +      // *** resizable widget ***
    +      // if false, resized columns are not saved for next page reload
    +      resizable : true,
    +      // if true, the last column will be resizable (use in non-full width tables)
    +      resizable_addLastColumn: false,
    +      // Add the starting & reset header widths
    +      resizable_widths : [],
    +      // throttle resizable event (needed for slow browsers)
    +      resizable_throttle : false,
    +      // target the last column for resize (like holding shift-drag)
    +      resizable_targetLast: false,
    +
    +      // *** savesort widget ***
    +      // if false, the sort will not be saved for next page reload
    +      saveSort : true,
    +
    +      // *** stickyHeaders widget ***
    +      // extra class name added to the sticky header row
    +      stickyHeaders : '',
    +      // jQuery selector or object to attach sticky header to
    +      stickyHeaders_attachTo : null,
    +      // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
    +      stickyHeaders_xScroll : null,
    +      // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
    +      stickyHeaders_yScroll : null,
    +      // number or jquery selector targeting the position:fixed element
    +      stickyHeaders_offset : 0,
    +      // scroll table top into view after filtering
    +      stickyHeaders_filteredToTop: true,
    +      // added to table ID, if it exists
    +      stickyHeaders_cloneId : '-sticky',
    +      // trigger "resize" event on headers
    +      stickyHeaders_addResizeEvent : true,
    +      // if false and a caption exist, it won't be included in the sticky header
    +      stickyHeaders_includeCaption : true,
    +      // The zIndex of the stickyHeaders, allows the user to adjust this to their needs
    +      stickyHeaders_zIndex : 2,
    +
    +      // *** storage widget ***
    +      // allows switching between using local & session storage
    +      storage_useSessionStorage : false,
    +      // alternate table id (set if grouping multiple tables together)
    +      storage_tableId  : '',
    +      // table attribute to get the table ID, if storage_tableId is undefined
    +      storage_group    : '', // defaults to "data-table-group"
    +      // alternate url to use (set if grouping tables across multiple pages)
    +      storage_fixedUrl : '',
    +      // table attribute to get the fixedUrl, if storage_fixedUrl is undefined
    +      storage_page     : '',
    +
    +      // *** zebra widget ***
    +      // class names to add to alternating rows
    +      zebra : ["even", "odd"]
    +
    +      // *** uitheme widget ***
    +      // use "config.theme" to set the theme to use
    +
    +    }
    +
    +  });
    +});
    +
    Example
    Utility Options
    dataObject, ArrayundefinedStorage for processed table build widget data (array, object, string) (v2.11).Example
    dateRangeNumeric50 + Used by the two digit year parser to set the date range (v2.14).Example
    Deprecated/Removed Options
    Stringundefined + This option is being deprecated in v2.21.3! + It has been replaced by widgetOptions.storage_fixedUrl; but is still available for backwards compatibility. +

    + This option was added to set a specific page when storing data using the $.tablesorter.storage code (v2.12). +
    + More specifically, when the storage function is used, it attempts to give every table a unique identifier using both the page url and table ID (or index on the page if no id exists). This option allows you to override the current page url (it doesn't need to be a url, just some constant value) and save data for multiple tables across a domain.
    +
    + The table url & id can also be overridden by setting table data attributes data-table-page (url) and data-table-group (id)
    (e.g. <table class="tablesorter" data-table-page="mydomain" data-table-group="financial">...</table>)
    +
    + For a bit more detail, specifically on how to use the new storage function options for a custom widget, please refer to issue #389. +
    +
    StringThis option was removed! + It has been replaced by cssNoSort which does the opposite of what this class name was supposed to do. +
    +

    This option was not working as intended, so it was completely removed - sorry for the lack of notice.

    +

    Previous default was "tablesorter-allowClicks"

    + Class name added to table header which allows clicks to bubble up. (added v2.18.1; removed in v2.20.0). +
    +
    + This option was removed in v2.21.2! + It has been replaced by widgetOptions.columns. +
    +
    + Default value: { css: [ "primary", "secondary", "tertiary" ] } (Object with Array) +

    + When the column styling widget is initialized, it automatically applied the default class names of "primary" for the primary sort, "secondary" for the next sort, "tertiary" for the next sort, and so on (add more as needed)... (v2.0.17). + Use the widgetColumns option to change the css class name as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["columns"], // initialize column styling of the table
    +    widgetColumns: { css: ["primary", "secondary", "tertiary" ] }
    +  });
    +});
    +
    + This option was removed in v2.4! + It has been replaced by widgetOptions.uitheme. +
    +
    + Default value: { css: [ "ui-icon-arrowthick-2-n-s", "ui-icon-arrowthick-1-s", "ui-icon-arrowthick-1-n" ] } (Object with Array) +

    + Used when the ui theme styling widget is initialized. It automatically applies the default class names of "ui-icon-arrowthick-2-n-s" for the unsorted column, "ui-icon-arrowthick-1-s" for the descending sort and "ui-icon-arrowthick-1-n" for the ascending sort. (v2.0.9). + Find more jQuery UI class names by hovering over the Framework icons on this page: http://jqueryui.com/themeroller/
    +
    + Use the widgetUitheme option to change the css class name as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["uitheme"], // initialize ui theme styling widget of the table
    +    widgetUitheme: {
    +      css: [
    +        "ui-icon-carat-2-n-s", // Unsorted icon
    +        "ui-icon-carat-1-s",   // Sort up (down arrow)
    +        "ui-icon-carat-1-n"    // Sort down (up arrow)
    +      ]
    +    }
    +  });
    +});
    +
    + This option was removed in v2.4! + It has been replaced by widgetOptions.zebra. +
    +
    + Default value: { css: [ "even", "odd" ] } (Object with Array) +

    + When the zebra striping widget is initialized, it automatically applied the default class names of "even" and "odd". + Use the widgetZebra option to change the css class name as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["zebra"], // initialize zebra striping of the table
    +    widgetZebra: { css: [ "normal-row", "alt-row" ] }
    +  });
    +});
    +
    + + +

    Widget & Pager Options

    + + + + + + + + + + + + + + + + +
    Widget PriorityNameRequires jQueryLimiting function
    30columnsv1.2.6
    50filterv1.4.31.4.3 (nextUntil & delegate)
    Lastpager pluginv1.2.6
    55pager widgetv1.71.7 (on)
    40resizablev1.4.1*1.4 (isEmptyObject); 1.4.1 (parseJSON)*
    20saveSortv1.4.11.4.1 (parseJSON)*
    60stickyHeadersv1.4.31.4.3 (isWindow)**
    10uithemev1.2.6
    90zebrav1.2.6
    + +
    +

    + tablesorter widgets have many options, and to better organize them, they now are grouped together inside of the widgetOptions. Thanks to thezoggy for putting together this jQuery-widget compatibility table, but please note: +
      +
    • The applied order of widget is dependent of the widget priority, from low to high.
    • +
    • Widget priority values do not need to be unique. Any new widget without a defined priority will automatically have a priority of 10.
    • +
    • The pager, being a plugin, is actually initialized after tablesorter has initialized and all selected widgets applied.
    • +
    • * The saveSort and resizable widgets use the $.tablesorter.storage function by default and thus need the parseJSON function which is available in jQuery 1.4.1+.
    • +
    • ** The stickyHeaders widget was updated in v2.18.0 to use $.isWindow for the xScroll & yScroll options; and therefore now requires jQuery 1.4.3+.
    • +
    + +
    + TIP! Click on the link in the property column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PropertyTypeDefaultDescriptionLink
    PropertyTypeDefaultDescriptionLink
    Array[ "primary", "secondary", "tertiary" ] + Columns widget: When the column styling widget is initialized, it automatically applied the default class names of "primary" for the primary sort, "secondary" for the next sort, "tertiary" for the next sort, and so on (add more as needed)... (Modified v2.1). +
    +
    + Use the "columns" option to change the css class name as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["columns"], // initialize column styling of the table
    +    widgetOptions : {
    +      columns: [ "primary", "secondary", "tertiary" ]
    +    }
    +  });
    +});
    +
    Example
    Booleantrue + Columns widget: If true, the class names from the columns option will also be added to the table thead (v2.4). +
    +
    + Use the "columns_thead" option to add the column class names to the thead as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["columns"], // initialize column styling of the table
    +    widgetOptions : {
    +      columns_thead: true
    +    }
    +  });
    +});
    +
    Example
    Booleantrue + Columns widget: If true, the class names from the columns option will also be added to the table tfoot (v2.4). +
    +
    + Use the "columns_tfoot" option to add the column class names to the tfoot as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["columns"], // initialize column styling of the table
    +    widgetOptions : {
    +      columns_tfoot: true
    +    }
    +  });
    +});
    +
    Example
    Booleanfalse + Filter widget: If there are child rows in the table (rows with class name from "cssChildRow" option) and this option is true and a match is found anywhere in the child row, then it will make that row visible. + (Modified v2.1). +
    +

    *NOTE* When using this option, please be aware that all child row content will be obtained from each table cell using textContent, so none of the markup will be preserved. Also, carriage returns (<br>) will not be included. To account for the loss of white space, especially after carriage returns, please add an extra space to the end of the line. Using innerText, could have been an option for preserving the white space, but it is not standardized across all browsers (ref).

    + Use the filter_childRows option to include child row text as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_childRows : true
    +    }
    +  });
    +});
    +
    Booleanfalse + Filter widget: If true, queries will search child row content by column (v2.22.0). +
    +

    The filter_childRows option must also be true for this option to work.

    +

    If false, and the filter_childRows option is true, then queries in any column will search all child content, as before this option was added.

    +

    + Use the filter_childByColumn option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_childRows : true,
    +      filter_childByColumn : true
    +    }
    +  });
    +});
    +
    +
    Example
    Booleantrue + Filter widget: If true, a filter will be added to the top of each table column (v2.4). +
    +
    + Use the filter_columnFilters option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_columnFilters : true
    +    }
    +  });
    +});
    +
    String or Array""Filter widget: Additional CSS class applied to each filter cell (v2.18.0). +

    + When the filter row is built, each table cell (<td>) will get the class name from this option. +
      +
    • If this option is a plain string, all filter row cells will get the text applied as a class name.
    • +
    • If this option is an array, then each filter row cell will get the text from the associate array element applied as a class name.
    • +
    +

    Use the filter_cellFilter option to add an extra css class name as follows:

    +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      // css class applied to the table row containing the filters & the inputs within that row
    +      // or [ "filter-cell0", "filter-cell1", "filter-cell2", etc... ]
    +      filter_cellFilter : "tablesorter-filter-cell"
    +    }
    +  });
    +});
    Note The cells from this option are also contained within the config.$filters variable. +
    +
    Example
    String or Array""Filter widget: Additional CSS class applied to each filter (v2.15). +

    + As of v2.15, this option can also contain an array of class names that are to be applied to input filters.
    +
    + Changed to empty string in v2.11, as the "tablesorter-filter" class will always be added to the filter; this option now contains any additional class names to add. +

    Use the filter_cssFilter option to add an extra css class name as follows:

    +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      // css class applied to the table row containing the filters & the inputs within that row
    +      // or [ "filter0", "filter1", "filter2", etc... ]
    +      filter_cssFilter : "tablesorter-filter"
    +    }
    +  });
    +});
    +
    +
    Example
    Object{ } + Filter widget: Add a default filter type to a column (v2.17.8). +
    +
    + Warning If a column has a default filter set, the user will not be able to use other filters.
    +
    + Use the filter_defaultFilter option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +
    +      filter_defaultFilter : {
    +        // target a column by class name or column index (zero-based)
    +
    +        '.fuzzy' : '~{q}',
    +        2 : '{q}=',
    +
    +        // for default "anyMatches" use the column length as the index
    +        // e.g. if your table has 5 columns (0,1,2,3,4), then set the anyMatch column as 5.
    +        5 : '{q} or {q}' // any match column
    +      }
    +
    +    }
    +  });
    +});
    + Set up the column string as follows: +
      +
    • Add the desired filter type symbol along with {query} or {q} to maintain positioning
    • +
    • Symbols can be added to the beginning "~{query}" (default fuzzy search) or end "{q}=" (default exact search)
    • +
    • For symbols that separate queries, like "AND", "OR" or "-" (range): +
        +
      • Add one additional {q} tag.
      • +
      • For example, to add a default "OR" search, use "{q} OR {q}".
      • +
      • If the user enters "a b c d" the column will be filtered using "a OR b OR c OR d", so there is no need to add more {q} tags within the string; adding more will likely mess up the results.
      • +
      • If the user only enters "a", then the column will be filtered using "a OR a" so as not to cause other issues.
      • +
      +
    • +
    • Note It is not possible to set up a default filter search within a query. So the "wild" filter search will not work as intended (e.g. {q}* and {q}? are essentially the same as {q}.
    • +
    +
    +
    Example
    Object{ }Filter widget: Additional CSS class applied to each filter (v2.17.8). + Exclude a filter type(s) for a column. +
    +
    + Use the filter_excludeFilter option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +
    +      filter_excludeFilter : {
    +        // target a column by class name or column index (zero-based)
    +        '.title' : 'range',
    +
    +        // separate multiple filter types using spaces
    +        2 : 'range notMatch exact'
    +      }
    +
    +    }
    +  });
    +});
    + Exclusion names must be separated by a comma. Here is a full list of filter type names: +
      +
    • and - logical " AND " or && type filter.
    • +
    • exact - exact match (using " or =).
    • +
    • fuzzy - fuzzy match (~)
    • +
    • notMatch - not match (! or !=)
    • +
    • operators - comparison filters (< <= >= >)
    • +
    • range - range ( - or to )
    • +
    • regex - regex (/\d/)
    • +
    • wild - wild card matching (? for single characters, * for multiple characters not including spaces, or | or OR for a logical OR.
    • +
    +
    +
    String"" + Filter widget: jQuery selector string of inputs, outside of the table, to be used for searching table content (v2.15). +
    +
    + Set this option to be a jQuery selector string, or jQuery object, pointing to any external inputs that are to be used for searching the table.
    +
    + Use the filter_external option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_external : '.search'
    +    }
    +  });
    +});
    + These external inputs have one requirement, they must have a data-column="#", where the # targets the column (zero-based index), pointing to a specific column to search.
    +
    <input class="search" type="search" data-column="0" placeholder="Search first column">
    + If you want to search all columns, using the updated "any match" method, set the data column value to "all":
    +
    <input class="search" type="search" data-column="all" placeholder="Search entire table">
    + The updated any matching code will now automatically update all associated inputs with the latest search. +
    + This option replaces filter_anyMatch. +
    +
    Example
    filter_filteredRowString"filtered" + Filter widget: This is the class name applied to all rows that do not match the filter (hidden rows); used by pager plugin (v2.10). +
    Objectnull + Filter widget: This option allows you to add custom controls within the filter widget row (v2.7.7; v2.17.0).
    +
    +
    + In v2.17.0, the filter_formatter column can also be referenced by using a jQuery selector (e.g. class name or ID) that points to a table header cell.
    +
    filter_formatter : {
    +    ".col-value" : function($cell, indx){
    +      return $.tablesorter.filterFormatter.uiSpinner( $cell, indx, {
    +        ...
    +      });
    +    }
    +}
    + Warning What won't work is if you try to target the header using a filtering selector that uses an index, e.g. "th:eq()", ":gt()", ":lt()", ":first", ":last", ":even" or ":odd", ":first-child", ":last-child", ":nth-child()", ":nth-last-child()", etc.
    +
    + A new file has been included named "widget-filter-formatter-jui.js" & "widget-filter-formatter-html5.js". The files include code to add jQuery UI and HTML5 controls via the filter_formatter option.
    +
    + Most of the formatter functions have an option named valueToHeader which, when true adds a span to the header cell above the filter row and updates it with the current control's value (see example 2). If the option exists and is set to false, then the current value is added to the control's handle and css can be used to create a popup to show the current value (see example 1).
    +
    + Another custom option named addToggle is included with the "uiSpinner", "html5Color" and "html5Number" code. This allows the user to disable the control to show all table rows. For the single sliders, "uiSlider" and "html5Range", the minimum value is used to clear the filter (show all rows).
    +
    + The options included for each jQuery UI control only show basic options, but any or all of the jQuery UI options for that control can be included.
    +
      +
    • + To add the jQuery UI slider, follow this example: +
      $(function(){
      +  $("table").tablesorter({
      +    widgets: ["filter"],
      +    widgetOptions : {
      +      filter_formatter : {
      +        // column index `0` or use a jQuery selector `"th:contains('Discount')"`
      +        0 : function($cell, indx){
      +          return $.tablesorter.filterFormatter.uiSpinner( $cell, indx, {
      +            value : 0,  // starting value
      +            min   : 0,  // minimum value
      +            max   : 50, // maximum value
      +            step  : 1,  // increment value by
      +            addToggle: true, // Add a toggle to enable/disable the control
      +            valueToHeader: false // add current slider value to the header cell
      +          });
      +        }
      +      }
      +    }
      +  });
      +});
      Any of the other jQuery UI spinner widget options can also be included.
      +
      +
    • +
    • Filter formatter functions include: "uiSpinner", "uiSlider", "uiRange" (uiSlider ranged), "uiDatepicker" (range only), "html5Number", "html5Range" and "html5Color".
    • +
    • + For other examples, please refer to the example pages. Formatter part 1 (example 1) adds jQuery UI controls to the filter row, while formatter part 2 (example 2) adds HTML5 controls, if supported, to the filter row. +
    • +
    +
    +
    + 1 + 2 +
    Objectnull + Filter widget: Customize the filter widget by adding a select dropdown with content, custom options or custom filter functions (v2.3.6; v2.17.0). +
    +
    + In v2.22.0, a data parameter was added to that long list of parameters.

    + *WARNING* In a future update, the filter function parameters will be cleaned up and changed as follows! +
    filter_functions : {
    +  // function(e, n, f, i, $r, c, data) {} <- current parameters
    +  0 : function(c, data) {} // planned change (version undetermined)
    +}
    The e (exact table cell text), n (normalized table cell text), f (filter input value), i (column index) and $r (current row; jQuery object) are all already included in the data object. +

    + In v2.17.0, the filter_functions column can also be referenced by using a jQuery selector (e.g. class name or ID) that points to a table header cell.
    +
    filter_functions : {
    +    ".col-date" : {
    +        "< 2004" : function (e, n, f, i, $r, c, data) {
    +            return n < Date.UTC(2004, 0, 1); // < Jan 1 2004
    +        },
    +        ...
    +    }
    +}
    + Warning What won't work is if you try to target the header using a filtering selector that uses an index, e.g. "th:eq()", ":gt()", ":lt()", ":first", ":last", ":even" or ":odd", ":first-child", ":last-child", ":nth-child()", ":nth-last-child()", etc.
    +
    + Use the "filter_functions" option in three different ways: +
    +
      +
    • + Make a sorted select dropdown list of all column contents. Repeated content will be combined. +
      $(function(){
      +  $("table").tablesorter({
      +    widgets: ["filter"],
      +    widgetOptions: {
      +      filter_functions: {
      +        // Add select menu to this column
      +        // set the column value to true, and/or add "filter-select" class name to header
      +        0 : true
      +      }
      +    }
      +  });
      +});
      + Alternately, instead of setting the column filter funtion to true, give the column header a class name of "filter-select". See the demo.

      +
    • +
    • + Make a select dropdown list with custom option settings. Each option must have a corresponding function which returns a boolean value; return true if there is a match, or false with no match. + +

      Regex example

      +
      $(function(){
      +  $("table").tablesorter({
      +    widgets: ["filter"],
      +    widgetOptions: {
      +      // function variables:
      +      // e = exact text from cell
      +      // n = normalized value returned by the column parser
      +      // f = search filter input value
      +      // i = column index
      +      // $r = jQuery element of current row
      +      // c = table.config
      +      // data = combined filter data - see filter widget "custom searches" demo, look under "How to add Custom filter types"
      +      filter_functions: {
      +        // Add these options to the select dropdown (regex example)
      +        2 : {
      +          "A - D" : function(e, n, f, i, $r, c, data) { return /^[A-D]/.test(e); },
      +          "E - H" : function(e, n, f, i, $r, c, data) { return /^[E-H]/.test(e); },
      +          "I - L" : function(e, n, f, i, $r, c, data) { return /^[I-L]/.test(e); },
      +          "M - P" : function(e, n, f, i, $r, c, data) { return /^[M-P]/.test(e); },
      +          "Q - T" : function(e, n, f, i, $r, c, data) { return /^[Q-T]/.test(e); },
      +          "U - X" : function(e, n, f, i, $r, c, data) { return /^[U-X]/.test(e); },
      +          "Y - Z" : function(e, n, f, i, $r, c, data) { return /^[Y-Z]/.test(e); }
      +        }
      +      }
      +    }
      +  });
      +});
      +

      Comparison example

      +
      $(function(){
      +  $("table").tablesorter({
      +    widgets: ["filter"],
      +    widgetOptions: {
      +      // function variables:
      +      // e = exact text from cell
      +      // n = normalized value returned by the column parser
      +      // f = search filter input value
      +      // i = column index
      +      // $r = jQuery element of current row
      +      // c = table.config
      +      // data = combined filter data - see filter widget "custom searches" demo, look under "How to add Custom filter types"
      +      filter_functions: {
      +        // Add these options to the select dropdown (numerical comparison example)
      +        // Note that only the normalized (n) value will contain numerical data
      +        // If you use the exact text, you'll need to parse it (parseFloat or parseInt)
      +        4 : {
      +          "< $10"      : function(e, n, f, i, $r, c, data) { return n < 10; },
      +          "$10 - $100" : function(e, n, f, i, $r, c, data) { return n >= 10 && n <=100; },
      +          "> $100"     : function(e, n, f, i, $r, c, data) { return n > 100; }
      +        }
      +      }
      +    }
      +  });
      +});
      + Note: if the filter_ignoreCase option is true, it DOES alter the normalized value (n) by making it all lower case.

      +
    • +
    • + Make a custom filter for the column. +
      $(function(){
      +  $("table").tablesorter({
      +    widgets: ["filter"],
      +    widgetOptions: {
      +      // function variables:
      +      // e = exact text from cell
      +      // n = normalized value returned by the column parser
      +      // f = search filter input value
      +      // i = column index
      +      // $r = jQuery element of current row
      +      // c = table.config
      +      // data = combined filter data - see filter widget "custom searches" demo, look under "How to add Custom filter types"
      +      filter_functions: {
      +        // Exact match only
      +        1 : function(e, n, f, i, $r, c, data) {
      +          return e === f;
      +        }
      +      }
      +    }
      +  });
      +});
      + Note: if the filter_ignoreCase option is true, it DOES alter the normalized value (n) by making it all lower case.

      +
    • +
    +
    +
    Example
    Booleantrue + Filter widget: Set this option to false to always show the filter row; by default, the filter row is completely hidden when no rows exist within the tbody (v2.15). +
    +
    + Use the filter_hideEmpty option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_hideEmpty : false
    +    }
    +  });
    +});
    +
    Booleanfalse + Filter widget: Set this option to true to hide the filter row initially. The row is revealed by hovering over the visible portion of the filter row or by giving any filter input/select focus (tab key) (v2.4). +
    +
    + Use the filter_hideFilters option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_hideFilters : true
    +    }
    +  });
    +});
    You can change the style (thickness) of the hidden filter row in the tablesorter theme css. Look for .tablesorter-filter-row (revealed row) and .tablesorter-filter-row.hideme (for the hidden row) css definitions.
    +
    Example
    Booleantrue + Filter widget: Set this option to false to make the column content search case-sensitive, so typing in "a" will not find "Albert". (v2.3.4) +
    +
    + Use the filter_ignoreCase option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_ignoreCase : false
    +    }
    +  });
    +});
    +
    Example
    Boolean, or Numbertrue + Filter widget: If true, a search of the column content will occur as the user types, with the delay set in the filter_searchDelay option (v2.9; v2.10). +
    +
    + This option, when false allows you to disable the live search behavior, so that a filter is only applied when the user presses Enter (or uses Esc to clear and cancel the search).
    +
    + If this option is set to a number, e.g. 4, a search of the column content will not initiate until this minimum number of characters are entered into the input. +
    +
    String"filter-onlyAvail" + Filter widget: If a header contains a select dropdown and this class name, only the available (visible) options in the column will show (v2.10.1; v2.17.6). +
    +
    + In v2.17.6, columns with the only available class name set, that are not currently being filtered will only show the available options. Conversely, the column(s) with a selected option will show all options.
    +
    + This option is useful after one or more columns have been filtered, then the column select filter with this class applied will only show the contents of the column within the dropdown that are currently visible. See the custom filter widget demo "Discount" column for an example (sort the "First Name" column first).
    +
    + Caution: The main issue with this functionality is with keyboard accessibility. If the keyboard is used to select an option, only the first and default options will be available for chosing. The only way to select other options is with the mouse. +
    +
    Example
    object{ search : '', select : '' } + Filter widget: Set global filter input placeholder text for search inputs and selects (v2.16). +
    +
    + Any search type input added to the filter row will automatically get a placeholder attribute added, the source of this placeholder text is from the following sources, in order of priority: +
      +
    • Header cell data (table.config.$headers.eq(0).data('placeholder', 'search for...');
    • +
    • Header cell data-attribute (<th data-placeholder="Find Rank...">Rank</th>)
    • +
    • Global filter_placeholder.search setting.
    • +
    + The filter_placeholder.select setting adds the text to the first select option (default option to show all rows).
    +
    + Note: The widget-filter-formatter-jui.js jQuery UI Datepicker Range Selector creates two inputs, so this option then includes two additional settings:
    +
    +
    filter_placeholder : {
    +	search : '',
    +	select : '',
    +	from   : '', // datepicker range "from" placeholder
    +	to     : ''  // datepicker range "to" placeholder
    +}
    +
    Note: The browser must support the placeholder attribute before it will be visible. +
    +
    Example
    String, jQuery objectnull + Filter widget: jQuery selector string of an element used to reset the filters (v2.4; v2.16). +
    +

    + When this option points to a reset element using a jQuery selector string, it is bound using event delegation. So if any additional reset elements, with the same class name, are added to the page dynamically, they will be associated with the same table.
    +
    + For example, add this button (<button class="reset">Reset</button>) to the table header, or anywhere else on the page. That element will be used as a reset for all column and quick search filters (clears all fields): +

    + Use the filter_reset option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_reset : '.reset'
    +    }
    +  });
    +});
    + If this option contains a jQuery object (v2.16), clicking on any of the elements within that jQuery object will trigger a filter reset. If any additional elements with the same selector are added to the page, they will not be dynamically functional.
    +
    + If either of these methods do not work as desired, simply trigger a filterReset event on the table. +
    +
    Example
    Booleanfalse + Filter widget: If the storage utility is available (included with jquery.tablesorter.widgets.js file, the last applied filter is saved to storage (v2.14). +
    +
    + Filters saved to local storage (or cookies) will override any default filters within the header data-attribute (set by the filter_defaultAttrib option) and be available to the pager before any ajax calls are made.
    +
    + To bypass this behavior, clear out the saved filters as follows: +
    $.tablesorter.storage( $('table'), 'tablesorter-filters', '' );
    +
    +
    Example
    Numeric300 + Filter widget: Set this option to the number of milliseconds to delay the search. (v2.3.4). +
    +
    + Use the filter_searchDelay option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_searchDelay : 500
    +    }
    +  });
    +});
    + + If you want to want to initialize the filter without user input, target any one of the filters and trigger a "search". + +
    // target the first filter input
    +// this method will begin the search after the searchDelay time
    +$('input.tablesorter-filter:eq(0)').trigger('search');
    +
    +// this method will begin the search immediately
    +$('input.tablesorter-filter:eq(0)').trigger('search', false);
    + + In tablesorter v2.4+, the trigger can be applied directly to the table: +
    // refresh the widget filter; no delay
    +$('table').trigger('search', false);
    +
    Booleantrue + Filter widget: Set this option to allow searching through already filtered rows (in special conditions); this will speed up searching in large tables (v2.17.4). +
    +
    + To better explain this, lets do it by example. Lets say you have a column of color names and you enter "light" and results like "light blue" and "light grey" show up.
    +
    + When you press the space bar, a space is added, and instead of searching though all of the colors again, the filter widget only searches through the already filtered results that started with "light". This can substantially speed up searching, especially in large tables.
    +
    + But, there are some special circumstances which would make this method return incorrect results. So, this option was added to allow you to disable this feature in case one of these following conditions doesn't cover your need; but still, please report any issues!
    +
    + The search through filtered results only occurs if the following conditions are met: +
      +
    • The last search (for all columns) was not completely empty - all rows will be searched anyway.
    • +
    • If there were no changes to the search from the beginning of the search string (changing the above search to "bright" will force a new search of all rows).
    • +
    • If the search does not contain a logical or ( or or |), or a range delimiter ( - or to ) within the search query.
    • +
    • If the search is not looking for an exact match (" or =) or a logical not search (!).
    • +
    • Or, if the search is using a select dropdown without a "filter-match" class name (looking for an exact match).
    • +
    • If the search does not contain an operator greater than or equal to a negative number (>=-10) or less than or equal to a positive number (<=10).
    • +
    • And lastly, only search filtered rows if all rows are not hidden.
    • +
    + If the debug option is set to true, then a message will appear while filtering stating the specific number of rows, or "all" rows, that are being searched.
    +
    + Use the filter_searchFiltered option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_searchFiltered : false
    +    }
    +  });
    +});
    +
    Example
    Functionnull + Filter widget: Include a function to return an array of values to be added to the column filter select (v2.16.0; v2.21.5). +
    +
    + In v2.21.5, this option will now override the filter_function options (so you need to add them back!), allowing the addition of custom select options and still maintain basic filtering action - see this demo (ref).
    +
    + In v2.17.0, the filter_selectSource column can also be referenced by using a jQuery selector (e.g. class name or ID) that points to a table header cell.
    +
    filter_selectSource : {
    +  ".model-number" : [ "abc", "def", "ghi", "xyz" ]
    +}
    + Warning What won't work is if you try to target the header using a filtering selector that uses an index, e.g. "th:eq()", ":gt()", ":lt()", ":first", ":last", ":even" or ":odd", ":first-child", ":last-child", ":nth-child()", ":nth-last-child()", etc.
    +
    + A column will have a filter select dropdown when a "filter-select" class name is added to the header cell, or if the filter_functions column value is set to true
    +
    + This option allows using an alternate source, or customizing options of the filter select dropdown. This option can be set as follows: +
      +
    • null - this value will set the default behavior and return all table cell values from the current column.
    • +
    • An overall function - when this option is a function, it will be used for all filter selects in the table. +
      $(function(){
      +  $("table").tablesorter({
      +    widgets: ["filter"],
      +    widgetOptions : {
      +      filter_selectSource : function(table, column, onlyAvail){
      +        // get an array of all table cell contents for a table column
      +        var array = $.tablesorter.filter.getOptions(table, column, onlyAvail);
      +        // manipulate the array as desired, then return it
      +        return array;
      +      }
      +    }
      +  });
      +});
      +
    • +
    • An object containing column keys set with a function - when the option is set in this manner, a function can be applied to a specific column +
      $(function(){
      +  $("table").tablesorter({
      +    widgets: ["filter"],
      +    widgetOptions : {
      +      filter_selectSource : {
      +        0 : function(table, column, onlyAvail){
      +          return $.getJSON('ajax/options.json', function(data) {
      +            // return false if there is a problem and the select
      +            // will display the original defaults
      +            return data.hasOwnProperty('options') ? data.options : false;
      +        }
      +      }
      +    }
      +  });
      +});
      +
    • +
    + The function uses the following parameters: +
      +
    • table - table DOM element
    • +
    • column - zero-based index of the column with a filter select
    • +
    • onlyAvail - boolean indicating if the returned options should only be from available (non-filtered) rows.
    • +
    + Important Return an array of values which will be added to the filter select dropdown. This array will automatically be stripped of any duplicate values and sorted alphanumerically before being added to the select. If for some reason the custom filter_selectSource function does not obtain the desired array of values, return false and the original method of obtaining column cell content will be used. +
    +
    Example
    String'|' + Filter widget: Set this option to be any separator (v2.17.6) that is to be used within the filter_selectSource returned array. +
    +
    + Use the filter_selectSourceSeparator option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_selectSource : {
    +        0 : [ 'en|English', 'fr|French', 'de|German' ]
    +      },
    +      // filter_selectSource array text left of the separator is added to the option value, right into the option text
    +      filter_selectSourceSeparator : '|'
    +    }
    +  });
    +});
    Results in this HTML: +
    <select>
    +	<option value=""></option>
    +	<option value="en">English</option>
    +	<option value="fr">French</option>
    +	<option value="de">German</option>
    +</select>
    This also works for the filter_functions +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions: {
    +      filter_functions: {
    +        // Add these options to the select dropdown (regex example)
    +        1 : {
    +          "<10|Less than 10" : function(e, n, f, i, $r, c, data) { return n < 10; },
    +          "10 - 100|Between 10 & 100" : function(e, n, f, i, $r, c, data) { return n >= 10 && n <=100; },
    +          ">100|Greater than 100" : function(e, n, f, i, $r, c, data) { return n > 100; }
    +        }
    +      },
    +      // filter_selectSource array text left of the separator is added to the option value, right into the option text
    +      filter_selectSourceSeparator : '|'
    +    }
    +  });
    +});
    + Results in this HTML (this adds a data-function-name attribute to keep a reference to the associated filter_functions. +
    <select>
    +  <option value=""></option>
    +  <option data-function-name="&lt;10|Less than 10" value="&lt;10">Less than 10</option>
    +  <option data-function-name="10 - 100|Between 10 &amp; 100" value="10 - 100">Between 10 & 100</option>
    +  <option data-function-name="&gt;100|Greater than 100" value="&gt;100">Greater than 100</option>
    +</select>
    +
    +
    Booleanfalse + Filter widget: Set this option to true if filtering is performed on the server-side (v2.5.3). +
    +
    + Use the filter_serversideFiltering option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_serversideFiltering : true
    +    }
    +  });
    +});
    +
    Booleanfalse + Filter widget: Set this option to true to use the filter to find text from the start of the column, so typing in "a" will find "albert" but not "frank", both have a's. (v2.1). +
    +
    + Use the filter_startsWith option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_startsWith : true
    +    }
    +  });
    +});
    +
    Example
    Booleanfalse + Filter widget: If true, ALL filter searches will only use parsed data (v2.4). +
    +
    + Use the filter_useParsedData option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_useParsedData : false
    +    }
    +  });
    +});
    +
      +
    • To only use parsed data in specific columns, set this option to false and use any of the following (they all do the same thing), set in order of priority: +
        +
      • jQuery data data-filter="parsed".
      • +
      • metadata class="{ filter: 'parsed'}". This requires the metadata plugin.
      • +
      • headers option headers : { 0 : { filter : 'parsed' } }.
      • +
      • header class name class="filter-parsed".
      • +
      +
    • +
    • Remember that parsed data most likely doesn't match the actual table cell text, 20% becomes 20 and Jan 1, 2013 12:01 AM becomes 1357020060000.
    • +
    +
    +
    String"data-value" + Filter widget: This option contains the name of the data-attribute which contains the default (starting) filter value (v2.10.8). +
    +
    + Use the filter_defaultAttrib option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_defaultAttrib : 'data-value'
    +    }
    +  });
    +});
    Then add the default filter value to the table header as follows:
    <th data-value="<30">Age</th>
    +
    Example
    String""Sticky Headers widget: This additional CSS class applied to the sticky header row (v2.11). +

    + Changed to empty string in v2.11, as the "tablesorter-stickyHeader" class will always be added to the sticky header row; this option now contains any additional class names to add. +

    Previously, this option contained the class name to be applied to the sticky header row (tr) (v2.1).

    + Use the "stickyHeaders" option to add an extra css class name as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["stickyHeaders"],
    +    widgetOptions : {
    +      // css class name applied to the sticky header
    +      stickyHeaders : "tablesorter-stickyHeader"
    +    }
    +  });
    +});
    +
    Example
    String"-sticky" + Sticky Headers widget: If the table has an ID defined, the suffix from this option will be added to the ID in the cloned sticky table (v2.9). +
    +
    + So if your table ID is "gummy", then the cloned sticky table id becomes "gummy-sticky"
    +
    + Use the "stickyHeaders_cloneId" option to change the cloned table id as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["stickyHeaders"],
    +    widgetOptions : {
    +      // cloned table id suffix
    +      stickyHeaders_cloneId : "-clone"
    +    }
    +  });
    +});
    +
    Booleantrue + Sticky Headers widget: If this option is false and a caption exists, it will not be included in the sticky header (v2.10.8). +
    +
    + Use the stickyHeaders_includeCaption option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["stickyHeaders"],
    +    widgetOptions : {
    +      // cloned table id suffix
    +      stickyHeaders_includeCaption : false
    +    }
    +  });
    +});
    +
    Example
    Stringnull + Sticky Headers widget: points to the table wrapper to stick the headers to while scrolling. Use this option to point to their needs (v2.14.4). +
    +
    + Use the stickyHeaders_attachTo option as follows:
    +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["stickyHeaders"],
    +    widgetOptions : {
    +      // Where to attach the stickyHeaders
    +      stickyHeaders_attachTo : '.wrapper' // $('.wrapper') jQuery object can also be used
    +    }
    +  });
    +});
    +
    Example
    Stringnull + Sticky Headers widget: points to the element in which to monitor for horizontal scrolling (v2.18.0). +
    +
    + If undefined (or null), the window element will be monitored.
    +
    + Use the stickyHeaders_xScroll option as follows:
    +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["stickyHeaders"],
    +    widgetOptions : {
    +      // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
    +      stickyHeaders_xScroll : '.wrapper' // $('.wrapper') jQuery object can also be used
    +    }
    +  });
    +});
    +
    Example
    Stringnull + Sticky Headers widget: points to the element in which to monitor for vertical scrolling (v2.18.0). +
    +
    + If undefined (or null), the window element will be monitored.
    +
    + Use the stickyHeaders_yScroll option as follows:
    +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["stickyHeaders"],
    +    widgetOptions : {
    +      // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
    +      stickyHeaders_yScroll : '.wrapper' // $('.wrapper') jQuery object can also be used
    +    }
    +  });
    +});
    +
    Example
    Multiple0 + Sticky Headers widget: Set the sticky header offset from the top as a Number or jQuery selector string or object (v2.10). +
    +
    + If the page includes a fixed navigation bar at the top, like Bootstrap, set "stickyHeaders_offset" option to offset the sticky table header to be below the fixed navigation by setting this option using any of the following examples:
    +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["stickyHeaders"],
    +    widgetOptions : {
    +      // apply sticky header top 30px below the top of the browser window
    +      stickyHeaders_offset : 30
    +    }
    +  });
    +});
    or +
    stickyHeaders_offset : '.navbar-fixed-top' // jQuery selector string
    or +
    stickyHeaders_offset : $('.navbar-fixed-top') // jQuery object
    +
    Booleantrue + Sticky Headers widget: Scroll table top into view after filtering (v2.16.2). +
    +
    + When a user searches the table using the sticky header filter row the results may reduce the number of rows so that the table would scroll up out of the viewport. So, this option scrolls the table top into view and moves the filter focus to the same input in the original header, instead of the sticky header input.
    +
    + Set this option to false to prevent the page scroll after filtering the table. +
    +
    Booleantrue + Sticky Headers widget: If true, sticky table headers will resize automatically when content is added to or removed from the table headers (v2.10). +
    +
    + While this option is true, a timer is initialized to check the width of every header cell every 1/4 second. If this causes lag, or any other problems, set this option to false. + When this option is false, sticky table headers are unable to detect and match the width of the original table headers when content is added or removed.
    +
    + Use the "stickyHeaders_addResizeEvent" option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["resizable"],
    +    widgetOptions : {
    +      // add header resize detection
    +      stickyHeaders_addResizeEvent : true
    +    }
    +  });
    +});
    When the browser window is resized, the headers (original and sticky) will resize automatically no matter the value of this option. +
    +
    Numeric2 + Sticky Headers widget: The zIndex added to the stickyHeaders. This option allows the user to adjust the value to their needs (v2.11). +
    +
    + Use the stickyHeaders_zIndex option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["stickyHeaders"],
    +    widgetOptions : {
    +      // The zIndex of the stickyHeaders, allows the user to adjust this to their needs
    +      stickyHeaders_zIndex : 100
    +    }
    +  });
    +});
    +
    Booleantrue + Resizable widget: If this option is set to false, resized column widths will not be saved. Previous saved values will be restored on page reload (v2.4). +
    +
    + Use the "resizable" option to not save the resized widths: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["resizable"],
    +    widgetOptions : {
    +      // css class name applied to the sticky header
    +      resizable : false
    +    }
    +  });
    +});
    +
    Example
    Booleanfalse + Resizable widget: If this option is set to true, a resizing anchor will be included in the last column of the table (v2.8.3). +
    +
    + If an anchor was included and the table is full width, the column would resize in the opposite direction which my not be intuitive to the user. So set this option as desired, but please be mindful of the user experience.
    +
    + Use the "resizable_addLastColumn" option to include the last column resizer as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["resizable"],
    +    widgetOptions : {
    +      // css class name applied to the sticky header
    +      resizable_addlastcolumn : true
    +    }
    +  });
    +});
    +
    Example
    Array[] + Resizable widget: Set this option to the starting & reset header widths (v2.15.12). +
    +
    + Use the "resizable_widths" option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["resizable"],
    +    widgetOptions : {
    +      // headers widths applied at initialization & resizable reset
    +      // this setting includes any non-resizable cells (resizable-false)
    +      resizable_widths : [ '10%', '10%', '50px' ]
    +    }
    +  });
    +});
    +
    Example
    Booleanfalse + Resizable widget: Set this option to throttle the resizable events (v2.17.4). +
    +
    + When false throttling of the mousemove (resizing) event is not applied.
    +
    + Set this option to either true for a default 5 millisecond delay, or set it to any number less than 10 to adjust the throttling delay that is applied to the mousemove/resizing event.
    +
    + Use the "resizable_throttle" option as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["resizable"],
    +    widgetOptions : {
    +      // set to true for a default 5ms throttling delay
    +      // or set to a number < 10 (more than that makes the resizing adjustment unusable
    +      resizable_throttle : true
    +    }
    +  });
    +});
    +
    Booleanfalse + Resizable widget: When true, the last column will be targeted for resizing (v2.21.3). +
    +

    When true, resizing a column will change the size of the selected column, and the last column, not the selected column's neighbor.

    +

    When false, resizing a column will move the column border between it's neighbors.

    +

    Also, in a full width table, if this option is false, the same behavior as when this option is true can be seen when resizing a column while holding down the Shift key on the keyboard - the last column is resized.

    +
    +
    Booleantrue + SaveSort widget: If this option is set to false, new sorts will not be saved. Any previous saved sort will be restored on page reload (v2.4). +
    +
    + Use the "saveSort" option to not save the current sort: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["saveSort"],
    +    widgetOptions : {
    +      // if false, the sort will not be saved for next page reload
    +      saveSort : false
    +    }
    +  });
    +});
    +
    Example
    Booleanfalse + Storage widget: If this option is set to false, all saved variables for the table will be within local storage (v2.21.3). +
    +

    If true, all saved variables for the table will be within the session storage. This means once the user closes the browser, all saved variables are lost.

    + Use the "storage_useSessionStorage" option to switch to session storage as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["saveSort"],
    +    widgetOptions : {
    +      // if false, saved variables will be saved in local storage
    +      storage_useSessionStorage : true
    +    }
    +  });
    +});
    +
    Example
    String"" + Storage widget: This option allows setting an alternate table id so multiple tables on a page have the settings grouped together +
    +

    When grouping together multiple tables, setting the variable on one table will not cause the setting to modify a second table, the change will only be apparent on page reload.

    +

    If this option is not defined, the actual table id will be used (which isn't conducive to applying to multiple tables!)

    +

    A more detailed list of the table id priority settings can be found in the $.tablesorter.storage function description.

    +
    +
    String"" + Storage widget: Set a table (data) attribute to use to obtain a table id, which allows grouping multiple tables on one page together - they share a common saved setting. +
    +

    If a value is set in this option, the storage widget looks in that defined table data-attribute for a table id.

    +

    If this option is not defined, then the default data-attribute for the table becomes "data-table-group".

    +

    The value in the data-attribute sets a table id, if not found, the storage widget then looks for an id in the storage_tableId option.

    +
    +
    String"" + Storage widget: This option allows setting an alternate table url so that tables on multiple pages will have their settings grouped together +
    +

    This option replaces and will override the now deprecated config.fixedUrl option.

    +

    If there is a value within the table's "data-table-page" (set by the storage_page option), it will override this setting.

    +

    A more detailed list of the table url priority settings can be found in the $.tablesorter.storage function description.

    +
    +
    String"" + Storage widget: Set a table (data) attribute to use to obtain a table url, which allows grouping tables across multiple pages together - they share a common saved setting. +
    +

    If a value is set in this option, the storage widget looks in that defined table data-attribute for a table url.

    +

    If this option is not defined, then the default data-attribute for the table becomes "data-table-page".

    +

    The value in the data-attribute sets a table url, if not found, the storage widget then looks for a url in the storage_fixedUrl option.

    +
    +
    Array[ "even", "odd" ] + Zebra widget: When the zebra striping widget is initialized, it automatically applied the default class names of "even" and "odd". (Modified v2.1). +
    +
    + Use the "zebra" option to change the theme as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["zebra"], // initialize zebra striping of the table
    +    widgetOptions: {
    +      zebra: [ "normal-row", "alt-row" ]
    +    }
    +  });
    +});
    +
    Example
    Pager
    Objectnull + Target your one or more pager markup blocks by setting this option with a jQuery selector. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_selectors.container; additionally you can change the class name that is applied to the pager (used within the jquery.tablesorter.pager.css file) by modifying the widgetOption.pager_css.container class name (default is "tablesorter-pager")
    +
    + This is some example pager markup. It should contain all of the controls set by the multiple css-named options:
    +<div class="pager">
    +  <form>
    +    <img src="first.png" class="first"/>
    +    <img src="prev.png" class="prev"/>
    +    <span class="pagedisplay"></span> <!-- this can be any element, including an input -->
    +    <img src="next.png" class="next"/>
    +    <img src="last.png" class="last"/>
    +    <select class="pagesize">
    +      <option value="10">10</option>
    +      <option value="20">20</option>
    +      <option value="30">30</option>
    +      <option value="40">40</option>
    +    </select>
    +    <select class="gotoPage" title="Select page number"></select>
    +  </form>
    +</div>
    Caution If you use buttons in your pager container, make sure the buttons include a button type (<button type="button">Next</button>) to prevent form submission and page reloading every time the button is clicked.
    +
    Use this option as follows:
    $(function(){
    +  $("table")
    +    .tablesorter()
    +    .tablesorterPager({
    +      container: $(".pager")
    +    });
    +  });
    +});
    +
    Example
    Stringnull + Set this option to include a url template to use so that the pager plugin can interact with your database (v2.1; v2.9). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_ajaxUrl
    +
    + The tags within the ajaxUrl string are optional. If do not want the user to change the page size, then you only need to include the page in this string: +
    ajaxUrl: "http://mydatabase.com?start={page}"
    + If you need to send your server a page offset (actual starting record number), then you'll need to use the customAjaxUrl option.
    +
    + Here is an example of how to include the option, it should always be paired with an ajaxProcessing function: +
    $(function(){
    +  $("table")
    +    .tablesorter()
    +    .tablesorterPager({
    +      ajaxUrl: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}",
    +      ajaxProcessing: function(data, table, xhr){
    +        // do something with the ajax data
    +        return [ formatted_data, total_rows ];
    +      }
    +    });
    +});
    The ajaxUrl template replaces the following tags with values from the tablesorter plugin and pager addon: +
    + + + + + + + + + + + + + + + + + +
    TagReplaced with
    {page}Zero-based index of the current pager page
    {page+1}One-based index of the current pager page (replace "+1" with any number) (e.g. {page+3}) (v2.9).
    {size}Number of rows showing, or number of rows to get from the server
    {sortList:col} or {sort:col}Adds the current sort to the ajax url string into a "col" array, so your server-side code knows how to sort the data (v2.4.5).
    + The col portion of the {sortList:col} tag can be any name string (no spaces) to indicate the name of the variable to apply. So if your current sortList is [[2,0],[3,0]], it becomes "&sort[2]=0&sort[3]=0" in the url. {sort:col} shortened tag also works (v2.9). +
    {filterList:fcol} or {filter:fcol}Adds the value of the current filters to the ajax url string into a "fcol" array, so your server-side code knows how to filter the data (v2.6).
    + The fcol portion of the {filterList:fcol} tag can be any name string (no spaces) to indicate the name of the variable to apply. So if your current filters are ['','Blue',13], it becomes "&fcol[2]=Blue&fcol[3]=13" in the url. {filter:col} shortened tag also works (v2.9). +
    +
    Example
    Functionfunction(table, url) { return url; } + This callback function allows you to modify the processed URL as desired (v2.8.1). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_customAjaxUrl
    +
    + The customAjaxUrl function has two parameters, the table DOM element and the processed url string (all tags within the ajaxUrl have been replaced with their appropriate values). +
    $(function(){
    +  $("table")
    +    .tablesorter()
    +    .tablesorterPager({
    +      ajaxUrl: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}",
    +      ajaxProcessing: function(data, table, xhr){
    +        // do something with the ajax data
    +        return [ formatted_data, total_rows ];
    +      },
    +      // modify the url after all processing has been applied
    +      customAjaxUrl: function(table, url) {
    +        // trigger my custom event
    +        $(table).trigger('changingUrl');
    +        // send the server the current page
    +        return url += '&currntUrl=' + window.location.href;
    +      }
    +    });
    +});
    + In the following example, lets say your server needs a starting and ending record number instead of a page & size parameter. Use this option as follows: +
    $(function(){
    +  $("table")
    +    .tablesorter()
    +    .tablesorterPager({
    +      ajaxUrl: "http://mydatabase.com?{sortList:col}",
    +      customAjaxUrl: function(table, url) {
    +        var pager = table.config.pager,
    +          start = pager.page * pager.size,
    +          end = start + pager.size;
    +        return url += '&start=' + start + '&end=' + end;
    +      },
    +      ajaxProcessing: function(data, table, xhr){
    +        // do something with the ajax data
    +        return [ total_rows, data ];
    +      }
    +    });
    +});
    +
    +
    Example
    Object{ dataType: 'json' } + This option contains the ajax settings for the pager interaction with your database (v2.10). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_ajaxObject
    +
    + The ajaxObject is completely customizable, except for the url setting which is processed using the pager's ajaxUrl and customAjaxUrl options. This means you can also add a success callback function which is called after the ajax has rendered.
    +
    + Your server does not need to return a JSON format, if you want to return pure HTML, set the dataType to "html" and modify the ajaxProcessing function to instead work with HTML; then return a jQuery object or apply the HTML to the table yourself.
    +
    + See all possible settings in the jQuery.ajax documentation +
    $(function(){
    +  $("table")
    +    .tablesorter()
    +    .tablesorterPager({
    +      ajaxUrl: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}",
    +      ajaxObject: {
    +        // add more ajax settings here
    +        // see http://api.jquery.com/jQuery.ajax/#jQuery-ajax-settings
    +        dataType: 'json'
    +      },
    +      ajaxProcessing: function(data, table, xhr){
    +        // do something with the ajax data;
    +        return [ total_rows ];
    +      }
    +    });
    +});
    +
    Example
    Booleantrue + Set this option to false if your table data is preloaded into the table, but you are still using ajax (v2.14.5). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_processAjaxOnInit +
    +
    Functionnull + This function is required to return the ajax data obtained from your server into a useable format for tablesorter to apply to the table (v2.1, v2.17.3). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_ajaxProcessing
    +
    + This function was created and modified to allow you a great deal of flexibility. The only required information that this function needs to return is an array containing the total number of rows, which is needed to calculate total pages.
    +
    + There are numerous examples below. Choosing which one to use is left to you. For more information, please check out related questions on Stackoverflow, in particular see this thread about how to use the different ajax options together.
    +
    + In v2.10, the returned rows is now optional. And it can either be an array of arrays or a jQuery object (not attached to the table)
    +
    + Process your ajax data so that the following information is returned:
    +
    + +
    + +

    Object

    +
    + After tablesorter v2.17.3, this function can include a filteredRows property which will update the internal value and thus show a proper filtered row count, and update the "goto" page drop down selector appropriately.
    +
    + After tablesorter v2.11, the ajaxProcessing function can return an object containing these properties, along with any extra properties. These extra properties will be available for use within the pager output string (see more details in issue #326);
    +
    + So, lets say the data sent by the server looks like this: +
    {
    +    "total_rows"    : 100,
    +    "filtered_rows" : 75,
    +    "new_headers"   : [ "ID", "Name", "Data", "Value" ],
    +    "data"          : '<tr><td>a123</td><td>abc</td><td>xyz</td><td>999</td></tr>',
    +    "subject"       : "cheese",
    +    "tasty"         : "It's delicious!"
    +}
    + This ajaxProcessing function must return an object with "total", "headers" and "rows" properties! As before, "total" is the only required property; if the headers don't need to be changed, don't return a headers array, and if you append the rows to the table yourself within the ajaxProcessing function, you don't need to return a "rows" property. +
    ajaxProcessing: function(result, table, xhr){
    +    if (result && result.hasOwnProperty('data')) {
    +
    +        // "total" is a required property!
    +        result.total = result["total_rows"];
    +
    +        // "filteredRows" is optional - in tablesorter v2.17.3, this updates the filter row count internally
    +        // and updates the "goto" page dropdown selector appropriately
    +        result.filteredRows = result["filtered_rows"];
    +
    +        // "headers" is optional. This is not needed if the table headers don't change
    +        result.headers = result["new_headers"];
    +
    +        // "rows" is optional. No need to return this if you process and add the rows to the table yourself
    +        // otherwise, return an array of arrays or jQuery object (shown in this example)
    +        result.rows = $(result.data);
    +
    +        return result;
    +    }
    +}
    + Now in the output string, you can also reference the extra ajax data: +
    output : '{startRow} to {endRow} of {filteredRows} ({totalRows}) rows about {subject} ({tasty})'
    +
    + +

    Array (total only)

    +
    + After tablesorter v2.10, just build the table yourself and return the total number of rows: +
    ajaxProcessing: function(data, table, xhr){
    +  if (data && data.hasOwnProperty('rows')) {
    +    var r, row, c, d = data.rows,
    +    // total number of rows (required)
    +    total = data.total_rows,
    +    // all rows: array of arrays; each internal array has the table cell data for that row
    +    rows = '',
    +    // len should match pager set size (c.size)
    +    len = d.length;
    +    // this will depend on how the json is set up - see City0.json
    +    // rows
    +    for ( r=0; r < len; r++ ) {
    +      rows += '<tr class="ajax-row">'; // new row
    +      // cells
    +      for ( c in d[r] ) {
    +        if (typeof(c) === "string") {
    +          rows += '<td>' + d[r][c] + '</td>'; // add each table cell data to row
    +        }
    +      }
    +      rows += '</tr>'; // end new row
    +    }
    +    // find first sortable tbody, then add new rows
    +    table.config.$tbodies.eq(0).html(rows);
    +    // no need to trigger an update method, it's done internally
    +    return [ total ];
    +  }
    +}
    +
    + +

    Array (rows as jQuery object)

    +
    + After tablesorter v2.10, return a jQuery object +
    ajaxProcessing: function(data, table, xhr){
    +  if (data && data.hasOwnProperty('rows')) {
    +    var r, row, c, d = data.rows,
    +    // total number of rows (required)
    +    total = data.total_rows,
    +    // array of header names (optional)
    +    headers = data.headers,
    +    // all rows: array of arrays; each internal array has the table cell data for that row
    +    rows = '',
    +    // len should match pager set size (c.size)
    +    len = d.length;
    +    // this will depend on how the json is set up - see City0.json
    +    // rows
    +    for ( r=0; r < len; r++ ) {
    +      rows += '<tr class="ajax-row">'; // new row
    +      // cells
    +      for ( c in d[r] ) {
    +        if (typeof(c) === "string") {
    +          rows += '<td>' + d[r][c] + '</td>'; // add each table cell data to row
    +        }
    +      }
    +      rows += '</tr>'; // end new row
    +    }
    +    // don't attach the $(rows) because it's difficult to tell old from new data
    +    // and no need to trigger an update method, it's done internally
    +    return [ total, $(rows), headers ];
    +  }
    +}
    + Or, if your JSON contains all the rows within a string this method will work: +
    ajaxProcessing: function(data, table, xhr){
    +  if (data && data.hasOwnProperty('rows')) {
    +    // data.rows would look something like this
    +    // '<tr><td>r0c0</td><td>r0c1</td></tr><tr><td>r1c0</td><td>r1c1</td></tr>'
    +    return [ data.total, $(data.rows), data.headers ];
    +  }
    +}
    +
    + +

    Array (rows as an array of arrays)

    +
    + After tablesorter v2.1, this function must return an array with values in any of the following orders: +
    // [ total_rows (number), rows (array of arrays), headers (array; optional) ]
    +// or [ rows, total_rows, headers ]
    +// or [ total_rows, $(rows) ]
    +// or [ total_rows ]
    +[
    +  100, // total rows
    +  [
    +    [ "row1cell1", "row1cell2", ... "row1cellN" ],
    +    [ "row2cell1", "row2cell2", ... "row2cellN" ],
    +    ...
    +    [ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
    +  ],
    +  [ "header1", "header2", ... "headerN" ] // optional
    +]
    Note: In v2.14.3, the contents of the array can also contain table cell markup (i.e. "<td class='green'>+ 10%</td>").
    +
    + Here is some example JSON (comments added, but not allowed in JSON) which is contained in the City0.json file: +
    {
    +  // total rows
    +  "total_rows": 80,
    +  // headers
    +  "cols" : [
    +    "ID", "Name", "Country Code", "District", "Population"
    +  ],
    +  // row data...
    +  "rows" : [{
    +    "ID": 1,
    +    "Name": "Kabul",
    +    "CountryCode": "AFG",
    +    "District": "Kabol",
    +    "Population": 1780000
    +  }, {
    +    // row 2, etc...
    +  }]
    +}
    + The above JSON is processed by the following code (this returns an array of array of table rows): +
    $(function(){
    +  $("table")
    +    .tablesorter()
    +    .tablesorterPager({
    +      ajaxUrl: "http://mydatabase.com?page={page}&size={size}",
    +      ajaxProcessing: function(data, table, xhr){
    +        if (data && data.hasOwnProperty('rows')) {
    +          var r, row, c, d = data.rows,
    +          // total number of rows (required)
    +          total = data.total_rows,
    +          // array of header names (optional)
    +          headers = data.cols,
    +          // all rows: array of arrays; each internal array has the table cell data for that row
    +          rows = [],
    +          // len should match pager set size (c.size)
    +          len = d.length;
    +          // this will depend on how the json is set up - see City0.json
    +          // rows
    +          for ( r = 0; r < len; r++ ) {
    +            row = []; // new row array
    +            // cells
    +            for ( c in d[r] ) {
    +              if (typeof(c) === "string") {
    +                row.push(d[r][c]); // add each table cell data to row array
    +              }
    +            }
    +            rows.push(row); // add new row array to rows array
    +          }
    +          return [ total, rows, headers ]; // or return [ rows, total, headers ] in v2.9+
    +        }
    +      }
    +    });
    +});
    +
    + +
    +
    +
    Example
    String"{page}/{totalPages}"This option allows you to format the output display which can show the current page, total pages, filtered pages, current start and end rows, total rows and filtered rows (v2.0.9; v2.17.6). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_output
    +
    + This option replaced the original separator option, which only separated the page number from the total number of pages. The formatted output from this option is placed inside the information block targeted by the cssPageDisplay option.
    +
    + Use it as follows: +
    $(function(){
    +  $("table")
    +    .tablesorter()
    +    .tablesorterPager({
    +      output: '{startRow} to {endRow} of {totalRows} rows'
    +    });
    +  });
    +});
    The following tags are replaced within the output string: + + + + + + + + + + + + + + + +
    TagReplaced with
    {page}The current pager page
    {page:input}The current pager page within an input (v2.17.6)
    {totalPages}Total number of pager pages
    {filteredPages}Total number of pages left after being filtered
    {startRow}Starting row number currently displayed
    {startRow:input}Starting row number currently displayed within an input (v2.17.6)
    {endRow}Ending row number currently displayed
    {filteredRows}Total number of rows left after being filtered
    {totalRows}Total number of rows
    +
    + 1 + 2 + 3 + 4 +
    Booleantrue + If true, the addon hides the left pager arrow on the first page and right pager arrow on the last page. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_updateArrows
    +
    + If true the classname from the cssDisabled option is applied to the arrows when at either page extreme.
    +
    Example
    Numeric0 + Set the starting page of the pager (zero-based index). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_startPage +
    +
    Example
    Numeric, Boolean0 + Reset pager to this page after filtering; set to desired page number (zero-based index), or false to not change page at filter start (v2.16). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_pageReset +
    +
    Numeric10 + Set initial number of visible rows. This value is changed by the dropdown selector targeted by the cssPageSize option. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_size +
    +
    Example
    Booleantrue + Saves the current pager page size and number. This option requires the $.tablesorter.storage script in the jquery.tablesorter.widgets.js file (v2.11). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_savePages +
    +
    Example
    String"tablesorter-pager" + Saves tablesorter paging to custom key if defined. Key parameter name used by the $.tablesorter.storage function. Useful if you have multiple tables defined (v2.15) +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_storageKey +
    +
    Example
    BooleanfalseMaintain the height of the table even when fewer than the set number of records is shown (v2.1; updated 2.7.1). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_fixedHeight
    +
    + This option replaced the original positionFixed and offset options which set the absolute position of the pager block.
    +
    + If true, it should maintain the height of the table, even when viewing fewer than the set number of records (go to the last page of any demo to see this in action). It works by adding an empty row to make up the differences in height. +
    +
    Example
    Booleanfalse + If true, child rows will be counted towards the pager set size (v2.13). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_countChildRows
    +
    + *CAUTION* When true, child row(s) may not appear to be attached to its parent row, may be split across pages or + may distort the table if rowspan or cellspans are included within the child row.
    +
    + If this option is false, child row(s) will always appear on the same page as its parent. +
    +
    Booleanfalse + If true, rows are removed from the table to speed up the sort of large tables (v2.0.21). +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_removeRows
    +
    + The original tablesorter plugin (v2.0.5) removed rows automatically, without providing an option. It really does speed up sorting of very large tables, but also breaks updating and modifying table content dynamically.
    +
    + If this option is false, the addon only hides the non-visible rows; this is useful if you plan to add/remove rows with the pager enabled. +
    +
    Example
    String".first" + This option contains a jQuery selector string pointing to the go to first page arrow. See container for full HTML. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_selectors.first +
    +
    Example
    String".prev" + This option contains a jQuery selector string pointing to the go to previous page arrow. See container for full HTML. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_selectors.prev +
    +
    Example
    String".next" + This option contains a jQuery selector string pointing to the go to next page arrow. See container for full HTML. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_selectors.next +
    +
    Example
    String".last" + This option contains a jQuery selector string pointing to the go to last page arrow. See container for full HTML. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_selectors.last +
    +
    Example
    String".gotoPage"This option contains a jQuery selector string pointing to the page select dropdown. See container for full HTML (v2.4; v2.17.3) +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_selectors.gotoPage (changed from goto in v2.17.3)
    +
    + Please note that this select dropdown is initially empty and automatically updated by the plugin with the correct number of pages, which depends on the size setting. +
    +
    Example
    String".pagedisplay"This option contains a jQuery selector string pointing to the output element (v2.0.9) +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_selectors.pageDisplay
    +
    + In the original tablesorter (v2.0.5) this option could only target an input, it was updated (v2.0.9) to display the formatted output from the output option inside of any element (span, div or input). +
    +
    Example
    String".pagesize" + This option contains a jQuery selector string pointing to the page size selector. See container for full HTML. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_selectors.pageSize +
    +
    Example
    String"tablesorter-errorRow"This option contains the class name that is applied to the error information row that is added inside the pager with any ajax exceptions. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_css.errorRow
    +
    + Note there is no period "." in front of this class name (it is not a selector). +
    String"disabled"This option contains the class name that is applied to disabled pager controls. +
    +
    + Note The pager widget equivalent option is within the widgetOptions and accessed via widgetOptions.pager_css.disabled
    +
    + More explicitly, this class is applied to the pager arrows when they are at either extreme of pages and the updateArrows option is true. When the pager has been disabled, this class is applied to all controls.
    +
    + Note there is no period "." in front of this class name (it is not a selector). +
    Removed Options
    Booleanfalse + Filter: This option was removed in v2.15... sorry for the sudden notice. +
    +
    + This option has been replaced by the filter_external option.
    +
    + Show any rows that match a search query. If this option is true any column match will show that row; but there are limitations (v2.13.3).
    +
    + It is best if this filter_anyMatch option is used with a single search input as follows: +
    <input class="search" type="search">
    +<button type="button" class="reset">Reset Search</button>
    +
    $(function(){
    +  $("table").tablesorter({
    +    widgets: ["filter"],
    +    widgetOptions : {
    +      filter_anyMatch : true,
    +      filter_columnFilters: false,
    +      filter_reset: '.reset'
    +    }
    +  });
    +
    +  // Target the $('.search') input using built in functioning
    +  // this binds to the search using "search" and "keyup"
    +  // Allows using filter_liveSearch or delayed search &
    +  // pressing escape to cancel the search
    +  $.tablesorter.filter.bindSearch( $table, $('.search') );
    +
    +});
    +
    String"jui"UiTheme: This option was removed in v2.19.0! + It has been replaced by theme. +

    + This option contains the name of the theme. Currently jQuery UI ("jui") and Bootstrap ("bootstrap") themes are supported (updated v2.4) +

    + * NOTE * only the uitheme widget option was removed. All of the information below is still pertinent and portions have been copied to the core theme option. +

    +

    To modify the class names used, extend from the $.tablesorter.themes variable as follows:

    +
    // Extend the themes to change any of the default class names ** NEW **
    +$.extend($.tablesorter.themes.jui, {
    +  // change default jQuery uitheme icons - find the full list of icons
    +  // here: http://jqueryui.com/themeroller/ (hover over them for their name)
    +  table      : 'ui-widget ui-widget-content ui-corner-all', // table classes
    +  header     : 'ui-widget-header ui-corner-all ui-state-default', // header classes
    +  footerRow  : '',
    +  footerCells: '',
    +  icons      : 'ui-icon', // icon class added to the <i> in the header
    +  sortNone   : 'ui-icon-carat-2-n-s',
    +  sortAsc    : 'ui-icon-carat-1-n',
    +  sortDesc   : 'ui-icon-carat-1-s',
    +  active     : 'ui-state-active', // applied when column is sorted
    +  hover      : 'ui-state-hover',  // hover class
    +  filterRow  : '',
    +  even       : 'ui-widget-content', // even row zebra striping
    +  odd        : 'ui-state-default'   // odd row zebra striping
    +});
    + + This widget option replaces the previous widgetUitheme. All theme css names are now contained within the $.tablesorter.themes variable. Extend the default theme as seen above.
    +
    + + The class names from the $.tablesorter.themes.{name} variable are applied to the table as indicated.
    +
    + + As before the jQuery UI theme applies the default class names of "ui-icon-arrowthick-2-n-s" for the unsorted column, "ui-icon-arrowthick-1-s" for the descending sort and "ui-icon-arrowthick-1-n" for the ascending sort. (Modified v2.1; Updated in v2.4). Find more jQuery UI class names by hovering over the Framework icons on this page: http://jqueryui.com/themeroller/
    +
    + Use the "uitheme" option to change the css class name as follows: +
    $(function(){
    +  $("table").tablesorter({
    +    theme     : 'jui',       // set theme name from $.tablesorter.themes here
    +    widgets   : ["uitheme"], // initialize ui theme styling widget of the table
    +    widgetOptions: {
    +      uitheme : "jui"        // this is now optional in v2.7, it is overridden by the theme option
    +    }
    +  });
    +});
    + + To add a new theme, define it as follows; replace "custom" with the name of your theme: +
    $.tablesorter.themes.custom = {
    +  table      : 'table',       // table classes
    +  header     : 'header',      // header classes
    +  footerRow  : '',
    +  footerCells: '',
    +  icons      : 'icon',        // icon class added to the <i> in the header
    +  sortNone   : 'sort-none',   // unsorted header
    +  sortAsc    : 'sort-asc',    // ascending sorted header
    +  sortDesc   : 'sort-desc',   // descending sorted header
    +  active     : 'sort-active', // applied when column is sorted
    +  hover      : 'hover',       // hover class
    +  filterRow  : 'filters',     // class added to the filter row
    +  even       : 'even',        // even row zebra striping
    +  odd        : 'odd'          // odd row zebra striping
    +}
    +
    Example
    Numeric0 + Pager: This option was removed! +
    +
    + The original tablesorter pager plugin absolutely positioned the pager controls at the bottom of the table. It appears that this option was intended to tweak the position of the pager container. The option exists, but no code was found.
    +
    Booleantrue + Pager: This option was removed! +
    +
    + If this option were true, the original tablesorter pager plugin would absolutely position the pager controls at the bottom of the table.
    +
    String"/" + Pager: This option was removed! Use the output option to allow for more control over the formatting. +
    +
    + The original tablesorter pager plugin would combine the current page with the calculated total number of pages within the cssPageDisplay with this separator string inbetween.
    +
    + + +

    Methods

    + +
    +

    + tablesorter has some methods available to allow updating, resorting or applying widgets to a table after it has been initialized. +
    + TIP! Click on the link in the method column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MethodDescriptionLink
    Use this method to add table rows (v2.0.16; v2.19.0). +
    +
    + It does not work the same as "update" in that it only adds rows, it does not remove them.
    +
    + Also, use this method to add table rows while using the pager plugin. If the "update" method is used, only the visible table rows continue to exist. +
    // Add multiple rows to the table
    +  var row = '<tr><td>Inigo</td><td>Montoya</td><td>34</td>' +
    +    '<td>$19.99</td><td>15%</td><td>Sep 25, 1987 12:00PM</td></tr>',
    +    $row = $(row),
    +    // resort table using true to reapply the current sort; set to false to prevent resort
    +    // if undefined, the resort value will be obtained from config.resort (added v2.19.0)
    +    // As of v2.19.0, the resort variable can contain a new sortList to be applied
    +    // A callback method was added in 2.3.9.
    +    resort = true, // or [[0,0],[1,0]] etc
    +    callback = function(table){
    +      alert('rows have been added!');
    +    };
    +  $('table')
    +    .find('tbody').append($row)
    +    .trigger('addRows', [$row, resort, callback]);
    + In v2.16.1, the $row parameter can be an HTML string, row DOM element or jQuery object. +
    +
    Example
    Use this method reset the table to it's original settings. (v2.17.0). +
    + Using this method will clear out any settings that have changed since the table was initialized (refreshes the entire table); so any sorting or modified widget options will be cleared.
    + However, it will not clear any values that were saved to storage. This method is basically like reloading the page. +
    $('table').trigger('resetToLoadState');
    +
    +
    Use this method to initialize a sort while targeting a specific column header (v2.9). +
    +
    // Target a specific header
    +$('table').find('th:eq(2)').trigger('sort');
    Using this method will maintain the sorting order; so, if the column is already sorted in ascending order, this method will act as if you manually clicked on the header. Whatever sort order is applied is dependent on other option settings such as initialSortOrder, lockedOrder (set within the headers), sortReset option, sortRestart and will be ignored if the column sort is disabled (sorter: false).
    +
    +
    Use this method to sort an initialized table in the desired order (v2.17.0) +
    +
    // Choose a new sort order
    +var sort = [[0,0],[2,0]],
    +    callback = function(table){
    +        alert('new sort applied to ' + table.id);
    +    };
    +// Note that the sort value below is inside of another array (inside another set of square brackets)
    +// without a callback it could look like this:
    +$("table").trigger("sorton", [ [[0,0],[2,0]] ]);
    +
    +// when including a callback method the outer square bracket wrap both parameters (added in 2.3.9).
    +$("table").trigger("sorton", [sort, callback]);
    + *NOTE* using this method to sort ignores the additions from the sortForce and sortAppend options.
    +
    + In v2.17.0, the sort direction can be set using "a" (ascending), "d" (descending), "n" (next), "s" (same) & "o" (opposite). +
    $('table').trigger('sorton', [ [[0,"a"],[2,"n"]] ]);
    + Please try out the demo (example link) to better understand how these values work. +
    +
    Example
    Use this method to reset the table to it's initial unsorted state (v2.4.7; v2.16.0). +
    +
    + This method immediately resets the entire table sort, while the option only resets the column sort after a third click.
    +
    + In v2.16.0, a callback function was added to this method.
    +
    +
    // Reset the table (make it unsorted)
    +var callback = function(table) {
    +	console.log('sort has been reset');
    +};
    +$("table").trigger("sortReset", [callback]);
    + *NOTE* Don't confuse this method with the sortReset option. +
    +
    Example
    / Update the tbody's stored data (update & updateRows do exactly the same thing; v2.19.0) +

    +
    // Add new content
    +$("table tbody").append(html);
    +
    +// let the plugin know that we made a update
    +// the resort flag set to true will trigger an automatic resort using the current sort
    +// if set to false, no new sort will be applied; or set it to any sortList value (e.g. [[0,0]]; new v2.19.0)
    +// A callback method was added in 2.3.9.
    +var resort = true,
    +    callback = function(table){
    +        alert('new sort applied');
    +    };
    +$("table").trigger("update", [resort, callback]);
    +
    +// As of version 2.19.0, if the resort parameter is undefined, the setting from the config.resort will be used
    +
    +// As of version 2.0.14, the table will automatically resort after the update (if the "resort" flag is true
    +// & will use the current sort selection), so include the following if you want to specify a different sort
    +
    +// set sorting column and direction, this will sort on the first and third column
    +var sorting = [[2,1],[0,0]];
    +// method to use prior to v2.19.0
    +// $("table")
    +//  .trigger("update", [ false ])
    +//  .trigger("sorton", [sorting]);
    +// After v2.19.0; do the following to apply a new sort after updating
    +// if sorting is an empty array [], then the sort will be reset
    +$('table').trigger('update', [ sorting ]);
    + NOTE Don't confuse this method with the sortReset option. updateRows was added to work around the issue of using jQuery with the Prototype library. Triggering an "update" would make Prototype clear the tbody; Please see issue #217 for more details. +
    +
    Example
    Update a column of cells (thead and tbody) (v2.8; v2.19.0). +
    +
    // Change thead & tbody column of cells
    +// remember, "eq()" is zero based & "nth-child()" is 1 based
    +$("table thead th:eq(2)").html("Number");
    +// add some random numbers to the table cell
    +$("table tbody").find('td:nth-child(3)').html(function(i,h){
    +  return Math.floor(Math.random()*10) + 1; // random number from 0 to 10
    +});
    +
    +// reapply the current sort if resort = true
    +// do not reapply the current sort if resort = false
    +// if undefined, resort will be obtained from config.resort (added v2.19.0)
    +// as of v2.19.0, apply a new sort if resort = [[0,0]] (or whatever)
    +// or the sort is reset if resort = []
    +var resort = true,
    +  // add a callback, as desired
    +  callback = function(table){
    +    alert('table updated!');
    +  };
    +
    +// let the plugin know that we made a update, then the plugin will
    +// automatically sort the table based on the header settings
    +$("table").trigger("updateAll", [ resort, callback ]);
    +
    Example
    Update the parsers, only if not defined, then update the internal cache (v2.15.4; v2.22.2). +
    +

    In v2.22.2, a new parameter was added to allow passing a jQuery object containing tbodies (for the tbody sorting widget)

    +

    This method is used by the pager (addon & widget) to update the data stored within the cache after the content has been updated using ajax.

    +
    // optional callback function
    +var callback = function( table ){ /* do something */ },
    +	// optional in v2.22.2; defaults to table.config.$tbodies if undefined
    +	$tbodies = $( 'table' ).children( 'tbody' );
    +$("table").trigger("updateCache", [ callback, $tbodies ] );
    +
    Example
    Adds all of the cached table rows back into the table.
    +

    + This method was originally designed to be used with the pager. It should be used under these conditions: +
      +
    • When the pager removeRows option is true.
    • +
    • When not using the "updateCell" or "addRows" methods.
    • +
    • Before manually adding or removing table rows.
    • +
    • And, before triggering an "update".
    • +
    + Note: The entire table is stored in the cache, but when using the pager with the removeRows option set to true, only the visible portion is actually exists within the table. So, use this option to add all stored rows back into the table before manually changing the contents. Otherwise, if any update method is triggered, only the visible rows will be added back to the cache. +
    // how to update the table contents
    +$("table")
    +  .trigger("appendCache")
    +  .append('<tr>...</tr>') // add new row(s), or delete rows
    +  .trigger("update"); // update the cache
    +
    +
    Update a table cell in the tablesorter data (v2.19.0). +
    +
    $(function() {
    +  $("table").tablesorter();
    +
    +  $("td.discount").click(function(){
    +
    +    // Do we want to reapply the current sort on the column?
    +    // see updateRow for other resort settings as of v2.19.0
    +    // if resort is undefined, the value from config.resort (added v2.19.0) will be used
    +    var resort = false,
    +        // Do something after the cell update in this callback function
    +        callback = function(table){
    +          /* do something */
    +        },
    +        // randomize a number & add it to the cell
    +        discount = '$' + Math.round(Math.random() * Math.random() * 100) + '.' +
    +          ('0' + Math.round(Math.random() * Math.random() * 100)).slice(-2);
    +
    +    // add new table cell text
    +    $(this).text(discount);
    +
    +    // update the table, so the tablesorter plugin can update its value
    +    // set resort flag to false to prevent automatic resort (since we're using a different sort below)
    +    // prior to v2.19.0, leave the resort flag as undefined, or with any other value, to automatically resort the table
    +    // new resort values can be set as of v2.19.0 - please see the "updateRow" documentation for more details
    +    // $("table").trigger("updateCell", [this]); < - resort is undefined so the table WILL resort
    +    $("table").trigger("updateCell", [this, resort, callback]);
    +
    +    // As of version 2.0.14, the table will automatically resort (using the current sort selection)
    +    // after the update, so include the following if you want to specify a different sort
    +
    +    // prior to v2.19.0, set sorting column and direction, this will sort on the first and third column
    +    // after v2.19.0, add any new sort to the "resort" variable above
    +    var sorting = [[3,1]];
    +    $("table").trigger("sorton", [sorting]);
    +
    +    return false;
    +  });
    +});
    +
    Example
    Apply the selected widget to the table, but the widget will not continue to be applied after each sort. See the example, it's easier than describing it. +
    +
    $(function(){
    +  // initialize tablesorter without the widget
    +  $("table").tablesorter();
    +
    +  // click a button to apply the zebra striping
    +  $("button").click(function(){
    +    $('table').trigger('applyWidgetId', ['zebra']);
    +    return false;
    +  });
    +
    +});
    +
    Example
    Apply the set widgets to the table (v2.16.0). +
    + This method can be used after a table has been initialized, but it won't work unless you update the configuration settings. See the example, it's easier than describing it. +
    // Update the list of widgets to apply to the table (add or remove)
    +// $("table").data("tablesorter").widgets = ["zebra"]; // works the same as
    +$("table")[0].config.widgets = ["zebra"];
    +
    +// This method applies the widget - no need to keep updating
    +$('table').trigger('applyWidgets');
    +
    +
    Example
    Use this method to remove tablesorter from the table (v2.3.2; v2.16). +
    +
    // Remove tablesorter and all classes
    +$("table").trigger("destroy");
    +
    +// Remove tablesorter and all classes but the "tablesorter" class on the table
    +// callback is a function
    +$("table").trigger("destroy", [false, callback]);
    +
    Refresh the currently applied widgets. Depending on the options, it will completely remove all widgets, then re-initialize the current widgets or just remove all non-current widgets (v2.4; v2.19.0). +

    + Trigger this method using either of the following methods (they are equivalent): +
    // trigger a refresh widget event
    +$('table').trigger('refreshWidgets', [doAll, dontapply]);
    +
    +// Use the API directly
    +$.tablesorter.refreshWidgets(table, doAll, dontapply)
    +
      +
    • If doAll is true it removes all widgets from the table. If false only non-current widgets (from the widgets option) are removed.
    • +
    • When done removing widgets, the widget re-initializes the currently selected widgets, unless the dontapply parameter is true leaving the table widget-less.
    • +
    • Note that if the widgets option has any named widgets, they will be re-applied to the table when it gets resorted. So if you want to completely remove all widgets from the table, also clear out the widgets option $('table')[0].config.widgets = [];
    • +
    +
    +
    Example
    Widget Methods
    filter: Trigger the filter widget to reset the search criteria (v2.7.7). +

    + If you are using the filter_formatter option to add custom input elements, this function may not work on those columns. Please refer to the filter_formatter section for more details. +
    $(function(){
    +  // this is the same code that the "filter_reset" element runs to clear out the filters.
    +  $('button').click(function(){
    +    $('table').trigger('filterReset');
    +    return false;
    +});
    + This method is used by the filter_reset option when defined. +
    +
    Example
    Trigger the saveSort widget to clear any saved sorts for that specific table (v2.7.11). +
    +
    $(function(){
    +  $('button').click(function(){
    +    $('table').trigger('saveSortReset');
    +    return false;
    +  });
    +});
    +
    Pager Methods
    Trigger the pager to change the page size (v2.7.4). +
    +
    $(function(){
    +  $('table').trigger('pageSize', 15);
    +});
    +
    Trigger the pager to change the current page (v2.7.7). +
    +
    + If no value is passed, the pager will reset to page 1; otherwise, pass a "one-based" index of the desired page +
    $(function(){
    +  $('table').trigger('pageSet', 3); // pass a one-based index
    +});
    +
    Trigger the pager to change the current page & size (v2.19.0). +
    +
    + If no value is passed, the pager will reset to page 1 with the original pager size setting; otherwise, pass a "one-based" index of the desired page and the pager size as an array +
    $(function(){
    +  $('table').trigger('pageAndSize', [ 2, 20 ]); // pass a one-based page index & page size
    +});
    +
    Force the pager to update the table with the current settings (v2.19.0). +
    +
    + If there is a need, this method will force the (ajax and non-ajax) pager to update. Use it as follows: +
    $(function(){
    +  $('table').trigger('pagerUpdate');
    +});
    + Or, if you need, you can optionally pass a new page number: +
    $(function(){
    +  $('table').trigger('pagerUpdate', 3); // update and set to page 3
    +});
    +
    +
    Calling this method will reveal the entire table, remove the pager functionality, and hide the actual pager (v2.0.16). +
    +
    $(function(){
    +  $('table').trigger('destroy.pager');
    +});
    + The only way to restore the pager is to re-initialize the pager addon +
    +
    $(function(){
    +  $('table').tablesorterPager(pagerOptions);
    +});
    +
    Example
    This method will put the pager into a disabled state (v2.0.21.2). +
    +
    + The disabled state will reveal all table rows and disable, but not hide, pager controls. +
    +
    $(function(){
    +  $('table').trigger('disable.pager');
    +});
    +
    Example
    This method will re-enable the pager, but only from the disabled state (v2.0.21.2). +
    +
    $(function(){
    +  $('table').trigger('enable.pager');
    +});
    +
    Example
    + + +

    Events

    + +
    +

    + tablesorter has some methods available to allow updating, resorting or applying widgets to a table after it has been initialized. +
    + TIP! Click on the link in the event column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    EventDescriptionLink
    This event fires when tablesorter has completed initialization. (v2.2). +
    +
    $(function(){
    +
    +  // bind to initialized event BEFORE initializing tablesorter*
    +  $("table")
    +    .bind("tablesorter-initialized",function(e, table) {
    +      // do something after tablesorter has initialized
    +    });
    +
    +  // initialize the tablesorter plugin
    +  $("table").tablesorter({
    +    // this is equivalent to the above bind method
    +    initialized : function(table){
    +      // do something after tablesorter has initialized
    +    }
    +  });
    +
    +});
    * Note: bind to all initialization events before initializing tablesorter; because most of the time, if bound after, the events will fire before the binding occurs.
    +
    This event fires immediately before tablesorter begins resorting the table. +
    +
    $(function(){
    +
    +  // initialize the tablesorter plugin
    +  $("table").tablesorter();
    +
    +  // bind to sort events
    +  $("table").bind("sortBegin",function(e, table) {
    +    // do something crazy!
    +  });
    +});
    +
    This event fires immediately after the tablesorter header has been clicked, initializing a resort. +
    +
    $(function(){
    +
    +  // initialize the tablesorter plugin
    +  $("table").tablesorter();
    +
    +  // bind to sort events
    +  $("table")
    +    .bind("sortStart",function(e, table) {
    +      $("#overlay").show();
    +    })
    +    .bind("sortEnd",function(e, table) {
    +      $("#overlay").hide();
    +    });
    +});
    +
    Example
    This event fires when tablesorter has completed resorting the table. +
    +
    $(function(){
    +
    +  // initialize the tablesorter plugin
    +  $("table").tablesorter();
    +
    +  // bind to sort events
    +  $("table")
    +    .bind("sortStart",function(e, table) {
    +      $("#overlay").show();
    +    })
    +    .bind("sortEnd",function(e, table) {
    +      $("#overlay").hide();
    +    });
    +});
    +
    Example
    This event fires after tablesorter has completed updating (v2.3.9). +
    + This occurs after an "update", "updateAll", "updateCell" or "addRows" method was called, but before any callback functions are executed. +
    $(function(){
    +
    +  // initialize the tablesorter plugin
    +  $('table')
    +    .tablesorter()
    +    // bind to sort events
    +
    +    .bind('updateComplete', function(e, table) {
    +      // do something after the table has been altered;
    +    });
    +
    +});
    +
    This event fires after tablesorter has completed executing the refreshWidget method (v2.19.0) +
    +
    + Use it as follows: +
    $(function(){
    +
    +  // initialize the tablesorter plugin
    +  $('table')
    +    .tablesorter()
    +    // bind to sort events
    +    .bind('refreshComplete', function(e, table) {
    +      // do something after the 'refreshWidgets' has refreshed
    +    });
    +
    +});
    +
    Widget Events
    Event triggered when the filter widget has finished initializing (v2.4). +

    + You can use this event to modify the filter elements (row, inputs and/or selects) as desired. Use it as follows:
    $(function(){
    +  $('table')
    +
    +    // bind to filter initialized event BEFORE initializing tablesorter*
    +    .bind('filterInit', function(){
    +      $(this).find('tr.tablesorter-filter-row').addClass('fred');
    +    })
    +
    +     // initialize the sorter
    +    .tablesorter({
    +      widgets : ['filter']
    +    });
    +
    +});
    * Note: bind to all initialization events before initializing tablesorter; because most of the time, if bound after, the events will fire before the binding occurs.
    +
    Example
    Event triggered when the filter widget has started processing the search (v2.4). +

    + You can use this event to do something like add a class to the filter row. Use it as follows:
    $(function(){
    +  $('table').bind('filterStart', function(){
    +    $(this).find('tr.tablesorter-filter-row').addClass('filtering');
    +  });
    +});
    +
    Example
    Event triggered when the filter widget has finished processing the search (v2.4). +

    + You can use this event to do something like remove the class added to the filter row when the filtering started. Use it as follows:
    $(function(){
    +  $('table').bind('filterEnd', function(event, config){
    +    $(this).find('tr.tablesorter-filter-row').removeClass('filtering');
    +  });
    +});
    +
    Example
    Event triggered when the stickyHeader widget has finished initializing (v2.10.4). +

    + You can use this event to do something like modify content within the sticky header:
    $(function(){
    +  $('table')
    +    // bind to the init event BEFORE initializing tablesorter*
    +    .bind('stickyHeadersInit', function(){
    +      // this.config.widgetOptions.$sticky contains the entire sticky header table
    +      this.config.widgetOptions.$sticky.find('tr.tablesorter-headerRow').addClass('sticky-styling');
    +    })
    +
    +  // initialize the tablesorter plugin
    +  .tablesorter({
    +    widgets : ['stickyHeaders']
    +  });
    +
    +});
    * Note: bind to all initialization events before initializing tablesorter; because most of the time, if bound after, the events will fire before the binding occurs.
    +
    Pager Events
    This event fires when the pager plugin begins to render the table on the currently selected page. (v2.0.7). +
    +
    $(function(){
    +
    +  // initialize the sorter
    +  $("table")
    +    .tablesorter()
    +
    +    // initialize the pager plugin
    +    .tablesorterPager({
    +      container: $("#pager")
    +    })
    +
    +    // bind to pager events
    +    .bind('pagerChange pagerComplete', function(event, options){
    +      // options = table.config.pager (pager addon)
    +      // options = table.config (pager widget) - so use options.pager.page below
    +      // c.totalPages contains the total number of pages
    +      $('#display').html( event.type + " event triggered, now on page " + (options.page + 1) );
    +    });
    +
    +});
    +
    Example
    This event fires when the pager plugin has completed initialization (v2.18.1), and its render of the table on the currently selected page. (v2.0.7). +
    +
    + Note In v2.18.1, the "pagerComplete" event also fires off immediately after pager initialization.
    +
    +
    $(function(){
    +
    +  // initialize the sorter
    +  $("table")
    +    .tablesorter()
    +
    +    // initialize the pager plugin
    +    .tablesorterPager({
    +      container: $("#pager")
    +    })
    +
    +    // bind to pager events
    +    .bind('pagerChange pagerComplete', function(event, options){
    +      // options = table.config.pager (pager addon)
    +      // options = table.config (pager widget) - so use options.pager.page below
    +      // c.totalPages contains the total number of pages
    +      $('#display').html( event.type + " event triggered, now on page " + (options.page + 1) );
    +    });
    +
    +});
    +
    Example
    This event fires after all pager controls have been bound and set up but before the pager formats the table or loads any ajax data (v2.4.4). +
    +
    $(function(){
    +
    +  $("table")
    +
    +    // bind to pager initialized event BEFORE calling the ADDON
    +    // or BEFORE initializing tablesorter when using the pager WIDGET*
    +    .bind('pagerBeforeInitialized', function(event, options){
    +      // options = table.config.pager (pager addon)
    +      // options = table.config (pager widget)
    +
    +      // event = event object; options = pager options
    +    })
    +
    +    // initialize the sorter
    +    .tablesorter()
    +
    +    // initialize the pager plugin
    +    .tablesorterPager({
    +      container: $("#pager")
    +    });
    +
    +});
    * Note: bind to all initialization events before initializing tablesorter; because most of the time, if bound after, the events will fire before the binding occurs.
    +
    This event fires when the pager plugin has completed initialization (v2.4.4). +
    +
    $(function(){
    +
    +  $("table")
    +
    +    // bind to pager initialized event BEFORE calling the ADDON
    +    // or BEFORE initializing tablesorter when using the pager WIDGET*
    +    .bind('pagerInitialized', function(event, options){
    +      // options = table.config.pager (pager addon)
    +      // options = table.config (pager widget) - so use options.pager.page below
    +      // c.totalPages contains the total number of pages
    +      $('#display').html( e.type + " event triggered, now on page " + (options.page + 1) );
    +    })
    +
    +    // initialize the sorter
    +    .tablesorter()
    +
    +    // initialize the pager plugin
    +    .tablesorterPager({
    +      container: $("#pager")
    +    });
    +
    +});
    * Note: bind to all initialization events before initializing tablesorter; because most of the time, if bound after, the events will fire before the binding occurs.
    +
    Example
    This event fires when the pager plugin begins to change to the selected page (v2.4.4). +
    + This event may fire before the pagerComplete event when ajax processing is involved, or after the pagerComplete on normal use. + See issue #153. +
    $(function(){
    +
    +  // initialize the sorter
    +  $("table")
    +    .tablesorter()
    +
    +    // initialize the pager plugin
    +    .tablesorterPager({
    +      container: $("#pager")
    +    })
    +
    +    // bind to pager events
    +    .bind('pageMoved', function(event, options){
    +      // options = table.config.pager (pager addon)
    +      // options = table.config (pager widget) - so use options.pager.page below
    +      // c.totalPages contains the total number of pages
    +      $('#display').html( event.type + " event triggered, now on page " + (options.page + 1) );
    +    });
    +
    +});
    +
    Example
    + + +

    Tablesorter API

    + +
    + tablesorter has some useful internal variables & functions available through the API which can be used in custom coding, parsers and/or widgets.
    + +

    Variables

    + TIP! Click on the link in the variable column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    VariableTypeDescriptionLink
    ArrayThis is an array of all parser objects added using the addParser function. +
    +
    + If a specific parser needs to be retreived from this array, use the getParserById function. +
    +
    $.tablesorter.themesObjectThis is an object containing a list of specific class names to be applied to table elements. Please see the widget uitheme option for more details.
    ArrayThis is an array of all widget objects added using the addWidget function. +
    +
    + If a specific widget needs to be retreived from this array, use the getWidgetById function. +
    +
    ObjectThis object contains the phrases (in English by default) added to the aria-label on each header column.
    +
    +
    + This is how the object is set up: +
    $.tablesorter.language = {
    +  sortAsc  : 'Ascending sort applied, ',
    +  sortDesc : 'Descending sort applied, ',
    +  sortNone : 'No sort applied, ',
    +  nextAsc  : 'activate to apply an ascending sort',
    +  nextDesc : 'activate to apply a descending sort',
    +  nextNone : 'activate to remove the sort'
    +};
    + So, as an example, in the following situation: +
      +
    • A table header is named "Account #"
    • +
    • This column has an ascending sort applied
    • +
    • The next click on the header will be a descending sort, which means: +
        +
      • sortInitialOrder option has its default setting; so the sort order will switch from ascending to descending on the second click.
      • +
      • No lockedOrder is set within the headers option
      • +
      +
    • +
    + Then the label will be built as follows: +
    // "Header Name" + $.tablesorter.language.sortAsc + $.tablesorter.language.nextDesc
    +"Account #: Ascending sort applied, activate to apply a descending sort"
    + If the next click were to reset the sort (sortReset applied), then the message would use $.tablesorter.language.nextNone.
    +
    + Use this variable to change the language as follows: +
    $(function(){
    +
    +  $.tablesorter.language = {
    +    sortAsc  : "sorting from a to z, ",
    +    sortDesc : "sorting from z to a, ",
    +    sortNone : "not sorted, but ",
    +    nextAsc  : "click to sort from a to z",
    +    nextDesc : "click to sort from z to a",
    +    nextNone : "click to clear the sort"
    +  }
    +  $("table").tablesorter();
    +});
    +
    +
    ObjectThis variable contains all instance methods of the config object. Added using addInstanceMethods function before table initialization (v2.21.0). +
    +
    +
    $.tablesorter.addInstanceMethods({
    +  columnSum: function(colNumber) {
    +    var sum = 0, tbodyIndex, normalizedRows, rowIndex;
    +    // `this` refers to config object
    +    for (tbodyIndex = 0; tbodyIndex < this.$tbodies.length; ++tbodyIndex) {
    +      normalizedRows = this.cache[tbodyIndex].normalized;
    +      for (rowIndex = 0; rowIndex < normalizedRows.length; ++rowIndex) {
    +        sum += normalizedRows[rowIndex][colNumber];
    +      }
    +    }
    +    return sum;
    +  },
    +  columnMean: function(colNumber) {
    +    return this.columnSum(colNumber) / this.totalRows;
    +  },
    +});
    +
    +$('table').tablesorter();
    +c = $('table')[0].config;
    +console.log('sum of third column: ' + c.columnSum(2));
    +console.log('mean of third column: ' + c.columnMean(2));
    +
    +
    Access the table configuration variables (config) using any of these methods: +
    +
    +
    // pure js, get the first table (zero index)
    +var config = document.getElementsByTagName('table')[0].config;
    +// or by table ID
    +var config = document.getElementById('mytable').config;
    +
    +// using jQuery, get first table (zero index)
    +var config = $('table')[0].config;
    +// or from the jQuery data
    +var config = $('#mytable').data('tablesorter');
    +
    +
    +
    ObjectInternal list of table contents (v2.0.18; v2.20.0 ) +
    +
    + This object contains the following:
    +
      +
    • tbody index (non-info block only, indexing now matches the config.$tbodies variable; v2.20.0) +
        +
      • colMax +
          +
        • This contains an array of the absolute value maximum numerical value for each "numerically" parsed column per tbody.
        • +
        • Text columns will have an undefined value in this array.
        • +
        • Used when determining how to sort text within a numeric column.
        • +
        • Access it as follows:
          // $('table')[0].config.cache[tbodyIndex].colMax[column];
          +// try this in the console for this page:
          +$('.tablesorter')[0].config.cache[0].colMax;
          +// result: [undefined × 3, 45, 153.19, 44.7, 100.9, 1169133120000]
        • +
        +
      • +
      • normalized +
          +
        • This contains an array of indexed table rows.
        • +
        • Within each row is an array of extracted, then parsed table contents for each column (plus one extra value; see the next comment).
        • +
        • It is important to note that the last value in the column array is the original row index value. This is used when resetting a column sort to its original unsorted order.
        • +
        • In v2.19.1, the raw unparsed data was added to the row data.
        • +
        • In v2.16.0, the last value in the column array is now an object which contains a jquery object of the row, index of the original unsorted order and a child array which contains raw html from any associated child row +
          // $('table')[0].config.cache[tbodyIndex].normalized[row][column]
          +// try this in the console for this page:
          +$('.tablesorter')[0].config.cache[0].normalized[0];
          +/* result: ["a1", "bruce", "almighty", 45, 153.19, 44.7, 77, 979830720000, {
          +    $row  : jQuery.fn.jQuery.init[1], // row (jQuery object)
          +    child : [], // child row raw html, if any
          +    // raw unparsed data from the table cells - added v2.19.1
          +    raw   : ["A1", "Bruce", "Almighty", "45", "$153.19", "44.7%", "+77", "Jan 18, 2001 9:12 AM"],
          +    order : 3   // original row index (unsorted)
          +}]
          +*/
          + to specifically target the extra row data, use this method: +
          var config = $('.tablesorter')[0].config,
          +    dataIndex = config.columns, // number of columns within the table
          +    rowData = config.cache[tbodyIndex].normalized[row][ dataIndex ];
          +
        • +
        • Note that all text values will be in lower case if the ignoreCase option is true.
        • +
        • This internal normalized content is what is actually sorted for maximum performance.
        • +
        +
      • +
      • row (removed in v2.16.0) +
          +
        • Well not removed, but moved into the row data, within the normalized section of the cache as described above.
        • +
        • This contains an array of jQuery row objects.
        • +
        • These rows are never in sort order, and are used when updating the table after sorting the normalized content. The indexing of these rows is cross-referenced within the normalized values - the extra column value within the row array. Hopefully that makes sense.
        • +
        +
      • +
      +
    • +
    + The table.config.cache variable is useful when writing widgets that need access to the parsed content. +
    +
    NumericInternal count of the number of table columns in the header (v2.12) +
    +
    + This number is stored as a length (one-based), and takes into account any colspan and rowspan within the table head.
    +
    + Note that the table.config.columns variable does not always correlate with the indexing of the headers stored within table.config.$headers because of multiple rows and column or row spans. +
    +
    ArrayInternal list of each header's starting HTML (as text) (v2.8) +

    + This HTML snapshot is taken using the $headers jQuery object, and done before the headerTemplate is applied and before the onRenderTemplate and onRenderHeader callbacks are executed.
    +
    + This list is used by the $.tablesorter.restoreHeaders function to restore the table headers when the destroy method is executed. +
    +
    ArrayInternal list of each header element as selected using jQuery selectors in the selectorHeaders option. +
    +
    + This list contains DOM elements (not jQuery objects of each table header cell like the $headers variable) and is how the original version of tablesorter stored these objects. +
    + It is not used in the current version of tablesorter, and is only left in place for backwards compatibility with widgets written for the original tablesorter plugin. +
    +
    ArrayInternal list of all of the table's currently set parsers (objects copied from $.tablesorter.parsers). Here is a complete list of default parsers: +
    +
    + + + + + + + + + + + + + + + +
    parser: falsedisable parsing for this column (this also disables sorting & filtering for the column; v2.17.6).
    sorter: falsedisable sort for this column.
    sorter: "text"Sort alpha-numerically.
    sorter: "digit"Sort numerically.
    sorter: "currency"Sort by currency value (supports "£$€¤¥¢").
    sorter: "image"Sort by image alt value (see imgAttr option).
    sorter: "ipAddress"Sort by IP Address; Warning This parser was moved to the parser-network.js file in v2.18.0.
    sorter: "url"Sort by url.
    sorter: "isoDate"Sort by ISO date (YYYY-MM-DD or YYYY/MM/DD; these formats can be followed by a time).
    sorter: "percent"Sort by percent.
    sorter: "usLongDate"Sort by date (U.S. Standard, e.g. Jan 18, 2001 9:12 AM or 18 Jan 2001 9:12 AM (new in v2.7.4)).
    sorter: "shortDate"Sort by a shortened date (see dateFormat; these formats can also be followed by a time).
    sorter: "time"Sort by time (23:59 or 12:59 pm).
    sorter: "metadata"Sort by the sorter value in the metadata - requires the metadata plugin.

    + Check out the headers option to see how to use these parsers in your table (example #1).
    Or add a header class name using "sorter-" plus the parser name (example #2), this includes custom parsers (example #3). +
    +
    + 1 + 2 + 3 +
    ArrayInternally stored Array of headers that represent each column (v2.21.0) +
    +
    + The table.config.$headers variable contains ALL header cells, not all of which contain sorting information (data-attributes, class names or sorting information). +

    + This variable targets the last sortable header cell in a particular column; unless an entire column is completely unsortable (checkbox column), then it just picks the last cell in that column. +

    + To make that description less confusing, look at the HTML in the config.$headers documentation, only the four middle rows (header-index 1-4) will be contained within this variable: +
    // the resulting config.$headerIndexed for the HTML example in config.$headers will look like this:
    +console.log( table.config.$headerIndexed );
    +/* outputs : [
    +  $('<th data-column="0">header-index 1</th>'),
    +  $('<th data-column="1">header-index 2</th>'),
    +  $('<th data-column="2">header-index 3</th>'),
    +  $('<th data-column="3">header-index 4</th>')
    +] */
    +

    + * NOTE * This variable contains an array of jQuery objects, it is not a collection of jQuery objects, i.e. +
    var $column = table.config.$headerIndexed[ 0 ]; // jQuery object returned
    +console.log( $column.hasClass('foo') ); // how to access information
    +
    +var $headers = $( table.config.$headerIndexed ); // make a collection of jQuery objects
    +// then use collection manipulation functions
    +$headers.each(function(){
    +  console.log( $(this).text() );
    +});
    +
    jQuery ObjectInternal list of all table header cells (v2.8) +
    +

    + *NOTE* The header cells within rows with the cssIgnoreRow class (default is "tablesorter-ignoreRow" will not be included in this variable.

    +

    Header cells in not-ignored rows are targeted using the jQuery selector from the selectorHeaders option

    + Please note that the headers cells are simply an array of targetted header cells and should not be targeted using a column index. For example, given the following table thead markup, the header-index counts the header th cells and does not actually match the data-column index when extra rows and/or colspan or rowspan are included in any of the header cells: +
    <thead>
    +	<tr>
    +		<th colspan="4" data-column="0" class="sorter-false">header-index 0</th>
    +	</tr>
    +	<tr>
    +		<th data-column="0">header-index 1</th>
    +		<th data-column="1">header-index 2</th>
    +		<th data-column="2">header-index 3</th>
    +		<th data-column="3">header-index 4</th>
    +	</tr>
    +	<!-- the next row WILL NOT be included in the config.$headers variable -->
    +	<tr class="tablesorter-ignoreRow">
    +		<th colspan="2" data-column="0">This cell is not included in the config.$headers</th>
    +		<th colspan="2" data-column="2">This cell is not included in the config.$headers</th>
    +	</tr>
    +	<tr>
    +		<th colspan="2" data-column="0" class="sorter-false">header-index 5</th>
    +		<th colspan="2" data-column="2" class="sorter-false">header-index 6</th>
    +	</tr>
    +</thead>
    + So, in the above example, to target the header cell in the second table column (data-column index of 1), use the following code: table.config.$headers.filter('[data-column="1"]') or table.config.$headers.eq(2).
    +
    + The table.config.$headers variable is useful within callback functions or when writing widgets that target the table header cells. +
    +
    DOM elementInternally stored DOM table element (v2.17.5) +
    +
    + The table.config.table variable is useful when certain callback functions only pass the config object; originally you could use config.$table[0], but this saves that small extra trouble. +
    +
    jQuery ObjectInternally stored jQuery object of the table (v2.7.1) +
    +
    + The table.config.$table variable is useful within callback functions or when writing widgets that target the table. +
    +
    jQuery ObjectInternally stored jQuery object of table non-info block tbodies (v2.7.1) +
    +
    + jQuery object of sortable tbodies.
    +
    + Caution! These tbodies are the ones without a class name from the cssInfoBlock option, so the indexing of this jQuery object does not match the actual table tbody indexes.
    +
    + The table.config.$tbodies variable is useful within callback functions or when writing widgets that target the table. +
    +
    BooleanBoolean value indicating that tablesorter has been initialized on a table +
    +
    + This variable is not stored within the config, as the config would not be defined (an alternative method of determining if tablesorter has been initialized).
    +
    + Access it as follows: $('table')[0].hasInitialized. It is true while tablesorter is active on a table, and false if tablesorter was destroyed. +
    +
    NumericThis variable contains the total number of rows within the table, not including rows within info-only tbodies (v2.17.4; v2.17.5) +
    +
    + Access this internal value after tablesorter has initialized. It is also included as a variable in the filterEnd event so you can update an external count like this: +
    $('table').bind('filterInit filterEnd', function(event, data){
    +    // use data.filteredRows or this.config.filteredRows
    +    $('.filter-rows').html( data.filteredRows );
    +    $('.total-rows').html( data.totalRows );
    +});

    + If using the pager plugin or widget, the value returned from the filterEnd event will not be accurate, so you'll need to bind to the pagerComplete event instead: +
    $('table').bind('filterInit filterEnd pagerComplete', function(event, data){
    +    // Note: data = table.config (filterEnd event); and data = table.config.pager (pagerComplete event)
    +    // both objects contain data.filteredRows & data.totalRows
    +    $('.filter-rows').html( data.filteredRows );
    +    $('.total-rows').html( data.totalRows );
    +});
    +
    +
    Access the widgetOptions (wo) using any of these methods: +
    +
    +
    // pure js, get the first table (zero index)
    +var wo = document.getElementsByTagName('table')[0].config.widgetOptions;
    +// or by table ID
    +var wo = document.getElementById('mytable').config.widgetOptions;
    +
    +// using jQuery, get first table (zero index)
    +var wo = $('table')[0].config.widgetOptions;
    +// or from the jQuery data
    +var wo = $('#mytable').data('tablesorter').widgetOptions;
    +
    +
    +
    jQuery ObjectOnly available when the filter widget is active. This variable contains all external search inputs with data-column="all", bound using the bindSearch function. +
    +
    + The table.config.widgetOptions.filter_$anyMatch variable contains one more more search inputs, and is dynamically updated if the bindSearch function is called; make sure to set the flag to force a new search so that the values of the altered filters is updated appropriately. +
    +
    jQuery ObjectOnly available when the filter widget is active. This variable contains all table cells within the filter row. +
    +
    + Use the table.config.$filters variable when access to filters is needed. Note! This variable contains the table cell and not the actual input because the filter_formatter function allows adding other types of value selectors (e.g. jQuery UI slider). +
    +
    jQuery ObjectOnly available when the filter widget is active. This variable contains all external search inputs bound using the bindSearch function. +
    +
    + The table.config.widgetOptions.filter_$externalFilters variable contains an array of jQuery objects pointing to all external inputs, even if the bindSearch function is used multiple times. +
    +
    wo.filter_initializedBooleanOnly available when the filter widget is active. This variable is true once the filter widget has initialized; it is undefined otherwise.
    NumericOnly available when the filter widget is active. This variable contains the current number of filtered rows (v2.17.4; v2.17.5) +
    +
    + This internal value will show an accurate number of filtered rows; which means the count won't include any rows from "information-only" tbodies.
    +
    + Access this internal value at any time after the filter widget has initialized, or as a shortcut it is included as a variable in the filterEnd event so you can update an external count like this: +
    $('table').bind('filterInit filterEnd', function(event, data){
    +    // use data.filteredRows or this.config.filteredRows
    +    $('.filter-rows').html( data.filteredRows );
    +    $('.total-rows').html( data.totalRows );
    +});

    + If using the pager plugin or widget, the value returned from the filterEnd event will not be accurate, so you'll need to bind to the pagerComplete event instead: +
    $('table').bind('filterInit filterEnd pagerComplete', function(event, data){
    +    // Note: data = table.config (filterEnd event); and data = table.config.pager (pagerComplete event)
    +    // both objects contain data.filteredRows & data.totalRows
    +    $('.filter-rows').html( data.filteredRows );
    +    $('.total-rows').html( data.totalRows );
    +});
    +
    +
    jQuery ObjectOnly available when the stickyHeaders widget (not the css3 version) is active. +
    +
    + The table.config.widgetOptions.$sticky variable contains a jQuery object pointing to a cloned table containing the sticky header. The table contained within this variable has a class name of "containsStickyHeaders" versus the original table with a class name of "hasStickyHeaders". +
    +
    Access the pager options (p) using any of these methods: +
    +
    +
    // pure js, get the first table (zero index)
    +var p = document.getElementsByTagName('table')[0].config.pager;
    +// or by table ID
    +var p = document.getElementById('mytable').config.pager;
    +
    +// using jQuery, get first table (zero index)
    +var p = $('table')[0].config.pager;
    +// or from the jQuery data
    +var p = $('#mytable').data('tablesorter').pager;
    +
    + These methods are the same for both the pager addon and the pager widget. +

    +*NOTE* This pager variable also contains all of the default pager option settings. +

    +*NOTE* When using the pager widget, changing a value within the widgetOptions for the pager may not update the pager as expected. The pager widget uses most of the values within config.pager instead of the pager widgetOptions after initialization. +
    +
    jQuery ObjectContains a jQuery object pointing to a pager block(s). +
    +
    + The table.config.pager.$container variable is targeted using the pager container option and will have a class name of "tablesorter-pager" applied.
    +
    + The container(s) may include the pager navigation arrows, page size selector, page selector and/or output block; the contents are completely customizable and all components are optional. +
    +
    jQuery ObjectContains a jQuery object pointing to an empty select within the pager block(s). +
    +
    + The table.config.pager.$goto variable is targeted using the pager cssGoto option.
    +
    + The contents of this select element are dynamically updated if the page size is changed or if the table gets filtered. +
    +
    jQuery ObjectContains a jQuery object pointing to a select with the desired page size settings already in place. +
    +
    + The table.config.pager.$size variable is targeted using the pager cssPageSize option.
    +
    + The contents of this select element must be set up with the desired page size settings before initializing tablesorter.
    +
    + Also, because Internet Explorer does not appear to get the select value from the option text, please include a value attribute with all options. For example: +
    <select class="pagesize">
    +  <option value="10">10</option>
    +  <option value="20">20</option>
    +  <option value="30">30</option>
    +  <option value="40">40</option>
    +</select>
    +
    +
    ArrayContains an array of zero-based row indexes of rows that currently displayed within the table. +
    +
    + For example, if you want to get the parsed values for the rows currently displayed within the pager, use the table.config.pager.cacheIndex variable as follows: +
    var c = $('table')[0].config,
    +	p = c.pager,
    +	cache = c.cache[0].normalized,
    +	cachedValues = [];
    +$.each( p.cacheIndex, function(i, v) {
    +	// cache[v] will be an array of parsed values for each cell in selected row
    +	cachedValues.push( cache[v] );
    +});
    + the p.cacheIndex variable get updated whenever the table is sorted, filtered or the pager changes pages or page size. +
    +
    NumericContains a one-based index of the first row visible in the pager. +
    +
    + The {startRow} tag in the pager output option is replaced by this value; and it does not correspond to the row index within the cache. +
    +
    NumericContains a one-based index of the last row visible in the pager. +
    +
    + The {endRow} tag in the pager output option is replaced by this value; and it does not correspond to the row index within the cache. +
    +
    NumericContains the page count, determined by the page size setting, after the table is filtered. It equals the totalPages if no filters are applied. +
    +
    + The {filteredPages} tag in the pager output option is replaced by this value. +
    +
    NumericContains the number of rows accessible by the pager after the table is filtered. It equals the totalRows if no filters are applied. +
    +
    + The {filteredRows} tag in the pager output option is replaced by this value. +
    +
    NumericContains a one-based index of the current page visible in the pager. +
    +
    + The {page} tag in the pager output option is replaced by this value.
    +
    + Initially, this value is set by either the pager page option or from local storage if the savePages option is true. It is then updated by user interaction with the page selector (targeted by the cssGoto option or programmically by the pageSet or pageAndSize method. +
    +
    NumericContains the currently selected page size. +
    +
    + Initially, this value is set by either the pager size option or from local storage if the savePages option is true. It is then updated by user interaction with the size selector (targeted by the cssPageSize option or programmically by the pageSize or pageAndSize method. +
    +
    NumericContains the total page count as determined by the page size setting. +
    +
    + The {totalPages} tag in the pager output option is replaced by this value. +
    +
    NumericContains the total number of rows within the table +
    +
    + The {totalRows} tag in the pager output option is replaced by this value. +
    +
    Removed Variables
    jQuery ObjectInternal list of all extra table header cells (v2.16.2; removed v2.21.3) +
    +

    This variable was removed due to it causing memory leak issues. To now find extra headers use config.namespace as follows:

    +
    $( config.namespace + '_extra_headers' )
    +

    When the bindEvents function is used, the extra (external) header cells are added to this variable, and automatically updated with the table headers (config.$headers).

    +

    So, when writing a custom widget that clones the table header, there is no longer a need to update the header class names, it's all done automatically.

    +
    +
    jQuery ObjectInternal list of all extra (cloned) table elements (v2.19.0; removed v2.21.3) +
    +

    This variable was removed due to it causing memory leak issues. To find extra tables use config.namespace as follows:

    +
    $( config.namespace + '_extra_table' )
    +

    Some widgets need to duplicate parts of the original table to provide functionality (e.g. stickyHeaders, scroller). This saved variable will either not exist or contain a jQuery object pointing to the cloned table elements.

    +

    This variable was added for the uitheme widget to allow dynamic updating of themes to the original table as well as all cloned parts.

    +
    +
    + +
    +

    Functions

    + TIP! Click on the link in the function column to reveal full details (or toggle|show|hide all) or double click to update the browser location. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FunctionDescription
    Core Functions
    This function adds a colgroup element to the table when widthFixed is true. +

    + A new colgroup with col elements is only added if: +
      +
    • widthFixed is true.
    • +
    • A predefined colgroup element does not already exist in the table *.
    • +
    + * Note If a colgroup was added by the plugin, calling this function additional times will refresh the set widths
    +
    + Also, the col elements within the colgroup are set with a percentage width to dynamically maintain the fixed column width ratios.
    +
    + Use it as follows: +
    $.tablesorter.fixColumnWidth( table );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    +
    +
    + This function detaches the targeted tbody from the DOM to allow faster manipulation of the tbody contents (v2.4). +
    + Use it as follows: +
    $.tablesorter.processTbody( table, $(tbody), getIt );
    +
      +
    • table - table DOM element (or jQuery object) of table containing the tbody.
    • +
    • $(tbody) - tbody jQuery object.
    • +
    • getIt - Boolean flag (optional if false).
    • +
    + When calling the function, to get a tbody, set the getIt boolean parameter to true and the removed tbody is returned; setting this option to false or optionally not including it will restore the tbody. +
    + Here is a basic example of how this function is used: +
    var tbodyIndex, _tbody,
    +	table = $('#my-table')[0],
    +	tbodies = table.tBodies, // use table.config.$tbodies for all tbodies EXcluding information only tbodies
    +for (tbodyIndex = 0; tbodyIndex < tbodies.length; tbodyIndex++) {
    +	// detach tbody from table
    +	_tbody = $.tablesorter.processTbody( table, tbodies[tbodyIndex], true );
    +	// do something magical to the tbody
    +	_tbody.addClass('unicorn');
    +	// restore tbody
    +	$.tablesorter.processTbody( table, _tbody );
    +}
    + Please note that completely detaching the tbody was found to be a much quicker method of manipulating DOM elements than just hiding the tbody; this is especially true in older browsers. +
    +
    This function adds the processing (indeterminant loading icon) to specific or all header cells while processing table elements (v2.4). +

    + Use it as follows: +
    $.tablesorter.isProcessing( table, toggle, $ths );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • toggle - Boolean flag.
    • +
    • $ths - jQuery object of targeted header cells (optional; if excluded all header cells are targeted).
    • +
    + When calling the function, set the toggle option to add (true) or remove (false) process indicators. Include any specific header cells within the $ths variable with which to add the process indicator. When $ths is not defined and a sort is applied, the currently sorted header cells will show process indicators.
    +
    + All this function does is add or remove a class name of "tablesorter-processing" and the class name contained within the cssProcessing option.
    +
    + Here is a basic example of how this function is used: +
    $('table').bind('sortBegin sortEnd', function(event, table){
    +	// this is included with the basic functionality of tablesorter
    +	$.tablesorter.isProcessing( this, event === 'sortBegin' );
    +});
    + Please note that currently the processing icons do not animate (see issue #158). This is due to javascript being a single-threaded, meaning it only does one task at a time, and maximizing the sorting script. So lots of processing is needed to sort & rebuild the table and thus it has no time for animation. If someone knows of a better solution, please share! +
    +
    This function empties ALL of the table tbodies (v2.17.2). +

    + Use it as follows: +
    $.tablesorter.clearTableBody( table );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    + Please note that this function uses jQuery empty(). All data & event handlers are removed. No where within the tablesorter script or included widgets is this function used, it is left intact for backwards compatibility. +
    +
    This function adds header event listeners to the targeted cells (v2.8; v2.16.2). +

    + Use it as follows: +
    $.tablesorter.bindEvents( table, $headers );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • $headers - jQuery object of targeted cells.
    • +
    + This function allows you to bind the same header event listeners to external headers cells (usually clones of the original table). This includes the triggered sort event, left click (only) to sort, ignoring long clicks (> 250ms), pressing enter to trigger a sort (must have focus and a tabindex attribute) and cancelling selection of text (if the option is set).
    +
    + To ensure the columns match the original table, include data-column attributes pointing to the desired column.
    +
    + Here is a basic example of how this function is used: +
    var $table = $('table'),
    +	// make a copy of the table
    +	$clonedTable = $table.clone().addClass('clonedTable').insertAfter($table);
    +// remove stuff we don't need in the clone
    +$clonedTable.find('tfoot,tbody').remove();
    +// bind events to the cloned headers
    +$.tablesorter.bindEvents( $table, $clonedTable.find('th') );
    + In v2.16.2, this function now saves all extra (external) headers to the config.$extraHeaders variable which allows the plugin to automatically update the sort status. +
    +
    This function restores the table headers cells with their original content (v2.8). +

    + The original header cell content is saved, within the headerContent variable array, before the headerTemplate is applied and before the onRenderTemplate and onRenderHeader callbacks are executed.
    +
    + Use it as follows: +
    $.tablesorter.restoreHeaders( table );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    + Please note that only header cells that still contain a div with a class name of tablesorter-header-inner will have their contents restored; it assumes that the contents have already been restored. +
    +
    This function completely removes tablesorter, including all widgets, associated data & event handlers from the table (v2.3.2). +

    + Use it as follows: +
    $.tablesorter.destroy( table, removeClasses, callback );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • removeClasses - Boolean flag
    • +
    • callback - Function executed once tablesorter has been removed.
    • +
    + When calling the function, set the removeClasses option to true to include removing of the "tablesorter" class name, tablesorter theme name (e.g. "tablesorter-blue") and the class name applied by the tableClass option. The callback function only provides a table (DOM element only) parameter.
    +
    + Here is a basic example of how this function is used: +
    $.tablesorter.destroy( table, true, function(table){
    +	alert('tablesorter has been removed! No sort for you!');
    +});
    + Please note that only header cells that still contain a div with a class name of tablesorter-header-inner will have their contents restored; it assumes that the contents have already been restored. +
    +
    This function sorts the a & b parameter using a natural sort (v2.12). +

    + Access it as follows: +
    $.tablesorter.sortNatural(a, b);
    +
      +
    • a - string.
    • +
    • b - string to compare.
    • +
    + Here is a basic example of how this function is used: +
    var myArray = [ '1a', '10a', '2a', '2b' ];
    +// result: ["1a", "2a", "2b", "10a"]
    +myArray.sort(function(a,b) { return $.tablesorter.sortNatural(a, b); });
    + Please note that this natural sort function only accepts strings (added v2.0.6; renamed v2.12). +
    +
    This function sorts the a & b parameter using a basic sort (renamed v2.12). +

    + Access it as follows: +
    $.tablesorter.sortText(a, b);
    +
      +
    • a - string.
    • +
    • b - string to compare.
    • +
    + Here is a basic example of how this function is used: +
    var myArray = [ '1a', '10a', '2a', '2b' ];
    +// result: ["10a", "1a", "2a", "2b"]
    +myArray.sort(function(a,b) { return $.tablesorter.sortText(a, b); });
    +
    +
    This function replaces basic accented characters to better sorting & filtering of table contents (v2.2). +

    + Use it as follows: +
    $.tablesorter.replaceAccents(string);
    +
      +
    • string - a string to process & replace accented characters.
    • +
    + Here is a basic example of how this function is used: +
    $.tablesorter.replaceAccents("áàâãä"); // result: "aaaaa"
    + This function is used when the sortLocaleCompare option is set to true. Please refer to the option and the demo for more details on the defaults values and how to add more accented characters. +
    +
    This function returns a zero-based index value of the position of the value within the array, otherwise it returns -1 (Modified v2.15.6). +

    + Use it as follows: +
    $.tablesorter.isValueInArray(value, array);
    +
      +
    • value - value to find within the array.
    • +
    • array - array (sortList) to search for the value.
    • +
    + Sadly, this function has limited usefulness outside of tablesorter. It is only meant to search a sortList array and determine if a column (value) is already contained within it. Here is a basic example of how this function is used: +
    var sortList = [ [1,0], [2,0], [0,0] ];
    +// result: 1
    +$.tablesorter.isValueInArray(2, sortList);
    + After v2.15.6, this function returns a zero-based index of the position of the value within the array parameter, or -1 if the value is not in the array. Previously, this function returned a boolean value of true if the value was contained within the array, or false if not. +
    +
    This function allows the adding of custom parser scripts to the tablesorter core. +

    + Access it as follows: +
    $.tablesorter.addParser(myParser);
    +
      +
    • myParser - object containing parser code.
    • +
    + The myParser object must contain a proper template. The template must include an id, is, format and type blocks. Please refer to the writing custom parsers demo page for more details & an example. +
    +
    This function allows to add custom methods for config object (v2.21.0). +

    + Access it as follows: +
    $.tablesorter.addInstanceMethods(methods);
    +
      +
    • methods - an object containing methods to be added, indexed by method names. These methods can use config object by refering this.
    • +
    + Take a look at instanceMethods variable description for more details. +
    +
    This function returns the named parser object. +

    + Access it as follows: +
    $.tablesorter.getParserById(name);
    +
      +
    • name - the name (or id) of the parser.
    • +
    + Use this function as follows: +
    var parser = $.tablesorter.getParserById("currency"),
    +	value = parser.format('100%'); // returns 100 (number type, not a string)
    +
    +
    This function allows the checking to see if a widget is installed (v2.17.4). +

    + Access it as follows: +
    $.tablesorter.hasWidget( table, 'mywidget');
    +
      +
    • table - table element or jQuery object of the selected table.
    • +
    • 'mywidget' - ID of the widget to check.
    • +
    + This function returns a boolean value, where true means the widget is currently installed and active; and false means the widget is not installed.
    +
    + Use this function as follows: +
    $.tablesorter.hasWidget( $('table'), 'zebra' ); // true
    +
    +
    This function allows the adding of custom widget scripts to the tablesorter core (v2.19.0). +
    +
    + In v2.19.0, a "refreshing" parameter was added to the remove widget function to indicate that the widget will be refreshed so it will only be temporarily removed (see this demo for more details).
    +
    + Access it as follows: +
    $.tablesorter.addWidget(myWidget);
    +
      +
    • myWidget - object containing widget code.
    • +
    + The myWidget object must contain a proper template. The template must include an id and format blocks. The priority, options, init and remove blocks are optional.
    +
    + Please refer to the writing custom widgets demo page for more details & an example. +
    +
    This function returns the named widget object. +

    + Access it as follows: +
    $.tablesorter.getWidgetById(name);
    +
      +
    • name - the name (or id) of the widget.
    • +
    + Use this function as follows: +
    var widget = $.tablesorter.getWidgetById("saveSort"),
    +	table = $('table')[0];
    +// apply save sort widget to a table; but it will get removed if the refreshWidgets method
    +// is triggered, unless the table.config.widgets array contains this widget name/id
    +widget.format( table, table.config, table.config.widgetOptions );
    +
    +
    This function applys (refreshes) all currently selected widgets on a table (v2.16.0; v2.19.0). +

    + Use it as follows: +
    $.tablesorter.applyWidget( table, init, callback );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • init - optional, boolean initialization flag.
    • +
    • callback - optional, a function executed after all widgets have been applied; the only parameter is table (v2.19.0).
    • +
    + The init flag is only set to true to extend the default option values from the widget options block. If the widget(s) have already been applied to the table, just leave this parameter undefined.
    +
    + This function is called when the applyWidgets method is triggered. +
    +
    This function removes, then reapplies all currently selected widgets on a table (v2.4; v2.19.0). +
    +
    + In v2.19.0, this function was modified to internally use the removeWidget function & a "refreshComplete" event is now triggered upon completion.
    +
    + Use it as follows: +
    $.tablesorter.refreshWidgets( table, doAll, dontapply );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • doAll - optional, boolean flag.
    • +
    • dontapply - optional, boolean flag.
    • +
    + The doAll flag is set to true if all widgets contained with the global $.tablesorter.widgets array are to be removed.
    + When doAll is false, only widgets not contained within the config.widget option are removed; then if the dontapply flag is false, the widgets named in that option are reapplied (without removing them).
    +
    + This function is called when the refreshWidgets method is triggered. +
    +
    This function removes selected widgets (v2.19.0). +

    + Use it as follows: +
    $.tablesorter.removeWidget( table, names, refreshing );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • names - string (space or comma separated widget names), an array of widget names, or if true all installed widgets are removed.
    • +
    • refreshing - if true, the widget name will not be removed from the widgets option; any other setting and the name will be removed.
    • +
    + This function is used by the refreshWidgets function (v2.19.0). +
    +
    This function returns the column data from an object based on a column index or classname/id (v2.21.1). +
    +
    + Use it as follows: +
    $.tablesorter.getColumnData( table, object, key );
    +
      +
    • table - table DOM element (or jQuery object).
    • +
    • object - object containing zero-based column indexes or column class names as a key (e.g. table.config.headers or table.config.widgetOptions.filter_functions; any data found as the value (of the key : value pair) will be returned.
    • +
    • key - key to be Object key; this can be a zero-based column index or header class name/id.
    • +
    + As a full example, say you have a header cell with a class name of "event". And you want to use the textExtraction function for that column, then you would use this function as follows: +
    var table = $('table')[0],
    +textExtractionFunction = $.tablesorter.getColumnData( table, table.config.textExtraction, ".event" );
    + The ".event" key can be replaced with a zero-based column index, if the textExtraction option is set up using indexes. +

    + This function is sometimes used in conjunction with the getData function. This function is called first because the getData function uses the result in the configHeaders parameter - the config.headers option result from this function would be an object and not a function. +
    +
    This utility function returns the entire column text (raw and parsed) as well as other data (v2.21.4). +
    +
    + Use it as follows: +
    $.tablesorter.getColumnText( table, column, callback );
    +
      +
    • table - table DOM element (or jQuery object).
    • +
    • column - zero-based column index or 'all'.
    • +
    • callback - callback function that is called while obtaining data for each cell within the specified column.
    • +
    + When using the callback, there is only one argument (object) passed to this function; it contains the following: +
      +
    • tbodyIndex - the tbody zero-based index of the current cell.
    • +
    • rowIndex - the row zero-based index of the current cell.
    • +
    • $row - a jQuery object targeting the current row being processed.
    • +
    • $cell - a jQuery object targeting the curretn cell being processed.
    • +
    • parsed - parsed text of the current cell.
    • +
    • raw - raw (unparsed) text of the current cell.
    • +
    + As an example, say you want to make the text of all cells with a value greater than 20 red (assuming the 'red' class name is defined in css). Do it as follows: +
    var table = $('table')[0];
    +// targeting the 4th column (zero-based index)
    +$.tablesorter.getColumnText( table, 3, function( data ) {
    +  if ( data.parsed > 20 ) {
    +    data.$cell.addClass('red');
    +  }
    +});
    + In this example, the goal is to get data from rows visible after filtering. When the callback returns false, that row/cell data will not be included in the resulting data: +
    var table = $('table')[0],
    +  // getting data from ALL columns, we're just skipping filtered out rows (rows with a "filtered" class)
    +  result = $.tablesorter.getColumnText( table, 'all', function( data ) {
    +    return !data.$row.hasClass('filtered');
    +  });
    +  // let's just assume this example is only showing filter matching rows (rows without a "filtered" class ;)
    +  // result = {
    +  //   raw    : [ [ 'r1c1', 'r1c2', ..., 'r1cN' ], [ 'r2c1', 'r2c2', ..., 'r2cN' ] ..., [ 'rNc1', 'rNc2', ..., 'rNcN' ] ],
    +  //   parsed : [ [ 'r1c1', 'r1c2', ..., 'r1cN' ], [ 'r2c1', 'r2c2', ..., 'r2cN' ] ..., [ 'rNc1', 'rNc2', ..., 'rNcN' ] ],
    +  //   $cell  : [ [ $r1c1,  $r1c2,  ..., $r1cN  ], [ $r2c1,  $r2c2,  ..., $r2cN  ] ..., [ $rNc1,  $rNc2,  ..., $rNcN  ] ]
    +  // }
    +
    + If the callback isn't used, the function will return the cummulated data for the column (it does not include all of the parameters available within the callback function): +
    var table = $('table')[0],
    +  // targeting the 4th column (zero-based index)
    +  columnText = $.tablesorter.getColumnText( table, 3 );
    +  // columnText = {
    +  //   raw    : [ 'cell1', 'cell2', ..., 'celln' ],
    +  //   parsed : [ 'cell1', 'cell2', ..., 'celln' ],
    +  //   $cell  : [ $cell1,  $cell2,  ..., $celln  ]
    +  // }
    +
    + All of these methods of gathering column data might be useful for custom widgets, etc. +

    + * NOTE * All currently available widgets that gather data from a column will be updated to use this function in v2.22.0. +
    +
    This functions gets the sorter, string, empty, etc options for each column from jQuery data, metadata, header option or header class name ("sorter-false") (v2.1.16). +

    + priority = jQuery data > meta > headers option > header class name
    +
    + Use it as follows: +
    $.tablesorter.getData(headerCell, configHeaders, key);
    +
      +
    • headerCell - table DOM element (or jQuery object) of targeted header cell.
    • +
    • configHeaders - table.config.headers option for the current column.
    • +
    • key - get value for this option name, e.g. "sorter".
    • +
    + If the value of the "sorter" option is needed for a column, set the key to "sorter" and this function will return the set value, e.g. false, digit, currency etc.
    + Use this function as follows: +
    var column = 2,
    +	config = $('table')[0].config,
    +	headerCell = config.$headers.filter('[data-column="' + column + '"]');
    +// e.g. returns "false" if the header cell has the "sorter-false" class name
    +$.tablesorter.getData( headerCell, config.headers[column], "sorter" );
    + The reason there is a priority is because that is the order in which the values are searched, only the first (higher priority) value is returned. +
    +
    This function converts a number string into a number type. +

    + Use it as follows: +
    $.tablesorter.formatFloat(string, table);
    +
      +
    • string - a string possibly containing a number.
    • +
    • table - table DOM element (or jQuery object) of table (optional; required for non U.S. formatting).
    • +
    + If string is empty, not a string type, or not a number (after processing), the string itself is returned.
    + If table is not provided, the format float function will default to U.S. number formatting. The reason a table parameter is needed is to check the value of the usNumberFormat option.
    +
    + This function uses the usNumberFormat option to determine if either commas or decimals are removed before converting the value within the string parameter into a number type variable. This function does not use the $.tablesorter.isDigit function.
    +
    + Any numbers wrapped within parentheses are converted into negative numbers; but any other symbols (e.g. currency) are not removed and will cause this function to determine the string as a non-number (e.g. "$1.25" will be returned as a string).
    +
    + Use this function as follows: +
    // result: -2345.67 if usNumberFormat option is true
    +$.tablesorter.formatFloat( "(2,345.67)", table );
    +
    +
    This function determines if a string contains a number after removing commas, periods, quotes and spaces. +

    + Use it as follows: +
    $.tablesorter.isDigit(string);
    +
      +
    • string - a string possibly containing a number.
    • +
    + This function will return a boolean value of true if the string parameter contains a number after all commas, decimals, quotes and spaces are removed, and still allow plus or minus signs, or the number wrapped in parenthesis (negative values).
    +
    + Use this function as follows: +
    // boolean value of true returned
    +$.tablesorter.isDigit( "(2,345.67)" );
    +
    +
    Adds the correct data-column indexing to all rows passed to this function (v2.16). +

    + Use it as follows: +
    $.tablesorter.computeColumnIndex($rows);
    +
      +
    • $rows - jQuery object of rows in which to add data-column indexes
    • +
    + Example result:
    <tr>
    +	<td colspan="2" data-column="0">r0c0</td>
    +	<td data-column="2">r0c2</td>
    +</tr>
    +<tr>
    +	<td data-column="0">r1c0</td>
    +	<td data-column="1">r1c1</td>
    +	<td data-column="2">r1c2</td>
    +</tr>
    +
    +
    This function allows adding/removing a row to the thead, to display any errors (v2.15). +

    + This function is ONLY included within the widget-pager.js and jquery.tablesorter.pager.js files; in version 3+, I plan to add it as a selectable option in a build.
    +
    + Use it as follows: +
    $.tablesorter.showError( table, message );
    +
      +
    • table - table DOM element (or jQuery object) of table (or tables).
    • +
    • message - a plain string, or string of an HTML row.
    • +
    + This function will add a table row to the thead, with a class name from either the pager plugin cssErrorRow option setting, or the pager widget pager_css.errorRow option (the default class name is "tablesorter-errorRow"; and styled within each theme css file).
    +
    + When passing this function a message, there are three possibilities: +
      +
    1. Plain string - "table refuses to cooperate"
    2. +
    3. HTML row string - '<tr><td colspan="' + table.config.columns + '">yeah, instead of showing your data... I am taking a nap</td></tr>' (the table.config.columns variable contains the number of table columns; use as needed)
    4. +
    5. undefined - completely leave out a message parameter $.tablesorter.showError( table ); to remove all error rows from the table thead.
    6. +
    +
    +
    Widget Functions
    This filter widget function allows binding external search filters to the table (v2.13.3; v2.15). +

    + Access it as follows: +
    $.tablesorter.filter.bindSearch(table, $els, false);
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • $els - jQuery object of all input (search) elements to bind.
    • +
    • false - boolean flag to force a new search.
    • +
    + The external elements ($els) will allow searching the table using "search" and "keyup" events (enter to start & escape to cancel the search), and uses the filter_liveSearch option, or delayed search.
    +
    + Include a data-column="#" attribute (where # is the column number) in the search input, to specify to which column the search should apply ~ see this demo for a full example. Warning!, if no data-column attribute is added to the input, the input will be ignored.
    +
    + In v2.15, use a data-column="all" to bind an external any-match search filter; but note that adding an external any-match filter using this method will not override the filter set by the filter_external option.
    +
    + The third function parameter, false, is optional. When set to false it forces the inputs to update their values (same as setting the apply flag when using the setFilters function), and reapplies (forces) the current search to be applied again, even if the filter values have not changed; this allows changing the data column attribute dynamically. See the filter external inputs demo for an example.
    +
    + Warning! If the third parameter is set to true the saved internal filters (config.$filters) will be replaced - not recommended! +
    +
    This filter widget function allows the updating or replacing of filter select options from an external source. (v2.17.5): +

    + Access it as follows: +
    $.tablesorter.filter.buildSelect( table, column, options, replace, onlyAvail );
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • column - zero-based column index.
    • +
    • options - array of options, jQuery object of option elements, or HTML string of option elements to apply to the targeted select.
    • +
    • replace - a boolean value, which if true all options will be replaced; if false the options will be appended to the current list of options.
    • +
    • onlyAvail - an optional boolean flag, which will be ignored if the options parameter is defined or is an empty string; otherwise it is the value passed to the function which finds all table column values; if true, only the available options will be diplayed.
    • +
    + Use this function as follows:
    +
    // replace filter select options for the first column with 1,2,3,4
    +$.tablesorter.filter.buildSelect( $('table'), 0, [ 1, 2, 3, 4 ], true );
    +
    +// append "Aaron" and "Fred" to the second column's filter select options. These options will remain unsorted.
    +$.tablesorter.filter.buildSelect( $('table'), 1, $(''), false );
    + Please be aware that this function will allow you to modify the select options, but as soon as the user filters any column, all of the select options will refresh and obtain options from the table column, or from the filter_selectSource function. +
    +
    This filter widget function allows getting an array of the currently applied filters (v2.9; v2.15) +

    + Access it as follows: +
    $.tablesorter.getFilters(table, flag);
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • flag - boolean flag (optional; false by default), added v2.15
    • +
    + Use this function as follows:
    +
    // use $('table') or $('table.hasFilters') to make sure the table has a filter row
    +// only required if the stickyHeaders or scroller widget is being used (they duplicate the table)
    +$.tablesorter.getFilters( $('table') );
    + This function returns an array of filter values (e.g. [ '', '', '', '', '', '2?%' ]), or false if the selected table does not have a filter row. It will also return an additional parameter if an external input with data-column="all" containing the value used when matching any table column.
    +
    + In v2.15, this function will also return values from any external filters (set either by the filter_external option or using the bindSearch function) - with or without an internal filter row.
    +
    + If the second parameter is set to true, it forces the function to get all of the current filter values directly from the inputs. Otherwise, by default, the function returns the last search as found in this stored data $('table').data('lastSearch');. +
    +
    This filter widget function allows setting of the filters; include a true boolean to actually apply the search (v2.9; v2.16): +

    + Access it as follows: +
    $.tablesorter.setFilters(table, filter, apply);
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • filter - array of filter values to apply to the table.
    • +
    • apply - boolean flag, if false (default setting), the input values are updated, but the search is not applied to the table.
    • +
    + Use this function as follows:
    +
    // update filters, but don't apply the search
    +$.tablesorter.setFilters( $('table'), [ '', '', '', '', '', '2?%' ] );
    +
    +// update filters, AND apply the search
    +$.tablesorter.setFilters( $('table'), [ '', '', '', '', '', '2?%' ], true ); // this will now use the search method
    + This function returns true if the filters were sucessfully applied, or false if the table does not have a filter row.
    +
    + As of v2.15, this function will also set values in any external filters (set either by the filter_external option or using the bindSearch function). An additional search parameter can be included to match any column, but please include an external input with data-column="all" using the bindSearch function so your users will know that a search has been applied.
    +
    + Also, changed is that when a true value is passed as a third parameter, the search is forced to refresh on the table; otherwise, if the filters set in the search exactly match the previous search, it would be ignored - this was added to prevent numerous ajax calls with exactly the same search or sort parameters (when using the pager). +
    +
    This resizable widget function allows resetting column width changes and clearing out the saved set widths (v2.4; v2.10.1) +

    + Use it as follows: +
    $.tablesorter.resizableReset(table, refreshing);
    +
      +
    • table - table DOM element (or jQuery object) of table(s).
    • +
    • refreshing - if this flag is set to true, the stored resize settings will not be cleared; all other settings will clear the storage.
    • +
    + This function is used when the user right-clicks on the table header (the refreshing flag is undefined at that time to allow saving the changes). +
    +
    Added a resize event to the table headers - used by the stickyHeaders widget, but this is a public function available to any widget (v2.10). +

    + There is no built-in resize event for non-window elements, so when this function is active it triggers a resize event when the header cell changes size. So, if you are writing your own widget and need a header resize event, just include the jquery.tablesorter.widgets.js file, or just the extract the function from that file.
    +
    + Access it as follows: +
    $.tablesorter.addHeaderResizeEvent(table, disable, { timer : 250 });
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • disable - boolean flag, if false events for the targeted table are disabled.
    • +
    • timer - currently only the timer option is available for modification.
    • +
    + Enable these triggered events as follows: +
    var table = $('table')[0],
    +    disable = false,
    +    options = {
    +      timer : 250 // header cell size is checked every 250 milliseconds (1/4 of a second)
    +    };
    +$.tablesorter.addHeaderResizeEvent( table, disable, options );
    Then use it in your custom widget as follows: +
    $(table).on('resize', function(event, columns){
    +  // columns contains an array of header cells that were resized
    +  // this seemed like a better idea than firing off a resize event for every
    +  // column when the table adjusts itself to fit within its container
    +  event.stopPropagation(); // optional
    +  // do something
    +  console.log( columns );
    +});
    To disable these resize events, use this code:
    // Disable resize event triggering:
    +var table = $('table')[0];
    +$.tablesorter.addHeaderResizeEvent( table, true );
    +
    +
    This function allows saving specific table data (especially widgets) to local storage (cookie fallback for no browser support) (v2.1) +

    + Access it as follows: +
    $.tablesorter.storage(table, key, value, options);
    +
      +
    • table - table DOM element (or jQuery object) of table.
    • +
    • key - name of the variable to save
    • +
    • value - value of the variable that is saved (for saving only); set to null if wanting to get a value with options.
    • +
    • options - storage options; see below
    • +
    + This function attempts to give every table a unique identifier using both the page url and table id (or index on the page if no id exists), by default. Here is a usage example and a look at what is stored within the local storage: +
    $.tablesorter.storage( $('#tablesorter-demo')[0], 'test', '123');
    +// stored under the "test" value as {"/tablesorter/docs/":{"tablesorter-demo":"123"}}
    +
    +
    + The saved table url & id can be overridden by setting table data attributes data-table-page (url) and data-table-group (id), as in this sample markup: +
    <table class="tablesorter" data-table-page="mydomain" data-table-group="financial">...</table>)
    + To change the default data attributes, use the options to modify them as follows:
    $.tablesorter.storage( table, key, value, {
    +  // table id/group id
    +  id  : 'group1',
    +  // this group option sets name of the table attribute with the ID;
    +  // but the value within this data attribute is overridden by the above id option
    +  group: 'data-table-group',
    +
    +  // table pages
    +  url : 'page1',
    +  // this page option sets name of the table attribute with the page/url;
    +  // but the value within the data attribute is overridden by the above url option
    +  page: 'data-table-page',
    +
    +  // Option added v2.21.3; if `true` the storage function will use sessionStorage
    +  // if not defined, the `config.widgetOptions.storage_useSessionStorage` setting is checked
    +  // if no settings are found, it will default to `false`, and use localStorage
    +  useSessionStorage : false
    +});
    + The priority of table ID settings is as follows: +
      +
    1. options.id setting
    2. +
    3. Table data attribute ("data-table-group" by default) value
    4. +
    5. widgetOptions.storage_tableId option
    6. +
    7. Table id attribute
    8. +
    9. Index of the table (compared to other tables with a "tablesorter" class name) on the page
    10. +
    + The priority of table url (group) settings is as follows: +
      +
    1. options.url setting
    2. +
    3. Table data attribute ("data-table-page" by default) value
    4. +
    5. widgetOptions.storage_fixedUrl option value
    6. +
    7. config.fixedUrl option value
    8. +
    9. window.location.pathname
    10. +
    +
    + The storage_fixedUrl widget option allows you to override the current page url (it doesn't need to be a url, just some constant value) and save data for multiple tables across a domain. The value from this option has a lower priority than the options id or group settings (see priority list above).
    +
    + When using the storage utility to get a value and use custom table options, set the value parameter to null.
    +
    + Lastly, this storage utility function needs the parseJSON function available in jQuery v1.4.1+. +
    +
    + + +

    Download

    + + File Downloads + + + Required: + + + Optional / Add-Ons: + + + Themes: +

    Theme zip files have been removed. There are now numerous themes available which can be seen here.

    + + +

    Browser Compatibility

    + +

    tablesorter has been tested successfully in the following browsers with Javascript enabled:

    +
      +
    • Firefox 2+
    • +
    • Internet Explorer 6+
    • +
    • Safari 2+
    • +
    • Opera 9+
    • +
    • Konqueror
    • +
    + +

    jQuery Browser Compatibility

    + + +

    Support

    + +

    First, please review the FAQ page to see if it will help you resolve the problem.

    + +

    If you are having a problem with the plugin or you want to submit a feature request, please submit an issue.

    + +

    Support is also available from stackoverflow.

    + +

    If you would like to contribute, fork a copy on github.

    + +

    Some basic unit testing has been added (v2.6). If you would like to add more or report a problem, please use the appropriate link above.

    + +

    For questions about jQuery, try irc, stackoverflow, or the jQuery forums.

    + + +

    Credits

    +

    Written by Christian Bach.

    +

    + Documentation written by Brian Ghidinelli, + based on Mike Alsup's great documention. +

    +

    + Additional & Missing documentation, alphanumeric sort, numerous widgets, unit testing and other changes added by Mottie. +

    +

    + Thanks to all that have contributed code, comments, feedback and everything else. A special thanks goes out to: +

    +

    +

    + John Resig for the fantastic jQuery +

    +
    + + + diff --git a/docs/js/bootstrap.min.js b/docs/js/bootstrap.min.js new file mode 100644 index 0000000..c8f82e5 --- /dev/null +++ b/docs/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.4",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.4",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.4",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.4",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport),this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-mp.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.4",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.4",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.4",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a(document.body).height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/docs/js/chili/jquery.chili-2.2.js b/docs/js/chili/jquery.chili-2.2.js new file mode 100644 index 0000000..0a971bf --- /dev/null +++ b/docs/js/chili/jquery.chili-2.2.js @@ -0,0 +1,704 @@ +/* +=============================================================================== +Chili is the jQuery code highlighter plugin +............................................................................... +LICENSE: http://www.opensource.org/licenses/mit-license.php +WEBSITE: http://noteslog.com/chili/ + + Copyright 2008 / Andrea Ercolino +=============================================================================== +*/ + + +( function($) { + +ChiliBook = { //implied global + + version: "2.2" // 2008-07-06 + +// options -------------------------------------------------------------------- + + , automatic: true + , automaticSelector: "code" + + , lineNumbers: !true + + , codeLanguage: function( el ) { + var recipeName = $( el ).attr( "class" ); + return recipeName ? recipeName : ''; + } + + , recipeLoading: true + , recipeFolder: "" // used like: recipeFolder + recipeName + '.js' + + // IE and FF convert   to " ", Safari and Opera do not + , replaceSpace: " " + , replaceTab: "    " + , replaceNewLine: " 
    " + + , selectionStyle: [ "position:absolute; z-index:3000; overflow:scroll;" + , "width:16em;" + , "height:9em;" + , "border:1px solid gray;" + , "padding:15px;" + , "background-color:yellow;" + ].join( ' ' ) + +// ------------------------------------------------------------- end of options + + , defaultReplacement: '$$' // TODO: make this an option again + , recipes: {} //repository + , queue: {} //registry + + , unique: function() { + return (new Date()).valueOf(); + } +}; + + + +$.fn.chili = function( options ) { + var book = $.extend( {}, ChiliBook, options || {} ); + + function cook( ingredients, recipe, blockName ) { + + function prepareBlock( recipe, blockName ) { + var steps = []; + for( var stepName in recipe[ blockName ] ) { + steps.push( prepareStep( recipe, blockName, stepName ) ); + } + return steps; + } // prepareBlock + + function prepareStep( recipe, blockName, stepName ) { + var step = recipe[ blockName ][ stepName ]; + var exp = ( typeof step._match == "string" ) ? step._match : step._match.source; + return { + recipe: recipe + , blockName: blockName + , stepName: stepName + , exp: "(" + exp + ")" + , length: 1 // add 1 to account for the newly added parentheses + + (exp // count number of submatches in here + .replace( /\\./g, "%" ) // disable any escaped character + .replace( /\[.*?\]/g, "%" ) // disable any character class + .match( /\((?!\?)/g ) // match any open parenthesis, not followed by a ? + || [] // make sure it is an empty array if there are no matches + ).length // get the number of matches + , replacement: step._replace ? step._replace : book.defaultReplacement + }; + } // prepareStep + + function knowHow( steps ) { + var prevLength = 1; + var exps = []; + for (var i = 0; i < steps.length; i++) { + var exp = steps[ i ].exp; + // adjust backreferences + exp = exp.replace( /\\\\|\\(\d+)/g, function( m, aNum ) { + return !aNum ? m : "\\" + ( prevLength + 1 + parseInt( aNum, 10 ) ); + } ); + exps.push( exp ); + prevLength += steps[ i ].length; + } + var prolog = '((?:\\s|\\S)*?)'; + var epilog = '((?:\\s|\\S)+)'; + var source = '(?:' + exps.join( "|" ) + ')'; + source = prolog + source + '|' + epilog; + return new RegExp( source, recipe._case ? "g" : "gi" ); + } // knowHow + + function escapeHTML( str ) { + return str.replace( /&/g, "&" ).replace( /' + filter( subject ) + ''; + } + return filter( subject ); + } + else { + return filter( subject ); + } + } + } // applyModule + + function addPrefix( prefix, replacement ) { + var aux = replacement.replace( /()/ig, "$1" + prefix + "__$3" ); + return aux; + } // addPrefix + + function chef() { + if (! arguments[ 0 ]) { + return ''; + } + var steps = this.steps; + var i = 0; // iterate steps + var j = 2; // iterate chef's arguments + var prolog = arguments[ 1 ]; + var epilog = arguments[ arguments.length - 3 ]; + if (! epilog) { + var step; + while( step = steps[ i++ ] ) { + var aux = arguments; // this unmasks chef's arguments inside the next function + if( aux[ j ] ) { + var replacement = ''; + if( $.isFunction( step.replacement ) ) { + var matches = []; //Array.slice.call( aux, j, step.length ); + for (var k = 0, kTop = step.length; k < kTop; k++) { + matches.push( aux[ j + k ] ); + } + matches.push( aux[ aux.length - 2 ] ); + matches.push( aux[ aux.length - 1 ] ); + replacement = step.replacement + .apply( { + x: function() { + var subject = arguments[0]; + var module = arguments[1]; + var context = { + recipe: step.recipe + , blockName: step.blockName + }; + return applyModule( subject, module, context ); + } + }, matches ); + } + else { //we expect step.replacement to be a string + replacement = step.replacement + .replace( /(\\\$)|(?:\$\$)|(?:\$(\d+))/g, function( m, escaped, K ) { + if( escaped ) { /* \$ */ + return "$"; + } + else if( !K ) { /* $$ */ + return filter( aux[ j ] ); + } + else if( K == "0" ) { /* $0 */ + return step.stepName; + } + else { /* $K */ + return filter( aux[ j + parseInt( K, 10 ) ] ); + } + } ); + } + replacement = addPrefix( step.recipe._name, replacement ); + return filter( prolog ) + replacement; + } + else { + j+= step.length; + } + } + } + else { + return filter( epilog ); + } + } // chef + + if( ! blockName ) { + blockName = '_main'; + checkSpices( recipe ); + } + if( ! (blockName in recipe) ) { + return filter( ingredients ); + } + var replaceSpace = book.replaceSpace; + var steps = prepareBlock( recipe, blockName ); + var kh = knowHow( steps ); + var perfect = ingredients.replace( kh, function() { + return chef.apply( { steps: steps }, arguments ); + } ); + return perfect; + + } // cook + + function loadStylesheetInline( sourceCode ) { + if( document.createElement ) { + var e = document.createElement( "style" ); + e.type = "text/css"; + if( e.styleSheet ) { // IE + e.styleSheet.cssText = sourceCode; + } + else { + var t = document.createTextNode( sourceCode ); + e.appendChild( t ); + } + document.getElementsByTagName( "head" )[0].appendChild( e ); + } + } // loadStylesheetInline + + function checkSpices( recipe ) { + var name = recipe._name; + if( ! book.queue[ name ] ) { + + var content = ['/* Chili -- ' + name + ' */']; + for (var blockName in recipe) { + if( blockName.search( /^_(?!main\b)/ ) < 0 ) { + for (var stepName in recipe[ blockName ]) { + var step = recipe[ blockName ][ stepName ]; + if( '_style' in step ) { + if( step[ '_style' ].constructor == String ) { + content.push( '.' + name + '__' + stepName + ' { ' + step[ '_style' ] + ' }' ); + } + else { + for (var className in step[ '_style' ]) { + content.push( '.' + name + '__' + className + ' { ' + step[ '_style' ][ className ] + ' }' ); + } + } + } + } + } + } + content = content.join('\n'); + + loadStylesheetInline( content ); + + book.queue[ name ] = true; + } + } // checkSpices + + function askDish( el ) { + var recipeName = book.codeLanguage( el ); + if( '' != recipeName ) { + var path = getPath( recipeName ); + if( book.recipeLoading ) { + /* dynamic setups come here */ + if( ! book.queue[ path ] ) { + /* this is a new recipe to download */ + try { + book.queue[ path ] = [ el ]; + $.getJSON( path, function( recipeLoaded ) { + book.recipes[ path ] = recipeLoaded; + var q = book.queue[ path ]; + for( var i = 0, iTop = q.length; i < iTop; i++ ) { + makeDish( q[ i ], path ); + } + } ); + } + catch( recipeNotAvailable ) { + alert( "the recipe for '" + recipeName + "' was not found in '" + path + "'" ); + } + } + else { + /* not a new recipe, so just enqueue this element */ + book.queue[ path ].push( el ); + } + /* a recipe could have been already downloaded */ + makeDish( el, path ); + } + else { + /* static setups come here */ + makeDish( el, path ); + } + } + } // askDish + + function makeDish( el, recipePath ) { + var recipe = book.recipes[ recipePath ]; + if( ! recipe ) { + return; + } + var $el = $( el ); + var ingredients = $el.text(); + if( ! ingredients ) { + return; + } + + //fix for msie: \r (13) is used instead of \n (10) + //fix for opera: \r\n is used instead of \n + ingredients = ingredients.replace(/\r\n?/g, "\n"); + + //reverse fix for safari: msie, mozilla and opera render the initial \n + if( $el.parent().is('pre') ) { + if( ! $.browser.safari ) { + ingredients = ingredients.replace(/^\n/g, ""); + } + } + + var dish = cook( ingredients, recipe ); // all happens here + + if( book.replaceTab ) { + dish = dish.replace( /\t/g, book.replaceTab ); + } + if( book.replaceNewLine ) { + dish = dish.replace( /\n/g, book.replaceNewLine ); + } + + el.innerHTML = dish; //much faster than $el.html( dish ); + //tried also the function replaceHtml from http://blog.stevenlevithan.com/archives/faster-than-innerhtml + //but it was not faster nor without sideffects (it was not possible to count spans into el) + + //opera and safari select PRE text correctly + if( $.browser.msie || $.browser.mozilla ) { + enableSelectionHelper( el ); + } + + var $that = $el.parent(); + var classes = $that.attr( 'class' ); + var ln = /ln-(\d+)-([\w][\w\-]*)|ln-(\d+)|ln-/.exec( classes ); + if( ln ) { + addLineNumbers( el ); + var start = 0; + if( ln[1] ) { + start = parseInt( ln[1], 10 ); + var $pieces = $( '.ln-' + ln[1] + '-' + ln[2] ); + var pos = $pieces.index( $that[0] ); + $pieces.slice( 0, pos ).each( function() { + start += $( this ).find( 'li' ).length; + } ); + } + else if( ln[3] ) { + start = parseInt( ln[3], 10 ); + } + else { + start = 1; + } + $el.find( 'ol' )[0].start = start; + $('body').width( $('body').width() - 1 ).width( $('body').width() + 1 ); + } + else if( book.lineNumbers ) { + addLineNumbers( el ); + } + + } // makeDish + + function enableSelectionHelper( el ) { + var element = null; + $( el ) + .parents() + .filter( "pre" ) + .bind( "mousedown", function() { + element = this; + if( $.browser.msie ) { + document.selection.empty(); + } + else { + window.getSelection().removeAllRanges(); + } + } ) + .bind( "mouseup", function( event ) { + if( element && (element == this) ) { + element = null; + var selected = ''; + if( $.browser.msie ) { + selected = document.selection.createRange().htmlText; + if( '' == selected ) { + return; + } + selected = preserveNewLines( selected ); + var container_tag = '",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:k.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){t.types.push(Z),x("BeforeChange",function(e,t,n){t!==n&&(t===Z?D():n===Z&&D(!0))}),x(l+"."+Z,function(){D()})},getIframe:function(n,i){var o=n.src,r=t.st.iframe;e.each(r.patterns,function(){return o.indexOf(this.index)>-1?(this.id&&(o="string"==typeof this.id?o.substr(o.lastIndexOf(this.id)+this.id.length,o.length):this.id.call(this,o)),o=this.src.replace("%id%",o),!1):void 0});var a={};return r.srcAction&&(a[r.srcAction]=o),t._parseMarkup(i,a,n),t.updateStatus("ready"),i}}});var K=function(e){var n=t.items.length;return e>n-1?e-n:0>e?n+e:e},Y=function(e,t,n){return e.replace(/%curr%/gi,t+1).replace(/%total%/gi,n)};e.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var n=t.st.gallery,i=".mfp-gallery",r=Boolean(e.fn.mfpFastClick);return t.direction=!0,n&&n.enabled?(a+=" mfp-gallery",x(f+i,function(){n.navigateByImgClick&&t.wrap.on("click"+i,".mfp-img",function(){return t.items.length>1?(t.next(),!1):void 0}),o.on("keydown"+i,function(e){37===e.keyCode?t.prev():39===e.keyCode&&t.next()})}),x("UpdateStatus"+i,function(e,n){n.text&&(n.text=Y(n.text,t.currItem.index,t.items.length))}),x(p+i,function(e,i,o,r){var a=t.items.length;o.counter=a>1?Y(n.tCounter,r.index,a):""}),x("BuildControls"+i,function(){if(t.items.length>1&&n.arrows&&!t.arrowLeft){var i=n.arrowMarkup,o=t.arrowLeft=e(i.replace(/%title%/gi,n.tPrev).replace(/%dir%/gi,"left")).addClass(y),a=t.arrowRight=e(i.replace(/%title%/gi,n.tNext).replace(/%dir%/gi,"right")).addClass(y),s=r?"mfpFastClick":"click";o[s](function(){t.prev()}),a[s](function(){t.next()}),t.isIE7&&(k("b",o[0],!1,!0),k("a",o[0],!1,!0),k("b",a[0],!1,!0),k("a",a[0],!1,!0)),t.container.append(o.add(a))}}),x(m+i,function(){t._preloadTimeout&&clearTimeout(t._preloadTimeout),t._preloadTimeout=setTimeout(function(){t.preloadNearbyImages(),t._preloadTimeout=null},16)}),x(l+i,function(){o.off(i),t.wrap.off("click"+i),t.arrowLeft&&r&&t.arrowLeft.add(t.arrowRight).destroyMfpFastClick(),t.arrowRight=t.arrowLeft=null}),void 0):!1},next:function(){t.direction=!0,t.index=K(t.index+1),t.updateItemHTML()},prev:function(){t.direction=!1,t.index=K(t.index-1),t.updateItemHTML()},goTo:function(e){t.direction=e>=t.index,t.index=e,t.updateItemHTML()},preloadNearbyImages:function(){var e,n=t.st.gallery.preload,i=Math.min(n[0],t.items.length),o=Math.min(n[1],t.items.length);for(e=1;(t.direction?o:i)>=e;e++)t._preloadItem(t.index+e);for(e=1;(t.direction?i:o)>=e;e++)t._preloadItem(t.index-e)},_preloadItem:function(n){if(n=K(n),!t.items[n].preloaded){var i=t.items[n];i.parsed||(i=t.parseEl(n)),T("LazyLoad",i),"image"===i.type&&(i.img=e('').on("load.mfploader",function(){i.hasSize=!0}).on("error.mfploader",function(){i.hasSize=!0,i.loadError=!0,T("LazyLoadError",i)}).attr("src",i.src)),i.preloaded=!0}}}});var U="retina";e.magnificPopup.registerModule(U,{options:{replaceSrc:function(e){return e.src.replace(/\.\w+$/,function(e){return"@2x"+e})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var e=t.st.retina,n=e.ratio;n=isNaN(n)?n():n,n>1&&(x("ImageHasSize."+U,function(e,t){t.img.css({"max-width":t.img[0].naturalWidth/n,width:"100%"})}),x("ElementParse."+U,function(t,i){i.src=e.replaceSrc(i,n)}))}}}}),function(){var t=1e3,n="ontouchstart"in window,i=function(){I.off("touchmove"+r+" touchend"+r)},o="mfpFastClick",r="."+o;e.fn.mfpFastClick=function(o){return e(this).each(function(){var a,s=e(this);if(n){var l,c,d,u,p,f;s.on("touchstart"+r,function(e){u=!1,f=1,p=e.originalEvent?e.originalEvent.touches[0]:e.touches[0],c=p.clientX,d=p.clientY,I.on("touchmove"+r,function(e){p=e.originalEvent?e.originalEvent.touches:e.touches,f=p.length,p=p[0],(Math.abs(p.clientX-c)>10||Math.abs(p.clientY-d)>10)&&(u=!0,i())}).on("touchend"+r,function(e){i(),u||f>1||(a=!0,e.preventDefault(),clearTimeout(l),l=setTimeout(function(){a=!1},t),o())})})}s.on("click"+r,function(){a||o()})})},e.fn.destroyMfpFastClick=function(){e(this).off("touchstart"+r+" click"+r),n&&I.off("touchmove"+r+" touchend"+r)}}(),_()})(window.jQuery||window.Zepto); diff --git a/docs/js/jquery.tipsy.min.js b/docs/js/jquery.tipsy.min.js new file mode 100644 index 0000000..9b730b6 --- /dev/null +++ b/docs/js/jquery.tipsy.min.js @@ -0,0 +1,7 @@ +/* tipsy, facebook style tooltips for jquery + * version 1.0.0a + * (c) 2008-2010 jason frame [jason@onehackoranother.com] + * released under the MIT license + * Modified to use themes: https://github.com/Mottie/tipsy + */ +(function(b){function l(a,c){this.$element=b(a);this.options=c;this.enabled=!0;this.fixTitle()}l.prototype={show:function(){var a=this.getTitle();if(a&&this.enabled){var c=this.tip(),d=this.options.theme[0]||"black",f=this.options.theme[1]||"white",g;c.find(".tipsy-inner").css({background:d,color:f})[this.options.html?"html":"text"](a);c[0].className="tipsy";c.remove().css({top:0,left:0,visibility:"hidden",display:"block"}).prependTo(document.body);var a=b.extend({},this.$element.offset(),{width:this.$element[0].offsetWidth, height:this.$element[0].offsetHeight}),f=c[0].offsetWidth,h=c[0].offsetHeight,e="function"==typeof this.options.gravity?this.options.gravity.call(this.$element[0]):this.options.gravity,k;switch(e.charAt(0)){case "n":k={top:a.top+a.height+this.options.offset,left:a.left+a.width/2-f/2};g={"border-bottom-color":d};break;case "s":k={top:a.top-h-this.options.offset,left:a.left+a.width/2-f/2};g={"border-top-color":d};break;case "e":k={top:a.top+a.height/2-h/2,left:a.left-f-this.options.offset};g={"border-left-color":d}; break;case "w":k={top:a.top+a.height/2-h/2,left:a.left+a.width+this.options.offset},g={"border-right-color":d}}2==e.length&&("w"==e.charAt(1)?k.left=a.left+a.width/2-15:k.left=a.left+a.width/2-f+15);c.css(k).addClass("tipsy-"+e);c.find(".tipsy-arrow").css(g)[0].className="tipsy-arrow tipsy-arrow-"+e.charAt(0);this.options.className&&c.addClass("function"==typeof this.options.className?this.options.className.call(this.$element[0]):this.options.className);this.options.fade?c.stop().css({opacity:0,display:"block", visibility:"visible"}).animate({opacity:this.options.opacity}):c.css({visibility:"visible",opacity:this.options.opacity})}},hide:function(){this.options.fade?this.tip().stop().fadeOut(function(){b(this).remove()}):this.tip().remove()},fixTitle:function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("original-title"))&&a.attr("original-title",a.attr("title")||"").removeAttr("title")},getTitle:function(){var a,b=this.$element,d=this.options;this.fixTitle();d=this.options;"string"== typeof d.title?a=b.attr("title"==d.title?"original-title":d.title):"function"==typeof d.title&&(a=d.title.call(b[0]));return(a=(""+a).replace(/(^\s*|\s*$)/,""))||d.fallback},tip:function(){this.$tip||(this.$tip=b('
    ').html('
    '));return this.$tip},validate:function(){this.$element[0].parentNode||(this.hide(),this.options=this.$element=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled= !this.enabled}};b.fn.tipsy=function(a){function c(e){var c=b.data(e,"tipsy");c||(c=new l(e,b.fn.tipsy.elementOptions(e,a)),b.data(e,"tipsy",c));return c}function d(){var b=c(this);b.hoverState="in";0==a.delayIn?b.show():(b.fixTitle(),setTimeout(function(){"in"==b.hoverState&&b.show()},a.delayIn))}function f(){var b=c(this);b.hoverState="out";0==a.delayOut?b.hide():setTimeout(function(){"out"==b.hoverState&&b.hide()},a.delayOut)}if(!0===a)return this.data("tipsy");if("string"==typeof a){var g=this.data("tipsy"); if(g)g[a]();return this}a=b.extend({},b.fn.tipsy.defaults,a);a.live||this.each(function(){c(this)});if("manual"!=a.trigger){var g=a.live?"live":"bind",h="hover"==a.trigger?"mouseleave":"blur";this[g]("hover"==a.trigger?"mouseenter":"focus",d)[g](h,f)}return this};b.fn.tipsy.defaults={className:null,delayIn:0,delayOut:0,fade:!1,fallback:"",gravity:"n",html:!1,live:!1,offset:0,opacity:0.8,title:"title",theme:["black","white"],trigger:"hover"};b.fn.tipsy.elementOptions=function(a,c){return b.metadata? b.extend({},c,b(a).metadata()):c};b.fn.tipsy.autoNS=function(){return b(this).offset().top>b(document).scrollTop()+b(window).height()/2?"s":"n"};b.fn.tipsy.autoWE=function(){return b(this).offset().left>b(document).scrollLeft()+b(window).width()/2?"e":"w"};b.fn.tipsy.autoBounds=function(a,c){return function(){var d=c[0],f=1122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}ph;h++)e[h]=c[h].style.display,c[h].style.display="block",c[h].style.height="0",c[h].style.overflow="hidden",c[h].style.visibility="hidden";g=a[b];for(var i=0;d>i;i++)c[i].style.display=e[i],c[i].style.height="",c[i].style.overflow="",c[i].style.visibility=""}return g}function h(b,e){if(this.$window=a(window),this.$document=a(document),this.$element=a(b),this.options=a.extend({},m,e),this._defaults=m,this._name=i,this.startEvent=this.options.startEvent.join("."+i+" ")+"."+i,this.moveEvent=this.options.moveEvent.join("."+i+" ")+"."+i,this.endEvent=this.options.endEvent.join("."+i+" ")+"."+i,this.polyfill=this.options.polyfill,this.onInit=this.options.onInit,this.onSlide=this.options.onSlide,this.onSlideEnd=this.options.onSlideEnd,this.polyfill&&l)return!1;this.identifier="js-"+i+"-"+k++,this.min=parseFloat(this.$element[0].getAttribute("min")||0),this.max=parseFloat(this.$element[0].getAttribute("max")||100),this.value=parseFloat(this.$element[0].value||this.min+(this.max-this.min)/2),this.step=parseFloat(this.$element[0].getAttribute("step")||1),this.$fill=a('
    '),this.$handle=a('
    '),this.$range=a('
    ').insertAfter(this.$element).prepend(this.$fill,this.$handle),this.$element.css({position:"absolute",width:"1px",height:"1px",overflow:"hidden",opacity:"0"}),this.handleDown=a.proxy(this.handleDown,this),this.handleMove=a.proxy(this.handleMove,this),this.handleEnd=a.proxy(this.handleEnd,this),this.init();var f=this;this.$window.on("resize."+i,d(function(){c(function(){f.update()},300)},20)),this.$document.on(this.startEvent,"#"+this.identifier+":not(."+this.options.disabledClass+")",this.handleDown),this.$element.on("change."+i,function(a,b){if(!b||b.origin!==i){var c=a.target.value,d=f.getPositionFromValue(c);f.setPosition(d)}})}var i="rangeslider",j=[],k=0,l=b(),m={polyfill:!0,rangeClass:"rangeslider",disabledClass:"rangeslider--disabled",fillClass:"rangeslider__fill",handleClass:"rangeslider__handle",startEvent:["mousedown","touchstart","pointerdown"],moveEvent:["mousemove","touchmove","pointermove"],endEvent:["mouseup","touchend","pointerup"]};h.prototype.init=function(){this.onInit&&"function"==typeof this.onInit&&this.onInit(),this.update()},h.prototype.update=function(){this.handleWidth=g(this.$handle[0],"offsetWidth"),this.rangeWidth=g(this.$range[0],"offsetWidth"),this.maxHandleX=this.rangeWidth-this.handleWidth,this.grabX=this.handleWidth/2,this.position=this.getPositionFromValue(this.value),this.$element[0].disabled?this.$range.addClass(this.options.disabledClass):this.$range.removeClass(this.options.disabledClass),this.setPosition(this.position)},h.prototype.handleDown=function(a){if(a.preventDefault(),this.$document.on(this.moveEvent,this.handleMove),this.$document.on(this.endEvent,this.handleEnd),!((" "+a.target.className+" ").replace(/[\n\t]/g," ").indexOf(this.options.handleClass)>-1)){var b=this.getRelativePosition(a),c=this.$range[0].getBoundingClientRect().left,d=this.getPositionFromNode(this.$handle[0])-c;this.setPosition(b-this.grabX),b>=d&&ba?b:a>c?c:a},h.prototype.setPosition=function(a){var b,c;b=this.getValueFromPosition(this.cap(a,0,this.maxHandleX))/this.step*this.step,c=this.getPositionFromValue(b),this.$fill[0].style.width=c+this.grabX+"px",this.$handle[0].style.left=c+"px",this.setValue(b),this.position=c,this.value=b,this.onSlide&&"function"==typeof this.onSlide&&this.onSlide(c,b)},h.prototype.getPositionFromNode=function(a){for(var b=0;null!==a;)b+=a.offsetLeft,a=a.offsetParent;return b},h.prototype.getRelativePosition=function(a){var b=this.$range[0].getBoundingClientRect().left,c=0;return"undefined"!=typeof a.pageX?c=a.pageX:"undefined"!=typeof a.originalEvent.clientX?c=a.originalEvent.clientX:a.originalEvent.touches&&a.originalEvent.touches[0]&&"undefined"!=typeof a.originalEvent.touches[0].clientX?c=a.originalEvent.touches[0].clientX:a.currentPoint&&"undefined"!=typeof a.currentPoint.x&&(c=a.currentPoint.x),c-b},h.prototype.getPositionFromValue=function(a){var b,c;return b=(a-this.min)/(this.max-this.min),c=b*this.maxHandleX},h.prototype.getValueFromPosition=function(a){var b,c;return b=a/(this.maxHandleX||1),c=this.step*Math.round(b*(this.max-this.min)/this.step)+this.min,Number(c.toFixed(2))},h.prototype.setValue=function(a){a!==this.value&&this.$element.val(a).trigger("change",{origin:i})},h.prototype.destroy=function(){this.$document.off(this.startEvent,"#"+this.identifier,this.handleDown),this.$element.off("."+i).removeAttr("style").removeData("plugin_"+i),this.$range&&this.$range.length&&this.$range[0].parentNode.removeChild(this.$range[0]),j.splice(j.indexOf(this.$element[0]),1),j.length||this.$window.off("."+i)},a.fn[i]=function(b){return this.each(function(){var c=a(this),d=c.data("plugin_"+i);d||(c.data("plugin_"+i,d=new h(this,b)),j.push(this)),"string"==typeof b&&d[b]()})}}); \ No newline at end of file diff --git a/docs/js/search-ie.js b/docs/js/search-ie.js new file mode 100644 index 0000000..c048382 --- /dev/null +++ b/docs/js/search-ie.js @@ -0,0 +1,28 @@ +/* IE 8 and less */ +$(function(){ + // open side menu + var checked = false; + $('.main-header').click(function(){ + checked = !checked; + $('#main-nav').animate({ width: checked ? 250 : 0 }, 300); + $('#main') + .animate({ marginLeft: checked ? 250 : 0 }, 300) + .css({ overflow: checked ? 'hidden' : '' }) + .find('.open-menu').toggle(!checked).end() + .find('.close-menu').toggle(checked).end() + .find('#banner h1').css({ paddingLeft : checked ? 0 : 30 }); + }); + + // make sure the case insensitive button is checked (visually) + $('#csfalse').addClass('switch-selection-right'); + + // search option buttons + $('.switch-label').click(function(){ + var tar = $(this).attr('for'); + $('#' + tar) + .prop('checked', true) + .change() + .siblings('.switch-selection') + .toggleClass( 'switch-selection-right', (tar === 'letter' || tar === 'csfalse') ); + }); +}); \ No newline at end of file diff --git a/docs/js/search.js b/docs/js/search.js new file mode 100644 index 0000000..b8ef1ff --- /dev/null +++ b/docs/js/search.js @@ -0,0 +1,160 @@ +/* jQuery Highlight plugin + * Based on highlight v3 by Johann Burkard + * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html + * Copyright (c) 2009 Bartek Szopka + * Licensed under MIT license. + * Modified to require a minimum number of characters before searching + */ +;jQuery.extend({highlight:function(a,c,b,d,f){if(3===a.nodeType){if(c=a.data.match(c))return b=document.createElement(b||"span"),b.className=d||"highlight",a=a.splitText(c.index),a.splitText(c[0].length),d=a.cloneNode(!0),b.appendChild(d),a.parentNode.replaceChild(b,a),1}else if(1===a.nodeType&&a.childNodes&&!/(script|style)/i.test(a.tagName)&&1>$(a).closest(f).length&&(a.tagName!==b.toUpperCase()||a.className!==d))for(var e=0;e= 3",message:function(a){console&&console.log&&console.log(a)}},b=jQuery.extend(b,c);a.constructor===String&&(a=0
    ').html('
    '));return this.$tip},validate:function(){this.$element[0].parentNode||(this.hide(),this.options=this.$element=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled= !this.enabled}};b.fn.tipsy=function(a){function c(e){var c=b.data(e,"tipsy");c||(c=new l(e,b.fn.tipsy.elementOptions(e,a)),b.data(e,"tipsy",c));return c}function d(){var b=c(this);b.hoverState="in";0==a.delayIn?b.show():(b.fixTitle(),setTimeout(function(){"in"==b.hoverState&&b.show()},a.delayIn))}function f(){var b=c(this);b.hoverState="out";0==a.delayOut?b.hide():setTimeout(function(){"out"==b.hoverState&&b.hide()},a.delayOut)}if(!0===a)return this.data("tipsy");if("string"==typeof a){var g=this.data("tipsy"); if(g)g[a]();return this}a=b.extend({},b.fn.tipsy.defaults,a);a.live||this.each(function(){c(this)});if("manual"!=a.trigger){var g=a.live?"live":"bind",h="hover"==a.trigger?"mouseleave":"blur";this[g]("hover"==a.trigger?"mouseenter":"focus",d)[g](h,f)}return this};b.fn.tipsy.defaults={className:null,delayIn:0,delayOut:0,fade:!1,fallback:"",gravity:"n",html:!1,live:!1,offset:0,opacity:0.8,title:"title",theme:["black","white"],trigger:"hover"};b.fn.tipsy.elementOptions=function(a,c){return b.metadata? b.extend({},c,b(a).metadata()):c};b.fn.tipsy.autoNS=function(){return b(this).offset().top>b(document).scrollTop()+b(window).height()/2?"s":"n"};b.fn.tipsy.autoWE=function(){return b(this).offset().left>b(document).scrollLeft()+b(window).width()/2?"e":"w"};b.fn.tipsy.autoBounds=function(a,c){return function(){var d=c[0],f=1 0 ? '' : + value.length > 2 ? 'No results' : 'Please enter three or more letters' + ); + } else { + message(''); + } + }, + message = function(text){ + $status + .attr('original-title', text) + .tipsy( text === '' ? 'hide' : 'show' ); + // make sure the result count doesn't cover the search text + $search.css('padding-right', $status.width() + 5); + }, + jumpTo = function(){ + if (resultsLength) { + var resultPosition, parentPosition, + $current = $results.eq(index), + $collapsible = $current.closest('.collapsible, tr[id]'); + if ($collapsible.length && $collapsible.is(':hidden')) { + $collapsible.slideToggle(); + } + if ($current.length) { + resultPosition = $current.position().top; + parentPosition = $collapsible.length ? $current.closest('tr[id]').position().top : resultPosition; + if (parentPosition + $(window).height() < resultPosition) { + parentPosition = resultPosition; + } + $window.scrollTop( parentPosition - 28 ); + } + } + updateStatus(); + }, + applySearch = function(){ + searching = queryString.parse(search); + if (searching.q) { + $('#main-nav-check').prop('checked', true); + $search + .val( searching.q ) + // make searching.index a zero-based index + .trigger('change', [ isNaN(searching.index) ? 0 : parseInt(searching.index, 10) - 1 ]); + } + }; + + // make sure defaults are set + $('#word, #csfalse').click(); + + $search + // needed for IE + .on('keyup', function(e){ + if (e.which === 13) { + $(this).trigger('change'); + } + }) + .add('#word, #letter, #cstrue, #csfalse').on('change', function(event, newIndex){ + index = newIndex || 0; + $status.addClass('busy'); + setTimeout(function(){ + $main + .unhighlight() + .highlight( $search.val(), { + ignore:'thead', + wordsOnly: $word.is(':checked'), + caseSensitive: $case.is(':checked') + }); + $results = $('.highlight'); + resultsLength = $results.length; + if (index > resultsLength) { + index = resultsLength - 1; + } + jumpTo(); + }, 1); + }); + $('.search-prev, .search-next').click(function(){ + if (resultsLength) { + index = index + ($(this).hasClass('search-prev') ? -1 : 1); + if (index < 0) { index = resultsLength - 1; } + if (index > resultsLength - 1) { index = 0; } + jumpTo(); + } + }); + $('.search-clear').click(function(){ + $search.val('').change(); + updateStatus(); + }); + $main.on('click', '.highlight', function(){ + index = $results.index(this); + updateStatus(); + }); + + $('.tooltip-bottom').tipsy({ gravity: 'n' }); + $('.tooltip-top').tipsy({ gravity: 's' }); + $('.tooltip-edge-left').tipsy({ gravity: 'nw' }); + $('.tooltip-edge-right').tipsy({ gravity: 'ne' }); + $('.tooltip-right').tipsy({ gravity: 'w' }); + $('.status').tipsy({ + gravity: 's', + opacity: 1, + theme: [ '#d9534f', 'white' ] + }); + + // search on load + // ?q=array&index=10 + if (search) { + applySearch(); + } + +}); \ No newline at end of file diff --git a/docs/js/select2-3.4.6.min.js b/docs/js/select2-3.4.6.min.js new file mode 100644 index 0000000..335c85e --- /dev/null +++ b/docs/js/select2-3.4.6.min.js @@ -0,0 +1,22 @@ +/* +Copyright 2014 Igor Vaynberg + +Version: 3.4.6 Timestamp: Sat Mar 22 22:30:15 EDT 2014 + +This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU +General Public License version 2 (the "GPL License"). You may choose either license to govern your +use of this software only upon the condition that you accept all of the terms of either the Apache +License or the GPL License. + +You may obtain a copy of the Apache License and the GPL License at: + +http://www.apache.org/licenses/LICENSE-2.0 +http://www.gnu.org/licenses/gpl-2.0.html + +Unless required by applicable law or agreed to in writing, software distributed under the Apache License +or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the Apache License and the GPL License for the specific language governing +permissions and limitations under the Apache License and the GPL License. +*/ +!function(a){"undefined"==typeof a.fn.each2&&a.extend(a.fn,{each2:function(b){for(var c=a([0]),d=-1,e=this.length;++dc;c++)e=a.charAt(c),b+=m[e]||e;return b}function p(a,b){for(var c=0,d=b.length;d>c;c+=1)if(r(a,b[c]))return c;return-1}function q(){var b=a(l);b.appendTo("body");var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function r(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function s(b,c){var d,e,f;if(null===b||b.length<1)return[];for(d=b.split(c),e=0,f=d.length;f>e;e+=1)d[e]=a.trim(d[e]);return d}function t(a){return a.outerWidth(!1)-a.width()}function u(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function v(c){c.on("mousemove",function(c){var d=i;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function w(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function x(a){var c,b=!1;return function(){return b===!1&&(c=a(),b=!0),c}}function y(a,b){var c=w(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){p(a.target,b.get())>=0&&c(a)})}function z(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus();var e=b.offsetWidth>0||b.offsetHeight>0;e&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function A(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function B(a){a.preventDefault(),a.stopPropagation()}function C(a){a.preventDefault(),a.stopImmediatePropagation()}function D(b){if(!h){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);h=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),h.attr("class","select2-sizer"),a("body").append(h)}return h.text(b.val()),h.width()}function E(b,c,d){var e,g,f=[];e=b.attr("class"),e&&(e=""+e,a(e.split(" ")).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=c.attr("class"),e&&(e=""+e,a(e.split(" ")).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(g))})),b.attr("class",f.join(" "))}function F(a,b,c,d){var e=o(a.toUpperCase()).indexOf(o(b.toUpperCase())),f=b.length;return 0>e?(c.push(d(a)),void 0):(c.push(d(a.substring(0,e))),c.push(""),c.push(d(a.substring(e,e+f))),c.push(""),c.push(d(a.substring(e+f,a.length))),void 0)}function G(a){var b={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})}function H(c){var d,e=null,f=c.quietMillis||100,g=c.url,h=this;return function(i){window.clearTimeout(d),d=window.setTimeout(function(){var d=c.data,f=g,j=c.transport||a.fn.select2.ajaxDefaults.transport,k={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},l=a.extend({},a.fn.select2.ajaxDefaults.params,k);d=d?d.call(h,i.term,i.page,i.context):null,f="function"==typeof f?f.call(h,i.term,i.page,i.context):f,e&&"function"==typeof e.abort&&e.abort(),c.params&&(a.isFunction(c.params)?a.extend(l,c.params.call(h)):a.extend(l,c.params)),a.extend(l,{url:f,dataType:c.dataType,data:d,success:function(a){var b=c.results(a,i.page);i.callback(b)}}),e=j.call(h,l)},f)}}function I(b){var d,e,c=b,f=function(a){return""+a.text};a.isArray(c)&&(e=c,c={results:e}),a.isFunction(c)===!1&&(e=c,c=function(){return e});var g=c();return g.text&&(f=g.text,a.isFunction(f)||(d=g.text,f=function(a){return a[d]})),function(b){var g,d=b.term,e={results:[]};return""===d?(b.callback(c()),void 0):(g=function(c,e){var h,i;if(c=c[0],c.children){h={};for(i in c)c.hasOwnProperty(i)&&(h[i]=c[i]);h.children=[],a(c.children).each2(function(a,b){g(b,h.children)}),(h.children.length||b.matcher(d,f(h),c))&&e.push(h)}else b.matcher(d,f(c),c)&&e.push(c)},a(c().results).each2(function(a,b){g(b,e.results)}),b.callback(e),void 0)}}function J(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]};a(d?c():c).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g)}}function K(b,c){if(a.isFunction(b))return!0;if(!b)return!1;if("string"==typeof b)return!0;throw new Error(c+" must be a string, function, or falsy value")}function L(b){if(a.isFunction(b)){var c=Array.prototype.slice.call(arguments,1);return b.apply(null,c)}return b}function M(b){var c=0;return a.each(b,function(a,b){b.children?c+=M(b.children):c++}),c}function N(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||e.tokenSeparators.length<1)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice.call(this,h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(r(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:void 0}function O(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,h,j,k,i={x:0,y:0},c={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case c.LEFT:case c.RIGHT:case c.UP:case c.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case c.SHIFT:case c.CTRL:case c.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="
    ",m={"\u24b6":"A","\uff21":"A","\xc0":"A","\xc1":"A","\xc2":"A","\u1ea6":"A","\u1ea4":"A","\u1eaa":"A","\u1ea8":"A","\xc3":"A","\u0100":"A","\u0102":"A","\u1eb0":"A","\u1eae":"A","\u1eb4":"A","\u1eb2":"A","\u0226":"A","\u01e0":"A","\xc4":"A","\u01de":"A","\u1ea2":"A","\xc5":"A","\u01fa":"A","\u01cd":"A","\u0200":"A","\u0202":"A","\u1ea0":"A","\u1eac":"A","\u1eb6":"A","\u1e00":"A","\u0104":"A","\u023a":"A","\u2c6f":"A","\ua732":"AA","\xc6":"AE","\u01fc":"AE","\u01e2":"AE","\ua734":"AO","\ua736":"AU","\ua738":"AV","\ua73a":"AV","\ua73c":"AY","\u24b7":"B","\uff22":"B","\u1e02":"B","\u1e04":"B","\u1e06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24b8":"C","\uff23":"C","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\xc7":"C","\u1e08":"C","\u0187":"C","\u023b":"C","\ua73e":"C","\u24b9":"D","\uff24":"D","\u1e0a":"D","\u010e":"D","\u1e0c":"D","\u1e10":"D","\u1e12":"D","\u1e0e":"D","\u0110":"D","\u018b":"D","\u018a":"D","\u0189":"D","\ua779":"D","\u01f1":"DZ","\u01c4":"DZ","\u01f2":"Dz","\u01c5":"Dz","\u24ba":"E","\uff25":"E","\xc8":"E","\xc9":"E","\xca":"E","\u1ec0":"E","\u1ebe":"E","\u1ec4":"E","\u1ec2":"E","\u1ebc":"E","\u0112":"E","\u1e14":"E","\u1e16":"E","\u0114":"E","\u0116":"E","\xcb":"E","\u1eba":"E","\u011a":"E","\u0204":"E","\u0206":"E","\u1eb8":"E","\u1ec6":"E","\u0228":"E","\u1e1c":"E","\u0118":"E","\u1e18":"E","\u1e1a":"E","\u0190":"E","\u018e":"E","\u24bb":"F","\uff26":"F","\u1e1e":"F","\u0191":"F","\ua77b":"F","\u24bc":"G","\uff27":"G","\u01f4":"G","\u011c":"G","\u1e20":"G","\u011e":"G","\u0120":"G","\u01e6":"G","\u0122":"G","\u01e4":"G","\u0193":"G","\ua7a0":"G","\ua77d":"G","\ua77e":"G","\u24bd":"H","\uff28":"H","\u0124":"H","\u1e22":"H","\u1e26":"H","\u021e":"H","\u1e24":"H","\u1e28":"H","\u1e2a":"H","\u0126":"H","\u2c67":"H","\u2c75":"H","\ua78d":"H","\u24be":"I","\uff29":"I","\xcc":"I","\xcd":"I","\xce":"I","\u0128":"I","\u012a":"I","\u012c":"I","\u0130":"I","\xcf":"I","\u1e2e":"I","\u1ec8":"I","\u01cf":"I","\u0208":"I","\u020a":"I","\u1eca":"I","\u012e":"I","\u1e2c":"I","\u0197":"I","\u24bf":"J","\uff2a":"J","\u0134":"J","\u0248":"J","\u24c0":"K","\uff2b":"K","\u1e30":"K","\u01e8":"K","\u1e32":"K","\u0136":"K","\u1e34":"K","\u0198":"K","\u2c69":"K","\ua740":"K","\ua742":"K","\ua744":"K","\ua7a2":"K","\u24c1":"L","\uff2c":"L","\u013f":"L","\u0139":"L","\u013d":"L","\u1e36":"L","\u1e38":"L","\u013b":"L","\u1e3c":"L","\u1e3a":"L","\u0141":"L","\u023d":"L","\u2c62":"L","\u2c60":"L","\ua748":"L","\ua746":"L","\ua780":"L","\u01c7":"LJ","\u01c8":"Lj","\u24c2":"M","\uff2d":"M","\u1e3e":"M","\u1e40":"M","\u1e42":"M","\u2c6e":"M","\u019c":"M","\u24c3":"N","\uff2e":"N","\u01f8":"N","\u0143":"N","\xd1":"N","\u1e44":"N","\u0147":"N","\u1e46":"N","\u0145":"N","\u1e4a":"N","\u1e48":"N","\u0220":"N","\u019d":"N","\ua790":"N","\ua7a4":"N","\u01ca":"NJ","\u01cb":"Nj","\u24c4":"O","\uff2f":"O","\xd2":"O","\xd3":"O","\xd4":"O","\u1ed2":"O","\u1ed0":"O","\u1ed6":"O","\u1ed4":"O","\xd5":"O","\u1e4c":"O","\u022c":"O","\u1e4e":"O","\u014c":"O","\u1e50":"O","\u1e52":"O","\u014e":"O","\u022e":"O","\u0230":"O","\xd6":"O","\u022a":"O","\u1ece":"O","\u0150":"O","\u01d1":"O","\u020c":"O","\u020e":"O","\u01a0":"O","\u1edc":"O","\u1eda":"O","\u1ee0":"O","\u1ede":"O","\u1ee2":"O","\u1ecc":"O","\u1ed8":"O","\u01ea":"O","\u01ec":"O","\xd8":"O","\u01fe":"O","\u0186":"O","\u019f":"O","\ua74a":"O","\ua74c":"O","\u01a2":"OI","\ua74e":"OO","\u0222":"OU","\u24c5":"P","\uff30":"P","\u1e54":"P","\u1e56":"P","\u01a4":"P","\u2c63":"P","\ua750":"P","\ua752":"P","\ua754":"P","\u24c6":"Q","\uff31":"Q","\ua756":"Q","\ua758":"Q","\u024a":"Q","\u24c7":"R","\uff32":"R","\u0154":"R","\u1e58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1e5a":"R","\u1e5c":"R","\u0156":"R","\u1e5e":"R","\u024c":"R","\u2c64":"R","\ua75a":"R","\ua7a6":"R","\ua782":"R","\u24c8":"S","\uff33":"S","\u1e9e":"S","\u015a":"S","\u1e64":"S","\u015c":"S","\u1e60":"S","\u0160":"S","\u1e66":"S","\u1e62":"S","\u1e68":"S","\u0218":"S","\u015e":"S","\u2c7e":"S","\ua7a8":"S","\ua784":"S","\u24c9":"T","\uff34":"T","\u1e6a":"T","\u0164":"T","\u1e6c":"T","\u021a":"T","\u0162":"T","\u1e70":"T","\u1e6e":"T","\u0166":"T","\u01ac":"T","\u01ae":"T","\u023e":"T","\ua786":"T","\ua728":"TZ","\u24ca":"U","\uff35":"U","\xd9":"U","\xda":"U","\xdb":"U","\u0168":"U","\u1e78":"U","\u016a":"U","\u1e7a":"U","\u016c":"U","\xdc":"U","\u01db":"U","\u01d7":"U","\u01d5":"U","\u01d9":"U","\u1ee6":"U","\u016e":"U","\u0170":"U","\u01d3":"U","\u0214":"U","\u0216":"U","\u01af":"U","\u1eea":"U","\u1ee8":"U","\u1eee":"U","\u1eec":"U","\u1ef0":"U","\u1ee4":"U","\u1e72":"U","\u0172":"U","\u1e76":"U","\u1e74":"U","\u0244":"U","\u24cb":"V","\uff36":"V","\u1e7c":"V","\u1e7e":"V","\u01b2":"V","\ua75e":"V","\u0245":"V","\ua760":"VY","\u24cc":"W","\uff37":"W","\u1e80":"W","\u1e82":"W","\u0174":"W","\u1e86":"W","\u1e84":"W","\u1e88":"W","\u2c72":"W","\u24cd":"X","\uff38":"X","\u1e8a":"X","\u1e8c":"X","\u24ce":"Y","\uff39":"Y","\u1ef2":"Y","\xdd":"Y","\u0176":"Y","\u1ef8":"Y","\u0232":"Y","\u1e8e":"Y","\u0178":"Y","\u1ef6":"Y","\u1ef4":"Y","\u01b3":"Y","\u024e":"Y","\u1efe":"Y","\u24cf":"Z","\uff3a":"Z","\u0179":"Z","\u1e90":"Z","\u017b":"Z","\u017d":"Z","\u1e92":"Z","\u1e94":"Z","\u01b5":"Z","\u0224":"Z","\u2c7f":"Z","\u2c6b":"Z","\ua762":"Z","\u24d0":"a","\uff41":"a","\u1e9a":"a","\xe0":"a","\xe1":"a","\xe2":"a","\u1ea7":"a","\u1ea5":"a","\u1eab":"a","\u1ea9":"a","\xe3":"a","\u0101":"a","\u0103":"a","\u1eb1":"a","\u1eaf":"a","\u1eb5":"a","\u1eb3":"a","\u0227":"a","\u01e1":"a","\xe4":"a","\u01df":"a","\u1ea3":"a","\xe5":"a","\u01fb":"a","\u01ce":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1ead":"a","\u1eb7":"a","\u1e01":"a","\u0105":"a","\u2c65":"a","\u0250":"a","\ua733":"aa","\xe6":"ae","\u01fd":"ae","\u01e3":"ae","\ua735":"ao","\ua737":"au","\ua739":"av","\ua73b":"av","\ua73d":"ay","\u24d1":"b","\uff42":"b","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24d2":"c","\uff43":"c","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\xe7":"c","\u1e09":"c","\u0188":"c","\u023c":"c","\ua73f":"c","\u2184":"c","\u24d3":"d","\uff44":"d","\u1e0b":"d","\u010f":"d","\u1e0d":"d","\u1e11":"d","\u1e13":"d","\u1e0f":"d","\u0111":"d","\u018c":"d","\u0256":"d","\u0257":"d","\ua77a":"d","\u01f3":"dz","\u01c6":"dz","\u24d4":"e","\uff45":"e","\xe8":"e","\xe9":"e","\xea":"e","\u1ec1":"e","\u1ebf":"e","\u1ec5":"e","\u1ec3":"e","\u1ebd":"e","\u0113":"e","\u1e15":"e","\u1e17":"e","\u0115":"e","\u0117":"e","\xeb":"e","\u1ebb":"e","\u011b":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u1e19":"e","\u1e1b":"e","\u0247":"e","\u025b":"e","\u01dd":"e","\u24d5":"f","\uff46":"f","\u1e1f":"f","\u0192":"f","\ua77c":"f","\u24d6":"g","\uff47":"g","\u01f5":"g","\u011d":"g","\u1e21":"g","\u011f":"g","\u0121":"g","\u01e7":"g","\u0123":"g","\u01e5":"g","\u0260":"g","\ua7a1":"g","\u1d79":"g","\ua77f":"g","\u24d7":"h","\uff48":"h","\u0125":"h","\u1e23":"h","\u1e27":"h","\u021f":"h","\u1e25":"h","\u1e29":"h","\u1e2b":"h","\u1e96":"h","\u0127":"h","\u2c68":"h","\u2c76":"h","\u0265":"h","\u0195":"hv","\u24d8":"i","\uff49":"i","\xec":"i","\xed":"i","\xee":"i","\u0129":"i","\u012b":"i","\u012d":"i","\xef":"i","\u1e2f":"i","\u1ec9":"i","\u01d0":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u012f":"i","\u1e2d":"i","\u0268":"i","\u0131":"i","\u24d9":"j","\uff4a":"j","\u0135":"j","\u01f0":"j","\u0249":"j","\u24da":"k","\uff4b":"k","\u1e31":"k","\u01e9":"k","\u1e33":"k","\u0137":"k","\u1e35":"k","\u0199":"k","\u2c6a":"k","\ua741":"k","\ua743":"k","\ua745":"k","\ua7a3":"k","\u24db":"l","\uff4c":"l","\u0140":"l","\u013a":"l","\u013e":"l","\u1e37":"l","\u1e39":"l","\u013c":"l","\u1e3d":"l","\u1e3b":"l","\u017f":"l","\u0142":"l","\u019a":"l","\u026b":"l","\u2c61":"l","\ua749":"l","\ua781":"l","\ua747":"l","\u01c9":"lj","\u24dc":"m","\uff4d":"m","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0271":"m","\u026f":"m","\u24dd":"n","\uff4e":"n","\u01f9":"n","\u0144":"n","\xf1":"n","\u1e45":"n","\u0148":"n","\u1e47":"n","\u0146":"n","\u1e4b":"n","\u1e49":"n","\u019e":"n","\u0272":"n","\u0149":"n","\ua791":"n","\ua7a5":"n","\u01cc":"nj","\u24de":"o","\uff4f":"o","\xf2":"o","\xf3":"o","\xf4":"o","\u1ed3":"o","\u1ed1":"o","\u1ed7":"o","\u1ed5":"o","\xf5":"o","\u1e4d":"o","\u022d":"o","\u1e4f":"o","\u014d":"o","\u1e51":"o","\u1e53":"o","\u014f":"o","\u022f":"o","\u0231":"o","\xf6":"o","\u022b":"o","\u1ecf":"o","\u0151":"o","\u01d2":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edd":"o","\u1edb":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u01eb":"o","\u01ed":"o","\xf8":"o","\u01ff":"o","\u0254":"o","\ua74b":"o","\ua74d":"o","\u0275":"o","\u01a3":"oi","\u0223":"ou","\ua74f":"oo","\u24df":"p","\uff50":"p","\u1e55":"p","\u1e57":"p","\u01a5":"p","\u1d7d":"p","\ua751":"p","\ua753":"p","\ua755":"p","\u24e0":"q","\uff51":"q","\u024b":"q","\ua757":"q","\ua759":"q","\u24e1":"r","\uff52":"r","\u0155":"r","\u1e59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u0157":"r","\u1e5f":"r","\u024d":"r","\u027d":"r","\ua75b":"r","\ua7a7":"r","\ua783":"r","\u24e2":"s","\uff53":"s","\xdf":"s","\u015b":"s","\u1e65":"s","\u015d":"s","\u1e61":"s","\u0161":"s","\u1e67":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u015f":"s","\u023f":"s","\ua7a9":"s","\ua785":"s","\u1e9b":"s","\u24e3":"t","\uff54":"t","\u1e6b":"t","\u1e97":"t","\u0165":"t","\u1e6d":"t","\u021b":"t","\u0163":"t","\u1e71":"t","\u1e6f":"t","\u0167":"t","\u01ad":"t","\u0288":"t","\u2c66":"t","\ua787":"t","\ua729":"tz","\u24e4":"u","\uff55":"u","\xf9":"u","\xfa":"u","\xfb":"u","\u0169":"u","\u1e79":"u","\u016b":"u","\u1e7b":"u","\u016d":"u","\xfc":"u","\u01dc":"u","\u01d8":"u","\u01d6":"u","\u01da":"u","\u1ee7":"u","\u016f":"u","\u0171":"u","\u01d4":"u","\u0215":"u","\u0217":"u","\u01b0":"u","\u1eeb":"u","\u1ee9":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u0173":"u","\u1e77":"u","\u1e75":"u","\u0289":"u","\u24e5":"v","\uff56":"v","\u1e7d":"v","\u1e7f":"v","\u028b":"v","\ua75f":"v","\u028c":"v","\ua761":"vy","\u24e6":"w","\uff57":"w","\u1e81":"w","\u1e83":"w","\u0175":"w","\u1e87":"w","\u1e85":"w","\u1e98":"w","\u1e89":"w","\u2c73":"w","\u24e7":"x","\uff58":"x","\u1e8b":"x","\u1e8d":"x","\u24e8":"y","\uff59":"y","\u1ef3":"y","\xfd":"y","\u0177":"y","\u1ef9":"y","\u0233":"y","\u1e8f":"y","\xff":"y","\u1ef7":"y","\u1e99":"y","\u1ef5":"y","\u01b4":"y","\u024f":"y","\u1eff":"y","\u24e9":"z","\uff5a":"z","\u017a":"z","\u1e91":"z","\u017c":"z","\u017e":"z","\u1e93":"z","\u1e95":"z","\u01b6":"z","\u0225":"z","\u0240":"z","\u2c6c":"z","\ua763":"z"};j=a(document),g=function(){var a=1;return function(){return a++}}(),j.on("mousemove",function(a){i.x=a.pageX,i.y=a.pageY}),d=O(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,f=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&c.element.data("select2").destroy(),this.container=this.createContainer(),this.liveRegion=a("",{role:"status","aria-live":"polite"}).addClass("select2-hidden-accessible").appendTo(document.body),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+g()).replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.containerSelector="#"+this.containerId,this.container.attr("id",this.containerId),this.body=x(function(){return c.element.closest("body")}),E(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",c.element.attr("style")),this.container.css(L(c.containerCss)),this.container.addClass(L(c.containerCssClass)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",B),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),E(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(L(c.dropdownCssClass)),this.dropdown.data("select2",this),this.dropdown.on("click",B),this.results=d=this.container.find(f),this.search=e=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",B),v(this.results),this.dropdown.on("mousemove-filtered touchstart touchmove touchend",f,this.bind(this.highlightUnderEvent)),this.dropdown.on("touchend",f,this.bind(this.selectHighlighted)),this.dropdown.on("touchmove",f,this.bind(this.touchMoved)),this.dropdown.on("touchstart touchend",f,this.bind(this.clearTouchMoved)),y(80,this.results),this.dropdown.on("scroll-debounced",f,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),B(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),B(a))}),u(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",f,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown focusin",function(a){a.stopPropagation()}),this.nextSearchTerm=b,a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),k=k||q(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.search.attr("placeholder",c.searchInputPlaceholder)},destroy:function(){var a=this.opts.element,c=a.data("select2");this.close(),this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),c!==b&&(c.container.remove(),c.liveRegion.remove(),c.dropdown.remove(),a.removeClass("select2-offscreen").removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?a.attr({tabindex:this.elementTabIndex}):a.removeAttr("tabindex"),a.show())},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:r(a.attr("locked"),"locked")||r(a.data("locked"),!0)}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:void 0},prepareOpts:function(c){var d,e,f,h,i=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a ","
    "," ","
      ","
    ","
    "].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var c,d,e;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.search.focus(),c=this.search.get(0),c.createTextRange?(d=c.createTextRange(),d.collapse(!1),d.select()):c.setSelectionRange&&(e=this.search.val().length,c.setSelectionRange(e,e)),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus()},destroy:function(){a("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments)},initContainer:function(){var b,h,d=this.container,e=this.dropdown,f=g();this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=b=d.find(".select2-choice"),this.focusser=d.find(".select2-focusser"),b.find(".select2-chosen").attr("id","select2-chosen-"+f),this.focusser.attr("aria-labelledby","select2-chosen-"+f),this.results.attr("id","select2-results-"+f),this.search.attr("aria-owns","select2-results-"+f),this.focusser.attr("id","s2id_autogen"+f),h=a("label[for='"+this.opts.element.attr("id")+"']"),this.focusser.prev().text(h.text()).attr("for",this.focusser.attr("id"));var i=this.opts.element.attr("title");this.opts.element.attr("title",i||h.text()),this.focusser.attr("tabindex",this.elementTabIndex),this.search.attr("id",this.focusser.attr("id")+"_search"),this.search.prev().text(a("label[for='"+this.focusser.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()){if(a.which===c.PAGE_UP||a.which===c.PAGE_DOWN)return B(a),void 0;switch(a.which){case c.UP:case c.DOWN:return this.moveHighlight(a.which===c.UP?-1:1),B(a),void 0;case c.ENTER:return this.selectHighlighted(),B(a),void 0;case c.TAB:return this.selectHighlighted({noFocus:!0}),void 0;case c.ESC:return this.cancel(a),B(a),void 0}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body().get(0)&&window.setTimeout(this.bind(function(){this.opened()&&this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&a.which!==c.TAB&&!c.isControl(a)&&!c.isFunctionKey(a)&&a.which!==c.ESC){if(this.opts.openOnEnter===!1&&a.which===c.ENTER)return B(a),void 0;if(a.which==c.DOWN||a.which==c.UP||a.which==c.ENTER&&this.opts.openOnEnter){if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return;return this.open(),B(a),void 0}return a.which==c.DELETE||a.which==c.BACKSPACE?(this.opts.allowClear&&this.clear(),B(a),void 0):void 0}})),u(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){if(this.opts.minimumResultsForSearch>=0){if(a.stopPropagation(),this.opened())return;this.open()}})),b.on("mousedown touchstart","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),C(a),this.close(),this.selection.focus())})),b.on("mousedown touchstart",this.bind(function(c){n(b),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),B(c)})),e.on("mousedown touchstart",this.bind(function(){this.search.focus()})),b.on("focus",this.bind(function(a){B(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.setPlaceholder()},clear:function(b){var c=this.selection.data("select2-data");if(c){var d=a.Event("select2-clearing");if(this.opts.element.trigger(d),d.isDefaultPrevented())return;var e=this.getPlaceholderOption();this.opts.element.val(e?e.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),b!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder(),c.nextSearchTerm=c.opts.nextSearchTerm(a,c.search.val()))})}},isPlaceholderOptionSelected:function(){var a;return this.getPlaceholder()?(a=this.getPlaceholderOption())!==b&&a.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===b||null===this.opts.element.val():!1},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find("option").filter(function(){return this.selected&&!this.disabled});b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=r(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===b?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&a!==b){if(this.select&&this.getPlaceholderOption()===b)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,b,c){var d=0,e=this;if(this.findHighlightableChoices().each2(function(a,b){return r(e.id(b.data("select2-data")),e.opts.element.val())?(d=a,!1):void 0}),c!==!1&&(b===!0&&d>=0?this.highlight(d):this.highlight(0)),b===!0){var g=this.opts.minimumResultsForSearch;g>=0&&this.showSearch(M(a.results)>=g)}},showSearch:function(b){this.showSearchInput!==b&&(this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b))},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.close(),b&&b.noFocus||!this.opts.shouldFocusInput(this)||this.focusser.focus(),r(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,e,c=this.selection.find(".select2-chosen");this.selection.data("select2-data",a),c.empty(),null!==a&&(d=this.opts.formatSelection(a,c,this.opts.escapeMarkup)),d!==b&&c.append(d),e=this.opts.formatSelectionCssClass(a,c),e!==b&&c.addClass(e),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find("option").filter(function(){return this.selected}).each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(!a&&0!==a)return this.clear(c),void 0;if(this.opts.initSelection===b)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a){var c,d=!1;return 0===arguments.length?(c=this.selection.data("select2-data"),c==b&&(c=null),c):(arguments.length>1&&(d=arguments[1]),a?(c=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),d&&this.triggerChange({added:a,removed:c})):this.clear(d),void 0)}}),f=O(d,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["
      ","
    • "," "," ","
    • ","
    ","
    ","
      ","
    ","
    "].join(""));return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find("option").filter(function(){return this.selected&&!this.disabled}).each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=s(c.val(),b.separator),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return r(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;c0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",b,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.updateResults(!0),this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){p(e.id(this),c)<0&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer.call(this,a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,c){this.triggerSelect(a)&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.clearSearch(),this.updateResults(),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(a,!1,this.opts.closeOnSelect===!0),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()?this.updateResults(!0):this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.updateResults(),this.search.select()),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),c&&c.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,k,d=!c.locked,e=a("
  • "),f=a("
  • "),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div"),this.opts.escapeMarkup),j!=b&&g.find("div").replaceWith("
    "+j+"
    "),k=this.opts.formatSelectionCssClass(c,g.find("div")),k!=b&&g.addClass(k),d&&g.find(".select2-search-choice-close").on("mousedown",B).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),B(b),this.close(),this.focusSearch())})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(b){var d,e,c=this.getVal();if(b=b.closest(".select2-search-choice"),0===b.length)throw"Invalid argument: "+b+". Must be .select2-search-choice";if(d=b.data("select2-data")){var f=a.Event("select2-removing");if(f.val=this.id(d),f.choice=d,this.opts.element.trigger(f),f.isDefaultPrevented())return!1;for(;(e=p(this.id(d),c))>=0;)c.splice(e,1),this.setVal(c),this.select&&this.postprocessResults();return b.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(d),choice:d}),this.triggerChange({removed:d}),!0}},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));p(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&(!a||a&&!a.more&&0===this.results.find(".select2-no-results").length)&&K(g.opts.formatNoMatches,"formatNoMatches")&&this.results.append("
  • "+L(g.opts.formatNoMatches,g.search.val())+"
  • ")},getMaxSearchWidth:function(){return this.selection.width()-t(this.search)},resizeSearch:function(){var a,b,c,d,e,f=t(this.search);a=D(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(Math.floor(e))},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),s(a,this.opts.separator))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){p(this,c)<0&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;c0&&c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),void 0;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a.map(b,f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(f.buildChangeDetails(e,f.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(b,c){var e,f,d=this;return 0===arguments.length?this.selection.children(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(f=this.data(),b||(b=[]),e=a.map(b,function(a){return d.opts.id(a)}),this.setVal(e),this.updateSelection(b),this.clearSearch(),c&&this.triggerChange(this.buildChangeDetails(f,this.data())),void 0)}}),a.fn.select2=function(){var d,e,f,g,h,c=Array.prototype.slice.call(arguments,0),i=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],j=["opened","isFocused","container","dropdown"],k=["val","data"],l={search:"externalSearch"};return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?h=d.element.prop("multiple"):(h=d.multiple||!1,"tags"in d&&(d.multiple=h=!0)),e=h?new window.Select2["class"].multi:new window.Select2["class"].single,e.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(p(c[0],i)<0)throw"Unknown method: "+c[0];if(g=b,e=a(this).data("select2"),e===b)return;if(f=c[0],"container"===f?g=e.container:"dropdown"===f?g=e.dropdown:(l[f]&&(f=l[f]),g=e[f].apply(e,c.slice(1))),p(c[0],j)>=0||p(c[0],k)&&1==c.length)return!1}}),g===b?this:g},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return F(a.text,c.term,e,d),e.join("")},formatSelection:function(a,c,d){return a?d(a.text):b},sortResults:function(a){return a},formatResultCssClass:function(a){return a.css},formatSelectionCssClass:function(){return b},formatMatches:function(a){return a+" results are available, use up and down arrow keys to navigate."},formatNoMatches:function(){return"No matches found"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" or more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results\u2026"},formatSearching:function(){return"Searching\u2026"},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a==b?null:a.id},matcher:function(a,b){return o(""+b).toUpperCase().indexOf(o(""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:N,escapeMarkup:G,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null},nextSearchTerm:function(){return b},searchInputPlaceholder:"",createSearchChoicePosition:"top",shouldFocusInput:function(a){return a.opts.minimumResultsForSearch<0?!1:!0}},a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:H,local:I,tags:J},util:{debounce:w,markMatch:F,escapeMarkup:G,stripDiacritics:o},"class":{"abstract":d,single:e,multi:f}}}}(jQuery); \ No newline at end of file diff --git a/docs/js/sugar.min.js b/docs/js/sugar.min.js new file mode 100644 index 0000000..f6cc085 --- /dev/null +++ b/docs/js/sugar.min.js @@ -0,0 +1,132 @@ +/* + * Sugar Library v1.4.1 + * + * Freely distributable and licensed under the MIT-style license. + * Copyright (c) 2013 Andrew Plummer + * http://sugarjs.com/ + * + * ---------------------------- */ +(function(){function aa(a){return function(){return a}} +var m=Object,p=Array,q=RegExp,r=Date,s=String,t=Number,u=Math,ba="undefined"!==typeof global?global:this,v=m.prototype.toString,da=m.prototype.hasOwnProperty,ea=m.defineProperty&&m.defineProperties,fa="function"===typeof q(),ga=!("0"in new s("a")),ia={},ja=/^\[object Date|Array|String|Number|RegExp|Boolean|Arguments\]$/,w="Boolean Number String Array Date RegExp Function".split(" "),la=ka("boolean",w[0]),y=ka("number",w[1]),z=ka("string",w[2]),A=ma(w[3]),C=ma(w[4]),D=ma(w[5]),F=ma(w[6]); +function ma(a){var b="Array"===a&&p.isArray||function(b,d){return(d||v.call(b))==="[object "+a+"]"};return ia[a]=b}function ka(a,b){function c(c){return G(c)?v.call(c)==="[object "+b+"]":typeof c===a}return ia[b]=c} +function na(a){a.SugarMethods||(oa(a,"SugarMethods",{}),H(a,!1,!0,{extend:function(b,c,d){H(a,!1!==d,c,b)},sugarRestore:function(){return pa(this,a,arguments,function(a,c,d){oa(a,c,d.method)})},sugarRevert:function(){return pa(this,a,arguments,function(a,c,d){d.existed?oa(a,c,d.original):delete a[c]})}}))}function H(a,b,c,d){var e=b?a.prototype:a;na(a);I(d,function(d,f){var h=e[d],l=J(e,d);F(c)&&h&&(f=qa(h,f,c));!1===c&&h||oa(e,d,f);a.SugarMethods[d]={method:f,existed:l,original:h,instance:b}})} +function K(a,b,c,d,e){var g={};d=z(d)?d.split(","):d;d.forEach(function(a,b){e(g,a,b)});H(a,b,c,g)}function pa(a,b,c,d){var e=0===c.length,g=L(c),f=!1;I(b.SugarMethods,function(b,c){if(e||-1!==g.indexOf(b))f=!0,d(c.instance?a.prototype:a,b,c)});return f}function qa(a,b,c){return function(d){return c.apply(this,arguments)?b.apply(this,arguments):a.apply(this,arguments)}}function oa(a,b,c){ea?m.defineProperty(a,b,{value:c,configurable:!0,enumerable:!1,writable:!0}):a[b]=c} +function L(a,b,c){var d=[];c=c||0;var e;for(e=a.length;cb&&(d=1/d);return c(a*d)/d}var Ea=48,Fa=57,Ga=65296,Ha=65305,Ia=".",Ja="",Ka={},La;function Ma(){return"\t\n\x0B\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u2028\u2029\u3000\ufeff"}function Na(a,b){var c="";for(a=a.toString();0>=1)a+=a;return c} +function Oa(a,b){var c,d;c=a.replace(La,function(a){a=Ka[a];a===Ia&&(d=!0);return a});return d?parseFloat(c):parseInt(c,b||10)}function T(a,b,c,d){d=P(a).toString(d||10);d=Na("0",b-d.replace(/\.\d+/,"").length)+d;if(c||0>a)d=(0>a?"-":"+")+d;return d}function Pa(a){if(11<=a&&13>=a)return"th";switch(a%10){case 1:return"st";case 2:return"nd";case 3:return"rd";default:return"th"}} +function Qa(a,b){function c(a,c){if(a||-1(f?1:2)))return Xa(a,e,b[0],f,c);d=[];L(b,function(b){if(la(b))return!1;d.push(Xa(a,e,b,f,c))});return d}function Xa(a,b,c,d,e){d&&(c%=b,0>c&&(c=b+c));return e?a.charAt(c):a[c]}function Ya(a,b){K(b,!0,!1,a,function(a,b){a[b+("equal"===b?"s":"")]=function(){return m[b].apply(null,[this].concat(L(arguments)))}})}na(m);I(w,function(a,b){na(ba[b])});var Za,$a; +for($a=0;9>=$a;$a++)Za=s.fromCharCode($a+Ga),Ja+=Za,Ka[Za]=s.fromCharCode($a+Ea);Ka[","]="";Ka["\uff0e"]=Ia;Ka[Ia]=Ia;La=q("["+Ja+"\uff0e,"+Ia+"]","g"); +"use strict";H(m,!1,!1,{keys:function(a){var b=[];if(!G(a)&&!D(a)&&!F(a))throw new TypeError("Object required");I(a,function(a){b.push(a)});return b}}); +function ab(a,b,c,d){var e=a.length,g=-1==d,f=g?e-1:0;c=isNaN(c)?f:parseInt(c>>0);0>c&&(c=e+c);if(!g&&0>c||g&&c>=e)c=f;for(;g&&0<=c||!g&&cc&&(c=a.length+c);c=isNaN(c)?0:c;for(!0===d&&(e+=c);c>>0==e&&4294967295!=e)&&e>=c&&d.push(parseInt(e));d.sort().each(function(c){return b.call(a,a[c],c,a)})}function mb(a,b,c,d,e,g){var f,h,l;0g||n&&f=Ea&&c<=Fa||c>=Ga&&c<=Ha)&&(d>=Ea&&d<=Fa||d>=Ga&&d<=Ha))&&(c=Oa(a.slice(f)),d=Oa(b.slice(f)))):(e=e!==a.charAt(f),g=g!==b.charAt(f),e!==g&&0===h&&(h=e-g)),f+=1;while(null!=c&&null!=d&&c===d);return c===d?h:c-d} +function Cb(a,b,c){z(a)||(a=s(a));c&&(a=a.toLowerCase());b&&(a=a.replace(b,""));return a}var Ab="AlphanumericSortOrder",xb="AlphanumericSortIgnore",yb="AlphanumericSortIgnoreCase",zb="AlphanumericSortEquivalents",Bb="AlphanumericSortNatural";H(p,!1,!0,{create:function(){var a=[];L(arguments,function(b){if(!ua(b)&&"length"in b&&("[object Arguments]"===v.call(b)||b.callee)||!ua(b)&&"length"in b&&!z(b)&&!va(b))b=p.prototype.slice.call(b,0);a=a.concat(b)});return a}}); +H(p,!0,!1,{find:function(a,b){ta(a);return mb(this,a,0,!1,!1,b)},findIndex:function(a,b){var c;ta(a);c=mb(this,a,0,!1,!0,b);return N(c)?-1:c}}); +H(p,!0,!0,{findFrom:function(a,b,c){return mb(this,a,b,c)},findIndexFrom:function(a,b,c){b=mb(this,a,b,c,!0);return N(b)?-1:b},findAll:function(a,b,c){var d=[],e;0a&&(a=0);return this.slice(0,a)},last:function(a){return N(a)?this[this.length-1]:this.slice(0>this.length-a?0:this.length-a)}, +from:function(a){return this.slice(a)},to:function(a){N(a)&&(a=this.length);return this.slice(0,a)},min:function(a,b){return tb(this,a,"min",b)},max:function(a,b){return tb(this,a,"max",b)},least:function(a,b){return tb(this.groupBy.apply(this,[a]),"length","min",b)},most:function(a,b){return tb(this.groupBy.apply(this,[a]),"length","max",b)},sum:function(a){a=a?this.map(a):this;return 0f?1:0)*(b?-1:1)});return c},randomize:function(){for(var a=this.concat(),b=a.length,c,d;b;)c=u.random()*b|0,d=a[--b],a[b]=a[c],a[c]=d;return a},zip:function(){var a=L(arguments);return this.map(function(b,c){return[b].concat(a.map(function(a){return c in a?a[c]:null}))})},sample:function(a){var b=this.randomize();return 0=k[1]&&c<=(k[2]|| +k[1])&&e.push(a)}),d=e),d=Ub(d));h?h="(?:"+d+")":(c||g.push(E),h="("+d+")");B&&(h+="?");return h});b?(b=Vb(f,e),e=["t","[\\s\\u3000]"].concat(f.timeMarker),h=a.match(/\\d\{\d,\d\}\)+\??$/),Wb(f,"(?:"+b+")[,\\s\\u3000]+?"+a,Jb.concat(g),d),Wb(f,a+"(?:[,\\s]*(?:"+e.join("|")+(h?"+":"*")+")"+b+")?",g.concat(Jb),d)):Wb(f,a,g,d)}}; +function Xb(a,b,c){var d,e,g=b[0],f=b[1],h=b[2];b=a[c]||a.relative;if(F(b))return b.call(a,g,f,h,c);e=a.units[8*(a.plural&&1Ba?Ba+7:Ba))}function h(){var a=B.i[k.edge];fc(function(a){if(M(k[a]))return E=a,!1},4);if("year"===E)k.e="month";else if("month"===E||"week"===E)k.e="day";n[(0>a.value?"endOf":"beginningOf")+Yb(E)]();-2===a.value&&n.reset()}function l(){var a;fc(function(b,c,d){"day"===b&&(b="date");if(M(k[b])){if(d>=wb)return n.setTime(NaN),!1;a=a||{};a[b]=k[b]; +delete k[b]}});a&&e(function(){n.set(a,!0)})}var n,x,ha,vb,B,k,E,wb,Ba,ra,ca;n=cc();vb=[];n.utc(d);C(a)?n.utc(a.isUTC()).setTime(a.getTime()):y(a)?n.setTime(a):G(a)?(n.set(a,!0),k=a):z(a)&&(ha=Y(b),a=hc(a),ha&&I(ha.o?[ha.o].concat(ha.g):ha.g,function(c,d){var g=a.match(d.q);if(g){B=d.locale;k=gc(g,d.to);B.o=d;k.utc&&n.utc();if(k.timestamp)return k=k.timestamp,!1;d.r&&(!z(k.month)&&(z(k.date)||Zb(ha,b)))&&(ca=k.month,k.month=k.date,k.date=ca);k.year&&2===k.t.length&&(k.year=100*R(U(cc(),"FullYear")/ +100)-100*R(k.year/100)+k.year);k.month&&(k.month=B.getMonth(k.month),k.shift&&!k.unit&&(k.unit=B.units[7]));k.weekday&&k.date?delete k.weekday:k.weekday&&(k.weekday=B.getWeekday(k.weekday),k.shift&&!k.unit&&(k.unit=B.units[5]));k.day&&(ca=B.i[k.day])?(k.day=ca.value,n.reset(),x=!0):k.day&&-1<(Ba=B.getWeekday(k.day))&&(delete k.day,k.num&&k.month?(e(f),k.day=1):k.weekday=Ba);k.date&&!y(k.date)&&(k.date=$b(B,k.date));k.ampm&&k.ampm===B.ampm[1]&&12>k.hour?k.hour+=12:k.ampm===B.ampm[0]&&12===k.hour&& +(k.hour=0);if("offset_hours"in k||"offset_minutes"in k)n.utc(),k.offset_minutes=k.offset_minutes||0,k.offset_minutes+=60*k.offset_hours,"-"===k.offset_sign&&(k.offset_minutes*=-1),k.minute-=k.offset_minutes;k.unit&&(x=!0,ra=ac(B,k.num),wb=B.units.indexOf(k.unit)%8,E=W.units[wb],l(),k.shift&&(ra*=(ca=B.i[k.shift])?ca.value:0),k.sign&&(ca=B.i[k.sign])&&(ra*=ca.value),M(k.weekday)&&(n.set({weekday:k.weekday},!0),delete k.weekday),k[E]=(k[E]||0)+ra);k.edge&&e(h);"-"===k.year_sign&&(k.year*=-1);fc(function(a, +b,c){b=k[a];var d=b%1;d&&(k[Ob[c-1].name]=R(d*("second"===a?1E3:60)),k[a]=Q(b))},1,4);return!1}}),k?x?n.advance(k):(n._utc&&n.reset(),kc(n,k,!0,!1,c)):("now"!==a&&(n=new r(a)),d&&n.addMinutes(-n.getTimezoneOffset())),g(),n.utc(!1));return{c:n,set:k}}function lc(a){var b,c=P(a),d=c,e=0;fc(function(a,f,h){b=Q(Da(c/f.b(),1));1<=b&&(d=b,e=h)},1);return[d,e,a]} +function mc(a){var b=lc(a.millisecondsFromNow());if(6===b[1]||5===b[1]&&4===b[0]&&a.daysFromNow()>=cc().daysInMonth())b[0]=P(a.monthsFromNow()),b[1]=6;return b}function nc(a,b,c){function d(a,c){var d=U(a,"Month");return Y(c).months[d+12*b]}Z(a,d,c);Z(Yb(a),d,c,1)}function Z(a,b,c,d){X[a]=function(a,g){var f=b(a,g);c&&(f=f.slice(0,c));d&&(f=f.slice(0,d).toUpperCase()+f.slice(d));return f}} +function oc(a,b,c){X[a]=b;X[a+a]=function(a,c){return T(b(a,c),2)};c&&(X[a+a+a]=function(a,c){return T(b(a,c),3)},X[a+a+a+a]=function(a,c){return T(b(a,c),4)})}function pc(a){var b=a.match(/(\{\w+\})|[^{}]+/g);Qb[a]=b.map(function(a){a.replace(/\{(\w+)\}/,function(b,e){a=X[e]||e;return e});return a})} +function qc(a,b,c,d){var e;if(!a.isValid())return"Invalid Date";Date[b]?b=Date[b]:F(b)&&(e=mc(a),b=b.apply(a,e.concat(Y(d))));if(!b&&c)return e=e||mc(a),0===e[1]&&(e[1]=1,e[0]=1),a=Y(d),Xb(a,e,0=b-n&&f<=h+x} +function sc(a,b,c){b=new r(b);a=(new r(c)).utc(a.isUTC());23!==U(a,"Hours")&&(b=b.getTimezoneOffset(),a=a.getTimezoneOffset(),b!==a&&(c+=(a-b).minutes()));return c} +function kc(a,b,c,d,e){function g(a){return M(b[a])?b[a]:b[a+"s"]}function f(a){return M(g(a))}var h;if(y(b)&&d)b={milliseconds:b};else if(y(b))return a.setTime(b),a;M(b.date)&&(b.day=b.date);fc(function(d,e,g){var l="day"===d;if(f(d)||l&&f("weekday"))return b.e=d,h=+g,!1;!c||("week"===d||l&&f("week"))||Sa(a,e.method,l?1:0)});Rb.forEach(function(c){var e=c.name;c=c.method;var h;h=g(e);N(h)||(d?("week"===e&&(h=(b.day||0)+7*h,c="Date"),h=h*d+U(a,c)):"month"===e&&f("day")&&Sa(a,"Date",15),Sa(a,c,h), +d&&"month"===e&&(e=h,0>e&&(e=e%12+12),e%12!=U(a,"Month")&&Sa(a,"Date",0)))});d||(f("day")||!f("weekday"))||a.setWeekday(g("weekday"));var l;a:{switch(e){case -1:l=a>cc();break a;case 1:l=ar.create(a).getTime()-(b||0)},isBefore:function(a,b){return this.getTime()d},isLeapYear:function(){var a=U(this,"FullYear");return 0===a%4&&0!==a%100||0===a%400}, +daysInMonth:function(){return 32-U(new r(U(this,"FullYear"),U(this,"Month"),32),"Date")},format:function(a,b){return qc(this,a,!1,b)},relative:function(a,b){z(a)&&(b=a,a=null);return qc(this,a,!0,b)},is:function(a,b,c){var d,e;if(this.isValid()){if(z(a))switch(a=a.trim().toLowerCase(),e=this.clone().utc(c),!0){case "future"===a:return this.getTime()>cc().getTime();case "past"===a:return this.getTime()U(e,"Day");case "weekend"===a:return 0=== +U(e,"Day")||6===U(e,"Day");case -1<(d=W.weekdays.indexOf(a)%7):return U(e,"Day")===d;case -1<(d=W.months.indexOf(a)%12):return U(e,"Month")===d}return rc(this,a,null,b,c)}},reset:function(a){var b={},c;a=a||"hours";"date"===a&&(a="days");c=Rb.some(function(b){return a===b.name||a===b.name+"s"});b[a]=a.match(/^days?/)?1:0;return c?this.set(b,!0):this},clone:function(){var a=new r(this.getTime());a.utc(!!this._utc);return a}}); +H(r,!0,!0,{iso:function(){return this.toISOString()},getWeekday:r.prototype.getDay,getUTCWeekday:r.prototype.getUTCDay});function uc(a,b){function c(){return R(this*b)}function d(){return tc(arguments)[a.j](this)}function e(){return tc(arguments)[a.j](-this)}var g=a.name,f={};f[g]=c;f[g+"s"]=c;f[g+"Before"]=e;f[g+"sBefore"]=e;f[g+"Ago"]=e;f[g+"sAgo"]=e;f[g+"After"]=d;f[g+"sAfter"]=d;f[g+"FromNow"]=d;f[g+"sFromNow"]=d;t.extend(f)}H(t,!0,!0,{duration:function(a){a=Y(a);return Xb(a,lc(this),"duration")}}); +W=Ib=r.addLocale("en",{plural:!0,timeMarker:"at",ampm:"am,pm",months:"January,February,March,April,May,June,July,August,September,October,November,December",weekdays:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",units:"millisecond:|s,second:|s,minute:|s,hour:|s,day:|s,week:|s,month:|s,year:|s",numbers:"one,two,three,four,five,six,seven,eight,nine,ten",articles:"a,an,the",tokens:"the,st|nd|rd|th,of","short":"{Month} {d}, {yyyy}","long":"{Month} {d}, {yyyy} {h}:{mm}{tt}",full:"{Weekday} {Month} {d}, {yyyy} {h}:{mm}:{ss}{tt}", +past:"{num} {unit} {sign}",future:"{num} {unit} {sign}",duration:"{num} {unit}",modifiers:[{name:"sign",src:"ago|before",value:-1},{name:"sign",src:"from now|after|from|in|later",value:1},{name:"edge",src:"last day",value:-2},{name:"edge",src:"end",value:-1},{name:"edge",src:"first day|beginning",value:1},{name:"shift",src:"last",value:-1},{name:"shift",src:"the|this",value:0},{name:"shift",src:"next",value:1}],dateParse:["{month} {year}","{shift} {unit=5-7}","{0?} {date}{1}","{0?} {edge} of {shift?} {unit=4-7?}{month?}{year?}"], +timeParse:"{num} {unit} {sign};{sign} {num} {unit};{0} {num}{1} {day} of {month} {year?};{weekday?} {month} {date}{1?} {year?};{date} {month} {year};{date} {month};{shift} {weekday};{shift} week {weekday};{weekday} {2?} {shift} week;{num} {unit=4-5} {sign} {day};{0?} {date}{1} of {month};{0?}{month?} {date?}{1?} of {shift} {unit=6-7}".split(";")});Ob=Rb.concat().reverse();Nb=Rb.concat();Nb.splice(2,1); +K(r,!0,!0,Rb,function(a,b,c){function d(a){a/=f;var c=a%1,d=b.error||0.999;c&&P(c%1)>d&&(a=R(a));return 0>a?Aa(a):Q(a)}var e=b.name,g=Yb(e),f=b.b(),h,l;b.j="add"+g+"s";h=function(a,b){return d(this.getTime()-r.create(a,b).getTime())};l=function(a,b){return d(r.create(a,b).getTime()-this.getTime())};a[e+"sAgo"]=l;a[e+"sUntil"]=l;a[e+"sSince"]=h;a[e+"sFromNow"]=h;a[b.j]=function(a,b){var c={};c[e]=a;return this.advance(c,b)};uc(b,f);3>c&&["Last","This","Next"].forEach(function(b){a["is"+b+g]=function(){return rc(this, +b+" "+e,"en")}});4>c&&(a["beginningOf"+g]=function(){var a={};switch(e){case "year":a.year=U(this,"FullYear");break;case "month":a.month=U(this,"Month");break;case "day":a.day=U(this,"Date");break;case "week":a.weekday=0}return this.set(a,!0)},a["endOf"+g]=function(){var a={hours:23,minutes:59,seconds:59,milliseconds:999};switch(e){case "year":a.month=11;a.day=31;break;case "month":a.day=this.daysInMonth();break;case "week":a.weekday=6}return this.set(a,!0)})}); +W.addFormat("([+-])?(\\d{4,4})[-.]?{full_month}[-.]?(\\d{1,2})?",!0,["year_sign","year","month","date"],!1,!0);W.addFormat("(\\d{1,2})[-.\\/]{full_month}(?:[-.\\/](\\d{2,4}))?",!0,["date","month","year"],!0);W.addFormat("{full_month}[-.](\\d{4,4})",!1,["month","year"]);W.addFormat("\\/Date\\((\\d+(?:[+-]\\d{4,4})?)\\)\\/",!1,["timestamp"]);W.addFormat(Vb(W),!1,Jb);Pb=W.g.slice(0,7).reverse();W.g=W.g.slice(7).concat(Pb);oc("f",function(a){return U(a,"Milliseconds")},!0); +oc("s",function(a){return U(a,"Seconds")});oc("m",function(a){return U(a,"Minutes")});oc("h",function(a){return U(a,"Hours")%12||12});oc("H",function(a){return U(a,"Hours")});oc("d",function(a){return U(a,"Date")});oc("M",function(a){return U(a,"Month")+1});(function(){function a(a,c){var d=U(a,"Hours");return Y(c).ampm[Q(d/12)]||""}Z("t",a,1);Z("tt",a);Z("T",a,1,1);Z("TT",a,null,2)})(); +(function(){function a(a,c){var d=U(a,"Day");return Y(c).weekdays[d]}Z("dow",a,3);Z("Dow",a,3,1);Z("weekday",a);Z("Weekday",a,null,1)})();nc("mon",0,3);nc("month",0);nc("month2",1);nc("month3",2);X.ms=X.f;X.milliseconds=X.f;X.seconds=X.s;X.minutes=X.m;X.hours=X.h;X["24hr"]=X.H;X["12hr"]=X.h;X.date=X.d;X.day=X.d;X.year=X.yyyy;K(r,!0,!0,"short,long,full",function(a,b){a[b]=function(a){return qc(this,b,!1,a)}}); +"\u3007\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07".split("").forEach(function(a,b){9=this.start&&a.start<=this.end&&a.end>=this.start&&a.end<=this.end:a>=this.start&&a<=this.end},every:function(a,b){var c,d=this.start,e=this.end,g=e=e:f<=e;)l.push(f),b&&b(f,h),f=c(f,a),h++;return l},union:function(a){return new Range(this.starta.end?this.end:a.end)},intersect:function(a){return a.start>this.end||a.enda.start?this.start:a.start,this.endc?b:c;return vc(ab?b:a)}});[t,s,r].forEach(function(a){H(a,!1,!0,{range:function(b,c){a.create&&(b=a.create(b),c=a.create(c));return new Range(b,c)}})}); +H(t,!0,!0,{upto:function(a,b,c){return t.range(this,a).every(c,b)},clamp:function(a,b){return(new Range(a,b)).clamp(this)},cap:function(a){return this.clamp(void 0,a)}});H(t,!0,!0,{downto:t.prototype.upto});H(p,!1,function(a){return a instanceof Range},{create:function(a){return a.every()}}); +"use strict";function Ac(a,b,c,d,e){Infinity!==b&&(a.timers||(a.timers=[]),y(b)||(b=1),a.n=!1,a.timers.push(setTimeout(function(){a.n||c.apply(d,e||[])},b)))} +H(Function,!0,!0,{lazy:function(a,b,c){function d(){g.lengthb;)x=Function.prototype.apply.apply(e,g.shift()),a--;Ac(d,l,function(){f=!1;h()})}};return d},throttle:function(a){return this.lazy(a,!0,1)},debounce:function(a){function b(){b.cancel();Ac(b,a,c,this,arguments)}var c=this;return b},delay:function(a){var b= +L(arguments,null,1);Ac(this,a,this,this,b);return this},every:function(a){function b(){c.apply(c,d);Ac(c,a,b)}var c=this,d=arguments,d=1=c.length)&&c.splice(b,0,a)});return a.apply(this,c)}}}); +"use strict";function Bc(a,b,c,d,e,g){var f=a.toFixed(20),h=f.search(/\./),f=f.search(/[1-9]/),h=h-f;0h&&(e=-3,b=P(h)-9,d=c.slice(0,1));c=g?za(2,10*e):za(10,3*e);return Da(a/c,b||0).format()+d.trim()} +H(t,!1,!0,{random:function(a,b){var c,d;1==arguments.length&&(b=a,a=0);c=Ca(a||0,N(b)?1:b);d=S(a||0,N(b)?1:b)+1;return Q(u.random()*(d-c)+c)}}); +H(t,!0,!0,{log:function(a){return u.log(this)/(a?u.log(a):1)},abbr:function(a){return Bc(this,a,"kmbt",0,4)},metric:function(a,b){return Bc(this,a,"n\u03bcm kMGTPE",4,N(b)?1:b)},bytes:function(a,b){return Bc(this,a,"kMGTPE",0,N(b)?4:b,!0)+"B"},isInteger:function(){return 0==this%1},isOdd:function(){return!isNaN(this)&&!this.isMultipleOf(2)},isEven:function(){return this.isMultipleOf(2)},isMultipleOf:function(a){return 0===this%a},format:function(a,b,c){var d,e,g,f="";N(b)&&(b=",");N(c)&&(c=".");d= +(y(a)?Da(this,a||0).toFixed(S(a,0)):this.toString()).replace(/^-/,"").split(".");e=d[0];g=d[1];for(d=e.length;0this?"-":"")+f},hex:function(a){return this.pad(a||1,!1,16)},times:function(a){if(a)for(var b=0;ba||Infinity===a)throw new RangeError("Invalid number");return a}function Jc(a,b){return Na(M(b)?b:" ",a)}function Kc(a,b,c,d,e){var g;if(a.length<=b)return a.toString();d=N(d)?"...":d;switch(c){case "left":return a=e?Lc(a,b,!0):a.slice(a.length-b),d+a;case "middle":return c=Aa(b/2),g=Q(b/2),b=e?Lc(a,c):a.slice(0,c),a=e?Lc(a,g,!0):a.slice(a.length-g),b+d+a;default:return b=e?Lc(a,b):a.slice(0,b),b+d}} +function Lc(a,b,c){if(c)return Lc(a.reverse(),b).reverse();c=q("(?=["+Ma()+"])");var d=0;return a.split(c).filter(function(a){d+=a.length;return d<=b}).join("")}function Mc(a,b,c){z(b)&&(b=a.indexOf(b),-1===b&&(b=c?a.length:0));return b}var Nc,Oc;H(s,!0,!1,{repeat:function(a){a=Ic(a);return Na(this,a)}}); +H(s,!0,function(a){return D(a)||2/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")},unescapeHTML:function(){return this.replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(///g, +"/").replace(/&/g,"&")},encodeBase64:function(){return Nc(unescape(encodeURIComponent(this)))},decodeBase64:function(){return decodeURIComponent(escape(Oc(this)))},each:function(a,b){var c,d,e;F(a)?(b=a,a=/[\s\S]/g):a?z(a)?a=q(Ra(a),"gi"):D(a)&&(a=q(a.source,Qa(a,"g"))):a=/[\s\S]/g;c=this.match(a)||[];if(b)for(d=0,e=c.length;d]*>","gi"),"")});return a},removeTags:function(){var a=this;sa(0]*(?:\\/>|>.*?<\\/\\1>)","gi");a=a.replace(b,"")});return a},truncate:function(a,b,c){return Kc(this,a,b,c)},truncateOnWord:function(a,b,c){return Kc(this,a,b,c,!0)},pad:function(a,b){var c,d;a=Ic(a);c=S(0,a-this.length)/2;d=Q(c);c=Aa(c);return Jc(d,b)+this+Jc(c,b)},padLeft:function(a,b){a=Ic(a);return Jc(S(0,a- +this.length),b)+this},padRight:function(a,b){a=Ic(a);return this+Jc(S(0,a-this.length),b)},first:function(a){N(a)&&(a=1);return this.substr(0,a)},last:function(a){N(a)&&(a=1);return this.substr(0>this.length-a?0:this.length-a)},toNumber:function(a){return Oa(this,a)},capitalize:function(a){var b;return this.toLowerCase().replace(a?/[^']/g:/^\S/,function(a){var d=a.toUpperCase(),e;e=b?a:d;b=d!==a;return e})},assign:function(){var a={};sa(arguments,function(b,c){G(b)?xa(a,b):a[c+1]=b});return this.replace(/\{([^{]+?)\}/g, +function(b,c){return J(a,c)?a[c]:b})}});H(s,!0,!0,{insert:s.prototype.add}); +(function(a){if(ba.btoa)Nc=ba.btoa,Oc=ba.atob;else{var b=/[^A-Za-z0-9\+\/\=]/g;Nc=function(b){var d="",e,g,f,h,l,n,x=0;do e=b.charCodeAt(x++),g=b.charCodeAt(x++),f=b.charCodeAt(x++),h=e>>2,e=(e&3)<<4|g>>4,l=(g&15)<<2|f>>6,n=f&63,isNaN(g)?l=n=64:isNaN(f)&&(n=64),d=d+a.charAt(h)+a.charAt(e)+a.charAt(l)+a.charAt(n);while(x>4,g=(g&15)<<4|h>>2,f=(h&3)<<6|l,d+=s.fromCharCode(e),64!=h&&(d+=s.fromCharCode(g)),64!=l&&(d+=s.fromCharCode(f));while(n + + + + jQuery plugin: Tablesorter 2.4 - Themes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +

    blackice

    +
    + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    blue

    + + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    dark

    + + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    default

    + + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    green

    + + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    grey

    + + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    ice

    + + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    Bootstrap

    + + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    jQuery UI

    + + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    dropbox

    + + + + + + + + + + +
    ABCD
    ABCD
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    +

    Metro Dark

    + + + + + + + + + + + + + + + + +
    Title
    ABCD
    ABCD
     
    1234
    1415165
    1320176
    1219187
    111098
    +
    + +
    + + + + diff --git a/example.json b/example.json new file mode 100644 index 0000000..4eebfd4 --- /dev/null +++ b/example.json @@ -0,0 +1,6 @@ +{ + "widgets" : "filter stickyHeaders uitheme", + "parsers" : "ignore-articles network", + "includeDependencies" : false, + "destFileName" : "jquery.tablesorter.custom-widgets.js" +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..441dc8d --- /dev/null +++ b/index.html @@ -0,0 +1,62 @@ + + + + + Basic Tablesorter Demo + + + + + + + + + + + + + + + +
    +

    tablesorter

    +

    By Christian Bach; github updates by Rob G
    + Complete docs included (updated with missing docs from this blog post) +

    + + + + + + + + + + + + + + + + + + + + + + +
    AlphaNumeric SortCurrencyAlphabeticalSites
    abc 123£10,40Koalahttp://www.google.com
    abc 1£234,10Oxhttp://www.yahoo.com
    abc 9£10,33Girafeehttp://www.facebook.com
    zyx 24£10Bisonhttp://www.whitehouse.gov/
    abc 11£3,20Chimphttp://www.ucla.edu/
    abc 2£56,10Elephanthttp://www.wikipedia.org/
    abc 9£3,20Lionhttp://www.nytimes.com/
    ABC 10£87,00Zebrahttp://www.google.com
    zyx 1£99,90Koalahttp://www.mit.edu/
    zyx 12£234,10Llamahttp://www.nasa.gov/
    + +

    This is a quick demo of the columns & zebra widget with the "sortReset" option set to true (clicking on a sort header a third time will reset the sort)

    + +
    + \ No newline at end of file diff --git a/js/extras/jquery.dragtable.mod.js b/js/extras/jquery.dragtable.mod.js new file mode 100644 index 0000000..debb642 --- /dev/null +++ b/js/extras/jquery.dragtable.mod.js @@ -0,0 +1,602 @@ +/*! Dragtable Mod for TableSorter - 2/7/2015 (v2.19.0) *//* + * Requires + * tablesorter v2.8+ + * jQuery 1.7+ + * jQuery UI (Core, Widget, Mouse & Sortable) + * Dragtable by Akottr (https://github.com/akottr) modified by Rob Garrison + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function( $ ) { +'use strict'; + var undef, + ts = $.tablesorter; + + ts.dragtable = { + create : function( _this ) { + var hasAccept, + $table = _this.originalTable.el, + handle = _this.options.dragHandle.replace('.', ''); + $table.children('thead').children().children('th,td').each(function(){ + var $this = $(this); + if ( !$this.find( _this.options.dragHandle + ',.' + handle + '-disabled' ).length ) { + hasAccept = _this.options.dragaccept ? $this.hasClass( _this.options.dragaccept.replace('.', '') ) : true; + $this + // sortClass includes a "." to match the tablesorter selectorSort option - for consistency + .wrapInner('
    ') + // add handle class + "-disabled" to drag-disabled columns + .prepend('
    '); + } + }); + }, + start : function( table ) { + table = $( table )[0]; + if ( table && table.config ) { + table.config.widgetOptions.dragtableLast = { + search : $( table ).data( 'lastSearch' ), + order : ts.dragtable.getOrder( table ) + }; + } + }, + update : function( _this ) { + var t, list, val, + dragTable = _this.originalTable, + table = dragTable.el[ 0 ], + $table = $( table ), + c = table.config, + wo = c && c.widgetOptions, + startIndex = dragTable.startIndex - 1, + endIndex = dragTable.endIndex - 1, + columnOrder = ts.dragtable.getOrder( table ) || [], + hasFilters = ts.hasWidget( $table, 'filter' ) || false, + last = wo && wo.dragtableLast || {}, + // update moved filters + filters = []; + + // only trigger updateAll if column order changed + if ( ( last.order || [] ).join( '' ) !== columnOrder.join( '' ) ) { + + if ( c.sortList.length ) { + // must deep extend (nested arrays) to prevent list from changing with c.sortList + list = $.extend( true, [], c.sortList ); + $.each( columnOrder, function( indx, value ) { + val = ts.isValueInArray( parseInt( value, 10 ), list ); + if ( value !== last.order[ indx ] && val >= 0 ) { + c.sortList[ val ][ 0 ] = indx; + } + }); + } + + // update filter widget + if ( hasFilters ) { + $.each( last.search || [], function( indx ) { + filters[ indx ] = last.search[ columnOrder[ indx ] ]; + }); + } + + // update preset editable widget columns + t = ( ts.hasWidget( c.$table, 'editable' ) || false ) ? wo.editable_columnsArray : false; + if ( t ) { + c.widgetOptions.editable_columnsArray = ts.dragtable.reindexArrayItem( t, startIndex, endIndex ); + } + // update ignore math columns + t = ( ts.hasWidget( c.$table, 'math' ) || false ) ? wo.math_ignore : false; + if ( t ) { + c.widgetOptions.math_ignore = ts.dragtable.reindexArrayItem( t, startIndex, endIndex ); + } + // update preset resizable widget widths + t = ( ts.hasWidget( c.$table, 'resizable' ) || false ) ? wo.resizable_widths : false; + if ( t ) { + // use zero-based indexes in the array + wo.resizable_widths = ts.dragtable.moveArrayItem( t, startIndex, endIndex ); + } + /* + // chart widget WIP - there are other options that need to be rearranged! + t = ( ts.hasWidget( c.$table, 'chart' ) || false ) ? wo.chart_ignoreColumns : false; + if ( t ) { + // use zero-based indexes in the array + wo.chart_ignoreColumns = ts.dragtable.moveArrayItem( t, startIndex, endIndex ); + } + */ + + $table.trigger('updateAll', [ false, function() { + if ( hasFilters ) { + setTimeout( function() { + // just update the filter values + c.lastCombinedFilter = null; + c.$table.data('lastSearch', filters); + ts.setFilters( $table, filters ); + if ($.isFunction(_this.options.tablesorterComplete)) { + _this.options.tablesorterComplete( c.table ); + } + }, 10 ); + } + } ]); + } + }, + getOrder : function( table ) { + return $( table ).children( 'thead' ).children( '.' + ts.css.headerRow ).children().map( function() { + return $( this ).attr( 'data-column' ); + }).get() || []; + }, + // bubble the moved col left or right + startColumnMove : function( dragTable ) { + var $cols, + c = dragTable.el[ 0 ].config, + startIndex = dragTable.startIndex - 1, + endIndex = dragTable.endIndex - 1, + cols = c.columns - 1, + pos = endIndex === cols ? false : endIndex <= startIndex, + $rows = c.$table.children().children( 'tr' ); + if ( c.debug ) { + ts.log( 'Inserting column ' + startIndex + ( pos ? ' before' : ' after' ) + ' column ' + endIndex ); + } + $rows.each( function() { + $cols = $( this ).children(); + $cols.eq( startIndex )[ pos ? 'insertBefore' : 'insertAfter' ]( $cols.eq( endIndex ) ); + }); + // rearrange col in colgroup + $cols = c.$table.children( 'colgroup' ).children(); + $cols.eq( startIndex )[ pos ? 'insertBefore' : 'insertAfter' ]( $cols.eq( endIndex ) ); + }, + swapNodes : function( a, b ) { + var indx, aparent, asibling, + len = a.length; + for ( indx = 0; indx < len; indx++ ) { + aparent = a[ indx ].parentNode; + asibling = a[ indx ].nextSibling === b[ indx ] ? a[ indx ] : a[ indx ].nextSibling; + b[ indx ].parentNode.insertBefore( a[ indx ], b[ indx ] ); + aparent.insertBefore( b[ indx ], asibling ); + } + }, + // http://stackoverflow.com/a/5306832/145346 + moveArrayItem : function( array, oldIndex, newIndex ) { + var indx, len = array.length; + if ( newIndex >= len ) { + indx = newIndex - len; + while ( ( indx-- ) + 1 ) { + array.push( undef ); + } + } + array.splice( newIndex, 0, array.splice( oldIndex, 1 )[ 0 ] ); + return array; + }, + reindexArrayItem : function( array, oldIndex, newIndex ) { + var nIndx = $.inArray( newIndex, array ), + oIndx = $.inArray( oldIndex, array ), + max = Math.max.apply( Math, array ), + arry = []; + // columns in the array were swapped so return original array + if ( nIndx >= 0 && oIndx >= 0 ) { + return array; + } + // columns not in the array were moved + $.each( array, function( indx, value ) { + // column (not in array) inserted between indexes + if ( newIndex < oldIndex ) { + // ( [ 0,1,2,3 ], 5, 1 ) -> column inserted between 0 & 1 => [ 0,2,3,4 ] + if ( value >= newIndex ) { + // 5 -> 1 [ 0, 2, 3 ] then 1 -> 0 [ 1, 2, 3 ] + arry.push( value + ( value < oldIndex ? 1 : 0 ) ); + } else { + arry.push( value ); + } + } else if ( newIndex > oldIndex ) { + // ( [ 0,1,2,3 ], 1, 5 ) -> column in array moved outside => [ 0,1,2,5 ] + if ( value === oldIndex ) { + arry.push( newIndex ); + } else if ( value < newIndex && value >= oldIndex ) { + arry.push( value - 1 ); + } else if ( value <= newIndex ) { + arry.push( value ); + } else if ( value > oldIndex ) { + arry.push( value + ( value < newIndex ? 0 : 1 ) ); + } + } + }); + return arry.sort(); + } + }; + +/*! dragtable v2.0.14 Mod *//* + * _____ _ + * | |___ _| | + * | | | | . | . | + * |_|_|_|___|___| + * + * Copyright (c) 2010-2013, Andres akottr@gmail.com + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * Inspired by the the dragtable from Dan Vanderkam (danvk.org/dragtable/) + * Thanks to the jquery and jqueryui comitters + * + * Any comment, bug report, feature-request is welcome + * Feel free to contact me. + */ + +/* TOKNOW: + * For IE7 you need this css rule: + * table { + * border-collapse: collapse; + * } + * Or take a clean reset.css (see http://meyerweb.com/eric/tools/css/reset/) + */ + +/* TODO: investigate + * Does not work properly with css rule: + * html { + * overflow: -moz-scrollbars-vertical; + * } + * Workaround: + * Fixing Firefox issues by scrolling down the page + * http://stackoverflow.com/questions/2451528/jquery-ui-sortable-scroll-helper-element-offset-firefox-issue + * + * var start = $.noop; + * var beforeStop = $.noop; + * if($.browser.mozilla) { + * var start = function (event, ui) { + * if( ui.helper !== undefined ) + * ui.helper.css('position','absolute').css('margin-top', $(window).scrollTop() ); + * } + * var beforeStop = function (event, ui) { + * if( ui.offset !== undefined ) + * ui.helper.css('margin-top', 0); + * } + * } + * + * and pass this as start and stop function to the sortable initialisation + * start: start, + * beforeStop: beforeStop + */ +/* + * Special thx to all pull requests comitters + */ + + $.widget("akottr.dragtable", { + options: { + revert: false, // smooth revert + dragHandle: '.table-handle', // handle for moving cols, if not exists the whole 'th' is the handle + maxMovingRows: 40, // 1 -> only header. 40 row should be enough, the rest is usually not in the viewport + excludeFooter: false, // excludes the footer row(s) while moving other columns. Make sense if there is a footer with a colspan. */ + onlyHeaderThreshold: 100, // TODO: not implemented yet, switch automatically between entire col moving / only header moving + dragaccept: null, // draggable cols -> default all + persistState: null, // url or function -> plug in your custom persistState function right here. function call is persistState(originalTable) + restoreState: null, // JSON-Object or function: some kind of experimental aka Quick-Hack TODO: do it better + exact: true, // removes pixels, so that the overlay table width fits exactly the original table width + clickDelay: 10, // ms to wait before rendering sortable list and delegating click event + containment: null, // @see http://api.jqueryui.com/sortable/#option-containment, use it if you want to move in 2 dimesnions (together with axis: null) + cursor: 'move', // @see http://api.jqueryui.com/sortable/#option-cursor + cursorAt: false, // @see http://api.jqueryui.com/sortable/#option-cursorAt + distance: 0, // @see http://api.jqueryui.com/sortable/#option-distance, for immediate feedback use "0" + tolerance: 'pointer', // @see http://api.jqueryui.com/sortable/#option-tolerance + axis: 'x', // @see http://api.jqueryui.com/sortable/#option-axis, Only vertical moving is allowed. Use 'x' or null. Use this in conjunction with the 'containment' setting + beforeStart: $.noop, // returning FALSE will stop the execution chain. + beforeMoving: $.noop, + beforeReorganize: $.noop, + beforeStop: $.noop, + // new options + tablesorterComplete: null, + sortClass : '.sorter' + }, + originalTable: { + el: null, + selectedHandle: null, + sortOrder: null, + startIndex: 0, + endIndex: 0 + }, + sortableTable: { + el: $(), + selectedHandle: $(), + movingRow: $() + }, + persistState: function() { + var _this = this; + this.originalTable.el.find('th').each(function(i) { + if (this.id !== '') { + _this.originalTable.sortOrder[this.id] = i; + } + }); + $.ajax({ + url: this.options.persistState, + data: this.originalTable.sortOrder + }); + }, + /* + * persistObj looks like + * {'id1':'2','id3':'3','id2':'1'} + * table looks like + * | id2 | id1 | id3 | + */ + _restoreState: function(persistObj) { + for (var n in persistObj) { + if (n in persistObj) { + this.originalTable.startIndex = $('#' + n).closest('th').prevAll().length + 1; + this.originalTable.endIndex = parseInt(persistObj[n], 10) + 1; + this._bubbleCols(); + } + } + }, + // bubble the moved col left or right + _bubbleCols: function() { + ts.dragtable.startColumnMove(this.originalTable); + }, + _rearrangeTableBackroundProcessing: function() { + var _this = this; + return function() { + _this._bubbleCols(); + _this.options.beforeStop(_this.originalTable); + _this.sortableTable.el.remove(); + restoreTextSelection(); + ts.dragtable.update(_this); + // persist state if necessary + if ($.isFunction(_this.options.persistState)) { + _this.options.persistState(_this.originalTable); + } else { + _this.persistState(); + } + + }; + }, + _rearrangeTable: function() { + var _this = this; + return function() { + // remove handler-class -> handler is now finished + _this.originalTable.selectedHandle.removeClass('dragtable-handle-selected'); + // add disabled class -> reorgorganisation starts soon + _this.sortableTable.el.sortable("disable"); + _this.sortableTable.el.addClass('dragtable-disabled'); + _this.options.beforeReorganize(_this.originalTable, _this.sortableTable); + // do reorganisation asynchronous + // for chrome a little bit more than 1 ms because we want to force a rerender + _this.originalTable.endIndex = _this.sortableTable.movingRow.prevAll().length + 1; + setTimeout(_this._rearrangeTableBackroundProcessing(), 50); + }; + }, + /* + * Disrupts the table. The original table stays the same. + * But on a layer above the original table we are constructing a list (ul > li) + * each li with a separate table representig a single col of the original table. + */ + _generateSortable: function(e) { + if (e.cancelBubble) { + e.cancelBubble = true; + } else { + e.stopPropagation(); + } + var _this = this; + // table attributes + var attrs = this.originalTable.el[0].attributes; + var tableAttrsString = ''; + for (var i = 0; i < attrs.length; i++) { + if ( (attrs[i].value || attrs[i].nodeValue) && attrs[i].nodeName != 'id' && attrs[i].nodeName != 'width') { + tableAttrsString += attrs[i].nodeName + '="' + ( attrs[i].value || attrs[i].nodeValue ) + '" '; + } + } + // row attributes + var rowAttrsArr = []; + //compute height, special handling for ie needed :-( + var heightArr = []; + + // don't save tfoot attributes because it messes up indexing + _this.originalTable.el.children('thead, tbody').children('tr:visible').slice(0, _this.options.maxMovingRow).each(function() { + // row attributes + var attrs = this.attributes; + var attrsString = ''; + for (var j = 0; j < attrs.length; j++) { + if ( (attrs[j].value || attrs[j].nodeValue ) && attrs[j].nodeName != 'id') { + attrsString += ' ' + attrs[j].nodeName + '="' + ( attrs[j].value || attrs[j].nodeValue ) + '"'; + } + } + rowAttrsArr.push(attrsString); + heightArr.push($(this).height()); + }); + + // compute width, no special handling for ie needed :-) + var widthArr = []; + // compute total width, needed for not wrapping around after the screen ends (floating) + var totalWidth = 0; + /* Find children thead and tbody. + * Only to process the immediate tr-children. Bugfix for inner tables + */ + var thtb = _this.originalTable.el.children(); + var headerRows = thtb.filter('thead').children('tr:visible'); + var visibleRows = thtb.filter('tbody').children('tr:visible'); + + headerRows.eq(0).children('th, td').filter(':visible').each(function() { + var w = $(this).outerWidth(); + widthArr.push(w); + totalWidth += w; + }); + if(_this.options.exact) { + var difference = totalWidth - _this.originalTable.el.outerWidth(); + widthArr[0] -= difference; + } + // one extra px on right and left side + totalWidth += 2; + + var captionHeight = 0; + thtb.filter('caption').each(function(){ + captionHeight += $(this).outerHeight(); + }); + + var sortableHtml = '
      '; + var sortableColumn = []; + // assemble the needed html + // build list + var rowIndex, + columns = headerRows.eq(0).children('th, td').length; + /*jshint loopfunc:true */ + for (i = 0; i < columns; i++) { + var row = headerRows.children(':nth-child(' + (i + 1) + ')'); + if (row.is(':visible')) { + rowIndex = 0; + sortableColumn[i] = '
    • ' + + '' + + ( captionHeight ? '' : '' ) + + ''; + // thead + headerRows.each(function(j){ + sortableColumn[i] += '' + + row[j].outerHTML + ''; + }); + sortableColumn[i] += ''; + // tbody + row = visibleRows.children(':nth-child(' + (i + 1) + ')'); + if (_this.options.maxMovingRows > 1) { + row = row.add(visibleRows.children(':nth-child(' + (i + 1) + ')').slice(0, _this.options.maxMovingRows - 1)); + } + row.each(function(j) { + sortableColumn[i] += '' + + this.outerHTML + ''; + }); + sortableColumn[i] += ''; + + // add footer to end of max Rows + if (!_this.options.excludeFooter) { + sortableColumn[i] += '' + + thtb.filter('tfoot').children('tr:visible').children()[i].outerHTML + ''; + } + sortableColumn[i] += '
    • '; + } + } + sortableHtml += sortableColumn.join('') + '
    '; + this.sortableTable.el = this.originalTable.el.before(sortableHtml).prev(); + // set width if necessary + this.sortableTable.el.find('> li > table').each(function(i) { + $(this).css('width', widthArr[i] + 'px'); + }); + + // assign this.sortableTable.selectedHandle + this.sortableTable.selectedHandle = this.sortableTable.el.find('th .dragtable-handle-selected'); + + var items = !this.options.dragaccept ? 'li' : 'li:has(' + this.options.dragaccept + ')'; + this.sortableTable.el.sortable({ + items: items, + stop: this._rearrangeTable(), + // pass thru options for sortable widget + revert: this.options.revert, + tolerance: this.options.tolerance, + containment: this.options.containment, + cursor: this.options.cursor, + cursorAt: this.options.cursorAt, + distance: this.options.distance, + axis: this.options.axis + }); + + // assign start index + this.originalTable.startIndex = $(e.target).closest('th,td').prevAll().length + 1; + this.options.beforeMoving(this.originalTable, this.sortableTable); + // Start moving by delegating the original event to the new sortable table + this.sortableTable.movingRow = this.sortableTable.el.children('li:nth-child(' + this.originalTable.startIndex + ')'); + + // prevent the user from drag selecting "highlighting" surrounding page elements + disableTextSelection(); + // clone the initial event and trigger the sort with it + this.sortableTable.movingRow.trigger($.extend($.Event(e.type), { + which: 1, + clientX: e.clientX, + clientY: e.clientY, + pageX: e.pageX, + pageY: e.pageY, + screenX: e.screenX, + screenY: e.screenY + })); + + // Some inner divs to deliver the posibillity to style the placeholder more sophisticated + var placeholder = this.sortableTable.el.find('.ui-sortable-placeholder'); + if(placeholder.height() > 0) { + placeholder.css('height', this.sortableTable.el.find('.ui-sortable-helper').height()); + } + + placeholder.html('
    '); + }, + bindTo: {}, + _create: function() { + var _this = this; + _this.originalTable = { + el: _this.element, + selectedHandle: $(), + sortOrder: {}, + startIndex: 0, + endIndex: 0 + }; + ts.dragtable.create( _this ); + // filter only the cols that are accepted + _this.bindTo = '> thead > tr > ' + ( _this.options.dragaccept || 'th, td' ); + // bind draggable to handle if exists + if (_this.element.find(_this.bindTo).find(_this.options.dragHandle).length) { + _this.bindTo += ' ' + _this.options.dragHandle; + } + // restore state if necessary + if ($.isFunction(_this.options.restoreState)) { + _this.options.restoreState(_this.originalTable); + } else { + _this._restoreState(_this.options.restoreState); + } + _this.originalTable.el.on( 'mousedown.dragtable', _this.bindTo, function(evt) { + // listen only to left mouse click + if (evt.which!==1) return; + ts.dragtable.start( _this.originalTable.el ); + if (_this.options.beforeStart(_this.originalTable) === false) { + return; + } + clearTimeout(_this.downTimer); + _this.downTimer = setTimeout(function() { + _this.originalTable.selectedHandle = $(_this); + _this.originalTable.selectedHandle.addClass('dragtable-handle-selected'); + _this._generateSortable(evt); + }, _this.options.clickDelay); + }).on( 'mouseup.dragtable', _this.options.dragHandle,function() { + clearTimeout(_this.downTimer); + }); + }, + redraw: function(){ + this.destroy(); + this._create(); + }, + destroy: function() { + this.originalTable.el.off('mousedown.dragtable mouseup.dragtable', this.bindTo); + $.Widget.prototype.destroy.apply(this, arguments); // default destroy + // now do other stuff particular to this widget + } + }); + + /** closure-scoped "private" functions **/ + var body_onselectstart_save = $(document.body).attr('onselectstart'), + body_unselectable_save = $(document.body).attr('unselectable'); + + // css properties to disable user-select on the body tag by appending a '); + $(document.head).append($style); + $(document.body).attr('onselectstart', 'return false;').attr('unselectable', 'on'); + if (window.getSelection) { + window.getSelection().removeAllRanges(); + } else { + document.selection.empty(); // MSIE http://msdn.microsoft.com/en-us/library/ms535869%28v=VS.85%29.aspx + } + } + + // remove the '; + $(s).appendTo('body'); +}); + +ts.resizable = { + init : function( c, wo ) { + if ( c.$table.hasClass( 'hasResizable' ) ) { return; } + c.$table.addClass( 'hasResizable' ); + ts.resizableReset( c.table, true ); // set default widths + + // internal variables + wo.resizable_ = { + $wrap : c.$table.parent(), + mouseXPosition : 0, + $target : null, + $next : null, + overflow : c.$table.parent().css('overflow') === 'auto', + fullWidth : Math.abs(c.$table.parent().width() - c.$table.width()) < 20, + storedSizes : [] + }; + + var noResize, $header, column, storedSizes, + marginTop = parseInt( c.$table.css( 'margin-top' ), 10 ); + + wo.resizable_.storedSizes = storedSizes = ( ( ts.storage && wo.resizable !== false ) ? + ts.storage( c.table, ts.css.resizableStorage ) : + [] ) || []; + ts.resizable.setWidths( c, wo, storedSizes ); + + wo.$resizable_container = $( '
    ' ) + .css({ top : marginTop }) + .insertBefore( c.$table ); + // add container + for ( column = 0; column < c.columns; column++ ) { + $header = c.$headerIndexed[ column ]; + noResize = ts.getData( $header, ts.getColumnData( c.table, c.headers, column ), 'resizable' ) === 'false'; + if ( !noResize ) { + $( '
    ' ) + .appendTo( wo.$resizable_container ) + .attr({ + 'data-column' : column, + 'unselectable' : 'on' + }) + .data( 'header', $header ) + .bind( 'selectstart', false ); + } + } + c.$table.one('tablesorter-initialized', function() { + ts.resizable.setHandlePosition( c, wo ); + ts.resizable.bindings( this.config, this.config.widgetOptions ); + }); + }, + + setWidth : function( $el, width ) { + $el.css({ + 'width' : width, + 'min-width' : '', + 'max-width' : '' + }); + }, + + setWidths : function( c, wo, storedSizes ) { + var column, + $extra = $( c.namespace + '_extra_headers' ), + $col = c.$table.children( 'colgroup' ).children( 'col' ); + storedSizes = storedSizes || wo.resizable_.storedSizes || []; + // process only if table ID or url match + if ( storedSizes.length ) { + for ( column = 0; column < c.columns; column++ ) { + // set saved resizable widths + c.$headerIndexed[ column ].width( storedSizes[ column ] ); + if ( $extra.length ) { + // stickyHeaders needs to modify min & max width as well + ts.resizable.setWidth( $extra.eq( column ).add( $col.eq( column ) ), storedSizes[ column ] ); + } + } + if ( $( c.namespace + '_extra_table' ).length && !ts.hasWidget( c.table, 'scroller' ) ) { + ts.resizable.setWidth( $( c.namespace + '_extra_table' ), c.$table.outerWidth() ); + } + } + }, + + setHandlePosition : function( c, wo ) { + var startPosition, + hasScroller = ts.hasWidget( c.table, 'scroller' ), + tableHeight = c.$table.height(), + $handles = wo.$resizable_container.children(), + handleCenter = Math.floor( $handles.width() / 2 ); + + if ( hasScroller ) { + tableHeight = 0; + c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function(){ + var $this = $(this); + // center table has a max-height set + tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height(); + }); + } + // subtract out table left position from resizable handles. Fixes #864 + startPosition = c.$table.position().left; + $handles.each( function() { + var $this = $(this), + column = parseInt( $this.attr( 'data-column' ), 10 ), + columns = c.columns - 1, + $header = $this.data( 'header' ); + if ( !$header ) { return; } // see #859 + if ( !$header.is(':visible') ) { + $this.hide(); + } else if ( column < columns || column === columns && wo.resizable_addLastColumn ) { + $this.css({ + display: 'inline-block', + height : tableHeight, + left : $header.position().left - startPosition + $header.outerWidth() - handleCenter + }); + } + }); + }, + + // prevent text selection while dragging resize bar + toggleTextSelection : function( c, toggle ) { + var namespace = c.namespace + 'tsresize'; + c.widgetOptions.resizable_.disabled = toggle; + $( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle ); + if ( toggle ) { + $( 'body' ) + .attr( 'unselectable', 'on' ) + .bind( 'selectstart' + namespace, false ); + } else { + $( 'body' ) + .removeAttr( 'unselectable' ) + .unbind( 'selectstart' + namespace ); + } + }, + + bindings : function( c, wo ) { + var namespace = c.namespace + 'tsresize'; + wo.$resizable_container.children().bind( 'mousedown', function( event ) { + // save header cell and mouse position + var column, $this, + vars = wo.resizable_, + $extras = $( c.namespace + '_extra_headers' ), + $header = $( event.target ).data( 'header' ); + + column = parseInt( $header.attr( 'data-column' ), 10 ); + vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') ); + vars.target = column; + + // if table is not as wide as it's parent, then resize the table + vars.$next = event.shiftKey || wo.resizable_targetLast ? + $header.parent().children().not( '.resizable-false' ).filter( ':last' ) : + $header.nextAll( ':not(.resizable-false)' ).eq( 0 ); + + column = parseInt( vars.$next.attr( 'data-column' ), 10 ); + vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') ); + vars.next = column; + + vars.mouseXPosition = event.pageX; + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + ts.resizable.toggleTextSelection( c, true ); + }); + + $( document ) + .bind( 'mousemove' + namespace, function( event ) { + var vars = wo.resizable_; + // ignore mousemove if no mousedown + if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; } + if ( wo.resizable_throttle ) { + clearTimeout( vars.timer ); + vars.timer = setTimeout( function() { + ts.resizable.mouseMove( c, wo, event ); + }, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle ); + } else { + ts.resizable.mouseMove( c, wo, event ); + } + }) + .bind( 'mouseup' + namespace, function() { + if (!wo.resizable_.disabled) { return; } + ts.resizable.toggleTextSelection( c, false ); + ts.resizable.stopResize( c, wo ); + ts.resizable.setHandlePosition( c, wo ); + }); + + // resizeEnd event triggered by scroller widget + $( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }); + + // right click to reset columns to default widths + c.$table + .bind( 'columnUpdate' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }) + .find( 'thead:first' ) + .add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) ) + .bind( 'contextmenu' + namespace, function() { + // $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset + var allowClick = wo.resizable_.storedSizes.length === 0; + ts.resizableReset( c.table ); + ts.resizable.setHandlePosition( c, wo ); + wo.resizable_.storedSizes = []; + return allowClick; + }); + + }, + + mouseMove : function( c, wo, event ) { + if ( wo.resizable_.mouseXPosition === 0 || !wo.resizable_.$target ) { return; } + // resize columns + var vars = wo.resizable_, + $next = vars.$next, + leftEdge = event.pageX - vars.mouseXPosition; + if ( vars.fullWidth ) { + vars.storedSizes[ vars.target ] += leftEdge; + vars.storedSizes[ vars.next ] -= leftEdge; + ts.resizable.setWidths( c, wo ); + + } else if ( vars.overflow ) { + c.$table.add( $( c.namespace + '_extra_table' ) ).width(function(i, w){ + return w + leftEdge; + }); + if ( !$next.length ) { + // if expanding right-most column, scroll the wrapper + vars.$wrap[0].scrollLeft = c.$table.width(); + } + } else { + vars.storedSizes[ vars.target ] += leftEdge; + ts.resizable.setWidths( c, wo ); + } + vars.mouseXPosition = event.pageX; + // dynamically update sticky header widths + c.$table.trigger('stickyHeadersUpdate'); + }, + + stopResize : function( c, wo ) { + var $this, column, + vars = wo.resizable_; + vars.storedSizes = []; + if ( ts.storage ) { + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + if ( wo.resizable !== false ) { + // save all column widths + ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes ); + } + } + vars.mouseXPosition = 0; + vars.$target = vars.$next = null; + // will update stickyHeaders, just in case, see #912 + c.$table.trigger('stickyHeadersUpdate'); + } +}; + +// this widget saves the column widths if +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: "resizable", + priority: 40, + options: { + resizable : true, + resizable_addLastColumn : false, + resizable_widths : [], + resizable_throttle : false, // set to true (5ms) or any number 0-10 range + resizable_targetLast : false + }, + init: function(table, thisWidget, c, wo) { + ts.resizable.init( c, wo ); + }, + remove: function( table, c, wo, refreshing ) { + if (wo.$resizable_container) { + var namespace = c.namespace + 'tsresize'; + c.$table.add( $( c.namespace + '_extra_table' ) ) + .removeClass('hasResizable') + .children( 'thead' ).unbind( 'contextmenu' + namespace ); + + wo.$resizable_container.remove(); + ts.resizable.toggleTextSelection( c, false ); + ts.resizableReset( table, refreshing ); + $( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace ); + } + } +}); + +ts.resizableReset = function( table, refreshing ) { + $( table ).each(function(){ + var index, $t, + c = this.config, + wo = c && c.widgetOptions; + if ( table && c && c.$headerIndexed.length ) { + for ( index = 0; index < c.columns; index++ ) { + $t = c.$headerIndexed[ index ]; + if ( wo.resizable_widths && wo.resizable_widths[ index ] ) { + $t.css( 'width', wo.resizable_widths[ index ] ); + } else if ( !$t.hasClass( 'resizable-false' ) ) { + // don't clear the width of any column that is not resizable + $t.css( 'width', '' ); + } + } + // reset stickyHeader widths + c.$table.trigger( 'stickyHeadersUpdate' ); + if ( ts.storage && !refreshing ) { + ts.storage( this, ts.css.resizableStorage, {} ); + } + } + }); +}; + +})( jQuery, window ); + +/*! Widget: saveSort */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +// this widget saves the last sort only if the +// saveSort widget option is true AND the +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: 'saveSort', + priority: 20, + options: { + saveSort : true + }, + init: function(table, thisWidget, c, wo) { + // run widget format before all other widgets are applied to the table + thisWidget.format(table, c, wo, true); + }, + format: function(table, c, wo, init) { + var stored, time, + $table = c.$table, + saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true + sortList = { "sortList" : c.sortList }; + if (c.debug) { + time = new Date(); + } + if ($table.hasClass('hasSaveSort')) { + if (saveSort && table.hasInitialized && ts.storage) { + ts.storage( table, 'tablesorter-savesort', sortList ); + if (c.debug) { + ts.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time); + } + } + } else { + // set table sort on initial run of the widget + $table.addClass('hasSaveSort'); + sortList = ''; + // get data + if (ts.storage) { + stored = ts.storage( table, 'tablesorter-savesort' ); + sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : ''; + if (c.debug) { + ts.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time); + } + $table.bind('saveSortReset', function(event) { + event.stopPropagation(); + ts.storage( table, 'tablesorter-savesort', '' ); + }); + } + // init is true when widget init is run, this will run this widget before all other widgets have initialized + // this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice. + if (init && sortList && sortList.length > 0) { + c.sortList = sortList; + } else if (table.hasInitialized && sortList && sortList.length > 0) { + // update sort change + $table.trigger('sorton', [sortList]); + } + } + }, + remove: function(table, c) { + c.$table.removeClass('hasSaveSort'); + // clear storage + if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); } + } +}); + +})(jQuery); + +return $.tablesorter; +})); diff --git a/js/jquery.tablesorter.js b/js/jquery.tablesorter.js new file mode 100644 index 0000000..d0c23f9 --- /dev/null +++ b/js/jquery.tablesorter.js @@ -0,0 +1,2177 @@ +/*! TableSorter (FORK) v2.22.1 *//* +* Client-side table sorting with ease! +* @requires jQuery v1.2.6+ +* +* Copyright (c) 2007 Christian Bach +* fork maintained by Rob Garrison +* +* Examples and docs at: http://tablesorter.com +* Dual licensed under the MIT and GPL licenses: +* http://www.opensource.org/licenses/mit-license.php +* http://www.gnu.org/licenses/gpl.html +* +* @type jQuery +* @name tablesorter (FORK) +* @cat Plugins/Tablesorter +* @author Christian Bach - christian.bach@polyester.se +* @contributor Rob Garrison - https://github.com/Mottie/tablesorter +*/ +/*jshint browser:true, jquery:true, unused:false, expr: true */ +/*global console:false, alert:false, require:false, define:false, module:false */ +;(function($){ + 'use strict'; + $.extend({ + /*jshint supernew:true */ + tablesorter: new function() { + + var ts = this; + + ts.version = '2.22.1'; + + ts.parsers = []; + ts.widgets = []; + ts.defaults = { + + // *** appearance + theme : 'default', // adds tablesorter-{theme} to the table for styling + widthFixed : false, // adds colgroup to fix widths of columns + showProcessing : false, // show an indeterminate timer icon in the header when the table is sorted or filtered. + + headerTemplate : '{content}',// header layout template (HTML ok); {content} = innerHTML, {icon} = (class from cssIcon) + onRenderTemplate : null, // function(index, template){ return template; }, (template is a string) + onRenderHeader : null, // function(index){}, (nothing to return) + + // *** functionality + cancelSelection : true, // prevent text selection in the header + tabIndex : true, // add tabindex to header for keyboard accessibility + dateFormat : 'mmddyyyy', // other options: 'ddmmyyy' or 'yyyymmdd' + sortMultiSortKey : 'shiftKey', // key used to select additional columns + sortResetKey : 'ctrlKey', // key used to remove sorting on a column + usNumberFormat : true, // false for German '1.234.567,89' or French '1 234 567,89' + delayInit : false, // if false, the parsed table contents will not update until the first sort + 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. + resort : true, // default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed + + // *** sort options + headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc. + ignoreCase : true, // ignore case while sorting + sortForce : null, // column(s) first sorted; always applied + sortList : [], // Initial sort order; applied initially; updated when manually sorted + sortAppend : null, // column(s) sorted last; always applied + sortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained + + sortInitialOrder : 'asc', // sort direction on first click + sortLocaleCompare: false, // replace equivalent character (accented characters) + sortReset : false, // third click on the header will reset column to default - unsorted + sortRestart : false, // restart sort to 'sortInitialOrder' when clicking on previously unsorted columns + + emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero, emptyMax, emptyMin + stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero + textExtraction : 'basic', // text extraction method/function - function(node, table, cellIndex){} + textAttribute : 'data-text',// data-attribute that contains alternate cell text (used in default textExtraction function) + textSorter : null, // choose overall or specific column sorter function(a, b, direction, table, columnIndex) [alt: ts.sortText] + numberSorter : null, // choose overall numeric sorter function(a, b, direction, maxColumnValue) + + // *** widget options + widgets: [], // method to add widgets, e.g. widgets: ['zebra'] + widgetOptions : { + zebra : [ 'even', 'odd' ] // zebra widget alternating row class names + }, + initWidgets : true, // apply widgets on tablesorter initialization + widgetClass : 'widget-{name}', // table class name template to match to include a widget + + // *** callbacks + initialized : null, // function(table){}, + + // *** extra css class names + tableClass : '', + cssAsc : '', + cssDesc : '', + cssNone : '', + cssHeader : '', + cssHeaderRow : '', + cssProcessing : '', // processing icon applied to header during sort/filter + + cssChildRow : 'tablesorter-childRow', // class name indiciating that a row is to be attached to the its parent + cssIcon : 'tablesorter-icon', // if this class does not exist, the {icon} will not be added from the headerTemplate + cssIconNone : '', // class name added to the icon when there is no column sort + cssIconAsc : '', // class name added to the icon when the column has an ascending sort + cssIconDesc : '', // class name added to the icon when the column has a descending sort + cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!) + cssNoSort : 'tablesorter-noSort', // class name added to element inside header; clicking on it won't cause a sort + cssIgnoreRow : 'tablesorter-ignoreRow', // header row to ignore; cells within this row will not be added to c.$headers + + // *** events + pointerClick : 'click', + pointerDown : 'mousedown', + pointerUp : 'mouseup', + + // *** selectors + selectorHeaders : '> thead th, > thead td', + selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort + selectorRemove : '.remove-me', + + // *** advanced + debug : false, + + // *** Internal variables + headerList: [], + empties: {}, + strings: {}, + parsers: [] + + // removed: widgetZebra: { css: ['even', 'odd'] } + + }; + + // internal css classes - these will ALWAYS be added to + // the table and MUST only contain one class name - fixes #381 + ts.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' + }; + + // labels applied to sortable headers for accessibility (aria) support + ts.language = { + sortAsc : 'Ascending sort applied, ', + sortDesc : 'Descending sort applied, ', + sortNone : 'No sort applied, ', + nextAsc : 'activate to apply an ascending sort', + nextDesc : 'activate to apply a descending sort', + nextNone : 'activate to remove the sort' + }; + + // These methods can be applied on table.config instance + ts.instanceMethods = {}; + + /* debuging utils */ + function log() { + var a = arguments[0], + s = arguments.length > 1 ? Array.prototype.slice.call(arguments) : a; + if (typeof console !== 'undefined' && typeof console.log !== 'undefined') { + console[ /error/i.test(a) ? 'error' : /warn/i.test(a) ? 'warn' : 'log' ](s); + } else { + alert(s); + } + } + + function benchmark(s, d) { + log(s + ' (' + (new Date().getTime() - d.getTime()) + 'ms)'); + } + + ts.log = log; + ts.benchmark = benchmark; + + // $.isEmptyObject from jQuery v1.4 + function isEmptyObject(obj) { + /*jshint forin: false */ + for (var name in obj) { + return false; + } + return true; + } + + ts.getElementText = function(c, node, cellIndex) { + if (!node) { return ''; } + var te, + t = c.textExtraction || '', + // node could be a jquery object + // http://jsperf.com/jquery-vs-instanceof-jquery/2 + $node = node.jquery ? node : $(node); + if (typeof(t) === 'string') { + // check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow! + // http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/ + return $.trim( + ( t === 'basic' ? $node.attr(c.textAttribute) || node.textContent : node.textContent ) || + $node.text() + ); + } else { + if (typeof(t) === 'function') { + return $.trim( t($node[0], c.table, cellIndex) ); + } else if (typeof (te = ts.getColumnData( c.table, t, cellIndex )) === 'function') { + return $.trim( te($node[0], c.table, cellIndex) ); + } + } + // fallback + return $.trim( $node[0].textContent || $node.text() ); + }; + + function detectParserForColumn(c, rows, rowIndex, cellIndex) { + var cur, $node, + i = ts.parsers.length, + node = false, + nodeValue = '', + keepLooking = true; + while (nodeValue === '' && keepLooking) { + rowIndex++; + if (rows[rowIndex]) { + node = rows[rowIndex].cells[cellIndex]; + nodeValue = ts.getElementText(c, node, cellIndex); + $node = $(node); + if (c.debug) { + log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"'); + } + } else { + keepLooking = false; + } + } + while (--i >= 0) { + cur = ts.parsers[i]; + // ignore the default text parser because it will always be true + if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, c.table, node, $node)) { + return cur; + } + } + // nothing found, return the generic parser (text) + return ts.getParserById('text'); + } + + // centralized function to extract/parse cell contents + ts.getParsedText = function( c, cell, colIndex, txt ) { + if ( typeof txt === 'undefined' ) { + txt = ts.getElementText( c, cell, colIndex ); + } + // if no parser, make sure to return the txt + var val = '' + txt, + parser = c.parsers[ colIndex ], + extractor = c.extractors[ colIndex ]; + if ( parser ) { + // do extract before parsing, if there is one + if ( extractor && typeof extractor.format === 'function' ) { + txt = extractor.format( txt, c.table, cell, colIndex ); + } + // allow parsing if the string is empty, previously parsing would change it to zero, + // in case the parser needs to extract data from the table cell attributes + val = parser.id === 'no-parser' ? '' : + // make sure txt is a string (extractor may have converted it) + parser.format( '' + txt, c.table, cell, colIndex ); + if ( c.ignoreCase && typeof val === 'string' ) { + val = val.toLowerCase(); + } + } + return val; + } + + function buildParserCache( c, $tbodies ) { + var rows, list, l, i, h, ch, np, p, e, time, tb, len, + table = c.table, + j = 0, + parsersDebug = ''; + // update table bodies in case we start with an empty table + c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'); + tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies; + len = tb.length; + if ( len === 0) { + return c.debug ? log('Warning: *Empty table!* Not building a parser cache') : ''; + } else if (c.debug) { + time = new Date(); + log('Detecting parsers for each column'); + } + list = { + extractors: [], + parsers: [] + }; + while (j < len) { + rows = tb[j].rows; + if (rows.length) { + l = c.columns; // rows[j].cells.length; + for (i = 0; i < l; i++) { + h = c.$headerIndexed[i]; + // get column indexed table cell + ch = ts.getColumnData( table, c.headers, i ); + // get column parser/extractor + e = ts.getParserById( ts.getData(h, ch, 'extractor') ); + p = ts.getParserById( ts.getData(h, ch, 'sorter') ); + np = ts.getData(h, ch, 'parser') === 'false'; + // empty cells behaviour - keeping emptyToBottom for backwards compatibility + c.empties[i] = ( ts.getData(h, ch, 'empty') || c.emptyTo || (c.emptyToBottom ? 'bottom' : 'top' ) ).toLowerCase(); + // text strings behaviour in numerical sorts + c.strings[i] = ( ts.getData(h, ch, 'string') || c.stringTo || 'max' ).toLowerCase(); + if (np) { + p = ts.getParserById('no-parser'); + } + if (!e) { + // For now, maybe detect someday + e = false; + } + if (!p) { + p = detectParserForColumn(c, rows, -1, i); + } + if (c.debug) { + parsersDebug += 'column:' + i + '; extractor:' + e.id + '; parser:' + p.id + '; string:' + c.strings[i] + '; empty: ' + c.empties[i] + '\n'; + } + list.parsers[i] = p; + list.extractors[i] = e; + } + } + j += (list.parsers.length) ? len : 1; + } + if (c.debug) { + log(parsersDebug ? parsersDebug : 'No parsers detected'); + benchmark('Completed detecting parsers', time); + } + c.parsers = list.parsers; + c.extractors = list.extractors; + } + + /* utils */ + function buildCache(table, $tbodies) { + var cc, t, v, i, j, k, $tb, $row, cols, cacheTime, + totalRows, rowData, prevRowData, colMax, + c = table.config, + parsers = c.parsers; + // update tbody variable + c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'); + $tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies, + c.cache = {}; + c.totalRows = 0; + // if no parsers found, return - it's an empty table. + if (!parsers) { + return c.debug ? log('Warning: *Empty table!* Not building a cache') : ''; + } + if (c.debug) { + cacheTime = new Date(); + } + // processing icon + if (c.showProcessing) { + ts.isProcessing(table, true); + } + for (k = 0; k < $tb.length; k++) { + colMax = []; // column max value per tbody + cc = c.cache[k] = { + normalized: [] // array of normalized row data; last entry contains 'rowData' above + // colMax: # // added at the end + }; + + totalRows = ($tb[k] && $tb[k].rows.length) || 0; + for (i = 0; i < totalRows; ++i) { + rowData = { + // order: original row order # + // $row : jQuery Object[] + child: [], // child row text (filter widget) + raw: [] // original row text + }; + /** Add the table data to main data array */ + $row = $( $tb[ k ].rows[ i ] ); + cols = []; + // if this is a child row, add it to the last row's children and continue to the next row + // ignore child row class, if it is the first row + if ( $row.hasClass( c.cssChildRow ) && i !== 0 ) { + t = cc.normalized.length - 1; + prevRowData = cc.normalized[ t ][ c.columns ]; + prevRowData.$row = prevRowData.$row.add( $row ); + // add 'hasChild' class name to parent row + if ( !$row.prev().hasClass( c.cssChildRow ) ) { + $row.prev().addClass( ts.css.cssHasChild ); + } + // save child row content (un-parsed!) + v = $row.children( 'th, td' ); + t = prevRowData.child.length; + prevRowData.child[ t ] = []; + // child row content does not account for colspans/rowspans; so indexing may be off + for ( j = 0; j < c.columns; j++ ) { + prevRowData.child[ t ][ j ] = ts.getParsedText( c, v[ j ], j ); + } + // go to the next for loop + continue; + } + rowData.$row = $row; + rowData.order = i; // add original row position to rowCache + for ( j = 0; j < c.columns; ++j ) { + if (typeof parsers[ j ] === 'undefined') { + if ( c.debug ) { + log( 'No parser found for cell:', $row[ 0 ].cells[ j ], 'does it have a header?' ); + } + continue; + } + t = ts.getElementText( c, $row[ 0 ].cells[j], j ); + rowData.raw.push( t ); // save original row text + v = ts.getParsedText( c, $row[ 0 ].cells[ j ], j, t ); + cols.push( v ); + if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) { + // determine column max value (ignore sign) + colMax[ j ] = Math.max( Math.abs( v ) || 0, colMax[ j ] || 0 ); + } + } + // ensure rowData is always in the same location (after the last column) + cols[ c.columns ] = rowData; + cc.normalized.push( cols ); + } + cc.colMax = colMax; + // total up rows, not including child rows + c.totalRows += cc.normalized.length; + + } + if ( c.showProcessing ) { + ts.isProcessing( table ); // remove processing icon + } + if ( c.debug ) { + benchmark( 'Building cache for ' + totalRows + ' rows', cacheTime ); + } + } + + // init flag (true) used by pager plugin to prevent widget application + function appendToTable(table, init) { + var c = table.config, + wo = c.widgetOptions, + $tbodies = c.$tbodies, + rows = [], + cc = c.cache, + n, totalRows, $bk, $tb, + i, k, appendTime; + // empty table - fixes #206/#346 + if (isEmptyObject(cc)) { + // run pager appender in case the table was just emptied + return c.appender ? c.appender(table, rows) : + table.isUpdating ? c.$table.trigger('updateComplete', table) : ''; // Fixes #532 + } + if (c.debug) { + appendTime = new Date(); + } + for (k = 0; k < $tbodies.length; k++) { + $bk = $tbodies.eq(k); + if ($bk.length) { + // get tbody + $tb = ts.processTbody(table, $bk, true); + n = cc[k].normalized; + totalRows = n.length; + for (i = 0; i < totalRows; i++) { + rows.push(n[i][c.columns].$row); + // removeRows used by the pager plugin; don't render if using ajax - fixes #411 + if (!c.appender || (c.pager && (!c.pager.removeRows || !wo.pager_removeRows) && !c.pager.ajax)) { + $tb.append(n[i][c.columns].$row); + } + } + // restore tbody + ts.processTbody(table, $tb, false); + } + } + if (c.appender) { + c.appender(table, rows); + } + if (c.debug) { + benchmark('Rebuilt table', appendTime); + } + // apply table widgets; but not before ajax completes + if (!init && !c.appender) { ts.applyWidget(table); } + if (table.isUpdating) { + c.$table.trigger('updateComplete', table); + } + } + + function formatSortingOrder(v) { + // look for 'd' in 'desc' order; return true + return (/^d/i.test(v) || v === 1); + } + + function buildHeaders(table) { + var ch, $t, h, i, t, lock, time, indx, + c = table.config; + c.headerList = []; + c.headerContent = []; + if (c.debug) { + time = new Date(); + } + // children tr in tfoot - see issue #196 & #547 + c.columns = ts.computeColumnIndex( c.$table.children('thead, tfoot').children('tr') ); + // add icon if cssIcon option exists + i = c.cssIcon ? '' : ''; + // redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683 + c.$headers = $( $.map( $(table).find(c.selectorHeaders), function(elem, index) { + $t = $(elem); + // ignore cell (don't add it to c.$headers) if row has ignoreRow class + if ($t.parent().hasClass(c.cssIgnoreRow)) { return; } + // make sure to get header cell & not column indexed cell + ch = ts.getColumnData( table, c.headers, index, true ); + // save original header content + c.headerContent[index] = $t.html(); + // if headerTemplate is empty, don't reformat the header cell + if ( c.headerTemplate !== '' && !$t.find('.' + ts.css.headerIn).length ) { + // set up header template + t = c.headerTemplate.replace(/\{content\}/g, $t.html()).replace(/\{icon\}/g, $t.find('.' + ts.css.icon).length ? '' : i); + if (c.onRenderTemplate) { + h = c.onRenderTemplate.apply($t, [index, t]); + if (h && typeof h === 'string') { t = h; } // only change t if something is returned + } + $t.html('
    ' + t + '
    '); // faster than wrapInner + } + if (c.onRenderHeader) { c.onRenderHeader.apply($t, [index, c, c.$table]); } + // *** remove this.column value if no conflicts found + elem.column = parseInt( $t.attr('data-column'), 10); + elem.order = formatSortingOrder( ts.getData($t, ch, 'sortInitialOrder') || c.sortInitialOrder ) ? [1,0,2] : [0,1,2]; + elem.count = -1; // set to -1 because clicking on the header automatically adds one + elem.lockedOrder = false; + lock = ts.getData($t, ch, 'lockedOrder') || false; + if (typeof lock !== 'undefined' && lock !== false) { + elem.order = elem.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0]; + } + $t.addClass(ts.css.header + ' ' + c.cssHeader); + // add cell to headerList + c.headerList[index] = elem; + // add to parent in case there are multiple rows + $t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow).attr('role', 'row'); + // allow keyboard cursor to focus on element + if (c.tabIndex) { $t.attr('tabindex', 0); } + return elem; + })); + // cache headers per column + c.$headerIndexed = []; + for (indx = 0; indx < c.columns; indx++) { + $t = c.$headers.filter('[data-column="' + indx + '"]'); + // target sortable column cells, unless there are none, then use non-sortable cells + // .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6 + c.$headerIndexed[indx] = $t.not('.sorter-false').length ? $t.not('.sorter-false').filter(':last') : $t.filter(':last'); + } + $(table).find(c.selectorHeaders).attr({ + scope: 'col', + role : 'columnheader' + }); + // enable/disable sorting + updateHeader(table); + if (c.debug) { + benchmark('Built headers:', time); + log(c.$headers); + } + } + + function commonUpdate(table, resort, callback) { + var c = table.config; + // remove rows/elements before update + c.$table.find(c.selectorRemove).remove(); + // rebuild parsers + buildParserCache(c); + // rebuild the cache map + buildCache(table); + checkResort(c, resort, callback); + } + + function updateHeader(table) { + var index, s, $th, col, + c = table.config, + len = c.$headers.length; + for ( index = 0; index < len; index++ ) { + $th = c.$headers.eq( index ); + col = ts.getColumnData( table, c.headers, index, true ); + // add 'sorter-false' class if 'parser-false' is set + s = ts.getData( $th, col, 'sorter' ) === 'false' || ts.getData( $th, col, 'parser' ) === 'false'; + $th[0].sortDisabled = s; + $th[ s ? 'addClass' : 'removeClass' ]('sorter-false').attr('aria-disabled', '' + s); + // aria-controls - requires table ID + if (table.id) { + if (s) { + $th.removeAttr('aria-controls'); + } else { + $th.attr('aria-controls', table.id); + } + } + } + } + + function setHeadersCss(table) { + var f, h, i, j, $headers, $h, nextSort, txt, + c = table.config, + list = c.sortList, + len = list.length, + none = ts.css.sortNone + ' ' + c.cssNone, + css = [ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc], + cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ], + aria = ['ascending', 'descending'], + // find the footer + $t = $(table).find('tfoot tr').children() + .add( $( c.namespace + '_extra_headers' ) ) + .removeClass( css.join( ' ' ) ); + // remove all header information + c.$headers + .removeClass(css.join(' ')) + .addClass(none).attr('aria-sort', 'none') + .find('.' + ts.css.icon) + .removeClass(cssIcon.join(' ')) + .addClass(cssIcon[2]); + for (i = 0; i < len; i++) { + // direction = 2 means reset! + if (list[i][1] !== 2) { + // multicolumn sorting updating - choose the :last in case there are nested columns + f = c.$headers.not('.sorter-false').filter('[data-column="' + list[i][0] + '"]' + (len === 1 ? ':last' : '') ); + if (f.length) { + for (j = 0; j < f.length; j++) { + if (!f[j].sortDisabled) { + f.eq(j) + .removeClass(none) + .addClass(css[list[i][1]]) + .attr('aria-sort', aria[list[i][1]]) + .find('.' + ts.css.icon) + .removeClass(cssIcon[2]) + .addClass(cssIcon[list[i][1]]); + } + } + // add sorted class to footer & extra headers, if they exist + if ($t.length) { + $t.filter('[data-column="' + list[i][0] + '"]').removeClass(none).addClass(css[list[i][1]]); + } + } + } + } + // add verbose aria labels + len = c.$headers.length; + $headers = c.$headers.not('.sorter-false'); + for ( i = 0; i < len; i++ ) { + $h = $headers.eq( i ); + if ( $h.length ) { + h = $headers[ i ]; + nextSort = h.order[ ( h.count + 1 ) % ( c.sortReset ? 3 : 2 ) ], + txt = $.trim( $h.text() ) + ': ' + + ts.language[ $h.hasClass( ts.css.sortAsc ) ? 'sortAsc' : $h.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone' ] + + ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ]; + $h.attr( 'aria-label', txt ); + } + } + } + + function updateHeaderSortCount( table, list ) { + var col, dir, group, header, indx, primary, temp, val, + c = table.config, + sortList = list || c.sortList, + len = sortList.length; + c.sortList = []; + for (indx = 0; indx < len; indx++) { + val = sortList[indx]; + // ensure all sortList values are numeric - fixes #127 + col = parseInt(val[0], 10); + // prevents error if sorton array is wrong + if ( col < c.columns && c.$headerIndexed[col] ) { + // make sure header exists + header = c.$headerIndexed[col][0]; + // o.count = o.count + 1; + dir = ('' + val[1]).match(/^(1|d|s|o|n)/); + dir = dir ? dir[0] : ''; + // 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext + switch(dir) { + case '1': case 'd': // descending + dir = 1; + break; + case 's': // same direction (as primary column) + // if primary sort is set to 's', make it ascending + dir = primary || 0; + break; + case 'o': + temp = header.order[(primary || 0) % (c.sortReset ? 3 : 2)]; + // opposite of primary column; but resets if primary resets + dir = temp === 0 ? 1 : temp === 1 ? 0 : 2; + break; + case 'n': + header.count = header.count + 1; + dir = header.order[(header.count) % (c.sortReset ? 3 : 2)]; + break; + default: // ascending + dir = 0; + break; + } + primary = indx === 0 ? dir : primary; + group = [ col, parseInt(dir, 10) || 0 ]; + c.sortList.push(group); + dir = $.inArray(group[1], header.order); // fixes issue #167 + header.count = dir >= 0 ? dir : group[1] % (c.sortReset ? 3 : 2); + } + } + } + + function getCachedSortType(parsers, i) { + return (parsers && parsers[i]) ? parsers[i].type || '' : ''; + } + + function initSort(table, cell, event){ + if (table.isUpdating) { + // let any updates complete before initializing a sort + return setTimeout(function(){ initSort(table, cell, event); }, 50); + } + var arry, indx, i, col, order, s, $header, + c = table.config, + key = !event[c.sortMultiSortKey], + $table = c.$table, + len = c.$headers.length; + // Only call sortStart if sorting is enabled + $table.trigger('sortStart', table); + // get current column sort order + cell.count = event[c.sortResetKey] ? 2 : (cell.count + 1) % (c.sortReset ? 3 : 2); + // reset all sorts on non-current column - issue #30 + if (c.sortRestart) { + indx = cell; + for ( i = 0; i < len; i++ ) { + $header = c.$headers.eq( i ); + // only reset counts on columns that weren't just clicked on and if not included in a multisort + if ( $header[0] !== indx && ( key || !$header.is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc) ) ) { + $header[0].count = -1; + } + } + } + // get current column index + indx = parseInt( $(cell).attr('data-column'), 10 ); + // user only wants to sort on one column + if (key) { + // flush the sort list + c.sortList = []; + if (c.sortForce !== null) { + arry = c.sortForce; + for (col = 0; col < arry.length; col++) { + if (arry[col][0] !== indx) { + c.sortList.push(arry[col]); + } + } + } + // add column to sort list + order = cell.order[cell.count]; + if (order < 2) { + c.sortList.push([indx, order]); + // add other columns if header spans across multiple + if (cell.colSpan > 1) { + for (col = 1; col < cell.colSpan; col++) { + c.sortList.push([indx + col, order]); + } + } + } + // multi column sorting + } else { + // get rid of the sortAppend before adding more - fixes issue #115 & #523 + if (c.sortAppend && c.sortList.length > 1) { + for (col = 0; col < c.sortAppend.length; col++) { + s = ts.isValueInArray(c.sortAppend[col][0], c.sortList); + if (s >= 0) { + c.sortList.splice(s,1); + } + } + } + // the user has clicked on an already sorted column + if (ts.isValueInArray(indx, c.sortList) >= 0) { + // reverse the sorting direction + for (col = 0; col < c.sortList.length; col++) { + s = c.sortList[col]; + order = c.$headerIndexed[ s[0] ][0]; + if (s[0] === indx) { + // order.count seems to be incorrect when compared to cell.count + s[1] = order.order[cell.count]; + if (s[1] === 2) { + c.sortList.splice(col,1); + order.count = -1; + } + } + } + } else { + // add column to sort list array + order = cell.order[cell.count]; + if (order < 2) { + c.sortList.push([indx, order]); + // add other columns if header spans across multiple + if (cell.colSpan > 1) { + for (col = 1; col < cell.colSpan; col++) { + c.sortList.push([indx + col, order]); + } + } + } + } + } + if (c.sortAppend !== null) { + arry = c.sortAppend; + for (col = 0; col < arry.length; col++) { + if (arry[col][0] !== indx) { + c.sortList.push(arry[col]); + } + } + } + // sortBegin event triggered immediately before the sort + $table.trigger('sortBegin', table); + // setTimeout needed so the processing icon shows up + setTimeout(function(){ + // set css for headers + setHeadersCss(table); + multisort(table); + appendToTable(table); + $table.trigger('sortEnd', table); + }, 1); + } + + // sort multiple columns + function multisort(table) { /*jshint loopfunc:true */ + var i, k, num, col, sortTime, colMax, + rows, order, sort, x, y, + dir = 0, + c = table.config, + cts = c.textSorter || '', + sortList = c.sortList, + l = sortList.length, + bl = c.$tbodies.length; + if (c.serverSideSorting || isEmptyObject(c.cache)) { // empty table - fixes #206/#346 + return; + } + if (c.debug) { sortTime = new Date(); } + for (k = 0; k < bl; k++) { + colMax = c.cache[k].colMax; + rows = c.cache[k].normalized; + + rows.sort(function(a, b) { + // rows is undefined here in IE, so don't use it! + for (i = 0; i < l; i++) { + col = sortList[i][0]; + order = sortList[i][1]; + // sort direction, true = asc, false = desc + dir = order === 0; + + if (c.sortStable && a[col] === b[col] && l === 1) { + return a[c.columns].order - b[c.columns].order; + } + + // fallback to natural sort since it is more robust + num = /n/i.test(getCachedSortType(c.parsers, col)); + if (num && c.strings[col]) { + // sort strings in numerical columns + if (typeof (c.string[c.strings[col]]) === 'boolean') { + num = (dir ? 1 : -1) * (c.string[c.strings[col]] ? -1 : 1); + } else { + num = (c.strings[col]) ? c.string[c.strings[col]] || 0 : 0; + } + // fall back to built-in numeric sort + // var sort = $.tablesorter['sort' + s]( a[c], b[c], dir, colMax[c], table); + sort = c.numberSorter ? c.numberSorter(a[col], b[col], dir, colMax[col], table) : + ts[ 'sortNumeric' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], num, colMax[col], col, table); + } else { + // set a & b depending on sort direction + x = dir ? a : b; + y = dir ? b : a; + // text sort function + if (typeof(cts) === 'function') { + // custom OVERALL text sorter + sort = cts(x[col], y[col], dir, col, table); + } else if (typeof(cts) === 'object' && cts.hasOwnProperty(col)) { + // custom text sorter for a SPECIFIC COLUMN + sort = cts[col](x[col], y[col], dir, col, table); + } else { + // fall back to natural sort + sort = ts[ 'sortNatural' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], col, table, c); + } + } + if (sort) { return sort; } + } + return a[c.columns].order - b[c.columns].order; + }); + } + if (c.debug) { benchmark('Sorting on ' + sortList.toString() + ' and dir ' + order + ' time', sortTime); } + } + + function resortComplete(c, callback){ + if (c.table.isUpdating) { + c.$table.trigger('updateComplete', c.table); + } + if ($.isFunction(callback)) { + callback(c.table); + } + } + + function checkResort(c, resort, callback) { + var sl = $.isArray(resort) ? resort : c.sortList, + // if no resort parameter is passed, fallback to config.resort (true by default) + resrt = typeof resort === 'undefined' ? c.resort : resort; + // don't try to resort if the table is still processing + // this will catch spamming of the updateCell method + if (resrt !== false && !c.serverSideSorting && !c.table.isProcessing) { + if (sl.length) { + c.$table.trigger('sorton', [sl, function(){ + resortComplete(c, callback); + }, true]); + } else { + c.$table.trigger('sortReset', [function(){ + resortComplete(c, callback); + ts.applyWidget(c.table, false); + }]); + } + } else { + resortComplete(c, callback); + ts.applyWidget(c.table, false); + } + } + + function bindMethods(table){ + var c = table.config, + $table = c.$table, + events = ('sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache ' + + 'updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ').split(' ') + .join(c.namespace + ' '); + // apply easy methods that trigger bound events + $table + .unbind( events.replace(/\s+/g, ' ') ) + .bind('sortReset' + c.namespace, function(e, callback){ + e.stopPropagation(); + c.sortList = []; + setHeadersCss(table); + multisort(table); + appendToTable(table); + if ($.isFunction(callback)) { + callback(table); + } + }) + .bind('updateAll' + c.namespace, function(e, resort, callback){ + e.stopPropagation(); + table.isUpdating = true; + ts.refreshWidgets(table, true, true); + buildHeaders(table); + ts.bindEvents(table, c.$headers, true); + bindMethods(table); + commonUpdate(table, resort, callback); + }) + .bind('update' + c.namespace + ' updateRows' + c.namespace, function(e, resort, callback) { + e.stopPropagation(); + table.isUpdating = true; + // update sorting (if enabled/disabled) + updateHeader(table); + commonUpdate(table, resort, callback); + }) + .bind('updateCell' + c.namespace, function(e, cell, resort, callback) { + e.stopPropagation(); + table.isUpdating = true; + $table.find(c.selectorRemove).remove(); + // get position from the dom + var t, row, icell, cache, + $tb = c.$tbodies, + $cell = $(cell), + // update cache - format: function(s, table, cell, cellIndex) + // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr'); + tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ), + tbcache = c.cache[ tbdy ], + $row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first'); + cell = $cell[0]; // in case cell is a jQuery object + // tbody may not exist if update is initialized while tbody is removed for processing + if ($tb.length && tbdy >= 0) { + row = $tb.eq( tbdy ).find( 'tr' ).index( $row ); + cache = tbcache.normalized[ row ]; + icell = $cell.index(); + t = ts.getParsedText( c, cell, icell ); + cache[ icell ] = t; + cache[ c.columns ].$row = $row; + if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) { + // update column max value (ignore sign) + tbcache.colMax[icell] = Math.max(Math.abs(t) || 0, tbcache.colMax[icell] || 0); + } + t = resort !== 'undefined' ? resort : c.resort; + if (t !== false) { + // widgets will be reapplied + checkResort(c, t, callback); + } else { + // don't reapply widgets is resort is false, just in case it causes + // problems with element focus + if ($.isFunction(callback)) { + callback(table); + } + c.$table.trigger('updateComplete', c.table); + } + } + }) + .bind('addRows' + c.namespace, function(e, $row, resort, callback) { + e.stopPropagation(); + table.isUpdating = true; + if (isEmptyObject(c.cache)) { + // empty table, do an update instead - fixes #450 + updateHeader(table); + commonUpdate(table, resort, callback); + } else { + $row = $($row).attr('role', 'row'); // make sure we're using a jQuery object + var i, j, l, rowData, cells, + rows = $row.filter('tr').length, + tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') ); + // fixes adding rows to an empty table - see issue #179 + if (!(c.parsers && c.parsers.length)) { + buildParserCache(c); + } + // add each row + for (i = 0; i < rows; i++) { + l = $row[i].cells.length; + cells = []; + rowData = { + child: [], + $row : $row.eq(i), + order: c.cache[tbdy].normalized.length + }; + // add each cell + for (j = 0; j < l; j++) { + cells[j] = ts.getParsedText( c, $row[i].cells[j], j ); + if ((c.parsers[j].type || '').toLowerCase() === 'numeric') { + // update column max value (ignore sign) + c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0); + } + } + // add the row data to the end + cells.push(rowData); + // update cache + c.cache[tbdy].normalized.push(cells); + } + // resort using current settings + checkResort(c, resort, callback); + } + }) + .bind('updateComplete' + c.namespace, function(){ + table.isUpdating = false; + }) + .bind('sorton' + c.namespace, function(e, list, callback, init) { + var c = table.config; + e.stopPropagation(); + $table.trigger('sortStart', this); + // update header count index + updateHeaderSortCount(table, list); + // set css for headers + setHeadersCss(table); + // fixes #346 + if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } + $table.trigger('sortBegin', this); + // sort the table and append it to the dom + multisort(table); + appendToTable(table, init); + $table.trigger('sortEnd', this); + ts.applyWidget(table); + if ($.isFunction(callback)) { + callback(table); + } + }) + .bind('appendCache' + c.namespace, function(e, callback, init) { + e.stopPropagation(); + appendToTable(table, init); + if ($.isFunction(callback)) { + callback(table); + } + }) + // $tbodies variable is used by the tbody sorting widget + .bind('updateCache' + c.namespace, function(e, callback, $tbodies){ + // rebuild parsers + if (!(c.parsers && c.parsers.length)) { + buildParserCache(c, $tbodies); + } + // rebuild the cache map + buildCache(table, $tbodies); + if ($.isFunction(callback)) { + callback(table); + } + }) + .bind('applyWidgetId' + c.namespace, function(e, id) { + e.stopPropagation(); + ts.getWidgetById(id).format(table, c, c.widgetOptions); + }) + .bind('applyWidgets' + c.namespace, function(e, init) { + e.stopPropagation(); + // apply widgets + ts.applyWidget(table, init); + }) + .bind('refreshWidgets' + c.namespace, function(e, all, dontapply){ + e.stopPropagation(); + ts.refreshWidgets(table, all, dontapply); + }) + .bind('destroy' + c.namespace, function(e, c, cb){ + e.stopPropagation(); + ts.destroy(table, c, cb); + }) + .bind('resetToLoadState' + c.namespace, function(){ + // remove all widgets + ts.removeWidget(table, true, false); + // restore original settings; this clears out current settings, but does not clear + // values saved to storage. + c = $.extend(true, ts.defaults, c.originalSettings); + table.hasInitialized = false; + // setup the entire table again + ts.setup( table, c ); + }); + } + + /* public methods */ + ts.construct = function(settings) { + return this.each(function() { + var table = this, + // merge & extend config options + c = $.extend(true, {}, ts.defaults, settings, ts.instanceMethods); + // save initial settings + c.originalSettings = settings; + // create a table from data (build table widget) + if (!table.hasInitialized && ts.buildTable && this.nodeName !== 'TABLE') { + // return the table (in case the original target is the table's container) + ts.buildTable(table, c); + } else { + ts.setup(table, c); + } + }); + }; + + ts.setup = function(table, c) { + // if no thead or tbody, or tablesorter is already present, quit + if (!table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true) { + return c.debug ? log('ERROR: stopping initialization! No table, thead, tbody or tablesorter has already been initialized') : ''; + } + + var k = '', + $table = $(table), + m = $.metadata; + // initialization flag + table.hasInitialized = false; + // table is being processed flag + table.isProcessing = true; + // make sure to store the config object + table.config = c; + // save the settings where they read + $.data(table, 'tablesorter', c); + if (c.debug) { $.data( table, 'startoveralltimer', new Date()); } + + // removing this in version 3 (only supports jQuery 1.7+) + c.supportsDataObject = (function(version) { + version[0] = parseInt(version[0], 10); + return (version[0] > 1) || (version[0] === 1 && parseInt(version[1], 10) >= 4); + })($.fn.jquery.split('.')); + // digit sort text location; keeping max+/- for backwards compatibility + c.string = { 'max': 1, 'min': -1, 'emptymin': 1, 'emptymax': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false }; + // ensure case insensitivity + c.emptyTo = c.emptyTo.toLowerCase(); + c.stringTo = c.stringTo.toLowerCase(); + // add table theme class only if there isn't already one there + if (!/tablesorter\-/.test($table.attr('class'))) { + k = (c.theme !== '' ? ' tablesorter-' + c.theme : ''); + } + c.table = table; + c.$table = $table + .addClass(ts.css.table + ' ' + c.tableClass + k) + .attr('role', 'grid'); + c.$headers = $table.find(c.selectorHeaders); + + // give the table a unique id, which will be used in namespace binding + if (!c.namespace) { + c.namespace = '.tablesorter' + Math.random().toString(16).slice(2); + } else { + // make sure namespace starts with a period & doesn't have weird characters + c.namespace = '.' + c.namespace.replace(/\W/g,''); + } + + c.$table.children().children('tr').attr('role', 'row'); + c.$tbodies = $table.children('tbody:not(.' + c.cssInfoBlock + ')').attr({ + 'aria-live' : 'polite', + 'aria-relevant' : 'all' + }); + if (c.$table.children('caption').length) { + k = c.$table.children('caption')[0]; + if (!k.id) { k.id = c.namespace.slice(1) + 'caption'; } + c.$table.attr('aria-labelledby', k.id); + } + c.widgetInit = {}; // keep a list of initialized widgets + // change textExtraction via data-attribute + c.textExtraction = c.$table.attr('data-text-extraction') || c.textExtraction || 'basic'; + // build headers + buildHeaders(table); + // fixate columns if the users supplies the fixedWidth option + // do this after theme has been applied + ts.fixColumnWidth(table); + // add widget options before parsing (e.g. grouping widget has parser settings) + ts.applyWidgetOptions(table, c); + // try to auto detect column type, and store in tables config + buildParserCache(c); + // start total row count at zero + c.totalRows = 0; + // build the cache for the tbody cells + // delayInit will delay building the cache until the user starts a sort + if (!c.delayInit) { buildCache(table); } + // bind all header events and methods + ts.bindEvents(table, c.$headers, true); + bindMethods(table); + // get sort list from jQuery data or metadata + // in jQuery < 1.4, an error occurs when calling $table.data() + if (c.supportsDataObject && typeof $table.data().sortlist !== 'undefined') { + c.sortList = $table.data().sortlist; + } else if (m && ($table.metadata() && $table.metadata().sortlist)) { + c.sortList = $table.metadata().sortlist; + } + // apply widget init code + ts.applyWidget(table, true); + // if user has supplied a sort list to constructor + if (c.sortList.length > 0) { + $table.trigger('sorton', [c.sortList, {}, !c.initWidgets, true]); + } else { + setHeadersCss(table); + if (c.initWidgets) { + // apply widget format + ts.applyWidget(table, false); + } + } + + // show processesing icon + if (c.showProcessing) { + $table + .unbind('sortBegin' + c.namespace + ' sortEnd' + c.namespace) + .bind('sortBegin' + c.namespace + ' sortEnd' + c.namespace, function(e) { + clearTimeout(c.processTimer); + ts.isProcessing(table); + if (e.type === 'sortBegin') { + c.processTimer = setTimeout(function(){ + ts.isProcessing(table, true); + }, 500); + } + }); + } + + // initialized + table.hasInitialized = true; + table.isProcessing = false; + if (c.debug) { + ts.benchmark('Overall initialization time', $.data( table, 'startoveralltimer')); + } + $table.trigger('tablesorter-initialized', table); + if (typeof c.initialized === 'function') { c.initialized(table); } + }; + + // automatically add a colgroup with col elements set to a percentage width + ts.fixColumnWidth = function(table) { + table = $(table)[0]; + var overallWidth, percent, $tbodies, len, index, + c = table.config, + colgroup = c.$table.children('colgroup'); + // remove plugin-added colgroup, in case we need to refresh the widths + if (colgroup.length && colgroup.hasClass(ts.css.colgroup)) { + colgroup.remove(); + } + if (c.widthFixed && c.$table.children('colgroup').length === 0) { + colgroup = $(''); + overallWidth = c.$table.width(); + // only add col for visible columns - fixes #371 + $tbodies = c.$tbodies.find('tr:first').children(':visible'); //.each(function() + len = $tbodies.length; + for ( index = 0; index < len; index++ ) { + percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%'; + colgroup.append( $('').css('width', percent) ); + } + c.$table.prepend(colgroup); + } + }; + + ts.getColumnData = function(table, obj, indx, getCell, $headers){ + if (typeof obj === 'undefined' || obj === null) { return; } + table = $(table)[0]; + var $h, k, + c = table.config, + $cells = ( $headers || c.$headers ), + // c.$headerIndexed is not defined initially + $cell = c.$headerIndexed && c.$headerIndexed[indx] || $cells.filter('[data-column="' + indx + '"]:last'); + if (obj[indx]) { + return getCell ? obj[indx] : obj[$cells.index( $cell )]; + } + for (k in obj) { + if (typeof k === 'string') { + $h = $cell + // header cell with class/id + .filter(k) + // find elements within the header cell with cell/id + .add( $cell.find(k) ); + if ($h.length) { + return obj[k]; + } + } + } + return; + }; + + // computeTableHeaderCellIndexes from: + // http://www.javascripttoolbox.com/lib/table/examples.php + // http://www.javascripttoolbox.com/temp/table_cellindex.html + ts.computeColumnIndex = function(trs) { + var i, j, k, l, $cell, cell, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol, + matrix = [], + matrixrow = [], + lookup = {}; + for (i = 0; i < trs.length; i++) { + cells = trs[i].cells; + for (j = 0; j < cells.length; j++) { + cell = cells[j]; + $cell = $(cell); + rowIndex = cell.parentNode.rowIndex; + cellId = rowIndex + '-' + $cell.index(); + rowSpan = cell.rowSpan || 1; + colSpan = cell.colSpan || 1; + if (typeof(matrix[rowIndex]) === 'undefined') { + matrix[rowIndex] = []; + } + // Find first available column in the first row + for (k = 0; k < matrix[rowIndex].length + 1; k++) { + if (typeof(matrix[rowIndex][k]) === 'undefined') { + firstAvailCol = k; + break; + } + } + lookup[cellId] = firstAvailCol; + // add data-column + $cell.attr({ 'data-column' : firstAvailCol }); // 'data-row' : rowIndex + for (k = rowIndex; k < rowIndex + rowSpan; k++) { + if (typeof(matrix[k]) === 'undefined') { + matrix[k] = []; + } + matrixrow = matrix[k]; + for (l = firstAvailCol; l < firstAvailCol + colSpan; l++) { + matrixrow[l] = 'x'; + } + } + } + } + return matrixrow.length; + }; + + // *** Process table *** + // add processing indicator + ts.isProcessing = function(table, toggle, $ths) { + table = $(table); + var c = table[0].config, + // default to all headers + $h = $ths || table.find('.' + ts.css.header); + if (toggle) { + // don't use sortList if custom $ths used + if (typeof $ths !== 'undefined' && c.sortList.length > 0) { + // get headers from the sortList + $h = $h.filter(function(){ + // get data-column from attr to keep compatibility with jQuery 1.2.6 + return this.sortDisabled ? false : ts.isValueInArray( parseFloat($(this).attr('data-column')), c.sortList) >= 0; + }); + } + table.add($h).addClass(ts.css.processing + ' ' + c.cssProcessing); + } else { + table.add($h).removeClass(ts.css.processing + ' ' + c.cssProcessing); + } + }; + + // detach tbody but save the position + // don't use tbody because there are portions that look for a tbody index (updateCell) + ts.processTbody = function(table, $tb, getIt){ + table = $(table)[0]; + var holdr; + if (getIt) { + table.isProcessing = true; + $tb.before(''); + holdr = ($.fn.detach) ? $tb.detach() : $tb.remove(); + return holdr; + } + holdr = $(table).find('span.tablesorter-savemyplace'); + $tb.insertAfter( holdr ); + holdr.remove(); + table.isProcessing = false; + }; + + ts.clearTableBody = function(table) { + $(table)[0].config.$tbodies.children().detach(); + }; + + ts.bindEvents = function(table, $headers, core) { + table = $(table)[0]; + var t, downTarget = null, + c = table.config; + if (core !== true) { + $headers.addClass( c.namespace.slice(1) + '_extra_headers' ); + t = $.fn.closest ? $headers.closest('table')[0] : $headers.parents('table')[0]; + if (t && t.nodeName === 'TABLE' && t !== table) { + $(t).addClass( c.namespace.slice(1) + '_extra_table' ); + } + } + t = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' ) + .replace(/\s+/g, ' ') + .split(' ') + .join(c.namespace + ' '); + // apply event handling to headers and/or additional headers (stickyheaders, scroller, etc) + $headers + // http://stackoverflow.com/questions/5312849/jquery-find-self; + .find(c.selectorSort).add( $headers.filter(c.selectorSort) ) + .unbind(t) + .bind(t, function(e, external) { + var cell, temp, + $target = $(e.target), + // wrap event type in spaces, so the match doesn't trigger on inner words + type = ' ' + e.type + ' '; + // only recognize left clicks + if ( ( ( e.which || e.button ) !== 1 && !type.match( ' ' + c.pointerClick + ' | sort | keyup ' ) ) || + // allow pressing enter + ( type === ' keyup ' && e.which !== 13 ) || + // allow triggering a click event (e.which is undefined) & ignore physical clicks + ( type.match(' ' + c.pointerClick + ' ') && typeof e.which !== 'undefined' ) ) { + return; + } + // ignore mouseup if mousedown wasn't on the same target + if ( type.match(' ' + c.pointerUp + ' ') && downTarget !== e.target && external !== true ) { return; } + // set target on mousedown + if ( type.match(' ' + c.pointerDown + ' ') ) { + downTarget = e.target; + // preventDefault needed or jQuery v1.3.2 and older throws an + // "Uncaught TypeError: handler.apply is not a function" error + temp = $target.jquery.split( '.' ); + if ( temp[0] === '1' && temp[1] < 4 ) { e.preventDefault(); } + return; + } + downTarget = null; + // prevent sort being triggered on form elements + if ( /(input|select|button|textarea)/i.test(e.target.nodeName) || + // nosort class name, or elements within a nosort container + $target.hasClass(c.cssNoSort) || $target.parents('.' + c.cssNoSort).length > 0 || + // elements within a button + $target.parents('button').length > 0 ) { + return !c.cancelSelection; + } + if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } + // jQuery v1.2.6 doesn't have closest() + cell = $.fn.closest ? $(this).closest('th, td')[0] : /TH|TD/.test(this.nodeName) ? this : $(this).parents('th, td')[0]; + // reference original table headers and find the same cell + cell = c.$headers[ $headers.index( cell ) ]; + if (!cell.sortDisabled) { + initSort(table, cell, e); + } + }); + if (c.cancelSelection) { + // cancel selection + $headers + .attr('unselectable', 'on') + .bind('selectstart', false) + .css({ + 'user-select': 'none', + 'MozUserSelect': 'none' // not needed for jQuery 1.8+ + }); + } + }; + + // restore headers + ts.restoreHeaders = function(table){ + var index, $cell, + c = $(table)[0].config, + $headers = c.$table.find( c.selectorHeaders ), + len = $headers.length; + // don't use c.$headers here in case header cells were swapped + for ( index = 0; index < len; index++ ) { + // c.$table.find(c.selectorHeaders).each(function(i){ + $cell = $headers.eq( index ); + // only restore header cells if it is wrapped + // because this is also used by the updateAll method + if ( $cell.find( '.' + ts.css.headerIn ).length ) { + $cell.html( c.headerContent[ index ] ); + } + } + }; + + ts.destroy = function(table, removeClasses, callback){ + table = $(table)[0]; + if (!table.hasInitialized) { return; } + // remove all widgets + ts.removeWidget(table, true, false); + var events, + $t = $(table), + c = table.config, + $h = $t.find('thead:first'), + $r = $h.find('tr.' + ts.css.headerRow).removeClass(ts.css.headerRow + ' ' + c.cssHeaderRow), + $f = $t.find('tfoot:first > tr').children('th, td'); + if (removeClasses === false && $.inArray('uitheme', c.widgets) >= 0) { + // reapply uitheme classes, in case we want to maintain appearance + $t.trigger('applyWidgetId', ['uitheme']); + $t.trigger('applyWidgetId', ['zebra']); + } + // remove widget added rows, just in case + $h.find('tr').not($r).remove(); + // disable tablesorter + events = 'sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache ' + + 'applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState '.split(' ') + .join(c.namespace + ' '); + $t + .removeData('tablesorter') + .unbind( events.replace(/\s+/g, ' ') ); + c.$headers.add($f) + .removeClass( [ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone].join(' ') ) + .removeAttr('data-column') + .removeAttr('aria-label') + .attr('aria-disabled', 'true'); + $r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(/\s+/g, ' ') ); + ts.restoreHeaders(table); + $t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false); + // clear flag in case the plugin is initialized again + table.hasInitialized = false; + delete table.config.cache; + if (typeof callback === 'function') { + callback(table); + } + }; + + // *** sort functions *** + // regex used in natural sort + ts.regex = { + chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters + chunks: /(^\\0|\\0$)/, // replace chunks @ ends + hex: /^0x[0-9a-f]+$/i // hex + }; + + // Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed) + // this function will only accept strings, or you'll see 'TypeError: undefined is not a function' + // I could add a = a.toString(); b = b.toString(); but it'll slow down the sort overall + ts.sortNatural = function(a, b) { + if (a === b) { return 0; } + var xN, xD, yN, yD, xF, yF, i, mx, + r = ts.regex; + // first try and sort Hex codes + if (r.hex.test(b)) { + xD = parseInt(a.match(r.hex), 16); + yD = parseInt(b.match(r.hex), 16); + if ( xD < yD ) { return -1; } + if ( xD > yD ) { return 1; } + } + // chunk/tokenize + xN = a.replace(r.chunk, '\\0$1\\0').replace(r.chunks, '').split('\\0'); + yN = b.replace(r.chunk, '\\0$1\\0').replace(r.chunks, '').split('\\0'); + mx = Math.max(xN.length, yN.length); + // natural sorting through split numeric strings and default strings + for (i = 0; i < mx; i++) { + // find floats not starting with '0', string or 0 if not defined + xF = isNaN(xN[i]) ? xN[i] || 0 : parseFloat(xN[i]) || 0; + yF = isNaN(yN[i]) ? yN[i] || 0 : parseFloat(yN[i]) || 0; + // handle numeric vs string comparison - number < string - (Kyle Adams) + if (isNaN(xF) !== isNaN(yF)) { return (isNaN(xF)) ? 1 : -1; } + // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' + if (typeof xF !== typeof yF) { + xF += ''; + yF += ''; + } + if (xF < yF) { return -1; } + if (xF > yF) { return 1; } + } + return 0; + }; + + ts.sortNaturalAsc = function(a, b, col, table, c) { + if (a === b) { return 0; } + var e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + return ts.sortNatural(a, b); + }; + + ts.sortNaturalDesc = function(a, b, col, table, c) { + if (a === b) { return 0; } + var e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + return ts.sortNatural(b, a); + }; + + // basic alphabetical sort + ts.sortText = function(a, b) { + return a > b ? 1 : (a < b ? -1 : 0); + }; + + // return text string value by adding up ascii value + // so the text is somewhat sorted when using a digital sort + // this is NOT an alphanumeric sort + ts.getTextValue = function(a, num, mx) { + if (mx) { + // make sure the text value is greater than the max numerical value (mx) + var i, l = a ? a.length : 0, n = mx + num; + for (i = 0; i < l; i++) { + n += a.charCodeAt(i); + } + return num * n; + } + return 0; + }; + + ts.sortNumericAsc = function(a, b, num, mx, col, table) { + if (a === b) { return 0; } + var c = table.config, + e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } + if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } + return a - b; + }; + + ts.sortNumericDesc = function(a, b, num, mx, col, table) { + if (a === b) { return 0; } + var c = table.config, + e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } + if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } + return b - a; + }; + + ts.sortNumeric = function(a, b) { + return a - b; + }; + + // used when replacing accented characters during sorting + ts.characterEquivalents = { + 'a' : '\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5', // áàâãäąå + 'A' : '\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5', // ÁÀÂÃÄĄÅ + 'c' : '\u00e7\u0107\u010d', // çćč + 'C' : '\u00c7\u0106\u010c', // ÇĆČ + 'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę + 'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ + 'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı + 'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ + 'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō + 'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ + 'ss': '\u00df', // ß (s sharp) + 'SS': '\u1e9e', // ẞ (Capital sharp s) + 'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů + 'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ + }; + ts.replaceAccents = function(s) { + var a, acc = '[', eq = ts.characterEquivalents; + if (!ts.characterRegex) { + ts.characterRegexArray = {}; + for (a in eq) { + if (typeof a === 'string') { + acc += eq[a]; + ts.characterRegexArray[a] = new RegExp('[' + eq[a] + ']', 'g'); + } + } + ts.characterRegex = new RegExp(acc + ']'); + } + if (ts.characterRegex.test(s)) { + for (a in eq) { + if (typeof a === 'string') { + s = s.replace( ts.characterRegexArray[a], a ); + } + } + } + return s; + }; + + // *** utilities *** + ts.isValueInArray = function(column, arry) { + var indx, len = arry.length; + for (indx = 0; indx < len; indx++) { + if (arry[indx][0] === column) { + return indx; + } + } + return -1; + }; + + ts.addParser = function(parser) { + var i, l = ts.parsers.length, a = true; + for (i = 0; i < l; i++) { + if (ts.parsers[i].id.toLowerCase() === parser.id.toLowerCase()) { + a = false; + } + } + if (a) { + ts.parsers.push(parser); + } + }; + + // Use it to add a set of methods to table.config which will be available for all tables. + // This should be done before table initialization + ts.addInstanceMethods = function(methods) { + $.extend(ts.instanceMethods, methods); + }; + + ts.getParserById = function(name) { + /*jshint eqeqeq:false */ + if (name == 'false') { return false; } + var i, l = ts.parsers.length; + for (i = 0; i < l; i++) { + if (ts.parsers[i].id.toLowerCase() === (name.toString()).toLowerCase()) { + return ts.parsers[i]; + } + } + return false; + }; + + ts.addWidget = function(widget) { + ts.widgets.push(widget); + }; + + ts.hasWidget = function(table, name){ + table = $(table); + return table.length && table[0].config && table[0].config.widgetInit[name] || false; + }; + + ts.getWidgetById = function(name) { + var i, w, l = ts.widgets.length; + for (i = 0; i < l; i++) { + w = ts.widgets[i]; + if (w && w.hasOwnProperty('id') && w.id.toLowerCase() === name.toLowerCase()) { + return w; + } + } + }; + + ts.applyWidgetOptions = function( table, c ){ + var indx, widget, + len = c.widgets.length, + wo = c.widgetOptions; + if (len) { + for (indx = 0; indx < len; indx++) { + widget = ts.getWidgetById( c.widgets[indx] ); + if ( widget && 'options' in widget ) { + wo = table.config.widgetOptions = $.extend( true, {}, widget.options, wo ); + } + } + } + }; + + ts.applyWidget = function(table, init, callback) { + table = $(table)[0]; // in case this is called externally + var indx, len, name, + c = table.config, + wo = c.widgetOptions, + tableClass = ' ' + c.table.className + ' ', + widgets = [], + time, time2, w, wd; + // prevent numerous consecutive widget applications + if (init !== false && table.hasInitialized && (table.isApplyingWidgets || table.isUpdating)) { return; } + if (c.debug) { time = new Date(); } + // look for widgets to apply from in table class + // stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget + wd = new RegExp( '\\s' + c.widgetClass.replace( /\{name\}/i, '([\\w-]+)' )+ '\\s', 'g' ); + if ( tableClass.match( wd ) ) { + // extract out the widget id from the table class (widget id's can include dashes) + w = tableClass.match( wd ); + if ( w ) { + len = w.length; + for (indx = 0; indx < len; indx++) { + c.widgets.push( w[indx].replace( wd, '$1' ) ); + } + } + } + if (c.widgets.length) { + table.isApplyingWidgets = true; + // ensure unique widget ids + c.widgets = $.grep(c.widgets, function(v, k){ + return $.inArray(v, c.widgets) === k; + }); + name = c.widgets || []; + len = name.length; + // build widget array & add priority as needed + for (indx = 0; indx < len; indx++) { + wd = ts.getWidgetById(name[indx]); + if (wd && wd.id) { + // set priority to 10 if not defined + if (!wd.priority) { wd.priority = 10; } + widgets[indx] = wd; + } + } + // sort widgets by priority + widgets.sort(function(a, b){ + return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1; + }); + // add/update selected widgets + len = widgets.length; + for (indx = 0; indx < len; indx++) { + if (widgets[indx]) { + if ( init || !( c.widgetInit[ widgets[indx].id ] ) ) { + // set init flag first to prevent calling init more than once (e.g. pager) + c.widgetInit[ widgets[indx].id ] = true; + if (table.hasInitialized) { + // don't reapply widget options on tablesorter init + ts.applyWidgetOptions( table, c ); + } + if ( 'init' in widgets[indx] ) { + if (c.debug) { time2 = new Date(); } + widgets[indx].init(table, widgets[indx], c, wo); + if (c.debug) { ts.benchmark('Initializing ' + widgets[indx].id + ' widget', time2); } + } + } + if ( !init && 'format' in widgets[indx] ) { + if (c.debug) { time2 = new Date(); } + widgets[indx].format(table, c, wo, false); + if (c.debug) { ts.benchmark( ( init ? 'Initializing ' : 'Applying ' ) + widgets[indx].id + ' widget', time2); } + } + } + } + // callback executed on init only + if (!init && typeof callback === 'function') { + callback(table); + } + } + setTimeout(function(){ + table.isApplyingWidgets = false; + $.data(table, 'lastWidgetApplication', new Date()); + }, 0); + if (c.debug) { + w = c.widgets.length; + benchmark('Completed ' + (init === true ? 'initializing ' : 'applying ') + w + ' widget' + (w !== 1 ? 's' : ''), time); + } + }; + + ts.removeWidget = function(table, name, refreshing){ + table = $(table)[0]; + var i, widget, indx, len, + c = table.config; + // if name === true, add all widgets from $.tablesorter.widgets + if (name === true) { + name = []; + len = ts.widgets.length; + for (indx = 0; indx < len; indx++) { + widget = ts.widgets[indx]; + if (widget && widget.id) { + name.push( widget.id ); + } + } + } else { + // name can be either an array of widgets names, + // or a space/comma separated list of widget names + name = ( $.isArray(name) ? name.join(',') : name || '' ).toLowerCase().split( /[\s,]+/ ); + } + len = name.length; + for (i = 0; i < len; i++) { + widget = ts.getWidgetById(name[i]); + indx = $.inArray( name[i], c.widgets ); + if ( widget && 'remove' in widget ) { + if (c.debug && indx >= 0) { log( 'Removing "' + name[i] + '" widget' ); } + widget.remove(table, c, c.widgetOptions, refreshing); + c.widgetInit[ name[i] ] = false; + } + // don't remove the widget from config.widget if refreshing + if (indx >= 0 && refreshing !== true) { + c.widgets.splice( indx, 1 ); + } + } + }; + + ts.refreshWidgets = function(table, doAll, dontapply) { + table = $(table)[0]; // see issue #243 + var indx, + c = table.config, + cw = c.widgets, + widgets = ts.widgets, + len = widgets.length, + list = [], + callback = function(table){ + $(table).trigger('refreshComplete'); + }; + // remove widgets not defined in config.widgets, unless doAll is true + for (indx = 0; indx < len; indx++) { + if (widgets[indx] && widgets[indx].id && (doAll || $.inArray( widgets[indx].id, cw ) < 0)) { + list.push( widgets[indx].id ); + } + } + ts.removeWidget( table, list.join(','), true ); + if (dontapply !== true) { + // call widget init if + ts.applyWidget(table, doAll || false, callback ); + if (doAll) { + // apply widget format + ts.applyWidget(table, false, callback); + } + } else { + callback(table); + } + }; + + ts.getColumnText = function( table, column, callback ) { + table = $( table )[0]; + var tbodyIndex, rowIndex, cache, row, tbodyLen, rowLen, raw, parsed, $cell, result, + hasCallback = typeof callback === 'function', + allColumns = column === 'all', + data = { raw : [], parsed: [], $cell: [] }, + c = table.config; + if ( !isEmptyObject( c ) ) { + tbodyLen = c.$tbodies.length; + for ( tbodyIndex = 0; tbodyIndex < tbodyLen; tbodyIndex++ ) { + cache = c.cache[ tbodyIndex ].normalized; + rowLen = cache.length; + for ( rowIndex = 0; rowIndex < rowLen; rowIndex++ ) { + result = true; + row = cache[ rowIndex ]; + parsed = ( allColumns ) ? row.slice(0, c.columns) : row[ column ]; + row = row[ c.columns ]; + raw = ( allColumns ) ? row.raw : row.raw[ column ]; + $cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column ); + if ( hasCallback ) { + result = callback({ + tbodyIndex: tbodyIndex, + rowIndex: rowIndex, + parsed: parsed, + raw: raw, + $row: row.$row, + $cell: $cell + }); + } + if ( result !== false ) { + data.parsed.push( parsed ); + data.raw.push( raw ); + data.$cell.push( $cell ); + } + } + } + // return everything + return data; + } + }; + + // get sorter, string, empty, etc options for each column from + // jQuery data, metadata, header option or header class name ('sorter-false') + // priority = jQuery data > meta > headers option > header class name + ts.getData = function(h, ch, key) { + var val = '', $h = $(h), m, cl; + if (!$h.length) { return ''; } + m = $.metadata ? $h.metadata() : false; + cl = ' ' + ($h.attr('class') || ''); + if (typeof $h.data(key) !== 'undefined' || typeof $h.data(key.toLowerCase()) !== 'undefined'){ + // 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder' + // 'data-sort-initial-order' is assigned to 'sortInitialOrder' + val += $h.data(key) || $h.data(key.toLowerCase()); + } else if (m && typeof m[key] !== 'undefined') { + val += m[key]; + } else if (ch && typeof ch[key] !== 'undefined') { + val += ch[key]; + } else if (cl !== ' ' && cl.match(' ' + key + '-')) { + // include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser' + val = cl.match( new RegExp('\\s' + key + '-([\\w-]+)') )[1] || ''; + } + return $.trim(val); + }; + + ts.formatFloat = function(s, table) { + if (typeof s !== 'string' || s === '') { return s; } + // allow using formatFloat without a table; defaults to US number format + var i, + t = table && table.config ? table.config.usNumberFormat !== false : + typeof table !== 'undefined' ? table : true; + if (t) { + // US Format - 1,234,567.89 -> 1234567.89 + s = s.replace(/,/g,''); + } else { + // German Format = 1.234.567,89 -> 1234567.89 + // French Format = 1 234 567,89 -> 1234567.89 + s = s.replace(/[\s|\.]/g,'').replace(/,/g,'.'); + } + if(/^\s*\([.\d]+\)/.test(s)) { + // make (#) into a negative number -> (10) = -10 + s = s.replace(/^\s*\(([.\d]+)\)/, '-$1'); + } + i = parseFloat(s); + // return the text instead of zero + return isNaN(i) ? $.trim(s) : i; + }; + + ts.isDigit = function(s) { + // replace all unwanted chars and match + return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : s !== ''; + }; + + }() + }); + + // make shortcut + var ts = $.tablesorter; + + // extend plugin scope + $.fn.extend({ + tablesorter: ts.construct + }); + + // add default parsers + ts.addParser({ + id: 'no-parser', + is: function() { + return false; + }, + format: function() { + return ''; + }, + type: 'text' + }); + + ts.addParser({ + id: 'text', + is: function() { + return true; + }, + format: function(s, table) { + var c = table.config; + if (s) { + s = $.trim( c.ignoreCase ? s.toLocaleLowerCase() : s ); + s = c.sortLocaleCompare ? ts.replaceAccents(s) : s; + } + return s; + }, + type: 'text' + }); + + ts.addParser({ + id: 'digit', + is: function(s) { + return ts.isDigit(s); + }, + format: function(s, table) { + var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table); + return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'currency', + is: function(s) { + return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test((s || '').replace(/[+\-,. ]/g,'')); // £$€¤¥¢ + }, + format: function(s, table) { + var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table); + return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'url', + is: function(s) { + return (/^(https?|ftp|file):\/\//).test(s); + }, + format: function(s) { + return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s; + }, + parsed : true, // filter widget flag + type: 'text' + }); + + ts.addParser({ + id: 'isoDate', + is: function(s) { + return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s); + }, + format: function(s, table) { + var date = s ? new Date( s.replace(/-/g, '/') ) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'percent', + is: function(s) { + return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15; + }, + format: function(s, table) { + return s ? ts.formatFloat(s.replace(/%/g, ''), table) : s; + }, + type: 'numeric' + }); + + // added image parser to core v2.17.9 + ts.addParser({ + id: 'image', + is: function(s, table, node, $node){ + return $node.find('img').length > 0; + }, + format: function(s, table, cell) { + return $(cell).find('img').attr(table.config.imgAttr || 'alt') || s; + }, + parsed : true, // filter widget flag + type: 'text' + }); + + ts.addParser({ + id: 'usLongDate', + is: function(s) { + // two digit years are not allowed cross-browser + // Jan 01, 2013 12:34:56 PM or 01 Jan 2013 + return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) || (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s); + }, + format: function(s, table) { + var date = s ? new Date( s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd' + is: function(s) { + // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included + return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test((s || '').replace(/\s+/g,' ').replace(/[\-.,]/g, '/')); + }, + format: function(s, table, cell, cellIndex) { + if (s) { + var date, d, + c = table.config, + ci = c.$headerIndexed[ cellIndex ], + format = ci.length && ci[0].dateFormat || ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') || c.dateFormat; + d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/'); // escaped - because JSHint in Firefox was showing it as an error + if (format === 'mmddyyyy') { + d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$1/$2'); + } else if (format === 'ddmmyyyy') { + d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$2/$1'); + } else if (format === 'yyyymmdd') { + d = d.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, '$1/$2/$3'); + } + date = new Date(d); + return date instanceof Date && isFinite(date) ? date.getTime() : s; + } + return s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'time', + is: function(s) { + return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s); + }, + format: function(s, table) { + var date = s ? new Date( '2000/01/01 ' + s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + ts.addParser({ + id: 'metadata', + is: function() { + return false; + }, + format: function(s, table, cell) { + var c = table.config, + p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; + return $(cell).metadata()[p]; + }, + type: 'numeric' + }); + + // add default widgets + ts.addWidget({ + id: 'zebra', + priority: 90, + format: function(table, c, wo) { + var $tv, $tr, row, even, time, k, i, len, + child = new RegExp(c.cssChildRow, 'i'), + b = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) ); + if (c.debug) { + time = new Date(); + } + for (k = 0; k < b.length; k++ ) { + // loop through the visible rows + row = 0; + $tv = b.eq( k ).children( 'tr:visible' ).not( c.selectorRemove ); + len = $tv.length; + for ( i = 0; i < len; i++ ) { + $tr = $tv.eq( i ); + // style child rows the same way the parent row was styled + if ( !child.test( $tr[0].className ) ) { row++; } + even = ( row % 2 === 0 ); + $tr + .removeClass( wo.zebra[ even ? 1 : 0 ] ) + .addClass( wo.zebra[ even ? 0 : 1 ] ); + } + } + }, + remove: function(table, c, wo, refreshing){ + if (refreshing) { return; } + var k, $tb, + b = c.$tbodies, + rmv = (wo.zebra || [ 'even', 'odd' ]).join(' '); + for (k = 0; k < b.length; k++ ){ + $tb = ts.processTbody(table, b.eq(k), true); // remove tbody + $tb.children().removeClass(rmv); + ts.processTbody(table, $tb, false); // restore tbody + } + } + }); + +})(jQuery); diff --git a/js/jquery.tablesorter.widgets.js b/js/jquery.tablesorter.widgets.js new file mode 100644 index 0000000..6b78ea1 --- /dev/null +++ b/js/jquery.tablesorter.widgets.js @@ -0,0 +1,2637 @@ +/*** This file is dynamically generated *** +█████▄ ▄████▄ █████▄ ▄████▄ ██████ ███████▄ ▄████▄ █████▄ ██ ██████ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██ +█████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀ +*/ +/*! tablesorter (FORK) - updated 06-07-2015 (v2.22.1)*/ +/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */ +(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($) { + +/*! Widget: storage - updated 3/26/2015 (v2.21.3) */ +;(function ($, window, document) { +'use strict'; + +var ts = $.tablesorter || {}; +// *** Store data in local storage, with a cookie fallback *** +/* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json) + if you need it, then include https://github.com/douglascrockford/JSON-js + + $.parseJSON is not available is jQuery versions older than 1.4.1, using older + versions will only allow storing information for one page at a time + + // *** Save data (JSON format only) *** + // val must be valid JSON... use http://jsonlint.com/ to ensure it is valid + var val = { "mywidget" : "data1" }; // valid JSON uses double quotes + // $.tablesorter.storage(table, key, val); + $.tablesorter.storage(table, 'tablesorter-mywidget', val); + + // *** Get data: $.tablesorter.storage(table, key); *** + v = $.tablesorter.storage(table, 'tablesorter-mywidget'); + // val may be empty, so also check for your data + val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : ''; + alert(val); // "data1" if saved, or "" if not +*/ +ts.storage = function(table, key, value, options) { + table = $(table)[0]; + var cookieIndex, cookies, date, + hasStorage = false, + values = {}, + c = table.config, + wo = c && c.widgetOptions, + storageType = ( options && options.useSessionStorage ) || ( wo && wo.storage_useSessionStorage ) ? + 'sessionStorage' : 'localStorage', + $table = $(table), + // id from (1) options ID, (2) table "data-table-group" attribute, (3) widgetOptions.storage_tableId, + // (4) table ID, then (5) table index + id = options && options.id || + $table.attr( options && options.group || wo && wo.storage_group || 'data-table-group') || + wo && wo.storage_tableId || table.id || $('.tablesorter').index( $table ), + // url from (1) options url, (2) table "data-table-page" attribute, (3) widgetOptions.storage_fixedUrl, + // (4) table.config.fixedUrl (deprecated), then (5) window location path + url = options && options.url || + $table.attr(options && options.page || wo && wo.storage_page || 'data-table-page') || + wo && wo.storage_fixedUrl || c && c.fixedUrl || window.location.pathname; + // https://gist.github.com/paulirish/5558557 + if (storageType in window) { + try { + window[storageType].setItem('_tmptest', 'temp'); + hasStorage = true; + window[storageType].removeItem('_tmptest'); + } catch(error) { + if (c && c.debug) { + ts.log( storageType + ' is not supported in this browser' ); + } + } + } + // *** get value *** + if ($.parseJSON) { + if (hasStorage) { + values = $.parseJSON( window[storageType][key] || 'null' ) || {}; + } else { + // old browser, using cookies + cookies = document.cookie.split(/[;\s|=]/); + // add one to get from the key to the value + cookieIndex = $.inArray(key, cookies) + 1; + values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {}; + } + } + // allow value to be an empty string too + if ((value || value === '') && window.JSON && JSON.hasOwnProperty('stringify')) { + // add unique identifiers = url pathname > table ID/index on page > data + if (!values[url]) { + values[url] = {}; + } + values[url][id] = value; + // *** set value *** + if (hasStorage) { + window[storageType][key] = JSON.stringify(values); + } else { + date = new Date(); + date.setTime(date.getTime() + (31536e+6)); // 365 days + document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g,'\"') + '; expires=' + date.toGMTString() + '; path=/'; + } + } else { + return values && values[url] ? values[url][id] : ''; + } +}; + +})(jQuery, window, document); + +/*! Widget: uitheme - updated 3/26/2015 (v2.21.3) */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +ts.themes = { + 'bootstrap' : { + table : 'table table-bordered table-striped', + caption : 'caption', + // header class names + header : 'bootstrap-header', // give the header a gradient background (theme.bootstrap_2.css) + sortNone : '', + sortAsc : '', + sortDesc : '', + active : '', // applied when column is sorted + hover : '', // custom css required - a defined bootstrap style may not override other classes + // icon class names + icons : '', // add "icon-white" to make them white; this icon class is added to the in the header + iconSortNone : 'bootstrap-icon-unsorted', // class name added to icon when column is not sorted + iconSortAsc : 'icon-chevron-up glyphicon glyphicon-chevron-up', // class name added to icon when column has ascending sort + iconSortDesc : 'icon-chevron-down glyphicon glyphicon-chevron-down', // class name added to icon when column has descending sort + filterRow : '', // filter row class + footerRow : '', + footerCells : '', + even : '', // even row zebra striping + odd : '' // odd row zebra striping + }, + 'jui' : { + table : 'ui-widget ui-widget-content ui-corner-all', // table classes + caption : 'ui-widget-content', + // header class names + header : 'ui-widget-header ui-corner-all ui-state-default', // header classes + sortNone : '', + sortAsc : '', + sortDesc : '', + active : 'ui-state-active', // applied when column is sorted + hover : 'ui-state-hover', // hover class + // icon class names + icons : 'ui-icon', // icon class added to the in the header + iconSortNone : 'ui-icon-carat-2-n-s', // class name added to icon when column is not sorted + iconSortAsc : 'ui-icon-carat-1-n', // class name added to icon when column has ascending sort + iconSortDesc : 'ui-icon-carat-1-s', // class name added to icon when column has descending sort + filterRow : '', + footerRow : '', + footerCells : '', + even : 'ui-widget-content', // even row zebra striping + odd : 'ui-state-default' // odd row zebra striping + } +}; + +$.extend(ts.css, { + wrapper : 'tablesorter-wrapper' // ui theme & resizable +}); + +ts.addWidget({ + id: "uitheme", + priority: 10, + format: function(table, c, wo) { + var i, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme, + themesAll = ts.themes, + $table = c.$table.add( $( c.namespace + '_extra_table' ) ), + $headers = c.$headers.add( $( c.namespace + '_extra_headers' ) ), + theme = c.theme || 'jui', + themes = themesAll[theme] || {}, + remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ), + iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) ); + if (c.debug) { time = new Date(); } + // initialization code - run once + if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) { + wo.uitheme_applied = true; + oldtheme = themesAll[c.appliedTheme] || {}; + hasOldTheme = !$.isEmptyObject(oldtheme); + oldremove = hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : ''; + oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : ''; + if (hasOldTheme) { + wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') ); + wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') ); + c.$tbodies.children().removeClass( [oldtheme.even, oldtheme.odd].join(' ') ); + } + // update zebra stripes + if (themes.even) { wo.zebra[0] += ' ' + themes.even; } + if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; } + // add caption style + $table.children('caption') + .removeClass(oldtheme.caption || '') + .addClass(themes.caption); + // add table/footer class names + $tfoot = $table + // remove other selected themes + .removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') ) + .addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name + .children('tfoot'); + c.appliedTheme = c.theme; + + if ($tfoot.length) { + $tfoot + // if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed + .children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow) + .children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells); + } + // update header classes + $headers + .removeClass( (hasOldTheme ? [oldtheme.header, oldtheme.hover, oldremove].join(' ') : '') || '' ) + .addClass(themes.header) + .not('.sorter-false') + .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') + .bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) { + // toggleClass with switch added in jQuery 1.3 + $(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || ''); + }); + + $headers.each(function(){ + var $this = $(this); + if (!$this.find('.' + ts.css.wrapper).length) { + // Firefox needs this inner div to position the icon & resizer correctly + $this.wrapInner('
    '); + } + }); + if (c.cssIcon) { + // if c.cssIcon is '', then no is added to the header + $headers + .find('.' + ts.css.icon) + .removeClass(hasOldTheme ? [oldtheme.icons, oldIconRmv].join(' ') : '') + .addClass(themes.icons || ''); + } + if ($table.hasClass('hasFilters')) { + $table.children('thead').children('.' + ts.css.filterRow) + .removeClass(hasOldTheme ? oldtheme.filterRow || '' : '') + .addClass(themes.filterRow || ''); + } + } + for (i = 0; i < c.columns; i++) { + $header = c.$headers + .add($(c.namespace + '_extra_headers')) + .not('.sorter-false') + .filter('[data-column="' + i + '"]'); + $icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $(); + $h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last'); + if ($h.length) { + $header.removeClass(remove); + $icon.removeClass(iconRmv); + if ($h[0].sortDisabled) { + // no sort arrows for disabled columns! + $icon.removeClass(themes.icons || ''); + } else { + hdr = themes.sortNone; + icon = themes.iconSortNone; + if ($h.hasClass(ts.css.sortAsc)) { + hdr = [themes.sortAsc, themes.active].join(' '); + icon = themes.iconSortAsc; + } else if ($h.hasClass(ts.css.sortDesc)) { + hdr = [themes.sortDesc, themes.active].join(' '); + icon = themes.iconSortDesc; + } + $header.addClass(hdr); + $icon.addClass(icon || ''); + } + } + } + if (c.debug) { + ts.benchmark("Applying " + theme + " theme", time); + } + }, + remove: function(table, c, wo, refreshing) { + if (!wo.uitheme_applied) { return; } + var $table = c.$table, + theme = c.appliedTheme || 'jui', + themes = ts.themes[ theme ] || ts.themes.jui, + $headers = $table.children('thead').children(), + remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc, + iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc; + $table.removeClass('tablesorter-' + theme + ' ' + themes.table); + wo.uitheme_applied = false; + if (refreshing) { return; } + $table.find(ts.css.header).removeClass(themes.header); + $headers + .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover + .removeClass(themes.hover + ' ' + remove + ' ' + themes.active) + .filter('.' + ts.css.filterRow) + .removeClass(themes.filterRow); + $headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv); + } +}); + +})(jQuery); + +/*! Widget: columns */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +ts.addWidget({ + id: "columns", + priority: 30, + options : { + columns : [ "primary", "secondary", "tertiary" ] + }, + format: function(table, c, wo) { + var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx, + $table = c.$table, + $tbodies = c.$tbodies, + sortList = c.sortList, + len = sortList.length, + // removed c.widgetColumns support + css = wo && wo.columns || [ "primary", "secondary", "tertiary" ], + last = css.length - 1; + remove = css.join(' '); + // check if there is a sort (on initialization there may not be one) + for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody + $rows = $tbody.children('tr'); + // loop through the visible rows + $rows.each(function() { + $row = $(this); + if (this.style.display !== 'none') { + // remove all columns class names + $cells = $row.children().removeClass(remove); + // add appropriate column class names + if (sortList && sortList[0]) { + // primary sort column class + $cells.eq(sortList[0][0]).addClass(css[0]); + if (len > 1) { + for (indx = 1; indx < len; indx++) { + // secondary, tertiary, etc sort column classes + $cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] ); + } + } + } + } + }); + ts.processTbody(table, $tbody, false); + } + // add classes to thead and tfoot + rows = wo.columns_thead !== false ? ['thead tr'] : []; + if (wo.columns_tfoot !== false) { + rows.push('tfoot tr'); + } + if (rows.length) { + $rows = $table.find( rows.join(',') ).children().removeClass(remove); + if (len) { + for (indx = 0; indx < len; indx++) { + // add primary. secondary, tertiary, etc sort column classes + $rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]); + } + } + } + }, + remove: function(table, c, wo) { + var tbodyIndex, $tbody, + $tbodies = c.$tbodies, + remove = (wo.columns || [ "primary", "secondary", "tertiary" ]).join(' '); + c.$headers.removeClass(remove); + c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove); + for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody + $tbody.children('tr').each(function() { + $(this).children().removeClass(remove); + }); + ts.processTbody(table, $tbody, false); // restore tbody + } + } +}); + +})(jQuery); + +/*! Widget: filter - updated 5/17/2015 (v2.22.1) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +;( function ( $ ) { +'use strict'; +var ts = $.tablesorter || {}, + tscss = ts.css; + +$.extend( tscss, { + filterRow : 'tablesorter-filter-row', + filter : 'tablesorter-filter', + filterDisabled : 'disabled', + filterRowHide : 'hideme' +}); + +ts.addWidget({ + id: 'filter', + priority: 50, + options : { + filter_childRows : false, // if true, filter includes child row content in the search + filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped + filter_columnFilters : true, // if true, a filter will be added to the top of each table column + filter_columnAnyMatch: true, // if true, allows using '#:{query}' in AnyMatch searches ( column:query ) + filter_cellFilter : '', // css class name added to the filter cell ( string or array ) + filter_cssFilter : '', // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added ) + 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. + filter_excludeFilter : {}, // filters to exclude, per column + filter_external : '', // jQuery selector string ( or jQuery object ) of external filters + filter_filteredRow : 'filtered', // class added to filtered rows; needed by pager plugin + filter_formatter : null, // add custom filter elements to the filter row + filter_functions : null, // add custom filter functions using this option + filter_hideEmpty : true, // hide filter row when table is empty + filter_hideFilters : false, // collapse filter row when mouse leaves the area + filter_ignoreCase : true, // if true, make all searches case-insensitive + filter_liveSearch : true, // if true, search column content while the user types ( with a delay ) + filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down + filter_placeholder : { search : '', select : '' }, // default placeholder text ( overridden by any header 'data-placeholder' setting ) + filter_reset : null, // jQuery selector string of an element used to reset the filters + filter_saveFilters : false, // Use the $.tablesorter.storage utility to save the most recent filters + filter_searchDelay : 300, // typing delay in milliseconds before starting a search + filter_searchFiltered: true, // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true + filter_selectSource : null, // include a function to return an array of values to be added to the column filter select + filter_startsWith : false, // if true, filter start from the beginning of the cell contents + filter_useParsedData : false, // filter all data using parsed content + filter_serversideFiltering : false, // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used. + filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value + filter_selectSourceSeparator : '|' // filter_selectSource array text left of the separator is added to the option value, right into the option text + }, + format: function( table, c, wo ) { + if ( !c.$table.hasClass( 'hasFilters' ) ) { + ts.filter.init( table, c, wo ); + } + }, + remove: function( table, c, wo, refreshing ) { + var tbodyIndex, $tbody, + $table = c.$table, + $tbodies = c.$tbodies, + events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ' + .split( ' ' ).join( c.namespace + 'filter ' ); + $table + .removeClass( 'hasFilters' ) + // add .tsfilter namespace to all BUT search + .unbind( events.replace( /\s+/g, ' ' ) ) + // remove the filter row even if refreshing, because the column might have been moved + .find( '.' + tscss.filterRow ).remove(); + if ( refreshing ) { return; } + for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody + $tbody.children().removeClass( wo.filter_filteredRow ).show(); + ts.processTbody( table, $tbody, false ); // restore tbody + } + if ( wo.filter_reset ) { + $( document ).undelegate( wo.filter_reset, 'click.tsfilter' ); + } + } +}); + +ts.filter = { + + // regex used in filter 'check' functions - not for general use and not documented + regex: { + regex : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex + child : /tablesorter-childRow/, // child row class name; this gets updated in the script + filtered : /filtered/, // filtered (hidden) row class name; updated in the script + type : /undefined|number/, // check type + exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==') + nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser) + operators : /[<>=]/g, // replace operators + query : '(q|query)' // replace filter queries + }, + // function( c, data ) { } + // c = table.config + // data.$row = jQuery object of the row currently being processed + // data.$cells = jQuery object of all cells within the current row + // data.filters = array of filters for all columns ( some may be undefined ) + // data.filter = filter for the current column + // data.iFilter = same as data.filter, except lowercase ( if wo.filter_ignoreCase is true ) + // data.exact = table cell text ( or parsed data if column parser enabled ) + // data.iExact = same as data.exact, except lowercase ( if wo.filter_ignoreCase is true ) + // data.cache = table cell text from cache, so it has been parsed ( & in all lower case if c.ignoreCase is true ) + // data.cacheArray = An array of parsed content from each table cell in the row being processed + // data.index = column index; table = table element ( DOM ) + // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class ) + types: { + // Look for regex + regex: function( c, data ) { + if ( ts.filter.regex.regex.test( data.filter ) ) { + var matches, + // cache regex per column for optimal speed + regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ), + isRegex = regex instanceof RegExp; + try { + if ( !isRegex ) { + // force case insensitive search if ignoreCase option set? + // if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; } + data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] ); + } + matches = regex.test( data.exact ); + } catch ( error ) { + matches = false; + } + return matches; + } + return null; + }, + // Look for operators >, >=, < or <= + operators: function( c, data ) { + // ignore empty strings... because '' < 10 is true + if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) { + var cachedValue, result, txt, + table = c.table, + index = data.index, + parsed = data.parsed[index], + query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ), + parser = c.parsers[index], + savedSearch = query; + // parse filter value in case we're comparing numbers ( dates ) + if ( parsed || parser.type === 'numeric' ) { + txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) ); + result = ts.filter.parseFilter( c, txt, index, true ); + query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query; + } + // iExact may be numeric - see issue #149; + // check if cached is defined, because sometimes j goes out of range? ( numeric columns ) + if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) && + typeof data.cache !== 'undefined' ) { + cachedValue = data.cache; + } else { + txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact; + cachedValue = ts.formatFloat( txt, table ); + } + if ( />/.test( data.iFilter ) ) { + result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query; + } else if ( /= 0 ); + } + } + return null; + }, + // Look for quotes or equals to get an exact match; ignore type since iExact could be numeric + exact: function( c, data ) { + /*jshint eqeqeq:false */ + if ( ts.filter.regex.exact.test( data.iFilter ) ) { + var txt = data.iFilter.replace( ts.filter.regex.exact, '' ), + filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || ''; + return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact; + } + return null; + }, + // Look for an AND or && operator ( logical and ) + and : function( c, data ) { + if ( ts.filter.regex.andTest.test( data.filter ) ) { + var index = data.index, + parsed = data.parsed[index], + query = data.iFilter.split( ts.filter.regex.andSplit ), + result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0, + indx = query.length - 1; + while ( result && indx ) { + result = result && + data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0; + indx--; + } + return result; + } + return null; + }, + // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu! + range : function( c, data ) { + if ( ts.filter.regex.toTest.test( data.iFilter ) ) { + var result, tmp, range1, range2, + table = c.table, + index = data.index, + parsed = data.parsed[index], + // make sure the dash is for a range and not indicating a negative number + query = data.iFilter.split( ts.filter.regex.toSplit ); + + tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || ''; + range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table ); + tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || ''; + range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table ); + // parse filter value in case we're comparing numbers ( dates ) + if ( parsed || c.parsers[index].type === 'numeric' ) { + result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index ); + range1 = ( result !== '' && !isNaN( result ) ) ? result : range1; + result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index ); + range2 = ( result !== '' && !isNaN( result ) ) ? result : range2; + } + if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) { + result = data.cache; + } else { + tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact; + result = ts.formatFloat( tmp, table ); + } + if ( range1 > range2 ) { + tmp = range1; range1 = range2; range2 = tmp; // swap + } + return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' ); + } + return null; + }, + // Look for wild card: ? = single, * = multiple, or | = logical OR + wild : function( c, data ) { + if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) { + var index = data.index, + parsed = data.parsed[ index ], + txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ), + query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' ); + // look for an exact match with the 'or' unless the 'filter-match' class is found + if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) { + // show all results while using filter match. Fixes #727 + if ( query[ query.length - 1 ] === '|' ) { + query += '*'; + } + query = data.anyMatch && $.isArray( data.rowArray ) ? + '(' + query + ')' : + '^(' + query + ')$'; + } + // parsing the filter may not work properly when using wildcards =/ + return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) ) + .test( data.iExact ); + } + return null; + }, + // fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license ) + fuzzy: function( c, data ) { + if ( /^~/.test( data.iFilter ) ) { + var indx, + patternIndx = 0, + len = data.iExact.length, + txt = data.iFilter.slice( 1 ), + pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || ''; + for ( indx = 0; indx < len; indx++ ) { + if ( data.iExact[ indx ] === pattern[ patternIndx ] ) { + patternIndx += 1; + } + } + if ( patternIndx === pattern.length ) { + return true; + } + return false; + } + return null; + } + }, + init: function( table, c, wo ) { + // filter language options + ts.language = $.extend( true, {}, { + to : 'to', + or : 'or', + and : 'and' + }, ts.language ); + + var options, string, txt, $header, column, filters, val, fxn, noSelect, + regex = ts.filter.regex; + c.$table.addClass( 'hasFilters' ); + + // define timers so using clearTimeout won't cause an undefined error + wo.searchTimer = null; + wo.filter_initTimer = null; + wo.filter_formatterCount = 0; + wo.filter_formatterInit = []; + wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]'; + wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]'; + + val = '\\{' + ts.filter.regex.query + '\\}'; + $.extend( regex, { + child : new RegExp( c.cssChildRow ), + filtered : new RegExp( wo.filter_filteredRow ), + alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ), + toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ), + toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ), + andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ), + andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ), + orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ), + iQuery : new RegExp( val, 'i' ), + igQuery : new RegExp( val, 'ig' ) + }); + + // don't build filter row if columnFilters is false or all columns are set to 'filter-false' + // see issue #156 + val = c.$headers.filter( '.filter-false, .parser-false' ).length; + if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) { + // build filter row + ts.filter.buildRow( table, c, wo ); + } + + txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ' + .split( ' ' ).join( c.namespace + 'filter ' ); + c.$table.bind( txt, function( event, filter ) { + val = wo.filter_hideEmpty && + $.isEmptyObject( c.cache ) && + !( c.delayInit && event.type === 'appendCache' ); + // hide filter row using the 'filtered' class name + c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450 + if ( !/(search|filter)/.test( event.type ) ) { + event.stopPropagation(); + ts.filter.buildDefault( table, true ); + } + if ( event.type === 'filterReset' ) { + c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' ); + ts.filter.searching( table, [] ); + } else if ( event.type === 'filterEnd' ) { + ts.filter.buildDefault( table, true ); + } else { + // send false argument to force a new search; otherwise if the filter hasn't changed, + // it will return + filter = event.type === 'search' ? filter : + event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : ''; + if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) { + // force a new search since content has changed + c.lastCombinedFilter = null; + c.lastSearch = []; + } + // pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first + // input ensures all inputs are updated when a search is triggered on the table + // $( 'table' ).trigger( 'search', [...] ); + ts.filter.searching( table, filter, true ); + } + return false; + }); + + // reset button/link + if ( wo.filter_reset ) { + if ( wo.filter_reset instanceof $ ) { + // reset contains a jQuery object, bind to it + wo.filter_reset.click( function() { + c.$table.trigger( 'filterReset' ); + }); + } else if ( $( wo.filter_reset ).length ) { + // reset is a jQuery selector, use event delegation + $( document ) + .undelegate( wo.filter_reset, 'click.tsfilter' ) + .delegate( wo.filter_reset, 'click.tsfilter', function() { + // trigger a reset event, so other functions ( filter_formatter ) know when to reset + c.$table.trigger( 'filterReset' ); + }); + } + } + if ( wo.filter_functions ) { + for ( column = 0; column < c.columns; column++ ) { + fxn = ts.getColumnData( table, wo.filter_functions, column ); + if ( fxn ) { + // remove 'filter-select' from header otherwise the options added here are replaced with + // all options + $header = c.$headerIndexed[ column ].removeClass( 'filter-select' ); + // don't build select if 'filter-false' or 'parser-false' set + noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) ); + options = ''; + if ( fxn === true && noSelect ) { + ts.filter.buildSelect( table, column ); + } else if ( typeof fxn === 'object' && noSelect ) { + // add custom drop down list + for ( string in fxn ) { + if ( typeof string === 'string' ) { + options += options === '' ? + '' : ''; + val = string; + txt = string; + if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) { + val = string.split( wo.filter_selectSourceSeparator ); + txt = val[1]; + val = val[0]; + } + options += ''; + } + } + c.$table + .find( 'thead' ) + .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' ) + .append( options ); + txt = wo.filter_selectSource; + fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column ); + if ( fxn ) { + // updating so the extra options are appended + ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) ); + } + } + } + } + } + // not really updating, but if the column has both the 'filter-select' class & + // filter_functions set to true, it would append the same options twice. + ts.filter.buildDefault( table, true ); + + ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true ); + if ( wo.filter_external ) { + ts.filter.bindSearch( table, wo.filter_external ); + } + + if ( wo.filter_hideFilters ) { + ts.filter.hideFilters( table, c ); + } + + // show processing icon + if ( c.showProcessing ) { + txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' ); + c.$table + .unbind( txt.replace( /\s+/g, ' ' ) ) + .bind( txt, function( event, columns ) { + // only add processing to certain columns to all columns + $header = ( columns ) ? + c.$table + .find( '.' + tscss.header ) + .filter( '[data-column]' ) + .filter( function() { + return columns[ $( this ).data( 'column' ) ] !== ''; + }) : ''; + ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' ); + }); + } + + // set filtered rows count ( intially unfiltered ) + c.filteredRows = c.totalRows; + + // add default values + txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' ); + c.$table + .unbind( txt.replace( /\s+/g, ' ' ) ) + .bind( txt, function() { + // redefine 'wo' as it does not update properly inside this callback + var wo = this.config.widgetOptions; + filters = ts.filter.setDefaults( table, c, wo ) || []; + if ( filters.length ) { + // prevent delayInit from triggering a cache build if filters are empty + if ( !( c.delayInit && filters.join( '' ) === '' ) ) { + ts.setFilters( table, filters, true ); + } + } + c.$table.trigger( 'filterFomatterUpdate' ); + // trigger init after setTimeout to prevent multiple filterStart/End/Init triggers + setTimeout( function() { + if ( !wo.filter_initialized ) { + ts.filter.filterInitComplete( c ); + } + }, 100 ); + }); + // if filter widget is added after pager has initialized; then set filter init flag + if ( c.pager && c.pager.initialized && !wo.filter_initialized ) { + c.$table.trigger( 'filterFomatterUpdate' ); + setTimeout( function() { + ts.filter.filterInitComplete( c ); + }, 100 ); + } + }, + // $cell parameter, but not the config, is passed to the filter_formatters, + // so we have to work with it instead + formatterUpdated: function( $cell, column ) { + var wo = $cell.closest( 'table' )[0].config.widgetOptions; + if ( !wo.filter_initialized ) { + // add updates by column since this function + // may be called numerous times before initialization + wo.filter_formatterInit[ column ] = 1; + } + }, + filterInitComplete: function( c ) { + var indx, len, + wo = c.widgetOptions, + count = 0, + completed = function() { + wo.filter_initialized = true; + c.$table.trigger( 'filterInit', c ); + ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] ); + }; + if ( $.isEmptyObject( wo.filter_formatter ) ) { + completed(); + } else { + len = wo.filter_formatterInit.length; + for ( indx = 0; indx < len; indx++ ) { + if ( wo.filter_formatterInit[ indx ] === 1 ) { + count++; + } + } + clearTimeout( wo.filter_initTimer ); + if ( !wo.filter_initialized && count === wo.filter_formatterCount ) { + // filter widget initialized + completed(); + } else if ( !wo.filter_initialized ) { + // fall back in case a filter_formatter doesn't call + // $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off + wo.filter_initTimer = setTimeout( function() { + completed(); + }, 500 ); + } + } + }, + + setDefaults: function( table, c, wo ) { + var isArray, saved, indx, col, $filters, + // get current ( default ) filters + filters = ts.getFilters( table ) || []; + if ( wo.filter_saveFilters && ts.storage ) { + saved = ts.storage( table, 'tablesorter-filters' ) || []; + isArray = $.isArray( saved ); + // make sure we're not just getting an empty array + if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) { + filters = saved; + } + } + // if no filters saved, then check default settings + if ( filters.join( '' ) === '' ) { + // allow adding default setting to external filters + $filters = c.$headers.add( wo.filter_$externalFilters ) + .filter( '[' + wo.filter_defaultAttrib + ']' ); + for ( indx = 0; indx <= c.columns; indx++ ) { + // include data-column='all' external filters + col = indx === c.columns ? 'all' : indx; + filters[indx] = $filters + .filter( '[data-column="' + col + '"]' ) + .attr( wo.filter_defaultAttrib ) || filters[indx] || ''; + } + } + c.$table.data( 'lastSearch', filters ); + return filters; + }, + parseFilter: function( c, filter, column, parsed ) { + return parsed ? c.parsers[column].format( filter, c.table, [], column ) : filter; + }, + buildRow: function( table, c, wo ) { + var col, column, $header, buildSelect, disabled, name, ffxn, tmp, + // c.columns defined in computeThIndexes() + cellFilter = wo.filter_cellFilter, + columns = c.columns, + arry = $.isArray( cellFilter ), + buildFilter = ''; + for ( column = 0; column < columns; column++ ) { + buildFilter += '' ).appendTo( c.$filters.eq( column ) ); + } else { + ffxn = ts.getColumnData( table, wo.filter_formatter, column ); + if ( ffxn ) { + wo.filter_formatterCount++; + buildFilter = ffxn( c.$filters.eq( column ), column ); + // no element returned, so lets go find it + if ( buildFilter && buildFilter.length === 0 ) { + buildFilter = c.$filters.eq( column ).children( 'input' ); + } + // element not in DOM, so lets attach it + if ( buildFilter && ( buildFilter.parent().length === 0 || + ( buildFilter.parent().length && buildFilter.parent()[0] !== c.$filters[column] ) ) ) { + c.$filters.eq( column ).append( buildFilter ); + } + } else { + buildFilter = $( '' ).appendTo( c.$filters.eq( column ) ); + } + if ( buildFilter ) { + tmp = $header.data( 'placeholder' ) || + $header.attr( 'data-placeholder' ) || + wo.filter_placeholder.search || ''; + buildFilter.attr( 'placeholder', tmp ); + } + } + if ( buildFilter ) { + // add filter class name + name = ( $.isArray( wo.filter_cssFilter ) ? + ( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) : + wo.filter_cssFilter ) || ''; + buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', column ); + if ( disabled ) { + buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true; + } + } + } + }, + bindSearch: function( table, $el, internal ) { + table = $( table )[0]; + $el = $( $el ); // allow passing a selector string + if ( !$el.length ) { return; } + var tmp, + c = table.config, + wo = c.widgetOptions, + namespace = c.namespace + 'filter', + $ext = wo.filter_$externalFilters; + if ( internal !== true ) { + // save anyMatch element + tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector; + wo.filter_$anyMatch = $el.filter( tmp ); + if ( $ext && $ext.length ) { + wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el ); + } else { + wo.filter_$externalFilters = $el; + } + // update values ( external filters added after table initialization ) + ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false ); + } + // unbind events + tmp = ( 'keypress keyup search change '.split( ' ' ).join( namespace + ' ' ) ); + $el + // use data attribute instead of jQuery data since the head is cloned without including + // the data/binding + .attr( 'data-lastSearchTime', new Date().getTime() ) + .unbind( tmp.replace( /\s+/g, ' ' ) ) + // include change for select - fixes #473 + .bind( 'keyup' + namespace, function( event ) { + $( this ).attr( 'data-lastSearchTime', new Date().getTime() ); + // emulate what webkit does.... escape clears the filter + if ( event.which === 27 ) { + this.value = ''; + // live search + } else if ( wo.filter_liveSearch === false ) { + return; + // don't return if the search value is empty ( all rows need to be revealed ) + } else if ( this.value !== '' && ( + // liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace + ( typeof wo.filter_liveSearch === 'number' && this.value.length < wo.filter_liveSearch ) || + // let return & backspace continue on, but ignore arrows & non-valid characters + ( event.which !== 13 && event.which !== 8 && + ( event.which < 32 || ( event.which >= 37 && event.which <= 40 ) ) ) ) ) { + return; + } + // change event = no delay; last true flag tells getFilters to skip newest timed input + ts.filter.searching( table, true, true ); + }) + .bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) { + var column = $( this ).data( 'column' ); + // don't allow 'change' event to process if the input value is the same - fixes #685 + if ( event.which === 13 || event.type === 'search' || + event.type === 'change' && this.value !== c.lastSearch[column] ) { + event.preventDefault(); + // init search with no delay + $( this ).attr( 'data-lastSearchTime', new Date().getTime() ); + ts.filter.searching( table, false, true ); + } + }); + }, + searching: function( table, filter, skipFirst ) { + var wo = table.config.widgetOptions; + clearTimeout( wo.searchTimer ); + if ( typeof filter === 'undefined' || filter === true ) { + // delay filtering + wo.searchTimer = setTimeout( function() { + ts.filter.checkFilters( table, filter, skipFirst ); + }, wo.filter_liveSearch ? wo.filter_searchDelay : 10 ); + } else { + // skip delay + ts.filter.checkFilters( table, filter, skipFirst ); + } + }, + checkFilters: function( table, filter, skipFirst ) { + var c = table.config, + wo = c.widgetOptions, + filterArray = $.isArray( filter ), + filters = ( filterArray ) ? filter : ts.getFilters( table, true ), + combinedFilters = ( filters || [] ).join( '' ); // combined filter values + // prevent errors if delay init is set + if ( $.isEmptyObject( c.cache ) ) { + // update cache if delayInit set & pager has initialized ( after user initiates a search ) + if ( c.delayInit && c.pager && c.pager.initialized ) { + c.$table.trigger( 'updateCache', [ function() { + ts.filter.checkFilters( table, false, skipFirst ); + } ] ); + } + return; + } + // add filter array back into inputs + if ( filterArray ) { + ts.setFilters( table, filters, false, skipFirst !== true ); + if ( !wo.filter_initialized ) { c.lastCombinedFilter = ''; } + } + if ( wo.filter_hideFilters ) { + // show/hide filter row as needed + c.$table + .find( '.' + tscss.filterRow ) + .trigger( combinedFilters === '' ? 'mouseleave' : 'mouseenter' ); + } + // return if the last search is the same; but filter === false when updating the search + // see example-widget-filter.html filter toggle buttons + if ( c.lastCombinedFilter === combinedFilters && filter !== false ) { + return; + } else if ( filter === false ) { + // force filter refresh + c.lastCombinedFilter = null; + c.lastSearch = []; + } + if ( wo.filter_initialized ) { + c.$table.trigger( 'filterStart', [filters] ); + } + if ( c.showProcessing ) { + // give it time for the processing icon to kick in + setTimeout( function() { + ts.filter.findRows( table, filters, combinedFilters ); + return false; + }, 30 ); + } else { + ts.filter.findRows( table, filters, combinedFilters ); + return false; + } + }, + hideFilters: function( table, c ) { + var $filterRow, $filterRow2, timer; + $( table ) + .find( '.' + tscss.filterRow ) + .addClass( tscss.filterRowHide ) + .bind( 'mouseenter mouseleave', function( e ) { + // save event object - http://bugs.jquery.com/ticket/12140 + var event = e; + $filterRow = $( this ); + clearTimeout( timer ); + timer = setTimeout( function() { + if ( /enter|over/.test( event.type ) ) { + $filterRow.removeClass( tscss.filterRowHide ); + } else { + // don't hide if input has focus + // $( ':focus' ) needs jQuery 1.6+ + if ( $( document.activeElement ).closest( 'tr' )[0] !== $filterRow[0] ) { + // don't hide row if any filter has a value + if ( c.lastCombinedFilter === '' ) { + $filterRow.addClass( tscss.filterRowHide ); + } + } + } + }, 200 ); + }) + .find( 'input, select' ).bind( 'focus blur', function( e ) { + $filterRow2 = $( this ).closest( 'tr' ); + clearTimeout( timer ); + var event = e; + timer = setTimeout( function() { + // don't hide row if any filter has a value + if ( ts.getFilters( c.$table ).join( '' ) === '' ) { + $filterRow2.toggleClass( tscss.filterRowHide, event.type === 'focus' ); + } + }, 200 ); + }); + }, + defaultFilter: function( filter, mask ) { + if ( filter === '' ) { return filter; } + var regex = ts.filter.regex.iQuery, + maskLen = mask.match( ts.filter.regex.igQuery ).length, + query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ], + len = query.length - 1, + indx = 0, + val = mask; + if ( len < 1 && maskLen > 1 ) { + // only one 'word' in query but mask has >1 slots + query[1] = query[0]; + } + // replace all {query} with query words... + // if query = 'Bob', then convert mask from '!{query}' to '!Bob' + // if query = 'Bob Joe Frank', then convert mask '{q} OR {q}' to 'Bob OR Joe OR Frank' + while ( regex.test( val ) ) { + val = val.replace( regex, query[indx++] || '' ); + if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) { + val = mask.replace( regex, val ); + } + } + return val; + }, + getLatestSearch: function( $input ) { + if ( $input ) { + return $input.sort( function( a, b ) { + return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' ); + }); + } + return $input || $(); + }, + multipleColumns: function( c, $input ) { + // look for multiple columns '1-3,4-6,8' in data-column + var temp, ranges, range, start, end, singles, i, indx, len, + wo = c.widgetOptions, + // only target 'all' column inputs on initialization + // & don't target 'all' column inputs if they don't exist + targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length, + columns = [], + val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' ); + // process column range + if ( targets && /-/.test( val ) ) { + ranges = val.match( /(\d+)\s*-\s*(\d+)/g ); + len = ranges.length; + for ( indx = 0; indx < len; indx++ ) { + range = ranges[indx].split( /\s*-\s*/ ); + start = parseInt( range[0], 10 ) || 0; + end = parseInt( range[1], 10 ) || ( c.columns - 1 ); + if ( start > end ) { + temp = start; start = end; end = temp; // swap + } + if ( end >= c.columns ) { + end = c.columns - 1; + } + for ( ; start <= end; start++ ) { + columns.push( start ); + } + // remove processed range from val + val = val.replace( ranges[ indx ], '' ); + } + } + // process single columns + if ( targets && /,/.test( val ) ) { + singles = val.split( /\s*,\s*/ ); + len = singles.length; + for ( i = 0; i < len; i++ ) { + if ( singles[ i ] !== '' ) { + indx = parseInt( singles[ i ], 10 ); + if ( indx < c.columns ) { + columns.push( indx ); + } + } + } + } + // return all columns + if ( !columns.length ) { + for ( indx = 0; indx < c.columns; indx++ ) { + columns.push( indx ); + } + } + return columns; + }, + processRow: function( c, data, vars ) { + var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, + fxn, ffxn, txt, + regex = ts.filter.regex, + wo = c.widgetOptions, + showRow = true; + data.$cells = data.$row.children(); + + if ( data.anyMatchFlag ) { + // look for multiple columns '1-3,4-6,8' + columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch ); + data.anyMatch = true; + data.rowArray = data.$cells.map( function( i ) { + if ( $.inArray( i, columnIndex ) > -1 ) { + if ( data.parsed[ i ] ) { + txt = data.cacheArray[ i ]; + } else { + txt = data.rawArray[ i ]; + txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt ); + if ( c.sortLocaleCompare ) { + txt = ts.replaceAccents( txt ); + } + } + return txt; + } + }).get(); + data.filter = data.anyMatchFilter; + data.iFilter = data.iAnyMatchFilter; + data.exact = data.rowArray.join( ' ' ); + data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact; + data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' ); + filterMatched = null; + matches = null; + for ( ffxn in ts.filter.types ) { + if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) { + matches = ts.filter.types[ffxn]( c, data ); + if ( matches !== null ) { + filterMatched = matches; + } + } + } + if ( filterMatched !== null ) { + showRow = filterMatched; + } else { + if ( wo.filter_startsWith ) { + showRow = false; + columnIndex = c.columns; + while ( !showRow && columnIndex > 0 ) { + columnIndex--; + showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0; + } + } else { + showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0; + } + } + data.anyMatch = false; + // no other filters to process + if ( data.filters.join( '' ) === data.filter ) { + return showRow; + } + } + + for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) { + data.filter = data.filters[ columnIndex ]; + data.index = columnIndex; + + // filter types to exclude, per column + excludeMatch = vars.excludeFilter[ columnIndex ]; + + // ignore if filter is empty or disabled + if ( data.filter ) { + data.cache = data.cacheArray[ columnIndex ]; + // check if column data should be from the cell or from parsed data + if ( wo.filter_useParsedData || data.parsed[ columnIndex ] ) { + data.exact = data.cache; + } else { + result = data.rawArray[ columnIndex ] || ''; + data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405 + } + data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ? + data.exact.toLowerCase() : data.exact; + result = showRow; // if showRow is true, show that row + + // in case select filter option has a different value vs text 'a - z|A through Z' + ffxn = wo.filter_columnFilters ? + c.$filters.add( c.$externalFilters ) + .filter( '[data-column="'+ columnIndex + '"]' ) + .find( 'select option:selected' ) + .attr( 'data-function-name' ) || '' : ''; + // replace accents - see #357 + if ( c.sortLocaleCompare ) { + data.filter = ts.replaceAccents( data.filter ); + } + + val = true; + if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) { + data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] ); + // val is used to indicate that a filter select is using a default filter; + // so we override the exact & partial matches + val = false; + } + // data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ), + // data.filter = case sensitive + data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter; + fxn = vars.functions[ columnIndex ]; + $cell = c.$headerIndexed[ columnIndex ]; + hasSelect = $cell.hasClass( 'filter-select' ); + filterMatched = null; + if ( fxn || ( hasSelect && val ) ) { + if ( fxn === true || hasSelect ) { + // default selector uses exact match unless 'filter-match' class is found + filterMatched = $cell.hasClass( 'filter-match' ) ? + data.iExact.search( data.iFilter ) >= 0 : + data.filter === data.exact; + } else if ( typeof fxn === 'function' ) { + // filter callback( exact cell content, parser normalized content, + // filter input value, column index, jQuery row object ) + filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data ); + } else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) { + // selector option function + txt = ffxn || data.filter; + filterMatched = + fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data ); + } + } + if ( filterMatched === null ) { + // cycle through the different filters + // filters return a boolean or null if nothing matches + matches = null; + for ( ffxn in ts.filter.types ) { + if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) { + matches = ts.filter.types[ ffxn ]( c, data ); + if ( matches !== null ) { + filterMatched = matches; + } + } + } + if ( filterMatched !== null ) { + result = filterMatched; + // Look for match, and add child row data for matching + } else { + txt = ( data.iExact + data.childRowText ) + .indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) ); + result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) ); + } + } else { + result = filterMatched; + } + showRow = ( result ) ? showRow : false; + } + } + return showRow; + }, + findRows: function( table, filters, combinedFilters ) { + if ( table.config.lastCombinedFilter === combinedFilters || + !table.config.widgetOptions.filter_initialized ) { + return; + } + var len, norm_rows, rowData, $rows, rowIndex, tbodyIndex, $tbody, columnIndex, + isChild, childRow, lastSearch, showRow, time, val, indx, + notFiltered, searchFiltered, query, injected, res, id, txt, + storedFilters = $.extend( [], filters ), + regex = ts.filter.regex, + c = table.config, + wo = c.widgetOptions, + // data object passed to filters; anyMatch is a flag for the filters + data = { + anyMatch: false, + filters: filters, + // regex filter type cache + filter_regexCache : [], + }, + vars = { + // anyMatch really screws up with these types of filters + noAnyMatch: [ 'range', 'notMatch', 'operators' ], + // cache filter variables that use ts.getColumnData in the main loop + functions : [], + excludeFilter : [], + defaultColFilter : [], + defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || '' + }; + + // parse columns after formatter, in case the class is added at that point + data.parsed = c.$headers.map( function( columnIndex ) { + return c.parsers && c.parsers[ columnIndex ] && + // force parsing if parser type is numeric + c.parsers[ columnIndex ].parsed || + // getData won't return 'parsed' if other 'filter-' class names exist + // ( e.g. ) + ts.getData && ts.getData( c.$headerIndexed[ columnIndex ], + ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' || + $( this ).hasClass( 'filter-parsed' ); + }).get(); + + for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) { + vars.functions[ columnIndex ] = + ts.getColumnData( table, wo.filter_functions, columnIndex ); + vars.defaultColFilter[ columnIndex ] = + ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || ''; + vars.excludeFilter[ columnIndex ] = + ( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ ); + } + + if ( c.debug ) { + ts.log( 'Filter: Starting filter widget search', filters ); + time = new Date(); + } + // filtered rows count + c.filteredRows = 0; + c.totalRows = 0; + // combindedFilters are undefined on init + combinedFilters = ( storedFilters || [] ).join( '' ); + + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true ); + // skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel! + // $rows = $tbody.children( 'tr' ).not( c.selectorRemove ); + columnIndex = c.columns; + // convert stored rows into a jQuery object + norm_rows = c.cache[ tbodyIndex ].normalized; + $rows = $( $.map( norm_rows, function( el ) { + return el[ columnIndex ].$row.get(); + }) ); + + if ( combinedFilters === '' || wo.filter_serversideFiltering ) { + $rows + .removeClass( wo.filter_filteredRow ) + .not( '.' + c.cssChildRow ) + .css( 'display', '' ); + } else { + // filter out child rows + $rows = $rows.not( '.' + c.cssChildRow ); + len = $rows.length; + + if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) || + typeof filters[c.columns] !== 'undefined' ) { + data.anyMatchFlag = true; + data.anyMatchFilter = '' + ( + filters[ c.columns ] || + wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() || + '' + ); + if ( wo.filter_columnAnyMatch ) { + // specific columns search + query = data.anyMatchFilter.split( regex.andSplit ); + injected = false; + for ( indx = 0; indx < query.length; indx++ ) { + res = query[ indx ].split( ':' ); + if ( res.length > 1 ) { + // make the column a one-based index ( non-developers start counting from one :P ) + id = parseInt( res[0], 10 ) - 1; + if ( id >= 0 && id < c.columns ) { // if id is an integer + filters[ id ] = res[1]; + query.splice( indx, 1 ); + indx--; + injected = true; + } + } + } + if ( injected ) { + data.anyMatchFilter = query.join( ' && ' ); + } + } + } + + // optimize searching only through already filtered rows - see #313 + searchFiltered = wo.filter_searchFiltered; + lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || []; + if ( searchFiltered ) { + // cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669 + for ( indx = 0; indx < columnIndex + 1; indx++ ) { + val = filters[indx] || ''; + // break out of loop if we've already determined not to search filtered rows + if ( !searchFiltered ) { indx = columnIndex; } + // search already filtered rows if... + searchFiltered = searchFiltered && lastSearch.length && + // there are no changes from beginning of filter + val.indexOf( lastSearch[indx] || '' ) === 0 && + // if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string + !regex.alreadyFiltered.test( val ) && + // if we are not doing exact matches, using '|' ( logical or ) or not '!' + !/[=\"\|!]/.test( val ) && + // don't search only filtered if the value is negative + // ( '> -10' => '> -100' will ignore hidden rows ) + !( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) && + // if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593 + !( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length && + !c.$headerIndexed[indx].hasClass( 'filter-match' ) ); + } + } + notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length; + // can't search when all rows are hidden - this happens when looking for exact matches + if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; } + if ( c.debug ) { + ts.log( 'Filter: Searching through ' + + ( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' ); + } + if ( data.anyMatchFlag ) { + if ( c.sortLocaleCompare ) { + // replace accents + data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter ); + } + if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) { + data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter ); + // clear search filtered flag because default filters are not saved to the last search + searchFiltered = false; + } + // make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true + // when c.ignoreCase is true, the cache contains all lower case data + data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ? + data.anyMatchFilter : + data.anyMatchFilter.toLowerCase(); + } + + // loop through the rows + for ( rowIndex = 0; rowIndex < len; rowIndex++ ) { + + txt = $rows[ rowIndex ].className; + // the first row can never be a child row + isChild = rowIndex && regex.child.test( txt ); + // skip child rows & already filtered rows + if ( isChild || ( searchFiltered && regex.filtered.test( txt ) ) ) { + continue; + } + + data.$row = $rows.eq( rowIndex ); + data.cacheArray = norm_rows[ rowIndex ]; + rowData = data.cacheArray[ c.columns ]; + data.rawArray = rowData.raw; + data.childRowText = ''; + + if ( !wo.filter_childByColumn ) { + txt = ''; + // child row cached text + childRow = rowData.child; + // so, if 'table.config.widgetOptions.filter_childRows' is true and there is + // a match anywhere in the child row, then it will make the row visible + // checked here so the option can be changed dynamically + for ( indx = 0; indx < childRow.length; indx++ ) { + txt += ' ' + childRow[indx].join( '' ) || ''; + } + data.childRowText = wo.filter_childRows ? + ( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) : + ''; + } + + showRow = ts.filter.processRow( c, data, vars ); + childRow = rowData.$row.filter( ':gt( 0 )' ); + + if ( wo.filter_childRows && childRow.length ) { + if ( wo.filter_childByColumn ) { + // cycle through each child row + for ( indx = 0; indx < childRow.length; indx++ ) { + data.$row = childRow.eq( indx ); + data.cacheArray = rowData.child[ indx ]; + data.rawArray = data.cacheArray; + // use OR comparison on child rows + showRow = showRow || ts.filter.processRow( c, data, vars ); + } + } + childRow.toggleClass( wo.filter_filteredRow, !showRow ); + } + + rowData.$row + .toggleClass( wo.filter_filteredRow, !showRow )[0] + .display = showRow ? '' : 'none'; + } + } + c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length; + c.totalRows += $rows.length; + ts.processTbody( table, $tbody, false ); + } + c.lastCombinedFilter = combinedFilters; // save last search + // don't save 'filters' directly since it may have altered ( AnyMatch column searches ) + c.lastSearch = storedFilters; + c.$table.data( 'lastSearch', storedFilters ); + if ( wo.filter_saveFilters && ts.storage ) { + ts.storage( table, 'tablesorter-filters', storedFilters ); + } + if ( c.debug ) { + ts.benchmark( 'Completed filter widget search', time ); + } + if ( wo.filter_initialized ) { + c.$table.trigger( 'filterEnd', c ); + } + setTimeout( function() { + c.$table.trigger( 'applyWidgets' ); // make sure zebra widget is applied + }, 0 ); + }, + getOptionSource: function( table, column, onlyAvail ) { + table = $( table )[0]; + var cts, txt, indx, len, + c = table.config, + wo = c.widgetOptions, + parsed = [], + arry = false, + source = wo.filter_selectSource, + last = c.$table.data( 'lastSearch' ) || [], + fxn = $.isFunction( source ) ? true : ts.getColumnData( table, source, column ); + + if ( onlyAvail && last[column] !== '' ) { + onlyAvail = false; + } + + // filter select source option + if ( fxn === true ) { + // OVERALL source + arry = source( table, column, onlyAvail ); + } else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '' ) >= 0 ) ) { + // selectSource is a jQuery object or string of options + return fxn; + } else if ( $.isArray( fxn ) ) { + arry = fxn; + } else if ( $.type( source ) === 'object' && fxn ) { + // custom select source function for a SPECIFIC COLUMN + arry = fxn( table, column, onlyAvail ); + } + if ( arry === false ) { + // fall back to original method + arry = ts.filter.getOptions( table, column, onlyAvail ); + } + + // get unique elements and sort the list + // if $.tablesorter.sortText exists ( not in the original tablesorter ), + // then natural sort the list otherwise use a basic sort + arry = $.grep( arry, function( value, indx ) { + return $.inArray( value, arry ) === indx; + }); + + if ( c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) { + // unsorted select options + return arry; + } else { + len = arry.length; + // parse select option values + for ( indx = 0; indx < len; indx++ ) { + txt = arry[ indx ]; + // parse array data using set column parser; this DOES NOT pass the original + // table cell to the parser format function + parsed.push({ + t : txt, + // check parser length - fixes #934 + p : c.parsers && c.parsers.length && c.parsers[ column ].format( txt, table, [], column ) || txt + }); + } + + // sort parsed select options + cts = c.textSorter || ''; + parsed.sort( function( a, b ) { + // sortNatural breaks if you don't pass it strings + var x = a.p.toString(), + y = b.p.toString(); + if ( $.isFunction( cts ) ) { + // custom OVERALL text sorter + return cts( x, y, true, column, table ); + } else if ( typeof( cts ) === 'object' && cts.hasOwnProperty( column ) ) { + // custom text sorter for a SPECIFIC COLUMN + return cts[column]( x, y, true, column, table ); + } else if ( ts.sortNatural ) { + // fall back to natural sort + return ts.sortNatural( x, y ); + } + // using an older version! do a basic sort + return true; + }); + // rebuild arry from sorted parsed data + arry = []; + len = parsed.length; + for ( indx = 0; indx < len; indx++ ) { + arry.push( parsed[indx].t ); + } + return arry; + } + }, + getOptions: function( table, column, onlyAvail ) { + table = $( table )[0]; + var rowIndex, tbodyIndex, len, row, cache, + c = table.config, + wo = c.widgetOptions, + arry = []; + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) { + cache = c.cache[tbodyIndex]; + len = c.cache[tbodyIndex].normalized.length; + // loop through the rows + for ( rowIndex = 0; rowIndex < len; rowIndex++ ) { + // get cached row from cache.row ( old ) or row data object + // ( new; last item in normalized array ) + row = cache.row ? + cache.row[ rowIndex ] : + cache.normalized[ rowIndex ][ c.columns ].$row[0]; + // check if has class filtered + if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) { + continue; + } + // get non-normalized cell content + if ( wo.filter_useParsedData || + c.parsers[column].parsed || + c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) { + arry.push( '' + cache.normalized[ rowIndex ][ column ] ); + } else { + // get raw cached data instead of content directly from the cells + arry.push( cache.normalized[ rowIndex ][ c.columns ].raw[ column ] ); + } + } + } + return arry; + }, + buildSelect: function( table, column, arry, updating, onlyAvail ) { + table = $( table )[0]; + column = parseInt( column, 10 ); + if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) { + return; + } + var indx, val, txt, t, $filters, $filter, + c = table.config, + wo = c.widgetOptions, + node = c.$headerIndexed[ column ], + // t.data( 'placeholder' ) won't work in jQuery older than 1.4.3 + options = '', + // Get curent filter value + currentValue = c.$table + .find( 'thead' ) + .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' ) + .val(); + // nothing included in arry ( external source ), so get the options from + // filter_selectSource or column data + if ( typeof arry === 'undefined' || arry === '' ) { + arry = ts.filter.getOptionSource( table, column, onlyAvail ); + } + + if ( $.isArray( arry ) ) { + // build option list + for ( indx = 0; indx < arry.length; indx++ ) { + txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '"' ); + val = txt; + // allow including a symbol in the selectSource array + // 'a-z|A through Z' so that 'a-z' becomes the option value + // and 'A through Z' becomes the option text + if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) { + t = txt.split( wo.filter_selectSourceSeparator ); + val = t[0]; + txt = t[1]; + } + // replace quotes - fixes #242 & ignore empty strings + // see http://stackoverflow.com/q/14990971/145346 + options += arry[indx] !== '' ? + '' : ''; + } + // clear arry so it doesn't get appended twice + arry = []; + } + + // update all selects in the same column ( clone thead in sticky headers & + // any external selects ) - fixes 473 + $filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) ) + .find( '.' + tscss.filter ); + if ( wo.filter_$externalFilters ) { + $filters = $filters && $filters.length ? + $filters.add( wo.filter_$externalFilters ) : + wo.filter_$externalFilters; + } + $filter = $filters.filter( 'select[data-column="' + column + '"]' ); + + // make sure there is a select there! + if ( $filter.length ) { + $filter[ updating ? 'html' : 'append' ]( options ); + if ( !$.isArray( arry ) ) { + // append options if arry is provided externally as a string or jQuery object + // options ( default value ) was already added + $filter.append( arry ).val( currentValue ); + } + $filter.val( currentValue ); + } + }, + buildDefault: function( table, updating ) { + var columnIndex, $header, noSelect, + c = table.config, + wo = c.widgetOptions, + columns = c.columns; + // build default select dropdown + for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) { + $header = c.$headerIndexed[columnIndex]; + noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) ); + // look for the filter-select class; build/update it if found + if ( ( $header.hasClass( 'filter-select' ) || + ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) { + ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) ); + } + } + } +}; + +ts.getFilters = function( table, getRaw, setFilters, skipFirst ) { + var i, $filters, $column, cols, + filters = false, + c = table ? $( table )[0].config : '', + wo = c ? c.widgetOptions : ''; + if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) || + // setFilters called, but last search is exactly the same as the current + // fixes issue #733 & #903 where calling update causes the input values to reset + ( $.isArray(setFilters) && setFilters.join('') === c.lastCombinedFilter ) ) { + return $( table ).data( 'lastSearch' ); + } + if ( c ) { + if ( c.$filters ) { + $filters = c.$filters.find( '.' + tscss.filter ); + } + if ( wo.filter_$externalFilters ) { + $filters = $filters && $filters.length ? + $filters.add( wo.filter_$externalFilters ) : + wo.filter_$externalFilters; + } + if ( $filters && $filters.length ) { + filters = setFilters || []; + for ( i = 0; i < c.columns + 1; i++ ) { + cols = ( i === c.columns ? + // 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' ) + wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector : + '[data-column="' + i + '"]' ); + $column = $filters.filter( cols ); + if ( $column.length ) { + // move the latest search to the first slot in the array + $column = ts.filter.getLatestSearch( $column ); + if ( $.isArray( setFilters ) ) { + // skip first ( latest input ) to maintain cursor position while typing + if ( skipFirst && $column.length > 1 ) { + $column = $column.slice( 1 ); + } + if ( i === c.columns ) { + // prevent data-column='all' from filling data-column='0,1' ( etc ) + cols = $column.filter( wo.filter_anyColumnSelector ); + $column = cols.length ? cols : $column; + } + $column + .val( setFilters[ i ] ) + .trigger( 'change.tsfilter' ); + } else { + filters[i] = $column.val() || ''; + // don't change the first... it will move the cursor + if ( i === c.columns ) { + // don't update range columns from 'all' setting + $column + .slice( 1 ) + .filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' ) + .val( filters[ i ] ); + } else { + $column + .slice( 1 ) + .val( filters[ i ] ); + } + } + // save any match input dynamically + if ( i === c.columns && $column.length ) { + wo.filter_$anyMatch = $column; + } + } + } + } + } + if ( filters.length === 0 ) { + filters = false; + } + return filters; +}; + +ts.setFilters = function( table, filter, apply, skipFirst ) { + var c = table ? $( table )[0].config : '', + valid = ts.getFilters( table, true, filter, skipFirst ); + if ( c && apply ) { + // ensure new set filters are applied, even if the search is the same + c.lastCombinedFilter = null; + c.lastSearch = []; + ts.filter.searching( c.table, filter, skipFirst ); + c.$table.trigger( 'filterFomatterUpdate' ); + } + return !!valid; +}; + +})( jQuery ); + +/*! Widget: stickyHeaders - updated 3/26/2015 (v2.21.3) *//* + * Requires tablesorter v2.8+ and jQuery 1.4.3+ + * by Rob Garrison + */ +;(function ($, window) { +'use strict'; +var ts = $.tablesorter || {}; + +$.extend(ts.css, { + sticky : 'tablesorter-stickyHeader', // stickyHeader + stickyVis : 'tablesorter-sticky-visible', + stickyHide: 'tablesorter-sticky-hidden', + stickyWrap: 'tablesorter-sticky-wrapper' +}); + +// Add a resize event to table headers +ts.addHeaderResizeEvent = function(table, disable, settings) { + table = $(table)[0]; // make sure we're using a dom element + if ( !table.config ) { return; } + var defaults = { + timer : 250 + }, + options = $.extend({}, defaults, settings), + c = table.config, + wo = c.widgetOptions, + checkSizes = function( triggerEvent ) { + var index, headers, $header, sizes, width, height, + len = c.$headers.length; + wo.resize_flag = true; + headers = []; + for ( index = 0; index < len; index++ ) { + $header = c.$headers.eq( index ); + sizes = $header.data( 'savedSizes' ) || [ 0,0 ]; // fixes #394 + width = $header[0].offsetWidth; + height = $header[0].offsetHeight; + if ( width !== sizes[0] || height !== sizes[1] ) { + $header.data( 'savedSizes', [ width, height ] ); + headers.push( $header[0] ); + } + } + if ( headers.length && triggerEvent !== false ) { + c.$table.trigger( 'resize', [ headers ] ); + } + wo.resize_flag = false; + }; + checkSizes( false ); + clearInterval(wo.resize_timer); + if (disable) { + wo.resize_flag = false; + return false; + } + wo.resize_timer = setInterval(function() { + if (wo.resize_flag) { return; } + checkSizes(); + }, options.timer); +}; + +// Sticky headers based on this awesome article: +// http://css-tricks.com/13465-persistent-headers/ +// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech +// ************************** +ts.addWidget({ + id: "stickyHeaders", + priority: 60, // sticky widget must be initialized after the filter widget! + options: { + stickyHeaders : '', // extra class name added to the sticky header row + stickyHeaders_attachTo : null, // jQuery selector or object to attach sticky header to + stickyHeaders_xScroll : null, // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window) + stickyHeaders_yScroll : null, // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window) + stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element + stickyHeaders_filteredToTop: true, // scroll table top into view after filtering + stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists + stickyHeaders_addResizeEvent : true, // trigger "resize" event on headers + stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header + stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs + }, + format: function(table, c, wo) { + // filter widget doesn't initialize on an empty table. Fixes #449 + if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) { + return; + } + var index, len, $t, + $table = c.$table, + // add position: relative to attach element, hopefully it won't cause trouble. + $attach = $(wo.stickyHeaders_attachTo), + namespace = c.namespace + 'stickyheaders ', + // element to watch for the scroll event + $yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window), + $xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window), + $thead = $table.children('thead:first'), + $header = $thead.children('tr').not('.sticky-false').children(), + $tfoot = $table.children('tfoot'), + $stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '', + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0, + // is this table nested? If so, find parent sticky header wrapper (div, not table) + $nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ? + $table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [], + nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0, + // clone table, then wrap to make sticky header + $stickyTable = wo.$sticky = $table.clone() + .addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders + ' ' + c.namespace.slice(1) + '_extra_table' ) + .wrap('
    '), + $stickyWrap = $stickyTable.parent() + .addClass(ts.css.stickyHide) + .css({ + position : $attach.length ? 'absolute' : 'fixed', + padding : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ), + top : stickyOffset + nestedStickyTop, + left : 0, + visibility : 'hidden', + zIndex : wo.stickyHeaders_zIndex || 2 + }), + $stickyThead = $stickyTable.children('thead:first'), + $stickyCells, + laststate = '', + spacing = 0, + setWidth = function($orig, $clone){ + var index, width, border, $cell, $this, + $cells = $orig.filter(':visible'), + len = $cells.length; + for ( index = 0; index < len; index++ ) { + $cell = $clone.filter(':visible').eq(index); + $this = $cells.eq(index); + // code from https://github.com/jmosbech/StickyTableHeaders + if ($this.css('box-sizing') === 'border-box') { + width = $this.outerWidth(); + } else { + if ($cell.css('border-collapse') === 'collapse') { + if (window.getComputedStyle) { + width = parseFloat( window.getComputedStyle($this[0], null).width ); + } else { + // ie8 only + border = parseFloat( $this.css('border-width') ); + width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border; + } + } else { + width = $this.width(); + } + } + $cell.css({ + 'width': width, + 'min-width': width, + 'max-width': width + }); + } + }, + resizeHeader = function() { + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0; + spacing = 0; + $stickyWrap.css({ + left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 : + $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing, + width: $table.outerWidth() + }); + setWidth( $table, $stickyTable ); + setWidth( $header, $stickyCells ); + }, + scrollSticky = function( resizing ) { + if (!$table.is(':visible')) { return; } // fixes #278 + // Detect nested tables - fixes #724 + nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0; + var offset = $table.offset(), + yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3 + xWindow = $.isWindow( $xScroll[0] ), + // scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop, + scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop, + tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)), + isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden', + cssSettings = { visibility : isVisible }; + + if ($attach.length) { + cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop(); + } + if (xWindow) { + // adjust when scrolling horizontally - fixes issue #143 + cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing; + } + if ($nestedSticky.length) { + cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop; + } + $stickyWrap + .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide ) + .addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide ) + .css(cssSettings); + if (isVisible !== laststate || resizing) { + // make sure the column widths match + resizeHeader(); + laststate = isVisible; + } + }; + // only add a position relative if a position isn't already defined + if ($attach.length && !$attach.css('position')) { + $attach.css('position', 'relative'); + } + // fix clone ID, if it exists - fixes #271 + if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; } + // clear out cloned table, except for sticky header + // include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing + $stickyTable.find('thead:gt(0), tr.sticky-false').hide(); + $stickyTable.find('tbody, tfoot').remove(); + $stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption); + // issue #172 - find td/th in sticky header + $stickyCells = $stickyThead.children().children(); + $stickyTable.css({ height:0, width:0, margin: 0 }); + // remove resizable block + $stickyCells.find('.' + ts.css.resizer).remove(); + // update sticky header class names to match real header after sorting + $table + .addClass('hasStickyHeaders') + .bind('pagerComplete' + namespace, function() { + resizeHeader(); + }); + + ts.bindEvents(table, $stickyThead.children().children('.' + ts.css.header)); + + // add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned. + $table.after( $stickyWrap ); + + // onRenderHeader is defined, we need to do something about it (fixes #641) + if (c.onRenderHeader) { + $t = $stickyThead.children('tr').children(); + len = $t.length; + for ( index = 0; index < len; index++ ) { + // send second parameter + c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] ); + } + } + + // make it sticky! + $xScroll.add($yScroll) + .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') ) + .bind('scroll resize '.split(' ').join( namespace ), function( event ) { + scrollSticky( event.type === 'resize' ); + }); + c.$table + .unbind('stickyHeadersUpdate' + namespace) + .bind('stickyHeadersUpdate' + namespace, function(){ + scrollSticky( true ); + }); + + if (wo.stickyHeaders_addResizeEvent) { + ts.addHeaderResizeEvent(table); + } + + // look for filter widget + if ($table.hasClass('hasFilters') && wo.filter_columnFilters) { + // scroll table into view after filtering, if sticky header is active - #482 + $table.bind('filterEnd' + namespace, function() { + // $(':focus') needs jQuery 1.6+ + var $td = $(document.activeElement).closest('td'), + column = $td.parent().children().index($td); + // only scroll if sticky header is active + if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) { + // scroll to original table (not sticky clone) + window.scrollTo(0, $table.position().top); + // give same input/select focus; check if c.$filters exists; fixes #594 + if (column >= 0 && c.$filters) { + c.$filters.eq(column).find('a, select, input').filter(':visible').focus(); + } + } + }); + ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) ); + // support hideFilters + if (wo.filter_hideFilters) { + ts.filter.hideFilters($stickyTable, c); + } + } + + $table.trigger('stickyHeadersInit'); + + }, + remove: function(table, c, wo) { + var namespace = c.namespace + 'stickyheaders '; + c.$table + .removeClass('hasStickyHeaders') + .unbind( ('pagerComplete filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') ) + .next('.' + ts.css.stickyWrap).remove(); + if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table + $(window) + .add(wo.stickyHeaders_xScroll) + .add(wo.stickyHeaders_yScroll) + .add(wo.stickyHeaders_attachTo) + .unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') ); + ts.addHeaderResizeEvent(table, false); + } +}); + +})(jQuery, window); + +/*! Widget: resizable - updated 5/17/2015 (v2.22.0) */ +;(function ($, window) { +'use strict'; +var ts = $.tablesorter || {}; + +$.extend(ts.css, { + resizableContainer : 'tablesorter-resizable-container', + resizableHandle : 'tablesorter-resizable-handle', + resizableNoSelect : 'tablesorter-disableSelection', + resizableStorage : 'tablesorter-resizable' +}); + +// Add extra scroller css +$(function(){ + var s = ''; + $(s).appendTo('body'); +}); + +ts.resizable = { + init : function( c, wo ) { + if ( c.$table.hasClass( 'hasResizable' ) ) { return; } + c.$table.addClass( 'hasResizable' ); + ts.resizableReset( c.table, true ); // set default widths + + // internal variables + wo.resizable_ = { + $wrap : c.$table.parent(), + mouseXPosition : 0, + $target : null, + $next : null, + overflow : c.$table.parent().css('overflow') === 'auto', + fullWidth : Math.abs(c.$table.parent().width() - c.$table.width()) < 20, + storedSizes : [] + }; + + var noResize, $header, column, storedSizes, + marginTop = parseInt( c.$table.css( 'margin-top' ), 10 ); + + wo.resizable_.storedSizes = storedSizes = ( ( ts.storage && wo.resizable !== false ) ? + ts.storage( c.table, ts.css.resizableStorage ) : + [] ) || []; + ts.resizable.setWidths( c, wo, storedSizes ); + + wo.$resizable_container = $( '
    ' ) + .css({ top : marginTop }) + .insertBefore( c.$table ); + // add container + for ( column = 0; column < c.columns; column++ ) { + $header = c.$headerIndexed[ column ]; + noResize = ts.getData( $header, ts.getColumnData( c.table, c.headers, column ), 'resizable' ) === 'false'; + if ( !noResize ) { + $( '
    ' ) + .appendTo( wo.$resizable_container ) + .attr({ + 'data-column' : column, + 'unselectable' : 'on' + }) + .data( 'header', $header ) + .bind( 'selectstart', false ); + } + } + c.$table.one('tablesorter-initialized', function() { + ts.resizable.setHandlePosition( c, wo ); + ts.resizable.bindings( this.config, this.config.widgetOptions ); + }); + }, + + setWidth : function( $el, width ) { + $el.css({ + 'width' : width, + 'min-width' : '', + 'max-width' : '' + }); + }, + + setWidths : function( c, wo, storedSizes ) { + var column, + $extra = $( c.namespace + '_extra_headers' ), + $col = c.$table.children( 'colgroup' ).children( 'col' ); + storedSizes = storedSizes || wo.resizable_.storedSizes || []; + // process only if table ID or url match + if ( storedSizes.length ) { + for ( column = 0; column < c.columns; column++ ) { + // set saved resizable widths + c.$headerIndexed[ column ].width( storedSizes[ column ] ); + if ( $extra.length ) { + // stickyHeaders needs to modify min & max width as well + ts.resizable.setWidth( $extra.eq( column ).add( $col.eq( column ) ), storedSizes[ column ] ); + } + } + if ( $( c.namespace + '_extra_table' ).length && !ts.hasWidget( c.table, 'scroller' ) ) { + ts.resizable.setWidth( $( c.namespace + '_extra_table' ), c.$table.outerWidth() ); + } + } + }, + + setHandlePosition : function( c, wo ) { + var startPosition, + hasScroller = ts.hasWidget( c.table, 'scroller' ), + tableHeight = c.$table.height(), + $handles = wo.$resizable_container.children(), + handleCenter = Math.floor( $handles.width() / 2 ); + + if ( hasScroller ) { + tableHeight = 0; + c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function(){ + var $this = $(this); + // center table has a max-height set + tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height(); + }); + } + // subtract out table left position from resizable handles. Fixes #864 + startPosition = c.$table.position().left; + $handles.each( function() { + var $this = $(this), + column = parseInt( $this.attr( 'data-column' ), 10 ), + columns = c.columns - 1, + $header = $this.data( 'header' ); + if ( !$header ) { return; } // see #859 + if ( !$header.is(':visible') ) { + $this.hide(); + } else if ( column < columns || column === columns && wo.resizable_addLastColumn ) { + $this.css({ + display: 'inline-block', + height : tableHeight, + left : $header.position().left - startPosition + $header.outerWidth() - handleCenter + }); + } + }); + }, + + // prevent text selection while dragging resize bar + toggleTextSelection : function( c, toggle ) { + var namespace = c.namespace + 'tsresize'; + c.widgetOptions.resizable_.disabled = toggle; + $( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle ); + if ( toggle ) { + $( 'body' ) + .attr( 'unselectable', 'on' ) + .bind( 'selectstart' + namespace, false ); + } else { + $( 'body' ) + .removeAttr( 'unselectable' ) + .unbind( 'selectstart' + namespace ); + } + }, + + bindings : function( c, wo ) { + var namespace = c.namespace + 'tsresize'; + wo.$resizable_container.children().bind( 'mousedown', function( event ) { + // save header cell and mouse position + var column, $this, + vars = wo.resizable_, + $extras = $( c.namespace + '_extra_headers' ), + $header = $( event.target ).data( 'header' ); + + column = parseInt( $header.attr( 'data-column' ), 10 ); + vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') ); + vars.target = column; + + // if table is not as wide as it's parent, then resize the table + vars.$next = event.shiftKey || wo.resizable_targetLast ? + $header.parent().children().not( '.resizable-false' ).filter( ':last' ) : + $header.nextAll( ':not(.resizable-false)' ).eq( 0 ); + + column = parseInt( vars.$next.attr( 'data-column' ), 10 ); + vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') ); + vars.next = column; + + vars.mouseXPosition = event.pageX; + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + ts.resizable.toggleTextSelection( c, true ); + }); + + $( document ) + .bind( 'mousemove' + namespace, function( event ) { + var vars = wo.resizable_; + // ignore mousemove if no mousedown + if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; } + if ( wo.resizable_throttle ) { + clearTimeout( vars.timer ); + vars.timer = setTimeout( function() { + ts.resizable.mouseMove( c, wo, event ); + }, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle ); + } else { + ts.resizable.mouseMove( c, wo, event ); + } + }) + .bind( 'mouseup' + namespace, function() { + if (!wo.resizable_.disabled) { return; } + ts.resizable.toggleTextSelection( c, false ); + ts.resizable.stopResize( c, wo ); + ts.resizable.setHandlePosition( c, wo ); + }); + + // resizeEnd event triggered by scroller widget + $( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }); + + // right click to reset columns to default widths + c.$table + .bind( 'columnUpdate' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }) + .find( 'thead:first' ) + .add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) ) + .bind( 'contextmenu' + namespace, function() { + // $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset + var allowClick = wo.resizable_.storedSizes.length === 0; + ts.resizableReset( c.table ); + ts.resizable.setHandlePosition( c, wo ); + wo.resizable_.storedSizes = []; + return allowClick; + }); + + }, + + mouseMove : function( c, wo, event ) { + if ( wo.resizable_.mouseXPosition === 0 || !wo.resizable_.$target ) { return; } + // resize columns + var vars = wo.resizable_, + $next = vars.$next, + leftEdge = event.pageX - vars.mouseXPosition; + if ( vars.fullWidth ) { + vars.storedSizes[ vars.target ] += leftEdge; + vars.storedSizes[ vars.next ] -= leftEdge; + ts.resizable.setWidths( c, wo ); + + } else if ( vars.overflow ) { + c.$table.add( $( c.namespace + '_extra_table' ) ).width(function(i, w){ + return w + leftEdge; + }); + if ( !$next.length ) { + // if expanding right-most column, scroll the wrapper + vars.$wrap[0].scrollLeft = c.$table.width(); + } + } else { + vars.storedSizes[ vars.target ] += leftEdge; + ts.resizable.setWidths( c, wo ); + } + vars.mouseXPosition = event.pageX; + // dynamically update sticky header widths + c.$table.trigger('stickyHeadersUpdate'); + }, + + stopResize : function( c, wo ) { + var $this, column, + vars = wo.resizable_; + vars.storedSizes = []; + if ( ts.storage ) { + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + if ( wo.resizable !== false ) { + // save all column widths + ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes ); + } + } + vars.mouseXPosition = 0; + vars.$target = vars.$next = null; + // will update stickyHeaders, just in case, see #912 + c.$table.trigger('stickyHeadersUpdate'); + } +}; + +// this widget saves the column widths if +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: "resizable", + priority: 40, + options: { + resizable : true, + resizable_addLastColumn : false, + resizable_widths : [], + resizable_throttle : false, // set to true (5ms) or any number 0-10 range + resizable_targetLast : false + }, + init: function(table, thisWidget, c, wo) { + ts.resizable.init( c, wo ); + }, + remove: function( table, c, wo, refreshing ) { + if (wo.$resizable_container) { + var namespace = c.namespace + 'tsresize'; + c.$table.add( $( c.namespace + '_extra_table' ) ) + .removeClass('hasResizable') + .children( 'thead' ).unbind( 'contextmenu' + namespace ); + + wo.$resizable_container.remove(); + ts.resizable.toggleTextSelection( c, false ); + ts.resizableReset( table, refreshing ); + $( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace ); + } + } +}); + +ts.resizableReset = function( table, refreshing ) { + $( table ).each(function(){ + var index, $t, + c = this.config, + wo = c && c.widgetOptions; + if ( table && c && c.$headerIndexed.length ) { + for ( index = 0; index < c.columns; index++ ) { + $t = c.$headerIndexed[ index ]; + if ( wo.resizable_widths && wo.resizable_widths[ index ] ) { + $t.css( 'width', wo.resizable_widths[ index ] ); + } else if ( !$t.hasClass( 'resizable-false' ) ) { + // don't clear the width of any column that is not resizable + $t.css( 'width', '' ); + } + } + // reset stickyHeader widths + c.$table.trigger( 'stickyHeadersUpdate' ); + if ( ts.storage && !refreshing ) { + ts.storage( this, ts.css.resizableStorage, {} ); + } + } + }); +}; + +})( jQuery, window ); + +/*! Widget: saveSort */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +// this widget saves the last sort only if the +// saveSort widget option is true AND the +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: 'saveSort', + priority: 20, + options: { + saveSort : true + }, + init: function(table, thisWidget, c, wo) { + // run widget format before all other widgets are applied to the table + thisWidget.format(table, c, wo, true); + }, + format: function(table, c, wo, init) { + var stored, time, + $table = c.$table, + saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true + sortList = { "sortList" : c.sortList }; + if (c.debug) { + time = new Date(); + } + if ($table.hasClass('hasSaveSort')) { + if (saveSort && table.hasInitialized && ts.storage) { + ts.storage( table, 'tablesorter-savesort', sortList ); + if (c.debug) { + ts.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time); + } + } + } else { + // set table sort on initial run of the widget + $table.addClass('hasSaveSort'); + sortList = ''; + // get data + if (ts.storage) { + stored = ts.storage( table, 'tablesorter-savesort' ); + sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : ''; + if (c.debug) { + ts.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time); + } + $table.bind('saveSortReset', function(event) { + event.stopPropagation(); + ts.storage( table, 'tablesorter-savesort', '' ); + }); + } + // init is true when widget init is run, this will run this widget before all other widgets have initialized + // this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice. + if (init && sortList && sortList.length > 0) { + c.sortList = sortList; + } else if (table.hasInitialized && sortList && sortList.length > 0) { + // update sort change + $table.trigger('sorton', [sortList]); + } + } + }, + remove: function(table, c) { + c.$table.removeClass('hasSaveSort'); + // clear storage + if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); } + } +}); + +})(jQuery); + +return $.tablesorter; +})); diff --git a/js/parsers/parser-date-extract.js b/js/parsers/parser-date-extract.js new file mode 100644 index 0000000..8e4a49f --- /dev/null +++ b/js/parsers/parser-date-extract.js @@ -0,0 +1,98 @@ +/*! Parser: Extract out date - updated 10/26/2014 (v2.18.0) */ +/*jshint jquery:true */ +;(function($){ +"use strict"; + + var regex = { + usLong : /[A-Z]{3,10}\.?\s+\d{1,2},?\s+(?:\d{4})(?:\s+\d{1,2}:\d{2}(?::\d{2})?(?:\s+[AP]M)?)?/i, + mdy : /(\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i, + + dmy : /(\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i, + dmyreplace : /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, + + ymd : /(\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i, + ymdreplace : /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/ + }; + + /*! extract US Long Date *//* (ignore any other text) + * e.g. "Sue's Birthday! Jun 26, 2004 7:22 AM (8# 2oz)" + * demo: http://jsfiddle.net/Mottie/abkNM/4165/ */ + $.tablesorter.addParser({ + id: "extractUSLongDate", + is: function () { + // don't auto detect this parser + return false; + }, + format: function (s) { + var date, + str = s ? s.match(regex.usLong) : s; + if (str) { + date = new Date( str[0] ); + return date instanceof Date && isFinite(date) ? date.getTime() : s; + } + return s; + }, + type: "numeric" + }); + + /*! extract MMDDYYYY *//* (ignore any other text) + * demo: http://jsfiddle.net/Mottie/abkNM/4166/ */ + $.tablesorter.addParser({ + id: "extractMMDDYYYY", + is: function () { + // don't auto detect this parser + return false; + }, + format: function (s) { + var date, + str = s ? s.replace(/\s+/g," ").replace(/[\-.,]/g, "/").match(regex.mdy) : s; + if (str) { + date = new Date( str[0] ); + return date instanceof Date && isFinite(date) ? date.getTime() : s; + } + return s; + }, + type: "numeric" + }); + + /*! extract DDMMYYYY *//* (ignore any other text) + * demo: http://jsfiddle.net/Mottie/abkNM/4167/ */ + $.tablesorter.addParser({ + id: "extractDDMMYYYY", + is: function () { + // don't auto detect this parser + return false; + }, + format: function (s) { + var date, + str = s ? s.replace(/\s+/g," ").replace(/[\-.,]/g, "/").match(regex.dmy) : s; + if (str) { + date = new Date( str[0].replace(regex.dmyreplace, "$2/$1/$3") ); + return date instanceof Date && isFinite(date) ? date.getTime() : s; + } + return s; + }, + type: "numeric" + }); + + /*! extract YYYYMMDD *//* (ignore any other text) + * demo: http://jsfiddle.net/Mottie/abkNM/4168/ */ + $.tablesorter.addParser({ + id: "extractYYYYMMDD", + is: function () { + // don't auto detect this parser + return false; + }, + format: function (s) { + var date, + str = s ? s.replace(/\s+/g," ").replace(/[\-.,]/g, "/").match(regex.ymd) : s; + if (str) { + date = new Date( str[0].replace(regex.ymdreplace, "$2/$3/$1") ); + return date instanceof Date && isFinite(date) ? date.getTime() : s; + } + return s; + }, + type: "numeric" + }); + +})(jQuery); diff --git a/js/parsers/parser-date-iso8601.js b/js/parsers/parser-date-iso8601.js new file mode 100644 index 0000000..3483d35 --- /dev/null +++ b/js/parsers/parser-date-iso8601.js @@ -0,0 +1,35 @@ +/*! Parser: ISO-8601 date - updated 10/26/2014 (v2.18.0) */ +/* This parser works with dates in ISO8601 format + * 2013-02-18T18:18:44+00:00 + * Written by Sean Ellingham :https://github.com/seanellingham + * See https://github.com/Mottie/tablesorter/issues/247 + */ +/*global jQuery: false */ +;(function($){ +"use strict"; + + var iso8601date = /^([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/; + + $.tablesorter.addParser({ + id : 'iso8601date', + is : function(s) { + return s ? s.match(iso8601date) : false; + }, + format : function(s) { + var result = s ? s.match(iso8601date) : s; + if (result) { + var date = new Date(result[1], 0, 1); + if (result[3]) { date.setMonth(result[3] - 1); } + if (result[5]) { date.setDate(result[5]); } + if (result[7]) { date.setHours(result[7]); } + if (result[8]) { date.setMinutes(result[8]); } + if (result[10]) { date.setSeconds(result[10]); } + if (result[12]) { date.setMilliseconds(Number('0.' + result[12]) * 1000); } + return date.getTime(); + } + return s; + }, + type : 'numeric' + }); + +})(jQuery); diff --git a/js/parsers/parser-date-month.js b/js/parsers/parser-date-month.js new file mode 100644 index 0000000..7caaae0 --- /dev/null +++ b/js/parsers/parser-date-month.js @@ -0,0 +1,38 @@ +/*! Parser: Month - updated 10/26/2014 (v2.18.0) */ +/* Demo: http://jsfiddle.net/Mottie/abkNM/4169/ */ +/*jshint jquery:true */ +;(function($){ +"use strict"; + + var ts = $.tablesorter; + ts.dates = $.extend({}, ts.dates, { + // *** modify this array to match the desired language *** + monthCased : [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] + }); + ts.dates.monthLower = ts.dates.monthCased.join(',').toLocaleLowerCase().split(','); + + ts.addParser({ + id: "month", + is: function(){ + return false; + }, + format: function(s, table) { + if (s) { + var j = -1, c = table.config, + n = c.ignoreCase ? s.toLocaleLowerCase() : s; + $.each(ts.dates[ 'month' + (c.ignoreCase ? 'Lower' : 'Cased') ], function(i,v){ + if (j < 0 && n.match(v)) { + j = i; + return false; + } + }); + // return s (original string) if there isn't a match + // (non-weekdays will sort separately and empty cells will sort as expected) + return j < 0 ? s : j; + } + return s; + }, + type: "numeric" + }); + +})(jQuery); diff --git a/js/parsers/parser-date-range.js b/js/parsers/parser-date-range.js new file mode 100644 index 0000000..eab7440 --- /dev/null +++ b/js/parsers/parser-date-range.js @@ -0,0 +1,90 @@ +/*! Parser: date ranges - updated 2/23/2015 (v2.21.0) */ +/* Include the 'widget-filter-type-insideRange.js' to filter ranges */ +/*jshint jquery:true */ +;(function($){ +'use strict'; + + var regex = { + mdy : /(\d{1,2}[-\s]\d{1,2}[-\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/gi, + + dmy : /(\d{1,2}[-\s]\d{1,2}[-\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/gi, + dmyreplace : /(\d{1,2})[-\s](\d{1,2})[-\s](\d{4})/, + + ymd : /(\d{4}[-\s]\d{1,2}[-\s]\d{1,2}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/gi, + ymdreplace : /(\d{4})[-\s](\d{1,2})[-\s](\d{1,2})/ + }; + + /*! date-range MMDDYYYY *//* (2/15/2000 - 5/18/2000) */ + $.tablesorter.addParser({ + id: 'date-range-mdy', + is: function () { + return false; + }, + format: function (text) { + var date, str, i, len, + parsed = []; + str = text.replace( /\s+/g, ' ' ).replace( /[\/\-.,]/g, '-' ).match( regex.mdy ); + len = str && str.length; + // work on dates, even if there is no range + if ( len ) { + for (i = 0; i < len; i++) { + date = new Date( str[i] ); + parsed.push( date instanceof Date && isFinite(date) ? date.getTime() : str[i] ); + } + // sort from min to max + return parsed.sort().join( ' - ' ); + } + return text; + }, + type: 'text' + }); + + /*! date-range DDMMYYYY *//* (15/2/2000 - 18/5/2000) */ + $.tablesorter.addParser({ + id: 'date-range-dmy', + is: function () { + return false; + }, + format: function (text) { + var date, str, i, len, + parsed = []; + str = text.replace( /\s+/g, ' ' ).replace( /[\/\-.,]/g, '-' ).match( regex.dmy ); + len = str && str.length; + if ( len ) { + for (i = 0; i < len; i++) { + date = new Date( ( '' + str[i] ).replace( regex.dmyreplace, '$2/$1/$3' ) ); + parsed.push( date instanceof Date && isFinite(date) ? date.getTime() : str[i] ); + } + // sort from min to max + return parsed.sort().join( ' - ' ); + } + return text; + }, + type: 'text' + }); + + /*! date-range DDMMYYYY *//* (2000/2/15 - 2000/5/18) */ + $.tablesorter.addParser({ + id: 'date-range-ymd', + is: function () { + return false; + }, + format: function (text) { + var date, str, i, len, + parsed = []; + str = text.replace( /\s+/g, ' ' ).replace( /[\/\-.,]/g, '-' ).match( regex.ymd ); + len = str && str.length; + if ( len ) { + for (i = 0; i < len; i++) { + date = new Date( ( '' + str[i] ).replace( regex.ymdreplace, '$2/$3/$1' ) ); + parsed.push( date instanceof Date && isFinite(date) ? date.getTime() : str[i] ); + } + // sort from min to max + return parsed.sort().join( ' - ' ); + } + return text; + }, + type: 'text' + }); + +})(jQuery); diff --git a/js/parsers/parser-date-two-digit-year.js b/js/parsers/parser-date-two-digit-year.js new file mode 100644 index 0000000..43571bd --- /dev/null +++ b/js/parsers/parser-date-two-digit-year.js @@ -0,0 +1,80 @@ +/*! Parser: two digit year - updated 10/26/2014 (v2.18.0) */ +/* Demo: http://mottie.github.io/tablesorter/docs/example-parsers-dates.html */ +/*jshint jquery:true */ +;(function($){ +"use strict"; + + // Make the date be within +/- range of the 2 digit year + // so if the current year is 2020, and the 2 digit year is 80 (2080 - 2020 > 50), it becomes 1980 + // if the 2 digit year is 50 (2050 - 2020 < 50), then it becomes 2050. + var range = 50, + + // no need to change any of the code below + ts = $.tablesorter, + now = new Date().getFullYear(); + + ts.dates = $.extend({}, ts.dates, { + regxxxxyy: /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{2})/, + regyyxxxx: /(\d{2})[\/\s](\d{1,2})[\/\s](\d{1,2})/ + }); + + ts.formatDate = function(s, regex, format, table){ + if (s) { + var y, rng, + n = s + // replace separators + .replace(/\s+/g," ").replace(/[-.,]/g, "/") + // reformat xx/xx/xx to mm/dd/19yy; + .replace(regex, format), + d = new Date(n); + if ( d instanceof Date && isFinite(d) ) { + y = d.getFullYear(); + rng = table && table.config.dateRange || range; + // if date > 50 years old (set range), add 100 years + // this will work when people start using "50" and mean "2050" + while (now - y > rng) { + y += 100; + } + return d.setFullYear(y); + } + } + return s; + }; + + $.tablesorter.addParser({ + id: "ddmmyy", + is: function() { + return false; + }, + format: function(s, table) { + // reformat dd/mm/yy to mm/dd/19yy; + return ts.formatDate(s, ts.dates.regxxxxyy, "$2/$1/19$3", table); + }, + type: "numeric" + }); + + $.tablesorter.addParser({ + id: "mmddyy", + is: function() { + return false; + }, + format: function(s, table) { + // reformat mm/dd/yy to mm/dd/19yy + return ts.formatDate(s, ts.dates.regxxxxyy, "$1/$2/19$3", table); + }, + type: "numeric" + }); + + $.tablesorter.addParser({ + id: "yymmdd", + is: function() { + return false; + }, + format: function(s, table) { + // reformat yy/mm/dd to mm/dd/19yy + return ts.formatDate(s, ts.dates.regyyxxxx, "$2/$3/19$1", table); + }, + type: "numeric" + }); + +})(jQuery); diff --git a/js/parsers/parser-date-weekday.js b/js/parsers/parser-date-weekday.js new file mode 100644 index 0000000..7a1b3fe --- /dev/null +++ b/js/parsers/parser-date-weekday.js @@ -0,0 +1,38 @@ +/*! Parser: weekday - updated 10/26/2014 (v2.18.0) */ +/* Demo: http://jsfiddle.net/Mottie/abkNM/4169/ */ +/*jshint jquery:true */ +;(function($){ +"use strict"; + + var ts = $.tablesorter; + ts.dates = $.extend({}, ts.dates, { + // *** modify this array to change match the language *** + weekdayCased : [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ] + }); + ts.dates.weekdayLower = ts.dates.weekdayCased.join(',').toLocaleLowerCase().split(','); + + ts.addParser({ + id: "weekday", + is: function(){ + return false; + }, + format: function(s, table) { + if (s) { + var j = -1, c = table.config; + s = c.ignoreCase ? s.toLocaleLowerCase() : s; + $.each(ts.dates[ 'weekday' + (c.ignoreCase ? 'Lower' : 'Cased') ], function(i,v){ + if (j < 0 && s.match(v)) { + j = i; + return false; + } + }); + // return s (original string) if there isn't a match + // (non-weekdays will sort separately and empty cells will sort as expected) + return j < 0 ? s : j; + } + return s; + }, + type: "numeric" + }); + +})(jQuery); diff --git a/js/parsers/parser-date.js b/js/parsers/parser-date.js new file mode 100644 index 0000000..dbc30ad --- /dev/null +++ b/js/parsers/parser-date.js @@ -0,0 +1,35 @@ +/*! Parser: dates - updated 10/26/2014 (v2.18.0) */ +/* Extract dates using popular natural language date parsers */ +/*jshint jquery:true */ +;(function($){ +'use strict'; + + /*! Sugar (http://sugarjs.com/dates#comparing_dates) */ + /* demo: http://jsfiddle.net/Mottie/abkNM/4163/ */ + $.tablesorter.addParser({ + id: 'sugar', + is: function() { + return false; + }, + format: function(s) { + var date = Date.create ? Date.create(s) : s ? new Date(s) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + + /*! Datejs (http://www.datejs.com/) */ + /* demo: http://jsfiddle.net/Mottie/abkNM/4164/ */ + $.tablesorter.addParser({ + id: 'datejs', + is: function() { + return false; + }, + format: function(s) { + var date = Date.parse ? Date.parse(s) : s ? new Date(s) : s; + return date instanceof Date && isFinite(date) ? date.getTime() : s; + }, + type: 'numeric' + }); + +})(jQuery); diff --git a/js/parsers/parser-duration.js b/js/parsers/parser-duration.js new file mode 100644 index 0000000..da9d4ba --- /dev/null +++ b/js/parsers/parser-duration.js @@ -0,0 +1,67 @@ +/*! Parser: duration & countdown - updated 2/7/2015 (v2.19.0) */ +/*jshint jquery:true, unused:false */ +;(function($){ +'use strict'; + + // If any number > 9999, then set table.config.durationLength = 5 + // The below regex matches this duration example: 1y 23d 12h 44m 9s + $.tablesorter.addParser({ + id: 'duration', + is: function() { + return false; + }, + format: function(s, table) { + var i, time, + c = table.config, + t = '', + duration = '', + len = c.durationLength || 4, + str = new Array(len + 1).join('0'), + labels = (c.durationLabels || '(?:years|year|y),(?:days|day|d),(?:hours|hour|h),(?:minutes|minute|min|m),(?:seconds|second|sec|s)').split(/\s*,\s*/), + llen = labels.length; + // build regex + if (!c.durationRegex) { + for (i = 0; i < llen; i++) { + t += '(?:(\\d+)\\s*' + labels[i] + '\\s*)?'; + } + c.durationRegex = new RegExp(t, 'i'); + } + // remove commas from value + time = ( c.usNumberFormat ? s.replace(/,/g, '') : s.replace( /(\d)(?:\.|\s*)(\d)/g, '$1$2') ).match(c.durationRegex); + for (i = 1; i < llen + 1; i++) { + duration += ( str + ( time[i] || 0 ) ).slice(-len); + } + return duration; + }, + type: 'text' + }); + + /*! Countdown parser ( hh:mm:ss ) */ + /* Added 2/7/2015 (v2.19.0) - see http://stackoverflow.com/a/27023733/145346 */ + $.tablesorter.addParser({ + id: 'countdown', + is: function () { + return false; + }, + format: function ( text, table ) { + // change maxDigits to 4, if values go > 999 + // or to 5 for values > 9999, etc. + var maxDigits = table.config.durationLength || 4, + // prefix contains leading zeros that are tacked + prefix = new Array( maxDigits + 1 ).join( '0' ), + // split time into blocks + blocks = text.split( /\s*:\s*/ ), + len = blocks.length, + result = []; + // add values in reverse, so if there is only one block + // ( e.g. '10' ), then it would be the time in seconds + while ( len ) { + result.push( ( prefix + ( blocks[ --len ] || 0 ) ).slice( -maxDigits ) ); + } + // reverse the results and join them + return result.length ? result.reverse().join( '' ) : text; + }, + type: 'text' + }); + +})(jQuery); diff --git a/js/parsers/parser-feet-inch-fraction.js b/js/parsers/parser-feet-inch-fraction.js new file mode 100644 index 0000000..eb7f259 --- /dev/null +++ b/js/parsers/parser-feet-inch-fraction.js @@ -0,0 +1,63 @@ +/*! Parser: distance *//* +* This parser will parser numbers like 5'10" (5 foot 10 inches) +* and 31½ into sortable values. +* Demo: http://jsfiddle.net/Mottie/abkNM/154/ +*/ +/*global jQuery: false */ +;(function($){ + "use strict"; + + var ts = $.tablesorter; + ts.symbolRegex = /[\u215b\u215c\u215d\u215e\u00bc\u00bd\u00be]/g; + ts.processFractions = function(n, table) { + if (n) { + var t, p = 0; + n = $.trim(n.replace(/\"/,'')); + // look for a space in the first part of the number: "10 3/4" and save the "10" + if (/\s/.test(n)) { + p = ts.formatFloat(n.split(' ')[0], table); + // remove stuff to the left of the space + n = $.trim(n.substring(n.indexOf(' '), n.length)); + } + // look for a "/" to calculate fractions + if (/\//g.test(n)) { + t = n.split('/'); + // turn 3/4 into .75; make sure we don't divide by zero + n = p + parseInt(t[0], 10) / parseInt(t[1] || 1, 10); + // look for fraction symbols + } else if (ts.symbolRegex.test(n)) { + n = p + n.replace(ts.symbolRegex, function(m){ + return { + '\u215b' : '.125', // 1/8 + '\u215c' : '.375', // 3/8 + '\u215d' : '.625', // 5/8 + '\u215e' : '.875', // 7/8 + '\u00bc' : '.25', // 1/4 + '\u00bd' : '.5', // 1/2 + '\u00be' : '.75' // 3/4 + }[m]; + }); + } + } + return n || 0; + }; + + $.tablesorter.addParser({ + id: 'distance', + is: function() { + // return false so this parser is not auto detected + return false; + }, + format: function(s, table) { + if (s === '') { return ''; } + // look for feet symbol = ' + // very generic test to catch 1.1', 1 1/2' and 1½' + var d = (/^\s*\S*(\s+\S+)?\s*\'/.test(s)) ? s.split("'") : [0,s], + f = ts.processFractions(d[0], table), // feet + i = ts.processFractions(d[1], table); // inches + return (/[\'\"]/).test(s) ? parseFloat(f) + (parseFloat(i)/12 || 0) : parseFloat(f) + parseFloat(i); + }, + type: 'numeric' + }); + +})(jQuery); diff --git a/js/parsers/parser-file-type.js b/js/parsers/parser-file-type.js new file mode 100644 index 0000000..e60abce --- /dev/null +++ b/js/parsers/parser-file-type.js @@ -0,0 +1,73 @@ +/*! Parser: filetype *//* + * When a file type extension is found, the equivalent name is + * prefixed into the parsed data, so sorting occurs in groups + */ +/*global jQuery: false */ +;(function($){ +"use strict"; + + // basic list from http://en.wikipedia.org/wiki/List_of_file_formats + // To add a custom equivalent, define: + // $.tablesorter.fileTypes.equivalents['xx'] = "A|B|C"; + $.tablesorter.fileTypes = { + // divides filetype extensions in the equivalent list below + separator : '|', + equivalents : { + "3D Image" : "3dm|3ds|dwg|max|obj", + "Audio" : "aif|aac|ape|flac|la|m4a|mid|midi|mp2|mp3|ogg|ra|raw|rm|wav|wma", + "Compressed" : "7z|bin|cab|cbr|gz|gzip|iso|lha|lz|rar|tar|tgz|zip|zipx|zoo", + "Database" : "csv|dat|db|dbf|json|ldb|mdb|myd|pdb|sql|tsv|wdb|wmdb|xlr|xls|xlsx|xml", + "Development" : "asm|c|class|cls|cpp|cc|cs|cxx|cbp|cs|dba|fla|h|java|lua|pl|py|pyc|pyo|sh|sln|r|rb|vb", + "Document" : "doc|docx|odt|ott|pages|pdf|rtf|tex|wpd|wps|wrd|wri", + "Executable" : "apk|app|com|exe|gadget|lnk|msi", + "Fonts" : "eot|fnt|fon|otf|ttf|woff", + "Icons" : "ani|cur|icns|ico", + "Images" : "bmp|gif|jpg|jpeg|jpe|jp2|pic|png|psd|tga|tif|tiff|wmf|webp", + "Presentation" : "pps|ppt", + "Published" : "chp|epub|lit|pub|ppp|fm|mobi", + "Script" : "as|bat|cgi|cmd|jar|js|lua|scpt|scptd|sh|vbs|vb|wsf", + "Styles" : "css|less|sass", + "Text" : "info|log|md|markdown|nfo|tex|text|txt", + "Vectors" : "awg|ai|eps|cdr|ps|svg", + "Video" : "asf|avi|flv|m4v|mkv|mov|mp4|mpe|mpeg|mpg|ogg|rm|rv|swf|vob|wmv", + "Web" : "asp|aspx|cer|cfm|htm|html|php|url|xhtml" + } + }; + + $.tablesorter.addParser({ + id: 'filetype', + is: function() { + return false; + }, + format: function(s, table) { + var t, + c = table.config, + wo = c.widgetOptions, + i = s.lastIndexOf('.'), + sep = $.tablesorter.fileTypes.separator, + m = $.tablesorter.fileTypes.matching, + types = $.tablesorter.fileTypes.equivalents; + if (!m) { + // make a string to "quick" match the existing equivalents + t = []; + $.each(types, function(i,v){ + t.push(v); + }); + m = $.tablesorter.fileTypes.matching = sep + t.join(sep) + sep; + } + if (i >= 0) { + t = sep + s.substring(i + 1, s.length) + sep; + if (m.indexOf(t) >= 0) { + for (i in types) { + if ((sep + types[i] + sep).indexOf(t) >= 0) { + return i + (wo.group_separator ? wo.group_separator : '-') + s; + } + } + } + } + return s; + }, + type: 'text' + }); + +})(jQuery); diff --git a/js/parsers/parser-globalize.js b/js/parsers/parser-globalize.js new file mode 100644 index 0000000..af69a1f --- /dev/null +++ b/js/parsers/parser-globalize.js @@ -0,0 +1,46 @@ +/*! Parser: jQuery Globalize - updated 5/17/2015 (v2.22.0) */ +/* Extract localized data using jQuery's Globalize parsers; set + Globalize.locale( 'xx' ) prior to initializing tablesorter! */ +/*jshint jquery:true */ +;( function( $ ) { +'use strict'; + + /*! jQuery Globalize date parser (https://github.com/jquery/globalize#date-module) */ + /* demo: http://jsfiddle.net/Mottie/0j18Lw8r/ */ + $.tablesorter.addParser({ + id: 'globalize-date', + is: function () { + return false; + }, + format: function ( str, table, cell, cellIndex ) { + var c = table.config, + // add options to 'config.globalize' for all columns --> globalize : { skeleton: 'GyMMMd' } + // or per column by using the column index --> globalize : { 0 : { datetime: 'medium' } } + options = c.globalize && ( c.globalize[ cellIndex ] || c.globalize ) || {}, + date = Globalize && Globalize.dateParser ? Globalize.dateParser( options )( str ) : + str ? new Date( str ) : str; + return date instanceof Date && isFinite( date ) ? date.getTime() : str; + }, + type: 'numeric' + }); + + /*! jQuery Globalize number parser (https://github.com/jquery/globalize#number-module) */ + /* demo: http://jsfiddle.net/Mottie/0j18Lw8r/ */ + $.tablesorter.addParser({ + id: 'globalize-number', + is: function () { + return false; + }, + format: function ( str, table, cell, cellIndex ) { + var c = table.config, + // add options to 'config.globalize' for all columns --> globalize : { skeleton: 'GyMMMd' } + // or per column by using the column index --> globalize : { 0 : { datetime: 'medium' } } + options = c.globalize && ( c.globalize[ cellIndex ] || c.globalize ) || {}, + num = Globalize && Globalize.numberParser ? Globalize.numberParser( options )( str ) : + str ? $.tablesorter.formatFloat( ( str || '' ).replace( /[^\w,. \-()]/g, '' ), table ) : str; + return str && typeof num === 'number' ? num : str; + }, + type: 'numeric' + }); + +})( jQuery ); diff --git a/js/parsers/parser-ignore-articles.js b/js/parsers/parser-ignore-articles.js new file mode 100644 index 0000000..3424f98 --- /dev/null +++ b/js/parsers/parser-ignore-articles.js @@ -0,0 +1,61 @@ +/*! Parser: ignoreArticles - updated 9/15/2014 (v2.17.8) *//* + * This parser will remove "The", "A" and "An" from the beginning of a book + * or movie title, so it sorts by the second word or number + * Demo: http://jsfiddle.net/Mottie/abkNM/5/ + */ +/*jshint browser: true, jquery:true, unused:false */ +;(function($){ +"use strict"; + +var ts = $.tablesorter; + + // basic list from http://en.wikipedia.org/wiki/Article_%28grammar%29 + ts.ignoreArticles = { + "en" : "the, a, an", + "de" : "der, die, das, des, dem, den, ein, eine, einer, eines, einem, einen", + "nl" : "de, het, de, een", + "es" : "el, la, lo, los, las, un, una, unos, unas", + "pt" : "o, a, os, as, um, uma, uns, umas", + "fr" : "le, la, l'_, les, un, une, des", + "it" : "il, lo, la, l'_, i, gli, le, un', uno, una, un", + "hu" : "a, az, egy" + }; + + // To add a custom parser, define: + // $.tablesorter.ignoreArticles['xx'] = "A, B, C"; + // and then set the language id 'xx' in the headers option + // ignoreArticles : 'xx' + + ts.addParser({ + id: 'ignoreArticles', + is: function() { + return false; + }, + format: function(s, table, cell, cellIndex) { + var art, ignore, lang, + c = table.config, + str = s || ''; + if ( !(c.headers && c.headers[cellIndex] && c.headers[cellIndex].ignoreArticlesRegex) ) { + // initialize - save regex in c.headers[cellIndex].ignoreArticlesRegex + if (!c.headers) { c.headers = {}; } + if (!c.headers[cellIndex]) { c.headers[cellIndex] = {}; } + lang = ts.getData( c.$headers.eq(cellIndex), ts.getColumnData( table, c.headers, cellIndex ), 'ignoreArticles' ); + art = (ts.ignoreArticles[lang] || "the, a, an" ) + ""; + c.headers[cellIndex].ignoreArticlesRegex = new RegExp('^(' + $.trim( art.split(/\s*\,\s*/).join('\\s|') + "\\s" ).replace("_\\s","") + ')', 'i'); + // exception regex stored in c.headers[cellIndex].ignoreArticlesRegex2 + ignore = ts.getData( c.$headers.eq(cellIndex), ts.getColumnData( table, c.headers, cellIndex ), 'ignoreArticlesExcept' ); + c.headers[cellIndex].ignoreArticlesRegex2 = ignore !== '' ? new RegExp('^(' + ignore.replace(/\s/g, "\\s") + ')', 'i') : ''; + } + art = c.headers[cellIndex].ignoreArticlesRegex; + if (art.test(str)) { + ignore = c.headers[cellIndex].ignoreArticlesRegex2; + if ( !(ignore && ignore.test(str)) ) { + return str.replace(art, ''); + } + } + return str; + }, + type: 'text' + }); + +})(jQuery); diff --git a/js/parsers/parser-image.js b/js/parsers/parser-image.js new file mode 100644 index 0000000..a8b8723 --- /dev/null +++ b/js/parsers/parser-image.js @@ -0,0 +1,19 @@ +/*! Parser: image - new 7/17/2014 (v2.17.5) */ +/* alt attribute parser for jQuery 1.7+ & tablesorter 2.7.11+ */ +/*jshint jquery:true, unused:false */ +;(function($){ +"use strict"; + + $.tablesorter.addParser({ + id: "image", + is: function(){ + return false; + }, + format: function(s, table, cell) { + return $(cell).find('img').attr(table.config.imgAttr || 'alt') || s; + }, + parsed : true, // filter widget flag + type: "text" + }); + +})(jQuery); diff --git a/js/parsers/parser-input-select.js b/js/parsers/parser-input-select.js new file mode 100644 index 0000000..e4016ec --- /dev/null +++ b/js/parsers/parser-input-select.js @@ -0,0 +1,183 @@ +/*! Parser: input & select - updated 5/17/2015 (v2.22.0) *//* + * for jQuery 1.7+ & tablesorter 2.7.11+ + * Demo: http://mottie.github.com/tablesorter/docs/example-widget-grouping.html + */ +/*jshint browser: true, jquery:true, unused:false */ +;( function( $ ) { +'use strict'; + + var updateServer = function( event, $table, $input ) { + // do something here to update your server, if needed + // event = change event object + // $table = jQuery object of the table that was just updated + // $input = jQuery object of the input or select that was modified + }; + + // Custom parser for parsing input values + // updated dynamically using the 'change' function below + $.tablesorter.addParser({ + id : 'inputs', + is : function() { + return false; + }, + format : function( txt, table, cell ) { + var $input = $( cell ).find( 'input' ); + return $input.length ? $input.val() : txt; + }, + parsed : true, // filter widget flag + type : 'text' + }); + + $.tablesorter.addParser({ + id : 'inputs-numeric', + is : function() { + return false; + }, + format : function( txt, table, cell ) { + var $input = $( cell ).find( 'input' ); + var val = $input.length ? $input.val() : txt, + num = $.tablesorter.formatFloat( ( val || '' ).replace( /[^\w,. \-()]/g, '' ), table ); + return txt && typeof num === 'number' ? num : + txt ? $.trim( txt && table.config.ignoreCase ? txt.toLocaleLowerCase() : txt ) : txt; + }, + parsed : true, // filter widget flag + type : 'numeric' + }); + + // Custom parser for including checkbox status if using the grouping widget + // updated dynamically using the 'change' function below + $.tablesorter.addParser({ + id : 'checkbox', + is : function() { + return false; + }, + format : function( txt, table, cell, cellIndex ) { + var $cell = $( cell ), + wo = table.config.widgetOptions, + checkedClass = table.config.checkboxClass || 'checked', + // returning plain language here because this is what is shown in the + // group headers - change it as desired + status = wo.group_checkbox ? wo.group_checkbox : [ 'checked', 'unchecked' ], + $input = $cell.find( 'input[type="checkbox"]' ), + isChecked = $input.length ? $input[ 0 ].checked : ''; + // adding class to row, indicating that a checkbox is checked; includes + // a column index in case more than one checkbox happens to be in a row + $cell.closest( 'tr' ).toggleClass( checkedClass + ' ' + checkedClass + '-' + cellIndex, isChecked ); + return $input.length ? status[ isChecked ? 0 : 1 ] : txt; + }, + parsed : true, // filter widget flag + type : 'text' + }); + + // Custom parser which returns the currently selected options + // updated dynamically using the 'change' function below + $.tablesorter.addParser({ + id : 'select', + is : function() { + return false; + }, + format : function( txt, table, cell ) { + var $select = $( cell ).find( 'select' ); + return $select.length ? $select.val() : txt; + }, + parsed : true, // filter widget flag + type : 'text' + }); + + // Select parser to get the selected text + $.tablesorter.addParser({ + id : 'select-text', + is : function() { + return false; + }, + format : function( txt, table, cell ) { + var $select = $( cell ).find( 'select' ); + return $select.length ? $select.find( 'option:selected' ).text() || '' : txt; + }, + parsed : true, // filter widget flag + type : 'text' + }); + + // Custom parser for parsing textarea values + // updated dynamically using the 'change' function below + $.tablesorter.addParser({ + id : 'textarea', + is : function() { + return false; + }, + format : function( txt, table, cell ) { + var $textarea = $( cell ).find( 'textarea' ); + return $textarea.length ? $textarea.val() : txt; + }, + parsed : true, // filter widget flag + type : 'text' + }); + + // update select and all input types in the tablesorter cache when the change event fires. + // This method only works with jQuery 1.7+ + // you can change it to use delegate (v1.4.3+) or live (v1.3+) as desired + // if this code interferes somehow, target the specific table $('#mytable'), instead of $('table') + $( function() { + $( 'table' ).on( 'tablesorter-initialized updateComplete', function() { + var namespace = '.parser-forms', + restoreValue = function( isTbody ) { + // make sure we restore original values (trigger blur) + // isTbody is needed to prevent the select from closing in IE + // see https://connect.microsoft.com/IE/feedbackdetail/view/962618/ + if ( isTbody ) { + $( ':focus' ).blur(); + } + return; + }; + // bind to .tablesorter (default class name) + $( this ).children( 'tbody' ) + .off( namespace ) + .on( 'mouseleave' + namespace, function( event ) { + restoreValue( event.target.nodeName === 'TBODY' ); + }) + .on( 'focus' + namespace, 'select, input, textarea', function() { + $( this ).data( 'ts-original-value', this.value ); + }) + .on( 'blur' + namespace, 'input, textarea', function() { + // restore input value; + // 'change' is triggered before 'blur' so this doesn't replace the new update with the original + this.value = $( this ).data( 'ts-original-value' ); + }) + .on( 'change keyup '.split( ' ' ).join( namespace + ' ' ), 'select, input, textarea', function( event ) { + if ( event.which === 27 ) { + // escape: restore original value + this.value = $( this ).data( 'ts-original-value' ); + return; + } + // Update cell cache using... select: change, input: enter or textarea: alt + enter + if ( event.type === 'change' || + ( event.type === 'keyup' && event.which === 13 && + ( event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' && event.altKey ) ) ) { + var undef, + $target = $( event.target ), + $cell = $target.closest( 'td' ), + $table = $cell.closest( 'table' ), + indx = $cell[ 0 ].cellIndex, + c = $table[ 0 ].config || false, + $hdr = c && c.$headerIndexed && c.$headerIndexed[ indx ] || [], + val = $target.val(); + // abort if not a tablesorter table, or don't use updateCell if column is set + // to 'sorter-false' and 'filter-false', or column is set to 'parser-false' + if ( $hdr.length && ( $hdr.hasClass( 'parser-false' ) || + ( $hdr.hasClass( 'sorter-false' ) && $hdr.hasClass( 'filter-false' ) ) ) ) { + return; + } + // ignore change event if nothing changed + if ( val !== $target.data( 'ts-original-value' ) || event.target.type === 'checkbox' ) { + $target.data( 'ts-original-value', val ); + // pass undefined resort value so it falls back to config.resort setting + $table.trigger( 'updateCell', [ $cell, undef, function() { + updateServer( event, $table, $target ); + } ]); + } + } + }); + }); + }); + +})( jQuery ); diff --git a/js/parsers/parser-metric.js b/js/parsers/parser-metric.js new file mode 100644 index 0000000..4f367d0 --- /dev/null +++ b/js/parsers/parser-metric.js @@ -0,0 +1,77 @@ +/*! Parser: metric *//* + * Demo: http://jsfiddle.net/Mottie/abkNM/382/ + * Set the metric name in the header (defaults to "m|meter"), e.g. + * HDD Size + * Distance + */ +/*jshint jquery:true */ +;(function($){ +"use strict"; + + var prefixes = { + // "prefix" : [ base 10, base 2 ] + // skipping IEEE 1541 defined prefixes: kibibyte, mebibyte, etc, for now. + "Y|Yotta|yotta" : [ 1e24, Math.pow(1024, 8) ], // 1024^8 + "Z|Zetta|zetta" : [ 1e21, Math.pow(1024, 7) ], // 1024^7 + "E|Exa|exa" : [ 1e18, Math.pow(1024, 6) ], // 1024^6 + "P|Peta|peta" : [ 1e15, Math.pow(1024, 5) ], // 1024^5 + "T|Tera|tera" : [ 1e12, Math.pow(1024, 4) ], // 1024^4 + "G|Giga|giga" : [ 1e9, Math.pow(1024, 3) ], // 1024^3 + "M|Mega|mega" : [ 1e6, Math.pow(1024, 2) ], // 1024^2 + "k|Kilo|kilo" : [ 1e3, 1024 ], // 1024 + // prefixes below here are rarely, if ever, used in binary + "h|hecto" : [ 1e2, 1e2 ], + "da|deka" : [ 1e1, 1e1 ], + "d|deci" : [ 1e-1, 1e-1 ], + "c|centi" : [ 1e-2, 1e-2], + "m|milli" : [ 1e-3, 1e-3 ], + "µ|micro" : [ 1e-6, 1e-6 ], + "n|nano" : [ 1e-9, 1e-9 ], + "p|pico" : [ 1e-12, 1e-12 ], + "f|femto" : [ 1e-15, 1e-15 ], + "a|atto" : [ 1e-18, 1e-18 ], + "z|zepto" : [ 1e-21, 1e-21 ], + "y|yocto" : [ 1e-24, 1e-24 ] + }, + // the \\d+ will not catch digits with spaces, commas or decimals; so use the value from n instead + RegLong = "(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(", + RegAbbr = "(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)("; + + $.tablesorter.addParser({ + id: 'metric', + is: function() { + return false; + }, + format: function(s, table, cell, cellIndex) { + var v = 'm|meter', + b, t, + // process number here to get a numerical format (us or eu) + n = $.tablesorter.formatFloat(s.replace(/[^\w,. \-()]/g, ""), table), + $t = table.config.$headerIndexed[cellIndex], + m = $t.data('metric'); + if (!m) { + // stored values + t = ($t.attr('data-metric-name') || v).split('|'); + m = [ t[1] || t[0].substring(1), t[0] ]; + m[2] = new RegExp(RegLong + m[0] + "|" + m[1] + ")"); + m[3] = new RegExp(RegAbbr + m[1] + ")"); + $t.data('metric', m); + } + // find match to full name or abbreviation + t = s.match(m[2]) || s.match(m[3]); + if (t) { + for (v in prefixes) { + if (t[3].match(v)) { + // exception when using binary prefix + // change base for binary use + b = /^[b|bit|byte|o|octet]/.test(t[4]) ? 1 : 0; + return n * prefixes[v][b]; + } + } + } + return n; + }, + type: 'numeric' + }); + +})(jQuery); diff --git a/js/parsers/parser-named-numbers.js b/js/parsers/parser-named-numbers.js new file mode 100644 index 0000000..53bfd8f --- /dev/null +++ b/js/parsers/parser-named-numbers.js @@ -0,0 +1,122 @@ +/*! Parser: namedNumbers - updated 10/26/2014 (v2.18.0) *//* + * code modified from http://stackoverflow.com/a/12014376/145346 + */ +/*jshint jquery:true */ +;(function($){ +"use strict"; + + // Change language of the named numbers as needed + var named = { + negative: [ 'negative', 'minus' ], + numbers : { + 'zero' : 0, + 'one' : 1, + 'two' : 2, + 'three' : 3, + 'four' : 4, + 'five' : 5, + 'six' : 6, + 'seven' : 7, + 'eight' : 8, + 'nine' : 9, + 'ten' : 10, + 'eleven' : 11, + 'twelve' : 12, + 'thirteen' : 13, + 'fourteen' : 14, + 'fifteen' : 15, + 'sixteen' : 16, + 'seventeen' : 17, + 'eighteen' : 18, + 'nineteen' : 19, + 'twenty' : 20, + 'thirty' : 30, + 'forty' : 40, + 'fourty' : 40, // common misspelling + 'fifty' : 50, + 'sixty' : 60, + 'seventy' : 70, + 'eighty' : 80, + 'ninety' : 90 + }, + // special case + hundred : 'hundred', + // multiples + powers : { + 'thousand' : 1e3, + 'million' : 1e6, + 'billion' : 1e9, + 'trillion' : 1e12, + 'quadrillion' : 1e15, + 'quintillion' : 1e18, + 'sextillion' : 1e21, + 'septillion' : 1e24, + 'octillion' : 1e27, + 'nonillion' : 1e30, + 'decillion' : 1e33, + 'undecillion' : 1e36, + 'duodecillion' : 1e39, + 'tredecillion' : 1e42, + 'quattuordecillion' : 1e45, + 'quindecillion' : 1e48, + 'sexdecillion' : 1e51, + 'septendecillion' : 1e54, + 'octodecillion' : 1e57, + 'novemdecillion' : 1e60, + 'vigintillion' : 1e63, + 'unvigintillion' : 1e66, + 'duovigintillion' : 1e69, + 'trevigintillion' : 1e72, + 'quattuorvigintillion' : 1e75, + 'quinvigintillion' : 1e78, + 'sexvigintillion' : 1e81, + 'septenvigintillion' : 1e84, + 'octovigintillion' : 1e87, + 'novemvigintillion' : 1e90, + 'trigintillion' : 1e93, + 'untrigintillion' : 1e96, + 'duotrigintillion' : 1e99, + 'googl' : 1e100 + } + }, + result, group, + negativeRegex = new RegExp('(' + named.negative.join('|') + ')'), + calc = function ( rawWord, table ) { + // remove extra characters that might be next to the word + var word = rawWord.replace( /[,."']/g, '' ), + // formatFloat will deal with the commas & decimals in the number format + num = $.tablesorter.formatFloat( rawWord || '', table ), + power = named.powers.hasOwnProperty( word ) ? named.powers[ word ] : null; + num = typeof num === 'number' ? num : named.numbers.hasOwnProperty( word ) ? named.numbers[ word ] : null; + if ( num !== null ) { + group += num; + } else if ( word === named.hundred ) { + group *= 100; + } else if ( power !== null ) { + result += group * power; + group = 0; + } + }; + + $.tablesorter.addParser({ + id: "namedNumbers", + is: function () { + return false; + }, + format: function ( str, table ) { + result = 0; + group = 0; + var indx, + arry = ( str || '' ).split( /[\s-]+/ ), + len = arry.length; + for ( indx = 0; indx < len; indx++ ) { + calc( arry[ indx ].toLowerCase(), table ); + } + result = ( result + group ) * ( str.match( negativeRegex ) ? -1 : 1 ); + // make sure to let zero get parsed, so check hasOwnProperty + return result || named.numbers.hasOwnProperty( str ) ? result : $.tablesorter.formatFloat( str || '', table ); + }, + type: "numeric" + }); + +})( jQuery ); diff --git a/js/parsers/parser-network.js b/js/parsers/parser-network.js new file mode 100644 index 0000000..7175578 --- /dev/null +++ b/js/parsers/parser-network.js @@ -0,0 +1,137 @@ +/*! Parser: network - updated 5/17/2015 (v2.22.0) */ +/* IPv4, IPv6 and MAC Addresses */ +/*global jQuery: false */ +;(function($){ + 'use strict'; + + var ts = $.tablesorter, + ipv4Format, + ipv4Is; + + /*! IPv6 Address parser (WIP) *//* + * IPv6 Address (ffff:0000:0000:0000:0000:0000:0000:0000) + * needs to support short versions like '::8' or '1:2::7:8' + * and '::00:192.168.10.184' (embedded IPv4 address) + * see http://www.intermapper.com/support/tools/IPV6-Validator.aspx + */ + $.extend( ts.regex, {}, { + ipv4Validate : /((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})/, + ipv4Extract : /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/, + + // simplified regex from http://www.intermapper.com/support/tools/IPV6-Validator.aspx + // (specifically from http://download.dartware.com/thirdparty/ipv6validator.js) + ipv6Validate : /^\s*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/i + }); + + ts.addParser({ + id: 'ipv6Address', + is: function(s) { + return ts.regex.ipv6Validate.test(s); + }, + format: function(address, table) { + // code modified from http://forrst.com/posts/JS_Expand_Abbreviated_IPv6_Addresses-1OR + var i, t, sides, groups, groupsPresent, + hex = table ? (typeof table === 'boolean' ? table : table && table.config.ipv6HexFormat || false) : false, + fullAddress = '', + expandedAddress = '', + validGroupCount = 8, + validGroupSize = 4; + // remove any extra spaces + address = address.replace(/\s*/g, ''); + // look for embedded ipv4 + if (ts.regex.ipv4Validate.test(address)) { + groups = address.match(ts.regex.ipv4Extract); + t = ''; + for (i = 1; i < groups.length; i++){ + t += ('00' + (parseInt(groups[i], 10).toString(16)) ).slice(-2) + ( i === 2 ? ':' : '' ); + } + address = address.replace( ts.regex.ipv4Extract, t ); + } + + if (address.indexOf('::') == -1) { + // All eight groups are present + fullAddress = address; + } else { + // Consecutive groups of zeroes have been collapsed with '::'. + sides = address.split('::'); + groupsPresent = 0; + for (i = 0; i < sides.length; i++) { + groupsPresent += sides[i].split(':').length; + } + fullAddress += sides[0] + ':'; + for (i = 0; i < validGroupCount - groupsPresent; i++) { + fullAddress += '0000:'; + } + fullAddress += sides[1]; + } + groups = fullAddress.split(':'); + for (i = 0; i < validGroupCount; i++) { + // it's fastest & easiest for tablesorter to sort decimal values (vs hex) + groups[i] = hex ? ('0000' + groups[i]).slice(-4) : + ('00000' + (parseInt(groups[i], 16) || 0)).slice(-5); + expandedAddress += ( i != validGroupCount-1) ? groups[i] + ':' : groups[i]; + } + return hex ? expandedAddress : expandedAddress.replace(/:/g, ''); + }, + // uses natural sort hex compare + type: 'numeric' + }); + + // ipv4 address + // moved here from jquery.tablesorter.js (core file) + ipv4Is = function(s) { + return (/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/).test(s); + }; + ipv4Format = function(s, table) { + var i, a = s ? s.split('.') : '', + r = '', + l = a.length; + for (i = 0; i < l; i++) { + r += ('000' + a[i]).slice(-3); + } + return s ? ts.formatFloat(r, table) : s; + }; + + /*! Parser: ipv4Address (a.k.a. ipAddress) */ + // duplicate 'ipAddress' as 'ipv4Address' (to maintain backwards compatility) + ts.addParser({ + id: 'ipAddress', + is: ipv4Is, + format: ipv4Format, + type: 'numeric' + }); + ts.addParser({ + id: 'ipv4Address', + is: ipv4Is, + format: ipv4Format, + type: 'numeric' + }); + + /*! Parser: MAC address */ + /* MAC examples: 12:34:56:78:9A:BC, 1234.5678.9ABC, 12-34-56-78-9A-BC, and 123456789ABC + */ + ts.addParser({ + id : 'MAC', + is : function( str ) { + return false; + }, + format : function( str ) { + var indx, len, + mac = '', + val = ( str || '' ).replace( /[:.-]/g, '' ).match( /\w{2}/g ); + if ( val ) { + // not assuming all mac addresses in the column will end up with six + // groups of two to process, so it's not actually validating the address + len = val.length; + for ( indx = 0; indx < len; indx++ ) { + mac += ( '000' + parseInt( val[ indx ], 16 ) ).slice( -3 ); + } + return mac; + } + return str; + }, + // uses natural sort hex compare + type : 'numeric' + }); + +})( jQuery ); diff --git a/js/parsers/parser-roman.js b/js/parsers/parser-roman.js new file mode 100644 index 0000000..0032a74 --- /dev/null +++ b/js/parsers/parser-roman.js @@ -0,0 +1,117 @@ +/*! Parser: roman - updated 6/28/MMXIV (v2.17.3) *//* + * code modified from both: + * Steven Levithan @ http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter + * Jonathan Snook comment @ http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter#comment-16140 + */ +/*jshint jquery:true, unused:false */ +;(function($){ +"use strict"; + + // allow lower case roman numerals, since lists use i, ii, iii, etc. + var validator = /^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/i, + matcher = /\b([MCDLXVI]+\b)/gi, + lookup = { I:1, V:5, X:10, L:50, C:100, D:500, M:1000 }; + + $.tablesorter.addParser({ + id: 'roman', + is: function(){ + return false; + }, + format: function(s) { + var val, + roman = s.toUpperCase().split(''), + num = 0; + + // roman numerals not found! + if ( !(s && validator.test(s)) ) { + return s; + } + + while (roman.length) { + val = lookup[roman.shift()]; + num += val * (val < lookup[roman[0]] ? -1 : 1); + } + + return num; + }, + type: "numeric" + }); + + $.tablesorter.addParser({ + id: 'roman-ignore', + is: function(){ + return false; + }, + format: function(s, table, cell, column) { + var val, orig, + c = table.config, + ignore = $.isArray(c.roman_ignore) ? c.roman_ignore[column] : 0, + // find roman numerals + roman = ( isNaN(ignore) ? + // ignore can be a regex or string + $.trim( s.replace(ignore, '') ) : + // or a number to ignore the last x letters... + $.trim( s.substring(0, s.length - ignore) ) + ).match(matcher), + v = validator.test(roman), + num = 0; + + // roman numerals not found! + if ( !(v) ) { + return s; + } + + // save roman numeral for replacement + orig = roman[0]; + roman = orig.toUpperCase().split(''); + + while (roman.length) { + val = lookup[roman.shift()]; + // ignore non-roman numerals + if (val) { + num += val * (val < lookup[roman[0]] ? -1 : 1); + } + } + + return num ? s.replace(orig, num) : s; + }, + type: "text" + }); + + $.tablesorter.addParser({ + id: 'roman-extract', + is: function(){ + return false; + }, + format: function(s) { + var val, + // find roman numerals + roman = $.grep(s.split(/\b/), function(v, i){ + return validator.test(v) ? v : ''; + }).join('').match(matcher), + + v = roman ? validator.test(roman) : 0, + num = 0; + + // roman numerals not found! + if ( !(v) ) { + return s; + } + + // save roman numeral for replacement + roman = roman[0].toUpperCase().split(''); + + while (roman.length) { + val = lookup[roman.shift()]; + // ignore non-roman numerals + if (val) { + num += val * (val < lookup[roman[0]] ? -1 : 1); + } + } + + return num ? num : s; + }, + type: "numeric" + }); + +})(jQuery); diff --git a/js/widgets/widget-alignChar.js b/js/widgets/widget-alignChar.js new file mode 100644 index 0000000..9284803 --- /dev/null +++ b/js/widgets/widget-alignChar.js @@ -0,0 +1,146 @@ +/*! Widget: alignChar - updated 2/7/2015 (v2.19.0) *//* + * Align Characters, Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; +var ts = $.tablesorter; + +ts.alignChar = { + + init : function(table, c, wo) { + c.$headers.filter('[' + wo.alignChar_charAttrib + ']').each(function(){ + var $this = $(this), + vars = { + column : this.column, + align : $this.attr(wo.alignChar_charAttrib), + alignIndex : parseInt( $this.attr(wo.alignChar_indexAttrib) || 0, 10), + adjust : parseFloat($this.attr(wo.alignChar_adjustAttrib)) || 0, + }; + vars.regex = new RegExp('\\' + vars.align, 'g'); + if (typeof vars.align !== 'undefined') { + wo.alignChar_savedVars[this.column] = vars; + ts.alignChar.setup(table, c, wo, vars); + } + }); + }, + + setup: function(table, c, wo, v){ + // do nothing for empty tables + if ($.isEmptyObject(c.cache)) { return; } + var tbodyIndex, rowIndex, start, end, last, index, rows, val, count, + len, wLeft, wRight, alignChar, $row, + left = [], + right = []; + for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++){ + rows = c.cache[tbodyIndex]; + len = rows.normalized.length; + for (rowIndex = 0; rowIndex < len; rowIndex++) { + // set up to work with modified cache v2.16.0+ + $row = rows.row ? rows.row[rowIndex] : rows.normalized[rowIndex][c.columns].$row; + val = $row.find('td').eq(v.column).text().replace(/[ ]/g, "\u00a0"); + // count how many "align" characters are in the string + count = (val.match( v.regex ) || []).length; + // set alignment @ alignIndex (one-based index) + if (count > 0 && v.alignIndex > 0) { + end = Math.min(v.alignIndex, count); + start = 0; + index = 0; + last = 0; + // find index of nth align character based on alignIndex (data-align-index) + while (start++ < end) { + last = val.indexOf(v.align, last + 1); + index = last < 0 ? index : last; + } + } else { + index = val.indexOf(v.align); + } + if ( index >= 0 ) { + left.push( val.substring(0, index) || '' ); + right.push( val.substring(index, val.length) || '' ); + } else { + // no align character found! + // put val in right or left based on the align index + left.push( (count >= 1 && v.alignIndex >= count) ? '' : val || '' ); + right.push( (count >= 1 && v.alignIndex >= count) ? val || '' : '' ); + } + } + } + + // find widest segments + wLeft = ($.extend([], left)).sort(function(a,b){ return b.length - a.length; })[0]; + wRight = ($.extend([], right)).sort(function(a,b){ return b.length - a.length; })[0]; + // calculate percentage widths + v.width = v.width || ( Math.floor(wLeft.length / (wLeft.length + wRight.length) * 100) + v.adjust ); + wLeft = 'min-width:' + v.width + '%'; + wRight = 'min-width:' + (100 - v.width) + '%'; + + for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++){ + rows = c.cache[tbodyIndex]; + len = rows.normalized.length; + for (rowIndex = 0; rowIndex < len; rowIndex++) { + alignChar = $(wo.alignChar_wrap).length ? $(wo.alignChar_wrap).html(v.align)[0].outerHTML : v.align; + $row = rows.row ? rows.row[rowIndex] : rows.normalized[rowIndex][c.columns].$row; + last = right[rowIndex].slice(v.align.length); + $row.find('td').eq(v.column).html( + '' + left[rowIndex] + '' + + '' + ( last.length ? alignChar + last : '' ) + '' + ); + } + } + wo.alignChar_initialized = true; + + }, + remove: function(table, c, column){ + if ($.isEmptyObject(c.cache)) { return; } + var tbodyIndex, rowIndex, len, rows, $row, $cell; + for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++){ + rows = c.cache[tbodyIndex]; + len = rows.normalized.length; + for (rowIndex = 0; rowIndex < len; rowIndex++) { + $row = rows.row ? rows.row[rowIndex] : rows.normalized[rowIndex][c.columns].$row; + $cell = $row.find('td').eq(column); + $cell.html( $cell.text().replace(/\s/g, ' ') ); + } + } + } +}; + +ts.addWidget({ + id: 'alignChar', + priority: 100, + options: { + alignChar_wrap : '', + alignChar_charAttrib : 'data-align-char', + alignChar_indexAttrib : 'data-align-index', + alignChar_adjustAttrib : 'data-align-adjust' // percentage width adjustments + }, + init: function(table, thisWidget, c, wo){ + wo.alignChar_initialized = false; + wo.alignChar_savedVars = []; + ts.alignChar.init(table, c, wo); + c.$table.on('pagerEnd refreshAlign', function(){ + c.$headers.filter('[' + wo.alignChar_charAttrib + ']').each(function(){ + ts.alignChar.remove(table, c, this.column); + }); + ts.alignChar.init(table, c, wo); + }); + }, + format : function(table, c, wo){ + // reinitialize in case table is empty when first initialized + if (!wo.alignChar_initialized) { + c.$table.trigger('refreshAlign'); + } + }, + remove : function(table, c, wo, refreshing){ + if (refreshing) { return; } + c.$headers.filter('[' + wo.alignChar_charAttrib + ']').each(function(){ + ts.alignChar.remove(table, c, this.column); + }); + wo.alignChar_initialized = false; + } +}); + +})(jQuery); \ No newline at end of file diff --git a/js/widgets/widget-build-table.js b/js/widgets/widget-build-table.js new file mode 100644 index 0000000..04fa1cf --- /dev/null +++ b/js/widgets/widget-build-table.js @@ -0,0 +1,454 @@ +/*! Widget: Build Table - updated 3/26/2015 (v2.21.3) *//* + * for tableSorter v2.16.0+ + * by Rob Garrison + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; +var ts = $.tablesorter = $.tablesorter || {}, + + // build a table from data (requires existing tag) + // data.header contains an array of header titles + // data.rows contains an array of rows which contains an array of cells + bt = ts.buildTable = function(tar, c){ + // add table if one doesn't exist + var $tbl = tar.nodeName === 'TABLE' ? $(tar) : $('
    ').appendTo(tar), + table = $tbl[0], + wo = c.widgetOptions = $.extend( true, {}, bt.defaults, c.widgetOptions ), + p = wo.build_processing, + typ = wo.build_type, + d = wo.build_source || c.data, + + // determine type: html, json, array, csv, object + runType = function(d){ + var t = $.type(d), + jq = d instanceof jQuery; + // run any processing if set + if ( typeof p === 'function' ) { d = p(d, wo); } + // store processed data in table.config.data + c.data = d; + // String (html or unprocessed json) or jQuery object + if ( jq || t === 'string' ) { + // look for closing tag, then we have an HTML string + if ( jq || /<\s*\/tr\s*>/.test(d) ) { + return bt.html( table, d, wo ); + } + try { + d = $.parseJSON(d || 'null'); + if (d) { + // valid JSON! + return bt.object( table, d, wo ); + } + } catch(ignore) {} + // fall through in case it's a csv string + } + // Array + if (t === 'array' || t === 'string' || typ === 'array' || typ === 'csv') { + // build table using an array (csv & array combined script) + return bt.csv( table, d, wo ); + } + // if we got here, it's an object, or nothing + return bt.object( table, d, wo ); + }; + + // store config + table.config = c; + + // even if wo.build_type is undefined, we can try to figure out the type + if ( !ts.buildTable.hasOwnProperty(typ) && typ !== '' ) { + if (c.debug) { ts.log('aborting build table widget, incorrect build type'); } + return false; + } + + if ( d instanceof jQuery ) { + // get data from within a jQuery object (csv) + runType( $.trim( d.html() ) ); + } else if ( d && ( d.hasOwnProperty('url') || typ === 'json' ) ) { + // load data via ajax + $.ajax( wo.build_source ) + .done(function(data) { + runType(data); + }) + .fail(function( jqXHR, textStatus, errorThrown) { + if (c.debug) { ts.log('aborting build table widget, failed ajax load'); } + $tbl.html(''); + }); + } else { + runType(d); + } + }; + + bt.defaults = { + // *** build widget core *** + build_type : '', // array, csv, object, json, html + build_source : '', // array, object, jQuery Object or ajaxObject { url: '', dataType: 'json' }, + build_processing : null, // function that returns a useable build_type (e.g. string to array) + build_complete : 'tablesorter-build-complete', // triggered event when build completes + + // *** CSV & Array *** + build_headers : { + rows : 1, // Number of header rows from the csv + classes : [], // Header classes to apply to cells + text : [], // Header cell text + widths : [] // set header cell widths (set in colgroup) + }, + build_footers : { + rows : 1, // Number of header rows from the csv + classes : [], // Footer classes to apply to cells + text : [] // Footer cell text + }, + build_numbers : { + addColumn : false, // include row numbering column? + sortable : false // make column sortable? + }, + + // *** CSV only options *** + build_csvStartLine : 0, // line within the csv to start adding to table + build_csvSeparator : ",", // csv separator + + // *** build object options *** + build_objectRowKey : 'rows', // object key containing table rows + build_objectCellKey : 'cells', // object key containing table cells (within the rows object) + build_objectHeaderKey : 'headers', // object key containing table headers + build_objectFooterKey : 'footers' // object key containing table footers + }; + + bt.build = { + colgroup : function(widths) { + var t = ''; + // add colgroup if widths set + if (widths && widths.length) { + t += ''; + $.each(widths, function(i, w){ + t += ''; + }); + t += ''; + } + return t; + }, + // d = cell data; typ = 'th' or 'td'; first = save widths from first header row only + cell : function(d, wo, typ, col, first){ + var j, $td, + $col = first ? $('') : '', + cls = wo.build_headers.classes, + cw = wo.build_headers.widths; + // d is just an array + if (/string|number/.test(typeof d)) { + // add classes from options, but not text + $td = $('<' + typ + (cls && cls[col] ? ' class="' + cls[col] + '"' : '') + '>' + d + ''); + // get widths from options (only from first row) + if (first && cw && cw[col]) { + $col.width(cw[col] || ''); + } + } else { + // assume we have an object + $td = $('<' + typ + '>'); + for (j in d) { + if (d.hasOwnProperty(j)){ + if (j === 'text' || j === 'html') { + $td[j]( d[j] ); + } else if (first && j === 'width') { + // set column width, but only from first row + $col.width(d[j] || ''); + } else { + $td.attr(j, d[j]); + } + } + } + } + return [ $td, $col ]; + }, + // h1 = header text from data + header : function(h1, wo){ + var h2 = wo.build_headers.text, + cls = wo.build_headers.classes, + t = '' + (wo.build_numbers.addColumn ? '' + wo.build_numbers.addColumn + '' : ''); + $.each(h1, function(i, h) { + if (/<\s*\/t(d|h)\s*>/.test(h)) { + t += h; + } else { + t += '' + + (h2 && h2[i] ? h2[i] : h) + ''; + } + }); + return t + ''; + }, + rows : function(items, txt, c, wo, num, ftr){ + var h = (ftr ? 'th' : 'td'), + t = '' + (wo.build_numbers.addColumn ? '<' + h + '>' + (ftr ? '' : num) + '' : ''); + $.each(items, function(i, item) { + // test if HTML is already included; look for closing + if (/<\s*\/t(d|h)\s*>/.test(item)) { + t += item; + } else { + t += '<' + (ftr ? h + (c && c[i] ? ' class="' + c[i] + '"' : '') : h) + '>' + + (ftr && txt && txt.length && txt[i] ? txt[i] : item) + ''; + } + }); + return t + ''; + } + }; + + bt.buildComplete = function(table, wo){ + $(table).trigger(wo.build_complete); + ts.setup(table, table.config); + }; + + /* ==== Array example ==== + [ + [ "header1", "header2", ... "headerN" ], + [ "row1cell1", "row1cell2", ... "row1cellN" ], + [ "row2cell1", "row2cell2", ... "row2cellN" ], + ... + [ "rowNcell1", "rowNcell2", ... "rowNcellN" ] + ] + */ + bt.array = function(table, data, wo) { + return bt.csv(table, data, wo); + }; + + /* ==== CSV example ==== + ID, Name, Age, Date + A42b, Parker, 28, "Jul 6, 2006 8:14 AM" + A255, Hood, 33, "Dec 10, 2002 5:14 AM" + A33, Kent, 18, "Jan 12, 2003 11:14 AM" + A1, Franklin, 45, "Jan 18, 2001 9:12 AM" + A102, Evans, 22, "Jan 18, 2007 9:12 AM" + A42a, Everet, 22, "Jan 18, 2007 9:12 AM" + ID, Name, Age, Date + */ + // Adapted & modified from csvToTable.js by Steve Sobel + // MIT license: https://code.google.com/p/jquerycsvtotable/ + bt.csv = function(table, data, wo) { + var c, h, + csv = wo.build_type === 'csv' || typeof data === 'string', + $t = $(table), + lines = csv ? data.replace('\r','').split('\n') : data, + len = lines.length, + printedLines = 0, + infooter = false, + r = wo.build_headers.rows + (csv ? wo.build_csvStartLine : 0), + f = wo.build_footers.rows, + headerCount = 0, + error = '', + items, + tableHTML = bt.build.colgroup( wo.build_headers.widths ) + ''; + + $.each(lines, function(n, line) { + if ( n >= len - f ) { infooter = true; } + // build header + if ( (csv ? n >= wo.build_csvStartLine : true) && ( n < r ) ) { + h = csv ? bt.splitCSV( line, wo.build_csvSeparator ) : line; + headerCount = h.length; + tableHTML += bt.build.header(h, wo); + } else if ( n >= r ) { + // build tbody & tfoot rows + if (n === r) { + tableHTML += ''; + } + items = csv ? bt.splitCSV( line, wo.build_csvSeparator ) : line; + if (infooter && f > 0) { + tableHTML += (n === len - f ? '' : '') + + (n === len ? '' : ''); + } + if (items.length > 1) { + printedLines++; + if ( items.length !== headerCount ) { + error += 'error on line ' + n + ': Item count (' + items.length + + ') does not match header count (' + headerCount + ') \n'; + } + c = infooter ? wo.build_footers.classes : ''; + tableHTML += bt.build.rows(items, wo.build_footers.text, c, wo, printedLines, infooter); + } + } + }); + tableHTML += (f > 0 ? '' : ''); + if (error) { + $t.html(error); + } else { + $t.html(tableHTML); + bt.buildComplete(table, wo); + } + }; + + // CSV Parser by Brian Huisman (http://www.greywyvern.com/?post=258) + bt.splitCSV = function(str, sep) { + var x, tl, + thisCSV = $.trim(str).split(sep = sep || ","); + for ( x = thisCSV.length - 1; x >= 0; x-- ) { + if ( thisCSV[x].replace(/\"\s+$/, '"').charAt(thisCSV[x].length - 1) === '"' ) { + if ( (tl = thisCSV[x].replace(/^\s+\"/, '"')).length > 1 && tl.charAt(0) === '"' ) { + thisCSV[x] = thisCSV[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"'); + } else if (x) { + thisCSV.splice(x - 1, 2, [thisCSV[x - 1], thisCSV[x]].join(sep)); + } else { + thisCSV = thisCSV.shift().split(sep).concat(thisCSV); + } + } else { + thisCSV[x].replace(/""/g, '"'); + } + } + return thisCSV; + }; + + // data may be a jQuery object after processing + bt.html = function(table, data, wo) { + var $t = $(table); + if ( data instanceof jQuery ) { + $t.empty().append(data); + } else { + $t.html(data); + } + bt.buildComplete(table, wo); + }; + +/* ==== Object example ==== + data : { + headers : [ + [ + { text: 'First Name', class: 'fname', width: '20%' }, // row 1 cell 1 + 'Last Name', + { text: 'Age', class: 'age', 'data-sorter' : false }, + 'Total', + { text: 'Discount', class : 'sorter-false' }, + { text: 'Date', class : 'date' } // row 1 cell 6 + ] + ], + footers : 'clone', // clone headers or assign array like headers + rows : [ + // TBODY 1 + [ 'Peter', 'Parker', 28, '$9.99', '20%', 'Jul 6, 2006 8:14 AM' ], // row 1 + [ 'John', 'Hood', 33, '$19.99', '25%', 'Dec 10, 2002 5:14 AM' ], // row 2 + [ 'Clark', 'Kent', 18, '$15.89', '44%', 'Jan 12, 2003 11:14 AM' ], // row 3 + + // TBODY 2 + { newTbody: true, class: 'tablesorter-infoOnly' }, + { cells : [ { text: 'Info Row', colSpan: 6 } ] }, // row 4 + + // TBODY 3 + { newTbody: true }, + [ 'Bruce', 'Evans', 22, '$13.19', '11%', 'Jan 18, 2007 9:12 AM' ], // row 5 + [ 'Brice', 'Almighty', 45, '$153.19', '44%', 'Jan 18, 2001 9:12 AM' ], // row 6 + + { class: 'specialRow', // row 7 + cells: [ + { text: 'Fred', class: 'fname' }, + { text: 'Smith', class: 'lname' }, + { text: 18, class: 'age', 'data-info': 'fake ID!, he is really 16' }, + { text: '$22.44', class: 'total' }, + { text: '8%', class: 'discount' }, + { text: 'Aug 20, 2012 10:15 AM', class: 'date' } + ], + 'data-info' : 'This row likes turtles' + } + ] + } +*/ + bt.object = function(table, data, wo) { + // "rows" + var j, l, t, $c, $t, $tb, $tr, + c = table.config, + kh = wo.build_objectHeaderKey, + kr = wo.build_objectRowKey, + h = data.hasOwnProperty(kh) && !$.isEmptyObject(data.kh) ? data.kh : data.hasOwnProperty('headers') ? data.headers : false, + r = data.hasOwnProperty(kr) && !$.isEmptyObject(data.kr) ? data.kr : data.hasOwnProperty('rows') ? data.rows : false; + + if (!h || !r || h.length === 0 || r.length === 0) { + if (c.debug) { ts.log('aborting build table widget, missing data for object build'); } + return false; + } + + $c = $(''); + $t = $('
    ' + jqXHR.status + ' ' + textStatus + '
    '); + + // Build thead + // h = [ ['headerRow1Cell1', 'headerRow1Cell2', ... 'headerRow1CellN' ], ['headerRow2Cell1', ... ] ] + // or h = [ [ { text: 'firstCell', class: 'fc', width: '20%' }, ..., { text: 'last Cell' } ], [ /* second row */ ] ] + $.each(h, function(i, d){ + $tr = $('').appendTo( $t.find('thead') ); + l = d.length; // header row + for ( j = 0; j < l; j++ ) { + // cell(cellData, widgetOptions, 'th', first row) + t = bt.build.cell(d[j], wo, 'th', j, i === 0); + if (t[0] && t[0].length) { t[0].appendTo( $tr ); } // add cell + if (i === 0 && t[1]) { t[1].appendTo( $c ); } // add col to colgroup + } + }); + if ($c.find('col[style]').length) { + // add colgroup if it contains col elements + $t.prepend( $c ); + } + + $tb = $(''); + // Build tbody + $.each(r, function(i, d){ + var j; + t = $.type(d) === 'object'; + // add new tbody + if (t && d.newTbody) { + $tb = $('').appendTo( $t ); + for (j in d) { + if (d.hasOwnProperty(j) && j !== 'newTbody'){ + $tb.attr(j, d[j]); + } + } + } else { + if (i === 0) { + // add tbody, if the first item in the object isn't a call for a new tbody + $tb.appendTo( $t ); + } + + $tr = $('').appendTo( $tb ); + if (t) { + // row defined by object + for (j in d) { + if (d.hasOwnProperty(j) && j !== wo.build_objectCellKey){ + $tr.attr(j, d[j]); + } + } + if (d.hasOwnProperty(wo.build_objectCellKey)) { + // cells contains each cell info + d = d.cells; + } + } + + l = d.length; + for ( j = 0; j < l; j++ ) { + // cell(cellData, widgetOptions, 'td') + $c = bt.build.cell(d[j], wo, 'td', j); + if ($c[0] && $c[0].length) { $c[0].appendTo( $tr ); } // add cell + } + } + }); + + // add footer + if (data.hasOwnProperty(wo.build_objectFooterKey)) { + t = data[wo.build_objectFooterKey]; + if (t === 'clone') { + $c = $t.find('thead').html(); + $t.append('' + $c + ''); + } else { + $c = $('').appendTo( $t ); + $.each(t, function(i, d) { + $tr = $('').appendTo( $c ); + l = d.length; // footer cells + for ( j = 0; j < l; j++ ) { + // cell(cellData, widgetOptions, 'th') + $tb = bt.build.cell(d[j], wo, 'th', j); + if ($tb[0] && $tb[0].length) { $tb[0].appendTo( $tr ); } // add cell + } + }); + } + } + + $(table).html( $t.html() ); + bt.buildComplete(table, wo); + }; + + bt.ajax = bt.json = function(table, data, wo) { + return bt.object(table, data, wo); + }; + +})(jQuery); diff --git a/js/widgets/widget-chart.js b/js/widgets/widget-chart.js new file mode 100644 index 0000000..6589fb5 --- /dev/null +++ b/js/widgets/widget-chart.js @@ -0,0 +1,275 @@ +/* Widget: chart (beta) - updated 2/7/2015 (v2.19.0) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ + 'use strict'; + + var ts = $.tablesorter, + + // temp variables + chart_cols = [], + chart_headers = [], + // google charts + chart_rows = [], + chart_data = [], + // highcharts + chart_categories = [], + chart_series = [], + // fusioncharts + chart_category = [], + chart_dataset = [], + + chart = ts.chart = { + + // regex used to strip out non-digit values before sending + // the string to the $.tablesorter.formatFloat function + nonDigit : /[^\d,.\-()]/g, + + init: function(c, wo) { + c.$table + .off(wo.chart_event) + .on(wo.chart_event, function() { + if (this.hasInitialized) { + // refresh "c" variable in case options are updated dynamically + var c = this.config; + chart.getCols(c, c.widgetOptions); + chart.getData(c, c.widgetOptions); + } + }); + }, + + getCols: function(c, wo) { + var i; + chart_cols = []; + chart_series = []; + chart_dataset = []; + + for ( i = 0; i < c.columns; i++ ) { + if ( wo.chart_useSelector && ts.hasWidget( c.table, 'columnSelector' ) && !c.selector.auto ) { + if ( ( c.selector.states[i] && $.inArray(i, wo.chart_ignoreColumns) < 0 ) || + i === wo.chart_labelCol || i === wo.chart_sort[0][0] ) { + chart_cols.push(i); + } + } else { + if ( $.inArray(i, wo.chart_ignoreColumns) < 0 || i === wo.chart_labelCol || i === wo.chart_sort[0][0] ) { + chart_cols.push(i); + } + } + } + }, + + getData: function(c, wo) { + chart.getHeaders(c, wo); + chart.getRows(c, wo); + + /* == Google data == + array of arrays (Google charts) + [ + [ "Year", "Sales", "Expenses" ], + [ "2004", 1000, 400 ], + [ "2005", 1170, 460 ], + [ "2006", 660, 1120 ], + [ "2007", 1030, 540 ] + ] + + == Highcharts == + categories -> [ '2004', '2005', '2006', '2007' ] + series -> [{ + name: 'Sales', + data: [ 1000, 1170, 660, 1030 ] + }, { + name: 'Expenses', + data: [ 400, 460, 1120, 540 ] + }] + + == Fusioncharts + "categories": [{ + "category": [ + {"label": "2004"}, + {"label": "2005"}, + {"label": "2006"}, + {"label": "2007"} + ] + }], + "dataset": [ + { + "seriesname": "Sales", + "data": [ + {"value": "1000"}, + {"value": "1170"}, + {"value": "660"}, + {"value": "1030"} + ] + },{ + "seriesname": "Expenses", + "data": [ + {"value": "400"}, + {"value": "600"}, + {"value": "1120"}, + {"value": "540"} + ] + } + ] + */ + + chart_data = [ chart_headers ]; + $.each(chart_rows, function(k, row) { + chart_data.push(row); + }); + + c.chart = { + // google + data: chart_data, + // highcharts + categories: chart_categories, + series: chart_series, + // FusionCharts + category: chart_category, + dataset: chart_dataset + }; + }, + + getHeaders: function(c, wo) { + var text; + chart_headers = []; + chart_series = []; + chart_dataset = []; + chart_headers.push( c.headerContent[wo.chart_labelCol] ); + $.each(chart_cols, function(k, col) { + if (col === wo.chart_labelCol) { + return true; + } + text = c.headerContent[col]; + chart_headers.push( text ); + chart_series.push( { name: text, data: [] } ); + chart_dataset.push( { seriesname: text, data: [] } ); + }); + }, + + getRows: function(c, wo) { + var norm_rows = c.cache[0].normalized, + rows = []; + chart_rows = []; + chart_categories = []; + chart_category = []; + + $.each(norm_rows, function(indx, rowVal) { + var i, txt, + $tr = rowVal[c.columns].$row, + $cells = $tr.children('th,td'), + row = []; + if ( + (/v/i.test(wo.chart_incRows) && $tr.is(':visible')) || + (/f/i.test(wo.chart_incRows) && !$tr.hasClass(wo.filter_filteredRow || 'filtered')) || + (!/(v|f)/i.test(wo.chart_incRows)) + ) { + // Add all cols (don't mess up indx for sorting) + for (i = 0; i < c.columns; i++) { + if ( $.inArray(indx, wo.chart_parsed) >= 0 ) { + row.push( rowVal[i] ); + } else { + txt = $cells[i].getAttribute( c.textAttribute ) || $cells[i].textContent || $cells.eq(i).text(); + row.push( $.trim( txt ) ); + } + } + rows.push(row); + } + }); + + // sort based on chart_sort + rows.sort(function(a, b) { + if ( wo.chart_sort[0][1] === 1 ) { + return ts.sortNatural( b[wo.chart_sort[0][0]], a[wo.chart_sort[0][0]] ); + } + return ts.sortNatural( a[wo.chart_sort[0][0]], b[wo.chart_sort[0][0]] ); + }); + + $.each(rows, function(i, rowVal) { + var value, + objIndex = 0, + row = [], + label = rowVal[wo.chart_labelCol]; + + row.push( '' + label ); + + $.each(rowVal, function(indx, cellValue) { + var tempVal; + if (indx === wo.chart_labelCol) { + chart_categories.push( cellValue ); + chart_category.push({ 'label': cellValue }); + return true; + } + value = false; + if ( wo.chart_useSelector && ts.hasWidget( c.table, 'columnSelector' ) && !c.selector.auto ) { + if ( c.selector.states[indx] && $.inArray(indx, wo.chart_ignoreColumns) < 0 ) { + value = '' + cellValue; + } + } else { + if ($.inArray(indx, wo.chart_ignoreColumns) < 0) { + value = '' + cellValue; + } + } + + if (value !== false) { + if ( /s/i.test( '' + wo.chart_layout[row.length] ) ) { + row.push( value ); + chart_series[objIndex].data.push( value ); + chart_dataset[objIndex].data.push( value ); + } else { + // using format float, after stripping out all non-digit values + tempVal = ts.formatFloat( value.replace( chart.nonDigit, '' ), c.table ); + tempVal = isNaN(tempVal) ? value : tempVal; + // if tempVal ends up being an empty string, fall back to value + row.push( tempVal ); + chart_series[objIndex].data.push( tempVal ); + chart_dataset[objIndex].data.push( { value : tempVal } ); + } + objIndex++; + } + }); + chart_rows.push(row); + }); + }, + + remove: function(c, wo) { + c.$table.off(wo.chart_event); + } + + }; + + ts.addWidget({ + id: 'chart', + options: { + // (a)ll, (v)isible or (f)iltered - only the first letter is needed + chart_incRows: 'filtered', + // prefer columnSelector for ignoreColumns + chart_useSelector: false, + // columns to ignore [0, 1,... ] (zero-based index) + chart_ignoreColumns: [], + // Use parsed data instead of cell.text() + chart_parsed: [], + // data output layout, float is default + chart_layout: { + // first element is a string, all others will be float + 0: 'string' + }, + // Set the label column + chart_labelCol: 0, + // data sort, should always be first row, might want [[0,1]] + chart_sort: [[0,0]], + // event to trigger get updated data + chart_event: 'chartData' + }, + + init: function(table, thisWidget, c, wo) { + chart.init(c, wo); + }, + + remove: function(table, c, wo) { + chart.remove(c, wo); + } + }); + +})(jQuery); diff --git a/js/widgets/widget-columnSelector.js b/js/widgets/widget-columnSelector.js new file mode 100644 index 0000000..2c519fc --- /dev/null +++ b/js/widgets/widget-columnSelector.js @@ -0,0 +1,366 @@ +/* Widget: columnSelector (responsive table widget) - updated 3/5/2015 (v2.21.0) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * by Justin Hallett & Rob Garrison + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; + +var ts = $.tablesorter, +namespace = '.tscolsel', +tsColSel = ts.columnSelector = { + + queryAll : '@media only all { [columns] { display: none; } } ', + queryBreak : '@media all and (min-width: [size]) { [columns] { display: table-cell; } } ', + + init: function(table, c, wo) { + var $t, colSel; + + // abort if no input is contained within the layout + $t = $(wo.columnSelector_layout); + if (!$t.find('input').add( $t.filter('input') ).length) { + if (c.debug) { + ts.log('ColumnSelector: >> ERROR: Column Selector aborting, no input found in the layout! ***'); + } + return; + } + + // unique table class name + c.$table.addClass( c.namespace.slice(1) + 'columnselector' ); + + // build column selector/state array + colSel = c.selector = { $container : $(wo.columnSelector_container || '
    ') }; + colSel.$style = $('').prop('disabled', true).appendTo('head'); + colSel.$breakpoints = $('').prop('disabled', true).appendTo('head'); + + colSel.isInitializing = true; + tsColSel.setupSelector(table, c, wo); + + if (wo.columnSelector_mediaquery) { + tsColSel.setupBreakpoints(c, wo); + } + + colSel.isInitializing = false; + if (colSel.$container.length) { + tsColSel.updateCols(c, wo); + } else if (c.debug) { + ts.log('ColumnSelector: >> container not found'); + } + + c.$table + .off('refreshColumnSelector' + namespace) + .on('refreshColumnSelector' + namespace, function(e, opt){ + // make sure we're using current config settings + var i, + isArry = $.isArray(opt), + c = this.config, + wo = c.widgetOptions; + // see #798 + if (opt && c.selector.$container.length) { + if (isArry) { + // make sure array contains numbers + $.each(opt, function(i,v){ + opt[i] = parseInt(v, 10); + }); + for (i = 0; i < c.columns; i++) { + c.selector.$container + .find('input[data-column=' + i + ']') + .prop('checked', $.inArray( i, opt ) >= 0 ); + } + } + // if passing an array, set auto to false to allow manual column selection & update columns + tsColSel.updateAuto( c, wo, colSel.$container.find('input[data-column="auto"]').prop('checked', !isArry) ); + } else { + tsColSel.updateBreakpoints(c, wo); + tsColSel.updateCols(c, wo); + } + }); + + }, + + setupSelector: function(table, c, wo) { + var name, + colSel = c.selector, + $container = colSel.$container, + useStorage = wo.columnSelector_saveColumns && ts.storage, + // get stored column states + saved = useStorage ? ts.storage( table, 'tablesorter-columnSelector' ) : [], + state = useStorage ? ts.storage( table, 'tablesorter-columnSelector-auto') : {}; + + // initial states + colSel.auto = $.isEmptyObject(state) || $.type(state.auto) !== "boolean" ? wo.columnSelector_mediaqueryState : state.auto; + colSel.states = []; + colSel.$column = []; + colSel.$wrapper = []; + colSel.$checkbox = []; + // populate the selector container + c.$table.children('thead').find('tr:first th', table).each(function() { + var $this = $(this), + // if no data-priority is assigned, default to 1, but don't remove it from the selector list + priority = $this.attr(wo.columnSelector_priority) || 1, + colId = $this.attr('data-column'), + state = ts.getData(this, c.headers[colId], 'columnSelector'); + + // if this column not hidable at all + // include getData check (includes "columnSelector-false" class, data attribute, etc) + if ( isNaN(priority) && priority.length > 0 || state === 'disable' || + ( wo.columnSelector_columns[colId] && wo.columnSelector_columns[colId] === 'disable') ) { + return true; // goto next + } + + // set default state; storage takes priority + colSel.states[colId] = saved && typeof(saved[colId]) !== 'undefined' ? + saved[colId] : typeof(wo.columnSelector_columns[colId]) !== 'undefined' ? + wo.columnSelector_columns[colId] : (state === 'true' || state !== 'false'); + colSel.$column[colId] = $(this); + + // set default col title + name = $this.attr(wo.columnSelector_name) || $this.text(); + + if ($container.length) { + colSel.$wrapper[colId] = $(wo.columnSelector_layout.replace(/\{name\}/g, name)).appendTo($container); + colSel.$checkbox[colId] = colSel.$wrapper[colId] + // input may not be wrapped within the layout template + .find('input').add( colSel.$wrapper[colId].filter('input') ) + .attr('data-column', colId) + .toggleClass( wo.columnSelector_cssChecked, colSel.states[colId] ) + .prop('checked', colSel.states[colId]) + .on('change', function(){ + colSel.states[colId] = this.checked; + tsColSel.updateCols(c, wo); + }).change(); + } + }); + + }, + + setupBreakpoints: function(c, wo){ + var colSel = c.selector; + + // add responsive breakpoints + if (wo.columnSelector_mediaquery) { + // used by window resize function + colSel.lastIndex = -1; + tsColSel.updateBreakpoints(c, wo); + c.$table + .off('updateAll' + namespace) + .on('updateAll' + namespace, function(){ + tsColSel.updateBreakpoints(c, wo); + tsColSel.updateCols(c, wo); + }); + } + + if (colSel.$container.length) { + // Add media queries toggle + if (wo.columnSelector_mediaquery) { + colSel.$auto = $( wo.columnSelector_layout.replace(/\{name\}/g, wo.columnSelector_mediaqueryName) ).prependTo(colSel.$container); + colSel.$auto + // needed in case the input in the layout is not wrapped + .find('input').add( colSel.$auto.filter('input') ) + .attr('data-column', 'auto') + .prop('checked', colSel.auto) + .toggleClass( wo.columnSelector_cssChecked, colSel.auto ) + .on('change', function(){ + tsColSel.updateAuto(c, wo, $(this)); + }).change(); + } + // Add a bind on update to re-run col setup + c.$table.off('update' + namespace).on('update' + namespace, function() { + tsColSel.updateCols(c, wo); + }); + } + }, + + updateAuto: function(c, wo, $el) { + var colSel = c.selector; + colSel.auto = $el.prop('checked') || false; + $.each( colSel.$checkbox, function(i, $cb){ + if ($cb) { + $cb[0].disabled = colSel.auto; + colSel.$wrapper[i].toggleClass('disabled', colSel.auto); + } + }); + if (wo.columnSelector_mediaquery) { + tsColSel.updateBreakpoints(c, wo); + } + tsColSel.updateCols(c, wo); + // copy the column selector to a popup/tooltip + if (c.selector.$popup) { + c.selector.$popup.find('.tablesorter-column-selector') + .html( colSel.$container.html() ) + .find('input').each(function(){ + var indx = $(this).attr('data-column'); + $(this).prop( 'checked', indx === 'auto' ? colSel.auto : colSel.states[indx] ); + }); + } + if (wo.columnSelector_saveColumns && ts.storage) { + ts.storage( c.$table[0], 'tablesorter-columnSelector-auto', { auto : colSel.auto } ); + } + // trigger columnUpdate if auto is true (it gets skipped in updateCols() + if (colSel.auto) { + c.$table.trigger('columnUpdate'); + } + }, + + updateBreakpoints: function(c, wo) { + var priority, column, breaks, temp, + colSel = c.selector, + prefix = c.namespace + 'columnselector', + mediaAll = [], + breakpts = ''; + if (wo.columnSelector_mediaquery && !colSel.auto) { + colSel.$breakpoints.prop('disabled', true); + colSel.$style.prop('disabled', false); + return; + } + + // only 6 breakpoints (same as jQuery Mobile) + for (priority = 0; priority < 6; priority++){ + /*jshint loopfunc:true */ + breaks = []; + c.$headers.filter('[' + wo.columnSelector_priority + '=' + (priority + 1) + ']').each(function(){ + column = parseInt($(this).attr('data-column'), 10) + 1; + temp = ' col:nth-child(' + column + ')'; + breaks.push(prefix + temp + ',' + prefix + '_extra_table' + temp); + temp = ' tr th:nth-child(' + column + ')'; + breaks.push(prefix + temp + ',' + prefix + '_extra_table' + temp); + temp = ' tr td:nth-child(' + column + ')'; + breaks.push(prefix + temp + ',' + prefix + '_extra_table' + temp); + }); + if (breaks.length) { + mediaAll = mediaAll.concat( breaks ); + breakpts += tsColSel.queryBreak + .replace(/\[size\]/g, wo.columnSelector_breakpoints[priority]) + .replace(/\[columns\]/g, breaks.join(',')); + } + } + if (colSel.$style) { + colSel.$style.prop('disabled', true); + } + if (mediaAll.length) { + colSel.$breakpoints + .prop('disabled', false) + .html( tsColSel.queryAll.replace(/\[columns\]/g, mediaAll.join(',')) + breakpts ); + } + }, + + updateCols: function(c, wo) { + if (wo.columnSelector_mediaquery && c.selector.auto || c.selector.isInitializing) { + return; + } + var column, temp, + colSel = c.selector, + styles = [], + prefix = c.namespace + 'columnselector'; + colSel.$container.find('input[data-column]').filter('[data-column!="auto"]').each(function(){ + if (!this.checked) { + column = parseInt( $(this).attr('data-column'), 10 ) + 1; + temp = ' col:nth-child(' + column + ')'; + styles.push(prefix + temp + ',' + prefix + '_extra_table' + temp); + temp = ' tr th:nth-child(' + column + ')'; + styles.push(prefix + temp + ',' + prefix + '_extra_table' + temp); + temp = ' tr td:nth-child(' + column + ')'; + styles.push(prefix + temp + ',' + prefix + '_extra_table' + temp); + } + $(this).toggleClass( wo.columnSelector_cssChecked, this.checked ); + }); + if (wo.columnSelector_mediaquery){ + colSel.$breakpoints.prop('disabled', true); + } + if (colSel.$style) { + colSel.$style.prop('disabled', false).html( styles.length ? styles.join(',') + ' { display: none; }' : '' ); + } + if (wo.columnSelector_saveColumns && ts.storage) { + ts.storage( c.$table[0], 'tablesorter-columnSelector', colSel.states ); + } + c.$table.trigger('columnUpdate'); + }, + + attachTo : function(table, elm) { + table = $(table)[0]; + var colSel, wo, indx, + c = table.config, + $popup = $(elm); + if ($popup.length && c) { + if (!$popup.find('.tablesorter-column-selector').length) { + // add a wrapper to add the selector into, in case the popup has other content + $popup.append(''); + } + colSel = c.selector; + wo = c.widgetOptions; + $popup.find('.tablesorter-column-selector') + .html( colSel.$container.html() ) + .find('input').each(function(){ + var indx = $(this).attr('data-column'), + isChecked = indx === 'auto' ? colSel.auto : colSel.states[indx]; + $(this) + .toggleClass( wo.columnSelector_cssChecked, isChecked ) + .prop( 'checked', isChecked ); + }); + colSel.$popup = $popup.on('change', 'input', function(){ + // data input + indx = $(this).toggleClass( wo.columnSelector_cssChecked, this.checked ).attr('data-column'); + // update original popup + colSel.$container.find('input[data-column="' + indx + '"]') + .prop('checked', this.checked) + .trigger('change'); + }); + } + } + +}; + +ts.addWidget({ + id: "columnSelector", + priority: 10, + options: { + // target the column selector markup + columnSelector_container : null, + // column status, true = display, false = hide + // disable = do not display on list + columnSelector_columns : {}, + // remember selected columns + columnSelector_saveColumns: true, + + // container layout + columnSelector_layout : '', + // data attribute containing column name to use in the selector container + columnSelector_name : 'data-selector-name', + + /* Responsive Media Query settings */ + // enable/disable mediaquery breakpoints + columnSelector_mediaquery: true, + // toggle checkbox name + columnSelector_mediaqueryName: 'Auto: ', + // breakpoints checkbox initial setting + columnSelector_mediaqueryState: true, + // responsive table hides columns with priority 1-6 at these breakpoints + // see http://view.jquerymobile.com/1.3.2/dist/demos/widgets/table-column-toggle/#Applyingapresetbreakpoint + // *** set to false to disable *** + columnSelector_breakpoints : [ '20em', '30em', '40em', '50em', '60em', '70em' ], + // data attribute containing column priority + // duplicates how jQuery mobile uses priorities: + // http://view.jquerymobile.com/1.3.2/dist/demos/widgets/table-column-toggle/ + columnSelector_priority : 'data-priority', + // class name added to checked checkboxes - this fixes an issue with Chrome not updating FontAwesome + // applied icons; use this class name (input.checked) instead of input:checked + columnSelector_cssChecked : 'checked' + + }, + init: function(table, thisWidget, c, wo) { + tsColSel.init(table, c, wo); + }, + remove: function(table, c, wo, refreshing) { + if (refreshing) { return; } + var csel = c.selector; + csel.$container.empty(); + if (csel.$popup) { csel.$popup.empty(); } + csel.$style.remove(); + csel.$breakpoints.remove(); + c.$table.off('updateAll' + namespace + ' update' + namespace); + } + +}); + +})(jQuery); diff --git a/js/widgets/widget-columns.js b/js/widgets/widget-columns.js new file mode 100644 index 0000000..30a2b1f --- /dev/null +++ b/js/widgets/widget-columns.js @@ -0,0 +1,78 @@ +/*! Widget: columns */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +ts.addWidget({ + id: "columns", + priority: 30, + options : { + columns : [ "primary", "secondary", "tertiary" ] + }, + format: function(table, c, wo) { + var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx, + $table = c.$table, + $tbodies = c.$tbodies, + sortList = c.sortList, + len = sortList.length, + // removed c.widgetColumns support + css = wo && wo.columns || [ "primary", "secondary", "tertiary" ], + last = css.length - 1; + remove = css.join(' '); + // check if there is a sort (on initialization there may not be one) + for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody + $rows = $tbody.children('tr'); + // loop through the visible rows + $rows.each(function() { + $row = $(this); + if (this.style.display !== 'none') { + // remove all columns class names + $cells = $row.children().removeClass(remove); + // add appropriate column class names + if (sortList && sortList[0]) { + // primary sort column class + $cells.eq(sortList[0][0]).addClass(css[0]); + if (len > 1) { + for (indx = 1; indx < len; indx++) { + // secondary, tertiary, etc sort column classes + $cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] ); + } + } + } + } + }); + ts.processTbody(table, $tbody, false); + } + // add classes to thead and tfoot + rows = wo.columns_thead !== false ? ['thead tr'] : []; + if (wo.columns_tfoot !== false) { + rows.push('tfoot tr'); + } + if (rows.length) { + $rows = $table.find( rows.join(',') ).children().removeClass(remove); + if (len) { + for (indx = 0; indx < len; indx++) { + // add primary. secondary, tertiary, etc sort column classes + $rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]); + } + } + } + }, + remove: function(table, c, wo) { + var tbodyIndex, $tbody, + $tbodies = c.$tbodies, + remove = (wo.columns || [ "primary", "secondary", "tertiary" ]).join(' '); + c.$headers.removeClass(remove); + c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove); + for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody + $tbody.children('tr').each(function() { + $(this).children().removeClass(remove); + }); + ts.processTbody(table, $tbody, false); // restore tbody + } + } +}); + +})(jQuery); diff --git a/js/widgets/widget-cssStickyHeaders.js b/js/widgets/widget-cssStickyHeaders.js new file mode 100644 index 0000000..07ed0f6 --- /dev/null +++ b/js/widgets/widget-cssStickyHeaders.js @@ -0,0 +1,154 @@ +/*! Widget: cssStickyHeaders - updated 2/9/2015 (v2.19.1) *//* +* Requires a modern browser, tablesorter v2.8+ +*/ +/*jshint jquery:true, unused:false */ +;(function($, window){ + 'use strict'; + + var ts = $.tablesorter; + + ts.addWidget({ + id: 'cssStickyHeaders', + priority: 10, + options: { + cssStickyHeaders_offset : 0, + cssStickyHeaders_addCaption : false, + // jQuery selector or object to attach sticky header to + cssStickyHeaders_attachTo : null, + cssStickyHeaders_filteredToTop : true + }, + init : function(table, thisWidget, c, wo) { + var ht, offst, adjustY, + $table = c.$table, + $attach = $(wo.cssStickyHeaders_attachTo), + isIE = 'ActiveXObject' in window, // target all versions of IE + namespace = c.namespace + 'cssstickyheader ', + $thead = $table.children('thead'), + $caption = $table.children('caption'), + $win = $attach.length ? $attach : $(window), + $parent = $table.parent().closest('table.' + ts.css.table), + $parentThead = $parent.length && ts.hasWidget($parent[0], 'cssStickyHeaders') ? $parent.children('thead') : [], + borderTopWidth = ( parseInt( $table.css('border-top-width'), 10 ) || 0 ), + lastCaptionSetting = wo.cssStickyHeaders_addCaption, + // table offset top changes while scrolling in FF + adjustOffsetTop = false, + addCaptionHeight = false, + setTransform = function( $elms, y ) { + var translate = y === 0 ? '' : 'translate(0px,' + y + 'px)'; + $elms.css({ + 'transform' : translate, + '-ms-transform' : translate, + '-webkit-transform' : translate + }); + }; + + // Firefox fixes + if ($caption.length) { + // Firefox does not include the caption height when getting the table height + // see https://bugzilla.mozilla.org/show_bug.cgi?id=820891, so lets detect it instead of browser sniff + ht = $table.height(); + $caption.hide(); + addCaptionHeight = $table.height() === ht; + $caption.show(); + + // Firefox changes the offset().top when translating the table caption + offst = $table.offset().top; + setTransform( $caption, 20 ); + adjustOffsetTop = $table.offset().top !== offst; + setTransform( $caption, 0 ); + } + + $win + .unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') ) + .bind('scroll resize '.split(' ').join(namespace), function() { + // make sure "wo" is current otherwise changes to widgetOptions + // are not dynamic (like the add caption button in the demo) + wo = c.widgetOptions; + + if ( adjustOffsetTop ) { + // remove transform from caption to get the correct offset().top value + setTransform( $caption, 0 ); + adjustY = $table.offset().top; + } + + var top = $attach.length ? $attach.offset().top : $win.scrollTop(), + // add caption height; include table padding top & border-spacing or text may be above the fold (jQuery UI themes) + // border-spacing needed in Firefox, but not webkit... not sure if I should account for that + captionHeight = ( $caption.outerHeight(true) || 0 ) + + ( parseInt( $table.css('padding-top'), 10 ) || 0 ) + + ( parseInt( $table.css('border-spacing'), 10 ) || 0 ), + + bottom = $table.height() + ( addCaptionHeight && wo.cssStickyHeaders_addCaption ? captionHeight : 0 ) - + $thead.height() - ( $table.children('tfoot').height() || 0 ) - + ( wo.cssStickyHeaders_addCaption ? captionHeight : ( addCaptionHeight ? 0 : captionHeight ) ), + + parentTheadHeight = $parentThead.length ? $parentThead.height() : 0, + + // get bottom of nested sticky headers + nestedStickyBottom = $parentThead.length ? ( + isIE ? $parent.data('cssStickyHeaderBottom') + parentTheadHeight : + $parentThead.offset().top + parentTheadHeight - $win.scrollTop() + ) : 0, + + // in this case FF's offsetTop changes while scrolling, so we get a saved offsetTop before scrolling occurs + // but when the table is inside a wrapper ($attach) we need to continually update the offset top + tableOffsetTop = adjustOffsetTop ? adjustY : $table.offset().top, + + offsetTop = addCaptionHeight ? tableOffsetTop - ( wo.cssStickyHeaders_addCaption ? captionHeight : 0 ) : tableOffsetTop, + + // Detect nested tables - fixes #724 + deltaY = top - offsetTop + nestedStickyBottom + borderTopWidth + ( wo.cssStickyHeaders_offset || 0 ) - + ( wo.cssStickyHeaders_addCaption ? ( addCaptionHeight ? captionHeight : 0 ) : captionHeight ), + + finalY = deltaY > 0 && deltaY <= bottom ? deltaY : 0, + + // All IE (even IE11) can only transform header cells - fixes #447 thanks to @gakreol! + $cells = isIE ? $thead.children().children() : $thead; + + // more crazy IE stuff... + if (isIE) { + // I didn't bother testing 3 nested tables deep in IE, because I hate it + c.$table.data( 'cssStickyHeaderBottom', ( $parentThead.length ? parentTheadHeight : 0 ) - + ( wo.cssStickyHeaders_addCaption ? captionHeight : 0 ) ); + } + + if (wo.cssStickyHeaders_addCaption) { + $cells = $cells.add($caption); + } + if (lastCaptionSetting !== wo.cssStickyHeaders_addCaption) { + lastCaptionSetting = wo.cssStickyHeaders_addCaption; + // reset caption position if addCaption option is dynamically changed to false + if (!lastCaptionSetting) { + setTransform( $caption, 0 ); + } + } + + setTransform( $cells, finalY ); + + }); + $table + .unbind( ('filterEnd' + namespace).replace(/\s+/g, ' ') ) + .bind('filterEnd' + namespace, function() { + if (wo.cssStickyHeaders_filteredToTop) { + // scroll top of table into view + window.scrollTo(0, $table.position().top); + } + }); + + }, + remove: function(table, c, wo, refreshing) { + if (refreshing) { return; } + var namespace = c.namespace + 'cssstickyheader '; + $(window).unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') ); + c.$table + .unbind( ('filterEnd scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') ) + .add( c.$table.children('thead').children().children() ) + .children('thead, caption').css({ + 'transform' : '', + '-ms-transform' : '', + '-webkit-transform' : '' + }); + } + }); + +})(jQuery, window); diff --git a/js/widgets/widget-editable.js b/js/widgets/widget-editable.js new file mode 100644 index 0000000..a0d519a --- /dev/null +++ b/js/widgets/widget-editable.js @@ -0,0 +1,282 @@ +/*! Widget: editable - updated 5/17/2015 (v2.22.0) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;( function( $ ){ + 'use strict'; + +var tse = $.tablesorter.editable = { + namespace : '.tseditable', + // last edited class name + lastEdited: 'tseditable-last-edited-cell', + + editComplete: function( c, wo, $cell, refocus ) { + $cell + .removeClass( tse.lastEdited ) + .trigger( wo.editable_editComplete, [ c ] ); + // restore focus last cell after updating + if ( refocus ) { + setTimeout( function() { + $cell.focus(); + }, 50 ); + } + }, + + selectAll: function( cell ) { + setTimeout( function() { + // select all text in contenteditable + // see http://stackoverflow.com/a/6150060/145346 + var range, selection; + if ( document.body.createTextRange ) { + range = document.body.createTextRange(); + range.moveToElementText( cell ); + range.select(); + } else if ( window.getSelection ) { + selection = window.getSelection(); + range = document.createRange(); + range.selectNodeContents( cell ); + selection.removeAllRanges(); + selection.addRange( range ); + } + }, 100 ); + }, + + getColumns : function( c, wo ) { + var indx, tmp, + colIndex = [], + cols = []; + if ( !wo.editable_columnsArray && $.type( wo.editable_columns ) === 'string' && wo.editable_columns.indexOf( '-' ) >= 0 ) { + // editable_columns can contain a range string ( i.e. '2-4' ) + tmp = wo.editable_columns.split( /\s*-\s*/ ); + indx = parseInt( tmp[ 0 ], 10 ) || 0; + tmp = parseInt( tmp[ 1 ], 10 ) || ( c.columns - 1 ); + if ( tmp > c.columns ) { + tmp = c.columns - 1; + } + for ( ; indx <= tmp; indx++ ) { + colIndex.push( indx ); + cols.push( 'td:nth-child(' + ( indx + 1 ) + ')' ); + } + } else if ( $.isArray( wo.editable_columns ) ) { + $.each( wo.editable_columnsArray || wo.editable_columns, function( i, col ) { + if ( col < c.columns ) { + colIndex.push( col ); + cols.push( 'td:nth-child(' + ( col + 1 ) + ')' ); + } + }); + } + if ( !wo.editable_columnsArray ) { + wo.editable_columnsArray = colIndex; + wo.editable_columnsArray.sort(function(a,b){ return a - b; }); + } + return cols; + }, + + update: function( c, wo ) { + var $t, + tmp = $( '
    ' ).wrapInner( wo.editable_wrapContent ).children().length || $.isFunction( wo.editable_wrapContent ), + cols = tse.getColumns( c, wo ).join( ',' ); + + // turn off contenteditable to allow dynamically setting the wo.editable_noEdit + // class on table cells - see issue #900 + c.$tbodies.find( cols ).find( '[contenteditable]' ).prop( 'contenteditable', false ); + + // IE does not allow making TR/TH/TD cells directly editable ( issue #404 ) + // so add a div or span inside ( it's faster than using wrapInner() ) + c.$tbodies.find( cols ).not( '.' + wo.editable_noEdit ).each( function() { + // test for children, if they exist, then make the children editable + $t = $( this ); + + if ( tmp && $t.children( 'div, span' ).length === 0 ) { + $t.wrapInner( wo.editable_wrapContent ); + } + if ( $t.children( 'div, span' ).length ) { + // make div/span children content editable + $t.children( 'div, span' ).not( '.' + wo.editable_noEdit ).each( function() { + var $this = $( this ); + if ( wo.editable_trimContent ) { + $this.html( function( i, txt ) { + return $.trim( txt ); + }); + } + $this.prop( 'contenteditable', true ); + }); + } else { + if ( wo.editable_trimContent ) { + $t.html( function( i, txt ) { + return $.trim( txt ); + }); + } + $t.prop( 'contenteditable', true ); + } + }); + }, + + bindEvents: function( c, wo ) { + var namespace = tse.namespace; + c.$table + .off( ( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ) ) + .on( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ), function() { + tse.update( c, c.widgetOptions ); + }) + // prevent sort initialized by user click on the header from changing the row indexing before + // updateCell can finish processing the change + .children( 'thead' ) + .add( $( c.namespace + '_extra_table' ).children( 'thead' ) ) + .off( 'mouseenter' + namespace ) + .on( 'mouseenter' + namespace, function() { + if ( c.$table.data( 'contentFocused' ) ) { + // change to 'true' instead of element to allow focusout to process + c.$table.data( 'contentFocused', true ); + $( ':focus' ).trigger( 'focusout' ); + } + }); + + c.$tbodies + .off( ( 'focus blur focusout keydown '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ) ) + .on( 'focus' + namespace, '[contenteditable]', function( e ) { + clearTimeout( $( this ).data( 'timer' ) ); + c.$table.data( 'contentFocused', e.target ); + var $this = $( this ), + selAll = wo.editable_selectAll, + column = $this.closest( 'td' ).index(), + txt = $this.html(); + if ( wo.editable_trimContent ) { + txt = $.trim( txt ); + } + // prevent enter from adding into the content + $this + .off( 'keydown' + namespace ) + .on( 'keydown' + namespace, function( e ){ + if ( wo.editable_enterToAccept && e.which === 13 ) { + e.preventDefault(); + } + }); + $this.data({ before : txt, original: txt }); + + if ( typeof wo.editable_focused === 'function' ) { + wo.editable_focused( txt, column, $this ); + } + + if ( selAll ) { + if ( typeof selAll === 'function' ) { + if ( selAll( txt, column, $this ) ) { + tse.selectAll( $this[0] ); + } + } else { + tse.selectAll( $this[0] ); + } + } + }) + .on( 'blur focusout keydown '.split( ' ' ).join( namespace + ' ' ), '[contenteditable]', function( e ) { + if ( !c.$table.data( 'contentFocused' ) ) { return; } + var t, validate, + valid = false, + $this = $( e.target ), + txt = $this.html(), + column = $this.closest( 'td' ).index(); + if ( wo.editable_trimContent ) { + txt = $.trim( txt ); + } + if ( e.which === 27 ) { + // user cancelled + $this.html( $this.data( 'original' ) ).trigger( 'blur' + namespace ); + c.$table.data( 'contentFocused', false ); + return false; + } + // accept on enter ( if set ), alt-enter ( always ) or if autoAccept is set and element is blurred or unfocused + t = e.which === 13 && ( wo.editable_enterToAccept || e.altKey ) || wo.editable_autoAccept && e.type !== 'keydown'; + // change if new or user hits enter ( if option set ) + if ( t && $this.data( 'before' ) !== txt ) { + + validate = wo.editable_validate; + valid = txt; + + if ( typeof( validate ) === 'function' ) { + valid = validate( txt, $this.data( 'original' ), column, $this ); + } else if ( typeof ( validate = $.tablesorter.getColumnData( c.table, validate, column ) ) === 'function' ) { + valid = validate( txt, $this.data( 'original' ), column, $this ); + } + + if ( t && valid !== false ) { + c.$table.find( '.' + tse.lastEdited ).removeClass( tse.lastEdited ); + $this + .addClass( tse.lastEdited ) + .html( valid ) + .data( 'before', valid ) + .data( 'original', valid ) + .trigger( 'change' ); + c.$table.trigger( 'updateCell', [ $this.closest( 'td' ), false, function() { + if ( wo.editable_autoResort ) { + setTimeout( function() { + c.$table.trigger( 'sorton', [ c.sortList, function() { + tse.editComplete( c, wo, c.$table.find( '.' + tse.lastEdited ), true ); + }, true ] ); + }, 10 ); + } else { + tse.editComplete( c, wo, c.$table.find( '.' + tse.lastEdited ) ); + } + } ] ); + return false; + } + } else if ( !valid && e.type !== 'keydown' ) { + clearTimeout( $this.data( 'timer' ) ); + $this.data( 'timer', setTimeout( function() { + if ( $.isFunction( wo.editable_blur ) ) { + txt = $this.html(); + wo.editable_blur( wo.editable_trimContent ? $.trim( txt ) : txt, column, $this ); + } + }, 100 ) ); + // restore original content on blur + $this.html( $this.data( 'original' ) ); + } + }); + }, + destroy : function( c, wo ) { + var namespace = tse.namespace, + cols = tse.getColumns( c, wo ), + + tmp = ( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ); + c.$table.off( tmp ); + + tmp = ( 'focus blur focusout keydown '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ); + c.$tbodies + .off( tmp ) + .find( cols.join( ',' ) ) + .find( '[contenteditable]' ) + .prop( 'contenteditable', false ); + } + +}; + + $.tablesorter.addWidget({ + id: 'editable', + options : { + editable_columns : [], + editable_enterToAccept : true, + editable_autoAccept : true, + editable_autoResort : false, + editable_wrapContent : '
    ', // wrap the cell content... makes this widget work in IE, and with autocomplete + editable_trimContent : true, // trim content inside of contenteditable ( remove tabs & carriage returns ) + editable_validate : null, // function( text, originalText ){ return text; } + editable_focused : null, // function( text, columnIndex, $element ) {} + editable_blur : null, // function( text, columnIndex, $element ) { } + editable_selectAll : false, // true/false or function( text, columnIndex, $element ) { return true; } + editable_noEdit : 'no-edit', + editable_editComplete : 'editComplete' + }, + init: function( table, thisWidget, c, wo ){ + if ( !wo.editable_columns.length ) { return; } + tse.update( c, wo ); + tse.bindEvents( c, wo ); + }, + remove : function( table, c, wo, refreshing ) { + if ( !refreshing ) { + tse.destroy( c, wo ) ; + } + } + }); + +})( jQuery ); diff --git a/js/widgets/widget-filter-formatter-html5.js b/js/widgets/widget-filter-formatter-html5.js new file mode 100644 index 0000000..1c5e303 --- /dev/null +++ b/js/widgets/widget-filter-formatter-html5.js @@ -0,0 +1,429 @@ +/*! Widget: filter, html5 formatter functions - updated 7/17/2014 (v2.17.5) *//* + * requires: tableSorter (FORK) 2.15+ and jQuery 1.4.3+ + * + * html5Number (spinner) + * html5Range (slider) + * html5Color (color) + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; + +var ts = $.tablesorter || {}, + +// compare option selector class name (jQuery selector) +compareSelect = '.compare-select', + + +tsff = ts.filterFormatter = $.extend( {}, ts.filterFormatter, { + + addCompare: function($cell, indx, options){ + if (options.compare && $.isArray(options.compare) && options.compare.length > 1) { + var opt = '', + compareSelectClass = [ compareSelect.slice(1), ' ' + compareSelect.slice(1), '' ], + txt = options.cellText ? '' : ''; + $.each(options.compare, function(i, c){ + opt += ''; + }); + $cell + .wrapInner('
    ') + .prepend( txt + '').appendTo($cell), + // test if HTML5 number is supported - from Modernizr + numberSupported = o.skipTest || $number.attr('type') === 'number' && $number.val() !== 'test', + $shcell = [], + c = $cell.closest('table')[0].config, + + updateNumber = function(delayed, notrigger){ + var chkd = o.addToggle ? $cell.find('.toggle').is(':checked') : true, + v = $cell.find('.number').val(), + compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '', + searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true; + $input + // add equal to the beginning, so we filter exact numbers + .val( !o.addToggle || chkd ? (compare ? compare : o.exactMatch ? '=' : '') + v : '' ) + .trigger( notrigger ? '' : 'search', searchType ).end() + .find('.number').val(v); + if ($cell.find('.number').length) { + $cell.find('.number')[0].disabled = (o.disabled || !chkd); + } + // update sticky header cell + if ($shcell.length) { + $shcell.find('.number').val(v)[0].disabled = (o.disabled || !chkd); + $shcell.find(compareSelect).val(compare); + if (o.addToggle) { + $shcell.find('.toggle')[0].checked = chkd; + } + } + }; + $number.remove(); + + if (numberSupported) { + t = o.addToggle ? '
    ' + + '
    ' : ''; + t += ''; + // add HTML5 number (spinner) + $cell + .append(t + '') + .find('.toggle, .number').bind('change', function(){ + updateNumber(); + }) + .closest('thead').find('th[data-column=' + indx + ']') + .addClass('filter-parsed') // get exact numbers from column + // on reset + .closest('table').bind('filterReset', function(){ + if ($.isArray(o.compare)) { + $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] ); + } + // turn off the toggle checkbox + if (o.addToggle) { + $cell.find('.toggle')[0].checked = false; + if ($shcell.length) { + $shcell.find('.toggle')[0].checked = false; + } + } + $cell.find('.number').val( o.value ); + setTimeout(function(){ + updateNumber(); + }, 0); + }); + $input = $cell.find('input[type=hidden]').bind('change', function(){ + $cell.find('.number').val( this.value ); + updateNumber(); + }); + + // update slider from hidden input, in case of saved filters + c.$table.bind('filterFomatterUpdate', function(){ + var val = tsff.updateCompare($cell, $input, o)[0] || o.value; + $cell.find('.number').val( ((val || '') + '').replace(/[><=]/g,'') ); + updateNumber(false, true); + ts.filter.formatterUpdated($cell, indx); + }); + + if (o.compare) { + // add compare select + tsff.addCompare($cell, indx, o); + $cell.find(compareSelect).bind('change', function(){ + updateNumber(); + }); + } + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + $shcell + .append(t) + .find('.toggle, .number').bind('change', function(){ + $cell.find('.number').val( $(this).val() ); + updateNumber(); + }); + + if (o.compare) { + // add compare select + tsff.addCompare($shcell, indx, o); + $shcell.find(compareSelect).bind('change', function(){ + $cell.find(compareSelect).val( $(this).val() ); + updateNumber(); + }); + } + + updateNumber(); + }); + + updateNumber(); + + } + + return numberSupported ? $cell.find('input[type="hidden"]') : $(''); + }, + + /**********************\ + HTML5 range slider + \**********************/ + html5Range : function($cell, indx, def5Range) { + var o = $.extend({ + value : 0, + min : 0, + max : 100, + step : 1, + delayed : true, + valueToHeader : true, + exactMatch : true, + cellText : '', + compare : '', + allText : 'all', + skipTest : false + }, def5Range), + + $input, + // test browser for HTML5 range support + $range = $('').appendTo($cell), + // test if HTML5 range is supported - from Modernizr (but I left out the method to detect in Safari 2-4) + // see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/inputtypes.js + rangeSupported = o.skipTest || $range.attr('type') === 'range' && $range.val() !== 'test', + $shcell = [], + c = $cell.closest('table')[0].config, + + updateRange = function(v, delayed, notrigger){ + /*jshint eqeqeq:false */ + // hidden input changes may include compare symbols + v = ( typeof v === "undefined" ? $input.val() : v ).toString().replace(/[<>=]/g,'') || o.value; + var compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '', + t = ' (' + (compare ? compare + v : v == o.min ? o.allText : v) + ')', + searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true; + $cell.find('input[type=hidden]') + // add equal to the beginning, so we filter exact numbers + .val( ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) ) ) + //( val == o.min ? '' : val + (o.exactMatch ? '=' : '')) + .trigger( notrigger ? '' : 'search', searchType ).end() + .find('.range').val(v); + // or add current value to the header cell, if desired + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t); + // update sticky header cell + if ($shcell.length) { + $shcell + .find('.range').val(v).end() + .find(compareSelect).val( compare ); + $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t); + } + }; + $range.remove(); + + if (rangeSupported) { + // add HTML5 range + $cell + .html('') + .closest('thead').find('th[data-column=' + indx + ']') + .addClass('filter-parsed') // get exact numbers from column + // add span to header for the current slider value + .find('.tablesorter-header-inner').append(''); + // hidden filter update namespace trigger by filter widget + $input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){ + /*jshint eqeqeq:false */ + var v = this.value, + compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || ''; + if (v !== this.lastValue) { + this.lastValue = ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) ); + this.value = this.lastValue; + updateRange( v ); + } + }); + + $cell.find('.range').bind('change', function(){ + updateRange( this.value ); + }); + + // update spinner from hidden input, in case of saved filters + c.$table.bind('filterFomatterUpdate', function(){ + var val = tsff.updateCompare($cell, $input, o)[0]; + $cell.find('.range').val( val ); + updateRange(val, false, true); + ts.filter.formatterUpdated($cell, indx); + }); + + if (o.compare) { + // add compare select + tsff.addCompare($cell, indx, o); + $cell.find(compareSelect).bind('change', function(){ + updateRange(); + }); + } + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + $shcell + .html('') + .find('.range').bind('change', function(){ + updateRange( $shcell.find('.range').val() ); + }); + updateRange(); + + if (o.compare) { + // add compare select + tsff.addCompare($shcell, indx, o); + $shcell.find(compareSelect).bind('change', function(){ + $cell.find(compareSelect).val( $(this).val() ); + updateRange(); + }); + } + + }); + + // on reset + $cell.closest('table').bind('filterReset', function(){ + if ($.isArray(o.compare)) { + $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] ); + } + setTimeout(function(){ + updateRange(o.value, false, true); + }, 0); + }); + updateRange(); + + } + + return rangeSupported ? $cell.find('input[type="hidden"]') : $(''); + }, + + /**********************\ + HTML5 Color picker + \**********************/ + html5Color: function($cell, indx, defColor) { + var t, o = $.extend({ + value : '#000000', + disabled : false, + addToggle : true, + exactMatch : true, + valueToHeader : false, + skipTest : false + }, defColor), + $input, + // Add a hidden input to hold the range values + $color = $('').appendTo($cell), + // test if HTML5 color is supported - from Modernizr + colorSupported = o.skipTest || $color.attr('type') === 'color' && $color.val() !== 'test', + $shcell = [], + c = $cell.closest('table')[0].config, + + updateColor = function(v, notrigger){ + v = ( typeof v === "undefined" ? $input.val() : v ).toString().replace('=','') || o.value; + var chkd = true, + t = ' (' + v + ')'; + if (o.addToggle) { + chkd = $cell.find('.toggle').is(':checked'); + } + if ($cell.find('.colorpicker').length) { + $cell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd); + } + + $input + .val( chkd ? v + (o.exactMatch ? '=' : '') : '' ) + .trigger( !c.$table[0].hasInitialized || notrigger ? '' : 'search' ); + if (o.valueToHeader) { + // add current color to the header cell + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t); + } else { + // current color to span in cell + $cell.find('.currentColor').html(t); + } + + // update sticky header cell + if ($shcell.length) { + $shcell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd); + if (o.addToggle) { + $shcell.find('.toggle')[0].checked = chkd; + } + if (o.valueToHeader) { + // add current color to the header cell + $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t); + } else { + // current color to span in cell + $shcell.find('.currentColor').html(t); + } + } + }; + $color.remove(); + + if (colorSupported) { + t = '' + indx + Math.round(Math.random() * 100); + // add HTML5 color picker + t = '
    ' + + (o.addToggle ? '
    ' : '') + + '' + + (o.valueToHeader ? '' : '(#000000)') + '
    '; + $cell.html(t); + // add span to header for the current color value - only works if the line in the updateColor() function is also un-commented out + if (o.valueToHeader) { + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append(''); + } + + $cell.find('.toggle, .colorpicker').bind('change', function(){ + updateColor( $cell.find('.colorpicker').val() ); + }); + + // hidden filter update namespace trigger by filter widget + $input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){ + updateColor( this.value ); + }); + + // update slider from hidden input, in case of saved filters + c.$table.bind('filterFomatterUpdate', function(){ + updateColor( $input.val(), true ); + ts.filter.formatterUpdated($cell, indx); + }); + + // on reset + $cell.closest('table').bind('filterReset', function(){ + // just turn off the colorpicker + if (o.addToggle) { + $cell.find('.toggle')[0].checked = false; + } + // delay needed because default color needs to be set in the filter + // there is no compare option here, so if addToggle = false, + // default color is #000000 (even with no value set) + setTimeout(function(){ + updateColor(); + }, 0); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx); + $shcell + .html(t) + .find('.toggle, .colorpicker').bind('change', function(){ + updateColor( $shcell.find('.colorpicker').val() ); + }); + updateColor( $shcell.find('.colorpicker').val() ); + }); + + updateColor( o.value ); + } + return colorSupported ? $cell.find('input[type="hidden"]') : $(''); + } + +}); + +})(jQuery); diff --git a/js/widgets/widget-filter-formatter-jui.js b/js/widgets/widget-filter-formatter-jui.js new file mode 100644 index 0000000..00ee461 --- /dev/null +++ b/js/widgets/widget-filter-formatter-jui.js @@ -0,0 +1,764 @@ +/*! Widget: filter jQuery UI formatter functions - updated 7/17/2014 (v2.17.5) *//* + * requires: tableSorter (FORK) 2.15+ and jQuery 1.4.3+ + * + * uiSpinner (jQuery UI spinner) + * uiSlider (jQuery UI slider) + * uiRange (jQuery UI range slider) + * uiDateCompare (jQuery UI datepicker; 1 input) + * uiDatepicker (jQuery UI datepicker; 2 inputs, filter range) + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; + +var ts = $.tablesorter || {}, + +// compare option selector class name (jQuery selector) +compareSelect = '.compare-select', + +tsff = ts.filterFormatter = $.extend( {}, ts.filterFormatter, { + + addCompare: function($cell, indx, options){ + if (options.compare && $.isArray(options.compare) && options.compare.length > 1) { + var opt = '', + compareSelectClass = [ compareSelect.slice(1), ' ' + compareSelect.slice(1), '' ], + txt = options.cellText ? '' : ''; + $.each(options.compare, function(i, c){ + opt += ''; + }); + $cell + .wrapInner('
    ') + .prepend( txt + '') + .appendTo($cell) + // hidden filter update namespace trigger by filter widget + .bind('change' + c.namespace + 'filter', function(){ + updateSpinner({ value: this.value, delayed: false }); + }), + $shcell = [], + + // this function updates the hidden input and adds the current values to the header cell text + updateSpinner = function(ui, notrigger) { + var chkd = true, state, + // ui is not undefined on create + v = ui && ui.value && ts.formatFloat((ui.value + '').replace(/[><=]/g,'')) || + $cell.find('.spinner').val() || o.value, + compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '', + searchType = ui && typeof ui.delayed === 'boolean' ? ui.delayed : c.$table[0].hasInitialized ? o.delayed || '' : true; + if (o.addToggle) { + chkd = $cell.find('.toggle').is(':checked'); + } + state = o.disabled || !chkd ? 'disable' : 'enable'; + $cell.find('.filter') + // add equal to the beginning, so we filter exact numbers + .val( chkd ? (compare ? compare : o.exactMatch ? '=' : '') + v : '' ) + .trigger( notrigger ? '' : 'search', searchType ).end() + .find('.spinner').spinner(state).val(v); + // update sticky header cell + if ($shcell.length) { + $shcell + .find('.spinner').spinner(state).val(v).end() + .find(compareSelect).val( compare ); + if (o.addToggle) { + $shcell.find('.toggle')[0].checked = chkd; + } + } + }; + + // add callbacks; preserve added callbacks + o.oldcreate = o.create; + o.oldspin = o.spin; + o.create = function(event, ui) { + updateSpinner(); // ui is an empty object on create + if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); } + }; + o.spin = function(event, ui) { + updateSpinner(ui); + if (typeof o.oldspin === 'function') { o.oldspin(event, ui); } + }; + if (o.addToggle) { + $('
    ' + + '
    ') + .appendTo($cell) + .find('.toggle') + .bind('change', function(){ + updateSpinner(); + }); + } + // make sure we use parsed data + $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'); + // add a jQuery UI spinner! + $('') + .val(o.value) + .appendTo($cell) + .spinner(o) + .bind('change keyup', function(){ + updateSpinner(); + }); + + // update spinner from hidden input, in case of saved filters + c.$table.bind('filterFomatterUpdate', function(){ + var val = tsff.updateCompare($cell, $input, o)[0]; + $cell.find('.spinner').val( val ); + updateSpinner({ value: val }, true); + ts.filter.formatterUpdated($cell, indx); + }); + + if (o.compare) { + // add compare select + tsff.addCompare($cell, indx, o); + $cell.find(compareSelect).bind('change', function(){ + updateSpinner(); + }); + } + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + if (o.addToggle) { + $('
    ' + + '
    ') + .appendTo($shcell) + .find('.toggle') + .bind('change', function(){ + $cell.find('.toggle')[0].checked = this.checked; + updateSpinner(); + }); + } + // add a jQuery UI spinner! + $('') + .val(o.value) + .appendTo($shcell) + .spinner(o) + .bind('change keyup', function(){ + $cell.find('.spinner').val( this.value ); + updateSpinner(); + }); + + if (o.compare) { + // add compare select + tsff.addCompare($shcell, indx, o); + $shcell.find(compareSelect).bind('change', function(){ + $cell.find(compareSelect).val( $(this).val() ); + updateSpinner(); + }); + } + + }); + + // on reset + c.$table.bind('filterReset', function(){ + if ($.isArray(o.compare)) { + $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] ); + } + // turn off the toggle checkbox + if (o.addToggle) { + $cell.find('.toggle')[0].checked = false; + } + $cell.find('.spinner').spinner('value', o.value); + setTimeout(function(){ + updateSpinner(); + }, 0); + }); + + updateSpinner(); + return $input; + }, + + /**********************\ + jQuery UI Slider + \**********************/ + uiSlider: function($cell, indx, sliderDef) { + var o = $.extend({ + // filter formatter options + delayed : true, + valueToHeader : false, + exactMatch : true, + cellText : '', + compare : '', + allText : 'all', + // include ANY jQuery UI spinner options below + // except values, since this is a non-range setup + value : 0, + min : 0, + max : 100, + step : 1, + range : "min" + }, sliderDef ), + c = $cell.closest('table')[0].config, + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update namespace trigger by filter widget + .bind('change' + c.namespace + 'filter', function(){ + updateSlider({ value: this.value }); + }), + $shcell = [], + + // this function updates the hidden input and adds the current values to the header cell text + updateSlider = function(ui, notrigger) { + // ui is not undefined on create + var v = typeof ui !== "undefined" ? ts.formatFloat((ui.value + '').replace(/[><=]/g,'')) || o.value : o.value, + val = o.compare ? v : v === o.min ? o.allText : v, + compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '', + result = compare + val, + searchType = ui && typeof ui.delayed === 'boolean' ? ui.delayed : c.$table[0].hasInitialized ? o.delayed || '' : true; + if (o.valueToHeader) { + // add range indication to the header cell above! + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')'); + } else { + // add values to the handle data-value attribute so the css tooltip will work properly + $cell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result); + } + // update the hidden input; + // ****** ADD AN EQUAL SIGN TO THE BEGINNING! <- this makes the slide exactly match the number ****** + // when the value is at the minimum, clear the hidden input so all rows will be seen + + $cell.find('.filter') + .val( ( compare ? compare + v : v === o.min ? '' : (o.exactMatch ? '=' : '') + v ) ) + .trigger( notrigger ? '' : 'search', searchType ).end() + .find('.slider').slider('value', v); + + // update sticky header cell + if ($shcell.length) { + $shcell + .find(compareSelect).val( compare ).end() + .find('.slider').slider('value', v); + if (o.valueToHeader) { + $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')'); + } else { + $shcell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result); + } + } + + }; + $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'); + + // add span to header for value - only works if the line in the updateSlider() function is also un-commented out + if (o.valueToHeader) { + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append(''); + } + + // add callbacks; preserve added callbacks + o.oldcreate = o.create; + o.oldslide = o.slide; + o.create = function(event, ui) { + updateSlider(); // ui is an empty object on create + if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); } + }; + o.slide = function(event, ui) { + updateSlider(ui); + if (typeof o.oldslide === 'function') { o.oldslide(event, ui); } + }; + // add a jQuery UI slider! + $('
    ') + .appendTo($cell) + .slider(o); + + // update slider from hidden input, in case of saved filters + c.$table.bind('filterFomatterUpdate', function(){ + var val = tsff.updateCompare($cell, $input, o)[0]; + $cell.find('.slider').slider('value', val ); + updateSlider({ value: val }, false); + ts.filter.formatterUpdated($cell, indx); + }); + + if (o.compare) { + // add compare select + tsff.addCompare($cell, indx, o); + $cell.find(compareSelect).bind('change', function(){ + updateSlider({ value: $cell.find('.slider').slider('value') }); + }); + } + + // on reset + c.$table.bind('filterReset', function(){ + if ($.isArray(o.compare)) { + $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] ); + } + setTimeout(function(){ + updateSlider({ value: o.value }); + }, 0); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + + // add a jQuery UI slider! + $('
    ') + .val(o.value) + .appendTo($shcell) + .slider(o) + .bind('change keyup', function(){ + $cell.find('.slider').slider('value', this.value ); + updateSlider(); + }); + + if (o.compare) { + // add compare select + tsff.addCompare($shcell, indx, o); + $shcell.find(compareSelect).bind('change', function(){ + $cell.find(compareSelect).val( $(this).val() ); + updateSlider(); + }); + } + + }); + + return $input; + }, + + /*************************\ + jQuery UI Range Slider (2 handles) + \*************************/ + uiRange: function($cell, indx, rangeDef) { + var o = $.extend({ + // filter formatter options + delayed : true, + valueToHeader : false, + // include ANY jQuery UI spinner options below + // except value, since this one is range specific) + values : [0, 100], + min : 0, + max : 100, + range : true + }, rangeDef ), + c = $cell.closest('table')[0].config, + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update namespace trigger by filter widget + .bind('change' + c.namespace + 'filter', function(){ + getRange(); + }), + $shcell = [], + + getRange = function(){ + var val = $input.val(), + v = val.split(' - '); + if (val === '') { v = [ o.min, o.max ]; } + if (v && v[1]) { + updateUiRange({ values: v, delay: false }, true); + } + }, + + // this function updates the hidden input and adds the current values to the header cell text + updateUiRange = function(ui, notrigger) { + // ui.values are undefined for some reason on create + var val = ui && ui.values || o.values, + result = val[0] + ' - ' + val[1], + // make range an empty string if entire range is covered so the filter row will hide (if set) + range = val[0] === o.min && val[1] === o.max ? '' : result, + searchType = ui && typeof ui.delayed === 'boolean' ? ui.delayed : c.$table[0].hasInitialized ? o.delayed || '': true; + if (o.valueToHeader) { + // add range indication to the header cell above (if not using the css method)! + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')'); + } else { + // add values to the handle data-value attribute so the css tooltip will work properly + $cell.find('.ui-slider-handle') + .addClass('value-popup') + .eq(0).attr('data-value', val[0]).end() // adding value to data attribute + .eq(1).attr('data-value', val[1]); // value popup shown via css + } + // update the hidden input + $cell.find('.filter').val(range) + .trigger(notrigger ? '' : 'search', searchType).end() + .find('.range').slider('values', val); + // update sticky header cell + if ($shcell.length) { + $shcell.find('.range').slider('values', val); + if (o.valueToHeader) { + $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')'); + } else { + $shcell.find('.ui-slider-handle') + .addClass('value-popup') + .eq(0).attr('data-value', val[0]).end() // adding value to data attribute + .eq(1).attr('data-value', val[1]); // value popup shown via css + } + } + + }; + $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'); + + // add span to header for value - only works if the line in the updateUiRange() function is also un-commented out + if (o.valueToHeader) { + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append(''); + } + + // add callbacks; preserve added callbacks + o.oldcreate = o.create; + o.oldslide = o.slide; + // add a jQuery UI range slider! + o.create = function(event, ui) { + updateUiRange(); // ui is an empty object on create + if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); } + }; + o.slide = function(event, ui) { + updateUiRange(ui); + if (typeof o.oldslide === 'function') { o.oldslide(event, ui); } + }; + $('
    ') + .appendTo($cell) + .slider(o); + + // update slider from hidden input, in case of saved filters + c.$table.bind('filterFomatterUpdate', function(){ + getRange(); + ts.filter.formatterUpdated($cell, indx); + }); + + // on reset + c.$table.bind('filterReset', function(){ + $cell.find('.range').slider('values', o.values); + setTimeout(function(){ + updateUiRange(); + }, 0); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + + // add a jQuery UI slider! + $('
    ') + .val(o.value) + .appendTo($shcell) + .slider(o) + .bind('change keyup', function(){ + $cell.find('.range').val( this.value ); + updateUiRange(); + }); + + }); + + // return the hidden input so the filter widget has a reference to it + return $input; + }, + + /*************************\ + jQuery UI Datepicker compare (1 input) + \*************************/ + uiDateCompare: function($cell, indx, defDate) { + var o = $.extend({ + // filter formatter options + cellText : '', + compare : '', + endOfDay : true, + // include ANY jQuery UI spinner options below + + defaultDate : '', + + changeMonth : true, + changeYear : true, + numberOfMonths : 1 + }, defDate), + + $date, + c = $cell.closest('table')[0].config, + // make sure we're using parsed dates in the search + $hdr = $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'), + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update namespace trigger by filter widget + .bind('change' + c.namespace + 'filter', function(){ + var v = this.value; + if (v) { + o.onClose(v); + } + }), + t, $shcell = [], + + // this function updates the hidden input + date1Compare = function(notrigger) { + var date, query, + getdate = $date.datepicker('getDate') || '', + compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '', + searchType = c.$table[0].hasInitialized ? o.delayed || '': true; + $date.datepicker('setDate', (getdate === '' ? '' : getdate) || null); + if (getdate === '') { notrigger = false; } + date = $date.datepicker('getDate'); + query = date ? ( o.endOfDay && /<=/.test(compare) ? date.setHours(23, 59, 59) : date.getTime() ) || '' : ''; + if (date && o.endOfDay && compare === '=') { + compare = ''; + query += ' - ' + date.setHours(23, 59, 59); + notrigger = false; + } + $cell.find('.dateCompare') + // add equal to the beginning, so we filter exact numbers + .val(compare + query) + .trigger( notrigger ? '' : 'search', searchType ).end(); + // update sticky header cell + if ($shcell.length) { + $shcell + .find('.dateCompare').val(compare + query).end() + .find(compareSelect).val(compare); + } + }; + + // Add date range picker + t = ''; + $date = $(t).appendTo($cell); + + // add callbacks; preserve added callbacks + o.oldonClose = o.onClose; + + o.onClose = function( selectedDate, ui ) { + date1Compare(); + if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); } + }; + $date.datepicker(o); + + // on reset + c.$table.bind('filterReset', function(){ + if ($.isArray(o.compare)) { + $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] ); + } + $cell.add($shcell).find('.date').val(o.defaultDate).datepicker('setDate', o.defaultDate || null); + setTimeout(function(){ + date1Compare(); + }, 0); + }); + + // update date compare from hidden input, in case of saved filters + c.$table.bind('filterFomatterUpdate', function(){ + var num, v = $input.val(); + if (/\s+-\s+/.test(v)) { + // date range found; assume an exact match on one day + $cell.find(compareSelect).val('='); + num = v.split(/\s+-\s+/)[0]; + $date.datepicker( 'setDate', num || null ); + } else { + num = (tsff.updateCompare($cell, $input, o)[1]).toString() || ''; + // differeniate 1388556000000 from 1/1/2014 using \d{5} regex + num = num !== '' ? /\d{5}/g.test(num) ? new Date(Number(num)) : num || '' : ''; + } + $cell.add($shcell).find('.date').datepicker( 'setDate', num || null ); + setTimeout(function(){ + date1Compare(true); + ts.filter.formatterUpdated($cell, indx); + }, 0); + }); + + if (o.compare) { + // add compare select + tsff.addCompare($cell, indx, o); + $cell.find(compareSelect).bind('change', function(){ + date1Compare(); + }); + } + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + + // add a jQuery datepicker! + $shcell + .append(t) + .find('.date') + .datepicker(o); + + if (o.compare) { + // add compare select + tsff.addCompare($shcell, indx, o); + $shcell.find(compareSelect).bind('change', function(){ + $cell.find(compareSelect).val( $(this).val() ); + date1Compare(); + }); + } + + }); + + // return the hidden input so the filter widget has a reference to it + return $input.val( o.defaultDate ? o.defaultDate : '' ); + }, + + /*************************\ + jQuery UI Datepicker (2 inputs) + \*************************/ + uiDatepicker: function($cell, indx, defDate) { + var o = $.extend({ + // filter formatter options + endOfDay : true, + textFrom : 'from', + textTo : 'to', + from : '', // defaultDate "from" input + to : '', // defaultDate "to" input + // include ANY jQuery UI spinner options below + changeMonth : true, + changeYear : true, + numberOfMonths : 1 + }, defDate), + t, closeDate, $shcell = [], + c = $cell.closest('table')[0].config, + validDate = function(d){ + return d instanceof Date && isFinite(d); + }, + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update namespace trigger by filter widget + .bind('change' + c.namespace + 'filter', function(){ + var v = this.value; + if (v.match(' - ')) { + v = v.split(' - '); + $cell.find('.dateTo').val(v[1]); + closeDate(v[0]); + } else if (v.match('>=')) { + closeDate( v.replace('>=', '') ); + } else if (v.match('<=')) { + closeDate( v.replace('<=', '') ); + } + }), + + // make sure we're using parsed dates in the search + $hdr = $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'); + // Add date range picker + t = '' + + ''; + $(t).appendTo($cell); + + // add callbacks; preserve added callbacks + o.oldonClose = o.onClose; + + closeDate = o.onClose = function( selectedDate, ui ) { + var range, + from = $cell.find('.dateFrom').datepicker('getDate'), + to = $cell.find('.dateTo').datepicker('getDate'); + from = validDate(from) ? from.getTime() : ''; + to = validDate(to) ? ( o.endOfDay ? to.setHours(23, 59, 59) : to.getTime() ) || '' : ''; + range = from ? ( to ? from + ' - ' + to : '>=' + from ) : (to ? '<=' + to : ''); + $cell.add( $shcell ) + .find('.dateRange').val(range) + .trigger('search'); + // date picker needs date objects + from = from ? new Date(from) : ''; + to = to ? new Date(to) : ''; + + if (/<=/.test(range)) { + $cell.add( $shcell ) + .find('.dateFrom').datepicker('option', 'maxDate', to || null ).end() + .find('.dateTo').datepicker('option', 'minDate', null).datepicker('setDate', to || null); + } else if (/>=/.test(range)) { + $cell.add( $shcell ) + .find('.dateFrom').datepicker('option', 'maxDate', null).datepicker('setDate', from || null).end() + .find('.dateTo').datepicker('option', 'minDate', from || null ); + } else { + $cell.add( $shcell ) + .find('.dateFrom').datepicker('option', 'maxDate', null).datepicker('setDate', from || null ).end() + .find('.dateTo').datepicker('option', 'minDate', null).datepicker('setDate', to || null); + } + + if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); } + }; + + o.defaultDate = o.from || ''; + $cell.find('.dateFrom').datepicker(o); + o.defaultDate = o.to || '+7d'; // set to date +7 days from today (if not defined) + $cell.find('.dateTo').datepicker(o); + + // update date compare from hidden input, in case of saved filters + c.$table.bind('filterFomatterUpdate', function(){ + var val = $input.val() || '', + from = '', + to = ''; + // date range + if (/\s+-\s+/.test(val)){ + val = val.split(/\s+-\s+/) || []; + from = val[0] || ''; + to = val[1] || ''; + } else if (/>=/.test(val)) { + // greater than date (to date empty) + from = val.replace(/>=/, '') || ''; + } else if (/<=/.test(val)) { + // less than date (from date empty) + to = val.replace(/<=/, '') || ''; + } + + // differeniate 1388556000000 from 1/1/2014 using \d{5} regex + from = from !== '' ? /\d{5}/g.test(from) ? new Date(Number(from)) : from || '' : ''; + to = to !== '' ? /\d{5}/g.test(to) ? new Date(Number(to)) : to || '' : ''; + + $cell.add($shcell).find('.dateFrom').datepicker('setDate', from || null); + $cell.add($shcell).find('.dateTo').datepicker('setDate', to || null); + // give datepicker time to process + setTimeout(function(){ + closeDate(); + ts.filter.formatterUpdated($cell, indx); + }, 0); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + $shcell.append(t); + + // add a jQuery datepicker! + o.defaultDate = o.from || ''; + $shcell.find('.dateFrom').datepicker(o); + + o.defaultDate = o.to || '+7d'; + $shcell.find('.dateTo').datepicker(o); + + }); + + // on reset + $cell.closest('table').bind('filterReset', function(){ + $cell.add($shcell).find('.dateFrom').val('').datepicker('setDate', o.from || null ); + $cell.add($shcell).find('.dateTo').val('').datepicker('setDate', o.to || null ); + setTimeout(function(){ + closeDate(); + }, 0); + }); + + // return the hidden input so the filter widget has a reference to it + return $input.val( o.from ? ( o.to ? o.from + ' - ' + o.to : '>=' + o.from ) : (o.to ? '<=' + o.to : '') ); + } + +}); + +})(jQuery); diff --git a/js/widgets/widget-filter-formatter-select2.js b/js/widgets/widget-filter-formatter-select2.js new file mode 100644 index 0000000..ec5d0d3 --- /dev/null +++ b/js/widgets/widget-filter-formatter-select2.js @@ -0,0 +1,149 @@ +/*! Widget: filter, select2 formatter function - updated 3/26/2015 (v2.21.3) *//* + * requires: jQuery 1.7.2+, tableSorter (FORK) 2.16+, filter widget 2.16+ and select2 v3.4.6+ plugin + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; + +var ts = $.tablesorter || {}; +ts.filterFormatter = ts.filterFormatter || {}; + +/************************\ + Select2 Filter Formatter +\************************/ +ts.filterFormatter.select2 = function($cell, indx, select2Def) { + var o = $.extend({ + // select2 filter formatter options + cellText : '', // Text (wrapped in a label element) + match : true, // adds "filter-match" to header + value : '', + // include ANY select2 options below + multiple : true, + width : '100%' + + }, select2Def ), + arry, data, + c = $cell.closest('table')[0].config, + wo = c.widgetOptions, + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update namespace trigger by filter widget + .bind('change' + c.namespace + 'filter', function(){ + var val = this.value; + val = val.replace(/[/()$^]/g, '').split('|'); + $cell.find('.select2').select2('val', val); + updateSelect2(); + }), + $header = c.$headerIndexed[indx], + onlyAvail = $header.hasClass(wo.filter_onlyAvail), + $shcell = [], + matchPrefix = o.match ? '' : '^', + matchSuffix = o.match ? '' : '$', + + // this function updates the hidden input and adds the current values to the header cell text + updateSelect2 = function() { + var arry = false, + v = $cell.find('.select2').select2('val') || o.value || ''; + // convert array to string + if ($.isArray(v)) { + arry = true; + v = v.join('\u0000'); + } + // escape special regex characters (http://stackoverflow.com/a/9310752/145346) + v = v.replace(/[-[\]{}()*+?.,/\\^$|#\s]/g, '\\$&'); + // convert string back into an array + if (arry) { + v = v.split('\u0000'); + } + $input + // add regex, so we filter exact numbers + .val( $.isArray(v) && v.length && v.join('') !== '' ? '/(' + matchPrefix + (v || []).join(matchSuffix + '|' + matchPrefix) + matchSuffix + ')/' : '' ) + .trigger('search').end() + .find('.select2').select2('val', v); + // update sticky header cell + if ($shcell.length) { + $shcell.find('.select2').select2('val', v); + } + }, + + // get options from table cell content or filter_selectSource (v2.16) + updateOptions = function(){ + data = []; + arry = ts.filter.getOptionSource(c.$table[0], indx, onlyAvail) || []; + // build select2 data option + $.each(arry, function(i,v){ + data.push({id: v, text: v}); + }); + o.data = data; + }; + + // get filter-match class from option + $header.toggleClass('filter-match', o.match); + if (o.cellText) { + $cell.prepend(''); + } + + // don't add default in table options if either ajax or + // data options are already defined + if (!(o.ajax && !$.isEmptyObject(o.ajax)) && !o.data) { + updateOptions(); + if (onlyAvail) { + c.$table.bind('filterEnd', function(){ + updateOptions(); + $cell.add($shcell).find('.select2').select2(o); + }); + } + } + + // add a select2 hidden input! + $('') + .val(o.value) + .appendTo($cell) + .select2(o) + .bind('change', function(){ + updateSelect2(); + }); + + // update select2 from filter hidden input, in case of saved filters + c.$table.bind('filterFomatterUpdate', function(){ + // value = '/(^x$|^y$)/' => 'x,y' + var val = c.$table.data('lastSearch')[indx] || ''; + val = val.replace(/^\/\(\^?/,'').replace(/\$\|\^/g, '|').replace(/\$?\)\/$/g,'').split('|'); + $cell.find('.select2').select2('val', val); + updateSelect2(); + ts.filter.formatterUpdated($cell, indx); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + // add a select2! + $('') + .val(o.value) + .appendTo($shcell) + .select2(o) + .bind('change', function(){ + $cell.find('.select2').select2('val', $shcell.find('.select2').select2('val') ); + updateSelect2(); + }); + if (o.cellText) { + $shcell.prepend(''); + } + + }); + + // on reset + c.$table.bind('filterReset', function(){ + $cell.find('.select2').select2('val', o.value || ''); + setTimeout(function(){ + updateSelect2(); + }, 0); + }); + + updateSelect2(); + return $input; +}; + +})(jQuery); diff --git a/js/widgets/widget-filter-type-insideRange.js b/js/widgets/widget-filter-type-insideRange.js new file mode 100644 index 0000000..0bdd37b --- /dev/null +++ b/js/widgets/widget-filter-type-insideRange.js @@ -0,0 +1,39 @@ +/*! Widget: filter, insideRange filter type - updated 2/23/2015 (v2.21.0) */ +;(function($){ +'use strict'; + + // Add insideRange filter type + // ============================ + // This allows you to enter a number (e.g. 8) and show the + // resulting rows that will have that query within it's range + // demo at http://mottie.github.io/tablesorter/docs/example-widget-filter-custom-search2.html + var ts = $.tablesorter, + isDigit = /\d+/, + range = /\s+-\s+/, + parseNumber = function(num) { + return isNaN(num) ? num : parseFloat(num); + }; + + ts.filter.types.insideRange = function( c, data ) { + if ( isDigit.test( data.iFilter ) && range.test( data.iExact ) ) { + var t, val, low, high, + parts = data.iExact.split( range ), + format = c.parsers[data.index].format; + // the cell does not contain a range + if ( parts && parts.length < 2 ) { + return null; + } + // format each side part of the range using the assigned parser + low = parseNumber( format( parts[0], c.table ) ); + high = parseNumber( format( parts[1], c.table ) ); + val = parseNumber( format( data.iFilter, c.table ) ); + if ( high < low ) { + // swap high & low + t = high; high = low; low = t; + } + return low <= val && val <= high; + } + return null; + }; + +})(jQuery); diff --git a/js/widgets/widget-filter.js b/js/widgets/widget-filter.js new file mode 100644 index 0000000..4a5c40e --- /dev/null +++ b/js/widgets/widget-filter.js @@ -0,0 +1,1567 @@ +/*! Widget: filter - updated 5/17/2015 (v2.22.1) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +;( function ( $ ) { +'use strict'; +var ts = $.tablesorter || {}, + tscss = ts.css; + +$.extend( tscss, { + filterRow : 'tablesorter-filter-row', + filter : 'tablesorter-filter', + filterDisabled : 'disabled', + filterRowHide : 'hideme' +}); + +ts.addWidget({ + id: 'filter', + priority: 50, + options : { + filter_childRows : false, // if true, filter includes child row content in the search + filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped + filter_columnFilters : true, // if true, a filter will be added to the top of each table column + filter_columnAnyMatch: true, // if true, allows using '#:{query}' in AnyMatch searches ( column:query ) + filter_cellFilter : '', // css class name added to the filter cell ( string or array ) + filter_cssFilter : '', // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added ) + 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. + filter_excludeFilter : {}, // filters to exclude, per column + filter_external : '', // jQuery selector string ( or jQuery object ) of external filters + filter_filteredRow : 'filtered', // class added to filtered rows; needed by pager plugin + filter_formatter : null, // add custom filter elements to the filter row + filter_functions : null, // add custom filter functions using this option + filter_hideEmpty : true, // hide filter row when table is empty + filter_hideFilters : false, // collapse filter row when mouse leaves the area + filter_ignoreCase : true, // if true, make all searches case-insensitive + filter_liveSearch : true, // if true, search column content while the user types ( with a delay ) + filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down + filter_placeholder : { search : '', select : '' }, // default placeholder text ( overridden by any header 'data-placeholder' setting ) + filter_reset : null, // jQuery selector string of an element used to reset the filters + filter_saveFilters : false, // Use the $.tablesorter.storage utility to save the most recent filters + filter_searchDelay : 300, // typing delay in milliseconds before starting a search + filter_searchFiltered: true, // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true + filter_selectSource : null, // include a function to return an array of values to be added to the column filter select + filter_startsWith : false, // if true, filter start from the beginning of the cell contents + filter_useParsedData : false, // filter all data using parsed content + filter_serversideFiltering : false, // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used. + filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value + filter_selectSourceSeparator : '|' // filter_selectSource array text left of the separator is added to the option value, right into the option text + }, + format: function( table, c, wo ) { + if ( !c.$table.hasClass( 'hasFilters' ) ) { + ts.filter.init( table, c, wo ); + } + }, + remove: function( table, c, wo, refreshing ) { + var tbodyIndex, $tbody, + $table = c.$table, + $tbodies = c.$tbodies, + events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ' + .split( ' ' ).join( c.namespace + 'filter ' ); + $table + .removeClass( 'hasFilters' ) + // add .tsfilter namespace to all BUT search + .unbind( events.replace( /\s+/g, ' ' ) ) + // remove the filter row even if refreshing, because the column might have been moved + .find( '.' + tscss.filterRow ).remove(); + if ( refreshing ) { return; } + for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody + $tbody.children().removeClass( wo.filter_filteredRow ).show(); + ts.processTbody( table, $tbody, false ); // restore tbody + } + if ( wo.filter_reset ) { + $( document ).undelegate( wo.filter_reset, 'click.tsfilter' ); + } + } +}); + +ts.filter = { + + // regex used in filter 'check' functions - not for general use and not documented + regex: { + regex : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex + child : /tablesorter-childRow/, // child row class name; this gets updated in the script + filtered : /filtered/, // filtered (hidden) row class name; updated in the script + type : /undefined|number/, // check type + exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==') + nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser) + operators : /[<>=]/g, // replace operators + query : '(q|query)' // replace filter queries + }, + // function( c, data ) { } + // c = table.config + // data.$row = jQuery object of the row currently being processed + // data.$cells = jQuery object of all cells within the current row + // data.filters = array of filters for all columns ( some may be undefined ) + // data.filter = filter for the current column + // data.iFilter = same as data.filter, except lowercase ( if wo.filter_ignoreCase is true ) + // data.exact = table cell text ( or parsed data if column parser enabled ) + // data.iExact = same as data.exact, except lowercase ( if wo.filter_ignoreCase is true ) + // data.cache = table cell text from cache, so it has been parsed ( & in all lower case if c.ignoreCase is true ) + // data.cacheArray = An array of parsed content from each table cell in the row being processed + // data.index = column index; table = table element ( DOM ) + // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class ) + types: { + // Look for regex + regex: function( c, data ) { + if ( ts.filter.regex.regex.test( data.filter ) ) { + var matches, + // cache regex per column for optimal speed + regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ), + isRegex = regex instanceof RegExp; + try { + if ( !isRegex ) { + // force case insensitive search if ignoreCase option set? + // if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; } + data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] ); + } + matches = regex.test( data.exact ); + } catch ( error ) { + matches = false; + } + return matches; + } + return null; + }, + // Look for operators >, >=, < or <= + operators: function( c, data ) { + // ignore empty strings... because '' < 10 is true + if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) { + var cachedValue, result, txt, + table = c.table, + index = data.index, + parsed = data.parsed[index], + query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ), + parser = c.parsers[index], + savedSearch = query; + // parse filter value in case we're comparing numbers ( dates ) + if ( parsed || parser.type === 'numeric' ) { + txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) ); + result = ts.filter.parseFilter( c, txt, index, true ); + query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query; + } + // iExact may be numeric - see issue #149; + // check if cached is defined, because sometimes j goes out of range? ( numeric columns ) + if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) && + typeof data.cache !== 'undefined' ) { + cachedValue = data.cache; + } else { + txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact; + cachedValue = ts.formatFloat( txt, table ); + } + if ( />/.test( data.iFilter ) ) { + result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query; + } else if ( /= 0 ); + } + } + return null; + }, + // Look for quotes or equals to get an exact match; ignore type since iExact could be numeric + exact: function( c, data ) { + /*jshint eqeqeq:false */ + if ( ts.filter.regex.exact.test( data.iFilter ) ) { + var txt = data.iFilter.replace( ts.filter.regex.exact, '' ), + filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || ''; + return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact; + } + return null; + }, + // Look for an AND or && operator ( logical and ) + and : function( c, data ) { + if ( ts.filter.regex.andTest.test( data.filter ) ) { + var index = data.index, + parsed = data.parsed[index], + query = data.iFilter.split( ts.filter.regex.andSplit ), + result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0, + indx = query.length - 1; + while ( result && indx ) { + result = result && + data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0; + indx--; + } + return result; + } + return null; + }, + // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu! + range : function( c, data ) { + if ( ts.filter.regex.toTest.test( data.iFilter ) ) { + var result, tmp, range1, range2, + table = c.table, + index = data.index, + parsed = data.parsed[index], + // make sure the dash is for a range and not indicating a negative number + query = data.iFilter.split( ts.filter.regex.toSplit ); + + tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || ''; + range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table ); + tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || ''; + range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table ); + // parse filter value in case we're comparing numbers ( dates ) + if ( parsed || c.parsers[index].type === 'numeric' ) { + result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index ); + range1 = ( result !== '' && !isNaN( result ) ) ? result : range1; + result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index ); + range2 = ( result !== '' && !isNaN( result ) ) ? result : range2; + } + if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) { + result = data.cache; + } else { + tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact; + result = ts.formatFloat( tmp, table ); + } + if ( range1 > range2 ) { + tmp = range1; range1 = range2; range2 = tmp; // swap + } + return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' ); + } + return null; + }, + // Look for wild card: ? = single, * = multiple, or | = logical OR + wild : function( c, data ) { + if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) { + var index = data.index, + parsed = data.parsed[ index ], + txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ), + query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' ); + // look for an exact match with the 'or' unless the 'filter-match' class is found + if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) { + // show all results while using filter match. Fixes #727 + if ( query[ query.length - 1 ] === '|' ) { + query += '*'; + } + query = data.anyMatch && $.isArray( data.rowArray ) ? + '(' + query + ')' : + '^(' + query + ')$'; + } + // parsing the filter may not work properly when using wildcards =/ + return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) ) + .test( data.iExact ); + } + return null; + }, + // fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license ) + fuzzy: function( c, data ) { + if ( /^~/.test( data.iFilter ) ) { + var indx, + patternIndx = 0, + len = data.iExact.length, + txt = data.iFilter.slice( 1 ), + pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || ''; + for ( indx = 0; indx < len; indx++ ) { + if ( data.iExact[ indx ] === pattern[ patternIndx ] ) { + patternIndx += 1; + } + } + if ( patternIndx === pattern.length ) { + return true; + } + return false; + } + return null; + } + }, + init: function( table, c, wo ) { + // filter language options + ts.language = $.extend( true, {}, { + to : 'to', + or : 'or', + and : 'and' + }, ts.language ); + + var options, string, txt, $header, column, filters, val, fxn, noSelect, + regex = ts.filter.regex; + c.$table.addClass( 'hasFilters' ); + + // define timers so using clearTimeout won't cause an undefined error + wo.searchTimer = null; + wo.filter_initTimer = null; + wo.filter_formatterCount = 0; + wo.filter_formatterInit = []; + wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]'; + wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]'; + + val = '\\{' + ts.filter.regex.query + '\\}'; + $.extend( regex, { + child : new RegExp( c.cssChildRow ), + filtered : new RegExp( wo.filter_filteredRow ), + alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ), + toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ), + toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ), + andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ), + andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ), + orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ), + iQuery : new RegExp( val, 'i' ), + igQuery : new RegExp( val, 'ig' ) + }); + + // don't build filter row if columnFilters is false or all columns are set to 'filter-false' + // see issue #156 + val = c.$headers.filter( '.filter-false, .parser-false' ).length; + if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) { + // build filter row + ts.filter.buildRow( table, c, wo ); + } + + txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ' + .split( ' ' ).join( c.namespace + 'filter ' ); + c.$table.bind( txt, function( event, filter ) { + val = wo.filter_hideEmpty && + $.isEmptyObject( c.cache ) && + !( c.delayInit && event.type === 'appendCache' ); + // hide filter row using the 'filtered' class name + c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450 + if ( !/(search|filter)/.test( event.type ) ) { + event.stopPropagation(); + ts.filter.buildDefault( table, true ); + } + if ( event.type === 'filterReset' ) { + c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' ); + ts.filter.searching( table, [] ); + } else if ( event.type === 'filterEnd' ) { + ts.filter.buildDefault( table, true ); + } else { + // send false argument to force a new search; otherwise if the filter hasn't changed, + // it will return + filter = event.type === 'search' ? filter : + event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : ''; + if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) { + // force a new search since content has changed + c.lastCombinedFilter = null; + c.lastSearch = []; + } + // pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first + // input ensures all inputs are updated when a search is triggered on the table + // $( 'table' ).trigger( 'search', [...] ); + ts.filter.searching( table, filter, true ); + } + return false; + }); + + // reset button/link + if ( wo.filter_reset ) { + if ( wo.filter_reset instanceof $ ) { + // reset contains a jQuery object, bind to it + wo.filter_reset.click( function() { + c.$table.trigger( 'filterReset' ); + }); + } else if ( $( wo.filter_reset ).length ) { + // reset is a jQuery selector, use event delegation + $( document ) + .undelegate( wo.filter_reset, 'click.tsfilter' ) + .delegate( wo.filter_reset, 'click.tsfilter', function() { + // trigger a reset event, so other functions ( filter_formatter ) know when to reset + c.$table.trigger( 'filterReset' ); + }); + } + } + if ( wo.filter_functions ) { + for ( column = 0; column < c.columns; column++ ) { + fxn = ts.getColumnData( table, wo.filter_functions, column ); + if ( fxn ) { + // remove 'filter-select' from header otherwise the options added here are replaced with + // all options + $header = c.$headerIndexed[ column ].removeClass( 'filter-select' ); + // don't build select if 'filter-false' or 'parser-false' set + noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) ); + options = ''; + if ( fxn === true && noSelect ) { + ts.filter.buildSelect( table, column ); + } else if ( typeof fxn === 'object' && noSelect ) { + // add custom drop down list + for ( string in fxn ) { + if ( typeof string === 'string' ) { + options += options === '' ? + '' : ''; + val = string; + txt = string; + if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) { + val = string.split( wo.filter_selectSourceSeparator ); + txt = val[1]; + val = val[0]; + } + options += ''; + } + } + c.$table + .find( 'thead' ) + .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' ) + .append( options ); + txt = wo.filter_selectSource; + fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column ); + if ( fxn ) { + // updating so the extra options are appended + ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) ); + } + } + } + } + } + // not really updating, but if the column has both the 'filter-select' class & + // filter_functions set to true, it would append the same options twice. + ts.filter.buildDefault( table, true ); + + ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true ); + if ( wo.filter_external ) { + ts.filter.bindSearch( table, wo.filter_external ); + } + + if ( wo.filter_hideFilters ) { + ts.filter.hideFilters( table, c ); + } + + // show processing icon + if ( c.showProcessing ) { + txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' ); + c.$table + .unbind( txt.replace( /\s+/g, ' ' ) ) + .bind( txt, function( event, columns ) { + // only add processing to certain columns to all columns + $header = ( columns ) ? + c.$table + .find( '.' + tscss.header ) + .filter( '[data-column]' ) + .filter( function() { + return columns[ $( this ).data( 'column' ) ] !== ''; + }) : ''; + ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' ); + }); + } + + // set filtered rows count ( intially unfiltered ) + c.filteredRows = c.totalRows; + + // add default values + txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' ); + c.$table + .unbind( txt.replace( /\s+/g, ' ' ) ) + .bind( txt, function() { + // redefine 'wo' as it does not update properly inside this callback + var wo = this.config.widgetOptions; + filters = ts.filter.setDefaults( table, c, wo ) || []; + if ( filters.length ) { + // prevent delayInit from triggering a cache build if filters are empty + if ( !( c.delayInit && filters.join( '' ) === '' ) ) { + ts.setFilters( table, filters, true ); + } + } + c.$table.trigger( 'filterFomatterUpdate' ); + // trigger init after setTimeout to prevent multiple filterStart/End/Init triggers + setTimeout( function() { + if ( !wo.filter_initialized ) { + ts.filter.filterInitComplete( c ); + } + }, 100 ); + }); + // if filter widget is added after pager has initialized; then set filter init flag + if ( c.pager && c.pager.initialized && !wo.filter_initialized ) { + c.$table.trigger( 'filterFomatterUpdate' ); + setTimeout( function() { + ts.filter.filterInitComplete( c ); + }, 100 ); + } + }, + // $cell parameter, but not the config, is passed to the filter_formatters, + // so we have to work with it instead + formatterUpdated: function( $cell, column ) { + var wo = $cell.closest( 'table' )[0].config.widgetOptions; + if ( !wo.filter_initialized ) { + // add updates by column since this function + // may be called numerous times before initialization + wo.filter_formatterInit[ column ] = 1; + } + }, + filterInitComplete: function( c ) { + var indx, len, + wo = c.widgetOptions, + count = 0, + completed = function() { + wo.filter_initialized = true; + c.$table.trigger( 'filterInit', c ); + ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] ); + }; + if ( $.isEmptyObject( wo.filter_formatter ) ) { + completed(); + } else { + len = wo.filter_formatterInit.length; + for ( indx = 0; indx < len; indx++ ) { + if ( wo.filter_formatterInit[ indx ] === 1 ) { + count++; + } + } + clearTimeout( wo.filter_initTimer ); + if ( !wo.filter_initialized && count === wo.filter_formatterCount ) { + // filter widget initialized + completed(); + } else if ( !wo.filter_initialized ) { + // fall back in case a filter_formatter doesn't call + // $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off + wo.filter_initTimer = setTimeout( function() { + completed(); + }, 500 ); + } + } + }, + + setDefaults: function( table, c, wo ) { + var isArray, saved, indx, col, $filters, + // get current ( default ) filters + filters = ts.getFilters( table ) || []; + if ( wo.filter_saveFilters && ts.storage ) { + saved = ts.storage( table, 'tablesorter-filters' ) || []; + isArray = $.isArray( saved ); + // make sure we're not just getting an empty array + if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) { + filters = saved; + } + } + // if no filters saved, then check default settings + if ( filters.join( '' ) === '' ) { + // allow adding default setting to external filters + $filters = c.$headers.add( wo.filter_$externalFilters ) + .filter( '[' + wo.filter_defaultAttrib + ']' ); + for ( indx = 0; indx <= c.columns; indx++ ) { + // include data-column='all' external filters + col = indx === c.columns ? 'all' : indx; + filters[indx] = $filters + .filter( '[data-column="' + col + '"]' ) + .attr( wo.filter_defaultAttrib ) || filters[indx] || ''; + } + } + c.$table.data( 'lastSearch', filters ); + return filters; + }, + parseFilter: function( c, filter, column, parsed ) { + return parsed ? c.parsers[column].format( filter, c.table, [], column ) : filter; + }, + buildRow: function( table, c, wo ) { + var col, column, $header, buildSelect, disabled, name, ffxn, tmp, + // c.columns defined in computeThIndexes() + cellFilter = wo.filter_cellFilter, + columns = c.columns, + arry = $.isArray( cellFilter ), + buildFilter = ''; + for ( column = 0; column < columns; column++ ) { + buildFilter += '' ).appendTo( c.$filters.eq( column ) ); + } else { + ffxn = ts.getColumnData( table, wo.filter_formatter, column ); + if ( ffxn ) { + wo.filter_formatterCount++; + buildFilter = ffxn( c.$filters.eq( column ), column ); + // no element returned, so lets go find it + if ( buildFilter && buildFilter.length === 0 ) { + buildFilter = c.$filters.eq( column ).children( 'input' ); + } + // element not in DOM, so lets attach it + if ( buildFilter && ( buildFilter.parent().length === 0 || + ( buildFilter.parent().length && buildFilter.parent()[0] !== c.$filters[column] ) ) ) { + c.$filters.eq( column ).append( buildFilter ); + } + } else { + buildFilter = $( '' ).appendTo( c.$filters.eq( column ) ); + } + if ( buildFilter ) { + tmp = $header.data( 'placeholder' ) || + $header.attr( 'data-placeholder' ) || + wo.filter_placeholder.search || ''; + buildFilter.attr( 'placeholder', tmp ); + } + } + if ( buildFilter ) { + // add filter class name + name = ( $.isArray( wo.filter_cssFilter ) ? + ( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) : + wo.filter_cssFilter ) || ''; + buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', column ); + if ( disabled ) { + buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true; + } + } + } + }, + bindSearch: function( table, $el, internal ) { + table = $( table )[0]; + $el = $( $el ); // allow passing a selector string + if ( !$el.length ) { return; } + var tmp, + c = table.config, + wo = c.widgetOptions, + namespace = c.namespace + 'filter', + $ext = wo.filter_$externalFilters; + if ( internal !== true ) { + // save anyMatch element + tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector; + wo.filter_$anyMatch = $el.filter( tmp ); + if ( $ext && $ext.length ) { + wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el ); + } else { + wo.filter_$externalFilters = $el; + } + // update values ( external filters added after table initialization ) + ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false ); + } + // unbind events + tmp = ( 'keypress keyup search change '.split( ' ' ).join( namespace + ' ' ) ); + $el + // use data attribute instead of jQuery data since the head is cloned without including + // the data/binding + .attr( 'data-lastSearchTime', new Date().getTime() ) + .unbind( tmp.replace( /\s+/g, ' ' ) ) + // include change for select - fixes #473 + .bind( 'keyup' + namespace, function( event ) { + $( this ).attr( 'data-lastSearchTime', new Date().getTime() ); + // emulate what webkit does.... escape clears the filter + if ( event.which === 27 ) { + this.value = ''; + // live search + } else if ( wo.filter_liveSearch === false ) { + return; + // don't return if the search value is empty ( all rows need to be revealed ) + } else if ( this.value !== '' && ( + // liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace + ( typeof wo.filter_liveSearch === 'number' && this.value.length < wo.filter_liveSearch ) || + // let return & backspace continue on, but ignore arrows & non-valid characters + ( event.which !== 13 && event.which !== 8 && + ( event.which < 32 || ( event.which >= 37 && event.which <= 40 ) ) ) ) ) { + return; + } + // change event = no delay; last true flag tells getFilters to skip newest timed input + ts.filter.searching( table, true, true ); + }) + .bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) { + var column = $( this ).data( 'column' ); + // don't allow 'change' event to process if the input value is the same - fixes #685 + if ( event.which === 13 || event.type === 'search' || + event.type === 'change' && this.value !== c.lastSearch[column] ) { + event.preventDefault(); + // init search with no delay + $( this ).attr( 'data-lastSearchTime', new Date().getTime() ); + ts.filter.searching( table, false, true ); + } + }); + }, + searching: function( table, filter, skipFirst ) { + var wo = table.config.widgetOptions; + clearTimeout( wo.searchTimer ); + if ( typeof filter === 'undefined' || filter === true ) { + // delay filtering + wo.searchTimer = setTimeout( function() { + ts.filter.checkFilters( table, filter, skipFirst ); + }, wo.filter_liveSearch ? wo.filter_searchDelay : 10 ); + } else { + // skip delay + ts.filter.checkFilters( table, filter, skipFirst ); + } + }, + checkFilters: function( table, filter, skipFirst ) { + var c = table.config, + wo = c.widgetOptions, + filterArray = $.isArray( filter ), + filters = ( filterArray ) ? filter : ts.getFilters( table, true ), + combinedFilters = ( filters || [] ).join( '' ); // combined filter values + // prevent errors if delay init is set + if ( $.isEmptyObject( c.cache ) ) { + // update cache if delayInit set & pager has initialized ( after user initiates a search ) + if ( c.delayInit && c.pager && c.pager.initialized ) { + c.$table.trigger( 'updateCache', [ function() { + ts.filter.checkFilters( table, false, skipFirst ); + } ] ); + } + return; + } + // add filter array back into inputs + if ( filterArray ) { + ts.setFilters( table, filters, false, skipFirst !== true ); + if ( !wo.filter_initialized ) { c.lastCombinedFilter = ''; } + } + if ( wo.filter_hideFilters ) { + // show/hide filter row as needed + c.$table + .find( '.' + tscss.filterRow ) + .trigger( combinedFilters === '' ? 'mouseleave' : 'mouseenter' ); + } + // return if the last search is the same; but filter === false when updating the search + // see example-widget-filter.html filter toggle buttons + if ( c.lastCombinedFilter === combinedFilters && filter !== false ) { + return; + } else if ( filter === false ) { + // force filter refresh + c.lastCombinedFilter = null; + c.lastSearch = []; + } + if ( wo.filter_initialized ) { + c.$table.trigger( 'filterStart', [filters] ); + } + if ( c.showProcessing ) { + // give it time for the processing icon to kick in + setTimeout( function() { + ts.filter.findRows( table, filters, combinedFilters ); + return false; + }, 30 ); + } else { + ts.filter.findRows( table, filters, combinedFilters ); + return false; + } + }, + hideFilters: function( table, c ) { + var $filterRow, $filterRow2, timer; + $( table ) + .find( '.' + tscss.filterRow ) + .addClass( tscss.filterRowHide ) + .bind( 'mouseenter mouseleave', function( e ) { + // save event object - http://bugs.jquery.com/ticket/12140 + var event = e; + $filterRow = $( this ); + clearTimeout( timer ); + timer = setTimeout( function() { + if ( /enter|over/.test( event.type ) ) { + $filterRow.removeClass( tscss.filterRowHide ); + } else { + // don't hide if input has focus + // $( ':focus' ) needs jQuery 1.6+ + if ( $( document.activeElement ).closest( 'tr' )[0] !== $filterRow[0] ) { + // don't hide row if any filter has a value + if ( c.lastCombinedFilter === '' ) { + $filterRow.addClass( tscss.filterRowHide ); + } + } + } + }, 200 ); + }) + .find( 'input, select' ).bind( 'focus blur', function( e ) { + $filterRow2 = $( this ).closest( 'tr' ); + clearTimeout( timer ); + var event = e; + timer = setTimeout( function() { + // don't hide row if any filter has a value + if ( ts.getFilters( c.$table ).join( '' ) === '' ) { + $filterRow2.toggleClass( tscss.filterRowHide, event.type === 'focus' ); + } + }, 200 ); + }); + }, + defaultFilter: function( filter, mask ) { + if ( filter === '' ) { return filter; } + var regex = ts.filter.regex.iQuery, + maskLen = mask.match( ts.filter.regex.igQuery ).length, + query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ], + len = query.length - 1, + indx = 0, + val = mask; + if ( len < 1 && maskLen > 1 ) { + // only one 'word' in query but mask has >1 slots + query[1] = query[0]; + } + // replace all {query} with query words... + // if query = 'Bob', then convert mask from '!{query}' to '!Bob' + // if query = 'Bob Joe Frank', then convert mask '{q} OR {q}' to 'Bob OR Joe OR Frank' + while ( regex.test( val ) ) { + val = val.replace( regex, query[indx++] || '' ); + if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) { + val = mask.replace( regex, val ); + } + } + return val; + }, + getLatestSearch: function( $input ) { + if ( $input ) { + return $input.sort( function( a, b ) { + return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' ); + }); + } + return $input || $(); + }, + multipleColumns: function( c, $input ) { + // look for multiple columns '1-3,4-6,8' in data-column + var temp, ranges, range, start, end, singles, i, indx, len, + wo = c.widgetOptions, + // only target 'all' column inputs on initialization + // & don't target 'all' column inputs if they don't exist + targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length, + columns = [], + val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' ); + // process column range + if ( targets && /-/.test( val ) ) { + ranges = val.match( /(\d+)\s*-\s*(\d+)/g ); + len = ranges.length; + for ( indx = 0; indx < len; indx++ ) { + range = ranges[indx].split( /\s*-\s*/ ); + start = parseInt( range[0], 10 ) || 0; + end = parseInt( range[1], 10 ) || ( c.columns - 1 ); + if ( start > end ) { + temp = start; start = end; end = temp; // swap + } + if ( end >= c.columns ) { + end = c.columns - 1; + } + for ( ; start <= end; start++ ) { + columns.push( start ); + } + // remove processed range from val + val = val.replace( ranges[ indx ], '' ); + } + } + // process single columns + if ( targets && /,/.test( val ) ) { + singles = val.split( /\s*,\s*/ ); + len = singles.length; + for ( i = 0; i < len; i++ ) { + if ( singles[ i ] !== '' ) { + indx = parseInt( singles[ i ], 10 ); + if ( indx < c.columns ) { + columns.push( indx ); + } + } + } + } + // return all columns + if ( !columns.length ) { + for ( indx = 0; indx < c.columns; indx++ ) { + columns.push( indx ); + } + } + return columns; + }, + processRow: function( c, data, vars ) { + var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, + fxn, ffxn, txt, + regex = ts.filter.regex, + wo = c.widgetOptions, + showRow = true; + data.$cells = data.$row.children(); + + if ( data.anyMatchFlag ) { + // look for multiple columns '1-3,4-6,8' + columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch ); + data.anyMatch = true; + data.rowArray = data.$cells.map( function( i ) { + if ( $.inArray( i, columnIndex ) > -1 ) { + if ( data.parsed[ i ] ) { + txt = data.cacheArray[ i ]; + } else { + txt = data.rawArray[ i ]; + txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt ); + if ( c.sortLocaleCompare ) { + txt = ts.replaceAccents( txt ); + } + } + return txt; + } + }).get(); + data.filter = data.anyMatchFilter; + data.iFilter = data.iAnyMatchFilter; + data.exact = data.rowArray.join( ' ' ); + data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact; + data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' ); + filterMatched = null; + matches = null; + for ( ffxn in ts.filter.types ) { + if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) { + matches = ts.filter.types[ffxn]( c, data ); + if ( matches !== null ) { + filterMatched = matches; + } + } + } + if ( filterMatched !== null ) { + showRow = filterMatched; + } else { + if ( wo.filter_startsWith ) { + showRow = false; + columnIndex = c.columns; + while ( !showRow && columnIndex > 0 ) { + columnIndex--; + showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0; + } + } else { + showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0; + } + } + data.anyMatch = false; + // no other filters to process + if ( data.filters.join( '' ) === data.filter ) { + return showRow; + } + } + + for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) { + data.filter = data.filters[ columnIndex ]; + data.index = columnIndex; + + // filter types to exclude, per column + excludeMatch = vars.excludeFilter[ columnIndex ]; + + // ignore if filter is empty or disabled + if ( data.filter ) { + data.cache = data.cacheArray[ columnIndex ]; + // check if column data should be from the cell or from parsed data + if ( wo.filter_useParsedData || data.parsed[ columnIndex ] ) { + data.exact = data.cache; + } else { + result = data.rawArray[ columnIndex ] || ''; + data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405 + } + data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ? + data.exact.toLowerCase() : data.exact; + result = showRow; // if showRow is true, show that row + + // in case select filter option has a different value vs text 'a - z|A through Z' + ffxn = wo.filter_columnFilters ? + c.$filters.add( c.$externalFilters ) + .filter( '[data-column="'+ columnIndex + '"]' ) + .find( 'select option:selected' ) + .attr( 'data-function-name' ) || '' : ''; + // replace accents - see #357 + if ( c.sortLocaleCompare ) { + data.filter = ts.replaceAccents( data.filter ); + } + + val = true; + if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) { + data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] ); + // val is used to indicate that a filter select is using a default filter; + // so we override the exact & partial matches + val = false; + } + // data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ), + // data.filter = case sensitive + data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter; + fxn = vars.functions[ columnIndex ]; + $cell = c.$headerIndexed[ columnIndex ]; + hasSelect = $cell.hasClass( 'filter-select' ); + filterMatched = null; + if ( fxn || ( hasSelect && val ) ) { + if ( fxn === true || hasSelect ) { + // default selector uses exact match unless 'filter-match' class is found + filterMatched = $cell.hasClass( 'filter-match' ) ? + data.iExact.search( data.iFilter ) >= 0 : + data.filter === data.exact; + } else if ( typeof fxn === 'function' ) { + // filter callback( exact cell content, parser normalized content, + // filter input value, column index, jQuery row object ) + filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data ); + } else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) { + // selector option function + txt = ffxn || data.filter; + filterMatched = + fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data ); + } + } + if ( filterMatched === null ) { + // cycle through the different filters + // filters return a boolean or null if nothing matches + matches = null; + for ( ffxn in ts.filter.types ) { + if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) { + matches = ts.filter.types[ ffxn ]( c, data ); + if ( matches !== null ) { + filterMatched = matches; + } + } + } + if ( filterMatched !== null ) { + result = filterMatched; + // Look for match, and add child row data for matching + } else { + txt = ( data.iExact + data.childRowText ) + .indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) ); + result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) ); + } + } else { + result = filterMatched; + } + showRow = ( result ) ? showRow : false; + } + } + return showRow; + }, + findRows: function( table, filters, combinedFilters ) { + if ( table.config.lastCombinedFilter === combinedFilters || + !table.config.widgetOptions.filter_initialized ) { + return; + } + var len, norm_rows, rowData, $rows, rowIndex, tbodyIndex, $tbody, columnIndex, + isChild, childRow, lastSearch, showRow, time, val, indx, + notFiltered, searchFiltered, query, injected, res, id, txt, + storedFilters = $.extend( [], filters ), + regex = ts.filter.regex, + c = table.config, + wo = c.widgetOptions, + // data object passed to filters; anyMatch is a flag for the filters + data = { + anyMatch: false, + filters: filters, + // regex filter type cache + filter_regexCache : [], + }, + vars = { + // anyMatch really screws up with these types of filters + noAnyMatch: [ 'range', 'notMatch', 'operators' ], + // cache filter variables that use ts.getColumnData in the main loop + functions : [], + excludeFilter : [], + defaultColFilter : [], + defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || '' + }; + + // parse columns after formatter, in case the class is added at that point + data.parsed = c.$headers.map( function( columnIndex ) { + return c.parsers && c.parsers[ columnIndex ] && + // force parsing if parser type is numeric + c.parsers[ columnIndex ].parsed || + // getData won't return 'parsed' if other 'filter-' class names exist + // ( e.g. ) + ts.getData && ts.getData( c.$headerIndexed[ columnIndex ], + ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' || + $( this ).hasClass( 'filter-parsed' ); + }).get(); + + for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) { + vars.functions[ columnIndex ] = + ts.getColumnData( table, wo.filter_functions, columnIndex ); + vars.defaultColFilter[ columnIndex ] = + ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || ''; + vars.excludeFilter[ columnIndex ] = + ( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ ); + } + + if ( c.debug ) { + ts.log( 'Filter: Starting filter widget search', filters ); + time = new Date(); + } + // filtered rows count + c.filteredRows = 0; + c.totalRows = 0; + // combindedFilters are undefined on init + combinedFilters = ( storedFilters || [] ).join( '' ); + + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) { + $tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true ); + // skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel! + // $rows = $tbody.children( 'tr' ).not( c.selectorRemove ); + columnIndex = c.columns; + // convert stored rows into a jQuery object + norm_rows = c.cache[ tbodyIndex ].normalized; + $rows = $( $.map( norm_rows, function( el ) { + return el[ columnIndex ].$row.get(); + }) ); + + if ( combinedFilters === '' || wo.filter_serversideFiltering ) { + $rows + .removeClass( wo.filter_filteredRow ) + .not( '.' + c.cssChildRow ) + .css( 'display', '' ); + } else { + // filter out child rows + $rows = $rows.not( '.' + c.cssChildRow ); + len = $rows.length; + + if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) || + typeof filters[c.columns] !== 'undefined' ) { + data.anyMatchFlag = true; + data.anyMatchFilter = '' + ( + filters[ c.columns ] || + wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() || + '' + ); + if ( wo.filter_columnAnyMatch ) { + // specific columns search + query = data.anyMatchFilter.split( regex.andSplit ); + injected = false; + for ( indx = 0; indx < query.length; indx++ ) { + res = query[ indx ].split( ':' ); + if ( res.length > 1 ) { + // make the column a one-based index ( non-developers start counting from one :P ) + id = parseInt( res[0], 10 ) - 1; + if ( id >= 0 && id < c.columns ) { // if id is an integer + filters[ id ] = res[1]; + query.splice( indx, 1 ); + indx--; + injected = true; + } + } + } + if ( injected ) { + data.anyMatchFilter = query.join( ' && ' ); + } + } + } + + // optimize searching only through already filtered rows - see #313 + searchFiltered = wo.filter_searchFiltered; + lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || []; + if ( searchFiltered ) { + // cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669 + for ( indx = 0; indx < columnIndex + 1; indx++ ) { + val = filters[indx] || ''; + // break out of loop if we've already determined not to search filtered rows + if ( !searchFiltered ) { indx = columnIndex; } + // search already filtered rows if... + searchFiltered = searchFiltered && lastSearch.length && + // there are no changes from beginning of filter + val.indexOf( lastSearch[indx] || '' ) === 0 && + // if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string + !regex.alreadyFiltered.test( val ) && + // if we are not doing exact matches, using '|' ( logical or ) or not '!' + !/[=\"\|!]/.test( val ) && + // don't search only filtered if the value is negative + // ( '> -10' => '> -100' will ignore hidden rows ) + !( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) && + // if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593 + !( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length && + !c.$headerIndexed[indx].hasClass( 'filter-match' ) ); + } + } + notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length; + // can't search when all rows are hidden - this happens when looking for exact matches + if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; } + if ( c.debug ) { + ts.log( 'Filter: Searching through ' + + ( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' ); + } + if ( data.anyMatchFlag ) { + if ( c.sortLocaleCompare ) { + // replace accents + data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter ); + } + if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) { + data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter ); + // clear search filtered flag because default filters are not saved to the last search + searchFiltered = false; + } + // make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true + // when c.ignoreCase is true, the cache contains all lower case data + data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ? + data.anyMatchFilter : + data.anyMatchFilter.toLowerCase(); + } + + // loop through the rows + for ( rowIndex = 0; rowIndex < len; rowIndex++ ) { + + txt = $rows[ rowIndex ].className; + // the first row can never be a child row + isChild = rowIndex && regex.child.test( txt ); + // skip child rows & already filtered rows + if ( isChild || ( searchFiltered && regex.filtered.test( txt ) ) ) { + continue; + } + + data.$row = $rows.eq( rowIndex ); + data.cacheArray = norm_rows[ rowIndex ]; + rowData = data.cacheArray[ c.columns ]; + data.rawArray = rowData.raw; + data.childRowText = ''; + + if ( !wo.filter_childByColumn ) { + txt = ''; + // child row cached text + childRow = rowData.child; + // so, if 'table.config.widgetOptions.filter_childRows' is true and there is + // a match anywhere in the child row, then it will make the row visible + // checked here so the option can be changed dynamically + for ( indx = 0; indx < childRow.length; indx++ ) { + txt += ' ' + childRow[indx].join( '' ) || ''; + } + data.childRowText = wo.filter_childRows ? + ( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) : + ''; + } + + showRow = ts.filter.processRow( c, data, vars ); + childRow = rowData.$row.filter( ':gt( 0 )' ); + + if ( wo.filter_childRows && childRow.length ) { + if ( wo.filter_childByColumn ) { + // cycle through each child row + for ( indx = 0; indx < childRow.length; indx++ ) { + data.$row = childRow.eq( indx ); + data.cacheArray = rowData.child[ indx ]; + data.rawArray = data.cacheArray; + // use OR comparison on child rows + showRow = showRow || ts.filter.processRow( c, data, vars ); + } + } + childRow.toggleClass( wo.filter_filteredRow, !showRow ); + } + + rowData.$row + .toggleClass( wo.filter_filteredRow, !showRow )[0] + .display = showRow ? '' : 'none'; + } + } + c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length; + c.totalRows += $rows.length; + ts.processTbody( table, $tbody, false ); + } + c.lastCombinedFilter = combinedFilters; // save last search + // don't save 'filters' directly since it may have altered ( AnyMatch column searches ) + c.lastSearch = storedFilters; + c.$table.data( 'lastSearch', storedFilters ); + if ( wo.filter_saveFilters && ts.storage ) { + ts.storage( table, 'tablesorter-filters', storedFilters ); + } + if ( c.debug ) { + ts.benchmark( 'Completed filter widget search', time ); + } + if ( wo.filter_initialized ) { + c.$table.trigger( 'filterEnd', c ); + } + setTimeout( function() { + c.$table.trigger( 'applyWidgets' ); // make sure zebra widget is applied + }, 0 ); + }, + getOptionSource: function( table, column, onlyAvail ) { + table = $( table )[0]; + var cts, txt, indx, len, + c = table.config, + wo = c.widgetOptions, + parsed = [], + arry = false, + source = wo.filter_selectSource, + last = c.$table.data( 'lastSearch' ) || [], + fxn = $.isFunction( source ) ? true : ts.getColumnData( table, source, column ); + + if ( onlyAvail && last[column] !== '' ) { + onlyAvail = false; + } + + // filter select source option + if ( fxn === true ) { + // OVERALL source + arry = source( table, column, onlyAvail ); + } else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '' ) >= 0 ) ) { + // selectSource is a jQuery object or string of options + return fxn; + } else if ( $.isArray( fxn ) ) { + arry = fxn; + } else if ( $.type( source ) === 'object' && fxn ) { + // custom select source function for a SPECIFIC COLUMN + arry = fxn( table, column, onlyAvail ); + } + if ( arry === false ) { + // fall back to original method + arry = ts.filter.getOptions( table, column, onlyAvail ); + } + + // get unique elements and sort the list + // if $.tablesorter.sortText exists ( not in the original tablesorter ), + // then natural sort the list otherwise use a basic sort + arry = $.grep( arry, function( value, indx ) { + return $.inArray( value, arry ) === indx; + }); + + if ( c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) { + // unsorted select options + return arry; + } else { + len = arry.length; + // parse select option values + for ( indx = 0; indx < len; indx++ ) { + txt = arry[ indx ]; + // parse array data using set column parser; this DOES NOT pass the original + // table cell to the parser format function + parsed.push({ + t : txt, + // check parser length - fixes #934 + p : c.parsers && c.parsers.length && c.parsers[ column ].format( txt, table, [], column ) || txt + }); + } + + // sort parsed select options + cts = c.textSorter || ''; + parsed.sort( function( a, b ) { + // sortNatural breaks if you don't pass it strings + var x = a.p.toString(), + y = b.p.toString(); + if ( $.isFunction( cts ) ) { + // custom OVERALL text sorter + return cts( x, y, true, column, table ); + } else if ( typeof( cts ) === 'object' && cts.hasOwnProperty( column ) ) { + // custom text sorter for a SPECIFIC COLUMN + return cts[column]( x, y, true, column, table ); + } else if ( ts.sortNatural ) { + // fall back to natural sort + return ts.sortNatural( x, y ); + } + // using an older version! do a basic sort + return true; + }); + // rebuild arry from sorted parsed data + arry = []; + len = parsed.length; + for ( indx = 0; indx < len; indx++ ) { + arry.push( parsed[indx].t ); + } + return arry; + } + }, + getOptions: function( table, column, onlyAvail ) { + table = $( table )[0]; + var rowIndex, tbodyIndex, len, row, cache, + c = table.config, + wo = c.widgetOptions, + arry = []; + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) { + cache = c.cache[tbodyIndex]; + len = c.cache[tbodyIndex].normalized.length; + // loop through the rows + for ( rowIndex = 0; rowIndex < len; rowIndex++ ) { + // get cached row from cache.row ( old ) or row data object + // ( new; last item in normalized array ) + row = cache.row ? + cache.row[ rowIndex ] : + cache.normalized[ rowIndex ][ c.columns ].$row[0]; + // check if has class filtered + if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) { + continue; + } + // get non-normalized cell content + if ( wo.filter_useParsedData || + c.parsers[column].parsed || + c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) { + arry.push( '' + cache.normalized[ rowIndex ][ column ] ); + } else { + // get raw cached data instead of content directly from the cells + arry.push( cache.normalized[ rowIndex ][ c.columns ].raw[ column ] ); + } + } + } + return arry; + }, + buildSelect: function( table, column, arry, updating, onlyAvail ) { + table = $( table )[0]; + column = parseInt( column, 10 ); + if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) { + return; + } + var indx, val, txt, t, $filters, $filter, + c = table.config, + wo = c.widgetOptions, + node = c.$headerIndexed[ column ], + // t.data( 'placeholder' ) won't work in jQuery older than 1.4.3 + options = '', + // Get curent filter value + currentValue = c.$table + .find( 'thead' ) + .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' ) + .val(); + // nothing included in arry ( external source ), so get the options from + // filter_selectSource or column data + if ( typeof arry === 'undefined' || arry === '' ) { + arry = ts.filter.getOptionSource( table, column, onlyAvail ); + } + + if ( $.isArray( arry ) ) { + // build option list + for ( indx = 0; indx < arry.length; indx++ ) { + txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '"' ); + val = txt; + // allow including a symbol in the selectSource array + // 'a-z|A through Z' so that 'a-z' becomes the option value + // and 'A through Z' becomes the option text + if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) { + t = txt.split( wo.filter_selectSourceSeparator ); + val = t[0]; + txt = t[1]; + } + // replace quotes - fixes #242 & ignore empty strings + // see http://stackoverflow.com/q/14990971/145346 + options += arry[indx] !== '' ? + '' : ''; + } + // clear arry so it doesn't get appended twice + arry = []; + } + + // update all selects in the same column ( clone thead in sticky headers & + // any external selects ) - fixes 473 + $filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) ) + .find( '.' + tscss.filter ); + if ( wo.filter_$externalFilters ) { + $filters = $filters && $filters.length ? + $filters.add( wo.filter_$externalFilters ) : + wo.filter_$externalFilters; + } + $filter = $filters.filter( 'select[data-column="' + column + '"]' ); + + // make sure there is a select there! + if ( $filter.length ) { + $filter[ updating ? 'html' : 'append' ]( options ); + if ( !$.isArray( arry ) ) { + // append options if arry is provided externally as a string or jQuery object + // options ( default value ) was already added + $filter.append( arry ).val( currentValue ); + } + $filter.val( currentValue ); + } + }, + buildDefault: function( table, updating ) { + var columnIndex, $header, noSelect, + c = table.config, + wo = c.widgetOptions, + columns = c.columns; + // build default select dropdown + for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) { + $header = c.$headerIndexed[columnIndex]; + noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) ); + // look for the filter-select class; build/update it if found + if ( ( $header.hasClass( 'filter-select' ) || + ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) { + ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) ); + } + } + } +}; + +ts.getFilters = function( table, getRaw, setFilters, skipFirst ) { + var i, $filters, $column, cols, + filters = false, + c = table ? $( table )[0].config : '', + wo = c ? c.widgetOptions : ''; + if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) || + // setFilters called, but last search is exactly the same as the current + // fixes issue #733 & #903 where calling update causes the input values to reset + ( $.isArray(setFilters) && setFilters.join('') === c.lastCombinedFilter ) ) { + return $( table ).data( 'lastSearch' ); + } + if ( c ) { + if ( c.$filters ) { + $filters = c.$filters.find( '.' + tscss.filter ); + } + if ( wo.filter_$externalFilters ) { + $filters = $filters && $filters.length ? + $filters.add( wo.filter_$externalFilters ) : + wo.filter_$externalFilters; + } + if ( $filters && $filters.length ) { + filters = setFilters || []; + for ( i = 0; i < c.columns + 1; i++ ) { + cols = ( i === c.columns ? + // 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' ) + wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector : + '[data-column="' + i + '"]' ); + $column = $filters.filter( cols ); + if ( $column.length ) { + // move the latest search to the first slot in the array + $column = ts.filter.getLatestSearch( $column ); + if ( $.isArray( setFilters ) ) { + // skip first ( latest input ) to maintain cursor position while typing + if ( skipFirst && $column.length > 1 ) { + $column = $column.slice( 1 ); + } + if ( i === c.columns ) { + // prevent data-column='all' from filling data-column='0,1' ( etc ) + cols = $column.filter( wo.filter_anyColumnSelector ); + $column = cols.length ? cols : $column; + } + $column + .val( setFilters[ i ] ) + .trigger( 'change.tsfilter' ); + } else { + filters[i] = $column.val() || ''; + // don't change the first... it will move the cursor + if ( i === c.columns ) { + // don't update range columns from 'all' setting + $column + .slice( 1 ) + .filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' ) + .val( filters[ i ] ); + } else { + $column + .slice( 1 ) + .val( filters[ i ] ); + } + } + // save any match input dynamically + if ( i === c.columns && $column.length ) { + wo.filter_$anyMatch = $column; + } + } + } + } + } + if ( filters.length === 0 ) { + filters = false; + } + return filters; +}; + +ts.setFilters = function( table, filter, apply, skipFirst ) { + var c = table ? $( table )[0].config : '', + valid = ts.getFilters( table, true, filter, skipFirst ); + if ( c && apply ) { + // ensure new set filters are applied, even if the search is the same + c.lastCombinedFilter = null; + c.lastSearch = []; + ts.filter.searching( c.table, filter, skipFirst ); + c.$table.trigger( 'filterFomatterUpdate' ); + } + return !!valid; +}; + +})( jQuery ); diff --git a/js/widgets/widget-formatter.js b/js/widgets/widget-formatter.js new file mode 100644 index 0000000..61e1a03 --- /dev/null +++ b/js/widgets/widget-formatter.js @@ -0,0 +1,72 @@ +/*! Widget: formatter - 2/9/2015 (v2.19.1) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +'use strict'; + var ts = $.tablesorter; + + ts.formatter = { + init : function( c ) { + var events = c.widgetOptions.formatter_event + + ' pagerComplete updateComplete '.split(' ').join('.tsformatter '); + c.$table + .off( events.replace(/\s+/g, ' ') ) + .on( events, function() { + ts.formatter.setup( c ); + }); + ts.formatter.setup( c ); + }, + setup : function( c ) { + // do nothing for empty tables + if ( $.isEmptyObject( c.cache ) ) { return; } + var $tbody, tbodyIndex, rowIndex, rows, cell, len, column, + wo = c.widgetOptions, + data = { config: c, wo: wo }, + formatter = [], + $headers = []; + // set up variables + for ( column = 0; column < c.columns; column++ ) { + $headers[ column ] = c.$headerIndexed[ column ]; + formatter[ column ] = ts.getColumnData( c.table, wo.formatter_column, column ) || false; + } + // main loop + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ){ + $tbody = ts.processTbody( c.table, c.$tbodies.eq( tbodyIndex ), true ); // detach tbody + rows = c.cache[ tbodyIndex ]; + len = rows.normalized.length; + for ( rowIndex = 0; rowIndex < len; rowIndex++ ) { + data.$row = rows.normalized[ rowIndex ][ c.columns ].$row; + data.$cells = data.$row.children( 'th, td' ); + for ( column = 0; column < c.columns; column++ ) { + if ( formatter[ column ] ) { + data.columnIndex = column; + data.$header = $headers[ column ]; + data.$cell = data.$cells.eq( column ); + cell = data.$cell[0]; + // get text from attribute first, just in case we're updating + data.text = cell.getAttribute( c.textAttribute ) || cell.textContent || data.$cell.text(); + cell.innerHTML = formatter[ column ]( data.text, data ); + } + } + } + ts.processTbody( c.table, $tbody, false); // restore tbody + } + } + }; + + ts.addWidget({ + id: 'formatter', + priority: 100, + options: { + formatter_column : {}, + formatter_event : 'applyFormatter' + }, + init: function( table ) { + ts.formatter.init( table.config ); + } + }); + +})( jQuery ); diff --git a/js/widgets/widget-grouping.js b/js/widgets/widget-grouping.js new file mode 100644 index 0000000..178d8cc --- /dev/null +++ b/js/widgets/widget-grouping.js @@ -0,0 +1,250 @@ +/*! Widget: grouping - updated 3/5/2015 (v2.21.0) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; +var ts = $.tablesorter; + +ts.grouping = { + + types : { + number : function(c, $column, txt, num, group){ + var value, word; + if (num > 1 && txt !== '') { + if ($column.hasClass(ts.css.sortAsc)) { + value = Math.floor(parseFloat(txt)/num) * num; + return value > parseFloat(group || 0) ? value : parseFloat(group || 0); + } else { + value = Math.ceil(parseFloat(txt)/num) * num; + return value < parseFloat(group || num) - value ? parseFloat(group || num) - value : value; + } + } else { + word = (txt + '').match(/\d+/g); + return word && word.length >= num ? word[num - 1] : txt || ''; + } + }, + separator : function(c, $column, txt, num){ + var word = (txt + '').split(c.widgetOptions.group_separator); + return $.trim(word && num > 0 && word.length >= num ? word[(num || 1) - 1] : ''); + }, + word : function(c, $column, txt, num){ + var word = (txt + ' ').match(/\w+/g); + return word && word.length >= num ? word[num - 1] : txt || ''; + }, + letter : function(c, $column, txt, num){ + return txt ? (txt + ' ').substring(0, num) : ''; + }, + date : function(c, $column, txt, part, group){ + var wo = c.widgetOptions, + time = new Date(txt || ''), + hours = time.getHours(); + return part === 'year' ? time.getFullYear() : + part === 'month' ? wo.group_months[time.getMonth()] : + part === 'monthyear' ? wo.group_months[time.getMonth()] + ' ' + time.getFullYear() : + part === 'day' ? wo.group_months[time.getMonth()] + ' ' + time.getDate() : + part === 'week' ? wo.group_week[time.getDay()] : + part === 'time' ? ('00' + (hours > 12 ? hours - 12 : hours === 0 ? hours + 12 : hours)).slice(-2) + ':' + + ('00' + time.getMinutes()).slice(-2) + ' ' + ('00' + wo.group_time[hours >= 12 ? 1 : 0]).slice(-2) : + wo.group_dateString(time); + } + }, + + update : function(table, c, wo){ + if ($.isEmptyObject(c.cache)) { return; } + var rowIndex, tbodyIndex, currentGroup, $rows, groupClass, grouping, norm_rows, saveName, direction, + lang = wo.grouping_language, + group = '', + savedGroup = false, + column = c.sortList[0] ? c.sortList[0][0] : -1; + c.$table + .find('tr.group-hidden').removeClass('group-hidden').end() + .find('tr.group-header').remove(); + if (wo.group_collapsible) { + // clear pager saved spacer height (in case the rows are collapsed) + c.$table.data('pagerSavedHeight', 0); + } + if (column >= 0 && !c.$headerIndexed[column].hasClass('group-false')) { + wo.group_currentGroup = ''; // save current groups + wo.group_currentGroups = {}; + + // group class finds "group-{word/separator/letter/number/date/false}-{optional:#/year/month/day/week/time}" + groupClass = (c.$headerIndexed[column].attr('class') || '').match(/(group-\w+(-\w+)?)/g); + // grouping = [ 'group', '{word/separator/letter/number/date/false}', '{#/year/month/day/week/time}' ] + grouping = groupClass ? groupClass[0].split('-') : ['group','letter',1]; // default to letter 1 + + // save current grouping + if (wo.group_collapsible && wo.group_saveGroups && ts.storage) { + wo.group_currentGroups = ts.storage( table, 'tablesorter-groups' ) || {}; + // include direction when grouping numbers > 1 (reversed direction shows different range values) + direction = (grouping[1] === 'number' && grouping[2] > 1) ? 'dir' + c.sortList[0][1] : ''; + // combine column, sort direction & grouping as save key + saveName = wo.group_currentGroup = '' + column + direction + grouping.join(''); + if (!wo.group_currentGroups[saveName]) { + wo.group_currentGroups[saveName] = []; + } else { + savedGroup = true; + } + } + for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++) { + norm_rows = c.cache[tbodyIndex].normalized; + group = ''; // clear grouping across tbodies + $rows = c.$tbodies.eq(tbodyIndex).children('tr').not('.' + c.cssChildRow); + for (rowIndex = 0; rowIndex < $rows.length; rowIndex++) { + if ( $rows.eq(rowIndex).is(':visible') ) { + // fixes #438 + if (ts.grouping.types[grouping[1]]) { + currentGroup = norm_rows[rowIndex] ? + ts.grouping.types[grouping[1]]( c, c.$headerIndexed[column], norm_rows[rowIndex][column], /date/.test(groupClass) ? + grouping[2] : parseInt(grouping[2] || 1, 10) || 1, group, lang ) : currentGroup; + if (group !== currentGroup) { + group = currentGroup; + // show range if number > 1 + if (grouping[1] === 'number' && grouping[2] > 1 && currentGroup !== '') { + currentGroup += ' - ' + (parseInt(currentGroup, 10) + + ((parseInt(grouping[2],10) - 1) * (c.$headerIndexed[column].hasClass(ts.css.sortAsc) ? 1 : -1))); + } + if ($.isFunction(wo.group_formatter)) { + currentGroup = wo.group_formatter((currentGroup || '').toString(), column, table, c, wo) || currentGroup; + } + $rows.eq(rowIndex).before('' + (wo.group_collapsible ? '' : '') + '' + + currentGroup + ''); + if (wo.group_saveGroups && !savedGroup && wo.group_collapsed && wo.group_collapsible) { + // all groups start collapsed + wo.group_currentGroups[wo.group_currentGroup].push(currentGroup); + } + } + } + } + } + } + c.$table.find('tr.group-header') + .bind('selectstart', false) + .each(function(){ + var isHidden, $label, name, + $row = $(this), + $rows = $row.nextUntil('tr.group-header').filter(':visible'); + if (wo.group_count || $.isFunction(wo.group_callback)) { + $label = $row.find('.group-count'); + if ($label.length) { + if (wo.group_count) { + $label.html( wo.group_count.replace(/\{num\}/g, $rows.length) ); + } + if ($.isFunction(wo.group_callback)) { + wo.group_callback($row.find('td'), $rows, column, table); + } + } + } + if (wo.group_saveGroups && wo.group_currentGroups.length && wo.group_currentGroups[wo.group_currentGroup].length) { + name = $row.find('.group-name').text().toLowerCase(); + isHidden = $.inArray( name, wo.group_currentGroups[wo.group_currentGroup] ) > -1; + $row.toggleClass('collapsed', isHidden); + $rows.toggleClass('group-hidden', isHidden); + } else if (wo.group_collapsed && wo.group_collapsible) { + $row.addClass('collapsed'); + $rows.addClass('group-hidden'); + } + }); + c.$table.trigger(wo.group_complete); + } + }, + + bindEvents : function(table, c, wo){ + if (wo.group_collapsible) { + wo.group_currentGroups = []; + // .on() requires jQuery 1.7+ + c.$table.on('click toggleGroup keyup', 'tr.group-header', function(event){ + event.stopPropagation(); + // pressing enter will toggle the group + if (event.type === 'keyup' && event.which !== 13) { return; } + var isCollapsed, $groups, indx, + $this = $(this), + name = $this.find('.group-name').text().toLowerCase(); + // use shift-click to toggle ALL groups + if (event.shiftKey && (event.type === 'click' || event.type ==='keyup')) { + $this.siblings('.group-header').trigger('toggleGroup'); + } + $this.toggleClass('collapsed'); + // nextUntil requires jQuery 1.4+ + $this.nextUntil('tr.group-header').toggleClass('group-hidden', $this.hasClass('collapsed') ); + // save collapsed groups + if (wo.group_saveGroups && ts.storage) { + $groups = c.$table.find('.group-header'); + isCollapsed = $this.hasClass('collapsed'); + if (!wo.group_currentGroups[wo.group_currentGroup]) { + wo.group_currentGroups[wo.group_currentGroup] = []; + } + if (isCollapsed && wo.group_currentGroup) { + wo.group_currentGroups[wo.group_currentGroup].push( name ); + } else if (wo.group_currentGroup) { + indx = $.inArray( name, wo.group_currentGroups[wo.group_currentGroup] ); + if (indx > -1) { + wo.group_currentGroups[wo.group_currentGroup].splice( indx, 1 ); + } + } + ts.storage( table, 'tablesorter-groups', wo.group_currentGroups ); + } + }); + } + $(wo.group_saveReset).on('click', function(){ + ts.grouping.clearSavedGroups(table); + }); + c.$table.on('pagerChange.tsgrouping', function(){ + ts.grouping.update(table, c, wo); + }); + }, + + clearSavedGroups: function(table){ + if (table && ts.storage) { + ts.storage(table, 'tablesorter-groups', ''); + ts.grouping.update(table, table.config, table.config.widgetOptions); + } + } + +}; + +ts.addWidget({ + id: 'group', + priority: 100, + options: { + group_collapsible : true, // make the group header clickable and collapse the rows below it. + group_collapsed : false, // start with all groups collapsed + group_saveGroups : true, // remember collapsed groups + group_saveReset : null, // element to clear saved collapsed groups + group_count : ' ({num})', // if not false, the "{num}" string is replaced with the number of rows in the group + group_separator : '-', // group name separator; used when group-separator-# class is used. + group_formatter : null, // function(txt, column, table, c, wo) { return txt; } + group_callback : null, // function($cell, $rows, column, table){}, callback allowing modification of the group header labels + group_complete : 'groupingComplete', // event triggered on the table when the grouping widget has finished work + + // checkbox parser text used for checked/unchecked values + group_checkbox : [ 'checked', 'unchecked' ], + // change these default date names based on your language preferences + group_months : [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ], + group_week : [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ], + group_time : [ 'AM', 'PM' ], + // this function is used when "group-date" is set to create the date string + // you can just return date, date.toLocaleString(), date.toLocaleDateString() or d.toLocaleTimeString() + // reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Conversion_getter + group_dateString : function(date) { return date.toLocaleString(); } + }, + init: function(table, thisWidget, c, wo){ + ts.grouping.bindEvents(table, c, wo); + }, + format: function(table, c, wo) { + ts.grouping.update(table, c, wo); + }, + remove : function(table, c, wo){ + c.$table + .off('click', 'tr.group-header') + .off('pagerChange.tsgrouping') + .find('.group-hidden').removeClass('group-hidden').end() + .find('tr.group-header').remove(); + } +}); + +})(jQuery); diff --git a/js/widgets/widget-headerTitles.js b/js/widgets/widget-headerTitles.js new file mode 100644 index 0000000..8f4f591 --- /dev/null +++ b/js/widgets/widget-headerTitles.js @@ -0,0 +1,91 @@ +/*! Widget: headerTitles - updated 3/5/2014 (v2.15.6) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; +var ts = $.tablesorter; + + ts.addWidget({ + id: 'headerTitles', + options: { + // use aria-label text + // e.g. "First Name: Ascending sort applied, activate to apply a descending sort" + headerTitle_useAria : false, + // add tooltip class + headerTitle_tooltip : '', + // custom titles [ ascending, descending, unsorted ] + headerTitle_cur_text : [ ' sort: A - Z', ' sort: Z - A', 'ly unsorted' ], + headerTitle_cur_numeric : [ ' sort: 0 - 9', ' sort: 9 - 0', 'ly unsorted' ], + headerTitle_nxt_text : [ ' sort: A - Z', ' sort: Z - A', 'remove sort' ], + headerTitle_nxt_numeric : [ ' sort: 0 - 9', ' sort: 9 - 0', 'remove sort' ], + + // title display; {prefix} adds above prefix + // {type} adds the current sort order from above (text or numeric) + // {next} adds the next sort direction using the sort order above + headerTitle_output_sorted : 'current{current}; activate to {next}', + headerTitle_output_unsorted : 'current{current}; activate to {next} ', + headerTitle_output_nosort : 'No sort available', + // use this type to override the parser detection result + // e.g. use for numerically parsed columns (e.g. dates), but you + // want the user to see a text sort, e.g. [ 'text', 'numeric' ] + headerTitle_type : [], + // manipulate the title as desired + headerTitle_callback : null // function($cell, txt) { return txt; } + }, + init: function(table, thisWidget, c, wo){ + // force refresh + c.$table.on('refreshHeaderTitle', function(){ + thisWidget.format(table, c, wo); + }); + // add tooltip class + if ($.isArray(wo.headerTitle_tooltip)) { + c.$headers.each(function(){ + $(this).addClass( wo.headerTitle_tooltip[this.column] || '' ); + }); + } else if (wo.headerTitle_tooltip !== '') { + c.$headers.addClass( wo.headerTitle_tooltip ); + } + }, + format: function (table, c, wo) { + var txt; + c.$headers.each(function(){ + var t = this, + $this = $(this), + sortType = wo.headerTitle_type[t.column] || c.parsers[ t.column ].type || 'text', + sortDirection = $this.hasClass(ts.css.sortAsc) ? 0 : $this.hasClass(ts.css.sortDesc) ? 1 : 2, + sortNext = t.order[(t.count + 1) % (c.sortReset ? 3 : 2)]; + if (wo.headerTitle_useAria) { + txt = $this.hasClass('sorter-false') ? wo.headerTitle_output_nosort : $this.attr('aria-label') || ''; + } else { + txt = (wo.headerTitle_prefix || '') + // now deprecated + ($this.hasClass('sorter-false') ? wo.headerTitle_output_nosort : + ts.isValueInArray( t.column, c.sortList ) >= 0 ? wo.headerTitle_output_sorted : wo.headerTitle_output_unsorted); + txt = txt.replace(/\{(current|next|name)\}/gi, function(m){ + return { + '{name}' : $this.text(), + '{current}' : wo[ 'headerTitle_cur_' + sortType ][ sortDirection ] || '', + '{next}' : wo[ 'headerTitle_nxt_' + sortType ][ sortNext ] || '' + }[m.toLowerCase()]; + }); + } + $this.attr('title', $.isFunction(wo.headerTitle_callback) ? wo.headerTitle_callback($this, txt) : txt); + }); + }, + remove: function (table, c, wo) { + c.$headers.attr('title', ''); + c.$table.off('refreshHeaderTitle'); + // remove tooltip class + if ($.isArray(wo.headerTitle_tooltip)) { + c.$headers.each(function(){ + $(this).removeClass( wo.headerTitle_tooltip[this.column] || '' ); + }); + } else if (wo.headerTitle_tooltip !== '') { + c.$headers.removeClass( wo.headerTitle_tooltip ); + } + } + }); + +})(jQuery); diff --git a/js/widgets/widget-math.js b/js/widgets/widget-math.js new file mode 100644 index 0000000..8ac8b49 --- /dev/null +++ b/js/widgets/widget-math.js @@ -0,0 +1,425 @@ +/*! Widget: math - updated 5/17/2015 (v2.22.0) *//* +* Requires tablesorter v2.16+ and jQuery 1.7+ +* by Rob Garrison +*/ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($) { + "use strict"; + + var ts = $.tablesorter, + + math = { + + events : ( 'tablesorter-initialized update updateAll updateRows addRows updateCell ' + + 'filterReset filterEnd ' ).split(' ').join('.tsmath '), + + // get all of the row numerical values in an arry + getRow : function(table, wo, $el, dataAttrib) { + var $t, txt, + c = table.config, + arry = [], + $row = $el.closest('tr'), + $cells = $row.children().not('[' + dataAttrib + '=ignore]'); + if (!$row.hasClass(wo.filter_filteredRow || 'filtered')) { + if (wo.math_ignore.length) { + $cells = $cells.not('[data-column=' + wo.math_ignore.join('],[data-column=') + ']'); + } + arry = $cells.not($el).map(function(){ + $t = $(this); + txt = $t.attr(c.textAttribute); + if (typeof txt === "undefined") { + txt = this.textContent || $t.text(); + } + txt = ts.formatFloat(txt.replace(/[^\w,. \-()]/g, ""), table) || 0; + return isNaN(txt) ? 0 : txt; + }).get(); + } + return arry; + }, + + // get all of the column numerical values in an arry + getColumn : function(table, wo, $el, type, dataAttrib) { + var i, txt, $t, len, mathAbove, + arry = [], + c = table.config, + filtered = wo.filter_filteredRow || 'filtered', + cIndex = parseInt( $el.attr('data-column'), 10 ), + $rows = c.$table.children('tbody').children(), + $row = $el.closest('tr'); + // make sure tfoot rows are AFTER the tbody rows + // $rows.add( c.$table.children('tfoot').children() ); + if (type === 'above') { + len = $rows.index($row); + i = len; + while (i >= 0) { + $t = $rows.eq(i).children().filter('[data-column=' + cIndex + ']'); + mathAbove = $t.filter('[' + dataAttrib + '^=above]').length; + // ignore filtered rows & rows with data-math="ignore" (and starting row) + if ( ( !$rows.eq(i).hasClass(filtered) && $rows.eq(i).not('[' + dataAttrib + '=ignore]').length && i !== len ) || mathAbove && i !== len ) { + // stop calculating "above", when encountering another "above" + if (mathAbove) { + i = 0; + } else if ($t.length) { + txt = $t.attr(c.textAttribute); + if (typeof txt === "undefined") { + txt = $t[0].textContent || $t.text(); + } + txt = ts.formatFloat(txt.replace(/[^\w,. \-()]/g, ""), table) || 0; + arry.push(isNaN(txt) ? 0 : txt); + } + } + i--; + } + } else { + $rows.each(function(){ + $t = $(this).children().filter('[data-column=' + cIndex + ']'); + if (!$(this).hasClass(filtered) && $t.not('[' + dataAttrib + '^=above],[' + dataAttrib + '^=col]').length && !$t.is($el)) { + txt = $t.attr(c.textAttribute); + if (typeof txt === "undefined") { + txt = ($t[0] ? $t[0].textContent : '') || $t.text(); + } + // isNaN('') => false + txt = ts.formatFloat(txt.replace(/[^\w,. \-()]/g, ""), table) || 0; + arry.push(isNaN(txt) ? 0 : txt); + } + }); + } + return arry; + }, + + // get all of the column numerical values in an arry + getAll : function(table, wo, dataAttrib) { + var txt, $t, col, + arry = [], + c = table.config, + filtered = wo.filter_filteredRow || 'filtered', + $rows = c.$table.children('tbody').children(); + $rows.each(function(){ + if (!$(this).hasClass(filtered)) { + $(this).children().each(function(){ + $t = $(this); + col = parseInt( $t.attr('data-column'), 10); + if (!$t.filter('[' + dataAttrib + ']').length && $.inArray(col, wo.math_ignore) < 0) { + txt = $t.attr(c.textAttribute); + if (typeof txt === "undefined") { + txt = ($t[0] ? $t[0].textContent : '') || $t.text(); + } + txt = ts.formatFloat(txt.replace(/[^\w,. \-()]/g, ""), table) || 0; + arry.push(isNaN(txt) ? 0 : txt); + } + }); + } + }); + return arry; + }, + + recalculate : function(table, c, wo, init) { + if (c && (!wo.math_isUpdating || init)) { + + // add data-column attributes to all table cells + if (init) { + ts.computeColumnIndex( c.$table.children('tbody').children() ); + } + + // data-attribute name (defaults to data-math) + var dataAttrib = 'data-' + (wo.math_data || 'math'), + + // all non-info tbody cells + $mathCells = c.$tbodies.find('[' + dataAttrib + ']'); + math.mathType( table, wo, $mathCells, wo.math_priority, dataAttrib ); + + // only info tbody cells + $mathCells = c.$table.find('.' + c.cssInfoBlock + ', tfoot').find('[' + dataAttrib + ']'); + math.mathType( table, wo, $mathCells, wo.math_priority, dataAttrib ); + + // find the "all" total + math.mathType( table, wo, c.$table.find('[' + dataAttrib + '^=all]'), ['all'], dataAttrib ); + + wo.math_isUpdating = true; + c.$table.trigger('update'); + } + }, + + mathType : function(table, wo, $cells, priority, dataAttrib) { + if ($cells.length) { + var formula, t, $t, arry, getAll, + eq = ts.equations; + if (priority[0] === 'all') { + // no need to get all cells more than once + getAll = math.getAll(table, wo, dataAttrib); + } + $.each( priority, function(i, type) { + $cells.filter('[' + dataAttrib + '^=' + type + ']').each(function(){ + $t = $(this); + formula = ($t.attr(dataAttrib) || '').replace(type + '-', ''); + arry = (type === "row") ? math.getRow(table, wo, $t, dataAttrib) : + (type === "all") ? getAll : math.getColumn(table, wo, $t, type, dataAttrib); + if (eq[formula]) { + t = eq[formula](arry); + if (table.config.debug && console && console.log) { + console.log($t.attr(dataAttrib), arry, '=', t); + } + math.output( $t, wo, t, arry ); + } + }); + }); + } + }, + + output : function($cell, wo, value, arry) { + // get mask from cell data-attribute: data-math-mask="#,##0.00" + var result = ts.formatMask( $cell.attr('data-' + wo.math_data + '-mask') || wo.math_mask, value, wo.math_wrapPrefix, wo.math_wrapSuffix ); + if ($.isFunction(wo.math_complete)) { + result = wo.math_complete($cell, wo, result, value, arry); + } + if (result !== false) { + $cell.html(result); + } + } + + }; + + // Modified from https://code.google.com/p/javascript-number-formatter/ + /** + * @preserve IntegraXor Web SCADA - JavaScript Number Formatter + * http:// www.integraxor.com/ + * author: KPL, KHL + * (c)2011 ecava + * Dual licensed under the MIT or GPL Version 2 licenses. + */ + ts.formatMask = function(m, v, tmpPrefix, tmpSuffix) { + if ( !m || isNaN(+v) ) { + return v; // return as it is. + } + + var isNegative, result, decimal, group, posLeadZero, posTrailZero, posSeparator, part, szSep, + integer, str, offset, i, l, len, start, tmp, end, inv, + prefix = '', + suffix = ''; + + // find prefix/suffix + len = m.length; + start = m.search( /[0-9\-\+#]/ ); + tmp = start > 0 ? m.substring(0, start) : ''; + prefix = tmp; + if ( start > 0 && tmpPrefix ) { + if ( /\{content\}/.test(tmpPrefix || '') ) { + prefix = (tmpPrefix || '').replace(/\{content\}/g, tmp || ''); + } else { + prefix = (tmpPrefix || '') + tmp; + } + } + // reverse string: not an ideal method if there are surrogate pairs + inv = m.split('').reverse().join(''); + end = inv.search( /[0-9\-\+#]/ ); + i = len - end; + i += (m.substring( i, i + 1 ) === '.') ? 1 : 0; + tmp = end > 0 ? m.substring( i, len) : ''; + suffix = tmp; + if (tmp !== '' && tmpSuffix) { + if ( /\{content\}/.test(tmpSuffix || '') ) { + suffix = (tmpSuffix || '').replace(/\{content\}/g, tmp || ''); + } else { + suffix = tmp + (tmpSuffix || ''); + } + } + m = m.substring(start, i); + + // convert any string to number according to formation sign. + v = m.charAt(0) == '-' ? -v : +v; + isNegative = v < 0 ? v = -v : 0; // process only abs(), and turn on flag. + + // search for separator for grp & decimal, anything not digit, not +/- sign, not #. + result = m.match( /[^\d\-\+#]/g ); + decimal = ( result && result[result.length-1] ) || '.'; // treat the right most symbol as decimal + group = ( result && result[1] && result[0] ) || ','; // treat the left most symbol as group separator + + // split the decimal for the format string if any. + m = m.split( decimal ); + // Fix the decimal first, toFixed will auto fill trailing zero. + v = v.toFixed( m[1] && m[1].length ); + v = +(v) + ''; // convert number to string to trim off *all* trailing decimal zero(es) + + // fill back any trailing zero according to format + posTrailZero = m[1] && m[1].lastIndexOf('0'); // look for last zero in format + part = v.split('.'); + // integer will get !part[1] + if ( !part[1] || ( part[1] && part[1].length <= posTrailZero ) ) { + v = (+v).toFixed( posTrailZero + 1 ); + } + szSep = m[0].split( group ); // look for separator + m[0] = szSep.join(''); // join back without separator for counting the pos of any leading 0. + + posLeadZero = m[0] && m[0].indexOf('0'); + if ( posLeadZero > -1 ) { + while ( part[0].length < ( m[0].length - posLeadZero ) ) { + part[0] = '0' + part[0]; + } + } else if ( +part[0] === 0 ) { + part[0] = ''; + } + + v = v.split('.'); + v[0] = part[0]; + + // process the first group separator from decimal (.) only, the rest ignore. + // get the length of the last slice of split result. + posSeparator = ( szSep[1] && szSep[ szSep.length - 1 ].length ); + if ( posSeparator ) { + integer = v[0]; + str = ''; + offset = integer.length % posSeparator; + l = integer.length; + for ( i = 0; i < l; i++ ) { + str += integer.charAt(i); // ie6 only support charAt for sz. + // -posSeparator so that won't trail separator on full length + /*jshint -W018 */ + if ( !( ( i - offset + 1 ) % posSeparator ) && i < l - posSeparator ) { + str += group; + } + } + v[0] = str; + } + + v[1] = ( m[1] && v[1] ) ? decimal + v[1] : ""; + // put back any negation, combine integer and fraction, and add back prefix & suffix + return prefix + ( ( isNegative ? '-' : '' ) + v[0] + v[1] ) + suffix; + }; + + ts.equations = { + count : function(arry) { + return arry.length; + }, + sum : function(arry) { + var total = 0; + $.each( arry, function(i) { + total += arry[i]; + }); + return total; + }, + mean : function(arry) { + var total = ts.equations.sum( arry ); + return total / arry.length; + }, + median : function(arry) { + // https://gist.github.com/caseyjustus/1166258 + arry.sort( function(a,b){ return a - b; } ); + var half = Math.floor( arry.length / 2 ); + return (arry.length % 2) ? arry[half] : ( arry[half - 1] + arry[half] ) / 2.0; + }, + mode : function(arry) { + // http://stackoverflow.com/a/3451640/145346 + if ( arry.length === 0 ) { return 'none'; } + var i, el, + modeMap = {}, + maxCount = 1, + modes = [arry[0]]; + for (i = 0; i < arry.length; i++) { + el = arry[i]; + modeMap[el] = modeMap[el] ? modeMap[el] + 1 : 1; + if ( modeMap[el] > maxCount ) { + modes = [el]; + maxCount = modeMap[el]; + } else if (modeMap[el] === maxCount) { + modes.push(el); + maxCount = modeMap[el]; + } + } + // returns arry of modes if there is a tie + return modes.sort( function(a,b){ return a - b; } ); + }, + max : function(arry) { + return Math.max.apply( Math, arry ); + }, + min : function(arry) { + return Math.min.apply( Math, arry ); + }, + range: function(arry) { + var v = arry.sort(function(a,b){ return a - b; }); + return v[ arry.length - 1 ] - v[0]; + }, + // common variance equation + // (not accessible via data-attribute setting) + variance: function(arry, population) { + var avg = ts.equations.mean( arry ), + v = 0, + i = arry.length; + while (i--) { + v += Math.pow( ( arry[i] - avg ), 2 ); + } + v /= ( arry.length - (population ? 0 : 1) ); + return v; + }, + // variance (population) + varp : function(arry) { + return ts.equations.variance(arry, true); + }, + // variance (sample) + vars : function(arry) { + return ts.equations.variance(arry); + }, + // standard deviation (sample) + stdevs : function(arry) { + var vars = ts.equations.variance(arry); + return Math.sqrt( vars ); + }, + // standard deviation (population) + stdevp : function(arry) { + var varp = ts.equations.variance(arry, true); + return Math.sqrt( varp ); + } + }; + + // add new widget called repeatHeaders + // ************************************ + ts.addWidget({ + id: "math", + priority: 100, + options: { + math_data : 'math', + // column index to ignore + math_ignore : [], + // mask info: https://code.google.com/p/javascript-number-formatter/ + math_mask : '#,##0.00', + // complete executed after each fucntion + math_complete : null, // function($cell, wo, result, value, arry){ return result; }, + // order of calculation; "all" is last + math_priority : [ 'row', 'above', 'col' ], + // template for or just prepend the mask prefix & suffix with this HTML + // e.g. '{content}' + math_prefix : '', + math_suffix : '', + math_event : 'recalculate' + }, + init : function(table, thisWidget, c, wo) { + c.$table + .off( (math.events + ' updateComplete.tsmath ' + wo.math_event).replace(/\s+/g, ' ') ) + .on(math.events + ' ' + wo.math_event, function(e) { + var init = e.type === 'tablesorter-initialized'; + if ( !wo.math_isUpdating || init ) { + if ( !/filter/.test(e.type) ) { + // redo data-column indexes on update + ts.computeColumnIndex( c.$table.children('tbody').children() ); + } + math.recalculate( table, c, wo, init ); + } + }) + .on('updateComplete.tsmath', function(){ + setTimeout(function(){ + wo.math_isUpdating = false; + }, 20); + }); + wo.math_isUpdating = false; + }, + // this remove function is called when using the refreshWidgets method or when destroying the tablesorter plugin + // this function only applies to tablesorter v2.4+ + remove: function(table, c, wo, refreshing) { + if (refreshing) { return; } + $(table) + .off( (math.events + ' updateComplete.tsmath ' + wo.math_event).replace(/\s+/g, ' ') ) + .find('[data-' + wo.math_data + ']').empty(); + } + }); + +})(jQuery); diff --git a/js/widgets/widget-output.js b/js/widgets/widget-output.js new file mode 100644 index 0000000..f6be6be --- /dev/null +++ b/js/widgets/widget-output.js @@ -0,0 +1,337 @@ +/*! Widget: output - updated 5/17/2015 (v2.22.0) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * Modified from: + * HTML Table to CSV: http://www.kunalbabre.com/projects/table2CSV.php (License unknown?) + * Download-File-JS: https://github.com/PixelsCommander/Download-File-JS (http://www.apache.org/licenses/LICENSE-2.0) + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; + +var ts = $.tablesorter, + +output = ts.output = { + + event : 'outputTable', + + // wrap line breaks & tabs in quotes + regexQuote : /([\n\t\x09\x0d\x0a]|<[^<]+>)/, // test if cell needs wrapping quotes + regexBR : /(|\n)/g, // replace + regexIMG : /]+alt\s*=\s*['"]([^'"]+)['"][^>]*>/i, // match + regexHTML : /<[^<]+>/g, // replace + + replaceCR : '\x0d\x0a', + replaceTab : '\x09', + + popupTitle : 'Output', + popupStyle : 'width:100%;height:100%;', // for textarea + message : 'Your device does not support downloading. Please try again in desktop browser.', + + init : function(c) { + c.$table + .off(output.event) + .on(output.event, function(){ + // explicitly use table.config.widgetOptions because we want + // the most up-to-date values; not the "wo" from initialization + output.process(c, c.widgetOptions); + }); + }, + + processRow: function(c, $rows, isHeader, isJSON) { + var $this, row, col, rowlen, collen, txt, + wo = c.widgetOptions, + tmpRow = [], + dupe = wo.output_duplicateSpans, + addSpanIndex = isHeader && isJSON && wo.output_headerRows && $.isFunction(wo.output_callbackJSON), + cellIndex = 0; + + $rows.each(function(rowIndex) { + if (!tmpRow[rowIndex]) { tmpRow[rowIndex] = []; } + cellIndex = 0; + $(this).children().each(function(){ + $this = $(this); + // process rowspans + if ($this.filter('[rowspan]').length) { + rowlen = parseInt( $this.attr('rowspan'), 10) - 1; + txt = output.formatData( wo, $this, isHeader ); + for (row = 1; row <= rowlen; row++) { + if (!tmpRow[rowIndex + row]) { tmpRow[rowIndex + row] = []; } + tmpRow[rowIndex + row][cellIndex] = isHeader ? txt : dupe ? txt : ''; + } + } + // process colspans + if ($this.filter('[colspan]').length) { + collen = parseInt( $this.attr('colspan'), 10) - 1; + // allow data-attribute to be an empty string + txt = output.formatData( wo, $this, isHeader ); + for (col = 1; col <= collen; col++) { + // if we're processing the header & making JSON, the header names need to be unique + if ($this.filter('[rowspan]').length) { + rowlen = parseInt( $this.attr('rowspan'), 10); + for (row = 0; row < rowlen; row++) { + if (!tmpRow[rowIndex + row]) { tmpRow[rowIndex + row] = []; } + tmpRow[rowIndex + row][cellIndex + col] = addSpanIndex ? + wo.output_callbackJSON($this, txt, cellIndex + col) || txt + '(' + (cellIndex + col) + ')' : isHeader ? txt : dupe ? txt : ''; + } + } else { + tmpRow[rowIndex][cellIndex + col] = addSpanIndex ? + wo.output_callbackJSON($this, txt, cellIndex + col) || txt + '(' + (cellIndex + col) + ')' : isHeader ? txt : dupe ? txt : ''; + } + } + } + // don't include hidden columns, unless option is set + if ( wo.output_hiddenColumns || $this.css('display') !== 'none' ) { + // skip column if already defined + while (typeof tmpRow[rowIndex][cellIndex] !== 'undefined') { cellIndex++; } + tmpRow[rowIndex][cellIndex] = tmpRow[rowIndex][cellIndex] || + output.formatData( wo, $this, isHeader ); + cellIndex++; + } + }); + }); + return tmpRow; + }, + + ignoreColumns : function(wo, data) { + // ignore columns -> remove data from built array (because we've already processed any rowspan/colspan) + $.each( data, function(indx, val){ + data[indx] = $.grep(val, function(v, cellIndx){ + return $.inArray(cellIndx, wo.output_ignoreColumns) < 0; + }); + }); + return data; + }, + + process : function(c, wo) { + var mydata, $this, $rows, headers, csvData, len, + hasStringify = window.JSON && JSON.hasOwnProperty('stringify'), + indx = 0, + tmpData = (wo.output_separator || ',').toLowerCase(), + outputJSON = tmpData === 'json', + outputArray = tmpData === 'array', + separator = outputJSON || outputArray ? ',' : wo.output_separator, + saveRows = wo.output_saveRows, + $el = c.$table; + // regex to look for the set separator or HTML + wo.output_regex = new RegExp('(' + (/\\/.test(separator) ? '\\' : '' ) + separator + ')' ); + + // get header cells + $this = $el.find('thead tr:visible').not('.' + (ts.css.filterRow || 'tablesorter-filter-row') ); + headers = output.processRow(c, $this, true, outputJSON); + + // all tbody rows + $rows = $el.children('tbody').children('tr'); + + if (wo.output_includeFooter) { + // clone, to force the tfoot rows to the end of this selection of rows + // otherwise they appear after the thead (the order in the HTML) + $rows = $rows.add( $el.children('tfoot').children('tr').clone() ); + } + + // get (f)iltered, (v)isible, all rows (look for the first letter only), or jQuery filter selector + $rows = /^f/.test(saveRows) ? $rows.not('.' + (wo.filter_filteredRow || 'filtered') ) : + /^v/.test(saveRows) ? $rows.filter(':visible') : + // look for '.' (class selector), '#' (id selector), + // ':' (basic filters, e.g. ':not()') or '[' (attribute selector start) + /^[.#:\[]/.test(saveRows) ? $rows.filter(saveRows) : + // default to all rows + $rows; + + // process to array of arrays + csvData = output.processRow(c, $rows); + len = headers.length; + + if (wo.output_ignoreColumns.length) { + headers = output.ignoreColumns(wo, headers); + csvData = output.ignoreColumns(wo, csvData); + } + + if (outputJSON) { + tmpData = []; + $.each( csvData, function(indx, val){ + // multiple header rows & output_headerRows = true, pick the last row... + tmpData.push( output.row2Hash( headers[ (len > 1 && wo.output_headerRows) ? indx % len : len - 1], val ) ); + }); + + // requires JSON stringify; if it doesn't exist, the output will show [object Object],... in the output window + mydata = hasStringify ? JSON.stringify(tmpData) : tmpData; + } else { + tmpData = output.row2CSV(wo, wo.output_headerRows ? headers : [ headers[ (len > 1 && wo.output_headerRows) ? indx % len : len - 1] ], outputArray) + .concat( output.row2CSV(wo, csvData, outputArray) ); + + // stringify the array; if stringify doesn't exist the array will be flattened + mydata = outputArray && hasStringify ? JSON.stringify(tmpData) : tmpData.join('\n'); + } + + // callback; if true returned, continue processing + if ($.isFunction(wo.output_callback) && !wo.output_callback(c, mydata)) { return; } + + if ( /p/i.test( wo.output_delivery || '' ) ) { + output.popup(mydata, wo.output_popupStyle, outputJSON || outputArray); + } else { + output.download(wo, mydata); + } + + }, // end process + + row2CSV : function(wo, tmpRow, outputArray) { + var tmp, rowIndex, + csvData = [], + rowLen = tmpRow.length; + for (rowIndex = 0; rowIndex < rowLen; rowIndex++) { + // remove any blank rows + tmp = ( tmpRow[rowIndex] || [] ).join('').replace(/\"/g,''); + if ( ( tmpRow[rowIndex] || [] ).length > 0 && tmp !== '' ) { + csvData[csvData.length] = outputArray ? tmpRow[rowIndex] : tmpRow[rowIndex].join(wo.output_separator); + } + } + return csvData; + }, + + row2Hash : function(keys, values) { + var json = {}; + $.each(values, function(indx, val) { + if ( indx < keys.length ) { + json[ keys[indx] ] = val; + } + }); + return json; + }, + + formatData : function(wo, $el, isHeader) { + var attr = $el.attr(wo.output_dataAttrib), + txt = typeof attr !== 'undefined' ? attr : $el.html(), + quotes = (wo.output_separator || ',').toLowerCase(), + separator = quotes === 'json' || quotes === 'array', + // replace " with “ if undefined + result = txt.replace(/\"/g, wo.output_replaceQuote || '\u201c'); + // replace line breaks with \\n & tabs with \\t + if (!wo.output_trimSpaces) { + result = result.replace(output.regexBR, output.replaceCR).replace(/\t/g, output.replaceTab); + } else { + result = result.replace(output.regexBR, ''); + } + // extract img alt text + txt = result.match(output.regexIMG); + if (!wo.output_includeHTML && txt !== null) { + result = txt[1]; + } + // replace/remove html + result = wo.output_includeHTML && !isHeader ? result : result.replace(output.regexHTML, ''); + result = wo.output_trimSpaces || isHeader ? $.trim(result) : result; + // JSON & array outputs don't need quotes + quotes = separator ? false : wo.output_wrapQuotes || wo.output_regex.test(result) || output.regexQuote.test(result); + return quotes ? '"' + result + '"' : result; + }, + + popup : function(data, style, wrap) { + var generator = window.open('', output.popupTitle, style); + generator.document.write( + '' + output.popupTitle + '' + + '' + + '' + ); + generator.document.close(); + generator.focus(); + // select all text and focus within the textarea in the popup + // $(generator.document).find('textarea').select().focus(); + return true; + }, + + // modified from https://github.com/PixelsCommander/Download-File-JS + // & http://html5-demos.appspot.com/static/a.download.html + download : function (wo, data){ + + var e, blob, gotBlob, + nav = window.navigator, + link = document.createElement('a'); + + // iOS devices do not support downloading. We have to inform user about this. + if (/(iP)/g.test(nav.userAgent)) { + alert(output.message); + return false; + } + + // test for blob support + try { + gotBlob = !!new Blob(); + } catch (err) { + gotBlob = false; + } + + // Use HTML5 Blob if browser supports it + if ( gotBlob ) { + + window.URL = window.URL || window.webkitURL; + // prepend BOM for utf-8 encoding - see https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.js#L140 + blob = new Blob( [ '\ufeff', data ], { type: wo.output_encoding } ); + + if (nav.msSaveBlob) { + // IE 10+ + nav.msSaveBlob(blob, wo.output_saveFileName); + } else { + // all other browsers + link.href = window.URL.createObjectURL(blob); + link.download = wo.output_saveFileName; + // Dispatching click event; using $(link).trigger() won't work + if (document.createEvent) { + e = document.createEvent('MouseEvents'); + // event.initMouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget); + e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + link.dispatchEvent(e); + } + } + return false; + } + + // fallback to force file download (whether supported by server). + // not sure if this actually works in IE9 and older... + window.open( wo.output_encoding + encodeURIComponent(data) + '?download' , '_self'); + return true; + + }, + + remove : function(c) { + c.$table.off(output.event); + } + +}; + +ts.addWidget({ + id: "output", + options: { + output_separator : ',', // set to "json", "array" or any separator + output_ignoreColumns : [], // columns to ignore [0, 1,... ] (zero-based index) + output_hiddenColumns : false, // include hidden columns in the output + output_includeFooter : false, // include footer rows in the output + output_dataAttrib : 'data-name', // header attrib containing modified header name + output_headerRows : false, // if true, include multiple header rows (JSON only) + output_delivery : 'popup', // popup, download + output_saveRows : 'filtered', // (a)ll, (v)isible, (f)iltered or jQuery filter selector + output_duplicateSpans: true, // duplicate output data in tbody colspan/rowspan + output_replaceQuote : '\u201c;', // left double quote + output_includeHTML : false, + output_trimSpaces : true, + output_wrapQuotes : false, + output_popupStyle : 'width=500,height=300', + output_saveFileName : 'mytable.csv', + // callback executed when processing completes + // return true to continue download/output + // return false to stop delivery & do something else with the data + output_callback : function(config, data){ return true; }, + // JSON callback executed when a colspan is encountered in the header + output_callbackJSON : function($cell, txt, cellIndex) { return txt + '(' + (cellIndex) + ')'; }, + // the need to modify this for Excel no longer exists + output_encoding : 'data:application/octet-stream;charset=utf8,' + }, + init: function(table, thisWidget, c) { + output.init(c); + }, + remove: function(table, c){ + output.remove(c); + } + +}); + +})(jQuery); diff --git a/js/widgets/widget-pager.js b/js/widgets/widget-pager.js new file mode 100644 index 0000000..9b65bef --- /dev/null +++ b/js/widgets/widget-pager.js @@ -0,0 +1,1149 @@ +/*! Widget: Pager - updated 5/17/2015 (v2.22.0) */ +/* Requires tablesorter v2.8+ and jQuery 1.7+ + * by Rob Garrison + */ +/*jshint browser:true, jquery:true, unused:false */ +;(function($){ +"use strict"; +var tsp, + ts = $.tablesorter; + +ts.addWidget({ + id: "pager", + priority: 55, // load pager after filter widget + options : { + // output default: '{page}/{totalPages}' + // possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + pager_output: '{startRow} to {endRow} of {totalRows} rows', // '{page}/{totalPages}' + + // apply disabled classname to the pager arrows when the rows at either extreme is visible + pager_updateArrows: true, + + // starting page of the pager (zero based index) + pager_startPage: 0, + + // reset pager after filtering; set to desired page # + // set to false to not change page at filter start + pager_pageReset: 0, + + // Number of visible rows + pager_size: 10, + + // Number of options to include in the pager number selector + pager_maxOptionSize: 20, + + // Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js) + pager_savePages: true, + + //defines custom storage key + pager_storageKey: 'tablesorter-pager', + + // if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty + // table row set to a height to compensate; default is false + pager_fixedHeight: false, + + // count child rows towards the set page size? (set true if it is a visible table row within the pager) + // if true, child row(s) may not appear to be attached to its parent row, may be split across pages or + // may distort the table if rowspan or cellspans are included. + pager_countChildRows: false, + + // remove rows from the table to speed up the sort of large tables. + // setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled. + pager_removeRows: false, // removing rows in larger tables speeds up the sort + + // use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}" + // where {page} is replaced by the page number, {size} is replaced by the number of records to show, + // {sortList:col} adds the sortList to the url into a "col" array, and {filterList:fcol} adds + // the filterList to the url into an "fcol" array. + // So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url + // and a filterList = [[2,Blue],[3,13]] becomes "&fcol[2]=Blue&fcol[3]=13" in the url + pager_ajaxUrl: null, + + // modify the url after all processing has been applied + pager_customAjaxUrl: function(table, url) { return url; }, + + // modify the $.ajax object to allow complete control over your ajax requests + pager_ajaxObject: { + dataType: 'json' + }, + + // set this to false if you want to block ajax loading on init + pager_processAjaxOnInit: true, + + // process ajax so that the following information is returned: + // [ total_rows (number), rows (array of arrays), headers (array; optional) ] + // example: + // [ + // 100, // total rows + // [ + // [ "row1cell1", "row1cell2", ... "row1cellN" ], + // [ "row2cell1", "row2cell2", ... "row2cellN" ], + // ... + // [ "rowNcell1", "rowNcell2", ... "rowNcellN" ] + // ], + // [ "header1", "header2", ... "headerN" ] // optional + // ] + pager_ajaxProcessing: function(ajax){ return [ 0, [], null ]; }, + + // css class names of pager arrows + pager_css: { + container : 'tablesorter-pager', + errorRow : 'tablesorter-errorRow', // error information row (don't include period at beginning) + disabled : 'disabled' // class added to arrows @ extremes (i.e. prev/first arrows "disabled" on first page) + }, + + // jQuery selectors + pager_selectors: { + container : '.pager', // target the pager markup + first : '.first', // go to first page arrow + prev : '.prev', // previous page arrow + next : '.next', // next page arrow + last : '.last', // go to last page arrow + gotoPage : '.gotoPage', // go to page selector - select dropdown that sets the current page + pageDisplay : '.pagedisplay', // location of where the "output" is displayed + pageSize : '.pagesize' // page size selector - select dropdown that sets the "size" option + } + }, + init: function(table){ + tsp.init(table); + }, + // only update to complete sorter initialization + format: function(table, c){ + if (!(c.pager && c.pager.initialized)){ + return tsp.initComplete(table, c); + } + tsp.moveToPage(table, c.pager, false); + }, + remove: function(table, c, wo, refreshing){ + tsp.destroyPager(table, c, refreshing); + } +}); + +/* pager widget functions */ +tsp = ts.pager = { + + init: function(table) { + // check if tablesorter has initialized + if (table.hasInitialized && table.config.pager.initialized) { return; } + var t, + c = table.config, + wo = c.widgetOptions, + s = wo.pager_selectors, + + // save pager variables + p = c.pager = $.extend({ + totalPages: 0, + filteredRows: 0, + filteredPages: 0, + currentFilters: [], + page: wo.pager_startPage, + startRow: 0, + endRow: 0, + ajaxCounter: 0, + $size: null, + last: {}, + // save original pager size + setSize: wo.pager_size, + setPage: wo.pager_startPage, + events: 'filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete ' + + 'pageSize pageSet pageAndSize pagerUpdate refreshComplete ' + }, c.pager); + + // pager initializes multiple times before table has completed initialization + if (p.isInitializing) { return; } + + p.isInitializing = true; + if (c.debug) { + ts.log('Pager: Initializing'); + } + + p.size = $.data(table, 'pagerLastSize') || wo.pager_size; + // added in case the pager is reinitialized after being destroyed. + p.$container = $(s.container).addClass(wo.pager_css.container).show(); + // goto selector + p.$goto = p.$container.find(s.gotoPage); // goto is a reserved word #657 + // page size selector + p.$size = p.$container.find(s.pageSize); + p.totalRows = c.$tbodies.eq(0).children('tr').not( wo.pager_countChildRows ? '' : '.' + c.cssChildRow ).length; + p.oldAjaxSuccess = p.oldAjaxSuccess || wo.pager_ajaxObject.success; + c.appender = tsp.appender; + p.initializing = true; + if (wo.pager_savePages && ts.storage) { + t = ts.storage(table, wo.pager_storageKey) || {}; // fixes #387 + p.page = ( isNaN(t.page) ? p.page : t.page ) || p.setPage || 0; + p.size = ( isNaN(t.size) ? p.size : t.size ) || p.setSize || 10; + $.data(table, 'pagerLastSize', p.size); + } + + // skipped rows + p.regexRows = new RegExp('(' + (wo.filter_filteredRow || 'filtered') + '|' + c.selectorRemove.slice(1) + '|' + c.cssChildRow + ')'); + + // clear initialized flag + p.initialized = false; + // before initialization event + c.$table.trigger('pagerBeforeInitialized', c); + + tsp.enablePager(table, c, false); + + // p must have ajaxObject + p.ajaxObject = wo.pager_ajaxObject; // $.extend({}, wo.pager_ajaxObject ); + p.ajaxObject.url = wo.pager_ajaxUrl; + + if ( typeof(wo.pager_ajaxUrl) === 'string' ) { + // ajax pager; interact with database + p.ajax = true; + // When filtering with ajax, allow only custom filtering function, disable default filtering since it will be done server side. + wo.filter_serversideFiltering = true; + c.serverSideSorting = true; + tsp.moveToPage(table, p); + } else { + p.ajax = false; + // Regular pager; all rows stored in memory + c.$table.trigger('appendCache', [{}, true]); + } + + }, + + initComplete: function(table, c){ + var p = c.pager; + tsp.bindEvents(table, c); + tsp.setPageSize(table, 0, c); // page size 0 is ignored + + if (!p.ajax) { + tsp.hideRowsSetup(table, c); + } + + // pager initialized + p.initialized = true; + p.initializing = false; + p.isInitializing = false; + if (c.debug) { + ts.log('Pager: Triggering pagerInitialized'); + } + c.$table.trigger('pagerInitialized', c); + // filter widget not initialized; it will update the output display & fire off the pagerComplete event + if ( !( c.widgetOptions.filter_initialized && ts.hasWidget(table, 'filter') ) ) { + // if ajax, then don't fire off pagerComplete + tsp.updatePageDisplay(table, c, !p.ajax); + } + }, + + bindEvents: function(table, c){ + var ctrls, fxn, + p = c.pager, + wo = c.widgetOptions, + s = wo.pager_selectors; + + c.$table + .off( $.trim(p.events.split(' ').join('.pager ')) ) + .on('filterInit.pager filterStart.pager', function(e, filters) { + p.currentFilters = $.isArray(filters) ? filters : c.$table.data('lastSearch'); + // don't change page if filters are the same (pager updating, etc) + if (e.type === 'filterStart' && wo.pager_pageReset !== false && (c.lastCombinedFilter || '') !== (p.currentFilters || []).join('')) { + p.page = wo.pager_pageReset; // fixes #456 & #565 + } + }) + // update pager after filter widget completes + .on('filterEnd.pager sortEnd.pager', function() { + p.currentFilters = c.$table.data('lastSearch'); + if (p.initialized || p.initializing) { + if (c.delayInit && c.rowsCopy && c.rowsCopy.length === 0) { + // make sure we have a copy of all table rows once the cache has been built + tsp.updateCache(table); + } + tsp.updatePageDisplay(table, c, false); + // tsp.moveToPage(table, p, false); <-- called when applyWidgets is triggered + c.$table.trigger('applyWidgets'); + } + }) + .on('disable.pager', function(e){ + e.stopPropagation(); + tsp.showAllRows(table, c); + }) + .on('enable.pager', function(e){ + e.stopPropagation(); + tsp.enablePager(table, c, true); + }) + .on('destroy.pager', function(e, refreshing){ + e.stopPropagation(); + tsp.destroyPager(table, c, refreshing); + }) + .on('updateComplete.pager', function(e, table, triggered){ + e.stopPropagation(); + // table can be unintentionally undefined in tablesorter v2.17.7 and earlier + // don't recalculate total rows/pages if using ajax + if (!table || triggered || p.ajax) { return; } + var $rows = c.$tbodies.eq(0).children('tr').not(c.selectorRemove); + p.totalRows = $rows.length - ( wo.pager_countChildRows ? 0 : $rows.filter('.' + c.cssChildRow).length ); + p.totalPages = Math.ceil( p.totalRows / p.size ); + if ($rows.length && c.rowsCopy && c.rowsCopy.length === 0) { + // make a copy of all table rows once the cache has been built + tsp.updateCache(table); + } + if ( p.page >= p.totalPages ) { + tsp.moveToLastPage(table, p); + } + tsp.hideRows(table, c); + tsp.changeHeight(table, c); + // update without triggering pagerComplete + tsp.updatePageDisplay(table, c, false); + // make sure widgets are applied - fixes #450 + c.$table.trigger('applyWidgets'); + tsp.updatePageDisplay(table, c); + }) + .on('pageSize.pager refreshComplete.pager', function(e,v){ + e.stopPropagation(); + tsp.setPageSize(table, parseInt(v, 10) || p.setSize || 10, c); + tsp.hideRows(table, c); + tsp.updatePageDisplay(table, c, false); + }) + .on('pageSet.pager pagerUpdate.pager', function(e,v){ + e.stopPropagation(); + // force pager refresh + if (e.type === 'pagerUpdate') { + v = typeof v === 'undefined' ? p.page + 1 : v; + p.last.page = true; + } + p.page = (parseInt(v, 10) || 1) - 1; + tsp.moveToPage(table, p, true); + tsp.updatePageDisplay(table, c, false); + }) + .on('pageAndSize.pager', function(e, page, size){ + e.stopPropagation(); + p.page = (parseInt(page, 10) || 1) - 1; + tsp.setPageSize(table, parseInt(size, 10) || p.setSize || 10, c); + tsp.moveToPage(table, p, true); + tsp.hideRows(table, c); + tsp.updatePageDisplay(table, c, false); + }); + + // clicked controls + ctrls = [ s.first, s.prev, s.next, s.last ]; + fxn = [ 'moveToFirstPage', 'moveToPrevPage', 'moveToNextPage', 'moveToLastPage' ]; + if (c.debug && !p.$container.length) { + ts.log('Pager: >> Container not found'); + } + p.$container.find(ctrls.join(',')) + .attr("tabindex", 0) + .off('click.pager') + .on('click.pager', function(e){ + e.stopPropagation(); + var i, + $c = $(this), + l = ctrls.length; + if ( !$c.hasClass(wo.pager_css.disabled) ) { + for (i = 0; i < l; i++) { + if ($c.is(ctrls[i])) { + tsp[fxn[i]](table, p); + break; + } + } + } + }); + + if ( p.$goto.length ) { + p.$goto + .off('change.pager') + .on('change.pager', function(){ + p.page = $(this).val() - 1; + tsp.moveToPage(table, p, true); + tsp.updatePageDisplay(table, c, false); + }); + } else if (c.debug) { + ts.log('Pager: >> Goto selector not found'); + } + + if ( p.$size.length ) { + // setting an option as selected appears to cause issues with initial page size + p.$size.find('option').removeAttr('selected'); + p.$size + .off('change.pager') + .on('change.pager', function() { + p.$size.val( $(this).val() ); // in case there are more than one pagers + if ( !$(this).hasClass(wo.pager_css.disabled) ) { + tsp.setPageSize(table, parseInt( $(this).val(), 10 ), c); + tsp.changeHeight(table, c); + } + return false; + }); + } else if (c.debug) { + ts.log('Pager: >> Size selector not found'); + } + + }, + + // hide arrows at extremes + pagerArrows: function(c, disable) { + var p = c.pager, + dis = !!disable, + first = dis || p.page === 0, + tp = Math.min( p.totalPages, p.filteredPages ), + last = dis || p.page === tp - 1 || tp === 0, + wo = c.widgetOptions, + s = wo.pager_selectors; + if ( wo.pager_updateArrows ) { + p.$container.find(s.first + ',' + s.prev).toggleClass(wo.pager_css.disabled, first).attr('aria-disabled', first); + p.$container.find(s.next + ',' + s.last).toggleClass(wo.pager_css.disabled, last).attr('aria-disabled', last); + } + }, + + calcFilters: function(table, c) { + var normalized, indx, len, + wo = c.widgetOptions, + p = c.pager, + hasFilters = c.$table.hasClass('hasFilters'); + if (hasFilters && !wo.pager_ajaxUrl) { + if ($.isEmptyObject(c.cache)) { + // delayInit: true so nothing is in the cache + p.filteredRows = p.totalRows = c.$tbodies.eq(0).children('tr').not( wo.pager_countChildRows ? '' : '.' + c.cssChildRow ).length; + } else { + p.filteredRows = 0; + normalized = c.cache[0].normalized; + len = normalized.length; + for (indx = 0; indx < len; indx++) { + p.filteredRows += p.regexRows.test(normalized[indx][c.columns].$row[0].className) ? 0 : 1; + } + } + } else if (!hasFilters) { + p.filteredRows = p.totalRows; + } + }, + + updatePageDisplay: function(table, c, completed) { + if ( c.pager.initializing ) { return; } + var s, t, $out, options, indx, len, + wo = c.widgetOptions, + p = c.pager, + sz = p.size || p.setSize || 10; // don't allow dividing by zero + if (wo.pager_countChildRows) { t.push(c.cssChildRow); } + p.$size.add(p.$goto).removeClass(wo.pager_css.disabled).removeAttr('disabled').attr('aria-disabled', 'false'); + p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method + c.totalRows = p.totalRows; + tsp.calcFilters(table, c); + c.filteredRows = p.filteredRows; + p.filteredPages = Math.ceil( p.filteredRows / sz ) || 0; + if ( Math.min( p.totalPages, p.filteredPages ) >= 0 ) { + t = (p.size * p.page > p.filteredRows) && completed; + p.page = (t) ? wo.pager_pageReset || 0 : p.page; + p.startRow = (t) ? p.size * p.page + 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1); + p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) ); + $out = p.$container.find(wo.pager_selectors.pageDisplay); + // form the output string (can now get a new output string from the server) + s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || wo.pager_output : wo.pager_output ) + // {page} = one-based index; {page+#} = zero based index +/- value + .replace(/\{page([\-+]\d+)?\}/gi, function(m,n){ + return p.totalPages ? p.page + (n ? parseInt(n, 10) : 1) : 0; + }) + // {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object) + .replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){ + var len, indx, + str = m.replace(/[{}\s]/g,''), + extra = str.split(':'), + data = p.ajaxData, + // return zero for default page/row numbers + deflt = /(rows?|pages?)$/i.test(str) ? 0 : ''; + if (/(startRow|page)/.test(extra[0]) && extra[1] === 'input') { + len = ('' + (extra[0] === 'page' ? p.totalPages : p.totalRows)).length; + indx = extra[0] === 'page' ? p.page + 1 : p.startRow; + return ''; + } + return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt; + }); + if ( p.$goto.length ) { + t = ''; + options = tsp.buildPageSelect(p, c); + len = options.length; + for (indx = 0; indx < len; indx++) { + t += ''; + } + // innerHTML doesn't work in IE9 - http://support2.microsoft.com/kb/276228 + p.$goto.html(t).val( p.page + 1 ); + } + if ($out.length) { + $out[ ($out[0].nodeName === 'INPUT') ? 'val' : 'html' ](s); + // rebind startRow/page inputs + $out.find('.ts-startRow, .ts-page').off('change.pager').on('change.pager', function(){ + var v = $(this).val(), + pg = $(this).hasClass('ts-startRow') ? Math.floor( v/p.size ) + 1 : v; + c.$table.trigger('pageSet.pager', [ pg ]); + }); + } + } + tsp.pagerArrows(c); + tsp.fixHeight(table, c); + if (p.initialized && completed !== false) { + if (c.debug) { + ts.log('Pager: Triggering pagerComplete'); + } + c.$table.trigger('pagerComplete', c); + // save pager info to storage + if (wo.pager_savePages && ts.storage) { + ts.storage(table, wo.pager_storageKey, { + page : p.page, + size : p.size + }); + } + } + }, + + buildPageSelect: function(p, c) { + // Filter the options page number link array if it's larger than 'pager_maxOptionSize' + // as large page set links will slow the browser on large dom inserts + var i, central_focus_size, focus_option_pages, insert_index, option_length, focus_length, + wo = c.widgetOptions, + pg = Math.min( p.totalPages, p.filteredPages ) || 1, + // make skip set size multiples of 5 + skip_set_size = Math.ceil( ( pg / wo.pager_maxOptionSize ) / 5 ) * 5, + large_collection = pg > wo.pager_maxOptionSize, + current_page = p.page + 1, + start_page = skip_set_size, + end_page = pg - skip_set_size, + option_pages = [1], + // construct default options pages array + option_pages_start_page = (large_collection) ? skip_set_size : 1; + + for ( i = option_pages_start_page; i <= pg; ) { + option_pages.push(i); + i = i + ( large_collection ? skip_set_size : 1 ); + } + option_pages.push(pg); + + if (large_collection) { + focus_option_pages = []; + // don't allow central focus size to be > 5 on either side of current page + central_focus_size = Math.max( Math.floor( wo.pager_maxOptionSize / skip_set_size ) - 1, 5 ); + + start_page = current_page - central_focus_size; + if (start_page < 1) { start_page = 1; } + end_page = current_page + central_focus_size; + if (end_page > pg) { end_page = pg; } + // construct an array to get a focus set around the current page + for (i = start_page; i <= end_page ; i++) { + focus_option_pages.push(i); + } + + // keep unique values + option_pages = $.grep(option_pages, function(value, indx) { + return $.inArray(value, option_pages) === indx; + }); + + option_length = option_pages.length; + focus_length = focus_option_pages.length; + + // make sure at all option_pages aren't replaced + if (option_length - focus_length > skip_set_size / 2 && option_length + focus_length > wo.pager_maxOptionSize ) { + insert_index = Math.floor(option_length / 2) - Math.floor(focus_length / 2); + Array.prototype.splice.apply(option_pages, [ insert_index, focus_length ]); + } + option_pages = option_pages.concat(focus_option_pages); + + } + + // keep unique values again + option_pages = $.grep(option_pages, function(value, indx) { + return $.inArray(value, option_pages) === indx; + }) + .sort(function(a,b) { return a - b; }); + + return option_pages; + }, + + fixHeight: function(table, c) { + var d, h, + p = c.pager, + wo = c.widgetOptions, + $b = c.$tbodies.eq(0); + $b.find('tr.pagerSavedHeightSpacer').remove(); + if (wo.pager_fixedHeight && !p.isDisabled) { + h = $.data(table, 'pagerSavedHeight'); + if (h) { + d = h - $b.height(); + if ( d > 5 && $.data(table, 'pagerLastSize') === p.size && $b.children('tr:visible').length < p.size ) { + $b.append(''); + } + } + } + }, + + changeHeight: function(table, c) { + var h, $b = c.$tbodies.eq(0); + $b.find('tr.pagerSavedHeightSpacer').remove(); + if (!$b.children('tr:visible').length) { + $b.append(' '); + } + h = $b.children('tr').eq(0).height() * c.pager.size; + $.data(table, 'pagerSavedHeight', h); + tsp.fixHeight(table, c); + $.data(table, 'pagerLastSize', c.pager.size); + }, + + hideRows: function(table, c){ + if (!c.widgetOptions.pager_ajaxUrl) { + var i, + lastIndex = 0, + p = c.pager, + wo = c.widgetOptions, + rows = c.$tbodies.eq(0).children('tr'), + l = rows.length, + s = ( p.page * p.size ), + e = s + p.size, + f = wo && wo.filter_filteredRow || 'filtered', + last = 0, // for cache indexing + j = 0; // size counter + p.cacheIndex = []; + for ( i = 0; i < l; i++ ){ + if ( !rows[i].className.match(f) ) { + if (j === s && rows[i].className.match(c.cssChildRow)) { + // hide child rows @ start of pager (if already visible) + rows[i].style.display = 'none'; + } else { + rows[i].style.display = ( j >= s && j < e ) ? '' : 'none'; + if ( last !== j && j >= s && j < e ) { + p.cacheIndex.push(i); + last = j; + } + // don't count child rows + j += rows[i].className.match(c.cssChildRow + '|' + c.selectorRemove.slice(1)) && !wo.pager_countChildRows ? 0 : 1; + if ( j === e && rows[i].style.display !== 'none' && rows[i].className.match(ts.css.cssHasChild) ) { + lastIndex = i; + } + } + } + } + // add any attached child rows to last row of pager. Fixes part of issue #396 + if ( lastIndex > 0 && rows[lastIndex].className.match(ts.css.cssHasChild) ) { + while ( ++lastIndex < l && rows[lastIndex].className.match(c.cssChildRow) ) { + rows[lastIndex].style.display = ''; + } + } + } + }, + + hideRowsSetup: function(table, c){ + var p = c.pager; + p.size = parseInt( p.$size.val(), 10 ) || p.size || p.setSize || 10; + $.data(table, 'pagerLastSize', p.size); + tsp.pagerArrows(c); + if ( !c.widgetOptions.pager_removeRows ) { + tsp.hideRows(table, c); + c.$table.on('sortEnd.pager filterEnd.pager', function(){ + tsp.hideRows(table, c); + }); + } + }, + + renderAjax: function(data, table, c, xhr, exception){ + var p = c.pager, + wo = c.widgetOptions; + // process data + if ( $.isFunction(wo.pager_ajaxProcessing) ) { + // ajaxProcessing result: [ total, rows, headers ] + var i, j, t, hsh, $f, $sh, $headers, $h, icon, th, d, l, rr_count, len, + $table = c.$table, + tds = '', + result = wo.pager_ajaxProcessing(data, table, xhr) || [ 0, [] ], + hl = $table.find('thead th').length; + + // Clean up any previous error. + ts.showError(table); + + if ( exception ) { + if (c.debug) { + ts.log('Pager: >> Ajax Error', xhr, exception); + } + ts.showError(table, exception.message + ' (' + xhr.status + ')'); + c.$tbodies.eq(0).children('tr').detach(); + p.totalRows = 0; + } else { + // process ajax object + if (!$.isArray(result)) { + p.ajaxData = result; + c.totalRows = p.totalRows = result.total; + c.filteredRows = p.filteredRows = typeof result.filteredRows !== 'undefined' ? result.filteredRows : result.total; + th = result.headers; + d = result.rows; + } else { + // allow [ total, rows, headers ] or [ rows, total, headers ] + t = isNaN(result[0]) && !isNaN(result[1]); + // ensure a zero returned row count doesn't fail the logical || + rr_count = result[t ? 1 : 0]; + p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count; + // can't set filtered rows when returning an array + c.totalRows = c.filteredRows = p.filteredRows = p.totalRows; + d = p.totalRows === 0 ? [""] : result[t ? 0 : 1] || []; // row data + th = result[2]; // headers + } + l = d && d.length; + if (d instanceof jQuery) { + if (wo.pager_processAjaxOnInit) { + // append jQuery object + c.$tbodies.eq(0).children('tr').detach(); + c.$tbodies.eq(0).append(d); + } + } else if (l) { + // build table from array + for ( i = 0; i < l; i++ ) { + tds += ''; + for ( j = 0; j < d[i].length; j++ ) { + // build tbody cells; watch for data containing HTML markup - see #434 + tds += /^\s*' + d[i][j] + ''; + } + tds += ''; + } + // add rows to first tbody + if (wo.pager_processAjaxOnInit) { + c.$tbodies.eq(0).html( tds ); + } + } + wo.pager_processAjaxOnInit = true; + // only add new header text if the length matches + if ( th && th.length === hl ) { + hsh = $table.hasClass('hasStickyHeaders'); + $sh = hsh ? wo.$sticky.children('thead:first').children('tr').children() : ''; + $f = $table.find('tfoot tr:first').children(); + // don't change td headers (may contain pager) + $headers = c.$headers.filter( 'th '); + len = $headers.length; + for ( j = 0; j < len; j++ ) { + $h = $headers.eq( j ); + // add new test within the first span it finds, or just in the header + if ( $h.find('.' + ts.css.icon).length ) { + icon = $h.find('.' + ts.css.icon).clone(true); + $h.find('.tablesorter-header-inner').html( th[j] ).append(icon); + if ( hsh && $sh.length ) { + icon = $sh.eq(j).find('.' + ts.css.icon).clone(true); + $sh.eq(j).find('.tablesorter-header-inner').html( th[j] ).append(icon); + } + } else { + $h.find('.tablesorter-header-inner').html( th[j] ); + if (hsh && $sh.length) { + $sh.eq(j).find('.tablesorter-header-inner').html( th[j] ); + } + } + $f.eq(j).html( th[j] ); + } + } + } + if (c.showProcessing) { + ts.isProcessing(table); // remove loading icon + } + // make sure last pager settings are saved, prevents multiple server side calls with + // the same parameters + p.totalPages = Math.ceil( p.totalRows / ( p.size || p.setSize || 10 ) ); + p.last.totalRows = p.totalRows; + p.last.currentFilters = p.currentFilters; + p.last.sortList = (c.sortList || []).join(','); + p.initializing = false; + // update display without triggering pager complete... before updating cache + tsp.updatePageDisplay(table, c, false); + $table.trigger('updateCache', [function(){ + if (p.initialized) { + // apply widgets after table has rendered & after a delay to prevent + // multiple applyWidget blocking code from blocking this trigger + setTimeout(function(){ + if (c.debug) { + ts.log('Pager: Triggering pagerChange'); + } + $table + .trigger('applyWidgets') + .trigger('pagerChange', p); + tsp.updatePageDisplay(table, c); + }, 0); + } + }]); + } + if (!p.initialized) { + c.$table.trigger('applyWidgets'); + } + }, + + getAjax: function(table, c){ + var counter, + url = tsp.getAjaxUrl(table, c), + $doc = $(document), + p = c.pager; + if ( url !== '' ) { + if (c.showProcessing) { + ts.isProcessing(table, true); // show loading icon + } + $doc.on('ajaxError.pager', function(e, xhr, settings, exception) { + tsp.renderAjax(null, table, c, xhr, exception); + $doc.off('ajaxError.pager'); + }); + counter = ++p.ajaxCounter; + p.last.ajaxUrl = url; // remember processed url + p.ajaxObject.url = url; // from the ajaxUrl option and modified by customAjaxUrl + p.ajaxObject.success = function(data, status, jqxhr) { + // Refuse to process old ajax commands that were overwritten by new ones - see #443 + if (counter < p.ajaxCounter){ + return; + } + tsp.renderAjax(data, table, c, jqxhr); + $doc.off('ajaxError.pager'); + if (typeof p.oldAjaxSuccess === 'function') { + p.oldAjaxSuccess(data); + } + }; + if (c.debug) { + ts.log('Pager: Ajax initialized', p.ajaxObject); + } + $.ajax(p.ajaxObject); + } + }, + + getAjaxUrl: function(table, c) { + var indx, len, + p = c.pager, + wo = c.widgetOptions, + url = (wo.pager_ajaxUrl) ? wo.pager_ajaxUrl + // allow using "{page+1}" in the url string to switch to a non-zero based index + .replace(/\{page([\-+]\d+)?\}/, function(s,n){ return p.page + (n ? parseInt(n, 10) : 0); }) + .replace(/\{size\}/g, p.size) : '', + sortList = c.sortList, + filterList = p.currentFilters || $(table).data('lastSearch') || [], + sortCol = url.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/), + filterCol = url.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/), + arry = []; + if (sortCol) { + sortCol = sortCol[1]; + len = sortList.length; + for (indx = 0; indx < len; indx++) { + arry.push(sortCol + '[' + sortList[indx][0] + ']=' + sortList[indx][1]); + } + // if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col" + url = url.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : sortCol ); + arry = []; + } + if (filterCol) { + filterCol = filterCol[1]; + len = filterList.length; + for (indx = 0; indx < len; indx++) { + if (filterList[indx]) { + arry.push(filterCol + '[' + indx + ']=' + encodeURIComponent(filterList[indx])); + } + } + // if the arry is empty, just add the fcol parameter... "&{filterList:fcol}" becomes "&fcol" + url = url.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : filterCol ); + p.currentFilters = filterList; + } + if ( $.isFunction(wo.pager_customAjaxUrl) ) { + url = wo.pager_customAjaxUrl(table, url); + } + if (c.debug) { + ts.log('Pager: Ajax url = ' + url); + } + return url; + }, + + renderTable: function(table, rows) { + var $tb, index, count, added, + c = table.config, + p = c.pager, + wo = c.widgetOptions, + f = c.$table.hasClass('hasFilters'), + l = rows && rows.length || 0, // rows may be undefined + s = ( p.page * p.size ), + e = p.size; + if ( l < 1 ) { + if (c.debug) { + ts.log('Pager: >> No rows for pager to render'); + } + // empty table, abort! + return; + } + if ( p.page >= p.totalPages ) { + // lets not render the table more than once + return tsp.moveToLastPage(table, p); + } + p.cacheIndex = []; + p.isDisabled = false; // needed because sorting will change the page and re-enable the pager + if (p.initialized) { + if (c.debug) { + ts.log('Pager: Triggering pagerChange'); + } + c.$table.trigger('pagerChange', c); + } + if ( !wo.pager_removeRows ) { + tsp.hideRows(table, c); + } else { + ts.clearTableBody(table); + $tb = ts.processTbody(table, c.$tbodies.eq(0), true); + // not filtered, start from the calculated starting point (s) + // if filtered, start from zero + index = f ? 0 : s; + count = f ? 0 : s; + added = 0; + while (added < e && index < rows.length) { + if (!f || !/filtered/.test(rows[index][0].className)){ + count++; + if (count > s && added <= e) { + added++; + p.cacheIndex.push(index); + $tb.append(rows[index]); + } + } + index++; + } + ts.processTbody(table, $tb, false); + } + tsp.updatePageDisplay(table, c); + + wo.pager_startPage = p.page; + wo.pager_size = p.size; + if (table.isUpdating) { + if (c.debug) { + ts.log('Pager: Triggering updateComplete'); + } + c.$table.trigger('updateComplete', [ table, true ]); + } + + }, + + showAllRows: function(table, c){ + var index, $controls, len, + p = c.pager, + wo = c.widgetOptions; + if ( p.ajax ) { + tsp.pagerArrows(c, true); + } else { + p.isDisabled = true; + $.data(table, 'pagerLastPage', p.page); + $.data(table, 'pagerLastSize', p.size); + p.page = 0; + p.size = p.totalRows; + p.totalPages = 1; + c.$table + .addClass('pagerDisabled') + .removeAttr('aria-describedby') + .find('tr.pagerSavedHeightSpacer').remove(); + tsp.renderTable(table, c.rowsCopy); + c.$table.trigger('applyWidgets'); + if (c.debug) { + ts.log('Pager: Disabled'); + } + } + // disable size selector + $controls = p.$size + .add( p.$goto ) + .add( p.$container.find( '.ts-startRow, .ts-page ' ) ); + len = $controls.length; + for ( index = 0; index < len; index++ ) { + $controls.eq( index ) + .attr( 'aria-disabled', 'true' ) + .addClass( wo.pager_css.disabled )[0].disabled = true; + } + }, + + // updateCache if delayInit: true + // this is normally done by "appendToTable" function in the tablesorter core AFTER a sort + updateCache: function(table) { + var c = table.config, + p = c.pager; + c.$table.trigger('updateCache', [ function(){ + if ( !$.isEmptyObject(table.config.cache) ) { + var i, + rows = [], + n = table.config.cache[0].normalized; + p.totalRows = n.length; + for (i = 0; i < p.totalRows; i++) { + rows.push(n[i][c.columns].$row); + } + c.rowsCopy = rows; + tsp.moveToPage(table, p, true); + // clear out last search to force an update + p.last.currentFilters = [' ']; + } + } ]); + }, + + moveToPage: function(table, p, pageMoved) { + if ( p.isDisabled ) { return; } + if ( pageMoved !== false && p.initialized && $.isEmptyObject(table.config.cache)) { + return tsp.updateCache(table); + } + var pg, c = table.config, + wo = c.widgetOptions, + l = p.last; + + // abort page move if the table has filters and has not been initialized + if (p.ajax && !wo.filter_initialized && ts.hasWidget(table, 'filter')) { return; } + + tsp.calcFilters(table, c); + pg = Math.min( p.totalPages, p.filteredPages ); + if ( p.page < 0 ) { p.page = 0; } + if ( p.page > ( pg - 1 ) && pg !== 0 ) { p.page = pg - 1; } + + // fixes issue where one current filter is [] and the other is ['','',''], + // making the next if comparison think the filters as different. Fixes #202. + l.currentFilters = (l.currentFilters || []).join('') === '' ? [] : l.currentFilters; + p.currentFilters = (p.currentFilters || []).join('') === '' ? [] : p.currentFilters; + // don't allow rendering multiple times on the same page/size/totalRows/filters/sorts + if ( l.page === p.page && l.size === p.size && l.totalRows === p.totalRows && + (l.currentFilters || []).join(',') === (p.currentFilters || []).join(',') && + // check for ajax url changes see #730 + (l.ajaxUrl || '') === (p.ajaxObject.url || '') && + // & ajax url option changes (dynamically add/remove/rename sort & filter parameters) + (l.optAjaxUrl || '') === (wo.pager_ajaxUrl || '') && + l.sortList === (c.sortList || []).join(',') ) { + return; + } + if (c.debug) { + ts.log('Pager: Changing to page ' + p.page); + } + p.last = { + page : p.page, + size : p.size, + // fixes #408; modify sortList otherwise it auto-updates + sortList : (c.sortList || []).join(','), + totalRows : p.totalRows, + currentFilters : p.currentFilters || [], + ajaxUrl : p.ajaxObject.url || '', + optAjaxUrl : wo.pager_ajaxUrl + }; + if (p.ajax) { + tsp.getAjax(table, c); + } else if (!p.ajax) { + tsp.renderTable(table, c.rowsCopy); + } + $.data(table, 'pagerLastPage', p.page); + if (p.initialized && pageMoved !== false) { + if (c.debug) { + ts.log('Pager: Triggering pageMoved'); + } + c.$table + .trigger('pageMoved', c) + .trigger('applyWidgets'); + if (!p.ajax && table.isUpdating) { + if (c.debug) { + ts.log('Pager: Triggering updateComplete'); + } + c.$table.trigger('updateComplete', [ table, true ]); + } + } + }, + + setPageSize: function(table, size, c) { + var p = c.pager; + p.size = size || p.size || p.setSize || 10; + p.$size.val(p.size); + $.data(table, 'pagerLastPage', p.page); + $.data(table, 'pagerLastSize', p.size); + p.totalPages = Math.ceil( p.totalRows / p.size ); + p.filteredPages = Math.ceil( p.filteredRows / p.size ); + tsp.moveToPage(table, p, true); + }, + + moveToFirstPage: function(table, p) { + p.page = 0; + tsp.moveToPage(table, p, true); + }, + + moveToLastPage: function(table, p) { + p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 ); + tsp.moveToPage(table, p, true); + }, + + moveToNextPage: function(table, p) { + p.page++; + if ( p.page >= ( Math.min( p.totalPages, p.filteredPages ) - 1 ) ) { + p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 ); + } + tsp.moveToPage(table, p, true); + }, + + moveToPrevPage: function(table, p) { + p.page--; + if ( p.page <= 0 ) { + p.page = 0; + } + tsp.moveToPage(table, p, true); + }, + + destroyPager: function(table, c, refreshing){ + var p = c.pager; + p.initialized = false; + c.$table.off( $.trim(p.events.split(' ').join('.pager ')) ); + if (refreshing) { return; } + tsp.showAllRows(table, c); + p.$container.hide(); // hide pager + c.appender = null; // remove pager appender function + delete table.config.rowsCopy; + if (ts.storage) { + ts.storage(table, c.widgetOptions.pager_storageKey, ''); + } + }, + + enablePager: function(table, c, triggered){ + var info, p = c.pager; + p.isDisabled = false; + p.page = $.data(table, 'pagerLastPage') || p.page || 0; + p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || p.setSize || 10; + p.$size.val(p.size); // set page size + p.totalPages = Math.ceil( Math.min( p.totalRows, p.filteredRows ) / p.size ); + c.$table.removeClass('pagerDisabled'); + // if table id exists, include page display with aria info + if ( table.id ) { + info = table.id + '_pager_info'; + p.$container.find(c.widgetOptions.pager_selectors.pageDisplay).attr('id', info); + c.$table.attr('aria-describedby', info); + } + tsp.changeHeight(table, c); + if ( triggered ) { + c.$table.trigger('updateRows'); + tsp.setPageSize(table, p.size, c); + tsp.hideRowsSetup(table, c); + if (c.debug) { + ts.log('Pager: Enabled'); + } + } + }, + + appender: function(table, rows) { + var c = table.config, + wo = c.widgetOptions, + p = c.pager; + if ( !p.ajax ) { + c.rowsCopy = rows; + p.totalRows = wo.pager_countChildRows ? c.$tbodies.eq(0).children('tr').length : rows.length; + p.size = $.data(table, 'pagerLastSize') || p.size || wo.pager_size || p.setSize || 10; + p.totalPages = Math.ceil( p.totalRows / p.size ); + tsp.moveToPage(table, p); + // update display here in case all rows are removed + tsp.updatePageDisplay(table, c, false); + } else { + tsp.moveToPage(table, p, true); + } + } + +}; + +// see #486 +ts.showError = function( table, message ) { + var index, $row, c, wo, errorRow, + $table = $( table ), + len = $table.length; + for ( index = 0; index < len; index++ ) { + c = $table[ index ].config; + if ( c ) { + wo = c.widgetOptions; + errorRow = c.pager && c.pager.cssErrorRow || wo.pager_css && wo.pager_css.errorRow || 'tablesorter-errorRow'; + if ( typeof message === 'undefined' ) { + c.$table.find('thead').find(c.selectorRemove).remove(); + } else { + $row = ( /tr\>/.test(message) ? $(message) : $('' + message + '') ) + .click(function(){ + $(this).remove(); + }) + // add error row to thead instead of tbody, or clicking on the header will result in a parser error + .appendTo( c.$table.find('thead:first') ) + .addClass( errorRow + ' ' + c.selectorRemove.slice(1) ) + .attr({ + role : 'alert', + 'aria-live' : 'assertive' + }); + } + } + } +}; + +})(jQuery); diff --git a/js/widgets/widget-print.js b/js/widgets/widget-print.js new file mode 100644 index 0000000..e7a53bb --- /dev/null +++ b/js/widgets/widget-print.js @@ -0,0 +1,123 @@ +/* Widget: print - updated 2/7/2015 (v2.19.0) *//* + * Requires tablesorter v2.8+ and jQuery 1.2.6+ + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; + +var ts = $.tablesorter, + +printTable = ts.printTable = { + + event : 'printTable', + basicStyle : 'table, tr, td, th { border : solid 1px black; border-collapse : collapse; } td, th { padding: 2px; }', + + init : function(c) { + c.$table + .unbind(printTable.event) + .bind(printTable.event, function(){ + // explicitly use table.config.widgetOptions because we want + // the most up-to-date values; not the "wo" from initialization + printTable.process(c, c.widgetOptions); + }); + }, + + process : function(c, wo) { + var $this, + $table = $('
    ').append(c.$table.clone()), + printStyle = printTable.basicStyle + 'table { width: 100% }' + + // hide filter row + '.tablesorter-filter-row { display: none }' + + // hide sort arrows + '.tablesorter-header { background-image: none !important; }'; + + // replace content with data-attribute content + $table.find('[' + wo.print_dataAttrib + ']').each(function(){ + $this = $(this); + $this.text( $this.attr(wo.print_dataAttrib) ); + }); + + // === rows === + // Assume "visible" means rows hidden by the pager (rows set to "display:none") + // or hidden by a class name which is added to the wo.print_extraCSS definition + if (/a/i.test(wo.print_rows)) { + // force show of all rows + printStyle += 'tbody tr { display: table-row !important; }'; + } else if (/f/i.test(wo.print_rows)) { + // add definition to show all non-filtered rows (cells hidden by the pager) + printStyle += 'tbody tr:not(.' + (wo.filter_filteredRow || 'filtered') + ') { display: table-row !important; }'; + } + + // === columns === + // columnSelector -> c.selector.$style + // Assume "visible" means hidden columns have a "display:none" style, or a class name + // add the definition to the wo.print_extraCSS option + if (/s/i.test(wo.print_columns) && c.selector && c.widgets.indexOf('columnSelector') >= 0) { + // show selected (visible) columns; make a copy of the columnSelector widget css (not media queries) + printStyle += wo.columnSelector_mediaquery && c.selector.auto ? '' : c.selector.$style.text(); + } else if (/a/i.test(wo.print_columns)) { + // force show all cells + printStyle += 'td, th { display: table-cell !important; }'; + } + + printStyle += wo.print_extraCSS; + + // callback function + if ( $.isFunction(wo.print_callback) ) { + wo.print_callback( c, $table, printStyle ); + } else { + printTable.printOutput(c, $table.html(), printStyle); + } + + }, // end process + + printOutput : function(c, data, style) { + var wo = c.widgetOptions, + generator = window.open('', wo.print_title, 'width=500,height=300'), + t = wo.print_title || c.$table.find('caption').text() || c.$table[0].id || document.title || 'table'; + generator.document.write( + '' + t + '' + + ( wo.print_styleSheet ? '' : '' ) + + '' + + '' + data + '' + ); + generator.document.close(); + generator.print(); + generator.close(); + return true; + }, + + remove : function(c) { + c.$table.off(printTable.event); + } + +}; + +ts.addWidget({ + id: 'print', + options: { + print_title : '', // this option > caption > table id > "table" + print_dataAttrib : 'data-name', // header attrib containing modified header name + print_rows : 'filtered', // (a)ll, (v)isible or (f)iltered + print_columns : 'selected', // (a)ll or (s)elected (if columnSelector widget is added) + print_extraCSS : '', // add any extra css definitions for the popup window here + print_styleSheet : '', // add the url of your print stylesheet + // callback executed when processing completes + // to continue printing, use the following function: + // function( config, $table, printStyle ) { + // // do something to the table or printStyle string + // $.tablesorter.printTable.printOutput( config, $table.html(), printStyle ); + // } + print_callback : null + }, + init: function(table, thisWidget, c) { + printTable.init(c); + }, + remove: function(table, c){ + printTable.remove(c); + } + +}); + +})(jQuery); diff --git a/js/widgets/widget-reflow.js b/js/widgets/widget-reflow.js new file mode 100644 index 0000000..063ebeb --- /dev/null +++ b/js/widgets/widget-reflow.js @@ -0,0 +1,180 @@ +/* Widget: reflow - updated 2/7/2015 (v2.19.0) *//* + * Requires tablesorter v2.8+ and jQuery 1.7+ + * Also, this widget requires the following default css (modify as desired) + + / * REQUIRED CSS: change your reflow breakpoint here (35em below) * / + @media ( max-width: 35em ) { + .ui-table-reflow td, + .ui-table-reflow th { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: right; + / * if not using the stickyHeaders widget (not the css3 version) + * the "!important" flag, and "height: auto" can be removed * / + width: 100% !important; + height: auto !important; + } + / * reflow widget * / + .ui-table-reflow tbody td[data-title]:before { + color: #469; + font-size: .9em; + content: attr(data-title); + float: left; + width: 50%; + white-space: pre-wrap; + text-align: bottom; + display: inline-block; + } + / * reflow2 widget * / + table.ui-table-reflow .ui-table-cell-label.ui-table-cell-label-top { + display: block; + padding: .4em 0; + margin: .4em 0; + text-transform: uppercase; + font-size: .9em; + font-weight: 400; + } + table.ui-table-reflow .ui-table-cell-label { + padding: .4em; + min-width: 30%; + display: inline-block; + margin: -.4em 1em -.4em -.4em; + } + } + .ui-table-reflow .ui-table-cell-label { + display: none; + } + + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; + +var ts = $.tablesorter, + +tablereflow = { + // simple reflow + // add data-attribute to each cell which shows when media query is active + // this widget DOES NOT WORK on a table with multiple thead rows + init : function(table, c, wo) { + var $this, + title = wo.reflow_dataAttrib, + header = wo.reflow_headerAttrib, + headers = []; + c.$table + .addClass(wo.reflow_className) + .off('refresh.tsreflow updateComplete.tsreflow2') + // emulate jQuery Mobile refresh + // https://api.jquerymobile.com/table-reflow/#method-refresh + .on('refresh.tsreflow updateComplete.tsreflow2', function(){ + tablereflow.init(table, c, wo); + }); + c.$headers.each(function(){ + $this = $(this); + headers.push( $.trim( $this.attr(header) || $this.text() ) ); + }); + c.$tbodies.children().each(function(){ + $(this).children().each(function(i){ + $(this).attr(title, headers[i]); + }); + }); + }, + init2: function(table, c, wo) { + var $this, $tbody, i, $hdr, txt, len, + cols = c.columns, + header = wo.reflow2_headerAttrib, + headers = []; + c.$table + .addClass(wo.reflow2_className) + .off('refresh.tsreflow2 updateComplete.tsreflow2') + // emulate jQuery Mobile refresh + // https://api.jquerymobile.com/table-reflow/#method-refresh + .on('refresh.tsreflow2 updateComplete.tsreflow2', function(){ + tablereflow.init2(table, c, wo); + }); + + // add to every table cell with thead cell contents + for (i = 0; i < cols; i++) { + $hdr = c.$headers.filter('[data-column="' + i + '"]'); + if ($hdr.length > 1) { + txt = []; + /*jshint loopfunc:true */ + $hdr.each(function(){ + $this = $(this); + if (!$this.hasClass(wo.reflow2_classIgnore)) { + txt.push( $this.attr(header) || $this.text() ); + } + }); + } else { + txt = [ $hdr.attr(header) || $hdr.text() ]; + } + headers.push( txt ); + } + // include "remove-me" class so these additional elements are removed before updating + txt = '' + headers[j][i] + ''); + i--; + } + }); + ts.processTbody(table, $tbody, false); + }); + }, + remove : function(table, c, wo) { + c.$table.removeClass(wo.reflow_className); + }, + remove2 : function(table, c, wo) { + c.$table.removeClass(wo.reflow2_className); + } +}; + +ts.addWidget({ + id: "reflow", + options: { + // class name added to make it responsive (class name within media query) + reflow_className : 'ui-table-reflow', + // header attribute containing modified header name + reflow_headerAttrib : 'data-name', + // data attribute added to each tbody cell + reflow_dataAttrib : 'data-title' + }, + init: function(table, thisWidget, c, wo) { + tablereflow.init(table, c, wo); + }, + remove: function(table, c, wo){ + tablereflow.remove(table, c, wo); + } +}); + +ts.addWidget({ + id: "reflow2", + options: { + // class name added to make it responsive (class name within media query) + reflow2_className : 'ui-table-reflow', + // ignore header cell content with this class name + reflow2_classIgnore : 'ui-table-reflow-ignore', + // header attribute containing modified header name + reflow2_headerAttrib : 'data-name', + // class name applied to thead labels + reflow2_labelClass : 'ui-table-cell-label', + // class name applied to first row thead label + reflow2_labelTop : 'ui-table-cell-label-top' + }, + init: function(table, thisWidget, c, wo) { + tablereflow.init2(table, c, wo); + }, + remove: function(table, c, wo){ + tablereflow.remove2(table, c, wo); + } +}); + + +})(jQuery); diff --git a/js/widgets/widget-repeatheaders.js b/js/widgets/widget-repeatheaders.js new file mode 100644 index 0000000..00c17ea --- /dev/null +++ b/js/widgets/widget-repeatheaders.js @@ -0,0 +1,52 @@ +/*! Widget: repeatHeaders - updated 2/7/2015 (v2.19.0) *//* +* Requires tablesorter v2.8+ and jQuery 1.7+ +* Original by Christian Bach from the example-widgets.html demo +*/ +/*global jQuery: false */ +;(function($){ + 'use strict'; + + $.tablesorter.addWidget({ + id: 'repeatHeaders', + priority: 10, + options: { + rowsToSkip : 4 + }, + // format is called on init and when a sorting has finished + format: function(table, c, wo) { + var h = '', i, $tr, l, skip; + // cache and collect all TH headers + if (!wo.repeatHeaders) { + h = ''; + for (i = 0; i < c.columns; i++) { + // only get the headerContent text + h += '' + $.trim( c.$headers.eq(i).text() ) + ''; + } + // 'remove-me' class was added in case the table needs to be updated, the 'remove-me' rows will be + // removed prior to the update to prevent including the rows in the update - see 'selectorRemove' option + wo.repeatHeaders = h + ''; + } + + // number of rows to skip + skip = wo && wo.rowsToSkip || 4; + + // remove appended headers by classname + c.$table.find('tr.repeated-header').remove(); + $tr = c.$tbodies.find('tr'); + l = $tr.length; + // loop all tr elements and insert a copy of the 'headers' + for (i = skip; i < l; i += skip) { + // insert a copy of the table head every X rows + $tr.eq(i).before(wo.repeatHeaders); + } + }, + // this remove function is called when using the refreshWidgets method or when destroying the tablesorter plugin + // this function only applies to tablesorter v2.4+ + remove: function(table, c, wo){ + wo.repeatHeaders = ''; + c.$table.find('tr.repeated-header').remove(); + } + + }); + +})(jQuery); diff --git a/js/widgets/widget-resizable.js b/js/widgets/widget-resizable.js new file mode 100644 index 0000000..7401619 --- /dev/null +++ b/js/widgets/widget-resizable.js @@ -0,0 +1,335 @@ +/*! Widget: resizable - updated 5/17/2015 (v2.22.0) */ +;(function ($, window) { +'use strict'; +var ts = $.tablesorter || {}; + +$.extend(ts.css, { + resizableContainer : 'tablesorter-resizable-container', + resizableHandle : 'tablesorter-resizable-handle', + resizableNoSelect : 'tablesorter-disableSelection', + resizableStorage : 'tablesorter-resizable' +}); + +// Add extra scroller css +$(function(){ + var s = ''; + $(s).appendTo('body'); +}); + +ts.resizable = { + init : function( c, wo ) { + if ( c.$table.hasClass( 'hasResizable' ) ) { return; } + c.$table.addClass( 'hasResizable' ); + ts.resizableReset( c.table, true ); // set default widths + + // internal variables + wo.resizable_ = { + $wrap : c.$table.parent(), + mouseXPosition : 0, + $target : null, + $next : null, + overflow : c.$table.parent().css('overflow') === 'auto', + fullWidth : Math.abs(c.$table.parent().width() - c.$table.width()) < 20, + storedSizes : [] + }; + + var noResize, $header, column, storedSizes, + marginTop = parseInt( c.$table.css( 'margin-top' ), 10 ); + + wo.resizable_.storedSizes = storedSizes = ( ( ts.storage && wo.resizable !== false ) ? + ts.storage( c.table, ts.css.resizableStorage ) : + [] ) || []; + ts.resizable.setWidths( c, wo, storedSizes ); + + wo.$resizable_container = $( '
    ' ) + .css({ top : marginTop }) + .insertBefore( c.$table ); + // add container + for ( column = 0; column < c.columns; column++ ) { + $header = c.$headerIndexed[ column ]; + noResize = ts.getData( $header, ts.getColumnData( c.table, c.headers, column ), 'resizable' ) === 'false'; + if ( !noResize ) { + $( '
    ' ) + .appendTo( wo.$resizable_container ) + .attr({ + 'data-column' : column, + 'unselectable' : 'on' + }) + .data( 'header', $header ) + .bind( 'selectstart', false ); + } + } + c.$table.one('tablesorter-initialized', function() { + ts.resizable.setHandlePosition( c, wo ); + ts.resizable.bindings( this.config, this.config.widgetOptions ); + }); + }, + + setWidth : function( $el, width ) { + $el.css({ + 'width' : width, + 'min-width' : '', + 'max-width' : '' + }); + }, + + setWidths : function( c, wo, storedSizes ) { + var column, + $extra = $( c.namespace + '_extra_headers' ), + $col = c.$table.children( 'colgroup' ).children( 'col' ); + storedSizes = storedSizes || wo.resizable_.storedSizes || []; + // process only if table ID or url match + if ( storedSizes.length ) { + for ( column = 0; column < c.columns; column++ ) { + // set saved resizable widths + c.$headerIndexed[ column ].width( storedSizes[ column ] ); + if ( $extra.length ) { + // stickyHeaders needs to modify min & max width as well + ts.resizable.setWidth( $extra.eq( column ).add( $col.eq( column ) ), storedSizes[ column ] ); + } + } + if ( $( c.namespace + '_extra_table' ).length && !ts.hasWidget( c.table, 'scroller' ) ) { + ts.resizable.setWidth( $( c.namespace + '_extra_table' ), c.$table.outerWidth() ); + } + } + }, + + setHandlePosition : function( c, wo ) { + var startPosition, + hasScroller = ts.hasWidget( c.table, 'scroller' ), + tableHeight = c.$table.height(), + $handles = wo.$resizable_container.children(), + handleCenter = Math.floor( $handles.width() / 2 ); + + if ( hasScroller ) { + tableHeight = 0; + c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function(){ + var $this = $(this); + // center table has a max-height set + tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height(); + }); + } + // subtract out table left position from resizable handles. Fixes #864 + startPosition = c.$table.position().left; + $handles.each( function() { + var $this = $(this), + column = parseInt( $this.attr( 'data-column' ), 10 ), + columns = c.columns - 1, + $header = $this.data( 'header' ); + if ( !$header ) { return; } // see #859 + if ( !$header.is(':visible') ) { + $this.hide(); + } else if ( column < columns || column === columns && wo.resizable_addLastColumn ) { + $this.css({ + display: 'inline-block', + height : tableHeight, + left : $header.position().left - startPosition + $header.outerWidth() - handleCenter + }); + } + }); + }, + + // prevent text selection while dragging resize bar + toggleTextSelection : function( c, toggle ) { + var namespace = c.namespace + 'tsresize'; + c.widgetOptions.resizable_.disabled = toggle; + $( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle ); + if ( toggle ) { + $( 'body' ) + .attr( 'unselectable', 'on' ) + .bind( 'selectstart' + namespace, false ); + } else { + $( 'body' ) + .removeAttr( 'unselectable' ) + .unbind( 'selectstart' + namespace ); + } + }, + + bindings : function( c, wo ) { + var namespace = c.namespace + 'tsresize'; + wo.$resizable_container.children().bind( 'mousedown', function( event ) { + // save header cell and mouse position + var column, $this, + vars = wo.resizable_, + $extras = $( c.namespace + '_extra_headers' ), + $header = $( event.target ).data( 'header' ); + + column = parseInt( $header.attr( 'data-column' ), 10 ); + vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') ); + vars.target = column; + + // if table is not as wide as it's parent, then resize the table + vars.$next = event.shiftKey || wo.resizable_targetLast ? + $header.parent().children().not( '.resizable-false' ).filter( ':last' ) : + $header.nextAll( ':not(.resizable-false)' ).eq( 0 ); + + column = parseInt( vars.$next.attr( 'data-column' ), 10 ); + vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') ); + vars.next = column; + + vars.mouseXPosition = event.pageX; + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + ts.resizable.toggleTextSelection( c, true ); + }); + + $( document ) + .bind( 'mousemove' + namespace, function( event ) { + var vars = wo.resizable_; + // ignore mousemove if no mousedown + if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; } + if ( wo.resizable_throttle ) { + clearTimeout( vars.timer ); + vars.timer = setTimeout( function() { + ts.resizable.mouseMove( c, wo, event ); + }, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle ); + } else { + ts.resizable.mouseMove( c, wo, event ); + } + }) + .bind( 'mouseup' + namespace, function() { + if (!wo.resizable_.disabled) { return; } + ts.resizable.toggleTextSelection( c, false ); + ts.resizable.stopResize( c, wo ); + ts.resizable.setHandlePosition( c, wo ); + }); + + // resizeEnd event triggered by scroller widget + $( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }); + + // right click to reset columns to default widths + c.$table + .bind( 'columnUpdate' + namespace, function() { + ts.resizable.setHandlePosition( c, wo ); + }) + .find( 'thead:first' ) + .add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) ) + .bind( 'contextmenu' + namespace, function() { + // $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset + var allowClick = wo.resizable_.storedSizes.length === 0; + ts.resizableReset( c.table ); + ts.resizable.setHandlePosition( c, wo ); + wo.resizable_.storedSizes = []; + return allowClick; + }); + + }, + + mouseMove : function( c, wo, event ) { + if ( wo.resizable_.mouseXPosition === 0 || !wo.resizable_.$target ) { return; } + // resize columns + var vars = wo.resizable_, + $next = vars.$next, + leftEdge = event.pageX - vars.mouseXPosition; + if ( vars.fullWidth ) { + vars.storedSizes[ vars.target ] += leftEdge; + vars.storedSizes[ vars.next ] -= leftEdge; + ts.resizable.setWidths( c, wo ); + + } else if ( vars.overflow ) { + c.$table.add( $( c.namespace + '_extra_table' ) ).width(function(i, w){ + return w + leftEdge; + }); + if ( !$next.length ) { + // if expanding right-most column, scroll the wrapper + vars.$wrap[0].scrollLeft = c.$table.width(); + } + } else { + vars.storedSizes[ vars.target ] += leftEdge; + ts.resizable.setWidths( c, wo ); + } + vars.mouseXPosition = event.pageX; + // dynamically update sticky header widths + c.$table.trigger('stickyHeadersUpdate'); + }, + + stopResize : function( c, wo ) { + var $this, column, + vars = wo.resizable_; + vars.storedSizes = []; + if ( ts.storage ) { + vars.storedSizes = []; + for ( column = 0; column < c.columns; column++ ) { + $this = c.$headerIndexed[ column ]; + vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0; + } + if ( wo.resizable !== false ) { + // save all column widths + ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes ); + } + } + vars.mouseXPosition = 0; + vars.$target = vars.$next = null; + // will update stickyHeaders, just in case, see #912 + c.$table.trigger('stickyHeadersUpdate'); + } +}; + +// this widget saves the column widths if +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: "resizable", + priority: 40, + options: { + resizable : true, + resizable_addLastColumn : false, + resizable_widths : [], + resizable_throttle : false, // set to true (5ms) or any number 0-10 range + resizable_targetLast : false + }, + init: function(table, thisWidget, c, wo) { + ts.resizable.init( c, wo ); + }, + remove: function( table, c, wo, refreshing ) { + if (wo.$resizable_container) { + var namespace = c.namespace + 'tsresize'; + c.$table.add( $( c.namespace + '_extra_table' ) ) + .removeClass('hasResizable') + .children( 'thead' ).unbind( 'contextmenu' + namespace ); + + wo.$resizable_container.remove(); + ts.resizable.toggleTextSelection( c, false ); + ts.resizableReset( table, refreshing ); + $( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace ); + } + } +}); + +ts.resizableReset = function( table, refreshing ) { + $( table ).each(function(){ + var index, $t, + c = this.config, + wo = c && c.widgetOptions; + if ( table && c && c.$headerIndexed.length ) { + for ( index = 0; index < c.columns; index++ ) { + $t = c.$headerIndexed[ index ]; + if ( wo.resizable_widths && wo.resizable_widths[ index ] ) { + $t.css( 'width', wo.resizable_widths[ index ] ); + } else if ( !$t.hasClass( 'resizable-false' ) ) { + // don't clear the width of any column that is not resizable + $t.css( 'width', '' ); + } + } + // reset stickyHeader widths + c.$table.trigger( 'stickyHeadersUpdate' ); + if ( ts.storage && !refreshing ) { + ts.storage( this, ts.css.resizableStorage, {} ); + } + } + }); +}; + +})( jQuery, window ); diff --git a/js/widgets/widget-saveSort.js b/js/widgets/widget-saveSort.js new file mode 100644 index 0000000..d34e2ad --- /dev/null +++ b/js/widgets/widget-saveSort.js @@ -0,0 +1,68 @@ +/*! Widget: saveSort */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +// this widget saves the last sort only if the +// saveSort widget option is true AND the +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: 'saveSort', + priority: 20, + options: { + saveSort : true + }, + init: function(table, thisWidget, c, wo) { + // run widget format before all other widgets are applied to the table + thisWidget.format(table, c, wo, true); + }, + format: function(table, c, wo, init) { + var stored, time, + $table = c.$table, + saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true + sortList = { "sortList" : c.sortList }; + if (c.debug) { + time = new Date(); + } + if ($table.hasClass('hasSaveSort')) { + if (saveSort && table.hasInitialized && ts.storage) { + ts.storage( table, 'tablesorter-savesort', sortList ); + if (c.debug) { + ts.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time); + } + } + } else { + // set table sort on initial run of the widget + $table.addClass('hasSaveSort'); + sortList = ''; + // get data + if (ts.storage) { + stored = ts.storage( table, 'tablesorter-savesort' ); + sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : ''; + if (c.debug) { + ts.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time); + } + $table.bind('saveSortReset', function(event) { + event.stopPropagation(); + ts.storage( table, 'tablesorter-savesort', '' ); + }); + } + // init is true when widget init is run, this will run this widget before all other widgets have initialized + // this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice. + if (init && sortList && sortList.length > 0) { + c.sortList = sortList; + } else if (table.hasInitialized && sortList && sortList.length > 0) { + // update sort change + $table.trigger('sorton', [sortList]); + } + } + }, + remove: function(table, c) { + c.$table.removeClass('hasSaveSort'); + // clear storage + if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); } + } +}); + +})(jQuery); diff --git a/js/widgets/widget-scroller.js b/js/widgets/widget-scroller.js new file mode 100644 index 0000000..7e40c96 --- /dev/null +++ b/js/widgets/widget-scroller.js @@ -0,0 +1,915 @@ +/*! Widget: scroller - updated 5/17/2015 (v2.22.0) *//* + Copyright (C) 2011 T. Connell & Associates, Inc. + + Dual-licensed under the MIT and GPL licenses + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Resizable scroller widget for the jQuery tablesorter plugin + + Version 2.0 - modified by Rob Garrison 4/12/2013; + updated 3/5/2015 (v2.22.2) with lots of help from TheSin- + Requires jQuery v1.7+ + Requires the tablesorter plugin, v2.8+, available at http://mottie.github.com/tablesorter/docs/ + + Usage: + $(function() { + $('table.tablesorter').tablesorter({ + widgets: ['zebra', 'scroller'], + widgetOptions : { + scroller_height : 300, // height of scroll window + scroller_jumpToHeader : true, // header snap to browser top when scrolling the tbody + scroller_upAfterSort : true, // scroll tbody to top after sorting + scroller_fixedColumns : 0 // set number of fixed columns + } + }); + }); + + Website: www.tconnell.com +*/ +/*jshint browser:true, jquery:true, unused:false */ +;( function( $, window ) { +'use strict'; + +var ts = $.tablesorter, + tscss = ts.css; + +$.extend( ts.css, { + scrollerWrap : 'tablesorter-scroller', + scrollerHeader : 'tablesorter-scroller-header', + scrollerTable : 'tablesorter-scroller-table', + scrollerFooter : 'tablesorter-scroller-footer', + scrollerFixed : 'tablesorter-scroller-fixed', + scrollerFixedPanel : 'tablesorter-scroller-fixed-panel', + scrollerHasFix : 'tablesorter-scroller-has-fixed-columns', + scrollerHideColumn : 'tablesorter-scroller-hidden-column', + scrollerHideElement : 'tablesorter-scroller-hidden', + scrollerSpacerRow : 'tablesorter-scroller-spacer', + scrollerBarSpacer : 'tablesorter-scroller-bar-spacer', + scrollerAddedHeight : 'tablesorter-scroller-added-height', + scrollerHack : 'tablesorter-scroller-scrollbar-hack', + scrollerReset : 'tablesorter-scroller-reset', + // class name on table cannot start with 'tablesorter-' or the + // suffix "scroller-rtl" will match as a theme name + scrollerRtl : 'ts-scroller-rtl' +}); + +ts.addWidget({ + id : 'scroller', + priority : 60, // run after the filter widget + options : { + scroller_height : 300, + // pop table header into view while scrolling up the page + scroller_jumpToHeader : true, + // scroll tbody to top after sorting + scroller_upAfterSort : true, + // set number of fixed columns + scroller_fixedColumns : 0, + // add hover highlighting to the fixed column (disable if it causes slowing) + scroller_rowHighlight : 'hover', + // add a fixed column overlay for styling + scroller_addFixedOverlay : false, + // In tablesorter v2.19.0 the scroll bar width is auto-detected + // add a value here to override the auto-detected setting + scroller_barWidth : null + }, + format : function( table, c, wo ) { + if ( !c.isScrolling ) { + // initialize here instead of in widget init to give the + // filter widget time to finish building the filter row + ts.scroller.setup( c, wo ); + } + }, + remove : function( table, c, wo ) { + ts.scroller.remove( c, wo ); + } +}); + +/* Add window resizeEnd event */ +ts.window_resize = function() { + if ( ts.timer_resize ) { + clearTimeout( ts.timer_resize ); + } + ts.timer_resize = setTimeout( function() { + $( window ).trigger( 'resizeEnd' ); + }, 250 ); +}; + +// Add extra scroller css +$( function() { + var style = ''; + $( style ).appendTo( 'body' ); +}); + +ts.scroller = { + + // Ugh.. Firefox misbehaves, so it needs to be detected + isFirefox : navigator.userAgent.toLowerCase().indexOf( 'firefox' ) > -1, + // old IE needs a wrap to hide the fixed column scrollbar; http://stackoverflow.com/a/24408672/145346 + isOldIE : document.all && !window.atob, + // http://stackoverflow.com/questions/7944460/detect-safari-browser - needed to position scrolling body + // when the table is set up in RTL direction + isSafari : navigator.userAgent.toLowerCase().indexOf( 'safari' ) > -1 && + navigator.userAgent.toLowerCase().indexOf( 'chrome' ) === -1, + + hasScrollBar : function( $target, checkWidth ) { + if ( checkWidth ) { + return $target.get(0).scrollWidth > $target.width(); + } else { + return $target.get(0).scrollHeight > $target.height(); + } + }, + + setWidth : function( $el, width ) { + $el.css({ + 'width' : width, + 'min-width' : width, + 'max-width' : width + }); + }, + + // modified from http://davidwalsh.name/detect-scrollbar-width + getBarWidth : function() { + var $div = $( '
    ' ).css({ + 'position' : 'absolute', + 'top' : '-9999px', + 'left' : 0, + 'width' : '100px', + 'height' : '100px', + 'overflow' : 'scroll', + 'visibility' : 'hidden' + }).appendTo( 'body' ), + div = $div[0], + barWidth = div.offsetWidth - div.clientWidth; + $div.remove(); + return barWidth; + }, + + setup : function( c, wo ) { + var maxHt, tbHt, $hdr, $t, $hCells, $fCells, $tableWrap, tmp, + $win = $( window ), + namespace = c.namespace + 'tsscroller', + $foot = $(), + // c.namespace contains a unique tablesorter ID, per table + id = c.namespace.slice( 1 ) + 'tsscroller', + $table = c.$table; + + wo.scroller_calcWidths = []; + wo.scroller_isBusy = true; + + // set scrollbar width & allow setting width to zero + wo.scroller_barSetWidth = wo.scroller_barWidth !== null ? + wo.scroller_barWidth : + ( ts.scroller.getBarWidth() || 15 ); + + maxHt = wo.scroller_height || 300; + + $hdr = $( '' + + $table.children( 'thead' )[ 0 ].outerHTML + '
    ' ); + wo.scroller_$header = $hdr.addClass( c.namespace.slice( 1 ) + '_extra_table' ); + + $t = $table.children( 'tfoot' ); + if ( $t.length ) { + $foot = $( '
    ' ) + .addClass( c.namespace.slice( 1 ) + '_extra_table' ) + // maintain any bindings on the tfoot cells + .append( $t.clone( true ) ) + .wrap( '
    ' ); + $fCells = $foot.children( 'tfoot' ).eq( 0 ).children( 'tr' ).children(); + } + wo.scroller_$footer = $foot; + + $table + .wrap( '
    ' ) + .before( $hdr ) + // shrink filter row but don't completely hide it because the inputs/selectors may distort the columns + .find( '.' + tscss.filterRow ) + .addClass( tscss.filterRowHide ); + + wo.scroller_$container = $table.parent(); + + if ( $foot.length ) { + // $foot.parent() to include
    wrapper + $table.after( $foot.parent() ); + } + + $hCells = $hdr + .wrap( '
    ' ) + .find( '.' + tscss.header ); + + // use max-height, so the height resizes dynamically while filtering + $table.wrap( '
    ' ); + $tableWrap = $table.parent(); + + // make scroller header sortable + ts.bindEvents( c.table, $hCells ); + + // look for filter widget + if ( $table.hasClass( 'hasFilters' ) ) { + ts.filter.bindSearch( $table, $hdr.find( '.' + tscss.filter ) ); + } + + $table + .find( 'thead' ) + .addClass( tscss.scrollerHideElement ); + + tbHt = $tableWrap.parent().height(); + + // The header will always jump into view if scrolling the table body + $tableWrap + .off( 'scroll' + namespace ) + .on( 'scroll' + namespace, function() { + if ( wo.scroller_jumpToHeader ) { + var pos = $win.scrollTop() - $hdr.offset().top; + if ( $( this ).scrollTop() !== 0 && pos < tbHt && pos > 0 ) { + $win.scrollTop( $hdr.offset().top ); + } + } + $hdr + .parent() + .add( $foot.parent() ) + .scrollLeft( $( this ).scrollLeft() ); + }); + + // Sorting, so scroll to top + tmp = 'sortEnd setFixedColumnSize updateComplete pagerComplete pagerInitialized columnUpdate ' + .split( ' ' ) + .join( namespace + ' ' ); + $table + .off( tmp ) + .on( 'sortEnd' + namespace, function() { + if ( wo.scroller_upAfterSort ) { + $table.parent().animate({ + scrollTop : 0 + }, 'fast' ); + } + }) + .on( 'setFixedColumnSize' + namespace, function( event, size ) { + var $wrap = wo.scroller_$container; + if ( typeof size !== 'undefined' && !isNaN( size ) ) { + wo.scroller_fixedColumns = parseInt( size, 10 ); + } + // remove fixed columns + ts.scroller.removeFixed( c, wo ); + size = wo.scroller_fixedColumns; + if ( size > 0 && size < c.columns - 1 ) { + ts.scroller.updateFixed( c, wo ); + } else if ( $wrap.hasClass( tscss.scrollerHasFix ) ) { + $wrap.removeClass( tscss.scrollerHasFix ); + // resize needed to make tables full width + ts.scroller.resize( c, wo ); + } + }) + .on( 'updateComplete pagerComplete columnUpdate '.split( ' ' ).join( namespace + ' ' ), function( event ) { + // Stop from running twice with pager + if ( ts.hasWidget( 'pager' ) && event.type === 'updateComplete' ) { + return; + } + // adjust column sizes after an update + ts.scroller.resize( c, wo ); + }); + + // Setup window.resizeEnd event + $win + .off( 'resize resizeEnd '.split( ' ' ).join( namespace + ' ' ) ) + .on( 'resize' + namespace, ts.window_resize ) + .on( 'resizeEnd' + namespace, function() { + // IE calls resize when you modify content, so we have to unbind the resize event + // so we don't end up with an infinite loop. we can rebind after we're done. + $win.off( 'resize' + namespace, ts.window_resize ); + ts.scroller.resize( c, wo ); + $win.on( 'resize' + namespace, ts.window_resize ); + $tableWrap.trigger( 'scroll' + namespace ); + }); + + // initialization flag + c.isScrolling = true; + + ts.scroller.updateFixed( c, wo ); + + }, + + resize : function( c, wo ) { + var index, borderWidth, setWidth, $hCells, $bCells, $fCells, $headers, $this, temp, + tsScroller = ts.scroller, + $table = c.$table, + $tableWrap = $table.parent(), + $hdr = wo.scroller_$header, + $foot = wo.scroller_$footer, + id = c.namespace.slice( 1 ) + 'tsscroller', + // Hide other scrollers so we can resize + $div = $( 'div.' + tscss.scrollerWrap + '[id!="' + id + '"]' ) + .addClass( tscss.scrollerHideElement ); + + wo.scroller_calcWidths = []; + + // Remove fixed so we get proper widths and heights + tsScroller.removeFixed( c, wo ); + + // show original table elements to get proper alignment + $table + .find( '.' + tscss.scrollerHideElement ) + .removeClass( tscss.scrollerHideElement ); + + // Reset sizes so parent can resize. + $table + .addClass( tscss.scrollerReset ) + .children( 'thead' ) + .find( '.' + tscss.headerIn ) + .addClass( tscss.scrollerReset ); + $tableWrap.addClass( tscss.scrollerReset ); + + // include left & right border widths + borderWidth = parseInt( $table.css( 'border-left-width' ), 10 ); + + $hCells = $hdr + .children( 'thead' ) + .children( 'tr' ) + .not( '.' + c.cssIgnoreRow ) + .children( 'th, td' ) + .filter( ':visible' ); + $bCells = c.$tbodies + .eq( 0 ) + .children( 'tr' ) + .not( '.' + c.cssChildRow ) + .eq( 0 ) + .children( 'th, td' ) + .filter( ':visible' ); + $fCells = $foot + .children( 'tfoot' ) + .children( 'tr' ) + .children( 'th, td' ) + .filter( ':visible' ); + + tsScroller.setWidth( $hCells.add( $bCells ).add( $fCells ), '' ); + $headers = c.$headerIndexed; + + for ( index = 0; index < $headers.length; index++ ) { + $this = $headers[ index ]; + // code from https://github.com/jmosbech/StickyTableHeaders + if ( $this.css( 'box-sizing' ) === 'border-box' ) { + setWidth = $this.outerWidth(); + } else { + if ( $hCells.eq( index ).css( 'border-collapse' ) === 'collapse' ) { + if ( $this.length && window.getComputedStyle ) { + setWidth = parseFloat( window.getComputedStyle( $this[ 0 ], null ).width ); + } else { + // ie8 only + setWidth = $this.outerWidth() - parseFloat( $this.css( 'padding-left' ) ) - + parseFloat( $this.css( 'padding-right' ) ) - + ( parseFloat( $this.css( 'border-width' ) ) || 0 ); + } + } else { + setWidth = $this.width(); + } + } + temp = $hCells.eq( index ) + .add( $bCells.eq( index ) ) + .add( $fCells.eq( index ) ); + tsScroller.setWidth( temp, setWidth ); + // save current widths + wo.scroller_calcWidths[ index ] = setWidth; + } + + temp = $tableWrap.parent().innerWidth() - + ( tsScroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 ); + $tableWrap.width( temp ); + + temp = ( tsScroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 ) + borderWidth; + setWidth = $tableWrap.innerWidth() - temp; + + $hdr + .parent() + .add( $foot.parent() ) + .width( setWidth ); + + $tableWrap + .width( setWidth + temp ); + + wo.scroller_$container + .find( '.' + tscss.scrollerReset ) + .removeClass( tscss.scrollerReset ); + + // hide original table thead + $table.children( 'thead' ).addClass( tscss.scrollerHideElement ); + + // update fixed column sizes + tsScroller.updateFixed( c, wo ); + + $div.removeClass( tscss.scrollerHideElement ); + + }, + + // Add fixed (frozen) columns (Do not call directly, use updateFixed) + setupFixed : function( c, wo ) { + var index, index2, $el, len, temp, $fixedColumn, $fixedTbody, + $table = c.$table, + $wrapper = wo.scroller_$container, + fixedColumns = wo.scroller_fixedColumns; + + $fixedColumn = $wrapper + .addClass( tscss.scrollerHasFix ) + .clone() + .addClass( tscss.scrollerFixed ) + .removeClass( tscss.scrollerWrap ) + .attr( 'id', '' ); + + if ( wo.scroller_addFixedOverlay ) { + $fixedColumn.append( '
    ' ); + } + + $fixedTbody = $fixedColumn.find( '.' + tscss.scrollerTable ); + $fixedTbody + .children( 'table' ) + .addClass( c.namespace.slice( 1 ) + '_extra_table' ) + .attr( 'id', '' ) + .children( 'thead, tfoot' ) + .remove(); + + wo.scroller_$fixedColumns = $fixedColumn; + + // RTL support (fixes column on right) + if ( $table.hasClass( tscss.scrollerRtl ) ) { + $fixedColumn.addClass( tscss.scrollerRtl ); + } + + $el = $fixedColumn.find( 'tr' ); + len = $el.length; + for ( index = 0; index < len; index++ ) { + $el.eq( index ).children( ':gt(' + ( fixedColumns - 1 ) + ')' ).remove(); + } + $fixedColumn + .addClass( tscss.scrollerHideElement ) + .prependTo( $wrapper ); + + // look for filter widget + if ( c.$table.hasClass( 'hasFilters' ) ) { + // make sure fixed column filters aren't disabled + $el = $fixedColumn + .find( '.' + tscss.filter ) + .not( '.' + tscss.filterDisabled ) + .prop( 'disabled', false ); + ts.filter.bindSearch( $table, $fixedColumn.find( '.' + tscss.filter ) ); + // disable/enable filters behind fixed column + $el = $wrapper + .children( '.' + tscss.scrollerHeader ) + .find( '.' + tscss.filter ); + len = $el.length; + for ( index = 0; index < len; index++ ) { + // previously disabled filter; don't mess with it! filterDisabled class added by filter widget + if ( !$el.eq( index ).hasClass( tscss.filterDisabled || 'disabled' ) ) { + // disable filters behind fixed column; don't disable visible filters + $el.eq( index ).prop( 'disabled', index < fixedColumns ); + } + } + } + + // disable/enable tab indexes behind fixed column + c.$table + .add( '.' + tscss.scrollerFooter + ' table' ) + .children( 'thead' ) + .children( 'tr.' + tscss.headerRow ) + .children() + .attr( 'tabindex', -1 ); + + $el = wo.scroller_$header + .add( $fixedColumn.find( '.' + tscss.scrollerTable + ' table' ) ) + .children( 'thead' ) + .children( 'tr.' + tscss.headerRow ); + len = $el.length; + for ( index = 0; index < len; index++ ) { + temp = $el.eq( index ).children(); + for ( index2 = 0; index2 < temp.length; index2++ ) { + temp.eq( index2 ).attr( 'tabindex', index2 < fixedColumns ? -1 : 0 ); + } + } + + ts.bindEvents( c.table, $fixedColumn.find( '.' + tscss.header ) ); + ts.scroller.bindFixedColumnEvents( c, wo ); + + /*** Scrollbar hack! Since we can't hide the scrollbar with css ***/ + if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) { + $fixedTbody.wrap( '
    ' ); + } + + }, + + bindFixedColumnEvents : function( c, wo ) { + // update thead & tbody in fixed column + var tsScroller = ts.scroller, + namespace = c.namespace + 'tsscrollerFixed', + // bind to ts-init or filterEnd, but not both! + events = ( ( ts.hasWidget( c.table, 'filter' ) ? 'filterEnd' : 'tablesorter-initialized' ) + + ' sortEnd ' ).split( ' ' ).join( namespace + ' ' ), + events2 = 'scroll' + namespace, + $fixedTbody = wo.scroller_$fixedColumns.find( '.' + tscss.scrollerTable ), + fixedScroll = true, + tableScroll = true; + + c.$table + .off( events ) + .on( events, function() { + tsScroller.updateFixed( c, wo, false ); + tsScroller.resize( c, wo ); + }) + .parent() + // *** SCROLL *** scroll fixed column along with main + .off( events2 ) + .on( events2, function() { + if ( wo.scroller_isBusy ) { return; } + // using flags to prevent firing the scroll event excessively leading to slow scrolling in Firefox + if ( fixedScroll || !tsScroller.isFirefox ) { + tableScroll = false; + $fixedTbody[0].scrollTop = $( this ).scrollTop(); + setTimeout( function() { + tableScroll = true; + }, 20 ); + } + }); + // scroll main along with fixed column + $fixedTbody + .off( events2 ) + .on( events2, function() { + // using flags to prevent firing the scroll event excessively leading to slow scrolling in Firefox + if ( tableScroll || !tsScroller.isFirefox ) { + fixedScroll = false; + c.$table.parent()[0].scrollTop = $( this ).scrollTop(); + setTimeout( function() { + fixedScroll = true; + }, 20 ); + } + }) + .scroll(); + + // *** ROW HIGHLIGHT *** + if ( wo.scroller_rowHighlight !== '' ) { + events = 'mouseover mouseleave '.split( ' ' ).join( namespace + ' ' ); + // can't use c.$tbodies because it doesn't include info-only tbodies + c.$table + .off( events, 'tbody > tr' ) + .on( events, 'tbody > tr', function( event ) { + var indx = c.$table.children( 'tbody' ).children( 'tr' ).index( this ); + $fixedTbody + .children( 'table' ) + .children( 'tbody' ) + .children( 'tr' ) + .eq( indx ) + .add( this ) + .toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' ); + }); + $fixedTbody + .find( 'table' ) + .off( events, 'tbody > tr' ) + .on( events, 'tbody > tr', function( event ) { + var $fixed = $fixedTbody.children( 'table' ).children( 'tbody' ).children( 'tr' ), + indx = $fixed.index( this ); + c.$table + .children( 'tbody' ) + .children( 'tr' ) + .eq( indx ) + .add( this ) + .toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' ); + }); + } + }, + + updateFixed : function( c, wo ) { + var $wrapper = wo.scroller_$container; + + if ( wo.scroller_fixedColumns === 0 ) { + wo.scroller_isBusy = false; + ts.scroller.removeFixed( c, wo ); + return; + } + + if ( !c.isScrolling ) { + return; + } + + wo.scroller_isBusy = true; + + // Make sure the wo.scroller_$fixedColumns container exists, if not build it + if ( !$wrapper.find( '.' + tscss.scrollerFixed ).length ) { + ts.scroller.setupFixed( c, wo ); + } + + // scroller_fixedColumns + var index, tbodyIndex, rowIndex, $tbody, $adjCol, $fb, $fixHead, $fixBody, $fixFoot, + totalRows, temp, adj, row, + $table = c.$table, + $tableWrap = $table.parent(), + $hdr = wo.scroller_$header, + $foot = wo.scroller_$footer, + + // source cells for measurement + $mainTbodies = wo.scroller_$container + .children( '.' + tscss.scrollerTable ) + .children( 'table' ) + .children( 'tbody' ), + // variable gets redefined + $rows = wo.scroller_$header + .children( 'thead' ) + .children( '.' + tscss.headerRow ), + + // hide fixed column during resize, or we get a FOUC + $fixedColumn = wo.scroller_$fixedColumns + .addClass( tscss.scrollerHideElement ), + + // target cells + $fixedTbodiesTable = $fixedColumn + .find( '.' + tscss.scrollerTable ) + .children( 'table' ), + $fixedTbodies = $fixedTbodiesTable + .children( 'tbody' ), + // variables + tsScroller = ts.scroller, + scrollBarWidth = wo.scroller_barSetWidth, + fixedColumns = wo.scroller_fixedColumns, + dir = $table.hasClass( tscss.scrollerRtl ), + // get dimensions + $temp = $table.find( 'tbody td' ), + borderRightWidth = parseInt( $temp.css( 'border-right-width' ), 10 ) || 1, + borderSpacing = parseInt( ( $temp.css( 'border-spacing' ) || '' ).split( /\s/ )[ 0 ], 10 ) / 2 || 0, + totalWidth = parseInt( $table.css( 'padding-left' ), 10 ) + + parseInt( $table.css( 'padding-right' ), 10 ) - + borderRightWidth, + widths = wo.scroller_calcWidths; + + ts.scroller.removeFixed( c, wo, false ); + + // calculate fixed column width + for ( index = 0; index < fixedColumns; index++ ) { + totalWidth += widths[ index ] + borderSpacing; + } + + // set fixed column width + totalWidth = totalWidth + borderRightWidth * 2 - borderSpacing; + tsScroller.setWidth( $fixedColumn.add( $fixedColumn.children() ), totalWidth ); + tsScroller.setWidth( $fixedColumn.children().children( 'table' ), totalWidth ); + + $table.find( '.' + tscss.scrollerSpacerRow ).remove(); + row = ''; + for ( index = 0; index < c.columns; index++ ) { + row += ''; + } + c.$tbodies.eq(0).prepend( row += '' ); + + // update fixed column tbody content, set cell widths on hidden row + for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) { + $tbody = $mainTbodies.eq( tbodyIndex ); + if ( $tbody.length ) { + // get tbody + $rows = $tbody.children(); + totalRows = $rows.length; + $fb = ts.processTbody( $fixedTbodiesTable, $fixedTbodies.eq( tbodyIndex ), true ); + $fb.empty(); + // update tbody cells after sort/filtering + for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) { + $adjCol = $( $rows[ rowIndex ].outerHTML ); + $adjCol + .children( 'td, th' ) + .slice( fixedColumns ) + .remove(); + $fb.append( $adjCol ); + } + // adjust fixed thead/tbody/tfoot cell widths + $fixHead = $fixedColumn + .find( 'thead' ) + .children( 'tr.' + tscss.headerRow ) + .children(); + $fixBody = $fixedColumn + .find( tscss.scrollerSpacerRow ) + .children(); + $fixFoot = $fixedColumn + .find( 'tfoot' ) + .children( 'tr' ) + .eq( 0 ) + .children(); + // reusing variables, so ignore the names :P + $adjCol = $hdr.children( 'thead' ).children( 'tr' ).children( 'td, th' ); + $rows = $foot.children( 'tfoot' ).children( 'tr' ).children( 'td, th' ); + for ( index = 0; index < c.columns; index++ ) { + if ( index < fixedColumns ) { + $temp = $fixHead.eq( index ) + .add( $fixBody.eq( index ) ) + .add( $fixFoot.eq( index ) ); + tsScroller.setWidth( $temp, widths[ index ] ); + } + $temp = $adjCol.eq( index ) + .add( $rows.eq( index ) ); + tsScroller.setWidth( $temp, widths[ index ] ); + } + + // restore tbody + ts.processTbody( $fixedTbodiesTable, $fb, false ); + } + } + + adj = ts.scroller.hasScrollBar( $tableWrap ) ? scrollBarWidth : 0; + + /*** scrollbar HACK! Since we can't hide the scrollbar with css ***/ + if ( tsScroller.isFirefox || tsScroller.isOldIE ) { + $fixedTbodiesTable + .css( 'width', totalWidth ) + .parent() + .css( 'width', totalWidth + adj ); + } + + $fixedColumn.removeClass( tscss.scrollerHideElement ); + for ( index = 0; index < fixedColumns; index++ ) { + $wrapper + .children( 'div' ) + .children( 'table' ) + .find( 'th:nth-child(' + ( index + 1 ) + '), td:nth-child(' + ( index + 1 ) + ')' ) + .addClass( tscss.scrollerHideColumn ); + } + + totalWidth = totalWidth - borderRightWidth; + temp = $tableWrap.parent().innerWidth() - totalWidth; + $tableWrap.width( temp ); + // RTL support (fixes column on right) + $wrapper + .children( '.' + tscss.scrollerTable ) + .css( dir ? 'right' : 'left', totalWidth ); + $wrapper + .children( '.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter ) + // Safari needs a scrollbar width of extra adjusment to align the fixed & scrolling columns + .css( dir ? 'right' : 'left', totalWidth + ( dir && ts.scroller.isSafari ? adj : 0 ) ); + + $hdr + .parent() + .add( $foot.parent() ) + .width( temp - adj ); + + // fix gap under the tbody for the horizontal scrollbar + temp = ts.scroller.hasScrollBar( $tableWrap, true ); + adj = temp ? scrollBarWidth : 0; + if ( !$fixedColumn.find( '.' + tscss.scrollerBarSpacer ).length && temp ) { + $temp = $( '
    ' ) + .css( 'height', adj + 'px' ); + $fixedColumn.find( '.' + tscss.scrollerTable ).append( $temp ); + } else if ( !temp ) { + $fixedColumn.find( '.' + tscss.scrollerBarSpacer ).remove(); + } + + ts.scroller.updateRowHeight( c, wo ); + // set fixed column height (changes with filtering) + $fixedColumn.height( $wrapper.height() ); + + $fixedColumn.removeClass( tscss.scrollerHideElement ); + + wo.scroller_isBusy = false; + }, + + fixHeight : function( $rows, $fixedRows ) { + var index, heightRow, heightFixed, $r, $f, + len = $rows.length; + for ( index = 0; index < len; index++ ) { + $r = $rows.eq( index ); + $f = $fixedRows.eq( index ); + heightRow = $r.height(); + heightFixed = $f.height(); + if ( heightRow > heightFixed ) { + $f.addClass( tscss.scrollerAddedHeight ).height( heightRow ); + } else if ( heightRow < heightFixed ) { + $r.addClass( tscss.scrollerAddedHeight ).height( heightFixed ); + } + } + }, + + updateRowHeight : function( c, wo ) { + var $rows, $fixed, + $fixedColumns = wo.scroller_$fixedColumns; + + wo.scroller_$container + .find( '.' + tscss.scrollerAddedHeight ) + .removeClass( tscss.scrollerAddedHeight ) + .height( '' ); + + $rows = wo.scroller_$header + .children( 'thead' ) + .children( 'tr' ); + $fixed = $fixedColumns + .children( '.' + tscss.scrollerHeader ) + .children( 'table' ) + .children( 'thead' ) + .children( 'tr' ); + ts.scroller.fixHeight( $rows, $fixed ); + + $rows = wo.scroller_$footer + .children( 'tfoot' ) + .children( 'tr' ); + $fixed = $fixedColumns + .children( '.' + tscss.scrollerFooter ) + .children( 'table' ) + .children( 'tfoot' ) + .children( 'tr' ); + ts.scroller.fixHeight( $rows, $fixed ); + + if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) { + // Firefox/Old IE scrollbar hack (wraps table to hide the scrollbar) + $fixedColumns = $fixedColumns.find( '.' + tscss.scrollerHack ); + } + $rows = c.$table + .children( 'tbody' ) + .children( 'tr' ); + $fixed = $fixedColumns + .children( '.' + tscss.scrollerTable ) + .children( 'table' ) + .children( 'tbody' ) + .children( 'tr' ); + ts.scroller.fixHeight( $rows, $fixed ); + + }, + + removeFixed : function( c, wo, removeIt ) { + var $table = c.$table, + $wrapper = wo.scroller_$container, + dir = $table.hasClass( tscss.scrollerRtl ); + + // remove fixed columns + if ( removeIt || typeof removeIt === 'undefined' ) { + $wrapper.find( '.' + tscss.scrollerFixed ).remove(); + } + + $wrapper + .find( '.' + tscss.scrollerHideColumn ) + .removeClass( tscss.scrollerHideColumn ); + + // RTL support ( fixes column on right ) + $wrapper + .children( ':not(.' + tscss.scrollerFixed + ')' ) + .css( dir ? 'right' : 'left', 0 ); + }, + + remove : function( c, wo ) { + var $wrap = wo.scroller_$container, + namespace = c.namespace + 'tsscroller'; + c.$table + .off( namespace ) + .insertBefore( $wrap ) + .find( 'thead' ) + .removeClass( tscss.scrollerHideElement ) + .children( 'tr.' + tscss.headerRow ) + .children() + .attr( 'tabindex', 0 ) + .end() + .find( '.' + tscss.filterRow ) + .removeClass( tscss.scrollerHideElement + ' ' + tscss.filterRowHide ); + c.$table + .find( '.' + tscss.filter ) + .not( '.' + tscss.filterDisabled ) + .prop( 'disabled', false ); + $wrap.remove(); + $( window ).off( namespace ); + c.isScrolling = false; + } + +}; + +})( jQuery, window ); diff --git a/js/widgets/widget-staticRow.js b/js/widgets/widget-staticRow.js new file mode 100644 index 0000000..ea04b85 --- /dev/null +++ b/js/widgets/widget-staticRow.js @@ -0,0 +1,121 @@ +/*! widget: staticRow - updated 2/9/2015 (v2.19.1) *//* + * Version 1.2 mod by Rob Garrison (requires tablesorter v2.16+) + * Requires: + * jQuery v1.4+ + * tablesorter plugin, v2.8+, available at http://mottie.github.com/tablesorter/docs/ + * + * Copyright (c) 2011 Nils Luxton + * Licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; +var ts = $.tablesorter, + +// add/refresh row indexes +addIndexes = function(table){ + var $tr, wo, v, indx, rows, + c = table.config; + // "Index" the static rows, saving their current (starting) position in the + // table inside a data() param on the element itself for later use. + if (c) { + wo = c.widgetOptions; + c.$tbodies.each(function(){ + $tr = $(this).children(); + rows = $tr.length; + $tr.filter(wo.staticRow_class).each(function() { + $tr = $(this); + indx = $tr.data(wo.staticRow_index); + if (typeof indx !== "undefined") { + v = parseFloat(indx); + // percentage of total rows + indx = (/%/.test(indx)) ? Math.round(v/100 * rows) : v; + } else { + indx = $tr.index(); + } + // row indexing starts over within each tbody + $tr.data( wo.staticRow_data, indx ); + }); + }); + } +}; + +ts.addWidget({ + // Give the new Widget an ID to be used in the tablesorter() call, as follows: + // $('#myElement').tablesorter({ widgets: ['zebra', 'staticRow'] }); + id: 'staticRow', + + options: { + staticRow_class : '.static', + staticRow_data : 'static-index', + staticRow_index : 'row-index', + staticRow_event : 'staticRowsRefresh' + }, + + init: function(table, thisWidget, c, wo){ + addIndexes(table); + // refresh static rows after updates + c.$table + .unbind( ('updateComplete.tsstaticrows ' + wo.staticRow_event).replace(/\s+/g, ' ') ) + .bind('updateComplete.tsstaticrows ' + wo.staticRow_event, function(){ + addIndexes(table); + c.$table.trigger('applyWidgets'); + }); + }, + + format: function(table, c, wo) { + // Loop thru static rows, moving them to their original "indexed" position, + // & repeat until no more re-shuffling is needed + var targetIndex, $thisRow, indx, numRows, $tbody, hasShuffled, $rows, max; + + c.$tbodies.each(function(){ + $tbody = $.tablesorter.processTbody(table, $(this), true); // remove tbody + hasShuffled = true; + indx = 0; + $rows = $tbody.children(wo.staticRow_class); + numRows = $tbody.children('tr').length - 1; + max = $rows.length; + + // don't allow the while loop to cycle more times than the set number of static rows + while (hasShuffled && indx < max) { + hasShuffled = false; + /*jshint loopfunc:true */ + $rows.each(function() { + targetIndex = $(this).data(wo.staticRow_data); + // allow setting target index >> num rows to always make a row last + targetIndex = targetIndex >= numRows ? numRows : targetIndex < 0 ? 0 : targetIndex; + if (targetIndex !== $(this).index()) { + hasShuffled = true; + $thisRow = $(this).detach(); + + if (targetIndex >= numRows) { + // Are we trying to be the last row? + $thisRow.appendTo( $tbody ); + } else if (targetIndex === 0) { + // Are we trying to be the first row? + $thisRow.prependTo( $tbody ); + } else { + // No, we want to be somewhere in the middle! + $thisRow.insertBefore( $tbody.find('tr:eq(' + targetIndex + ')') ); + } + } + }); + indx++; + } + + $.tablesorter.processTbody(table, $tbody, false); // restore tbody + }); + + c.$table.trigger('staticRowsComplete', table); + }, + + remove : function(table, c, wo){ + c.$table.unbind( ('updateComplete.tsstaticrows ' + wo.staticRow_event).replace(/\s+/g, ' ') ); + } + +}); + +})(jQuery); \ No newline at end of file diff --git a/js/widgets/widget-stickyHeaders.js b/js/widgets/widget-stickyHeaders.js new file mode 100644 index 0000000..f0fa8fc --- /dev/null +++ b/js/widgets/widget-stickyHeaders.js @@ -0,0 +1,288 @@ +/*! Widget: stickyHeaders - updated 3/26/2015 (v2.21.3) *//* + * Requires tablesorter v2.8+ and jQuery 1.4.3+ + * by Rob Garrison + */ +;(function ($, window) { +'use strict'; +var ts = $.tablesorter || {}; + +$.extend(ts.css, { + sticky : 'tablesorter-stickyHeader', // stickyHeader + stickyVis : 'tablesorter-sticky-visible', + stickyHide: 'tablesorter-sticky-hidden', + stickyWrap: 'tablesorter-sticky-wrapper' +}); + +// Add a resize event to table headers +ts.addHeaderResizeEvent = function(table, disable, settings) { + table = $(table)[0]; // make sure we're using a dom element + if ( !table.config ) { return; } + var defaults = { + timer : 250 + }, + options = $.extend({}, defaults, settings), + c = table.config, + wo = c.widgetOptions, + checkSizes = function( triggerEvent ) { + var index, headers, $header, sizes, width, height, + len = c.$headers.length; + wo.resize_flag = true; + headers = []; + for ( index = 0; index < len; index++ ) { + $header = c.$headers.eq( index ); + sizes = $header.data( 'savedSizes' ) || [ 0,0 ]; // fixes #394 + width = $header[0].offsetWidth; + height = $header[0].offsetHeight; + if ( width !== sizes[0] || height !== sizes[1] ) { + $header.data( 'savedSizes', [ width, height ] ); + headers.push( $header[0] ); + } + } + if ( headers.length && triggerEvent !== false ) { + c.$table.trigger( 'resize', [ headers ] ); + } + wo.resize_flag = false; + }; + checkSizes( false ); + clearInterval(wo.resize_timer); + if (disable) { + wo.resize_flag = false; + return false; + } + wo.resize_timer = setInterval(function() { + if (wo.resize_flag) { return; } + checkSizes(); + }, options.timer); +}; + +// Sticky headers based on this awesome article: +// http://css-tricks.com/13465-persistent-headers/ +// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech +// ************************** +ts.addWidget({ + id: "stickyHeaders", + priority: 60, // sticky widget must be initialized after the filter widget! + options: { + stickyHeaders : '', // extra class name added to the sticky header row + stickyHeaders_attachTo : null, // jQuery selector or object to attach sticky header to + stickyHeaders_xScroll : null, // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window) + stickyHeaders_yScroll : null, // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window) + stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element + stickyHeaders_filteredToTop: true, // scroll table top into view after filtering + stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists + stickyHeaders_addResizeEvent : true, // trigger "resize" event on headers + stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header + stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs + }, + format: function(table, c, wo) { + // filter widget doesn't initialize on an empty table. Fixes #449 + if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) { + return; + } + var index, len, $t, + $table = c.$table, + // add position: relative to attach element, hopefully it won't cause trouble. + $attach = $(wo.stickyHeaders_attachTo), + namespace = c.namespace + 'stickyheaders ', + // element to watch for the scroll event + $yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window), + $xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window), + $thead = $table.children('thead:first'), + $header = $thead.children('tr').not('.sticky-false').children(), + $tfoot = $table.children('tfoot'), + $stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '', + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0, + // is this table nested? If so, find parent sticky header wrapper (div, not table) + $nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ? + $table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [], + nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0, + // clone table, then wrap to make sticky header + $stickyTable = wo.$sticky = $table.clone() + .addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders + ' ' + c.namespace.slice(1) + '_extra_table' ) + .wrap('
    '), + $stickyWrap = $stickyTable.parent() + .addClass(ts.css.stickyHide) + .css({ + position : $attach.length ? 'absolute' : 'fixed', + padding : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ), + top : stickyOffset + nestedStickyTop, + left : 0, + visibility : 'hidden', + zIndex : wo.stickyHeaders_zIndex || 2 + }), + $stickyThead = $stickyTable.children('thead:first'), + $stickyCells, + laststate = '', + spacing = 0, + setWidth = function($orig, $clone){ + var index, width, border, $cell, $this, + $cells = $orig.filter(':visible'), + len = $cells.length; + for ( index = 0; index < len; index++ ) { + $cell = $clone.filter(':visible').eq(index); + $this = $cells.eq(index); + // code from https://github.com/jmosbech/StickyTableHeaders + if ($this.css('box-sizing') === 'border-box') { + width = $this.outerWidth(); + } else { + if ($cell.css('border-collapse') === 'collapse') { + if (window.getComputedStyle) { + width = parseFloat( window.getComputedStyle($this[0], null).width ); + } else { + // ie8 only + border = parseFloat( $this.css('border-width') ); + width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border; + } + } else { + width = $this.width(); + } + } + $cell.css({ + 'width': width, + 'min-width': width, + 'max-width': width + }); + } + }, + resizeHeader = function() { + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0; + spacing = 0; + $stickyWrap.css({ + left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 : + $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing, + width: $table.outerWidth() + }); + setWidth( $table, $stickyTable ); + setWidth( $header, $stickyCells ); + }, + scrollSticky = function( resizing ) { + if (!$table.is(':visible')) { return; } // fixes #278 + // Detect nested tables - fixes #724 + nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0; + var offset = $table.offset(), + yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3 + xWindow = $.isWindow( $xScroll[0] ), + // scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop, + scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop, + tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)), + isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden', + cssSettings = { visibility : isVisible }; + + if ($attach.length) { + cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop(); + } + if (xWindow) { + // adjust when scrolling horizontally - fixes issue #143 + cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing; + } + if ($nestedSticky.length) { + cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop; + } + $stickyWrap + .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide ) + .addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide ) + .css(cssSettings); + if (isVisible !== laststate || resizing) { + // make sure the column widths match + resizeHeader(); + laststate = isVisible; + } + }; + // only add a position relative if a position isn't already defined + if ($attach.length && !$attach.css('position')) { + $attach.css('position', 'relative'); + } + // fix clone ID, if it exists - fixes #271 + if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; } + // clear out cloned table, except for sticky header + // include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing + $stickyTable.find('thead:gt(0), tr.sticky-false').hide(); + $stickyTable.find('tbody, tfoot').remove(); + $stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption); + // issue #172 - find td/th in sticky header + $stickyCells = $stickyThead.children().children(); + $stickyTable.css({ height:0, width:0, margin: 0 }); + // remove resizable block + $stickyCells.find('.' + ts.css.resizer).remove(); + // update sticky header class names to match real header after sorting + $table + .addClass('hasStickyHeaders') + .bind('pagerComplete' + namespace, function() { + resizeHeader(); + }); + + ts.bindEvents(table, $stickyThead.children().children('.' + ts.css.header)); + + // add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned. + $table.after( $stickyWrap ); + + // onRenderHeader is defined, we need to do something about it (fixes #641) + if (c.onRenderHeader) { + $t = $stickyThead.children('tr').children(); + len = $t.length; + for ( index = 0; index < len; index++ ) { + // send second parameter + c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] ); + } + } + + // make it sticky! + $xScroll.add($yScroll) + .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') ) + .bind('scroll resize '.split(' ').join( namespace ), function( event ) { + scrollSticky( event.type === 'resize' ); + }); + c.$table + .unbind('stickyHeadersUpdate' + namespace) + .bind('stickyHeadersUpdate' + namespace, function(){ + scrollSticky( true ); + }); + + if (wo.stickyHeaders_addResizeEvent) { + ts.addHeaderResizeEvent(table); + } + + // look for filter widget + if ($table.hasClass('hasFilters') && wo.filter_columnFilters) { + // scroll table into view after filtering, if sticky header is active - #482 + $table.bind('filterEnd' + namespace, function() { + // $(':focus') needs jQuery 1.6+ + var $td = $(document.activeElement).closest('td'), + column = $td.parent().children().index($td); + // only scroll if sticky header is active + if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) { + // scroll to original table (not sticky clone) + window.scrollTo(0, $table.position().top); + // give same input/select focus; check if c.$filters exists; fixes #594 + if (column >= 0 && c.$filters) { + c.$filters.eq(column).find('a, select, input').filter(':visible').focus(); + } + } + }); + ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) ); + // support hideFilters + if (wo.filter_hideFilters) { + ts.filter.hideFilters($stickyTable, c); + } + } + + $table.trigger('stickyHeadersInit'); + + }, + remove: function(table, c, wo) { + var namespace = c.namespace + 'stickyheaders '; + c.$table + .removeClass('hasStickyHeaders') + .unbind( ('pagerComplete filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') ) + .next('.' + ts.css.stickyWrap).remove(); + if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table + $(window) + .add(wo.stickyHeaders_xScroll) + .add(wo.stickyHeaders_yScroll) + .add(wo.stickyHeaders_attachTo) + .unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') ); + ts.addHeaderResizeEvent(table, false); + } +}); + +})(jQuery, window); diff --git a/js/widgets/widget-storage.js b/js/widgets/widget-storage.js new file mode 100644 index 0000000..472d34c --- /dev/null +++ b/js/widgets/widget-storage.js @@ -0,0 +1,89 @@ +/*! Widget: storage - updated 3/26/2015 (v2.21.3) */ +;(function ($, window, document) { +'use strict'; + +var ts = $.tablesorter || {}; +// *** Store data in local storage, with a cookie fallback *** +/* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json) + if you need it, then include https://github.com/douglascrockford/JSON-js + + $.parseJSON is not available is jQuery versions older than 1.4.1, using older + versions will only allow storing information for one page at a time + + // *** Save data (JSON format only) *** + // val must be valid JSON... use http://jsonlint.com/ to ensure it is valid + var val = { "mywidget" : "data1" }; // valid JSON uses double quotes + // $.tablesorter.storage(table, key, val); + $.tablesorter.storage(table, 'tablesorter-mywidget', val); + + // *** Get data: $.tablesorter.storage(table, key); *** + v = $.tablesorter.storage(table, 'tablesorter-mywidget'); + // val may be empty, so also check for your data + val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : ''; + alert(val); // "data1" if saved, or "" if not +*/ +ts.storage = function(table, key, value, options) { + table = $(table)[0]; + var cookieIndex, cookies, date, + hasStorage = false, + values = {}, + c = table.config, + wo = c && c.widgetOptions, + storageType = ( options && options.useSessionStorage ) || ( wo && wo.storage_useSessionStorage ) ? + 'sessionStorage' : 'localStorage', + $table = $(table), + // id from (1) options ID, (2) table "data-table-group" attribute, (3) widgetOptions.storage_tableId, + // (4) table ID, then (5) table index + id = options && options.id || + $table.attr( options && options.group || wo && wo.storage_group || 'data-table-group') || + wo && wo.storage_tableId || table.id || $('.tablesorter').index( $table ), + // url from (1) options url, (2) table "data-table-page" attribute, (3) widgetOptions.storage_fixedUrl, + // (4) table.config.fixedUrl (deprecated), then (5) window location path + url = options && options.url || + $table.attr(options && options.page || wo && wo.storage_page || 'data-table-page') || + wo && wo.storage_fixedUrl || c && c.fixedUrl || window.location.pathname; + // https://gist.github.com/paulirish/5558557 + if (storageType in window) { + try { + window[storageType].setItem('_tmptest', 'temp'); + hasStorage = true; + window[storageType].removeItem('_tmptest'); + } catch(error) { + if (c && c.debug) { + ts.log( storageType + ' is not supported in this browser' ); + } + } + } + // *** get value *** + if ($.parseJSON) { + if (hasStorage) { + values = $.parseJSON( window[storageType][key] || 'null' ) || {}; + } else { + // old browser, using cookies + cookies = document.cookie.split(/[;\s|=]/); + // add one to get from the key to the value + cookieIndex = $.inArray(key, cookies) + 1; + values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {}; + } + } + // allow value to be an empty string too + if ((value || value === '') && window.JSON && JSON.hasOwnProperty('stringify')) { + // add unique identifiers = url pathname > table ID/index on page > data + if (!values[url]) { + values[url] = {}; + } + values[url][id] = value; + // *** set value *** + if (hasStorage) { + window[storageType][key] = JSON.stringify(values); + } else { + date = new Date(); + date.setTime(date.getTime() + (31536e+6)); // 365 days + document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g,'\"') + '; expires=' + date.toGMTString() + '; path=/'; + } + } else { + return values && values[url] ? values[url][id] : ''; + } +}; + +})(jQuery, window, document); diff --git a/js/widgets/widget-uitheme.js b/js/widgets/widget-uitheme.js new file mode 100644 index 0000000..9d6a095 --- /dev/null +++ b/js/widgets/widget-uitheme.js @@ -0,0 +1,185 @@ +/*! Widget: uitheme - updated 3/26/2015 (v2.21.3) */ +;(function ($) { +'use strict'; +var ts = $.tablesorter || {}; + +ts.themes = { + 'bootstrap' : { + table : 'table table-bordered table-striped', + caption : 'caption', + // header class names + header : 'bootstrap-header', // give the header a gradient background (theme.bootstrap_2.css) + sortNone : '', + sortAsc : '', + sortDesc : '', + active : '', // applied when column is sorted + hover : '', // custom css required - a defined bootstrap style may not override other classes + // icon class names + icons : '', // add "icon-white" to make them white; this icon class is added to the in the header + iconSortNone : 'bootstrap-icon-unsorted', // class name added to icon when column is not sorted + iconSortAsc : 'icon-chevron-up glyphicon glyphicon-chevron-up', // class name added to icon when column has ascending sort + iconSortDesc : 'icon-chevron-down glyphicon glyphicon-chevron-down', // class name added to icon when column has descending sort + filterRow : '', // filter row class + footerRow : '', + footerCells : '', + even : '', // even row zebra striping + odd : '' // odd row zebra striping + }, + 'jui' : { + table : 'ui-widget ui-widget-content ui-corner-all', // table classes + caption : 'ui-widget-content', + // header class names + header : 'ui-widget-header ui-corner-all ui-state-default', // header classes + sortNone : '', + sortAsc : '', + sortDesc : '', + active : 'ui-state-active', // applied when column is sorted + hover : 'ui-state-hover', // hover class + // icon class names + icons : 'ui-icon', // icon class added to the in the header + iconSortNone : 'ui-icon-carat-2-n-s', // class name added to icon when column is not sorted + iconSortAsc : 'ui-icon-carat-1-n', // class name added to icon when column has ascending sort + iconSortDesc : 'ui-icon-carat-1-s', // class name added to icon when column has descending sort + filterRow : '', + footerRow : '', + footerCells : '', + even : 'ui-widget-content', // even row zebra striping + odd : 'ui-state-default' // odd row zebra striping + } +}; + +$.extend(ts.css, { + wrapper : 'tablesorter-wrapper' // ui theme & resizable +}); + +ts.addWidget({ + id: "uitheme", + priority: 10, + format: function(table, c, wo) { + var i, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme, + themesAll = ts.themes, + $table = c.$table.add( $( c.namespace + '_extra_table' ) ), + $headers = c.$headers.add( $( c.namespace + '_extra_headers' ) ), + theme = c.theme || 'jui', + themes = themesAll[theme] || {}, + remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ), + iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) ); + if (c.debug) { time = new Date(); } + // initialization code - run once + if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) { + wo.uitheme_applied = true; + oldtheme = themesAll[c.appliedTheme] || {}; + hasOldTheme = !$.isEmptyObject(oldtheme); + oldremove = hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : ''; + oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : ''; + if (hasOldTheme) { + wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') ); + wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') ); + c.$tbodies.children().removeClass( [oldtheme.even, oldtheme.odd].join(' ') ); + } + // update zebra stripes + if (themes.even) { wo.zebra[0] += ' ' + themes.even; } + if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; } + // add caption style + $table.children('caption') + .removeClass(oldtheme.caption || '') + .addClass(themes.caption); + // add table/footer class names + $tfoot = $table + // remove other selected themes + .removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') ) + .addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name + .children('tfoot'); + c.appliedTheme = c.theme; + + if ($tfoot.length) { + $tfoot + // if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed + .children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow) + .children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells); + } + // update header classes + $headers + .removeClass( (hasOldTheme ? [oldtheme.header, oldtheme.hover, oldremove].join(' ') : '') || '' ) + .addClass(themes.header) + .not('.sorter-false') + .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') + .bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) { + // toggleClass with switch added in jQuery 1.3 + $(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || ''); + }); + + $headers.each(function(){ + var $this = $(this); + if (!$this.find('.' + ts.css.wrapper).length) { + // Firefox needs this inner div to position the icon & resizer correctly + $this.wrapInner('
    '); + } + }); + if (c.cssIcon) { + // if c.cssIcon is '', then no is added to the header + $headers + .find('.' + ts.css.icon) + .removeClass(hasOldTheme ? [oldtheme.icons, oldIconRmv].join(' ') : '') + .addClass(themes.icons || ''); + } + if ($table.hasClass('hasFilters')) { + $table.children('thead').children('.' + ts.css.filterRow) + .removeClass(hasOldTheme ? oldtheme.filterRow || '' : '') + .addClass(themes.filterRow || ''); + } + } + for (i = 0; i < c.columns; i++) { + $header = c.$headers + .add($(c.namespace + '_extra_headers')) + .not('.sorter-false') + .filter('[data-column="' + i + '"]'); + $icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $(); + $h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last'); + if ($h.length) { + $header.removeClass(remove); + $icon.removeClass(iconRmv); + if ($h[0].sortDisabled) { + // no sort arrows for disabled columns! + $icon.removeClass(themes.icons || ''); + } else { + hdr = themes.sortNone; + icon = themes.iconSortNone; + if ($h.hasClass(ts.css.sortAsc)) { + hdr = [themes.sortAsc, themes.active].join(' '); + icon = themes.iconSortAsc; + } else if ($h.hasClass(ts.css.sortDesc)) { + hdr = [themes.sortDesc, themes.active].join(' '); + icon = themes.iconSortDesc; + } + $header.addClass(hdr); + $icon.addClass(icon || ''); + } + } + } + if (c.debug) { + ts.benchmark("Applying " + theme + " theme", time); + } + }, + remove: function(table, c, wo, refreshing) { + if (!wo.uitheme_applied) { return; } + var $table = c.$table, + theme = c.appliedTheme || 'jui', + themes = ts.themes[ theme ] || ts.themes.jui, + $headers = $table.children('thead').children(), + remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc, + iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc; + $table.removeClass('tablesorter-' + theme + ' ' + themes.table); + wo.uitheme_applied = false; + if (refreshing) { return; } + $table.find(ts.css.header).removeClass(themes.header); + $headers + .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover + .removeClass(themes.hover + ' ' + remove + ' ' + themes.active) + .filter('.' + ts.css.filterRow) + .removeClass(themes.filterRow); + $headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv); + } +}); + +})(jQuery); diff --git a/package.json b/package.json new file mode 100644 index 0000000..cf37cef --- /dev/null +++ b/package.json @@ -0,0 +1,80 @@ +{ + "name": "tablesorter", + "title": "tablesorter", + "version": "2.22.1", + "description": "tablesorter (FORK) is a jQuery plugin for turning a standard HTML table with THEAD and TBODY tags into a sortable table without page refreshes. tablesorter can successfully parse and sort many types of data including linked data in a cell.", + "author": { + "name": "Christian Bach", + "url": "http://tablesorter.com/" + }, + "maintainers": [ + { + "name": "Rob Garrison", + "url": "https://github.com/Mottie", + "email": "wowmotty@gmail.com" + } + ], + "licenses": [ + { + "type": "MIT", + "url": "http://www.opensource.org/licenses/mit-license.php" + }, + { + "type": "GPL", + "url": "http://www.gnu.org/licenses/gpl.html" + } + ], + "homepage": "http://mottie.github.com/tablesorter/", + "bugs": "https://github.com/Mottie/tablesorter/issues", + "docs": "http://mottie.github.com/tablesorter/docs/index.html", + "demo": "https://github.com/Mottie/tablesorter/wiki", + "dependencies": { + "jquery": ">=1.2.6" + }, + "keywords": [ + "table", + "sort", + "sorting", + "alphanumeric", + "natural", + "jquery-plugin" + ], + "main": "dist/js/jquery.tablesorter.combined.js", + "files": [ + "dist/" + ], + "repository": { + "type": "git", + "url": "git://github.com/Mottie/tablesorter.git" + }, + "npmName": "tablesorter", + "npmFileMap": [ + { + "basePath": "", + "files": [ + "dist/**/*" + ] + } + ], + "autoupdate": { + "source": "git", + "target": "git://github.com/Mottie/tablesorter.git", + "basePath": "", + "files": [ + "dist/**/*" + ] + }, + "devDependencies": { + "grunt": "^0.4.5", + "grunt-cli": "~0.1.13", + "grunt-contrib-clean": "^0.6.0", + "grunt-contrib-concat": "^0.5.0", + "grunt-contrib-copy": "^0.7.0", + "grunt-contrib-cssmin": "^0.12.1", + "grunt-contrib-jshint": "^0.11.0", + "grunt-contrib-qunit": "^0.5.2", + "grunt-contrib-uglify": "^0.7.0", + "grunt-contrib-watch": "^0.6.1", + "grunt-string-replace": "^1.0.0" + } +} diff --git a/tablesorter.jquery.json b/tablesorter.jquery.json new file mode 100644 index 0000000..5d7d0b2 --- /dev/null +++ b/tablesorter.jquery.json @@ -0,0 +1,47 @@ +{ + "name": "tablesorter", + "title": "tablesorter", + "version": "2.22.1", + "description": "tablesorter is a jQuery plugin for turning a standard HTML table with THEAD and TBODY tags into a sortable table without page refreshes. tablesorter can successfully parse and sort many types of data including linked data in a cell.\n\nThis forked version adds lots of new enhancements including: alphanumeric sorting, pager callback functons, multiple widgets providing column styling, ui theme application, sticky headers, column filters and resizer, as well as extended documentation with a lot more demos.", + "author": { + "name": "Christian Bach", + "url": "http://tablesorter.com/" + }, + "maintainers": [ + { + "name": "Rob Garrison", + "url": "https://github.com/Mottie", + "email": "wowmotty@gmail.com" + } + ], + "licenses": [ + { + "type": "MIT", + "url": "http://www.opensource.org/licenses/mit-license.php" + }, + { + "type": "GPL", + "url": "http://www.gnu.org/licenses/gpl.html" + } + ], + "homepage": "http://mottie.github.com/tablesorter/", + "bugs": "https://github.com/Mottie/tablesorter/issues", + "docs": "http://mottie.github.com/tablesorter/docs/index.html", + "demo": "https://github.com/Mottie/tablesorter/wiki", + "dependencies": { + "jquery": ">=1.2.6" + }, + "keywords": [ + "table", + "sort", + "sorting", + "alphanumeric", + "natural", + "jquery-plugin" + ], + "main": "dist/js/jquery.tablesorter.js", + "files": [ + "dist/css/theme.default.min.css", + "dist/js/jquery.tablesorter.combined.min.js" + ] +} \ No newline at end of file diff --git a/test.html b/test.html new file mode 100644 index 0000000..555ee57 --- /dev/null +++ b/test.html @@ -0,0 +1,131 @@ + + + + + Tablesorter Testing (WIP) + + + + + + + + + + + + + + + +
    +
    + +

    This is a work-in-progress. It does not yet comprehensively test all sorting methods. The following are on the to do list:

    +
      +
    • Core tests: +
        +
      • Test each option, event & callback
      • +
      • Sorting empty cells.
      • +
      • Sorting strings in numeric columns.
      • +
      • Internal rendering, caching & indexing utilities.
      • +
      • Update methods.
      • +
      +
    • +
    • All widgets.
    • +
    • Pager plugin.
    • +
    • Include natural sort unit tests?
    • +
    + + + + + + + + + + + + + + + + + + + + + +
    test-headnum
    test-foottxt
    ignoredx2
    ignoredx3
    ignoredx1
    Info
    testBx5
    testCx4
    testAx6
    + + + + + + + + + + + + + + +
    1 2 3 4
    abcd
    zyxw
    + + + + + + + + + + + + + + + + + + + + + + +
    1234
    A43-3501-.1
    A2553302N/A #1
    A33203N/A #2
    A1-504-8.4
    A102NR05-2.2
    A10-10697.4
    A0210723.6
    A554411.4
    A8704NR5.2
    NR
    + + + + + + + + + + + + + + + + + +
    1234567
    F01xF11xA2101ZZSWAx
    F01gF11gA2102ZYWBx
    F02zF12zA2203ZZWAx
    F02bF12bA2204ZZWBx
    F02dF12dA2305ZYWAx
    F02fF12fA2306ZXWBx
    F02hF12hA2307ZXWAx
    F02aF13aA2308ZZWBx
    F03cF13cA2409ZZWAx
    F03eF13eA2410ZZWBx
    + + + + + + + + +
    1
    + +
    +
    + + + \ No newline at end of file diff --git a/testing/qunit-1.16.0.css b/testing/qunit-1.16.0.css new file mode 100644 index 0000000..385a1ce --- /dev/null +++ b/testing/qunit-1.16.0.css @@ -0,0 +1,264 @@ +/*! + * QUnit 1.16.0 + * http://qunitjs.com/ + * + * Copyright 2006, 2014 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-12-03T16:32Z + */ + +/** Font Family and Sizes */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; +} + +#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-tests { font-size: smaller; } + + +/** Resets */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { + margin: 0; + padding: 0; +} + + +/** Header */ + +#qunit-header { + padding: 0.5em 0 0.5em 1em; + + color: #8699A4; + background-color: #0D3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: 400; + + border-radius: 5px 5px 0 0; +} + +#qunit-header a { + text-decoration: none; + color: #C2CCD1; +} + +#qunit-header a:hover, +#qunit-header a:focus { + color: #FFF; +} + +#qunit-testrunner-toolbar label { + display: inline-block; + padding: 0 0.5em 0 0.1em; +} + +#qunit-banner { + height: 5px; +} + +#qunit-testrunner-toolbar { + padding: 0.5em 1em 0.5em 1em; + color: #5E740B; + background-color: #EEE; + overflow: hidden; +} + +#qunit-userAgent { + padding: 0.5em 1em 0.5em 1em; + background-color: #2B81AF; + color: #FFF; + text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; +} + +#qunit-modulefilter-container { + float: right; +} + +/** Tests: Pass/Fail */ + +#qunit-tests { + list-style-position: inside; +} + +#qunit-tests li { + padding: 0.4em 1em 0.4em 1em; + border-bottom: 1px solid #FFF; + list-style-position: inside; +} + +#qunit-tests > li { + display: none; +} + +#qunit-tests li.pass, #qunit-tests li.running, #qunit-tests li.fail { + display: list-item; +} + +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + +#qunit-tests li strong { + cursor: pointer; +} + +#qunit-tests li.skipped strong { + cursor: default; +} + +#qunit-tests li a { + padding: 0.5em; + color: #C2CCD1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + +#qunit-tests li .runtime { + float: right; + font-size: smaller; +} + +.qunit-assert-list { + margin-top: 0.5em; + padding: 0.5em; + + background-color: #FFF; + + border-radius: 5px; +} + +.qunit-collapsed { + display: none; +} + +#qunit-tests table { + border-collapse: collapse; + margin-top: 0.2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 0.5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #E0F2BE; + color: #374E0C; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #FFCACA; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: #000; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + +#qunit-tests li li { + padding: 5px; + background-color: #FFF; + border-bottom: none; + list-style-position: inside; +} + +/*** Passing Styles */ + +#qunit-tests li li.pass { + color: #3C510C; + background-color: #FFF; + border-left: 10px solid #C6E746; +} + +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } + +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999; } + +#qunit-banner.qunit-pass { background-color: #C6E746; } + +/*** Failing Styles */ + +#qunit-tests li li.fail { + color: #710909; + background-color: #FFF; + border-left: 10px solid #EE5757; + white-space: pre; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 5px 5px; +} + +#qunit-tests .fail { color: #000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: #008000; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + +/*** Skipped tests */ + +#qunit-tests .skipped { + background-color: #EBECE9; +} + +#qunit-tests .qunit-skipped-label { + background-color: #F4FF77; + display: inline-block; + font-style: normal; + color: #366097; + line-height: 1.8em; + padding: 0 0.5em; + margin: -0.4em 0.4em -0.4em 0; +} + +/** Result */ + +#qunit-testresult { + padding: 0.5em 1em 0.5em 1em; + + color: #2B81AF; + background-color: #D2E0E6; + + border-bottom: 1px solid #FFF; +} +#qunit-testresult .module-name { + font-weight: 700; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; + width: 1000px; + height: 1000px; +} diff --git a/testing/qunit-1.16.0.js b/testing/qunit-1.16.0.js new file mode 100644 index 0000000..82020d4 --- /dev/null +++ b/testing/qunit-1.16.0.js @@ -0,0 +1,2819 @@ +/*! + * QUnit 1.16.0 + * http://qunitjs.com/ + * + * Copyright 2006, 2014 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-12-03T16:32Z + */ + +(function( window ) { + +var QUnit, + config, + onErrorFnPrev, + loggingCallbacks = {}, + fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ), + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + // Keep a local reference to Date (GH-283) + Date = window.Date, + now = Date.now || function() { + return new Date().getTime(); + }, + globalStartCalled = false, + runStarted = false, + setTimeout = window.setTimeout, + clearTimeout = window.clearTimeout, + defined = { + document: window.document !== undefined, + setTimeout: window.setTimeout !== undefined, + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch ( e ) { + return false; + } + }()) + }, + /** + * Provides a normalized error string, correcting an issue + * with IE 7 (and prior) where Error.prototype.toString is + * not properly implemented + * + * Based on http://es5.github.com/#x15.11.4.4 + * + * @param {String|Error} error + * @return {String} error message + */ + errorString = function( error ) { + var name, message, + errorString = error.toString(); + if ( errorString.substring( 0, 7 ) === "[object" ) { + name = error.name ? error.name.toString() : "Error"; + message = error.message ? error.message.toString() : ""; + if ( name && message ) { + return name + ": " + message; + } else if ( name ) { + return name; + } else if ( message ) { + return message; + } else { + return "Error"; + } + } else { + return errorString; + } + }, + /** + * Makes a clone of an object using only Array or Object as base, + * and copies over the own enumerable properties. + * + * @param {Object} obj + * @return {Object} New object with only the own properties (recursively). + */ + objectValues = function( obj ) { + var key, val, + vals = QUnit.is( "array", obj ) ? [] : {}; + for ( key in obj ) { + if ( hasOwn.call( obj, key ) ) { + val = obj[ key ]; + vals[ key ] = val === Object( val ) ? objectValues( val ) : val; + } + } + return vals; + }; + +QUnit = {}; + +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ +config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + // by default, scroll to top of the page when suite is done + scrolltop: true, + + // when enabled, all tests must call expect() + requireExpects: false, + + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "hidepassed", + label: "Hide passed tests", + tooltip: "Only show tests and assertions that fail. Stored as query-strings." + }, + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the " + + "`window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " + + "exceptions in IE reasonable. Stored as query-strings." + } + ], + + // Set of all modules. + modules: [], + + // The first unnamed module + currentModule: { + name: "", + tests: [] + }, + + callbacks: {} +}; + +// Push a loose unnamed module to the modules collection +config.modules.push( config.currentModule ); + +// Initialize more QUnit.config and QUnit.urlParams +(function() { + var i, current, + location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}; + + if ( params[ 0 ] ) { + for ( i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + if ( urlParams[ current[ 0 ] ] ) { + urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] ); + } else { + urlParams[ current[ 0 ] ] = current[ 1 ]; + } + } + } + + QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName + config.filter = urlParams.filter; + + config.testId = []; + if ( urlParams.testId ) { + + // Ensure that urlParams.testId is an array + urlParams.testId = [].concat( urlParams.testId ); + for ( i = 0; i < urlParams.testId.length; i++ ) { + config.testId.push( urlParams.testId[ i ] ); + } + } + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = location.protocol === "file:"; +}()); + +// Root QUnit object. +// `QUnit` initialized at top of scope +extend( QUnit, { + + // call on start of module test to prepend name to all tests + module: function( name, testEnvironment ) { + var currentModule = { + name: name, + testEnvironment: testEnvironment, + tests: [] + }; + + // DEPRECATED: handles setup/teardown functions, + // beforeEach and afterEach should be used instead + if ( testEnvironment && testEnvironment.setup ) { + testEnvironment.beforeEach = testEnvironment.setup; + delete testEnvironment.setup; + } + if ( testEnvironment && testEnvironment.teardown ) { + testEnvironment.afterEach = testEnvironment.teardown; + delete testEnvironment.teardown; + } + + config.modules.push( currentModule ); + config.currentModule = currentModule; + }, + + // DEPRECATED: QUnit.asyncTest() will be removed in QUnit 2.0. + asyncTest: function( testName, expected, callback ) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test( testName, expected, callback, true ); + }, + + test: function( testName, expected, callback, async ) { + var test; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + test = new Test({ + testName: testName, + expected: expected, + async: async, + callback: callback + }); + + test.queue(); + }, + + skip: function( testName ) { + var test = new Test({ + testName: testName, + skip: true + }); + + test.queue(); + }, + + // DEPRECATED: The functionality of QUnit.start() will be altered in QUnit 2.0. + // In QUnit 2.0, invoking it will ONLY affect the `QUnit.config.autostart` blocking behavior. + start: function( count ) { + var globalStartAlreadyCalled = globalStartCalled; + + if ( !config.current ) { + globalStartCalled = true; + + if ( runStarted ) { + throw new Error( "Called start() outside of a test context while already started" ); + } else if ( globalStartAlreadyCalled || count > 1 ) { + throw new Error( "Called start() outside of a test context too many times" ); + } else if ( config.autostart ) { + throw new Error( "Called start() outside of a test context when " + + "QUnit.config.autostart was true" ); + } else if ( !config.pageLoaded ) { + + // The page isn't completely loaded yet, so bail out and let `QUnit.load` handle it + config.autostart = true; + return; + } + } else { + + // If a test is running, adjust its semaphore + config.current.semaphore -= count || 1; + + // Don't start until equal number of stop-calls + if ( config.current.semaphore > 0 ) { + return; + } + + // throw an Error if start is called more often than stop + if ( config.current.semaphore < 0 ) { + config.current.semaphore = 0; + + QUnit.pushFailure( + "Called start() while already started (test's semaphore was 0 already)", + sourceFromStacktrace( 2 ) + ); + return; + } + } + + resumeProcessing(); + }, + + // DEPRECATED: QUnit.stop() will be removed in QUnit 2.0. + stop: function( count ) { + + // If there isn't a test running, don't allow QUnit.stop() to be called + if ( !config.current ) { + throw new Error( "Called stop() outside of a test context" ); + } + + // If a test is running, adjust its semaphore + config.current.semaphore += count || 1; + + pauseProcessing(); + }, + + config: config, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) === type; + }, + + objectType: function( obj ) { + if ( typeof obj === "undefined" ) { + return "undefined"; + } + + // Consider: typeof null === object + if ( obj === null ) { + return "null"; + } + + var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ), + type = match && match[ 1 ] || ""; + + switch ( type ) { + case "Number": + if ( isNaN( obj ) ) { + return "nan"; + } + return "number"; + case "String": + case "Boolean": + case "Array": + case "Date": + case "RegExp": + case "Function": + return type.toLowerCase(); + } + if ( typeof obj === "object" ) { + return "object"; + } + return undefined; + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var key, + querystring = "?"; + + for ( key in params ) { + if ( hasOwn.call( params, key ) ) { + querystring += encodeURIComponent( key ); + if ( params[ key ] !== true ) { + querystring += "=" + encodeURIComponent( params[ key ] ); + } + querystring += "&"; + } + } + return location.protocol + "//" + location.host + + location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + + load: function() { + config.pageLoaded = true; + + // Initialize the configuration options + extend( config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: 0, + updateRate: 1000, + autostart: true, + filter: "" + }, true ); + + config.blocking = false; + + if ( config.autostart ) { + resumeProcessing(); + } + } +}); + +// Register logging callbacks +(function() { + var i, l, key, + callbacks = [ "begin", "done", "log", "testStart", "testDone", + "moduleStart", "moduleDone" ]; + + function registerLoggingCallback( key ) { + var loggingCallback = function( callback ) { + if ( QUnit.objectType( callback ) !== "function" ) { + throw new Error( + "QUnit logging methods require a callback function as their first parameters." + ); + } + + config.callbacks[ key ].push( callback ); + }; + + // DEPRECATED: This will be removed on QUnit 2.0.0+ + // Stores the registered functions allowing restoring + // at verifyLoggingCallbacks() if modified + loggingCallbacks[ key ] = loggingCallback; + + return loggingCallback; + } + + for ( i = 0, l = callbacks.length; i < l; i++ ) { + key = callbacks[ i ]; + + // Initialize key collection of logging callback + if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) { + config.callbacks[ key ] = []; + } + + QUnit[ key ] = registerLoggingCallback( key ); + } +})(); + +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will suppress the default browser handler, +// returning false will let it run. +window.onerror = function( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not suppressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", extend(function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }, { validTest: true } ) ); + } + return false; + } + + return ret; +}; + +function done() { + var runtime, passed; + + config.autorun = true; + + // Log the last module results + if ( config.previousModule ) { + runLoggingCallbacks( "moduleDone", { + name: config.previousModule.name, + tests: config.previousModule.tests, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all, + runtime: now() - config.moduleStats.started + }); + } + delete config.previousModule; + + runtime = now() - config.started; + passed = config.stats.all - config.stats.bad; + + runLoggingCallbacks( "done", { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + }); +} + +// Doesn't support IE6 to IE9 +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 4 : offset; + + var stack, include, i; + + if ( e.stacktrace ) { + + // Opera 12.x + return e.stacktrace.split( "\n" )[ offset + 3 ]; + } else if ( e.stack ) { + + // Firefox, Chrome, Safari 6+, IE10+, PhantomJS and Node + stack = e.stack.split( "\n" ); + if ( /^error$/i.test( stack[ 0 ] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) !== -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } + return stack[ offset ]; + } else if ( e.sourceURL ) { + + // Safari < 6 + // exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + + // for actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} + +function sourceFromStacktrace( offset ) { + var e = new Error(); + if ( !e.stack ) { + try { + throw e; + } catch ( err ) { + // This should already be true in most browsers + e = err; + } + } + return extractStacktrace( e, offset ); +} + +function synchronize( callback, last ) { + if ( QUnit.objectType( callback ) === "array" ) { + while ( callback.length ) { + synchronize( callback.shift() ); + } + return; + } + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process( last ); + } +} + +function process( last ) { + function next() { + process( last ); + } + var start = now(); + config.depth = config.depth ? config.depth + 1 : 1; + + while ( config.queue.length && !config.blocking ) { + if ( !defined.setTimeout || config.updateRate <= 0 || + ( ( now() - start ) < config.updateRate ) ) { + if ( config.current ) { + + // Reset async tracking for each phase of the Test lifecycle + config.current.usedAsync = false; + } + config.queue.shift()(); + } else { + setTimeout( next, 13 ); + break; + } + } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } +} + +function begin() { + var i, l, + modulesLog = []; + + // If the test run hasn't officially begun yet + if ( !config.started ) { + + // Record the time of the test run's beginning + config.started = now(); + + verifyLoggingCallbacks(); + + // Delete the loose unnamed module if unused. + if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) { + config.modules.shift(); + } + + // Avoid unnecessary information by not logging modules' test environments + for ( i = 0, l = config.modules.length; i < l; i++ ) { + modulesLog.push({ + name: config.modules[ i ].name, + tests: config.modules[ i ].tests + }); + } + + // The test run is officially beginning now + runLoggingCallbacks( "begin", { + totalTests: Test.count, + modules: modulesLog + }); + } + + config.blocking = false; + process( true ); +} + +function resumeProcessing() { + runStarted = true; + + // A slight delay to allow this iteration of the event loop to finish (more assertions, etc.) + if ( defined.setTimeout ) { + setTimeout(function() { + if ( config.current && config.current.semaphore > 0 ) { + return; + } + if ( config.timeout ) { + clearTimeout( config.timeout ); + } + + begin(); + }, 13 ); + } else { + begin(); + } +} + +function pauseProcessing() { + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = setTimeout(function() { + if ( config.current ) { + config.current.semaphore = 0; + QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) ); + } else { + throw new Error( "Test timed out" ); + } + resumeProcessing(); + }, config.testTimeout ); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + if ( hasOwn.call( window, key ) ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } + } + } +} + +function checkPollution() { + var newGlobals, + deletedGlobals, + old = config.pollution; + + saveGlobal(); + + newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) ); + } + + deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { + if ( result[ i ] === b[ j ] ) { + result.splice( i, 1 ); + i--; + break; + } + } + } + return result; +} + +function extend( a, b, undefOnly ) { + for ( var prop in b ) { + if ( hasOwn.call( b, prop ) ) { + + // Avoid "Member not found" error in IE8 caused by messing with window.constructor + if ( !( prop === "constructor" && a === window ) ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) { + a[ prop ] = b[ prop ]; + } + } + } + } + + return a; +} + +function runLoggingCallbacks( key, args ) { + var i, l, callbacks; + + callbacks = config.callbacks[ key ]; + for ( i = 0, l = callbacks.length; i < l; i++ ) { + callbacks[ i ]( args ); + } +} + +// DEPRECATED: This will be removed on 2.0.0+ +// This function verifies if the loggingCallbacks were modified by the user +// If so, it will restore it, assign the given callback and print a console warning +function verifyLoggingCallbacks() { + var loggingCallback, userCallback; + + for ( loggingCallback in loggingCallbacks ) { + if ( QUnit[ loggingCallback ] !== loggingCallbacks[ loggingCallback ] ) { + + userCallback = QUnit[ loggingCallback ]; + + // Restore the callback function + QUnit[ loggingCallback ] = loggingCallbacks[ loggingCallback ]; + + // Assign the deprecated given callback + QUnit[ loggingCallback ]( userCallback ); + + if ( window.console && window.console.warn ) { + window.console.warn( + "QUnit." + loggingCallback + " was replaced with a new value.\n" + + "Please, check out the documentation on how to apply logging callbacks.\n" + + "Reference: http://api.qunitjs.com/category/callbacks/" + ); + } + } + } +} + +// from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +function Test( settings ) { + var i, l; + + ++Test.count; + + extend( this, settings ); + this.assertions = []; + this.semaphore = 0; + this.usedAsync = false; + this.module = config.currentModule; + this.stack = sourceFromStacktrace( 3 ); + + // Register unique strings + for ( i = 0, l = this.module.tests; i < l.length; i++ ) { + if ( this.module.tests[ i ].name === this.testName ) { + this.testName += " "; + } + } + + this.testId = generateHash( this.module.name, this.testName ); + + this.module.tests.push({ + name: this.testName, + testId: this.testId + }); + + if ( settings.skip ) { + + // Skipped tests will fully ignore any sent callback + this.callback = function() {}; + this.async = false; + this.expected = 0; + } else { + this.assert = new Assert( this ); + } +} + +Test.count = 0; + +Test.prototype = { + before: function() { + if ( + + // Emit moduleStart when we're switching from one module to another + this.module !== config.previousModule || + + // They could be equal (both undefined) but if the previousModule property doesn't + // yet exist it means this is the first test in a suite that isn't wrapped in a + // module, in which case we'll just emit a moduleStart event for 'undefined'. + // Without this, reporters can get testStart before moduleStart which is a problem. + !hasOwn.call( config, "previousModule" ) + ) { + if ( hasOwn.call( config, "previousModule" ) ) { + runLoggingCallbacks( "moduleDone", { + name: config.previousModule.name, + tests: config.previousModule.tests, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all, + runtime: now() - config.moduleStats.started + }); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0, started: now() }; + runLoggingCallbacks( "moduleStart", { + name: this.module.name, + tests: this.module.tests + }); + } + + config.current = this; + + this.testEnvironment = extend( {}, this.module.testEnvironment ); + delete this.testEnvironment.beforeEach; + delete this.testEnvironment.afterEach; + + this.started = now(); + runLoggingCallbacks( "testStart", { + name: this.testName, + module: this.module.name, + testId: this.testId + }); + + if ( !config.pollution ) { + saveGlobal(); + } + }, + + run: function() { + var promise; + + config.current = this; + + if ( this.async ) { + QUnit.stop(); + } + + this.callbackStarted = now(); + + if ( config.notrycatch ) { + promise = this.callback.call( this.testEnvironment, this.assert ); + this.resolvePromise( promise ); + return; + } + + try { + promise = this.callback.call( this.testEnvironment, this.assert ); + this.resolvePromise( promise ); + } catch ( e ) { + this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); + + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + QUnit.start(); + } + } + }, + + after: function() { + checkPollution(); + }, + + queueHook: function( hook, hookName ) { + var promise, + test = this; + return function runHook() { + config.current = test; + if ( config.notrycatch ) { + promise = hook.call( test.testEnvironment, test.assert ); + test.resolvePromise( promise, hookName ); + return; + } + try { + promise = hook.call( test.testEnvironment, test.assert ); + test.resolvePromise( promise, hookName ); + } catch ( error ) { + test.pushFailure( hookName + " failed on " + test.testName + ": " + + ( error.message || error ), extractStacktrace( error, 0 ) ); + } + }; + }, + + // Currently only used for module level hooks, can be used to add global level ones + hooks: function( handler ) { + var hooks = []; + + // Hooks are ignored on skipped tests + if ( this.skip ) { + return hooks; + } + + if ( this.module.testEnvironment && + QUnit.objectType( this.module.testEnvironment[ handler ] ) === "function" ) { + hooks.push( this.queueHook( this.module.testEnvironment[ handler ], handler ) ); + } + + return hooks; + }, + + finish: function() { + config.current = this; + if ( config.requireExpects && this.expected === null ) { + this.pushFailure( "Expected number of assertions to be defined, but expect() was " + + "not called.", this.stack ); + } else if ( this.expected !== null && this.expected !== this.assertions.length ) { + this.pushFailure( "Expected " + this.expected + " assertions, but " + + this.assertions.length + " were run", this.stack ); + } else if ( this.expected === null && !this.assertions.length ) { + this.pushFailure( "Expected at least one assertion, but none were run - call " + + "expect(0) to accept zero assertions.", this.stack ); + } + + var i, + bad = 0; + + this.runtime = now() - this.started; + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + for ( i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[ i ].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + runLoggingCallbacks( "testDone", { + name: this.testName, + module: this.module.name, + skipped: !!this.skip, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length, + runtime: this.runtime, + + // HTML Reporter use + assertions: this.assertions, + testId: this.testId, + + // DEPRECATED: this property will be removed in 2.0.0, use runtime instead + duration: this.runtime + }); + + // QUnit.reset() is deprecated and will be replaced for a new + // fixture reset function on QUnit 2.0/2.1. + // It's still called here for backwards compatibility handling + QUnit.reset(); + + config.current = undefined; + }, + + queue: function() { + var bad, + test = this; + + if ( !this.valid() ) { + return; + } + + function run() { + + // each of these can by async + synchronize([ + function() { + test.before(); + }, + + test.hooks( "beforeEach" ), + + function() { + test.run(); + }, + + test.hooks( "afterEach" ).reverse(), + + function() { + test.after(); + }, + function() { + test.finish(); + } + ]); + } + + // `bad` initialized at top of scope + // defer when previous test run passed, if storage is available + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName ); + + if ( bad ) { + run(); + } else { + synchronize( run, true ); + } + }, + + push: function( result, actual, expected, message ) { + var source, + details = { + module: this.module.name, + name: this.testName, + result: result, + message: message, + actual: actual, + expected: expected, + testId: this.testId, + runtime: now() - this.started + }; + + if ( !result ) { + source = sourceFromStacktrace(); + + if ( source ) { + details.source = source; + } + } + + runLoggingCallbacks( "log", details ); + + this.assertions.push({ + result: !!result, + message: message + }); + }, + + pushFailure: function( message, source, actual ) { + if ( !this instanceof Test ) { + throw new Error( "pushFailure() assertion outside test context, was " + + sourceFromStacktrace( 2 ) ); + } + + var details = { + module: this.module.name, + name: this.testName, + result: false, + message: message || "error", + actual: actual || null, + testId: this.testId, + runtime: now() - this.started + }; + + if ( source ) { + details.source = source; + } + + runLoggingCallbacks( "log", details ); + + this.assertions.push({ + result: false, + message: message + }); + }, + + resolvePromise: function( promise, phase ) { + var then, message, + test = this; + if ( promise != null ) { + then = promise.then; + if ( QUnit.objectType( then ) === "function" ) { + QUnit.stop(); + then.call( + promise, + QUnit.start, + function( error ) { + message = "Promise rejected " + + ( !phase ? "during" : phase.replace( /Each$/, "" ) ) + + " " + test.testName + ": " + ( error.message || error ); + test.pushFailure( message, extractStacktrace( error, 0 ) ); + + // else next test will carry the responsibility + saveGlobal(); + + // Unblock + QUnit.start(); + } + ); + } + } + }, + + valid: function() { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(), + fullName = ( this.module.name + ": " + this.testName ).toLowerCase(); + + // Internally-generated tests are always valid + if ( this.callback && this.callback.validTest ) { + return true; + } + + if ( config.testId.length > 0 && inArray( this.testId, config.testId ) < 0 ) { + return false; + } + + if ( module && ( !this.module.name || this.module.name.toLowerCase() !== module ) ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; + } + +}; + +// Resets the test setup. Useful for tests that modify the DOM. +/* +DEPRECATED: Use multiple tests instead of resetting inside a test. +Use testStart or testDone for custom cleanup. +This method will throw an error in 2.0, and will be removed in 2.1 +*/ +QUnit.reset = function() { + + // Return on non-browser environments + // This is necessary to not break on node tests + if ( typeof window === "undefined" ) { + return; + } + + var fixture = defined.document && document.getElementById && + document.getElementById( "qunit-fixture" ); + + if ( fixture ) { + fixture.innerHTML = config.fixture; + } +}; + +QUnit.pushFailure = function() { + if ( !QUnit.config.current ) { + throw new Error( "pushFailure() assertion outside test context, in " + + sourceFromStacktrace( 2 ) ); + } + + // Gets current test obj + var currentTest = QUnit.config.current; + + return currentTest.pushFailure.apply( currentTest, arguments ); +}; + +// Based on Java's String.hashCode, a simple but not +// rigorously collision resistant hashing function +function generateHash( module, testName ) { + var hex, + i = 0, + hash = 0, + str = module + "\x1C" + testName, + len = str.length; + + for ( ; i < len; i++ ) { + hash = ( ( hash << 5 ) - hash ) + str.charCodeAt( i ); + hash |= 0; + } + + // Convert the possibly negative integer hash code into an 8 character hex string, which isn't + // strictly necessary but increases user understanding that the id is a SHA-like hash + hex = ( 0x100000000 + hash ).toString( 16 ); + if ( hex.length < 8 ) { + hex = "0000000" + hex; + } + + return hex.slice( -8 ); +} + +function Assert( testContext ) { + this.test = testContext; +} + +// Assert helpers +QUnit.assert = Assert.prototype = { + + // Specify the number of expected assertions to guarantee that failed test + // (no assertions are run at all) don't slip through. + expect: function( asserts ) { + if ( arguments.length === 1 ) { + this.test.expected = asserts; + } else { + return this.test.expected; + } + }, + + // Increment this Test's semaphore counter, then return a single-use function that + // decrements that counter a maximum of once. + async: function() { + var test = this.test, + popped = false; + + test.semaphore += 1; + test.usedAsync = true; + pauseProcessing(); + + return function done() { + if ( !popped ) { + test.semaphore -= 1; + popped = true; + resumeProcessing(); + } else { + test.pushFailure( "Called the callback returned from `assert.async` more than once", + sourceFromStacktrace( 2 ) ); + } + }; + }, + + // Exports test.push() to the user API + push: function( /* result, actual, expected, message */ ) { + var assert = this, + currentTest = ( assert instanceof Assert && assert.test ) || QUnit.config.current; + + // Backwards compatibility fix. + // Allows the direct use of global exported assertions and QUnit.assert.* + // Although, it's use is not recommended as it can leak assertions + // to other tests from async tests, because we only get a reference to the current test, + // not exactly the test where assertion were intended to be called. + if ( !currentTest ) { + throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) ); + } + + if ( currentTest.usedAsync === true && currentTest.semaphore === 0 ) { + currentTest.pushFailure( "Assertion after the final `assert.async` was resolved", + sourceFromStacktrace( 2 ) ); + + // Allow this assertion to continue running anyway... + } + + if ( !( assert instanceof Assert ) ) { + assert = currentTest.assert; + } + return assert.test.push.apply( assert.test, arguments ); + }, + + /** + * Asserts rough true-ish result. + * @name ok + * @function + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function( result, message ) { + message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " + + QUnit.dump.parse( result ) ); + this.push( !!result, result, true, message ); + }, + + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @name equal + * @function + * @example equal( format( "{0} bytes.", 2), "2 bytes.", "replaces {0} with next argument" ); + */ + equal: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + this.push( expected == actual, actual, expected, message ); + }, + + /** + * @name notEqual + * @function + */ + notEqual: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + this.push( expected != actual, actual, expected, message ); + }, + + /** + * @name propEqual + * @function + */ + propEqual: function( actual, expected, message ) { + actual = objectValues( actual ); + expected = objectValues( expected ); + this.push( QUnit.equiv( actual, expected ), actual, expected, message ); + }, + + /** + * @name notPropEqual + * @function + */ + notPropEqual: function( actual, expected, message ) { + actual = objectValues( actual ); + expected = objectValues( expected ); + this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); + }, + + /** + * @name deepEqual + * @function + */ + deepEqual: function( actual, expected, message ) { + this.push( QUnit.equiv( actual, expected ), actual, expected, message ); + }, + + /** + * @name notDeepEqual + * @function + */ + notDeepEqual: function( actual, expected, message ) { + this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); + }, + + /** + * @name strictEqual + * @function + */ + strictEqual: function( actual, expected, message ) { + this.push( expected === actual, actual, expected, message ); + }, + + /** + * @name notStrictEqual + * @function + */ + notStrictEqual: function( actual, expected, message ) { + this.push( expected !== actual, actual, expected, message ); + }, + + "throws": function( block, expected, message ) { + var actual, expectedType, + expectedOutput = expected, + ok = false; + + // 'expected' is optional unless doing string comparison + if ( message == null && typeof expected === "string" ) { + message = expected; + expected = null; + } + + this.test.ignoreGlobalErrors = true; + try { + block.call( this.test.testEnvironment ); + } catch (e) { + actual = e; + } + this.test.ignoreGlobalErrors = false; + + if ( actual ) { + expectedType = QUnit.objectType( expected ); + + // we don't want to validate thrown error + if ( !expected ) { + ok = true; + expectedOutput = null; + + // expected is a regexp + } else if ( expectedType === "regexp" ) { + ok = expected.test( errorString( actual ) ); + + // expected is a string + } else if ( expectedType === "string" ) { + ok = expected === errorString( actual ); + + // expected is a constructor, maybe an Error constructor + } else if ( expectedType === "function" && actual instanceof expected ) { + ok = true; + + // expected is an Error object + } else if ( expectedType === "object" ) { + ok = actual instanceof expected.constructor && + actual.name === expected.name && + actual.message === expected.message; + + // expected is a validation function which returns true if validation passed + } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) { + expectedOutput = null; + ok = true; + } + + this.push( ok, actual, expectedOutput, message ); + } else { + this.test.pushFailure( message, null, "No exception was thrown." ); + } + } +}; + +// Provide an alternative to assert.throws(), for enviroments that consider throws a reserved word +// Known to us are: Closure Compiler, Narwhal +(function() { + /*jshint sub:true */ + Assert.prototype.raises = Assert.prototype[ "throws" ]; +}()); + +// Test for equality any JavaScript type. +// Author: Philippe Rathé +QUnit.equiv = (function() { + + // Call the o related callback with the given arguments. + function bindCallbacks( o, callbacks, args ) { + var prop = QUnit.objectType( o ); + if ( prop ) { + if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { + return callbacks[ prop ].apply( callbacks, args ); + } else { + return callbacks[ prop ]; // or undefined + } + } + } + + // the real equiv function + var innerEquiv, + + // stack to decide between skip/abort functions + callers = [], + + // stack to avoiding loops from circular referencing + parents = [], + parentsB = [], + + getProto = Object.getPrototypeOf || function( obj ) { + /* jshint camelcase: false, proto: true */ + return obj.__proto__; + }, + callbacks = (function() { + + // for string, boolean, number and null + function useStrictEquality( b, a ) { + + /*jshint eqeqeq:false */ + if ( b instanceof a.constructor || a instanceof b.constructor ) { + + // to catch short annotation VS 'new' annotation of a + // declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function( b ) { + return isNaN( b ); + }, + + "date": function( b, a ) { + return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function( b, a ) { + return QUnit.objectType( b ) === "regexp" && + + // the regex itself + a.source === b.source && + + // and its modifiers + a.global === b.global && + + // (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline && + a.sticky === b.sticky; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function() { + var caller = callers[ callers.length - 1 ]; + return caller !== Object && typeof caller !== "undefined"; + }, + + "array": function( b, a ) { + var i, j, len, loop, aCircular, bCircular; + + // b could be an object literal here + if ( QUnit.objectType( b ) !== "array" ) { + return false; + } + + len = a.length; + if ( len !== b.length ) { + // safe and faster + return false; + } + + // track reference to avoid circular references + parents.push( a ); + parentsB.push( b ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[ j ] === a[ i ]; + bCircular = parentsB[ j ] === b[ i ]; + if ( aCircular || bCircular ) { + if ( a[ i ] === b[ i ] || aCircular && bCircular ) { + loop = true; + } else { + parents.pop(); + parentsB.pop(); + return false; + } + } + } + if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { + parents.pop(); + parentsB.pop(); + return false; + } + } + parents.pop(); + parentsB.pop(); + return true; + }, + + "object": function( b, a ) { + + /*jshint forin:false */ + var i, j, loop, aCircular, bCircular, + // Default to true + eq = true, + aProperties = [], + bProperties = []; + + // comparing constructors is more strict than using + // instanceof + if ( a.constructor !== b.constructor ) { + + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( !( ( getProto( a ) === null && getProto( b ) === Object.prototype ) || + ( getProto( b ) === null && getProto( a ) === Object.prototype ) ) ) { + return false; + } + } + + // stack constructor before traversing properties + callers.push( a.constructor ); + + // track reference to avoid circular references + parents.push( a ); + parentsB.push( b ); + + // be strict: don't ensure hasOwnProperty and go deep + for ( i in a ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[ j ] === a[ i ]; + bCircular = parentsB[ j ] === b[ i ]; + if ( aCircular || bCircular ) { + if ( a[ i ] === b[ i ] || aCircular && bCircular ) { + loop = true; + } else { + eq = false; + break; + } + } + } + aProperties.push( i ); + if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { + eq = false; + break; + } + } + + parents.pop(); + parentsB.pop(); + callers.pop(); // unstack, we are done + + for ( i in b ) { + bProperties.push( i ); // collect b's properties + } + + // Ensures identical properties name + return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + } + }; + }()); + + innerEquiv = function() { // can take multiple arguments + var args = [].slice.apply( arguments ); + if ( args.length < 2 ) { + return true; // end transition + } + + return ( (function( a, b ) { + if ( a === b ) { + return true; // catch the most you can + } else if ( a === null || b === null || typeof a === "undefined" || + typeof b === "undefined" || + QUnit.objectType( a ) !== QUnit.objectType( b ) ) { + + // don't lose time with error prone cases + return false; + } else { + return bindCallbacks( a, callbacks, [ b, a ] ); + } + + // apply transition with (1..n) arguments + }( args[ 0 ], args[ 1 ] ) ) && + innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) ); + }; + + return innerEquiv; +}()); + +// Based on jsDump by Ariel Flesler +// http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html +QUnit.dump = (function() { + function quote( str ) { + return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; + } + function literal( o ) { + return o + ""; + } + function join( pre, arr, post ) { + var s = dump.separator(), + base = dump.indent(), + inner = dump.indent( 1 ); + if ( arr.join ) { + arr = arr.join( "," + s + inner ); + } + if ( !arr ) { + return pre + post; + } + return [ pre, inner + arr, base + post ].join( s ); + } + function array( arr, stack ) { + var i = arr.length, + ret = new Array( i ); + + if ( dump.maxDepth && dump.depth > dump.maxDepth ) { + return "[object Array]"; + } + + this.up(); + while ( i-- ) { + ret[ i ] = this.parse( arr[ i ], undefined, stack ); + } + this.down(); + return join( "[", ret, "]" ); + } + + var reName = /^function (\w+)/, + dump = { + + // objType is used mostly internally, you can fix a (custom) type in advance + parse: function( obj, objType, stack ) { + stack = stack || []; + var res, parser, parserType, + inStack = inArray( obj, stack ); + + if ( inStack !== -1 ) { + return "recursion(" + ( inStack - stack.length ) + ")"; + } + + objType = objType || this.typeOf( obj ); + parser = this.parsers[ objType ]; + parserType = typeof parser; + + if ( parserType === "function" ) { + stack.push( obj ); + res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + return ( parserType === "string" ) ? parser : this.parsers.error; + }, + typeOf: function( obj ) { + var type; + if ( obj === null ) { + type = "null"; + } else if ( typeof obj === "undefined" ) { + type = "undefined"; + } else if ( QUnit.is( "regexp", obj ) ) { + type = "regexp"; + } else if ( QUnit.is( "date", obj ) ) { + type = "date"; + } else if ( QUnit.is( "function", obj ) ) { + type = "function"; + } else if ( obj.setInterval !== undefined && + obj.document !== undefined && + obj.nodeType === undefined ) { + type = "window"; + } else if ( obj.nodeType === 9 ) { + type = "document"; + } else if ( obj.nodeType ) { + type = "node"; + } else if ( + + // native arrays + toString.call( obj ) === "[object Array]" || + + // NodeList objects + ( typeof obj.length === "number" && obj.item !== undefined && + ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null && + obj[ 0 ] === undefined ) ) ) + ) { + type = "array"; + } else if ( obj.constructor === Error.prototype.constructor ) { + type = "error"; + } else { + type = typeof obj; + } + return type; + }, + separator: function() { + return this.multiline ? this.HTML ? "
    " : "\n" : this.HTML ? " " : " "; + }, + // extra can be a number, shortcut for increasing-calling-decreasing + indent: function( extra ) { + if ( !this.multiline ) { + return ""; + } + var chr = this.indentChar; + if ( this.HTML ) { + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); + } + return new Array( this.depth + ( extra || 0 ) ).join( chr ); + }, + up: function( a ) { + this.depth += a || 1; + }, + down: function( a ) { + this.depth -= a || 1; + }, + setParser: function( name, parser ) { + this.parsers[ name ] = parser; + }, + // The next 3 are exposed so you can use them + quote: quote, + literal: literal, + join: join, + // + depth: 1, + maxDepth: 5, + + // This is the list of parsers, to modify them, use dump.setParser + parsers: { + window: "[Window]", + document: "[Document]", + error: function( error ) { + return "Error(\"" + error.message + "\")"; + }, + unknown: "[Unknown]", + "null": "null", + "undefined": "undefined", + "function": function( fn ) { + var ret = "function", + + // functions never have name in IE + name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ]; + + if ( name ) { + ret += " " + name; + } + ret += "( "; + + ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" ); + return join( ret, dump.parse( fn, "functionCode" ), "}" ); + }, + array: array, + nodelist: array, + "arguments": array, + object: function( map, stack ) { + var keys, key, val, i, nonEnumerableProperties, + ret = []; + + if ( dump.maxDepth && dump.depth > dump.maxDepth ) { + return "[object Object]"; + } + + dump.up(); + keys = []; + for ( key in map ) { + keys.push( key ); + } + + // Some properties are not always enumerable on Error objects. + nonEnumerableProperties = [ "message", "name" ]; + for ( i in nonEnumerableProperties ) { + key = nonEnumerableProperties[ i ]; + if ( key in map && !( key in keys ) ) { + keys.push( key ); + } + } + keys.sort(); + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + val = map[ key ]; + ret.push( dump.parse( key, "key" ) + ": " + + dump.parse( val, undefined, stack ) ); + } + dump.down(); + return join( "{", ret, "}" ); + }, + node: function( node ) { + var len, i, val, + open = dump.HTML ? "<" : "<", + close = dump.HTML ? ">" : ">", + tag = node.nodeName.toLowerCase(), + ret = open + tag, + attrs = node.attributes; + + if ( attrs ) { + for ( i = 0, len = attrs.length; i < len; i++ ) { + val = attrs[ i ].nodeValue; + + // IE6 includes all attributes in .attributes, even ones not explicitly + // set. Those have values like undefined, null, 0, false, "" or + // "inherit". + if ( val && val !== "inherit" ) { + ret += " " + attrs[ i ].nodeName + "=" + + dump.parse( val, "attribute" ); + } + } + } + ret += close; + + // Show content of TextNode or CDATASection + if ( node.nodeType === 3 || node.nodeType === 4 ) { + ret += node.nodeValue; + } + + return ret + open + "/" + tag + close; + }, + + // function calls it internally, it's the arguments part of the function + functionArgs: function( fn ) { + var args, + l = fn.length; + + if ( !l ) { + return ""; + } + + args = new Array( l ); + while ( l-- ) { + + // 97 is 'a' + args[ l ] = String.fromCharCode( 97 + l ); + } + return " " + args.join( ", " ) + " "; + }, + // object calls it internally, the key part of an item in a map + key: quote, + // function calls it internally, it's the content of the function + functionCode: "[code]", + // node calls it internally, it's an html attribute value + attribute: quote, + string: quote, + date: quote, + regexp: literal, + number: literal, + "boolean": literal + }, + // if true, entities are escaped ( <, >, \t, space and \n ) + HTML: false, + // indentation unit + indentChar: " ", + // if true, items in a collection, are separated by a \n, else just a space. + multiline: true + }; + + return dump; +}()); + +// back compat +QUnit.jsDump = QUnit.dump; + +// For browser, export only select globals +if ( typeof window !== "undefined" ) { + + // Deprecated + // Extend assert methods to QUnit and Global scope through Backwards compatibility + (function() { + var i, + assertions = Assert.prototype; + + function applyCurrent( current ) { + return function() { + var assert = new Assert( QUnit.config.current ); + current.apply( assert, arguments ); + }; + } + + for ( i in assertions ) { + QUnit[ i ] = applyCurrent( assertions[ i ] ); + } + })(); + + (function() { + var i, l, + keys = [ + "test", + "module", + "expect", + "asyncTest", + "start", + "stop", + "ok", + "equal", + "notEqual", + "propEqual", + "notPropEqual", + "deepEqual", + "notDeepEqual", + "strictEqual", + "notStrictEqual", + "throws" + ]; + + for ( i = 0, l = keys.length; i < l; i++ ) { + window[ keys[ i ] ] = QUnit[ keys[ i ] ]; + } + })(); + + window.QUnit = QUnit; +} + +// For nodejs +if ( typeof module !== "undefined" && module.exports ) { + module.exports = QUnit; +} + +// For CommonJS with exports, but without module.exports, like Rhino +if ( typeof exports !== "undefined" ) { + exports.QUnit = QUnit; +} + +// Get a reference to the global object, like window in browsers +}( (function() { + return this; +})() )); + +/*istanbul ignore next */ +// jscs:disable maximumLineLength +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" + */ +QUnit.diff = (function() { + var hasOwn = Object.prototype.hasOwnProperty; + + /*jshint eqeqeq:false, eqnull:true */ + function diff( o, n ) { + var i, + ns = {}, + os = {}; + + for ( i = 0; i < n.length; i++ ) { + if ( !hasOwn.call( ns, n[ i ] ) ) { + ns[ n[ i ] ] = { + rows: [], + o: null + }; + } + ns[ n[ i ] ].rows.push( i ); + } + + for ( i = 0; i < o.length; i++ ) { + if ( !hasOwn.call( os, o[ i ] ) ) { + os[ o[ i ] ] = { + rows: [], + n: null + }; + } + os[ o[ i ] ].rows.push( i ); + } + + for ( i in ns ) { + if ( hasOwn.call( ns, i ) ) { + if ( ns[ i ].rows.length === 1 && hasOwn.call( os, i ) && os[ i ].rows.length === 1 ) { + n[ ns[ i ].rows[ 0 ] ] = { + text: n[ ns[ i ].rows[ 0 ] ], + row: os[ i ].rows[ 0 ] + }; + o[ os[ i ].rows[ 0 ] ] = { + text: o[ os[ i ].rows[ 0 ] ], + row: ns[ i ].rows[ 0 ] + }; + } + } + } + + for ( i = 0; i < n.length - 1; i++ ) { + if ( n[ i ].text != null && n[ i + 1 ].text == null && n[ i ].row + 1 < o.length && o[ n[ i ].row + 1 ].text == null && + n[ i + 1 ] == o[ n[ i ].row + 1 ] ) { + + n[ i + 1 ] = { + text: n[ i + 1 ], + row: n[ i ].row + 1 + }; + o[ n[ i ].row + 1 ] = { + text: o[ n[ i ].row + 1 ], + row: i + 1 + }; + } + } + + for ( i = n.length - 1; i > 0; i-- ) { + if ( n[ i ].text != null && n[ i - 1 ].text == null && n[ i ].row > 0 && o[ n[ i ].row - 1 ].text == null && + n[ i - 1 ] == o[ n[ i ].row - 1 ] ) { + + n[ i - 1 ] = { + text: n[ i - 1 ], + row: n[ i ].row - 1 + }; + o[ n[ i ].row - 1 ] = { + text: o[ n[ i ].row - 1 ], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function( o, n ) { + o = o.replace( /\s+$/, "" ); + n = n.replace( /\s+$/, "" ); + + var i, pre, + str = "", + out = diff( o === "" ? [] : o.split( /\s+/ ), n === "" ? [] : n.split( /\s+/ ) ), + oSpace = o.match( /\s+/g ), + nSpace = n.match( /\s+/g ); + + if ( oSpace == null ) { + oSpace = [ " " ]; + } else { + oSpace.push( " " ); + } + + if ( nSpace == null ) { + nSpace = [ " " ]; + } else { + nSpace.push( " " ); + } + + if ( out.n.length === 0 ) { + for ( i = 0; i < out.o.length; i++ ) { + str += "" + out.o[ i ] + oSpace[ i ] + ""; + } + } else { + if ( out.n[ 0 ].text == null ) { + for ( n = 0; n < out.o.length && out.o[ n ].text == null; n++ ) { + str += "" + out.o[ n ] + oSpace[ n ] + ""; + } + } + + for ( i = 0; i < out.n.length; i++ ) { + if ( out.n[ i ].text == null ) { + str += "" + out.n[ i ] + nSpace[ i ] + ""; + } else { + + // `pre` initialized at top of scope + pre = ""; + + for ( n = out.n[ i ].row + 1; n < out.o.length && out.o[ n ].text == null; n++ ) { + pre += "" + out.o[ n ] + oSpace[ n ] + ""; + } + str += " " + out.n[ i ].text + nSpace[ i ] + pre; + } + } + } + + return str; + }; +}()); +// jscs:enable + +(function() { + +// Deprecated QUnit.init - Ref #530 +// Re-initialize the configuration options +QUnit.init = function() { + var tests, banner, result, qunit, + config = QUnit.config; + + config.stats = { all: 0, bad: 0 }; + config.moduleStats = { all: 0, bad: 0 }; + config.started = 0; + config.updateRate = 1000; + config.blocking = false; + config.autostart = true; + config.autorun = false; + config.filter = ""; + config.queue = []; + + // Return on non-browser environments + // This is necessary to not break on node tests + if ( typeof window === "undefined" ) { + return; + } + + qunit = id( "qunit" ); + if ( qunit ) { + qunit.innerHTML = + "

    " + escapeText( document.title ) + "

    " + + "

    " + + "
    " + + "

    " + + "
      "; + } + + tests = id( "qunit-tests" ); + banner = id( "qunit-banner" ); + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...
       "; + } +}; + +// Don't load the HTML Reporter on non-Browser environments +if ( typeof window === "undefined" ) { + return; +} + +var config = QUnit.config, + hasOwn = Object.prototype.hasOwnProperty, + defined = { + document: window.document !== undefined, + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch ( e ) { + return false; + } + }()) + }, + modulesList = []; + +/** +* Escape text for attribute or text content. +*/ +function escapeText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + + // Both single quotes and double quotes (for attributes) + return s.replace( /['"<>&]/g, function( s ) { + switch ( s ) { + case "'": + return "'"; + case "\"": + return """; + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + } + }); +} + +/** + * @param {HTMLElement} elem + * @param {string} type + * @param {Function} fn + */ +function addEvent( elem, type, fn ) { + if ( elem.addEventListener ) { + + // Standards-based browsers + elem.addEventListener( type, fn, false ); + } else if ( elem.attachEvent ) { + + // support: IE <9 + elem.attachEvent( "on" + type, fn ); + } +} + +/** + * @param {Array|NodeList} elems + * @param {string} type + * @param {Function} fn + */ +function addEvents( elems, type, fn ) { + var i = elems.length; + while ( i-- ) { + addEvent( elems[ i ], type, fn ); + } +} + +function hasClass( elem, name ) { + return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0; +} + +function addClass( elem, name ) { + if ( !hasClass( elem, name ) ) { + elem.className += ( elem.className ? " " : "" ) + name; + } +} + +function toggleClass( elem, name ) { + if ( hasClass( elem, name ) ) { + removeClass( elem, name ); + } else { + addClass( elem, name ); + } +} + +function removeClass( elem, name ) { + var set = " " + elem.className + " "; + + // Class name may appear multiple times + while ( set.indexOf( " " + name + " " ) >= 0 ) { + set = set.replace( " " + name + " ", " " ); + } + + // trim for prettiness + elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" ); +} + +function id( name ) { + return defined.document && document.getElementById && document.getElementById( name ); +} + +function getUrlConfigHtml() { + var i, j, val, + escaped, escapedTooltip, + selection = false, + len = config.urlConfig.length, + urlConfigHtml = ""; + + for ( i = 0; i < len; i++ ) { + val = config.urlConfig[ i ]; + if ( typeof val === "string" ) { + val = { + id: val, + label: val + }; + } + + escaped = escapeText( val.id ); + escapedTooltip = escapeText( val.tooltip ); + + config[ val.id ] = QUnit.urlParams[ val.id ]; + if ( !val.value || typeof val.value === "string" ) { + urlConfigHtml += ""; + } else { + urlConfigHtml += ""; + } + } + + return urlConfigHtml; +} + +// Handle "click" events on toolbar checkboxes and "change" for select menus. +// Updates the URL with the new state of `config.urlConfig` values. +function toolbarChanged() { + var updatedUrl, value, + field = this, + params = {}; + + // Detect if field is a select menu or a checkbox + if ( "selectedIndex" in field ) { + value = field.options[ field.selectedIndex ].value || undefined; + } else { + value = field.checked ? ( field.defaultValue || true ) : undefined; + } + + params[ field.name ] = value; + updatedUrl = QUnit.url( params ); + + if ( "hidepassed" === field.name && "replaceState" in window.history ) { + config[ field.name ] = value || false; + if ( value ) { + addClass( id( "qunit-tests" ), "hidepass" ); + } else { + removeClass( id( "qunit-tests" ), "hidepass" ); + } + + // It is not necessary to refresh the whole page + window.history.replaceState( null, "", updatedUrl ); + } else { + window.location = updatedUrl; + } +} + +function toolbarUrlConfigContainer() { + var urlConfigContainer = document.createElement( "span" ); + + urlConfigContainer.innerHTML = getUrlConfigHtml(); + + // For oldIE support: + // * Add handlers to the individual elements instead of the container + // * Use "click" instead of "change" for checkboxes + addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", toolbarChanged ); + addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", toolbarChanged ); + + return urlConfigContainer; +} + +function toolbarModuleFilterHtml() { + var i, + moduleFilterHtml = ""; + + if ( !modulesList.length ) { + return false; + } + + modulesList.sort(function( a, b ) { + return a.localeCompare( b ); + }); + + moduleFilterHtml += "" + + ""; + + return moduleFilterHtml; +} + +function toolbarModuleFilter() { + var toolbar = id( "qunit-testrunner-toolbar" ), + moduleFilter = document.createElement( "span" ), + moduleFilterHtml = toolbarModuleFilterHtml(); + + if ( !moduleFilterHtml ) { + return false; + } + + moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); + moduleFilter.innerHTML = moduleFilterHtml; + + addEvent( moduleFilter.lastChild, "change", function() { + var selectBox = moduleFilter.getElementsByTagName( "select" )[ 0 ], + selection = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value ); + + window.location = QUnit.url({ + module: ( selection === "" ) ? undefined : selection, + + // Remove any existing filters + filter: undefined, + testId: undefined + }); + }); + + toolbar.appendChild( moduleFilter ); +} + +function appendToolbar() { + var toolbar = id( "qunit-testrunner-toolbar" ); + + if ( toolbar ) { + toolbar.appendChild( toolbarUrlConfigContainer() ); + } +} + +function appendBanner() { + var banner = id( "qunit-banner" ); + + if ( banner ) { + banner.className = ""; + banner.innerHTML = "" + banner.innerHTML + " "; + } +} + +function appendTestResults() { + var tests = id( "qunit-tests" ), + result = id( "qunit-testresult" ); + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + tests.innerHTML = ""; + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...
       "; + } +} + +function storeFixture() { + var fixture = id( "qunit-fixture" ); + if ( fixture ) { + config.fixture = fixture.innerHTML; + } +} + +function appendUserAgent() { + var userAgent = id( "qunit-userAgent" ); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } +} + +function appendTestsList( modules ) { + var i, l, x, z, test, moduleObj; + + for ( i = 0, l = modules.length; i < l; i++ ) { + moduleObj = modules[ i ]; + + if ( moduleObj.name ) { + modulesList.push( moduleObj.name ); + } + + for ( x = 0, z = moduleObj.tests.length; x < z; x++ ) { + test = moduleObj.tests[ x ]; + + appendTest( test.name, test.testId, moduleObj.name ); + } + } +} + +function appendTest( name, testId, moduleName ) { + var title, rerunTrigger, testBlock, assertList, + tests = id( "qunit-tests" ); + + if ( !tests ) { + return; + } + + title = document.createElement( "strong" ); + title.innerHTML = getNameHtml( name, moduleName ); + + rerunTrigger = document.createElement( "a" ); + rerunTrigger.innerHTML = "Rerun"; + rerunTrigger.href = QUnit.url({ testId: testId }); + + testBlock = document.createElement( "li" ); + testBlock.appendChild( title ); + testBlock.appendChild( rerunTrigger ); + testBlock.id = "qunit-test-output-" + testId; + + assertList = document.createElement( "ol" ); + assertList.className = "qunit-assert-list"; + + testBlock.appendChild( assertList ); + + tests.appendChild( testBlock ); +} + +// HTML Reporter initialization and load +QUnit.begin(function( details ) { + var qunit = id( "qunit" ); + + // Fixture is the only one necessary to run without the #qunit element + storeFixture(); + + if ( !qunit ) { + return; + } + + qunit.innerHTML = + "

      " + escapeText( document.title ) + "

      " + + "

      " + + "
      " + + "

      " + + "
        "; + + appendBanner(); + appendTestResults(); + appendUserAgent(); + appendToolbar(); + appendTestsList( details.modules ); + toolbarModuleFilter(); + + if ( config.hidepassed ) { + addClass( qunit.lastChild, "hidepass" ); + } +}); + +QUnit.done(function( details ) { + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + html = [ + "Tests completed in ", + details.runtime, + " milliseconds.
        ", + "", + details.passed, + " assertions of ", + details.total, + " passed, ", + details.failed, + " failed." + ].join( "" ); + + if ( banner ) { + banner.className = details.failed ? "qunit-fail" : "qunit-pass"; + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && defined.document && document.title ) { + + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( details.failed ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && details.failed === 0 ) { + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } + } + } + + // scroll back to top to show results + if ( config.scrolltop && window.scrollTo ) { + window.scrollTo( 0, 0 ); + } +}); + +function getNameHtml( name, module ) { + var nameHtml = ""; + + if ( module ) { + nameHtml = "" + escapeText( module ) + ": "; + } + + nameHtml += "" + escapeText( name ) + ""; + + return nameHtml; +} + +QUnit.testStart(function( details ) { + var running, testBlock; + + testBlock = id( "qunit-test-output-" + details.testId ); + if ( testBlock ) { + testBlock.className = "running"; + } else { + + // Report later registered tests + appendTest( details.name, details.testId, details.module ); + } + + running = id( "qunit-testresult" ); + if ( running ) { + running.innerHTML = "Running:
        " + getNameHtml( details.name, details.module ); + } + +}); + +QUnit.log(function( details ) { + var assertList, assertLi, + message, expected, actual, + testItem = id( "qunit-test-output-" + details.testId ); + + if ( !testItem ) { + return; + } + + message = escapeText( details.message ) || ( details.result ? "okay" : "failed" ); + message = "" + message + ""; + message += "@ " + details.runtime + " ms"; + + // pushFailure doesn't provide details.expected + // when it calls, it's implicit to also not show expected and diff stuff + // Also, we need to check details.expected existence, as it can exist and be undefined + if ( !details.result && hasOwn.call( details, "expected" ) ) { + expected = escapeText( QUnit.dump.parse( details.expected ) ); + actual = escapeText( QUnit.dump.parse( details.actual ) ); + message += ""; + + if ( actual !== expected ) { + message += "" + + ""; + } + + if ( details.source ) { + message += ""; + } + + message += "
        Expected:
        " +
        +			expected +
        +			"
        Result:
        " +
        +				actual + "
        Diff:
        " +
        +				QUnit.diff( expected, actual ) + "
        Source:
        " +
        +				escapeText( details.source ) + "
        "; + + // this occours when pushFailure is set and we have an extracted stack trace + } else if ( !details.result && details.source ) { + message += "" + + "" + + "
        Source:
        " +
        +			escapeText( details.source ) + "
        "; + } + + assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; + + assertLi = document.createElement( "li" ); + assertLi.className = details.result ? "pass" : "fail"; + assertLi.innerHTML = message; + assertList.appendChild( assertLi ); +}); + +QUnit.testDone(function( details ) { + var testTitle, time, testItem, assertList, + good, bad, testCounts, skipped, + tests = id( "qunit-tests" ); + + if ( !tests ) { + return; + } + + testItem = id( "qunit-test-output-" + details.testId ); + + assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; + + good = details.passed; + bad = details.failed; + + // store result when possible + if ( config.reorder && defined.sessionStorage ) { + if ( bad ) { + sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad ); + } else { + sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name ); + } + } + + if ( bad === 0 ) { + addClass( assertList, "qunit-collapsed" ); + } + + // testItem.firstChild is the test name + testTitle = testItem.firstChild; + + testCounts = bad ? + "" + bad + ", " + "" + good + ", " : + ""; + + testTitle.innerHTML += " (" + testCounts + + details.assertions.length + ")"; + + if ( details.skipped ) { + addClass( testItem, "skipped" ); + skipped = document.createElement( "em" ); + skipped.className = "qunit-skipped-label"; + skipped.innerHTML = "skipped"; + testItem.insertBefore( skipped, testTitle ); + } else { + addEvent( testTitle, "click", function() { + toggleClass( assertList, "qunit-collapsed" ); + }); + + testItem.className = bad ? "fail" : "pass"; + + time = document.createElement( "span" ); + time.className = "runtime"; + time.innerHTML = details.runtime + " ms"; + testItem.insertBefore( time, assertList ); + } +}); + +if ( !defined.document || document.readyState === "complete" ) { + config.pageLoaded = true; + config.autorun = true; +} + +if ( defined.document ) { + addEvent( window, "load", QUnit.load ); +} + +})(); diff --git a/testing/testing-ipv6.js b/testing/testing-ipv6.js new file mode 100644 index 0000000..d447735 --- /dev/null +++ b/testing/testing-ipv6.js @@ -0,0 +1,594 @@ +var ipv6parser = $.tablesorter.getParserById('ipv6Address').format, +ipv6regex = $.tablesorter.regex.ipv6Validate; + +QUnit.extend(QUnit.assert, { + ipv6test: function(result, str, expect){ + if (result) { + // ok( $.tablesorter.regex.ipv6Validate.test(str), "valid: " + str ); + // second parameter = true, so we get the hex format (false or undefined returns decimal) + var t = ipv6parser(str, true); + QUnit.assert.equal( t, expect, 'valid: ' + t + ' \u2190 "' + str + '"' ); + } else { + QUnit.assert.ok( !ipv6regex.test(str), 'invalid: "' + str + '"' ); + } + } +}); + +ipv6tests = function(){ + + QUnit.test( "ipv6 parser", function(assert) { + expect(483); + + // IPV6 tests by Rich Brown copied from http:// download.dartware.com/thirdparty/test-ipv6-regex.pl + // modified to compare to canonical ipv6 output using http://www.v6decode.com/ to produce the result + assert.ipv6test(!1,""); // empty string + assert.ipv6test(1,"::1", "0000:0000:0000:0000:0000:0000:0000:0001"); // loopback, compressed, non-routable + assert.ipv6test(1,"::", "0000:0000:0000:0000:0000:0000:0000:0000"); // unspecified, compressed, non-routable + assert.ipv6test(1,"0:0:0:0:0:0:0:1", "0000:0000:0000:0000:0000:0000:0000:0001"); // loopback, full + assert.ipv6test(1,"0:0:0:0:0:0:0:0", "0000:0000:0000:0000:0000:0000:0000:0000"); // unspecified, full + assert.ipv6test(1,"2001:db8:0:0:8:800:200c:417a", "2001:0db8:0000:0000:0008:0800:200c:417a"); // unicast, full + assert.ipv6test(1,"ff01:0:0:0:0:0:0:101", "ff01:0000:0000:0000:0000:0000:0000:0101"); // multicast, full + assert.ipv6test(1,"2001:db8::8:800:200c:417a", "2001:0db8:0000:0000:0008:0800:200c:417a"); // unicast, compressed + assert.ipv6test(1,"ff01::101", "ff01:0000:0000:0000:0000:0000:0000:0101"); // multicast, compressed + assert.ipv6test(!1,"2001:db8:0:0:8:800:200c:417a:221"); // unicast, full + assert.ipv6test(!1,"ff01::101::2"); // multicast, compressed + assert.ipv6test(1,"fe80::217:f2ff:fe07:ed62", "fe80:0000:0000:0000:0217:f2ff:fe07:ed62"); + + assert.ipv6test(1,"2001:0000:1234:0000:0000:c1c0:abcd:0876", "2001:0000:1234:0000:0000:c1c0:abcd:0876"); + assert.ipv6test(1,"3ffe:0b00:0000:0000:0001:0000:0000:000a", "3ffe:0b00:0000:0000:0001:0000:0000:000a"); + assert.ipv6test(1,"ff02:0000:0000:0000:0000:0000:0000:0001", "ff02:0000:0000:0000:0000:0000:0000:0001"); + assert.ipv6test(1,"0000:0000:0000:0000:0000:0000:0000:0001", "0000:0000:0000:0000:0000:0000:0000:0001"); + assert.ipv6test(1,"0000:0000:0000:0000:0000:0000:0000:0000", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(!1,"02001:0000:1234:0000:0000:c1c0:abcd:0876"); // extra 0 not allowed! + assert.ipv6test(!1,"2001:0000:1234:0000:00001:c1c0:abcd:0876"); // extra 0 not allowed! + // assert.ipv6test(1," 2001:0000:1234:0000:0000:c1c0:abcd:0876"); // leading space + // assert.ipv6test(1,"2001:0000:1234:0000:0000:c1c0:abcd:0876"); // trailing space + // assert.ipv6test(1," 2001:0000:1234:0000:0000:c1c0:abcd:0876 "); // leading and trailing space + assert.ipv6test(!1,"2001:0000:1234:0000:0000:c1c0:abcd:0876 0"); // junk after valid address + assert.ipv6test(!1,"2001:0000:1234: 0000:0000:c1c0:abcd:0876"); // internal space + + assert.ipv6test(!1,"3ffe:0b00:0000:0001:0000:0000:000a"); // seven segments + assert.ipv6test(!1,"ff02:0000:0000:0000:0000:0000:0000:0000:0001"); // nine segments + assert.ipv6test(!1,"3ffe:b00::1::a"); // double "::" + assert.ipv6test(!1,"::1111:2222:3333:4444:5555:6666::"); // double "::" + assert.ipv6test(1,"2::10", "0002:0000:0000:0000:0000:0000:0000:0010"); + assert.ipv6test(1,"ff02::1", "ff02:0000:0000:0000:0000:0000:0000:0001"); + assert.ipv6test(1,"fe80::", "fe80:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"2002::", "2002:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"2001:db8::", "2001:0db8:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"2001:0db8:1234::", "2001:0db8:1234:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"::ffff:0:0", "0000:0000:0000:0000:0000:ffff:0000:0000"); + assert.ipv6test(1,"1:2:3:4:5:6:7:8", "0001:0002:0003:0004:0005:0006:0007:0008"); + assert.ipv6test(1,"1:2:3:4:5:6::8", "0001:0002:0003:0004:0005:0006:0000:0008"); + assert.ipv6test(1,"1:2:3:4:5::8", "0001:0002:0003:0004:0005:0000:0000:0008"); + assert.ipv6test(1,"1:2:3:4::8", "0001:0002:0003:0004:0000:0000:0000:0008"); + assert.ipv6test(1,"1:2:3::8", "0001:0002:0003:0000:0000:0000:0000:0008"); + assert.ipv6test(1,"1:2::8", "0001:0002:0000:0000:0000:0000:0000:0008"); + assert.ipv6test(1,"1::8", "0001:0000:0000:0000:0000:0000:0000:0008"); + assert.ipv6test(1,"1::2:3:4:5:6:7", "0001:0000:0002:0003:0004:0005:0006:0007"); + assert.ipv6test(1,"1::2:3:4:5:6", "0001:0000:0000:0002:0003:0004:0005:0006"); + assert.ipv6test(1,"1::2:3:4:5", "0001:0000:0000:0000:0002:0003:0004:0005"); + assert.ipv6test(1,"1::2:3:4", "0001:0000:0000:0000:0000:0002:0003:0004"); + assert.ipv6test(1,"1::2:3", "0001:0000:0000:0000:0000:0000:0002:0003"); + assert.ipv6test(1,"1::8", "0001:0000:0000:0000:0000:0000:0000:0008"); + assert.ipv6test(1,"::2:3:4:5:6:7:8", "0000:0002:0003:0004:0005:0006:0007:0008"); + assert.ipv6test(1,"::2:3:4:5:6:7", "0000:0000:0002:0003:0004:0005:0006:0007"); + assert.ipv6test(1,"::2:3:4:5:6", "0000:0000:0000:0002:0003:0004:0005:0006"); + assert.ipv6test(1,"::2:3:4:5", "0000:0000:0000:0000:0002:0003:0004:0005"); + assert.ipv6test(1,"::2:3:4", "0000:0000:0000:0000:0000:0002:0003:0004"); + assert.ipv6test(1,"::2:3", "0000:0000:0000:0000:0000:0000:0002:0003"); + assert.ipv6test(1,"::8", "0000:0000:0000:0000:0000:0000:0000:0008"); + assert.ipv6test(1,"1:2:3:4:5:6::", "0001:0002:0003:0004:0005:0006:0000:0000"); + assert.ipv6test(1,"1:2:3:4:5::", "0001:0002:0003:0004:0005:0000:0000:0000"); + assert.ipv6test(1,"1:2:3:4::", "0001:0002:0003:0004:0000:0000:0000:0000"); + assert.ipv6test(1,"1:2:3::", "0001:0002:0003:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"1:2::", "0001:0002:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"1::", "0001:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"1:2:3:4:5::7:8", "0001:0002:0003:0004:0005:0000:0007:0008"); + assert.ipv6test(!1,"1:2:3::4:5::7:8"); // double "::" + assert.ipv6test(!1,"12345::6:7:8"); + assert.ipv6test(1,"1:2:3:4::7:8", "0001:0002:0003:0004:0000:0000:0007:0008"); + assert.ipv6test(1,"1:2:3::7:8", "0001:0002:0003:0000:0000:0000:0007:0008"); + assert.ipv6test(1,"1:2::7:8", "0001:0002:0000:0000:0000:0000:0007:0008"); + assert.ipv6test(1,"1::7:8", "0001:0000:0000:0000:0000:0000:0007:0008"); + + // ipv4 addresses as dotted-quads + assert.ipv6test(1,"1:2:3:4:5:6:1.2.3.4", "0001:0002:0003:0004:0005:0006:0102:0304"); + assert.ipv6test(1,"1:2:3:4:5::1.2.3.4", "0001:0002:0003:0004:0005:0000:0102:0304"); + assert.ipv6test(1,"1:2:3:4::1.2.3.4", "0001:0002:0003:0004:0000:0000:0102:0304"); + assert.ipv6test(1,"1:2:3::1.2.3.4", "0001:0002:0003:0000:0000:0000:0102:0304"); + assert.ipv6test(1,"1:2::1.2.3.4", "0001:0002:0000:0000:0000:0000:0102:0304"); + assert.ipv6test(1,"1::1.2.3.4", "0001:0000:0000:0000:0000:0000:0102:0304"); + assert.ipv6test(1,"1:2:3:4::5:1.2.3.4", "0001:0002:0003:0004:0000:0005:0102:0304"); + assert.ipv6test(1,"1:2:3::5:1.2.3.4", "0001:0002:0003:0000:0000:0005:0102:0304"); + assert.ipv6test(1,"1:2::5:1.2.3.4", "0001:0002:0000:0000:0000:0005:0102:0304"); + assert.ipv6test(1,"1::5:1.2.3.4", "0001:0000:0000:0000:0000:0005:0102:0304"); + assert.ipv6test(1,"1::5:11.22.33.44", "0001:0000:0000:0000:0000:0005:0b16:212c"); + assert.ipv6test(!1,"1::5:400.2.3.4"); + assert.ipv6test(!1,"1::5:260.2.3.4"); + assert.ipv6test(!1,"1::5:256.2.3.4"); + assert.ipv6test(!1,"1::5:1.256.3.4"); + assert.ipv6test(!1,"1::5:1.2.256.4"); + assert.ipv6test(!1,"1::5:1.2.3.256"); + assert.ipv6test(!1,"1::5:300.2.3.4"); + assert.ipv6test(!1,"1::5:1.300.3.4"); + assert.ipv6test(!1,"1::5:1.2.300.4"); + assert.ipv6test(!1,"1::5:1.2.3.300"); + assert.ipv6test(!1,"1::5:900.2.3.4"); + assert.ipv6test(!1,"1::5:1.900.3.4"); + assert.ipv6test(!1,"1::5:1.2.900.4"); + assert.ipv6test(!1,"1::5:1.2.3.900"); + assert.ipv6test(!1,"1::5:300.300.300.300"); + assert.ipv6test(!1,"1::5:3000.30.30.30"); + assert.ipv6test(!1,"1::400.2.3.4"); + assert.ipv6test(!1,"1::260.2.3.4"); + assert.ipv6test(!1,"1::256.2.3.4"); + assert.ipv6test(!1,"1::1.256.3.4"); + assert.ipv6test(!1,"1::1.2.256.4"); + assert.ipv6test(!1,"1::1.2.3.256"); + assert.ipv6test(!1,"1::300.2.3.4"); + assert.ipv6test(!1,"1::1.300.3.4"); + assert.ipv6test(!1,"1::1.2.300.4"); + assert.ipv6test(!1,"1::1.2.3.300"); + assert.ipv6test(!1,"1::900.2.3.4"); + assert.ipv6test(!1,"1::1.900.3.4"); + assert.ipv6test(!1,"1::1.2.900.4"); + assert.ipv6test(!1,"1::1.2.3.900"); + assert.ipv6test(!1,"1::300.300.300.300"); + assert.ipv6test(!1,"1::3000.30.30.30"); + assert.ipv6test(!1,"::400.2.3.4"); + assert.ipv6test(!1,"::260.2.3.4"); + assert.ipv6test(!1,"::256.2.3.4"); + assert.ipv6test(!1,"::1.256.3.4"); + assert.ipv6test(!1,"::1.2.256.4"); + assert.ipv6test(!1,"::1.2.3.256"); + assert.ipv6test(!1,"::300.2.3.4"); + assert.ipv6test(!1,"::1.300.3.4"); + assert.ipv6test(!1,"::1.2.300.4"); + assert.ipv6test(!1,"::1.2.3.300"); + assert.ipv6test(!1,"::900.2.3.4"); + assert.ipv6test(!1,"::1.900.3.4"); + assert.ipv6test(!1,"::1.2.900.4"); + assert.ipv6test(!1,"::1.2.3.900"); + assert.ipv6test(!1,"::300.300.300.300"); + assert.ipv6test(!1,"::3000.30.30.30"); + assert.ipv6test(1,"fe80::217:f2ff:254.7.237.98", "fe80:0000:0000:0000:0217:f2ff:fe07:ed62"); + assert.ipv6test(1,"::ffff:192.168.1.26", "0000:0000:0000:0000:0000:ffff:c0a8:011a"); + assert.ipv6test(!1,"2001:1:1:1:1:1:255z255x255y255"); // garbage instead of "." in ipv4 + assert.ipv6test(!1,"::ffff:192x168.1.26"); // ditto + assert.ipv6test(1,"::ffff:192.168.1.1", "0000:0000:0000:0000:0000:ffff:c0a8:0101"); + assert.ipv6test(1,"0:0:0:0:0:0:13.1.68.3", "0000:0000:0000:0000:0000:0000:0d01:4403"); // ipv4-compatible ipv6 address, full, deprecated + assert.ipv6test(1,"0:0:0:0:0:ffff:129.144.52.38", "0000:0000:0000:0000:0000:ffff:8190:3426"); // ipv4-mapped ipv6 address, full + assert.ipv6test(1,"::13.1.68.3", "0000:0000:0000:0000:0000:0000:0d01:4403"); // ipv4-compatible ipv6 address, compressed, deprecated + assert.ipv6test(1,"::ffff:129.144.52.38", "0000:0000:0000:0000:0000:ffff:8190:3426"); // ipv4-mapped ipv6 address, compressed + assert.ipv6test(1,"fe80:0:0:0:204:61ff:254.157.241.86", "fe80:0000:0000:0000:0204:61ff:fe9d:f156"); + assert.ipv6test(1,"fe80::204:61ff:254.157.241.86", "fe80:0000:0000:0000:0204:61ff:fe9d:f156"); + assert.ipv6test(1,"::ffff:12.34.56.78", "0000:0000:0000:0000:0000:ffff:0c22:384e"); + assert.ipv6test(!1,"::ffff:2.3.4"); + assert.ipv6test(!1,"::ffff:257.1.2.3"); + assert.ipv6test(!1,"1.2.3.4"); + + assert.ipv6test(!1,"1.2.3.4:1111:2222:3333:4444::5555"); // aeron + assert.ipv6test(!1,"1.2.3.4:1111:2222:3333::5555"); + assert.ipv6test(!1,"1.2.3.4:1111:2222::5555"); + assert.ipv6test(!1,"1.2.3.4:1111::5555"); + assert.ipv6test(!1,"1.2.3.4::5555"); + assert.ipv6test(!1,"1.2.3.4::"); + + // testing ipv4 addresses represented as dotted-quads + // leading zero's in ipv4 addresses not allowed: some systems treat the leading "0" in ".086" as the start of an octal number + // update: the bnf in rfc-3986 explicitly defines the dec-octet (for ipv4 addresses) not to have a leading zero + assert.ipv6test(!1,"fe80:0000:0000:0000:0204:61ff:254.157.241.086"); + assert.ipv6test(1,"::ffff:192.0.2.128", "0000:0000:0000:0000:0000:ffff:c000:0280"); // but this is ok, since there's a single digit + assert.ipv6test(!1,"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:00.00.00.00"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:000.000.000.000"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:256.256.256.256"); + + // not testing address with subnet mask + // assert.ipv6test(1,"2001:0db8:0000:cd30:0000:0000:0000:0000/60"); // full, with prefix + // assert.ipv6test(1,"2001:0db8::cd30:0:0:0:0/60"); // compressed, with prefix + // assert.ipv6test(1,"2001:0db8:0:cd30::/60"); // compressed, with prefix // 2 + // assert.ipv6test(1,"::/128"); // compressed, unspecified address type, non-routable + // assert.ipv6test(1,"::1/128"); // compressed, loopback address type, non-routable + // assert.ipv6test(1,"ff00::/8"); // compressed, multicast address type + // assert.ipv6test(1,"fe80::/10"); // compressed, link-local unicast, non-routable + // assert.ipv6test(1,"fec0::/10"); // compressed, site-local unicast, deprecated + // assert.ipv6test(!1,"124.15.6.89/60"); // standard ipv4, prefix not allowed + + assert.ipv6test(1,"fe80:0000:0000:0000:0204:61ff:fe9d:f156", "fe80:0000:0000:0000:0204:61ff:fe9d:f156"); + assert.ipv6test(1,"fe80:0:0:0:204:61ff:fe9d:f156", "fe80:0000:0000:0000:0204:61ff:fe9d:f156"); + assert.ipv6test(1,"fe80::204:61ff:fe9d:f156", "fe80:0000:0000:0000:0204:61ff:fe9d:f156"); + assert.ipv6test(1,"fe80::", "fe80:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"fe80::1", "fe80:0000:0000:0000:0000:0000:0000:0001"); + assert.ipv6test(!1,":"); + assert.ipv6test(1,"::ffff:c000:280", "0000:0000:0000:0000:0000:ffff:c000:0280"); + + // aeron supplied these test cases + assert.ipv6test(!1,"1111:2222:3333:4444::5555:"); + assert.ipv6test(!1,"1111:2222:3333::5555:"); + assert.ipv6test(!1,"1111:2222::5555:"); + assert.ipv6test(!1,"1111::5555:"); + assert.ipv6test(!1,"::5555:"); + assert.ipv6test(!1,":::"); + assert.ipv6test(!1,"1111:"); + assert.ipv6test(!1,":"); + + assert.ipv6test(!1,":1111:2222:3333:4444::5555"); + assert.ipv6test(!1,":1111:2222:3333::5555"); + assert.ipv6test(!1,":1111:2222::5555"); + assert.ipv6test(!1,":1111::5555"); + assert.ipv6test(!1,":::5555"); + assert.ipv6test(!1,":::"); + + + // additional test cases + // from http:// rt.cpan.org/public/bug/display.html?id=50693 + + assert.ipv6test(1,"2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + assert.ipv6test(1,"2001:db8:85a3:0:0:8a2e:370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + assert.ipv6test(1,"2001:db8:85a3::8a2e:370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + assert.ipv6test(1,"2001:0db8:0000:0000:0000:0000:1428:57ab", "2001:0db8:0000:0000:0000:0000:1428:57ab"); + assert.ipv6test(1,"2001:0db8:0000:0000:0000::1428:57ab", "2001:0db8:0000:0000:0000:0000:1428:57ab"); + assert.ipv6test(1,"2001:0db8:0:0:0:0:1428:57ab", "2001:0db8:0000:0000:0000:0000:1428:57ab"); + assert.ipv6test(1,"2001:0db8:0:0::1428:57ab", "2001:0db8:0000:0000:0000:0000:1428:57ab"); + assert.ipv6test(1,"2001:0db8::1428:57ab", "2001:0db8:0000:0000:0000:0000:1428:57ab"); + assert.ipv6test(1,"2001:db8::1428:57ab", "2001:0db8:0000:0000:0000:0000:1428:57ab"); + assert.ipv6test(1,"0000:0000:0000:0000:0000:0000:0000:0001", "0000:0000:0000:0000:0000:0000:0000:0001"); + assert.ipv6test(1,"::ffff:0c22:384e", "0000:0000:0000:0000:0000:ffff:0c22:384e"); + assert.ipv6test(1,"2001:0db8:1234:0000:0000:0000:0000:0000", "2001:0db8:1234:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"2001:0db8:1234:ffff:ffff:ffff:ffff:ffff", "2001:0db8:1234:ffff:ffff:ffff:ffff:ffff"); + assert.ipv6test(1,"2001:db8:a::123", "2001:0db8:000a:0000:0000:0000:0000:0123"); + assert.ipv6test(1,"fe80::", "fe80:0000:0000:0000:0000:0000:0000:0000"); + + assert.ipv6test(!1,"123"); + assert.ipv6test(!1,"ldkfj"); + assert.ipv6test(!1,"2001::ffd3::57ab"); + assert.ipv6test(!1,"2001:db8:85a3::8a2e:37023:7334"); + assert.ipv6test(!1,"2001:db8:85a3::8a2e:370k:7334"); + assert.ipv6test(!1,"1:2:3:4:5:6:7:8:9"); + assert.ipv6test(!1,"1::2::3"); + assert.ipv6test(!1,"1:::3:4:5"); + assert.ipv6test(!1,"1:2:3::4:5:6:7:8:9"); + + // new from aeron + assert.ipv6test(1,"1111:2222:3333:4444:5555:6666:7777:8888", "1111:2222:3333:4444:5555:6666:7777:8888"); + assert.ipv6test(1,"1111:2222:3333:4444:5555:6666:7777::", "1111:2222:3333:4444:5555:6666:7777:0000"); + assert.ipv6test(1,"1111:2222:3333:4444:5555:6666::", "1111:2222:3333:4444:5555:6666:0000:0000"); + assert.ipv6test(1,"1111:2222:3333:4444:5555::", "1111:2222:3333:4444:5555:0000:0000:0000"); + assert.ipv6test(1,"1111:2222:3333:4444::", "1111:2222:3333:4444:0000:0000:0000:0000"); + assert.ipv6test(1,"1111:2222:3333::", "1111:2222:3333:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"1111:2222::", "1111:2222:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"1111::", "1111:0000:0000:0000:0000:0000:0000:0000"); + // assert.ipv6test(1,"::", ""); // duplicate + assert.ipv6test(1,"1111:2222:3333:4444:5555:6666::8888", "1111:2222:3333:4444:5555:6666:0000:8888"); + assert.ipv6test(1,"1111:2222:3333:4444:5555::8888", "1111:2222:3333:4444:5555:0000:0000:8888"); + assert.ipv6test(1,"1111:2222:3333:4444::8888", "1111:2222:3333:4444:0000:0000:0000:8888"); + assert.ipv6test(1,"1111:2222:3333::8888", "1111:2222:3333:0000:0000:0000:0000:8888"); + assert.ipv6test(1,"1111:2222::8888", "1111:2222:0000:0000:0000:0000:0000:8888"); + assert.ipv6test(1,"1111::8888", "1111:0000:0000:0000:0000:0000:0000:8888"); + assert.ipv6test(1,"::8888", "0000:0000:0000:0000:0000:0000:0000:8888"); + assert.ipv6test(1,"1111:2222:3333:4444:5555::7777:8888", "1111:2222:3333:4444:5555:0000:7777:8888"); + assert.ipv6test(1,"1111:2222:3333:4444::7777:8888", "1111:2222:3333:4444:0000:0000:7777:8888"); + assert.ipv6test(1,"1111:2222:3333::7777:8888", "1111:2222:3333:0000:0000:0000:7777:8888"); + assert.ipv6test(1,"1111:2222::7777:8888", "1111:2222:0000:0000:0000:0000:7777:8888"); + assert.ipv6test(1,"1111::7777:8888", "1111:0000:0000:0000:0000:0000:7777:8888"); + assert.ipv6test(1,"::7777:8888", "0000:0000:0000:0000:0000:0000:7777:8888"); + assert.ipv6test(1,"1111:2222:3333:4444::6666:7777:8888", "1111:2222:3333:4444:0000:6666:7777:8888"); + assert.ipv6test(1,"1111:2222:3333::6666:7777:8888", "1111:2222:3333:0000:0000:6666:7777:8888"); + assert.ipv6test(1,"1111:2222::6666:7777:8888", "1111:2222:0000:0000:0000:6666:7777:8888"); + assert.ipv6test(1,"1111::6666:7777:8888", "1111:0000:0000:0000:0000:6666:7777:8888"); + assert.ipv6test(1,"::6666:7777:8888", "0000:0000:0000:0000:0000:6666:7777:8888"); + assert.ipv6test(1,"1111:2222:3333::5555:6666:7777:8888", "1111:2222:3333:0000:5555:6666:7777:8888"); + assert.ipv6test(1,"1111:2222::5555:6666:7777:8888", "1111:2222:0000:0000:5555:6666:7777:8888"); + assert.ipv6test(1,"1111::5555:6666:7777:8888", "1111:0000:0000:0000:5555:6666:7777:8888"); + assert.ipv6test(1,"::5555:6666:7777:8888", "0000:0000:0000:0000:5555:6666:7777:8888"); + assert.ipv6test(1,"1111:2222::4444:5555:6666:7777:8888", "1111:2222:0000:4444:5555:6666:7777:8888"); + assert.ipv6test(1,"1111::4444:5555:6666:7777:8888", "1111:0000:0000:4444:5555:6666:7777:8888"); + assert.ipv6test(1,"::4444:5555:6666:7777:8888", "0000:0000:0000:4444:5555:6666:7777:8888"); + assert.ipv6test(1,"1111::3333:4444:5555:6666:7777:8888", "1111:0000:3333:4444:5555:6666:7777:8888"); + assert.ipv6test(1,"::3333:4444:5555:6666:7777:8888", "0000:0000:3333:4444:5555:6666:7777:8888"); + assert.ipv6test(1,"::2222:3333:4444:5555:6666:7777:8888", "0000:2222:3333:4444:5555:6666:7777:8888"); + assert.ipv6test(1,"1111:2222:3333:4444:5555:6666:123.123.123.123", "1111:2222:3333:4444:5555:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222:3333:4444:5555::123.123.123.123", "1111:2222:3333:4444:5555:0000:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222:3333:4444::123.123.123.123", "1111:2222:3333:4444:0000:0000:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222:3333::123.123.123.123", "1111:2222:3333:0000:0000:0000:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222::123.123.123.123", "1111:2222:0000:0000:0000:0000:7b7b:7b7b"); + assert.ipv6test(1,"1111::123.123.123.123", "1111:0000:0000:0000:0000:0000:7b7b:7b7b"); + assert.ipv6test(1,"::123.123.123.123", "0000:0000:0000:0000:0000:0000:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222:3333:4444::6666:123.123.123.123", "1111:2222:3333:4444:0000:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222:3333::6666:123.123.123.123", "1111:2222:3333:0000:0000:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222::6666:123.123.123.123", "1111:2222:0000:0000:0000:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111::6666:123.123.123.123", "1111:0000:0000:0000:0000:6666:7b7b:7b7b"); + assert.ipv6test(1,"::6666:123.123.123.123", "0000:0000:0000:0000:0000:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222:3333::5555:6666:123.123.123.123", "1111:2222:3333:0000:5555:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222::5555:6666:123.123.123.123", "1111:2222:0000:0000:5555:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111::5555:6666:123.123.123.123", "1111:0000:0000:0000:5555:6666:7b7b:7b7b"); + assert.ipv6test(1,"::5555:6666:123.123.123.123", "0000:0000:0000:0000:5555:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111:2222::4444:5555:6666:123.123.123.123", "1111:2222:0000:4444:5555:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111::4444:5555:6666:123.123.123.123", "1111:0000:0000:4444:5555:6666:7b7b:7b7b"); + assert.ipv6test(1,"::4444:5555:6666:123.123.123.123", "0000:0000:0000:4444:5555:6666:7b7b:7b7b"); + assert.ipv6test(1,"1111::3333:4444:5555:6666:123.123.123.123", "1111:0000:3333:4444:5555:6666:7b7b:7b7b"); + assert.ipv6test(1,"::2222:3333:4444:5555:6666:123.123.123.123", "0000:2222:3333:4444:5555:6666:7b7b:7b7b"); + + // playing with combinations of "0" and "::" + // nb: these are all sytactically correct, but are bad form + // because "0" adjacent to "::" should be combined into "::" + assert.ipv6test(1,"::0:0:0:0:0:0:0", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"::0:0:0:0:0:0", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"::0:0:0:0:0", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"::0:0:0:0", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"::0:0:0", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"::0:0", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"::0", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"0:0:0:0:0:0:0::", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"0:0:0:0:0:0::", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"0:0:0:0:0::", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"0:0:0:0::", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"0:0:0::", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"0:0::", "0000:0000:0000:0000:0000:0000:0000:0000"); + assert.ipv6test(1,"0::", "0000:0000:0000:0000:0000:0000:0000:0000"); + + // new invalid from aeron + // invalid data + assert.ipv6test(!1,"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx"); + + // too many components + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:7777:8888:9999"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:7777:8888::"); + assert.ipv6test(!1,"::2222:3333:4444:5555:6666:7777:8888:9999"); + + // too few components + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:7777"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555"); + assert.ipv6test(!1,"1111:2222:3333:4444"); + assert.ipv6test(!1,"1111:2222:3333"); + assert.ipv6test(!1,"1111:2222"); + assert.ipv6test(!1,"1111"); + + // missing : + assert.ipv6test(!1,"11112222:3333:4444:5555:6666:7777:8888"); + assert.ipv6test(!1,"1111:22223333:4444:5555:6666:7777:8888"); + assert.ipv6test(!1,"1111:2222:33334444:5555:6666:7777:8888"); + assert.ipv6test(!1,"1111:2222:3333:44445555:6666:7777:8888"); + assert.ipv6test(!1,"1111:2222:3333:4444:55556666:7777:8888"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:66667777:8888"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:77778888"); + + // missing : intended for :: + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:7777:8888:"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:7777:"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:"); + assert.ipv6test(!1,"1111:2222:3333:4444:"); + assert.ipv6test(!1,"1111:2222:3333:"); + assert.ipv6test(!1,"1111:2222:"); + assert.ipv6test(!1,"1111:"); + assert.ipv6test(!1,":"); + assert.ipv6test(!1,":8888"); + assert.ipv6test(!1,":7777:8888"); + assert.ipv6test(!1,":6666:7777:8888"); + assert.ipv6test(!1,":5555:6666:7777:8888"); + assert.ipv6test(!1,":4444:5555:6666:7777:8888"); + assert.ipv6test(!1,":3333:4444:5555:6666:7777:8888"); + assert.ipv6test(!1,":2222:3333:4444:5555:6666:7777:8888"); + assert.ipv6test(!1,":1111:2222:3333:4444:5555:6666:7777:8888"); + + // ::: + assert.ipv6test(!1,":::2222:3333:4444:5555:6666:7777:8888"); + assert.ipv6test(!1,"1111:::3333:4444:5555:6666:7777:8888"); + assert.ipv6test(!1,"1111:2222:::4444:5555:6666:7777:8888"); + assert.ipv6test(!1,"1111:2222:3333:::5555:6666:7777:8888"); + assert.ipv6test(!1,"1111:2222:3333:4444:::6666:7777:8888"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:::7777:8888"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:::8888"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:7777:::"); + + // double ::"); + assert.ipv6test(!1,"::2222::4444:5555:6666:7777:8888"); + assert.ipv6test(!1,"::2222:3333::5555:6666:7777:8888"); + assert.ipv6test(!1,"::2222:3333:4444::6666:7777:8888"); + assert.ipv6test(!1,"::2222:3333:4444:5555::7777:8888"); + assert.ipv6test(!1,"::2222:3333:4444:5555:7777::8888"); + assert.ipv6test(!1,"::2222:3333:4444:5555:7777:8888::"); + + assert.ipv6test(!1,"1111::3333::5555:6666:7777:8888"); + assert.ipv6test(!1,"1111::3333:4444::6666:7777:8888"); + assert.ipv6test(!1,"1111::3333:4444:5555::7777:8888"); + assert.ipv6test(!1,"1111::3333:4444:5555:6666::8888"); + assert.ipv6test(!1,"1111::3333:4444:5555:6666:7777::"); + + assert.ipv6test(!1,"1111:2222::4444::6666:7777:8888"); + assert.ipv6test(!1,"1111:2222::4444:5555::7777:8888"); + assert.ipv6test(!1,"1111:2222::4444:5555:6666::8888"); + assert.ipv6test(!1,"1111:2222::4444:5555:6666:7777::"); + + assert.ipv6test(!1,"1111:2222:3333::5555::7777:8888"); + assert.ipv6test(!1,"1111:2222:3333::5555:6666::8888"); + assert.ipv6test(!1,"1111:2222:3333::5555:6666:7777::"); + + assert.ipv6test(!1,"1111:2222:3333:4444::6666::8888"); + assert.ipv6test(!1,"1111:2222:3333:4444::6666:7777::"); + + assert.ipv6test(!1,"1111:2222:3333:4444:5555::7777::"); + + + // too many components" + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:7777:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666::1.2.3.4"); + assert.ipv6test(!1,"::2222:3333:4444:5555:6666:7777:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:1.2.3.4.5"); + + // too few components + assert.ipv6test(!1,"1111:2222:3333:4444:5555:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:4444:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:1.2.3.4"); + assert.ipv6test(!1,"1111:1.2.3.4"); + assert.ipv6test(!1,"1.2.3.4"); + + // missing : + assert.ipv6test(!1,"11112222:3333:4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,"1111:22223333:4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:33334444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:44445555:6666:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:4444:55556666:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:66661.2.3.4"); + + // missing . + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:255255.255.255"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:255.255255.255"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:255.255.255255"); + + // missing : intended for :: + assert.ipv6test(!1,":1.2.3.4"); + assert.ipv6test(!1,":6666:1.2.3.4"); + assert.ipv6test(!1,":5555:6666:1.2.3.4"); + assert.ipv6test(!1,":4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,":3333:4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,":2222:3333:4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,":1111:2222:3333:4444:5555:6666:1.2.3.4"); + + // ::: + assert.ipv6test(!1,":::2222:3333:4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,"1111:::3333:4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:::4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:::5555:6666:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:4444:::6666:1.2.3.4"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:::1.2.3.4"); + + // double :: + assert.ipv6test(!1,"::2222::4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,"::2222:3333::5555:6666:1.2.3.4"); + assert.ipv6test(!1,"::2222:3333:4444::6666:1.2.3.4"); + assert.ipv6test(!1,"::2222:3333:4444:5555::1.2.3.4"); + + assert.ipv6test(!1,"1111::3333::5555:6666:1.2.3.4"); + assert.ipv6test(!1,"1111::3333:4444::6666:1.2.3.4"); + assert.ipv6test(!1,"1111::3333:4444:5555::1.2.3.4"); + + assert.ipv6test(!1,"1111:2222::4444::6666:1.2.3.4"); + assert.ipv6test(!1,"1111:2222::4444:5555::1.2.3.4"); + + assert.ipv6test(!1,"1111:2222:3333::5555::1.2.3.4"); + + // missing parts + assert.ipv6test(!1,"::."); + assert.ipv6test(!1,"::.."); + assert.ipv6test(!1,"::..."); + assert.ipv6test(!1,"::1..."); + assert.ipv6test(!1,"::1.2.."); + assert.ipv6test(!1,"::1.2.3."); + assert.ipv6test(!1,"::.2.."); + assert.ipv6test(!1,"::.2.3."); + assert.ipv6test(!1,"::.2.3.4"); + assert.ipv6test(!1,"::..3."); + assert.ipv6test(!1,"::..3.4"); + assert.ipv6test(!1,"::...4"); + + // extra : in front + assert.ipv6test(!1,":1111:2222:3333:4444:5555:6666:7777::"); + assert.ipv6test(!1,":1111:2222:3333:4444:5555:6666::"); + assert.ipv6test(!1,":1111:2222:3333:4444:5555::"); + assert.ipv6test(!1,":1111:2222:3333:4444::"); + assert.ipv6test(!1,":1111:2222:3333::"); + assert.ipv6test(!1,":1111:2222::"); + assert.ipv6test(!1,":1111::"); + assert.ipv6test(!1,":::"); + assert.ipv6test(!1,":1111:2222:3333:4444:5555:6666::8888"); + assert.ipv6test(!1,":1111:2222:3333:4444:5555::8888"); + assert.ipv6test(!1,":1111:2222:3333:4444::8888"); + assert.ipv6test(!1,":1111:2222:3333::8888"); + assert.ipv6test(!1,":1111:2222::8888"); + assert.ipv6test(!1,":1111::8888"); + assert.ipv6test(!1,":::8888"); + assert.ipv6test(!1,":1111:2222:3333:4444:5555::7777:8888"); + assert.ipv6test(!1,":1111:2222:3333:4444::7777:8888"); + assert.ipv6test(!1,":1111:2222:3333::7777:8888"); + assert.ipv6test(!1,":1111:2222::7777:8888"); + assert.ipv6test(!1,":1111::7777:8888"); + assert.ipv6test(!1,":::7777:8888"); + assert.ipv6test(!1,":1111:2222:3333:4444::6666:7777:8888"); + assert.ipv6test(!1,":1111:2222:3333::6666:7777:8888"); + assert.ipv6test(!1,":1111:2222::6666:7777:8888"); + assert.ipv6test(!1,":1111::6666:7777:8888"); + assert.ipv6test(!1,":::6666:7777:8888"); + assert.ipv6test(!1,":1111:2222:3333::5555:6666:7777:8888"); + assert.ipv6test(!1,":1111:2222::5555:6666:7777:8888"); + assert.ipv6test(!1,":1111::5555:6666:7777:8888"); + assert.ipv6test(!1,":::5555:6666:7777:8888"); + assert.ipv6test(!1,":1111:2222::4444:5555:6666:7777:8888"); + assert.ipv6test(!1,":1111::4444:5555:6666:7777:8888"); + assert.ipv6test(!1,":::4444:5555:6666:7777:8888"); + assert.ipv6test(!1,":1111::3333:4444:5555:6666:7777:8888"); + assert.ipv6test(!1,":::3333:4444:5555:6666:7777:8888"); + assert.ipv6test(!1,":::2222:3333:4444:5555:6666:7777:8888"); + assert.ipv6test(!1,":1111:2222:3333:4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,":1111:2222:3333:4444:5555::1.2.3.4"); + assert.ipv6test(!1,":1111:2222:3333:4444::1.2.3.4"); + assert.ipv6test(!1,":1111:2222:3333::1.2.3.4"); + assert.ipv6test(!1,":1111:2222::1.2.3.4"); + assert.ipv6test(!1,":1111::1.2.3.4"); + assert.ipv6test(!1,":::1.2.3.4"); + assert.ipv6test(!1,":1111:2222:3333:4444::6666:1.2.3.4"); + assert.ipv6test(!1,":1111:2222:3333::6666:1.2.3.4"); + assert.ipv6test(!1,":1111:2222::6666:1.2.3.4"); + assert.ipv6test(!1,":1111::6666:1.2.3.4"); + assert.ipv6test(!1,":::6666:1.2.3.4"); + assert.ipv6test(!1,":1111:2222:3333::5555:6666:1.2.3.4"); + assert.ipv6test(!1,":1111:2222::5555:6666:1.2.3.4"); + assert.ipv6test(!1,":1111::5555:6666:1.2.3.4"); + assert.ipv6test(!1,":::5555:6666:1.2.3.4"); + assert.ipv6test(!1,":1111:2222::4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,":1111::4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,":::4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,":1111::3333:4444:5555:6666:1.2.3.4"); + assert.ipv6test(!1,":::2222:3333:4444:5555:6666:1.2.3.4"); + + // extra : at end + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:7777:::"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666:::"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:::"); + assert.ipv6test(!1,"1111:2222:3333:4444:::"); + assert.ipv6test(!1,"1111:2222:3333:::"); + assert.ipv6test(!1,"1111:2222:::"); + assert.ipv6test(!1,"1111:::"); + assert.ipv6test(!1,":::"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555:6666::8888:"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555::8888:"); + assert.ipv6test(!1,"1111:2222:3333:4444::8888:"); + assert.ipv6test(!1,"1111:2222:3333::8888:"); + assert.ipv6test(!1,"1111:2222::8888:"); + assert.ipv6test(!1,"1111::8888:"); + assert.ipv6test(!1,"::8888:"); + assert.ipv6test(!1,"1111:2222:3333:4444:5555::7777:8888:"); + assert.ipv6test(!1,"1111:2222:3333:4444::7777:8888:"); + assert.ipv6test(!1,"1111:2222:3333::7777:8888:"); + assert.ipv6test(!1,"1111:2222::7777:8888:"); + assert.ipv6test(!1,"1111::7777:8888:"); + assert.ipv6test(!1,"::7777:8888:"); + assert.ipv6test(!1,"1111:2222:3333:4444::6666:7777:8888:"); + assert.ipv6test(!1,"1111:2222:3333::6666:7777:8888:"); + assert.ipv6test(!1,"1111:2222::6666:7777:8888:"); + assert.ipv6test(!1,"1111::6666:7777:8888:"); + assert.ipv6test(!1,"::6666:7777:8888:"); + assert.ipv6test(!1,"1111:2222:3333::5555:6666:7777:8888:"); + assert.ipv6test(!1,"1111:2222::5555:6666:7777:8888:"); + assert.ipv6test(!1,"1111::5555:6666:7777:8888:"); + assert.ipv6test(!1,"::5555:6666:7777:8888:"); + assert.ipv6test(!1,"1111:2222::4444:5555:6666:7777:8888:"); + assert.ipv6test(!1,"1111::4444:5555:6666:7777:8888:"); + assert.ipv6test(!1,"::4444:5555:6666:7777:8888:"); + assert.ipv6test(!1,"1111::3333:4444:5555:6666:7777:8888:"); + assert.ipv6test(!1,"::3333:4444:5555:6666:7777:8888:"); + assert.ipv6test(!1,"::2222:3333:4444:5555:6666:7777:8888:"); + + // additional cases: http:// crisp.tweakblogs.net/blog/2031/ipv6-validation-%28and-caveats%29.html + assert.ipv6test(1,"0:a:b:c:d:e:f::", "0000:000a:000b:000c:000d:000e:000f:0000"); + assert.ipv6test(1,"::0:a:b:c:d:e:f", "0000:0000:000a:000b:000c:000d:000e:000f"); // syntactically correct, but bad form (::0:... could be combined) + assert.ipv6test(1,"a:b:c:d:e:f:0::", "000a:000b:000c:000d:000e:000f:0000:0000"); + assert.ipv6test(!1,"':10.0.0.1"); + }); +}; diff --git a/testing/testing-widgets.js b/testing/testing-widgets.js new file mode 100644 index 0000000..1f51dcf --- /dev/null +++ b/testing/testing-widgets.js @@ -0,0 +1,283 @@ +/*! +* TableSorter QUnit Testing +*/ +/*jshint unused: false */ +/*global start: false, asyncTest: false, equal: false, $: false, expect: false, module: false, + tester: false, test: false, stop: false */ + +/* +Filter widget tested parts +======================== +OPTIONS: + filter_defaultAttrib, filter_ignoreCase, filter_startsWith, + filter_selectSource, filter_functions (set, not functionality) + +CLASSES: + filter-false, filter-match, filter-parsed + +METHODS: + filterReset, search (false), setFilters + +EVENTS: + filterInit, filterEnd + +Not yet tested +========================= +OPTIONS: + filter_childRows, filter_columnFilters, filter_cssFilter, filter_external, + filter_filteredRow, filter_formatter, filter_hideEmpty, + filter_hideEmpty, filter_liveSearch, filter_onlyAvail, filter_placeholder, + filter_reset, filter_saveFilters, filter_searchDelay, + filter_serversideFiltering, filter_useParsedData + +CLASSES: + filter-select, filter-select-nosort, filter-onlyAvail + +METHODS: + search (array), getFilters, external filters + +EVENTS: + filterStart +*/ + +$(function(){ + module('Widgets', { + beforeEach: function(assert) { + this.ts = $.tablesorter; + + // filter widget table + this.$table = $('#testblock').html('' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
        RankFirst NameLast NameAgeTotalDiscountDateLast Name2
        1Philip Aaron WongJohnson Sr Esq25$5.9522%Jun 26, 2004 7:22 AMJohnson Sr Esq
        11AaronHibert12$2.995%Aug 21, 2009 12:21 PMHibert
        12Brandon ClarkHenry Jr51$42.2918%Oct 13, 2000 1:15 PMHenry Jr
        111PeterParker28$9.9920%Jul 6, 2006 8:14 AMParker
        21JohnHood33$19.9925%Dec 10, 2002 5:14 AMHood
        013ClarkKent Sr.18$15.8944%Jan 12, 2003 11:14 AMKent Sr.
        005BruceAlmighty Esq45$153.1944%Jan 18, 2021 9:12 AMAlmighty Esq
        10AlexDumass13$5.294%Jan 8, 2012 5:11 PMDumass
        16JimFranco24$14.1914%Jan 14, 2004 11:23 AMFranco
        166Bruce LeeEvans22$13.1911%Jan 18, 2007 9:12 AMEvans
        100Brenda DexterMcMasters18$55.2015%Feb 12, 2010 7:23 PMMcMasters
        55DennisBronson65$123.00Jan 20, 2001 1:12 PMBronson
        9MarthadelFuego25$22.0917%Jun 11, 2011 10:55 AMdelFuego
        ').find('table'); + this.table = this.$table[0]; + this.init = false; + + var self = this; + var initTablesort = function(){ + self.$table.tablesorter({ + ignoreCase: false, + widgets: ['zebra', 'filter'], + headers: { + '.rank' : { filter: false } + }, + widgetOptions: { + filter_functions : { + '.last2' : true, + '.rank' : { + "< 10" : function(e, n) { return n <= 10; }, + "> 10" : function(e, n) { return n > 10; } + } + }, + filter_selectSource : { + // Alphanumeric match (prefix only) + // added as select2 options (you could also use select2 data option) + '.last2' : function(table, column) { + return ['abc', 'def', 'zyx']; + } + } + } + }); + }; + + var onEventCallback = function(){ + self.init = true; + self.c = self.table.config, + self.wo = self.c.widgetOptions; + }; + + return QUnit.SequentialRunner().next( + QUnit.assertOnEvent( + self.$table, + 'filterInit', + initTablesort, + onEventCallback + ) + ).promise(); + + }, + afterEach: function(assert) { + var done = assert.async(); + this.$table.trigger('destroy', [false, done]); + } + }); + + + /************************************************ + Filter widget + ************************************************/ + + QUnit.test( 'Filter: init', function(assert) { + expect(6); + + assert.equal( this.init, true, 'Init event' ); + assert.equal( this.$table.hasClass('hasFilters'), true, '`hasFilters` class applied' ); + + assert.equal( this.ts.filter.regex.child.test( this.c.cssChildRow ), true, 'child row regex check' ); + assert.equal( this.ts.filter.regex.filtered.test( this.wo.filter_filteredRow ), true, 'filtered row regex check' ); + // this includes check of headers option & referencing column by class + assert.equal ( this.c.$table.find('.tablesorter-filter').eq(0).hasClass('disabled'), true, 'filter disabled & headers class name working' ); + + assert.cacheCompare( this.table, 3, [ 12, 18, 13, 18 ], 'starting filter value on age column', true ); + }); + + QUnit.test( 'Filter searches', function(assert) { + var ts = this.ts, + c = this.c, + wo = this.wo, + $table = this.$table, + table = this.table; + expect(27); + + return QUnit.SequentialRunner( + function(actions, assertions) { + return QUnit.assertOnEvent($table, 'filterEnd', actions, assertions); + } + ).nextTask( + function(){ ts.setFilters( table, ['', 'e'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Peter', 'Bruce', 'Alex', 'Bruce Lee', 'Brenda Dexter', 'Dennis'], 'search regular', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '~bee'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Bruce Lee', 'Brenda Dexter'], 'search fuzzy', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '~piano'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Philip Aaron Wong'], 'search fuzzy2', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', 'john='], true ); }, + function(){ assert.cacheCompare( table, 1, ['John'], 'search exact', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', 'a?s'], true ); }, + function(){ assert.cacheCompare( table, 2, ['Dumass', 'Evans'], 'search wildcard, one character (?)', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', 'a*s'], true ); }, + function(){ assert.cacheCompare( table, 2, ['Dumass', 'Evans', 'McMasters'], 'search wildcard, multiple characters (*)', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '/r$/'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Peter', 'Brenda Dexter'], 'search regex', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', '', '', '>10'], true ); }, + function(){ assert.cacheCompare( table, 4, [42.29, 19.99, 15.89, 153.19, 14.19, 13.19, 55.2, 123, 22.09], 'search operator (>10)', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', '', '', '>100'], true ); }, + function(){ assert.cacheCompare( table, 4, [153.19, 123], 'search operator (>100); ensure search filtered gets cleared', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', '', '', '', '>=20'], true ); }, + function(){ assert.cacheCompare( table, 5, [22, 20, 25, 44, 44], 'search operator (>=)', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', '', '', '', '<10'], true ); }, + function(){ assert.cacheCompare( table, 5, [5, 4], 'search operator (<10)', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', '', '', '', '<100'], true ); }, + function(){ assert.cacheCompare( table, 5, [22, 5, 18, 20, 25, 44, 44, 4, 14, 11, 15, 17], 'search operator (<100); ensure search filtered gets cleared', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', '', '', '', '<=20'], true ); }, + function(){ assert.cacheCompare( table, 5, [5, 18, 20, 4, 14, 11, 15, 17], 'search operator (<=)', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '!a'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Peter', 'John', 'Bruce', 'Jim', 'Bruce Lee', 'Dennis'], 'search not match', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '!aa'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Brandon Clark', 'Peter', 'John', 'Clark', 'Bruce', 'Alex', 'Jim', 'Bruce Lee', 'Brenda Dexter', 'Dennis', 'Martha'], 'search not match; ensure search filtered gets cleared', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', 'br && c'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Brandon Clark', 'Bruce', 'Bruce Lee'], 'search and match', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', 'br && cl'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Brandon Clark'], 'search and match; ensure search filtered gets cleared', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', 'alex|br*'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Brandon Clark', 'Bruce', 'Alex', 'Bruce Lee', 'Brenda Dexter'], 'search OR match', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', '', '', '5 - 10'], true ); }, + function(){ assert.cacheCompare( table, 4, [5.95, 9.99, 5.29], 'search range', true ); } + ).nextTask( + function(){ ts.setFilters( table, ['', '', '', '', '5 - 100'], true ); }, + function(){ assert.cacheCompare( table, 4, [5.95, 42.29, 9.99, 19.99, 15.89, 5.29, 14.19, 13.19, 55.2, 22.09], 'search range; ensure search filtered gets cleared', true ); } + ).nextTask( // test filter_startsWith (false by default) + function(){ + wo.filter_startsWith = false; + ts.setFilters( table, ['', 'aa'], true ); + }, + function(){ assert.cacheCompare( table, 1, ['Philip Aaron Wong', 'Aaron'], 'search - filter_startsWith : false', true ); } + ).nextTask( // test filter_startsWith (false by default) + function(){ + wo.filter_startsWith = true; + c.$table.trigger('search', false); + }, + function(){ + assert.cacheCompare( table, 1, ['Aaron'], 'search - filter_startsWith : true', true ); + wo.filter_startsWith = false; + } + ).nextTask( // test filter_ignoreCase (true by default) + function(){ + wo.filter_ignoreCase = false; + c.$table.trigger('search', false); + }, + function(){ + assert.cacheCompare( table, 1, [], 'search - filter_ignoreCase : false', true ); + wo.filter_ignoreCase = true; + } + ).nextTask( // test filter-match class (added in the example code) + function(){ ts.setFilters( table, ['', 'alex|br*|c'], true ); }, + function(){ assert.cacheCompare( table, 1, ['Brandon Clark', 'Clark', 'Bruce', 'Alex', 'Bruce Lee', 'Brenda Dexter'], 'search - filter-match', true ); } + ).nextTask( // test filter-match class + function(){ + c.$table.find('.tablesorter-header').eq(1).removeClass('filter-match'); + c.$table.trigger('search', false); + }, + function(){ assert.cacheCompare( table, 1, ['Bruce', 'Alex'], 'search - filter-match removed', true ); } + ).nextTask( // filter reset + function(){ c.$table.trigger('filterReset'); }, + function(){ assert.cacheCompare( table, 5, [22, 5, 18, 20, 25, 44, 44, 4, 14, 11, 15, '', 17], 'filterReset', true ); } + ).nextTask( // filter parsed class + function(){ + wo.filter_startsWith = false; + ts.setFilters( table, ['', '', '', '', '', '', '< 1/1/2001'], true ); + }, + function(){ assert.cacheCompare( table, 6, [ new Date('Oct 13, 2000 1:15 PM').getTime() ], 'search - filter-parsed', true ); } + ).promise(); + }); + + QUnit.test( 'Filter: function & selectSource', function(assert) { + expect(3); + + var $t, opts = []; + $t = this.c.$table.find('.tablesorter-filter-row select:last'); + assert.equal ( $t.length !== 0, true, 'filter_functions: true working' ); + + this.c.$table.find('.tablesorter-filter-row select:first option').each(function(){ + opts.push( $.trim( $(this).text() ) ); + }); + assert.equal ( opts.length === 3 && opts.join('') === '< 10> 10', true, 'filter_functions set' ); + + opts = []; + $t.find('option').each(function(){ + opts.push( $.trim( $(this).text() ) ); + }); + assert.equal ( opts.length === 4 && opts.join('') === 'abcdefzyx', true, 'filter_selectSource set' ); + + }); + + +}); diff --git a/testing/testing.css b/testing/testing.css new file mode 100644 index 0000000..6e5bb1c --- /dev/null +++ b/testing/testing.css @@ -0,0 +1,10 @@ +/* tables */ +.tester { /* */ + position: absolute; + top: -999em; +} + +/* skipped tests */ +#qunit-tests li.pass.skipped { + background-color: #fffacd; +} diff --git a/testing/testing.js b/testing/testing.js new file mode 100644 index 0000000..81b6a6f --- /dev/null +++ b/testing/testing.js @@ -0,0 +1,777 @@ +/*! +* TableSorter QUnit Testing +*/ +/*jshint unused: false */ +/*global QUnit: false, JSHINT: false, ok: false, start: false, deepEqual: false, asyncTest: false, + strictEqual: false, jQuery: false, equal: false, $: false, expect: false, module: false, + test: false, stop: false, ipv6tests: false */ + +// Accepts a function with a single argument -- deferred object, which should be resolved at some point in a function. +// Returns a promise, wrapping this function call. +QUnit.deferredCallback = function(func) { + return function(){ + var defer = $.Deferred(); + func(defer); + return defer.promise(); + }; +}; + +// SequentialRunner is an object to build and run a list of asynchronous calls in a sequential way. +// It wraps a deferred object; initially it's resolved, but .next and .nextTask calls add runners to be invoked. +// Underlying promise can be obtained by .promise() call. +// Each runner should accept deferred object and resolve it at some point when it's safe to invoke the next runner. +// +// Its constructor has an optional argument runnerCreator -- function which accepts task arguments +// and returns a runner (i.e. another function). If runnerCreator supplied, SequentialRunner object gets +// an additional method #nextTask(...) that is useful when you run lots of similar tasks. +// +// Example: +// +// QUnit.SequentialRunner(function(buttonSelector){ +// return function(defer){ // each task is to wait until specified button is clicked +// $(buttonSelector).click(function(){ +// defer.resolve() +// }) +// }; +// }) +// .nextTask('#login').nextTask('#demo').nextTask('button') +// .promise() +// .then(function(){ console.log('Login, demo and any other button were clicked in that order.') }); +// +QUnit.SequentialRunner = function(runnerCreator){ + var result = { + defer: $.Deferred().resolve(), + promise: function(){ + return this.defer.promise(); + }, + next: function(runner) { + this.defer = this.defer.then( QUnit.deferredCallback(runner) ); + return this; + }, + }; + if (runnerCreator) { + result.nextTask = function(args) { // any argument list + var deferredRunner = QUnit.deferredCallback( runnerCreator.apply(this, arguments) ); + this.defer = this.defer.then(deferredRunner); + return this; + }; + } + return result; +}; + +// Returns an runner which runs some actions and wait for an event to be triggered. +// When an event is triggered assertions block is called and defer is resolved (independent on assertion result). +// This runner is useful when you want to check some conditions which should be met after an event was triggered. +// +// Example: +// QUnit.test('tablesorter initialization', function(assert){ +// return QUnit.SequentialRunner() +// .next( +// QUnit.assertOnEvent( +// $('table'), +// 'tablesorter-initialized', +// function() { +// $('table').tablesorter( {sortList: [[0,0]]} ); +// }, +// function() { +// QUnit.assert.deepEqual($('table')[0].config.sortList, [[0,0]], 'sortList should be present in config'); +// } +// ) +// ).promise(); +// }); +// +QUnit.assertOnEvent = function($element, eventType, actions, assertions) { + return function(defer){ + $element + .off(eventType) + .on(eventType, function() { + $element.off(eventType); + assertions(); + defer && defer.resolve(); + }); + actions(); + }; +}; + +QUnit.extend(QUnit.assert, { + /************************************************ + test table data cache + ************************************************/ + cacheCompare : function(table, col, expected, txt, filtered){ + var flat = [], + result = $.tablesorter.getColumnText( table, col, function( data ){ + return !( filtered && data.$row.hasClass( table.config.widgetOptions.filter_filteredRow ) ); + }); + // flatten array + flat = flat.concat.apply( flat, result.parsed ); + QUnit.assert.deepEqual( flat, expected, 'testing parser cache: ' + txt); + } +}); + +/* +Core plugin tested +======================== +OPTIONS: + cssAsc, cssChildRow, cssDesc, cssHeader, cssHeaderRow, cssInfoBlock, dateFormat, emptyTo, headerList, + headers, ignoreCase, initialized, parsers, sortList, sortLocaleCompare, sortReset, stringTo, tableClass, + usNumberFormat, widgets (just zebra), sortAppend, sortForce, sortMultiSortKey, sortResetKey, numberSorter + +METHODS: + addRows, applyWidgets, destroy, sorton, sortReset, update/updateRow, updateAll, updateCell + +EVENTS: + initialized, sortBegin, sortEnd, sortStart, updateComplete + +Not yet tested +========================= +OPTIONS: + cancelSelection, cssIcon, cssProcessing, debug, delayInit, headerTemplate, initWidgets, onRenderHeader, + onRenderTemplate, selectorHeaders, selectorRemove, selectorSort, serverSideSorting, showProcessing, + sortInitialOrder, sortRestart, strings, + textExtraction, textSorter, theme, widthFixed, widgets (also need priority testing) + +METHODS: + appendCache, applyWidgetId, sort, refreshWidgets + +EVENTS: + - +*/ + +$(function(){ + + var ts = $.tablesorter, + $table1 = $('#table1'), + $table2 = $('#table2'), + $table3 = $('#table3'), + $table4 = $('#table4'), + $table5 = $('#table5'), // empty table + table1 = $table1[0], + table2 = $table2[0], + table3 = $table3[0], + table4 = $table4[0], + table5 = $table5[0], + th0 = $table1.find('th')[0], // first table header cell + init = false, + sortIndx = 0, + updateIndx = 0, + updateCallback = 0, + events = ['sortStart', 'sortBegin', 'sortEnd', ' '], + returnTime = function(string){ + return new Date(string).getTime(); + }, + undef, c1, c2, c3, c4, e, i, t; + + $table1 + .bind('tablesorter-initialized', function(){ + init = true; + }) + .tablesorter(); + + $table2.tablesorter({ + headers: { + 0: { sorter: 'text' }, + 1: { sorter: 'text' }, + 2: { sorter: false } + } + }); + + $table3.tablesorter({ + emptyTo: "bottom", + stringTo: "max", // non-numeric content is treated as a MAX value + headers: { + 0: { empty : "top" }, // sort empty cells to the top + 2: { string: "min" }, // non-numeric content is treated as a MIN value + 3: { sorter: "digit", empty : "zero", string : "top" } + } + }); + + $table4.tablesorter({ + sortAppend : [[2,0],[3,0]], + sortForce : [[0,0],[1,0]], + textExtraction : { + '.te-test' : function(node){ + return $(node).find('span').text(); + }, + 2 : function(node){ + return $(node).find('span').text(); + } + }, + initialized: function(table){ + var e, c = table.config; + // trigger sort on 5th column + // this method is used because triggering a "sorton" would ignore sortForce/sortAppend + c.$headers.eq(4).trigger('sort'); + e = $.Event('sort'); + e.which = 1; + e.shiftKey = true; + c.$headers.eq(5).trigger(e); + }, + numberSorter: function(a, b, dir){ + return dir ? a-b : b-a; + } + }); + + $table5.tablesorter(); + + module('core'); + /************************************************ + Initialization + ************************************************/ + QUnit.test( "tablesorter loaded & initialized", function(assert) { + assert.expect(3); + assert.equal( typeof ts, 'object', "tablesorter loaded"); + assert.equal( table1.hasInitialized, true, "tablesorter initialized flag"); + assert.equal( init, true, "tablesorter initialized event"); + }); + + c1 = table1.config; + c2 = table2.config; + c3 = table3.config; + c4 = table4.config; + + /************************************************ + Test column numbering + ************************************************/ + // later: include a table header with colspan & rowspan + QUnit.test( "column numbering", function(assert) { + assert.expect(2); + var internalColumn = true, + dataColumn = true; + $table4.find('thead th').each(function(i){ + internalColumn = internalColumn && this.column === i; + dataColumn = dataColumn && $(this).attr('data-column') == i; + }); + assert.equal( internalColumn, true, "Correct internal column numbering" ); + assert.equal( dataColumn, true, "Correct data-column attribute numbering" ); + }); + + /************************************************ + check isDigit function + ************************************************/ + var d = ts.isDigit; + QUnit.test( "isDigit", function(assert) { + assert.expect(18); + ok( d('-1'), "allow negative (-1)"); + ok( d('+1'), "allow plus (+1)"); + ok( d('(1)'), "allow parenthesis (1)"); + ok( d('123'), "string has numbers ('123')"); + ok( d(123), "has numbers (123)"); + ok( d('1.2'), "remove decimal (1.2)"); + ok( d('1,234'),"remove commas (1,234)"); + ok( d("11'"), "remove apostrophe's (11')"); // 11 feet + ok( d('3\'4"'),"remove quotes (3'4\")"); // 3 foot 4 inches + ok( d(' 12 '), "remove spaces ( 12 )"); + ok( !d('x'), "non-digit alphabet"); + ok( !d('1x'), "digit + alphabet"); + ok( !d('x1'), "alphabet + digit"); + ok( !d('@'), "non-digit symbols"); + ok( !d('1-'), "negative after (1-) not allowed?"); + ok( !d('1+'), "plus after (1+) not allowed?"); + ok( !d('$2'), "no money; the currency parser will catch these"); + ok( !d(''), "empty string ('')"); + }); + + /************************************************ + check formatFloat function + ************************************************/ + var ff = function(str) { + return ts.formatFloat(str, table1); + }; + QUnit.test( "formatFloat", function(assert) { + assert.expect(18); + assert.strictEqual( ff(''), '', 'returns empty string' ); + assert.strictEqual( ff(5), 5, 'returns numerical values'); + + c1.usNumberFormat = false; + assert.strictEqual( ts.formatFloat('1,234,567.89'), 1234567.89, 'use format float without including table - defaults to US number format'); + + assert.strictEqual( ff('1 234,56'), 1234.56, 'parse non-U.S. (French) number format'); + assert.strictEqual( ff('1.234,56'), 1234.56, 'parse non-U.S. (German) number format'); + assert.strictEqual( ff('-32,32'), -32.32, 'negative non-U.S. signed numbers'); + assert.strictEqual( ff('-1.234,56'), -1234.56, 'negative non-U.S. signed numbers'); + assert.strictEqual( ff('(32,32)'), -32.32, 'parenthesis wrapped non-U.S. negative number'); + assert.strictEqual( ff(' (32,32) '), -32.32, 'space + parenthesis wrapped non-U.S. negative number'); + + c1.usNumberFormat = true; + assert.strictEqual( ff('1,234.56'), 1234.56, 'parse U.S. number format'); + assert.strictEqual( ff('-32.32'), -32.32, 'negative U.S. signed numbers'); + assert.strictEqual( ff('(32.32)'), -32.32, 'parenthesis wrapped U.S. negative number'); + assert.strictEqual( ff(' (32.32)'), -32.32, 'space + parenthesis wrapped U.S. negative number'); + + assert.strictEqual( ff('fred'), 'fred', 'return string if not a number'); + assert.strictEqual( ff(' fred '), 'fred', 'return trimmed string if not a number'); + assert.strictEqual( ff('fred 12'), 'fred 12', 'return string if number not at beginning'); + assert.strictEqual( ff('12fred'), 12, 'parse number + string into number only'); + assert.strictEqual( ff('(fred)'), '(fred)', 'leave parenthesis intact on strings'); + + }); + + /************************************************ + get data function - jQuery data > meta > headers option > header class name + ************************************************/ + var gd = function(n){ + return ts.getData( c2.$headers[n], c2.headers[n], 'sorter' ); + }; + + QUnit.test( "getData", function(assert) { + assert.expect(4); + var txt = [ 'jQuery data', 'meta data', 'headers option', 'header class name' ]; + for (i = 0; i < 4; i++) { + assert.equal( gd(i), 'false', txt[i]); // all columns have sorter false set + } + }); + + /************************************************ + character equivalent replacement + ************************************************/ + QUnit.test( "replace accents", function(assert) { + assert.expect(6); + assert.strictEqual( ts.replaceAccents('\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5'), 'aaaaaaaAAAAAAA', "replaced a's"); + assert.strictEqual( ts.replaceAccents('\u00e9\u00e8\u00ea\u00eb\u011b\u0119\u00c9\u00c8\u00ca\u00cb\u011a\u0118'), 'eeeeeeEEEEEE', "replaced e's"); + assert.strictEqual( ts.replaceAccents('\u00ed\u00ec\u0130\u00ee\u00ef\u0131\u00cd\u00cc\u0130\u00ce\u00cf'), 'iiiiiiIIiII', "replaced i's"); + assert.strictEqual( ts.replaceAccents('\u00f3\u00f2\u00f4\u00f5\u00f6\u00d3\u00d2\u00d4\u00d5\u00d6'), 'oooooOOOOO', "replaced o's"); + assert.strictEqual( ts.replaceAccents('\u00fa\u00f9\u00fb\u00fc\u016f\u00da\u00d9\u00db\u00dc\u016e'), 'uuuuuUUUUU', "replaced u's"); + assert.strictEqual( ts.replaceAccents('\u00e7\u0107\u010d\u00c7\u0106\u010c\u00df\u1e9e'), 'cccCCCssSS', "replaced c & s sharp"); + }); + + /************************************************ + detect parsers + ************************************************/ + QUnit.test( "detect parsers", function(assert) { + var done = assert.async(); + assert.expect(2); + $('#testblock2').html('' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
        InfoDetails
        First NameLast NameAgeTotalDiscountDate
        PeterParker28$9.9920%Jul 6, 2006 8:14 AM
        JohnHood33$19.9925%Dec 10, 2002 5:14 AM
        ClarkKent18$15.8944%Jan 12, 2003 11:14 AM
        BruceAlmighty45$153.1944%Jan 18, 2001 9:12 AM
        BruceEvans22$13.1911%Jan 18, 2007 9:12 AM
        ') + .find('table') + .tablesorter({ + headers : { + 0 : { sorter: false }, + 1 : { sorter: false }, + 3 : { sorter: 'digit' } // 3 sets the 4th column, not the 3rd header cell now + }, + initialized: function(table){ + var i, + result = true, + parsers = [ 'text', 'digit', 'digit', 'currency', 'percent', 'usLongDate' ], + c = table.config; + for (i = 0; i < c.columns; i++){ + result = result && c.parsers[i].id === parsers[i]; + } + assert.equal( result, true, 'detect parsers by header index' ); + // table inception! + $(table) + .trigger('destroy') + .tablesorter({ + headers : { + '.col-first' : { sorter: 'url' }, + '.col-off' : { sorter: false }, + '.col-total' : { sorter : 'percent' }, + '#age, .col-last' : { sorter: 'currency' }, + '.col-date' : { sorter : 'time' }, + '.col-discount' : { sorter: 'digit' } + }, + initialized: function(table){ + var i, + result = true, + parsers = [ 'url', 'currency', 'currency', 'percent', 'digit', 'time' ], + c = table.config; + for (i = 0; i < c.columns; i++){ + result = result && c.parsers[i].id === parsers[i]; + } + assert.equal( result, true, 'detect parsers by class/id' ); + done(); + } + }); + } + }); + + }); + + /************************************************ + check all default parsers + ************************************************/ + var p = ts.parsers, + // test by parser + parserTests = 85, + // skipping metadata parser + sample1 = { + 'text' : { 'test': 'test', 'TesT': 'test', '\u00e1 test': '\u00e1 test' }, + 'currency' : { '\u00a31': 1, '($2.23)': -2.23, '5\u20ac': 5, '(11\u00a4)': -11, '500\u00a5': 500, '25\u00a2': 25, '$1,000.50': 1000.5 }, + 'ipAddress' : { '255.255.255.255': 255255255255, '32.32.32.32': 32032032032, '1.1.1.1': 1001001001 }, + 'url' : { 'http://google.com': 'google.com', 'ftp://fred.com': 'fred.com', 'https://github.com': 'github.com' }, + 'isoDate' : { '2012/12/12': returnTime('2012/12/12'), '2012-12/12': returnTime('2012/12/12'), '2013-1-1': returnTime('2013/1/1'), '2013/1/1 12:34:56 AM': returnTime('2013/1/1 12:34:56 AM') }, + 'percent' : { '100%': 100, '22%': 22, '%2': 2, '2 %': 2, '(4%)': -4, '1,234.56 %': 1234.56 }, + 'usLongDate': { 'Feb 23, 1999': returnTime('Feb 23, 1999'), 'Feb 23, 1999 12:34': returnTime('Feb 23, 1999 12:34'), 'Feb 23, 1999 12:34 AM': returnTime('Feb 23, 1999 12:34 AM'), 'Feb 23, 1999 12:34:56 PM': returnTime('Feb 23, 1999 12:34:56 PM'), '01 Jan 2013': returnTime('01 Jan 2013') }, + 'shortDate' : { '1/2/2001': returnTime('1/2/2001'), '1 2 2001': returnTime('1/2/2001'), '1.2.2001': returnTime('1/2/2001'), '1-2-2001': returnTime('1/2/2001'), '1/2/2001 12:34 PM' : returnTime('1/2/2001 12:34 PM'), '1.2.2001 13:34' : returnTime('1/2/2001 13:34') }, + 'time' : { '12:34 AM': returnTime('2000/01/01 12:34 AM'), '1:00 pm': returnTime('2000/01/01 1:00 pm') }, + 'digit' : { '12': 12, '$23': 23, '&44^': 44, '#(33)': -33, '1,000': 1000, '12.34': 12.34 } + }, + // switch ignoreCase, sortLocalCompare & shortDate "ddmmyyyy" + sample2 = { + 'text' : { 'TesT': 'TesT', '\u00e1 test': 'a test' }, + 'currency' : { '\u20ac 123 456,78': 123456.78, '\u20ac 123.456,78': 123456.78 }, + 'shortDate' : { '2/1/2001': returnTime('1/2/2001'), '2-1-2001': returnTime('1/2/2001'), '2 1,2001': returnTime('1/2/2001') } + }, + // shortdate to "yyyymmdd" + sample3 = { + 'shortDate' : { '2001/1/2': returnTime('1/2/2001'), '2001-1/2': returnTime('1/2/2001'), '2001,1.2': returnTime('1/2/2001') } + }, + report = function(assert, s) { + for (i = 0; i < p.length; i++) { + t = p[i].id; + if (s.hasOwnProperty(t)) { + /*jshint loopfunc:true */ + $.each(s[t], function(k,v){ + // check "is" and "format" functions + if (p[i].is(k)) { + assert.equal( p[i].format(k, table1, th0, 0), v, t + ' parser: "' + k + '" parsed to ' + v ); + } else { + assert.equal( p[i].format(k, table1, th0, 0), v, t + ' parser **NOT DETECTED**: "' + k + '", but returns ' + v ); + } + }); + // test for undefined & null - probably overkill + assert.strictEqual( p[i].format(undef, table1, th0, 0), undef, t + ' parser: will return undefined values properly' ); + assert.strictEqual( p[i].format(null, table1, th0, 0), null, t + ' parser: will return null values properly' ); + } + } + }; + + QUnit.test( "testing parsers", function(assert) { + assert.expect(parserTests); + report(assert, sample1); + + c1.sortLocaleCompare = true; + c1.ignoreCase = false; + c1.usNumberFormat = false; + th0.dateFormat = c1.dateFormat = "ddmmyyyy"; + report(assert, sample2); + + c1.usNumberFormat = true; + th0.dateFormat = c1.dateFormat = "yyyymmdd"; + report(assert, sample3); + + // undocumented sortValue + assert.equal( ts.getParserById('metadata').format(null, table1, th0, 0), 'zzz', 'metadata parser found sortValue'); + c1.parserMetadataName = 'poe'; + assert.equal( ts.getParserById('metadata').format(null, table1, th0, 0), 'nevermore', 'metadata parser found poe'); + }); + + QUnit.test( "textExtraction Method", function(assert) { + assert.expect(4); + + $table1.trigger('sorton', [[[ 0,0 ]]]); + assert.cacheCompare( table1, 0, [ 'test1', 'test2', 'test3', + 'testa', 'testb', 'testc' ], 'from data-attribute' ); + + $table3.trigger('sorton', [[[ 0,1 ]]]); + assert.cacheCompare( table3, 0, [ '', 'a255', 'a102', 'a87', 'a55', 'a43', 'a33', 'a10', 'a02', 'a1' ], 'ignore data-attribute' ); + + assert.cacheCompare( table4, 1, [ 'f11', 'f11', 'f12', 'f12', 'f12', 'f12', 'f12', 'f13', 'f13', 'f13' ], 'extract using class name' ); + + assert.cacheCompare( table4, 2, [ 'a21', 'a21', 'a23', 'a23', 'a23', 'a22', 'a22', 'a23', 'a24', 'a24' ], 'extract using column index' ); + + }); + + /************************************************ + test parser cache + ************************************************/ + QUnit.test( "parser cache; sorton methods; empty & string", function(assert) { + assert.expect(18); + $table1.trigger('sortReset'); + + // lower case because table was parsed before c1.ignoreCase was changed + assert.cacheCompare( table1, 'all', [ 'test2', 'x2', 'test1', 'x3', 'test3', 'x1', + 'testb', 'x5', 'testc', 'x4', 'testa', 'x6' ], 'unsorted' ); + + $table1.trigger('sorton', [[[ 0,0 ]]]); + assert.cacheCompare( table1, 'all', [ 'test1', 'x3', 'test2', 'x2', 'test3', 'x1', + 'testa', 'x6', 'testb', 'x5', 'testc', 'x4' ], 'ascending sort' ); + + $table1.trigger('sorton', [[[ 0,1 ]]]); + assert.cacheCompare( table1, 'all', [ 'test3', 'x1', 'test2', 'x2', 'test1', 'x3', + 'testc', 'x4', 'testb', 'x5', 'testa', 'x6' ], 'descending sort' ); + + // empty cell position + $table3.trigger('sorton', [[[ 0,0 ]]]); + assert.cacheCompare( table3, 0, [ '', 'a1', 'a02', 'a10', 'a33', 'a43', 'a55', 'a87', 'a102', 'a255' ], 'asc sort; empty to top' ); + + $table3.trigger('sorton', [[[ 0,1 ]]]); + assert.cacheCompare( table3, 0, [ '', 'a255', 'a102', 'a87', 'a55', 'a43', 'a33', 'a10', 'a02', 'a1' ], 'desc sort; empty to top' ); + + // string position within number column + $table3.trigger('sorton', [[[ 1,0 ]]]); + assert.cacheCompare( table3, 1, [ -35, -5, -1, 1, 2, 4, 33, 44, 'nr', '' ], 'asc sort; empty to bottom; string to max' ); + + $table3.trigger('sorton', [[[ 1,1 ]]]); + assert.cacheCompare( table3, 1, [ 'nr', 44, 33, 4, 2, 1, -1, -5, -35, '' ], 'desc sort; empty to bottom; string to max' ); + + $table3.trigger('sorton', [[[ 2,0 ]]]); + assert.cacheCompare( table3, 2, [ 'nr', 'nr', 1, 2, 3, 4, 5, 6, 7, '' ], 'asc sort; empty to bottom; string to min' ); + + $table3.trigger('sorton', [[[ 2,1 ]]]); + assert.cacheCompare( table3, 2, [ 7, 6, 5, 4, 3, 2, 1, 'nr', 'nr', '' ], 'desc sort; empty to bottom; string to min' ); + + $table3.trigger('sorton', [[[ 3,0 ]]]); + assert.cacheCompare( table3, 3, [ 'n/a #2', 'n/a #1', -8.4, -2.2, -0.1, '', 5.2, 11.4, 23.6, 97.4 ], 'asc sort; empty to zero; string to top' ); + + $table3.trigger('sorton', [[[ 3,1 ]]]); + assert.cacheCompare( table3, 3, [ 'n/a #2', 'n/a #1', 97.4, 23.6, 11.4, 5.2, '', -0.1, -2.2, -8.4 ], 'desc sort; empty to zero; string to top' ); + + $table3.find('th:eq(3)').data('string', 'bottom'); + $table3.trigger('update'); + assert.cacheCompare( table3, 3, [ 97.4, 23.6, 11.4, 5.2, '', -0.1, -2.2, -8.4, 'n/a #1', 'n/a #2' ], 'desc sort; empty to zero; string to bottom' ); + + $table3.trigger('sorton', [[[ 3,0 ]]]); + assert.cacheCompare( table3, 3, [ -8.4, -2.2, -0.1, '', 5.2, 11.4, 23.6, 97.4, 'n/a #1', 'n/a #2' ], 'asc sort; empty to zero; string to bottom' ); + + $table3.find('th:eq(3)').data('string', 'none'); + c3.headers[3].empty = "bottom"; + c3.sortList = [[ 3, 1 ]]; // added to test sortList + $table3.trigger('update'); + assert.cacheCompare( table3, 3, [ 97.4, 23.6, 11.4, 5.2, 'n/a #1', 'n/a #2', -0.1, -2.2, -8.4, '' ], 'desc sort; empty to zero; string to none/zero' ); + + $table3.trigger('sorton', [[[ 3,0 ]]]); + assert.cacheCompare( table3, 3, [ -8.4, -2.2, -0.1, 'n/a #1', 'n/a #2', 5.2, 11.4, 23.6, 97.4, '' ], 'asc sort; empty to zero; string to none/zero' ); + + t = [ 'x', 'X', 'y', 'Y', 'z', 'Z', 'a', 'A', 'b', 'B', 'c', 'C' ]; + assert.deepEqual( t.sort($.tablesorter.sortText), [ 'A', 'B', 'C', 'X', 'Y', 'Z', 'a', 'b', 'c', 'x', 'y', 'z' ], 'test sortText function directly' ); + + t = [ 'a02', 'a10', 'a43', 'a255', 'a102', 'a33', '', 'a1', 'a55', 'a87' ]; + assert.deepEqual( t.sort($.tablesorter.sortNatural), [ '', 'a1', 'a02', 'a10', 'a33', 'a43', 'a55', 'a87', 'a102', 'a255' ], 'test sortNatural function directly' ); + + assert.cacheCompare( table4, 6, [ '', '', '', '', '', '', '', '', '', '' ], 'parser-false does not extract text' ); + + }); + + QUnit.test( "sorton methods", function(assert) { + assert.expect(6); + + $table3.trigger('sorton', [[[ 0,'d' ]]]); + assert.equal( c3.sortList + '', '0,1', 'sorton desc [0,"d"]' ); + + $table3.trigger('sorton', [[[ 0,'a' ]]]); + assert.equal( c3.sortList + '', '0,0', 'sorton asc [0,"a"]' ); + + $table3.trigger('sorton', [[[ 0,'n' ]]]); + assert.equal( c3.sortList + '', '0,1', 'sorton next [0,"n"]' ); + $table3.trigger('sorton', [[[ 0,'n' ]]]); + assert.equal( c3.sortList + '', '0,0', 'sorton next [0,"n"]' ); + + $table3.trigger('sorton', [[ [ 0,'n'], [1,'o'], [2,'s'] ]]); + assert.equal( c3.sortList + '', '0,1,1,0,2,1', 'sorton next/opposite/same [0,"n"],[1,"o"],[2,"s"]' ); + + $table3.trigger('sorton', [[ [ 0,'n'], [1,'o'], [2,'s'] ]]); + assert.equal( c3.sortList + '', '0,0,1,1,2,0', 'sorton next/opposite/same [0,"n"],[1,"o"],[2,"s"]' ); + + }); + + QUnit.test( "sort Events", function(assert) { + assert.expect(1); + + $table1.add($table5).bind( events.join('.testing '), function(e){ + if (e.type === events[sortIndx%3]) { + sortIndx++; + } + }); + + $table1.trigger('sorton', [[[ 0,0 ]]]); + $table1.trigger('sorton', [[[ 1,0 ]]]); + + // ensure all sort events fire on an empty table + $table5.trigger('sorton', [ [[0,0]] ]); + + $table1.add($table5).unbind( events.join('.testing ') ); + + // table1 sorted twice in the above test; sortIndx = 9 then empty table5 x1 (total = 3 events x 3) + assert.equal( sortIndx, 9, 'sortStart, sortBegin & sortEnd fired in order x2; including empty table' ); + }); + + /************************************************ + test update methods + ************************************************/ + QUnit.test( "parser cache; update methods & callbacks", function(assert) { + assert.expect(10); + var oldColMax; + c1.ignoreCase = true; + // updateAll + $table1 + .trigger('sorton', [ [[0,1]] ]) + .bind('updateComplete.testing', function(){ updateIndx++; }) + .find('th:eq(1)').removeAttr('class').html('num').end() + .find('td:nth-child(2)').html(function(i,h){ + return h.substring(1); + }); + $table1 + .trigger('updateAll', [false, function(){ + updateCallback++; + var nw = $table1.find('th:eq(1)')[0], + hc = c1.headerContent[1] === 'num', + hd = c1.$headers[1] === nw, + hl = c1.headerList[1] === nw, + p1 = c1.parsers[1].id === 'digit'; + assert.equal(hc && hd && hl && p1, true, 'testing header cache: updateAll - thead'); + assert.cacheCompare( table1, 'all', [ 'test3', 1, 'test2', 2, 'test1', 3, + 'testc', 4, 'testb', 5, 'testa', 6 ], 'updateAll - tbody' ); + }]); + + // addRows + t = $('testd7'); + $table1.find('tbody:last').prepend(t); + oldColMax = c1.cache[1].colMax[1]; + $table1.trigger('addRows', [t, true, function(){ + updateCallback++; + assert.equal( oldColMax === 6 && c1.cache[1].colMax[1] === 7, true, 'addRows includes updating colMax value'); + assert.cacheCompare( table1, 'all', [ 'test3', 1, 'test2', 2, 'test1', 3, + 'testd', 7, 'testc', 4, 'testb', 5, 'testa', 6 ], 'addRows method' ); + }]); + + // updateCell + t = $table1.find('td:contains("7")'); + t.html('-8'); + oldColMax = c1.cache[1].colMax[1]; + $table1.trigger('updateCell', [t[0], true, function(){ + updateCallback++; + assert.equal( oldColMax === 7 && c1.cache[1].colMax[1] === 8, true, 'updateCell includes updating colMax value'); + assert.cacheCompare( table1, 'all', [ 'test3', 1, 'test2', 2, 'test1', 3, + 'testd', -8, 'testc', 4, 'testb', 5, 'testa', 6 ], 'updateCell method' ); + }]); + + // update + $table1.find('tr.temp').remove(); + oldColMax = c1.cache[1].colMax[1]; + $table1.trigger('update', [true, function(){ + updateCallback++; + assert.equal( oldColMax === 8 && c1.cache[1].colMax[1] === 6, true, 'update includes updating colMax value'); + assert.cacheCompare( table1, 'all', [ 'test3', 1, 'test2', 2, 'test1', 3, + 'testc', 4, 'testb', 5, 'testa', 6 ], 'update method' ); + }]); + + $table5 + .bind('updateComplete.testing', function(){ updateIndx++; }) + .trigger('update', [true, function(){ + updateCallback++; + assert.cacheCompare( table5, 'all', [], 'update method on empty table' ); + }]); + + $table1.add($table5).unbind('updateComplete.testing'); + + // table1 updated 4x in the above test + // table5 updated 1x + assert.equal( updateIndx, updateCallback, 'updatedComplete and update callback functions working properly' ); + + }); + + /************************************************ + test sortForce, sortAppend, sortMultiSortKey and sortResetKey options + ************************************************/ + QUnit.test( "sortForce, sortAppend, sortMultiSortKey & sortResetKey; and numberSorter option", function(assert){ + assert.expect(3); + + assert.cacheCompare( table4, 3, [ 2, 1, 7, 6, 5, 3, 4, 8, 9, 10 ], 'force x2 + sorted x2 + append x2, ascending' ); + + return QUnit.SequentialRunner( + function(actions, assertions){ + return QUnit.assertOnEvent($table4, 'sortEnd', actions, assertions); + } + ).nextTask( + function(){ + c4.sortMultiSortKey = 'altKey'; + c4.$headers.eq(5).trigger( $.Event('sort', { which: 1, altKey: true }) ); + }, + function(){ + assert.cacheCompare( table4, 3, [ 2, 1, 6, 7, 5, 4, 3, 8, 10, 9 ], 'force x2 + sorted x2 + append x2, descending' ); + } + ).nextTask( + function() { + c4.sortResetKey = 'shiftKey'; + c4.$headers.eq(0).trigger( $.Event('sort', {which: 1, shiftKey: true}) ); + }, + function() { + assert.cacheCompare( table4, 3, [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], 'sortResetKey' ); + } + ).promise(); + }); + + /************************************************ + check header css + ************************************************/ + QUnit.test( "testing header css & sortReset method", function(assert) { + assert.expect(7); + t = $(th0); + assert.equal( $table1.hasClass(ts.css.table), true, 'table class applied'); + assert.equal( t.hasClass(ts.css.header), true, 'Header class present' ); + assert.equal( t.parent().hasClass(ts.css.headerRow), true, 'Header row class present' ); + assert.equal( $table1.find('tbody:eq(1)').hasClass(c1.cssInfoBlock), true, 'Tbody info block class present' ); + $table1.trigger('sorton', [[[ 0,1 ]]] ); + assert.equal( t.hasClass(ts.css.sortDesc), true, 'Descending class present' ); + $table1.trigger('sorton', [[[ 0,0 ]]] ); + assert.equal( t.hasClass(ts.css.sortAsc), true, 'Ascending class present' ); + $table1.trigger('sortReset'); + assert.equal( t.hasClass(ts.css.sortAsc) || t.hasClass(ts.css.sortDesc), false, 'Testing sortReset' ); + }); + + /************************************************ + test apply widgets function using zebra widget + ************************************************/ + var zebra = function(){ + t = true; + var classes = ['odd','even']; + $table2.find('tbody tr').each(function(i){ + t = t ? $(this).hasClass( classes[i%2] ) : false; + }); + return t; + }; + + QUnit.test( "apply zebra widget", function(assert) { + assert.expect(3); + assert.equal( zebra(), false, 'zebra not applied' ); + c2.widgets = [ 'zebra' ]; + $table2.trigger('applyWidgets'); + assert.equal( zebra(), true, 'zebra is applied' ); + $table2 + .append('stuv') + .trigger('update'); + assert.equal( zebra(), true, 'zebra is applied after update' ); + }); + + /************************************************ + check destroy method + ************************************************/ + QUnit.test("testing destroy method", function(assert) { + $table2.trigger('sorton', [[[ 0,1 ]]] ); + $table2.trigger('destroy'); + assert.expect(7); + t = $table2.find('th:first'); + e = jQuery._data(table2, 'events'); // get a list of all bound events + assert.equal( $.isEmptyObject(e), true, 'no events applied' ); + assert.equal( $table2.data().hasOwnProperty('tablesorter'), false, 'Data removed' ); + assert.equal( $table2.attr('class'), 'tester', 'All table classes removed' ); + assert.equal( $table2.find('tr:first').attr('class'), '', 'Header row class removed' ); + assert.equal( t.attr('class').match('tablesorter'), null, 'Header classes removed' ); + assert.equal( t.children().length, 0, 'Inner wrapper removed' ); + assert.equal( typeof (t.data().column) , 'undefined', 'data-column removed'); + + $table2.tablesorter(); + }); + + /************************************************ + ipv6 parser testing + ************************************************/ + ipv6tests(); + +});