aa-ledger 1.0.4__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. {aa_ledger-1.0.4.dist-info → aa_ledger-2.0.0.dist-info}/METADATA +5 -6
  2. aa_ledger-2.0.0.dist-info/RECORD +267 -0
  3. ledger/__init__.py +2 -2
  4. ledger/admin.py +23 -18
  5. ledger/api/__init__.py +23 -7
  6. ledger/api/{ledger/admin.py → admin.py} +25 -31
  7. ledger/api/alliance.py +755 -0
  8. ledger/api/character.py +786 -0
  9. ledger/api/corporation.py +1141 -0
  10. ledger/api/{helpers.py → helpers/core.py} +33 -33
  11. ledger/api/helpers/icons.py +372 -0
  12. ledger/api/helpers/planetary_helper.py +354 -0
  13. ledger/api/planetary.py +354 -0
  14. ledger/api/schema.py +240 -15
  15. ledger/app_settings.py +11 -27
  16. ledger/auth_hooks.py +2 -2
  17. ledger/constants.py +50 -177
  18. ledger/decorators.py +2 -46
  19. ledger/forms.py +133 -39
  20. ledger/helpers/billboard.py +194 -144
  21. ledger/helpers/cache.py +105 -0
  22. ledger/helpers/discord.py +2 -4
  23. ledger/helpers/eveonline.py +160 -0
  24. ledger/helpers/ledger_data.py +23 -0
  25. ledger/helpers/ref_type.py +53 -78
  26. ledger/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  27. ledger/locale/cs_CZ/LC_MESSAGES/django.po +349 -193
  28. ledger/locale/de/LC_MESSAGES/django.mo +0 -0
  29. ledger/locale/de/LC_MESSAGES/django.po +528 -379
  30. ledger/locale/django.pot +721 -546
  31. ledger/locale/es/LC_MESSAGES/django.mo +0 -0
  32. ledger/locale/es/LC_MESSAGES/django.po +349 -194
  33. ledger/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
  34. ledger/locale/fr_FR/LC_MESSAGES/django.po +349 -193
  35. ledger/locale/it_IT/LC_MESSAGES/django.mo +0 -0
  36. ledger/locale/it_IT/LC_MESSAGES/django.po +349 -193
  37. ledger/locale/ja/LC_MESSAGES/django.mo +0 -0
  38. ledger/locale/ja/LC_MESSAGES/django.po +348 -193
  39. ledger/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
  40. ledger/locale/ko_KR/LC_MESSAGES/django.po +349 -193
  41. ledger/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
  42. ledger/locale/nl_NL/LC_MESSAGES/django.po +349 -193
  43. ledger/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
  44. ledger/locale/pl_PL/LC_MESSAGES/django.po +350 -193
  45. ledger/locale/ru/LC_MESSAGES/django.mo +0 -0
  46. ledger/locale/ru/LC_MESSAGES/django.po +348 -193
  47. ledger/locale/sk/LC_MESSAGES/django.mo +0 -0
  48. ledger/locale/sk/LC_MESSAGES/django.po +348 -193
  49. ledger/locale/uk/LC_MESSAGES/django.mo +0 -0
  50. ledger/locale/uk/LC_MESSAGES/django.po +348 -193
  51. ledger/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  52. ledger/locale/zh_Hans/LC_MESSAGES/django.po +348 -193
  53. ledger/managers/character_audit_manager.py +28 -20
  54. ledger/managers/character_journal_manager.py +185 -357
  55. ledger/managers/character_mining_manager.py +52 -26
  56. ledger/managers/character_planetary_manager.py +178 -136
  57. ledger/managers/corporation_audit_manager.py +36 -27
  58. ledger/managers/corporation_journal_manager.py +92 -56
  59. ledger/managers/general_manager.py +8 -7
  60. ledger/migrations/0018_remove_characterplanet_ledger_char_planet__58a5b6_idx_and_more.py +44 -0
  61. ledger/migrations/0019_rename_characteraudit_characterowner_and_more.py +48 -0
  62. ledger/models/__init__.py +5 -11
  63. ledger/models/characteraudit.py +101 -109
  64. ledger/models/corporationaudit.py +94 -49
  65. ledger/models/general.py +105 -211
  66. ledger/models/helpers/update_manager.py +302 -0
  67. ledger/models/planetary.py +60 -205
  68. ledger/providers.py +101 -0
  69. ledger/static/ledger/css/{ledger.css → aa-ledger.css} +54 -28
  70. ledger/static/ledger/js/aa-ledger.js +124 -0
  71. ledger/static/ledger/js/charts.js +25 -1
  72. ledger/static/ledger/js/view-alliance-ledger.js +383 -0
  73. ledger/static/ledger/js/view-character-ledger.js +388 -0
  74. ledger/static/ledger/js/view-corporation-ledger.js +402 -0
  75. ledger/static/ledger/js/view-planetary.js +492 -0
  76. ledger/static/ledger/libs/amCharts/5.14.4/js/flow.js +2 -0
  77. ledger/static/ledger/libs/amCharts/5.14.4/js/index.js +2 -0
  78. ledger/static/ledger/libs/amCharts/5.14.4/js/percent.js +2 -0
  79. ledger/static/ledger/libs/amCharts/5.14.4/js/themes/Animated.js +2 -0
  80. ledger/static/ledger/libs/amCharts/5.14.4/js/themes/Dark.js +2 -0
  81. ledger/static/ledger/libs/amCharts/5.14.4/js/xy.js +2 -0
  82. ledger/static/ledger/libs/datatables/2.3.5/css/dataTables.bootstrap5.css +610 -0
  83. ledger/static/ledger/libs/datatables/2.3.5/js/dataTables.bootstrap5.js +122 -0
  84. ledger/static/ledger/libs/datatables/2.3.5/js/dataTables.js +14127 -0
  85. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/css/columnControl.bootstrap5.css +516 -0
  86. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/css/columnControl.dataTables.css +529 -0
  87. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/js/columnControl.bootstrap5.js +73 -0
  88. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/js/dataTables.columnControl.js +3090 -0
  89. ledger/static/ledger/libs/datatables/Extensions/FixedHeader/4.0.4/css/fixedHeader.bootstrap5.css +20 -0
  90. ledger/static/ledger/libs/datatables/Extensions/FixedHeader/4.0.4/js/dataTables.fixedHeader.js +1203 -0
  91. ledger/static/ledger/libs/datatables/Extensions/FixedHeader/4.0.4/js/fixedHeader.bootstrap5.js +59 -0
  92. ledger/tasks.py +157 -141
  93. ledger/templates/ledger/base.html +59 -21
  94. ledger/templates/ledger/bundles/aa-ledger-css.html +3 -0
  95. ledger/templates/ledger/bundles/aa-ledger-js.html +3 -0
  96. ledger/templates/ledger/bundles/view-alliance-ledger-js.html +14 -0
  97. ledger/templates/ledger/bundles/view-character-ledger-js.html +15 -0
  98. ledger/templates/ledger/bundles/view-character-planetary-css.html +3 -0
  99. ledger/templates/ledger/bundles/view-character-planetary-js.html +4 -0
  100. ledger/templates/ledger/bundles/view-corporation-ledger-js.html +15 -0
  101. ledger/templates/ledger/partials/modal/confirm.html +0 -1
  102. ledger/templates/ledger/partials/modal/request-accept-delete-alliance.html +38 -0
  103. ledger/templates/ledger/partials/modal/request-accept-delete-character.html +38 -0
  104. ledger/templates/ledger/partials/modal/request-accept-delete-corporation.html +38 -0
  105. ledger/templates/ledger/partials/modal/request-accept-switch-notification.html +38 -0
  106. ledger/templates/ledger/partials/modal/request-view-alliance-details.html +26 -0
  107. ledger/templates/ledger/partials/modal/request-view-character-details.html +26 -0
  108. ledger/templates/ledger/partials/modal/request-view-corporation-details.html +26 -0
  109. ledger/templates/ledger/partials/modal/request-view-extractor.html +32 -0
  110. ledger/templates/ledger/partials/modal/request-view-factory.html +31 -0
  111. ledger/templates/ledger/partials/{menu → navigation}/administration.html +8 -0
  112. ledger/templates/ledger/partials/{menu → navigation}/navigation.html +2 -2
  113. ledger/templates/ledger/partials/{administration → view-alliance-administration}/alliance_corporations.html +3 -3
  114. ledger/templates/ledger/partials/view-alliance-administration/dashboard.html +81 -0
  115. ledger/templates/ledger/partials/view-alliance-ledger/alliance-billboard.html +25 -0
  116. ledger/templates/ledger/partials/view-alliance-ledger/alliance-ledger-details.html +21 -0
  117. ledger/templates/ledger/partials/view-alliance-ledger/alliance-table.html +24 -0
  118. ledger/templates/ledger/partials/view-alliance-ledger/information/daily.html +18 -0
  119. ledger/templates/ledger/partials/view-alliance-ledger/information/hourly.html +18 -0
  120. ledger/templates/ledger/partials/view-alliance-ledger/information/summary.html +19 -0
  121. ledger/templates/ledger/partials/{administration → view-character-administration}/character.html +1 -9
  122. ledger/templates/ledger/partials/{administration → view-character-administration}/dashboard.html +0 -34
  123. ledger/templates/ledger/partials/view-character-ledger/character-billboard.html +25 -0
  124. ledger/templates/ledger/partials/view-character-ledger/character-ledger-details.html +21 -0
  125. ledger/templates/ledger/partials/view-character-ledger/character-table.html +25 -0
  126. ledger/templates/ledger/partials/view-character-ledger/information/daily.html +18 -0
  127. ledger/templates/ledger/partials/view-character-ledger/information/hourly.html +18 -0
  128. ledger/templates/ledger/partials/view-character-ledger/information/summary.html +19 -0
  129. ledger/templates/ledger/partials/view-character-planetary/extractor-table.html +24 -0
  130. ledger/templates/ledger/partials/view-character-planetary/factory-table.html +24 -0
  131. ledger/templates/ledger/partials/view-character-planetary/planetary-table.html +22 -0
  132. ledger/templates/ledger/partials/view-character-planetary/storage-table.html +23 -0
  133. ledger/templates/ledger/partials/{administration → view-corporation-administration}/corporation.html +5 -13
  134. ledger/templates/ledger/partials/{administration → view-corporation-administration}/corporation_characters.html +1 -1
  135. ledger/templates/ledger/partials/view-corporation-administration/dashboard.html +81 -0
  136. ledger/templates/ledger/partials/view-corporation-ledger/corporation-billboard.html +25 -0
  137. ledger/templates/ledger/partials/view-corporation-ledger/corporation-ledger-details.html +21 -0
  138. ledger/templates/ledger/partials/view-corporation-ledger/corporation-table.html +26 -0
  139. ledger/templates/ledger/partials/view-corporation-ledger/information/daily.html +18 -0
  140. ledger/templates/ledger/partials/view-corporation-ledger/information/hourly.html +18 -0
  141. ledger/templates/ledger/partials/view-corporation-ledger/information/summary.html +19 -0
  142. ledger/templates/ledger/view-administration.html +62 -0
  143. ledger/templates/ledger/view-alliance-administration.html +49 -0
  144. ledger/templates/ledger/view-alliance-ledger.html +72 -0
  145. ledger/templates/ledger/view-alliance-overview.html +131 -0
  146. ledger/templates/ledger/view-character-administration.html +42 -0
  147. ledger/templates/ledger/view-character-ledger.html +73 -0
  148. ledger/templates/ledger/view-character-overview.html +135 -0
  149. ledger/templates/ledger/view-character-planetary-overview.html +135 -0
  150. ledger/templates/ledger/view-character-planetary.html +73 -0
  151. ledger/templates/ledger/view-corporation-administration.html +42 -0
  152. ledger/templates/ledger/view-corporation-ledger.html +73 -0
  153. ledger/templates/ledger/view-corporation-overview.html +131 -0
  154. ledger/templatetags/ledger.py +3 -5
  155. ledger/tests/__init__.py +187 -0
  156. ledger/tests/test_admin.py +164 -68
  157. ledger/tests/test_auth_hook.py +31 -13
  158. ledger/tests/test_decarators.py +14 -79
  159. ledger/tests/test_discord_installed.py +0 -1
  160. ledger/tests/test_helpers/test_ledger_data.py +19 -0
  161. ledger/tests/test_managers/test_character_audit_manager.py +111 -69
  162. ledger/tests/test_managers/test_character_journal_manager.py +48 -208
  163. ledger/tests/test_managers/test_character_mining_manager.py +37 -16
  164. ledger/tests/test_managers/test_corporation_division_manager.py +66 -28
  165. ledger/tests/test_managers/test_corporation_journal_manager.py +39 -42
  166. ledger/tests/test_managers/test_general_manager.py +78 -18
  167. ledger/tests/test_managers/test_planetary_manager.py +73 -32
  168. ledger/tests/test_models/test_characteraudit.py +58 -74
  169. ledger/tests/test_models/test_characterminingledger.py +20 -26
  170. ledger/tests/test_models/test_characterwalletjournal.py +10 -33
  171. ledger/tests/test_models/test_corporationaudit.py +41 -35
  172. ledger/tests/test_models/test_corporationwalletjournal.py +35 -32
  173. ledger/tests/test_models/test_general.py +44 -11
  174. ledger/tests/test_models/test_planetary.py +14 -80
  175. ledger/tests/test_templatetags.py +2 -7
  176. ledger/tests/test_views/corporation/test_add_corp.py +16 -35
  177. ledger/tests/test_views/corporation/test_delete_corporation.py +66 -42
  178. ledger/tests/test_views/test_access.py +512 -545
  179. ledger/tests/test_views/test_add_ally.py +57 -46
  180. ledger/tests/test_views/test_add_char.py +21 -33
  181. ledger/tests/test_views/test_delete_character.py +24 -21
  182. ledger/tests/testdata/README_ESI_STUB.md +430 -0
  183. ledger/tests/testdata/esi_stub_openapi.py +511 -0
  184. ledger/tests/testdata/integrations/__init__.py +0 -0
  185. ledger/tests/testdata/{load_eveuniverse.py → integrations/eveuniverse.py} +0 -1
  186. ledger/tests/testdata/integrations/planetary.py +13 -0
  187. ledger/tests/testdata/json/factory.json +281 -0
  188. ledger/tests/testdata/json/inactive.json +281 -0
  189. ledger/tests/testdata/json/pins.json +175 -272
  190. ledger/tests/testdata/json/route.json +95 -528
  191. ledger/tests/testdata/test_esi_stub.py +468 -0
  192. ledger/tests/testdata/utils.py +601 -0
  193. ledger/thirdparty/charlink_hook.py +60 -30
  194. ledger/urls.py +0 -135
  195. ledger/views/alliance/add_ally.py +2 -4
  196. ledger/views/alliance/alliance_ledger.py +64 -147
  197. ledger/views/character/add_char.py +8 -10
  198. ledger/views/character/character_ledger.py +60 -126
  199. ledger/views/character/planetary.py +5 -98
  200. ledger/views/corporation/add_corp.py +10 -12
  201. ledger/views/corporation/corporation_ledger.py +65 -327
  202. ledger/views/index.py +92 -30
  203. aa_ledger-1.0.4.dist-info/RECORD +0 -236
  204. ledger/api/api_helper/planetary_helper.py +0 -107
  205. ledger/api/ledger/__init__.py +0 -7
  206. ledger/api/ledger/planetary.py +0 -231
  207. ledger/helpers/alliance.py +0 -317
  208. ledger/helpers/character.py +0 -251
  209. ledger/helpers/core.py +0 -665
  210. ledger/helpers/corporation.py +0 -427
  211. ledger/helpers/data_exporter.py +0 -452
  212. ledger/static/ledger/js/planetary-confirm.js +0 -66
  213. ledger/static/ledger/js/planetary.js +0 -143
  214. ledger/templates/ledger/admin.html +0 -43
  215. ledger/templates/ledger/allyledger/admin/alliance_administration.html +0 -46
  216. ledger/templates/ledger/allyledger/admin/alliance_overview.html +0 -108
  217. ledger/templates/ledger/allyledger/alliance_ledger.html +0 -86
  218. ledger/templates/ledger/bundles/character-ledger-bundles.html +0 -66
  219. ledger/templates/ledger/bundles/corporation-ledger-bundles.html +0 -75
  220. ledger/templates/ledger/bundles/ledger-bundles.html +0 -23
  221. ledger/templates/ledger/bundles/ledger-css.html +0 -3
  222. ledger/templates/ledger/bundles/planetary-bundles.html +0 -50
  223. ledger/templates/ledger/bundles/table-css.html +0 -3
  224. ledger/templates/ledger/charledger/admin/character_administration.html +0 -39
  225. ledger/templates/ledger/charledger/admin/character_overview.html +0 -106
  226. ledger/templates/ledger/charledger/character_ledger.html +0 -94
  227. ledger/templates/ledger/charledger/planetary/admin/planetary_overview.html +0 -123
  228. ledger/templates/ledger/charledger/planetary/planetary_ledger.html +0 -54
  229. ledger/templates/ledger/corpledger/admin/corporation_administration.html +0 -39
  230. ledger/templates/ledger/corpledger/admin/corporation_overview.html +0 -108
  231. ledger/templates/ledger/corpledger/corporation_ledger.html +0 -129
  232. ledger/templates/ledger/data-export.html +0 -78
  233. ledger/templates/ledger/error.html +0 -31
  234. ledger/templates/ledger/partials/form/error-message.html +0 -1
  235. ledger/templates/ledger/partials/information/daily.html +0 -56
  236. ledger/templates/ledger/partials/information/day.html +0 -48
  237. ledger/templates/ledger/partials/information/error.html +0 -8
  238. ledger/templates/ledger/partials/information/hourly.html +0 -53
  239. ledger/templates/ledger/partials/information/summary.html +0 -88
  240. ledger/templates/ledger/partials/information/view_character_content.html +0 -35
  241. ledger/templates/ledger/partials/modal/switchalarm_confirm.html +0 -39
  242. ledger/templates/ledger/partials/modal/view_extractor.html +0 -48
  243. ledger/templates/ledger/partials/modal/view_factory.html +0 -123
  244. ledger/templates/ledger/partials/table/char-ledger.html +0 -85
  245. ledger/templates/ledger/partials/table/corp-ledger.html +0 -66
  246. ledger/templates/ledger/partials/table/planetary.html +0 -18
  247. ledger/templates/ledger/partials/thirdparty/billboard.html +0 -22
  248. ledger/templates/ledger/partials/view/card.html +0 -160
  249. ledger/templates/ledger/permission.html +0 -2
  250. ledger/tests/test_helpers/test_billboard.py +0 -11
  251. ledger/tests/test_helpers/test_data_exporter.py +0 -207
  252. ledger/tests/test_tasks.py +0 -282
  253. ledger/tests/test_view_helpers/test_core.py +0 -47
  254. ledger/tests/test_views/corporation/test_corporation.py +0 -267
  255. ledger/tests/test_views/test_planetary.py +0 -137
  256. ledger/tests/testdata/esi_stub.py +0 -109
  257. ledger/tests/testdata/esi_stub_migration.py +0 -80
  258. ledger/tests/testdata/generate_characteraudit.py +0 -106
  259. ledger/tests/testdata/generate_corporationaudit.py +0 -74
  260. ledger/tests/testdata/generate_events.py +0 -31
  261. ledger/tests/testdata/generate_miningledger.py +0 -13
  262. ledger/tests/testdata/generate_planets.py +0 -48
  263. ledger/tests/testdata/generate_walletjournal.py +0 -42
  264. ledger/tests/testdata/json/czarno-pins.json +0 -240
  265. ledger/tests/testdata/json/czarno-routes.json +0 -165
  266. ledger/tests/testdata/json/pins2.json +0 -538
  267. {aa_ledger-1.0.4.dist-info → aa_ledger-2.0.0.dist-info}/WHEEL +0 -0
  268. {aa_ledger-1.0.4.dist-info → aa_ledger-2.0.0.dist-info}/licenses/LICENSE +0 -0
  269. /ledger/{tests/test_view_helpers → api/helpers}/__init__.py +0 -0
  270. /ledger/templates/ledger/bundles/{ally-administration-bundles.html → view-alliance-administration-js.html} +0 -0
  271. /ledger/templates/ledger/bundles/{char-administration-bundles.html → view-character-administration-js.html} +0 -0
  272. /ledger/templates/ledger/bundles/{corp-administration-bundles.html → view-corporation-administration-js.html} +0 -0
  273. /ledger/templates/ledger/partials/{administration → view-alliance-administration}/alliance.html +0 -0
  274. /ledger/tests/testdata/{esi.json → esi_test_data.json} +0 -0
  275. /ledger/tests/testdata/{allianceauth.json → integrations/allianceauth.json} +0 -0
  276. /ledger/tests/testdata/{load_allianceauth.py → integrations/allianceauth.py} +0 -0
  277. /ledger/tests/testdata/{eveentity.json → integrations/eveentity.json} +0 -0
  278. /ledger/tests/testdata/{load_eveentity.py → integrations/eveentity.py} +0 -0
  279. /ledger/tests/testdata/{eveuniverse.json → integrations/eveuniverse.json} +0 -0
  280. /ledger/tests/testdata/{planetary.json → integrations/planetary.json} +0 -0
@@ -0,0 +1,3090 @@
1
+ /*! ColumnControl 1.1.1
2
+ * Copyright (c) SpryMedia Ltd - datatables.net/license
3
+ *
4
+ * SVG icons: ISC License
5
+ * Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT).
6
+ * All other copyright (c) for Lucide are held by Lucide Contributors 2022.
7
+ */
8
+
9
+ (function( factory ){
10
+ if ( typeof define === 'function' && define.amd ) {
11
+ // AMD
12
+ define( ['jquery', 'datatables.net'], function ( $ ) {
13
+ return factory( $, window, document );
14
+ } );
15
+ }
16
+ else if ( typeof exports === 'object' ) {
17
+ // CommonJS
18
+ var jq = require('jquery');
19
+ var cjsRequires = function (root, $) {
20
+ if ( ! $.fn.dataTable ) {
21
+ require('datatables.net')(root, $);
22
+ }
23
+ };
24
+
25
+ if (typeof window === 'undefined') {
26
+ module.exports = function (root, $) {
27
+ if ( ! root ) {
28
+ // CommonJS environments without a window global must pass a
29
+ // root. This will give an error otherwise
30
+ root = window;
31
+ }
32
+
33
+ if ( ! $ ) {
34
+ $ = jq( root );
35
+ }
36
+
37
+ cjsRequires( root, $ );
38
+ return factory( $, root, root.document );
39
+ };
40
+ }
41
+ else {
42
+ cjsRequires( window, jq );
43
+ module.exports = factory( jq, window, window.document );
44
+ }
45
+ }
46
+ else {
47
+ // Browser
48
+ factory( jQuery, window, document );
49
+ }
50
+ }(function( $, window, document ) {
51
+ 'use strict';
52
+ var DataTable = $.fn.dataTable;
53
+
54
+
55
+
56
+ function createElement(type, classes, text, children) {
57
+ if (classes === void 0) { classes = []; }
58
+ if (text === void 0) { text = null; }
59
+ if (children === void 0) { children = []; }
60
+ var el = document.createElement(type);
61
+ addClass(el, classes);
62
+ if (text) {
63
+ el.innerHTML = text;
64
+ }
65
+ children.forEach(function (child) {
66
+ el.appendChild(child);
67
+ });
68
+ return el;
69
+ }
70
+ function addClass(el, classes) {
71
+ if (!classes) {
72
+ return;
73
+ }
74
+ if (!Array.isArray(classes)) {
75
+ classes = [classes];
76
+ }
77
+ classes.forEach(function (className) {
78
+ if (el && className) {
79
+ el.classList.add(className);
80
+ }
81
+ });
82
+ }
83
+
84
+ // The SVG for many of these icons are from Lucide ( https://lucide.dev ), which are available
85
+ // under the ISC License. There are a number of custom icons as well. These are optimised through
86
+ // https://optimize.svgomg.net/
87
+ function wrap(paths) {
88
+ return ('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
89
+ paths +
90
+ '</svg>');
91
+ }
92
+ var icons = {
93
+ chevronRight: wrap('<path d="m9 18 6-6-6-6"/>'),
94
+ // columns-3
95
+ columns: wrap('<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/><path d="M15 3v18"/>'),
96
+ // Custom
97
+ contains: wrap('<path d="M10 3h4v18h-4z"/><path d="M18 8h3v9h-3"/><path d="M6 17H3V8h3"/>'),
98
+ empty: wrap('<circle cx="12" cy="12" r="10"/>'),
99
+ ends: wrap('<path d="M21 3h-4v18h4z"/><path d="M13 8H3v9h10"/>'),
100
+ // Customised
101
+ equal: wrap('<line x1="5" x2="19" y1="9" y2="9"/><line x1="5" x2="19" y1="15" y2="15"/>'),
102
+ greater: wrap('<path d="m9 18 6-6-6-6"/>'),
103
+ // Custom
104
+ greaterOrEqual: wrap('<path d="m9 16 6-6-6-6"/><path d="m9 21 6-6"/>'),
105
+ // Custom
106
+ groupAdd: wrap('<path d="M6 21v-7.5m-3.549 3.75H9.75"/><rect width="13.5" height="7.5" x="3" y="3" rx="1.5"/><rect width="7.5" height="7.5" x="13.5" y="13.5" fill="currentColor" rx="1.5"/>'),
107
+ // Custom
108
+ groupClear: wrap('<rect width="13.5" height="7.5" x="3" y="3" rx="1.5"/><rect width="7.5" height="7.5" x="13.5" y="13.5" rx="1.5"/>'),
109
+ // Custom
110
+ groupTop: wrap('<rect width="13.5" height="7.5" x="3" y="3" fill="currentColor" rx="1.5"/><rect width="7.5" height="7.5" x="13.5" y="13.5" rx="1.5"/>'),
111
+ // Custom
112
+ groupRemove: wrap('<path d="M2.451 17.25H9.75"/><rect width="13.5" height="7.5" x="3" y="3" rx="1.5"/><rect width="7.5" height="7.5" x="13.5" y="13.5" rx="1.5"/>'),
113
+ less: wrap('<path d="m15 18-6-6 6-6"/>'),
114
+ // Custom
115
+ lessOrEqual: wrap('<path d="m15 16-6-6 6-6"/><path d="m15 21-6-6"/>'),
116
+ menu: wrap('<line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/>'),
117
+ // move-horizontal
118
+ move: wrap('<line x1="12" x2="12" y1="3" y2="21"/><polyline points="8 8 4 12 8 16"/><polyline points="16 16 20 12 16 8"/>'),
119
+ // arrow-left-from-line
120
+ moveLeft: wrap('<path d="m9 6-6 6 6 6"/><path d="M3 12h14"/><path d="M21 19V5"/>'),
121
+ // arrow-right-from-line
122
+ moveRight: wrap('<path d="M3 5v14"/><path d="M21 12H7"/><path d="m15 18 6-6-6-6"/>'),
123
+ // Custom
124
+ notContains: wrap('<path d="M15 4 9 20"/><path d="M3 8h18v9H3z"/>'),
125
+ notEmpty: wrap('<circle cx="12" cy="12" r="10"/><line x1="9" x2="15" y1="15" y2="9"/>'),
126
+ notEqual: wrap('<path d="M5 9h14"/><path d="M5 15h14"/><path d="M15 5 9 19"/>'),
127
+ // Custom
128
+ orderAddAsc: wrap('<path d="M17 21v-8"/><path d="M3 4h6"/><path d="M3 8h9"/><path d="M3 12h10"/><path d="M13 17h8"/>'),
129
+ // Custom
130
+ orderAddDesc: wrap('<path d="M17 21v-8"/><path d="M3 4h12"/><path d="M3 8h9"/><path d="M3 12h6"/><path d="M13 17h8"/>'),
131
+ orderAsc: wrap('<path d="m3 8 4-4 4 4"/><path d="M7 4v16"/><path d="M11 12h4"/><path d="M11 16h7"/><path d="M11 20h10"/>'),
132
+ // Custom
133
+ orderClear: wrap('<path d="m21 21-8-8"/><path d="M3 4h12"/><path d="M3 8h9"/><path d="M3 12h6"/><path d="m13 21 8-8"/>'),
134
+ orderDesc: wrap('<path d="m3 16 4 4 4-4"/><path d="M7 20V4"/><path d="M11 4h10"/><path d="M11 8h7"/><path d="M11 12h4"/>'),
135
+ // Custom
136
+ orderRemove: wrap('<path d="M3 4h12"/><path d="M3 8h9"/><path d="M3 12h6"/><path d="M13 17h8"/>'),
137
+ // Custom
138
+ orderNone: wrap('<path d="m3 8 4-4 4 4"/><path d="m11 16-4 4-4-4"/><path d="M7 4v16"/><path d="M15 8h6"/><path d="M15 16h6"/><path d="M13 12h8"/>'),
139
+ // search
140
+ search: wrap('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>'),
141
+ // search-x
142
+ searchClear: wrap('<path d="m13.5 8.5-5 5"/><path d="m8.5 8.5 5 5"/><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>'),
143
+ // Custom
144
+ starts: wrap('<path d="M3 3h4v18H3z"/><path d="M11 8h10v9H11"/>'),
145
+ // tick
146
+ tick: wrap('<path d="M20 6 9 17l-5-5"/>'),
147
+ // x
148
+ x: wrap('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>')
149
+ };
150
+
151
+ /**
152
+ * Close all or only other dropdowns
153
+ *
154
+ * @param e Event or null to close all others
155
+ */
156
+ function close(e) {
157
+ if (e === void 0) { e = null; }
158
+ document.querySelectorAll('div.dtcc-dropdown').forEach(function (el) {
159
+ if (e === null || !el.contains(e.target)) {
160
+ el._close();
161
+ if (!e._closed) {
162
+ e._closed = [];
163
+ }
164
+ e._closed.push(el);
165
+ }
166
+ });
167
+ }
168
+ function getContainer(dt, btn) {
169
+ return btn.closest('div.dtfh-floatingparent') || dt.table().container();
170
+ }
171
+ /**
172
+ * Position the dropdown relative to the button that activated it, with possible corrections
173
+ * to make sure it is visible on the page.
174
+ *
175
+ * @param dropdown Dropdown element
176
+ * @param dt Container DataTable
177
+ * @param btn Button the dropdown emanates from
178
+ */
179
+ function positionDropdown(dropdown, dt, btn) {
180
+ var header = btn.closest('div.dt-column-header');
181
+ var container = getContainer(dt, btn);
182
+ var headerStyle = getComputedStyle(header);
183
+ var dropdownWidth = dropdown.offsetWidth;
184
+ var position = relativePosition(container, btn);
185
+ var left, top;
186
+ top = position.top + btn.offsetHeight;
187
+ if (headerStyle.flexDirection === 'row-reverse') {
188
+ // Icon is on the left of the header - align the left hand sides
189
+ left = position.left;
190
+ }
191
+ else {
192
+ // Icon is on the right of the header - align the right hand sides
193
+ left = position.left - dropdownWidth + btn.offsetWidth;
194
+ }
195
+ // Corrections - don't extend past the DataTable to the left and right
196
+ var containerWidth = container.offsetWidth;
197
+ if (left + dropdownWidth > containerWidth) {
198
+ left -= left + dropdownWidth - containerWidth;
199
+ }
200
+ if (left < 0) {
201
+ left = 0;
202
+ }
203
+ dropdown.style.top = top + 'px';
204
+ dropdown.style.left = left + 'px';
205
+ }
206
+ /**
207
+ * Display the dropdown in the document
208
+ *
209
+ * @param dropdown Dropdown element
210
+ * @param dt Container DataTable
211
+ * @param btn Button the dropdown emanates from
212
+ * @returns Function to call when the dropdown should be removed from the document
213
+ */
214
+ function attachDropdown(dropdown, dt, btn) {
215
+ var dtContainer = getContainer(dt, btn.element());
216
+ dropdown._shown = true;
217
+ dtContainer.append(dropdown);
218
+ positionDropdown(dropdown, dt, btn.element());
219
+ btn.element().setAttribute('aria-expanded', 'true');
220
+ // Note that this could be called when the dropdown has already been removed from the document
221
+ // via another dropdown being shown. This will clean up the event on the next body click.
222
+ var removeDropdown = function (e) {
223
+ // Not in document, so just clean up the event handler
224
+ if (!dropdown._shown) {
225
+ document.body.removeEventListener('click', removeDropdown);
226
+ return;
227
+ }
228
+ // If the click is inside the dropdown, ignore it - we don't want to immediately close
229
+ if (e.target === dropdown || dropdown.contains(e.target)) {
230
+ return;
231
+ }
232
+ // If there is currently a datetime picker visible on the page, assume that it belongs to
233
+ // this dropdown. Don't want to close while operating on the picker.
234
+ var datetime = document.querySelector('div.dt-datetime');
235
+ if (datetime && (e.target === datetime || datetime.contains(e.target))) {
236
+ return;
237
+ }
238
+ dropdown._close();
239
+ document.body.removeEventListener('click', removeDropdown);
240
+ };
241
+ document.body.addEventListener('click', removeDropdown);
242
+ return removeDropdown;
243
+ }
244
+ /**
245
+ * Get the position of an element, relative to a given parent. The origin MUST be under the
246
+ * parent's tree.
247
+ *
248
+ * @param parent Parent element to get position relative to
249
+ * @param origin Target element
250
+ */
251
+ function relativePosition(parent, origin) {
252
+ var top = 0;
253
+ var left = 0;
254
+ while (origin && origin !== parent && origin !== document.body) {
255
+ top += origin.offsetTop;
256
+ left += origin.offsetLeft;
257
+ if (origin.scrollTop) {
258
+ left -= origin.scrollTop;
259
+ }
260
+ if (origin.scrollLeft) {
261
+ left -= origin.scrollLeft;
262
+ }
263
+ origin = origin.offsetParent;
264
+ }
265
+ return {
266
+ top: top,
267
+ left: left
268
+ };
269
+ }
270
+ /**
271
+ * Function that will provide the keyboard navigation for the dropdown
272
+ *
273
+ * @param dropdown Dropdown element in question
274
+ * @returns Function that can be bound to `keypress`
275
+ */
276
+ function focusCapture(dropdown, host) {
277
+ return function (e) {
278
+ // Do nothing if not shown
279
+ if (!dropdown._shown) {
280
+ return;
281
+ }
282
+ // Focus trap for tab key
283
+ var elements = Array.from(dropdown.querySelectorAll('a, button, input, select'));
284
+ var active = document.activeElement;
285
+ // An escape key should close the dropdown
286
+ if (e.key === 'Escape') {
287
+ dropdown._close();
288
+ host.focus(); // Restore focus to the host
289
+ return;
290
+ }
291
+ else if (e.key !== 'Tab' || elements.length === 0) {
292
+ // Anything other than tab we aren't interested in from here
293
+ return;
294
+ }
295
+ if (!elements.includes(active)) {
296
+ // If new focus is not inside the popover we want to drag it back in
297
+ elements[0].focus();
298
+ e.preventDefault();
299
+ }
300
+ else if (e.shiftKey) {
301
+ // Reverse tabbing order when shift key is pressed
302
+ if (active === elements[0]) {
303
+ elements[elements.length - 1].focus();
304
+ e.preventDefault();
305
+ }
306
+ }
307
+ else {
308
+ if (active === elements[elements.length - 1]) {
309
+ elements[0].focus();
310
+ e.preventDefault();
311
+ }
312
+ }
313
+ };
314
+ }
315
+ var dropdownContent = {
316
+ classes: {
317
+ container: 'dtcc-dropdown',
318
+ liner: 'dtcc-dropdown-liner'
319
+ },
320
+ defaults: {
321
+ className: 'dropdown',
322
+ content: [],
323
+ icon: 'menu',
324
+ text: 'More...'
325
+ },
326
+ init: function (config) {
327
+ var dt = this.dt();
328
+ var dropdown = createElement('div', dropdownContent.classes.container, '', [
329
+ createElement('div', dropdownContent.classes.liner)
330
+ ]);
331
+ dropdown._shown = false;
332
+ dropdown._close = function () {
333
+ dropdown.remove();
334
+ dropdown._shown = false;
335
+ btn.element().setAttribute('aria-expanded', 'false');
336
+ };
337
+ dropdown.setAttribute('role', 'dialog');
338
+ dropdown.setAttribute('aria-label', dt.i18n('columnControl.dropdown', config.text));
339
+ // When FixedHeader is used, the transition between states messes up positioning, so if
340
+ // shown we just reattach the dropdown.
341
+ dt.on('fixedheader-mode', function () {
342
+ if (dropdown._shown) {
343
+ attachDropdown(dropdown, dt, config._parents ? config._parents[0] : btn);
344
+ }
345
+ });
346
+ // A liner element allows more styling options, so the contents go inside this
347
+ var liner = dropdown.childNodes[0];
348
+ var btn = new Button(dt, this)
349
+ .text(dt.i18n('columnControl.dropdown', config.text))
350
+ .icon(config.icon)
351
+ .className(config.className)
352
+ .dropdownDisplay(liner)
353
+ .handler(function (e) {
354
+ // Do nothing if our dropdown was just closed as part of the event (i.e. allow
355
+ // the button to toggle it closed)
356
+ if (e._closed && e._closed.includes(dropdown)) {
357
+ return;
358
+ }
359
+ attachDropdown(dropdown, dt, config._parents ? config._parents[0] : btn);
360
+ // When activated using a key - auto focus on the first item in the popover
361
+ var focusable = dropdown.querySelector('input, a, button');
362
+ if (focusable && e.type === 'keypress') {
363
+ focusable.focus();
364
+ }
365
+ });
366
+ btn.element().setAttribute('aria-haspopup', 'dialog');
367
+ btn.element().setAttribute('aria-expanded', 'false');
368
+ // Add the content for the dropdown
369
+ for (var i = 0; i < config.content.length; i++) {
370
+ var content = this.resolve(config.content[i]);
371
+ // For nested items we need to keep a reference to the top level so the sub-levels
372
+ // can communicate back - e.g. active or positioned relative to that top level.
373
+ if (!content.config._parents) {
374
+ content.config._parents = [];
375
+ }
376
+ content.config._parents.push(btn);
377
+ var el = content.plugin.init.call(this, content.config);
378
+ liner.appendChild(el);
379
+ }
380
+ // For nested dropdowns, add an extra icon element to show that it will dropdown further
381
+ if (config._parents && config._parents.length) {
382
+ btn.extra('chevronRight');
383
+ }
384
+ // Reposition if needed
385
+ dt.on('columns-reordered', function () {
386
+ positionDropdown(dropdown, dt, btn.element());
387
+ });
388
+ // Focus capture events
389
+ var capture = focusCapture(dropdown, btn.element());
390
+ document.body.addEventListener('keydown', capture);
391
+ dt.on('destroy', function () {
392
+ document.body.removeEventListener('keydown', capture);
393
+ });
394
+ return btn.element();
395
+ }
396
+ };
397
+
398
+ var _namespace = 0;
399
+ var Button = /** @class */ (function () {
400
+ /**
401
+ * Create a new button for use in ColumnControl contents. Buttons created by this class can be
402
+ * used at the top level in the header or in a dropdown.
403
+ */
404
+ function Button(dt, host) {
405
+ this._s = {
406
+ active: false,
407
+ activeList: [],
408
+ buttonClick: null,
409
+ dt: null,
410
+ enabled: true,
411
+ host: null,
412
+ label: '',
413
+ namespace: '',
414
+ value: null
415
+ };
416
+ this._s.dt = dt;
417
+ this._s.host = host;
418
+ this._dom = {
419
+ button: createElement('button', Button.classes.container),
420
+ dropdownDisplay: null,
421
+ extra: createElement('span', 'dtcc-button-extra'),
422
+ icon: createElement('span', 'dtcc-button-icon'),
423
+ state: createElement('span', 'dtcc-button-state'),
424
+ text: createElement('span', 'dtcc-button-text')
425
+ };
426
+ this._dom.button.setAttribute('type', 'button');
427
+ this._dom.button.append(this._dom.icon);
428
+ this._dom.button.append(this._dom.text);
429
+ this._dom.button.append(this._dom.state);
430
+ this._dom.button.append(this._dom.extra);
431
+ // Default state is enabled
432
+ this.enable(true);
433
+ }
434
+ Button.prototype.active = function (active) {
435
+ if (active === undefined) {
436
+ return this._s.active;
437
+ }
438
+ this._s.active = active;
439
+ this._checkActive();
440
+ return this;
441
+ };
442
+ /**
443
+ * A button can be marked as active by any of its sub-buttons (i.e. if it is a dropdown)
444
+ * and each one needs to be able to enable this button without effecting the active state
445
+ * trigged by any other sub-buttons. This method provides a way to do that.
446
+ *
447
+ * @param unique Unique id for the activate state
448
+ * @param active If it is active
449
+ * @returns Button instance
450
+ */
451
+ Button.prototype.activeList = function (unique, active) {
452
+ this._s.activeList[unique] = active;
453
+ this._checkActive();
454
+ return this;
455
+ };
456
+ /**
457
+ * Scan over the dropdown element looking for any visible content. If there isn't any then
458
+ * we hide this button.
459
+ *
460
+ * @returns Button instance
461
+ */
462
+ Button.prototype.checkDisplay = function () {
463
+ var visible = 0;
464
+ var children = this._dom.dropdownDisplay.childNodes;
465
+ for (var i = 0; i < children.length; i++) {
466
+ // No need to getComputedStyle since if a button is hidden, it was done with JS writing
467
+ // to style.display, so we can check against that.
468
+ if (children[i].style.display !== 'none') {
469
+ visible++;
470
+ }
471
+ }
472
+ if (visible === 0) {
473
+ this._dom.button.style.display = 'none';
474
+ }
475
+ return this;
476
+ };
477
+ /**
478
+ * Set the class name for the button
479
+ *
480
+ * @param className Class name
481
+ * @returns Button instance
482
+ */
483
+ Button.prototype.className = function (className) {
484
+ this._dom.button.classList.add('dtcc-button_' + className);
485
+ return this;
486
+ };
487
+ /**
488
+ * Destroy the button, cleaning up event listeners
489
+ */
490
+ Button.prototype.destroy = function () {
491
+ if (this._s.buttonClick) {
492
+ this._dom.button.removeEventListener('click', this._s.buttonClick);
493
+ this._dom.button.removeEventListener('keypress', this._s.buttonClick);
494
+ }
495
+ this._s.host.destroyRemove(this);
496
+ };
497
+ /**
498
+ * Relevant for drop downs only. When a button in a dropdown is hidden, we might want to
499
+ * hide the host button as well (if it has nothing else to show). For that we need to know
500
+ * what the dropdown element is.
501
+ *
502
+ * @param el Element that can be used for telling us about drop down elements.
503
+ * @returns Button instance
504
+ */
505
+ Button.prototype.dropdownDisplay = function (el) {
506
+ this._dom.dropdownDisplay = el;
507
+ return this;
508
+ };
509
+ /**
510
+ * Get the DOM Button element to attach into the document
511
+ *
512
+ * @returns The Button element
513
+ */
514
+ Button.prototype.element = function () {
515
+ return this._dom.button;
516
+ };
517
+ Button.prototype.enable = function (enable) {
518
+ if (enable === undefined) {
519
+ return this._s.enabled;
520
+ }
521
+ this._dom.button.classList.toggle('dtcc-button_disabled', !enable);
522
+ this._s.enabled = enable;
523
+ return this;
524
+ };
525
+ /**
526
+ * Set the extra information icon
527
+ *
528
+ * @param icon Icon name
529
+ * @returns Button instance
530
+ */
531
+ Button.prototype.extra = function (icon) {
532
+ this._dom.extra.innerHTML = icon ? icons[icon] : '';
533
+ return this;
534
+ };
535
+ /**
536
+ * Set the event handler for when the button is activated
537
+ *
538
+ * @param fn Event handler
539
+ * @returns Button instance
540
+ */
541
+ Button.prototype.handler = function (fn) {
542
+ var _this = this;
543
+ var buttonClick = function (e) {
544
+ // Close any dropdowns which are already open
545
+ close(e);
546
+ // Stop bubbling to the DataTables default header, which might still be enabled
547
+ e.stopPropagation();
548
+ e.preventDefault();
549
+ if (_this._s.enabled) {
550
+ fn(e);
551
+ }
552
+ };
553
+ this._s.buttonClick = buttonClick;
554
+ this._s.namespace = 'dtcc-' + _namespace++;
555
+ this._dom.button.addEventListener('click', buttonClick);
556
+ this._dom.button.addEventListener('keypress', buttonClick);
557
+ this._s.host.destroyAdd(this);
558
+ return this;
559
+ };
560
+ /**
561
+ * Set the icon to display in the button
562
+ *
563
+ * @param icon Icon name
564
+ * @returns Button instance
565
+ */
566
+ Button.prototype.icon = function (icon) {
567
+ this._dom.icon.innerHTML = icon ? icons[icon] : '';
568
+ return this;
569
+ };
570
+ Button.prototype.text = function (text) {
571
+ if (text === undefined) {
572
+ return this._s.label;
573
+ }
574
+ this._dom.text.innerHTML = text;
575
+ this._s.label = text; // for fast retrieval
576
+ this._dom.button.setAttribute('aria-label', text);
577
+ return this;
578
+ };
579
+ Button.prototype.value = function (val) {
580
+ if (val === undefined) {
581
+ return this._s.value;
582
+ }
583
+ this._s.value = val;
584
+ return this;
585
+ };
586
+ /**
587
+ * Check if anything is making this button active
588
+ *
589
+ * @returns Self for chaining
590
+ */
591
+ Button.prototype._checkActive = function () {
592
+ if (this._s.active === true || Object.values(this._s.activeList).includes(true)) {
593
+ this._dom.state.innerHTML = icons.tick;
594
+ this._dom.button.classList.add('dtcc-button_active');
595
+ }
596
+ else {
597
+ this._dom.state.innerHTML = '';
598
+ this._dom.button.classList.remove('dtcc-button_active');
599
+ }
600
+ return this;
601
+ };
602
+ Button.classes = {
603
+ container: 'dtcc-button'
604
+ };
605
+ return Button;
606
+ }());
607
+
608
+ var CheckList = /** @class */ (function () {
609
+ /**
610
+ * Container for a list of buttons
611
+ */
612
+ function CheckList(dt, host, opts) {
613
+ var _this = this;
614
+ this._s = {
615
+ buttons: [],
616
+ dt: null,
617
+ handler: function () { },
618
+ host: null,
619
+ search: ''
620
+ };
621
+ this._s.dt = dt;
622
+ this._s.host = host;
623
+ this._dom = {
624
+ buttons: createElement('div', 'dtcc-list-buttons'),
625
+ container: createElement('div', CheckList.classes.container),
626
+ controls: createElement('div', 'dtcc-list-controls'),
627
+ empty: createElement('div', 'dtcc-list-empty', dt.i18n('columnControl.list.empty', 'No options')),
628
+ title: createElement('div', 'dtcc-list-title'),
629
+ selectAll: createElement('button', 'dtcc-list-selectAll', dt.i18n('columnControl.list.all', 'Select all')),
630
+ selectAllCount: createElement('span'),
631
+ selectNone: createElement('button', 'dtcc-list-selectNone', dt.i18n('columnControl.list.none', 'Deselect')),
632
+ selectNoneCount: createElement('span'),
633
+ search: createElement('input', CheckList.classes.input)
634
+ };
635
+ var dom = this._dom;
636
+ dom.search.setAttribute('type', 'text');
637
+ dom.container.append(dom.title);
638
+ dom.container.append(dom.controls);
639
+ dom.container.append(dom.empty);
640
+ dom.container.append(dom.buttons);
641
+ if (opts.select) {
642
+ dom.controls.append(dom.selectAll);
643
+ dom.controls.append(dom.selectNone);
644
+ dom.selectAll.append(dom.selectAllCount);
645
+ dom.selectNone.append(dom.selectNoneCount);
646
+ dom.selectAll.setAttribute('type', 'button');
647
+ dom.selectNone.setAttribute('type', 'button');
648
+ }
649
+ // Events
650
+ var searchInput = function () {
651
+ _this._s.search = dom.search.value;
652
+ _this._redraw();
653
+ };
654
+ var selectAllClick = function (e) {
655
+ _this.selectAll();
656
+ _this._s.handler(e, null, _this._s.buttons, true);
657
+ _this._updateCount();
658
+ };
659
+ var selectNoneClick = function (e) {
660
+ _this.selectNone();
661
+ _this._s.handler(e, null, _this._s.buttons, true);
662
+ _this._updateCount();
663
+ };
664
+ if (opts.search) {
665
+ dom.controls.append(dom.search);
666
+ dom.search.setAttribute('placeholder', dt.i18n('columnControl.list.search', 'Search...'));
667
+ dom.search.addEventListener('input', searchInput);
668
+ }
669
+ dom.selectAll.addEventListener('click', selectAllClick);
670
+ dom.selectNone.addEventListener('click', selectNoneClick);
671
+ dt.on('destroy', function () {
672
+ dom.selectAll.removeEventListener('click', selectAllClick);
673
+ dom.selectNone.removeEventListener('click', selectNoneClick);
674
+ dom.search.removeEventListener('input', searchInput);
675
+ });
676
+ }
677
+ /**
678
+ * Add one or more buttons to the list
679
+ *
680
+ * @param options Configuration for the button(s) to add
681
+ * @returns Self for chaining
682
+ */
683
+ CheckList.prototype.add = function (options, update) {
684
+ var _this = this;
685
+ if (!Array.isArray(options)) {
686
+ options = [options];
687
+ }
688
+ var _loop_1 = function (i) {
689
+ var option = options[i];
690
+ var btn = new Button(this_1._s.dt, this_1._s.host)
691
+ .active(option.active || false)
692
+ .handler(function (e) {
693
+ _this._s.handler(e, btn, _this._s.buttons, true);
694
+ _this._updateCount();
695
+ })
696
+ .icon(option.icon || '')
697
+ .text(option.label !== ''
698
+ ? option.label
699
+ : this_1._s.dt.i18n('columnControl.list.empty', 'Empty'))
700
+ .value(option.value);
701
+ if (option.label === '') {
702
+ btn.className('empty');
703
+ }
704
+ this_1._s.buttons.push(btn);
705
+ };
706
+ var this_1 = this;
707
+ for (var i = 0; i < options.length; i++) {
708
+ _loop_1(i);
709
+ }
710
+ var count = this._s.buttons.length;
711
+ if (update === true || update === undefined) {
712
+ this._dom.selectAllCount.innerHTML = count ? '(' + count + ')' : '';
713
+ this._redraw();
714
+ }
715
+ return this;
716
+ };
717
+ /**
718
+ * Find a button with a given value
719
+ *
720
+ * @param val Value to search for
721
+ * @returns Found button
722
+ */
723
+ CheckList.prototype.button = function (val) {
724
+ var buttons = this._s.buttons;
725
+ for (var i = 0; i < buttons.length; i++) {
726
+ if (buttons[i].value() === val) {
727
+ return buttons[i];
728
+ }
729
+ }
730
+ return null;
731
+ };
732
+ /**
733
+ * Remove all buttons from the list
734
+ *
735
+ * @returns Self for chaining
736
+ */
737
+ CheckList.prototype.clear = function () {
738
+ // Clean up the buttons
739
+ for (var i = 0; i < this._s.buttons.length; i++) {
740
+ this._s.buttons[i].destroy();
741
+ }
742
+ // Then empty them out
743
+ this._dom.buttons.replaceChildren();
744
+ this._s.buttons.length = 0;
745
+ return this;
746
+ };
747
+ /**
748
+ * Get the DOM container element to attach into the document
749
+ *
750
+ * @returns Container
751
+ */
752
+ CheckList.prototype.element = function () {
753
+ return this._dom.container;
754
+ };
755
+ /**
756
+ * Set the event handler for what happens when a button is clicked
757
+ *
758
+ * @param fn Event handler
759
+ */
760
+ CheckList.prototype.handler = function (fn) {
761
+ this._s.handler = fn;
762
+ return this;
763
+ };
764
+ /**
765
+ * Indicate that this is a search control and should listen for corresponding events
766
+ *
767
+ * @param dt DataTable instance
768
+ * @param idx Column index
769
+ */
770
+ CheckList.prototype.searchListener = function (dt) {
771
+ var _this = this;
772
+ // Column control search clearing (column().columnControl.searchClear() method)
773
+ dt.on('cc-search-clear', function (e, colIdx) {
774
+ if (colIdx === _this._s.host.idx()) {
775
+ _this.selectNone();
776
+ _this._s.handler(e, null, _this._s.buttons, false);
777
+ _this._s.search = '';
778
+ _this._dom.search.value = '';
779
+ _this._redraw();
780
+ _this._updateCount();
781
+ }
782
+ });
783
+ return this;
784
+ };
785
+ /**
786
+ * Select all buttons
787
+ *
788
+ * @returns Self for chaining
789
+ */
790
+ CheckList.prototype.selectAll = function () {
791
+ for (var i = 0; i < this._s.buttons.length; i++) {
792
+ this._s.buttons[i].active(true);
793
+ }
794
+ return this;
795
+ };
796
+ /**
797
+ * Deselect all buttons
798
+ *
799
+ * @returns Self for chaining
800
+ */
801
+ CheckList.prototype.selectNone = function () {
802
+ for (var i = 0; i < this._s.buttons.length; i++) {
803
+ this._s.buttons[i].active(false);
804
+ }
805
+ return this;
806
+ };
807
+ /**
808
+ * Set the list's title
809
+ *
810
+ * @param title Display title
811
+ * @returns Button instance
812
+ */
813
+ CheckList.prototype.title = function (title) {
814
+ this._dom.title.innerHTML = title;
815
+ return this;
816
+ };
817
+ CheckList.prototype.values = function (values) {
818
+ var i;
819
+ var result = [];
820
+ var buttons = this._s.buttons;
821
+ if (values !== undefined) {
822
+ for (i = 0; i < buttons.length; i++) {
823
+ if (values.includes(buttons[i].value())) {
824
+ buttons[i].active(true);
825
+ }
826
+ }
827
+ this._updateCount();
828
+ return this;
829
+ }
830
+ for (i = 0; i < buttons.length; i++) {
831
+ if (buttons[i].active()) {
832
+ result.push(buttons[i].value());
833
+ }
834
+ }
835
+ return result;
836
+ };
837
+ /**
838
+ * Update the deselect counter
839
+ */
840
+ CheckList.prototype._updateCount = function () {
841
+ var count = this.values().length;
842
+ this._dom.selectNoneCount.innerHTML = count ? '(' + count + ')' : '';
843
+ };
844
+ /**
845
+ * Add the buttons to the page - taking into account filtering
846
+ */
847
+ CheckList.prototype._redraw = function () {
848
+ var buttons = this._s.buttons;
849
+ var el = this._dom.buttons;
850
+ var searchTerm = this._s.search.toLowerCase();
851
+ el.replaceChildren();
852
+ for (var i = 0; i < buttons.length; i++) {
853
+ var btn = buttons[i];
854
+ if (!searchTerm ||
855
+ btn
856
+ .text()
857
+ .toLowerCase()
858
+ .includes(searchTerm)) {
859
+ el.appendChild(btn.element());
860
+ }
861
+ }
862
+ this._dom.empty.style.display = buttons.length === 0 ? 'block' : 'none';
863
+ el.style.display = buttons.length > 0 ? 'block' : 'none';
864
+ };
865
+ CheckList.classes = {
866
+ container: 'dtcc-list',
867
+ input: 'dtcc-list-search'
868
+ };
869
+ return CheckList;
870
+ }());
871
+
872
+ var colVis = {
873
+ defaults: {
874
+ className: 'colVis',
875
+ columns: '',
876
+ search: false,
877
+ select: false,
878
+ title: 'Column visibility'
879
+ },
880
+ init: function (config) {
881
+ var dt = this.dt();
882
+ var checkList = new CheckList(dt, this, {
883
+ search: config.search,
884
+ select: config.select
885
+ })
886
+ .title(dt.i18n('columnControl.colVis', config.title))
887
+ .handler(function (e, btn, buttons) {
888
+ if (btn) {
889
+ btn.active(!btn.active());
890
+ }
891
+ apply(buttons);
892
+ });
893
+ // Need to apply in a loop to allow for select all / select none
894
+ var apply = function (buttons) {
895
+ for (var i = 0; i < buttons.length; i++) {
896
+ var btn = buttons[i];
897
+ var idx = btn.value();
898
+ var col = dt.column(idx);
899
+ if (btn.active() && !col.visible()) {
900
+ col.visible(true);
901
+ }
902
+ else if (!btn.active() && col.visible()) {
903
+ col.visible(false);
904
+ }
905
+ }
906
+ };
907
+ var rebuild = function () {
908
+ var columns = dt.columns(config.columns);
909
+ columns.every(function () {
910
+ checkList.add({
911
+ active: this.visible(),
912
+ label: this.title(),
913
+ value: this.index()
914
+ });
915
+ });
916
+ };
917
+ rebuild();
918
+ dt.on('column-visibility', function (e, s, colIdx, state) {
919
+ var btn = checkList.button(colIdx);
920
+ if (btn) {
921
+ btn.active(state);
922
+ }
923
+ });
924
+ dt.on('columns-reordered', function (e, details) {
925
+ checkList.clear();
926
+ rebuild();
927
+ });
928
+ return checkList.element();
929
+ }
930
+ };
931
+
932
+ var colVisDropdown = {
933
+ defaults: {
934
+ className: 'colVis',
935
+ columns: '',
936
+ search: false,
937
+ select: false,
938
+ text: 'Column visibility',
939
+ title: 'Column visibility'
940
+ },
941
+ extend: function (config) {
942
+ var dt = this.dt();
943
+ return {
944
+ extend: 'dropdown',
945
+ icon: 'columns',
946
+ text: dt.i18n('columnControl.colVisDropdown', config.text),
947
+ content: [
948
+ Object.assign(config, {
949
+ extend: 'colVis'
950
+ })
951
+ ]
952
+ };
953
+ }
954
+ };
955
+
956
+ var reorder = {
957
+ defaults: {
958
+ className: 'reorder',
959
+ icon: 'move',
960
+ text: 'Reorder columns'
961
+ },
962
+ init: function (config) {
963
+ var _this = this;
964
+ var dt = this.dt();
965
+ var btn = new Button(dt, this)
966
+ .text(dt.i18n('columnControl.reorder', config.text))
967
+ .icon(config.icon)
968
+ .className(config.className);
969
+ // The event handling for this is done in ColReorder._addListener - no event
970
+ // handler needed here for click / drag
971
+ if (this.idx() === 0) {
972
+ btn.enable(false);
973
+ }
974
+ dt.on('columns-reordered', function (e, details) {
975
+ btn.enable(_this.idx() > 0);
976
+ });
977
+ // If ColReorder wasn't initialised on this DataTable, then we need to add it
978
+ if (!dt.init().colReorder) {
979
+ new DataTable.ColReorder(dt, {});
980
+ }
981
+ return btn.element();
982
+ }
983
+ };
984
+
985
+ var reorderLeft = {
986
+ defaults: {
987
+ className: 'reorderLeft',
988
+ icon: 'moveLeft',
989
+ text: 'Move column left'
990
+ },
991
+ init: function (config) {
992
+ var _this = this;
993
+ var dt = this.dt();
994
+ var btn = new Button(dt, this)
995
+ .text(dt.i18n('columnControl.reorderLeft', config.text))
996
+ .icon(config.icon)
997
+ .className(config.className)
998
+ .handler(function () {
999
+ var idx = _this.idx();
1000
+ // TODO account for visibility
1001
+ if (idx > 0) {
1002
+ dt.colReorder.move(idx, idx - 1);
1003
+ }
1004
+ });
1005
+ if (this.idx() === 0) {
1006
+ btn.enable(false);
1007
+ }
1008
+ dt.on('columns-reordered', function (e, details) {
1009
+ btn.enable(_this.idx() > 0);
1010
+ });
1011
+ return btn.element();
1012
+ }
1013
+ };
1014
+
1015
+ var reorderRight = {
1016
+ defaults: {
1017
+ className: 'reorderRight',
1018
+ icon: 'moveRight',
1019
+ text: 'Move column right'
1020
+ },
1021
+ init: function (config) {
1022
+ var _this = this;
1023
+ var dt = this.dt();
1024
+ var btn = new Button(dt, this)
1025
+ .text(dt.i18n('columnControl.reorderRight', config.text))
1026
+ .icon(config.icon)
1027
+ .className(config.className)
1028
+ .handler(function () {
1029
+ var idx = _this.idx();
1030
+ if (idx < dt.columns().count() - 1) {
1031
+ dt.colReorder.move(idx, idx + 1);
1032
+ }
1033
+ });
1034
+ if (this.idx() === dt.columns().count() - 1) {
1035
+ btn.enable(false);
1036
+ }
1037
+ dt.on('columns-reordered', function (e, details) {
1038
+ btn.enable(_this.idx() < dt.columns().count() - 1);
1039
+ });
1040
+ return btn.element();
1041
+ }
1042
+ };
1043
+
1044
+ var order = {
1045
+ defaults: {
1046
+ className: 'order',
1047
+ iconAsc: 'orderAsc',
1048
+ iconDesc: 'orderDesc',
1049
+ iconNone: 'orderNone',
1050
+ statusOnly: false,
1051
+ text: 'Toggle ordering'
1052
+ },
1053
+ init: function (config) {
1054
+ var _this = this;
1055
+ var dt = this.dt();
1056
+ var btn = new Button(dt, this)
1057
+ .text(dt.i18n('columnControl.order', config.text))
1058
+ .icon('orderAsc')
1059
+ .className(config.className);
1060
+ if (!config.statusOnly) {
1061
+ dt.order.listener(btn.element(), DataTable.versionCheck('2.3.2') ? function () { return [_this.idx()]; } : this.idx(), function () { });
1062
+ }
1063
+ dt.on('order', function (e, s, order) {
1064
+ var found = order.find(function (o) { return o.col === _this.idx(); });
1065
+ if (!found) {
1066
+ btn.active(false).icon(config.iconNone);
1067
+ }
1068
+ else if (found.dir === 'asc') {
1069
+ btn.active(true).icon(config.iconAsc);
1070
+ }
1071
+ else if (found.dir === 'desc') {
1072
+ btn.active(true).icon(config.iconDesc);
1073
+ }
1074
+ });
1075
+ return btn.element();
1076
+ }
1077
+ };
1078
+
1079
+ var orderAddAsc = {
1080
+ defaults: {
1081
+ className: 'orderAddAsc',
1082
+ icon: 'orderAddAsc',
1083
+ text: 'Add Sort Ascending'
1084
+ },
1085
+ init: function (config) {
1086
+ var _this = this;
1087
+ var dt = this.dt();
1088
+ var btn = new Button(dt, this)
1089
+ .text(dt.i18n('columnControl.orderAddAsc', config.text))
1090
+ .icon(config.icon)
1091
+ .className(config.className)
1092
+ .handler(function () {
1093
+ var order = dt.order();
1094
+ order.push([_this.idx(), 'asc']);
1095
+ dt.draw();
1096
+ });
1097
+ dt.on('order', function (e, s, order) {
1098
+ var found = order.some(function (o) { return o.col === _this.idx(); });
1099
+ btn.enable(!found);
1100
+ });
1101
+ return btn.element();
1102
+ }
1103
+ };
1104
+
1105
+ var orderAddDesc = {
1106
+ defaults: {
1107
+ className: 'orderAddDesc',
1108
+ icon: 'orderAddDesc',
1109
+ text: 'Add Sort Descending'
1110
+ },
1111
+ init: function (config) {
1112
+ var _this = this;
1113
+ var dt = this.dt();
1114
+ var btn = new Button(dt, this)
1115
+ .text(dt.i18n('columnControl.orderAddDesc', config.text))
1116
+ .icon(config.icon)
1117
+ .className(config.className)
1118
+ .handler(function () {
1119
+ var order = dt.order();
1120
+ order.push([_this.idx(), 'desc']);
1121
+ dt.draw();
1122
+ });
1123
+ dt.on('order', function (e, s, order) {
1124
+ var found = order.some(function (o) { return o.col === _this.idx(); });
1125
+ btn.enable(!found);
1126
+ });
1127
+ return btn.element();
1128
+ }
1129
+ };
1130
+
1131
+ var orderAsc = {
1132
+ defaults: {
1133
+ className: 'orderAsc',
1134
+ icon: 'orderAsc',
1135
+ text: 'Sort Ascending'
1136
+ },
1137
+ init: function (config) {
1138
+ var _this = this;
1139
+ var dt = this.dt();
1140
+ var btn = new Button(dt, this)
1141
+ .text(dt.i18n('columnControl.orderAsc', config.text))
1142
+ .icon(config.icon)
1143
+ .className(config.className)
1144
+ .handler(function () {
1145
+ _this.dt()
1146
+ .order([
1147
+ {
1148
+ idx: _this.idx(),
1149
+ dir: 'asc'
1150
+ }
1151
+ ])
1152
+ .draw();
1153
+ });
1154
+ dt.on('order', function (e, s, order) {
1155
+ var found = order.some(function (o) { return o.col === _this.idx() && o.dir === 'asc'; });
1156
+ btn.active(found);
1157
+ });
1158
+ return btn.element();
1159
+ }
1160
+ };
1161
+
1162
+ var orderClear = {
1163
+ defaults: {
1164
+ className: 'orderClear',
1165
+ icon: 'orderClear',
1166
+ text: 'Clear sort'
1167
+ },
1168
+ init: function (config) {
1169
+ var dt = this.dt();
1170
+ var btn = new Button(dt, this)
1171
+ .text(dt.i18n('columnControl.orderClear', config.text))
1172
+ .icon(config.icon)
1173
+ .className(config.className)
1174
+ .handler(function () {
1175
+ dt.order([]).draw();
1176
+ });
1177
+ dt.on('order', function (e, s, order) {
1178
+ btn.enable(order.length > 0);
1179
+ });
1180
+ if (dt.order().length === 0) {
1181
+ btn.enable(false);
1182
+ }
1183
+ return btn.element();
1184
+ }
1185
+ };
1186
+
1187
+ var orderDesc = {
1188
+ defaults: {
1189
+ className: 'orderDesc',
1190
+ icon: 'orderDesc',
1191
+ text: 'Sort Descending'
1192
+ },
1193
+ init: function (config) {
1194
+ var _this = this;
1195
+ var dt = this.dt();
1196
+ var btn = new Button(dt, this)
1197
+ .text(dt.i18n('columnControl.orderDesc', config.text))
1198
+ .icon(config.icon)
1199
+ .className(config.className)
1200
+ .handler(function () {
1201
+ _this.dt()
1202
+ .order([
1203
+ {
1204
+ idx: _this.idx(),
1205
+ dir: 'desc'
1206
+ }
1207
+ ])
1208
+ .draw();
1209
+ });
1210
+ dt.on('order', function (e, s, order) {
1211
+ var found = order.some(function (o) { return o.col === _this.idx() && o.dir === 'desc'; });
1212
+ btn.active(found);
1213
+ });
1214
+ return btn.element();
1215
+ }
1216
+ };
1217
+
1218
+ var orderRemove = {
1219
+ defaults: {
1220
+ className: 'orderRemove',
1221
+ icon: 'orderRemove',
1222
+ text: 'Remove from sort'
1223
+ },
1224
+ init: function (config) {
1225
+ var _this = this;
1226
+ var dt = this.dt();
1227
+ var btn = new Button(dt, this)
1228
+ .text(dt.i18n('columnControl.orderRemove', config.text))
1229
+ .icon(config.icon)
1230
+ .className(config.className)
1231
+ .handler(function () {
1232
+ // Remove the current column from the ordering array, then reorder the table
1233
+ var order = dt.order();
1234
+ var idx = order.findIndex(function (o) { return o[0] === _this.idx(); });
1235
+ order.splice(idx, 1);
1236
+ dt.order(order).draw();
1237
+ });
1238
+ dt.on('order', function (e, s, order) {
1239
+ var found = order.some(function (o) { return o.col === _this.idx(); });
1240
+ btn.enable(found);
1241
+ });
1242
+ btn.enable(false);
1243
+ return btn.element();
1244
+ }
1245
+ };
1246
+
1247
+ var orderStatus = {
1248
+ defaults: {
1249
+ className: 'order',
1250
+ iconAsc: 'orderAsc',
1251
+ iconDesc: 'orderDesc',
1252
+ iconNone: 'orderNone',
1253
+ statusOnly: true,
1254
+ text: 'Sort status'
1255
+ },
1256
+ extend: function (config) {
1257
+ return Object.assign(config, { extend: 'order' });
1258
+ }
1259
+ };
1260
+
1261
+ /**
1262
+ * Add an item to the grouping structure
1263
+ *
1264
+ * @param dt DataTable API instance
1265
+ * @param dataSrc Grouping data point to add
1266
+ * @returns Grouping array
1267
+ */
1268
+ function rowGroupAdd$1(dt, dataSrc) {
1269
+ var applied = rowGroupApplied(dt);
1270
+ var idx = applied.indexOf(dataSrc);
1271
+ if (idx === -1) {
1272
+ applied.push(dataSrc);
1273
+ dt.rowGroup().dataSrc(applied);
1274
+ }
1275
+ return applied;
1276
+ }
1277
+ /**
1278
+ * Always want an array return
1279
+ *
1280
+ * @param dt DataTable API instance
1281
+ * @returns
1282
+ */
1283
+ function rowGroupApplied(dt) {
1284
+ var applied = dt.rowGroup().dataSrc();
1285
+ return Array.isArray(applied)
1286
+ ? applied
1287
+ : [applied];
1288
+ }
1289
+ /**
1290
+ * Remove all grouping
1291
+ *
1292
+ * @param dt DataTable API instance
1293
+ */
1294
+ function rowGroupClear$1(dt) {
1295
+ dt.rowGroup().dataSrc([]);
1296
+ }
1297
+ /**
1298
+ * Remove an item from the grouping structure
1299
+ *
1300
+ * @param dt DataTable API instance
1301
+ * @param dataSrc Grouping data point to remove
1302
+ * @returns Grouping array
1303
+ */
1304
+ function rowGroupRemove$1(dt, dataSrc) {
1305
+ var applied = rowGroupApplied(dt);
1306
+ var idx = applied.indexOf(dataSrc);
1307
+ if (idx !== -1) {
1308
+ applied.splice(idx, 1);
1309
+ dt.rowGroup().dataSrc(applied);
1310
+ }
1311
+ return applied;
1312
+ }
1313
+ var rowGroup = {
1314
+ defaults: {
1315
+ className: 'rowGroup',
1316
+ icon: 'groupTop',
1317
+ order: true,
1318
+ text: 'Group rows'
1319
+ },
1320
+ init: function (config) {
1321
+ var _this = this;
1322
+ var dt = this.dt();
1323
+ var btn = new Button(dt, this)
1324
+ .text(dt.i18n('columnControl.rowGroup', config.text))
1325
+ .icon(config.icon)
1326
+ .className(config.className)
1327
+ .handler(function () {
1328
+ var dataSrc = dt.column(_this.idx()).dataSrc();
1329
+ if (btn.active()) {
1330
+ // Grouping is active - remove
1331
+ rowGroupRemove$1(dt, dataSrc);
1332
+ }
1333
+ else {
1334
+ // No grouping by this column yet, set it
1335
+ rowGroupClear$1(dt);
1336
+ rowGroupAdd$1(dt, dataSrc);
1337
+ if (config.order !== false) {
1338
+ dt.order([_this.idx(), 'asc']);
1339
+ }
1340
+ }
1341
+ dt.draw();
1342
+ });
1343
+ // Show as active when grouping is applied
1344
+ dt.on('rowgroup-datasrc', function () {
1345
+ var applied = rowGroupApplied(dt);
1346
+ var ours = dt.column(_this.idx()).dataSrc();
1347
+ btn.active(applied.includes(ours));
1348
+ });
1349
+ return btn.element();
1350
+ }
1351
+ };
1352
+
1353
+ var rowGroupAdd = {
1354
+ defaults: {
1355
+ className: 'rowGroupAdd',
1356
+ icon: 'groupAdd',
1357
+ order: true,
1358
+ text: 'Add to grouping'
1359
+ },
1360
+ init: function (config) {
1361
+ var _this = this;
1362
+ var dt = this.dt();
1363
+ var btn = new Button(dt, this)
1364
+ .text(dt.i18n('columnControl.rowGroup', config.text))
1365
+ .icon(config.icon)
1366
+ .className(config.className)
1367
+ .handler(function () {
1368
+ var dataSrc = dt.column(_this.idx()).dataSrc();
1369
+ if (btn.enable()) {
1370
+ // No grouping by this column yet, add it
1371
+ rowGroupAdd$1(dt, dataSrc);
1372
+ }
1373
+ dt.draw();
1374
+ });
1375
+ // Show as active when grouping is applied
1376
+ dt.on('rowgroup-datasrc', function () {
1377
+ var applied = rowGroupApplied(dt);
1378
+ var ours = dt.column(_this.idx()).dataSrc();
1379
+ btn.enable(!applied.includes(ours));
1380
+ });
1381
+ return btn.element();
1382
+ }
1383
+ };
1384
+
1385
+ var rowGroupClear = {
1386
+ defaults: {
1387
+ className: 'rowGroupClear',
1388
+ icon: 'groupClear',
1389
+ text: 'Clear all grouping'
1390
+ },
1391
+ init: function (config) {
1392
+ var dt = this.dt();
1393
+ var btn = new Button(dt, this)
1394
+ .text(dt.i18n('columnControl.rowGroup', config.text))
1395
+ .icon(config.icon)
1396
+ .className(config.className)
1397
+ .handler(function () {
1398
+ rowGroupClear$1(dt);
1399
+ dt.draw();
1400
+ });
1401
+ // Show as active when any grouping is applied
1402
+ dt.on('rowgroup-datasrc', function () {
1403
+ btn.enable(rowGroupApplied(dt).length > 0);
1404
+ });
1405
+ // Default status
1406
+ btn.enable(rowGroupApplied(dt).length > 0);
1407
+ return btn.element();
1408
+ }
1409
+ };
1410
+
1411
+ var rowGroupRemove = {
1412
+ defaults: {
1413
+ className: 'rowGroupRemove',
1414
+ icon: 'groupRemove',
1415
+ order: true,
1416
+ text: 'Remove from grouping'
1417
+ },
1418
+ init: function (config) {
1419
+ var _this = this;
1420
+ var dt = this.dt();
1421
+ var btn = new Button(dt, this)
1422
+ .text(dt.i18n('columnControl.rowGroup', config.text))
1423
+ .icon(config.icon)
1424
+ .className(config.className)
1425
+ .handler(function () {
1426
+ var dataSrc = dt.column(_this.idx()).dataSrc();
1427
+ if (btn.enable()) {
1428
+ // Grouping is active - remove
1429
+ rowGroupRemove$1(dt, dataSrc);
1430
+ dt.draw();
1431
+ }
1432
+ });
1433
+ // Show as active when grouping is applied
1434
+ dt.on('rowgroup-datasrc', function () {
1435
+ var applied = rowGroupApplied(dt);
1436
+ var ours = dt.column(_this.idx()).dataSrc();
1437
+ btn.enable(applied.includes(ours));
1438
+ });
1439
+ // Default disabled
1440
+ btn.enable(false);
1441
+ return btn.element();
1442
+ }
1443
+ };
1444
+
1445
+ var SearchInput = /** @class */ (function () {
1446
+ /**
1447
+ * Create a container element, for consistent DOM structure and styling
1448
+ */
1449
+ function SearchInput(dt, idx) {
1450
+ var _this = this;
1451
+ this._type = 'text';
1452
+ this._sspTransform = null;
1453
+ this._sspData = {};
1454
+ this._dt = dt;
1455
+ this._idx = idx;
1456
+ this._dom = {
1457
+ clear: createElement('span', 'dtcc-search-clear', icons['x']),
1458
+ container: createElement('div', SearchInput.classes.container),
1459
+ typeIcon: createElement('div', 'dtcc-search-type-icon'),
1460
+ searchIcon: createElement('div', 'dtcc-search-icon', icons['search']),
1461
+ input: createElement('input', SearchInput.classes.input),
1462
+ inputs: createElement('div'),
1463
+ select: createElement('select', SearchInput.classes.select),
1464
+ title: createElement('div', 'dtcc-search-title')
1465
+ };
1466
+ var dom = this._dom;
1467
+ var originalIdx = idx;
1468
+ dom.input.setAttribute('type', 'text');
1469
+ dom.container.append(dom.title, dom.inputs);
1470
+ dom.inputs.append(dom.typeIcon, dom.select, dom.searchIcon, dom.clear, dom.input);
1471
+ // Listeners
1472
+ var inputInput = function () {
1473
+ _this.runSearch();
1474
+ };
1475
+ var selectInput = function () {
1476
+ dom.typeIcon.innerHTML = icons[dom.select.value];
1477
+ _this.runSearch();
1478
+ };
1479
+ var clearClick = function () {
1480
+ _this.clear();
1481
+ };
1482
+ dom.input.addEventListener('input', inputInput);
1483
+ dom.select.addEventListener('input', selectInput);
1484
+ dom.clear.addEventListener('click', clearClick);
1485
+ dt.on('destroy', function () {
1486
+ dom.input.removeEventListener('input', inputInput);
1487
+ dom.select.removeEventListener('input', selectInput);
1488
+ dom.clear.removeEventListener('click', clearClick);
1489
+ });
1490
+ // State handling - all components that use this class have the same state saving structure
1491
+ // so shared handling can be performed here.
1492
+ dt.on('stateSaveParams.DT', function (e, s, data) {
1493
+ if (!data.columnControl) {
1494
+ data.columnControl = {};
1495
+ }
1496
+ if (!data.columnControl[_this._idx]) {
1497
+ data.columnControl[_this._idx] = {};
1498
+ }
1499
+ data.columnControl[_this._idx].searchInput = {
1500
+ logic: dom.select.value,
1501
+ type: _this._type,
1502
+ value: dom.input.value
1503
+ };
1504
+ });
1505
+ dt.on('stateLoaded.DT', function (e, s, state) {
1506
+ _this._stateLoad(state);
1507
+ });
1508
+ // Same as for ColumnControl - reassign a column index if needed.
1509
+ dt.on('columns-reordered.DT', function (e, details) {
1510
+ _this._idx = dt.colReorder.transpose(originalIdx, 'fromOriginal');
1511
+ });
1512
+ // Column control search clearing (column().columnControl.searchClear() method)
1513
+ dt.on('cc-search-clear.DT', function (e, colIdx) {
1514
+ if (colIdx === _this._idx) {
1515
+ // Don't want an automatic redraw on this event
1516
+ _this._loadingState = true;
1517
+ _this.clear();
1518
+ _this._loadingState = false;
1519
+ }
1520
+ });
1521
+ // Data for server-side processing
1522
+ if (dt.page.info().serverSide) {
1523
+ dt.on('preXhr.DT', function (e, s, d) {
1524
+ // The column has been removed from the submit data - can't do anything
1525
+ if (!d.columns || !d.columns[_this._idx]) {
1526
+ return;
1527
+ }
1528
+ if (!d.columns[_this._idx].columnControl) {
1529
+ d.columns[_this._idx].columnControl = {};
1530
+ }
1531
+ var val = _this._dom.input.value;
1532
+ if (_this._sspTransform) {
1533
+ val = _this._sspTransform(val);
1534
+ }
1535
+ d.columns[_this._idx].columnControl.search = Object.assign({
1536
+ value: val,
1537
+ logic: _this._dom.select.value,
1538
+ type: _this._type
1539
+ }, _this._sspData);
1540
+ });
1541
+ }
1542
+ }
1543
+ /**
1544
+ * Add a class to the container
1545
+ *
1546
+ * @param name Class name to add
1547
+ * @returns Self for chaining
1548
+ */
1549
+ SearchInput.prototype.addClass = function (name) {
1550
+ this._dom.container.classList.add(name);
1551
+ return this;
1552
+ };
1553
+ /**
1554
+ * Clear any applied search
1555
+ *
1556
+ * @returns Self for chaining
1557
+ */
1558
+ SearchInput.prototype.clear = function () {
1559
+ this.set(this._dom.select.children[0].getAttribute('value'), '');
1560
+ return this;
1561
+ };
1562
+ /**
1563
+ * Set the clear icon feature can be used or not
1564
+ *
1565
+ * @param set Flag
1566
+ * @returns Self for chaining
1567
+ */
1568
+ SearchInput.prototype.clearable = function (set) {
1569
+ // Note there is no add here as it is added by default and never used after setup, so
1570
+ // no need.
1571
+ if (!set) {
1572
+ this._dom.clear.remove();
1573
+ }
1574
+ return this;
1575
+ };
1576
+ /**
1577
+ * Get the container element
1578
+ *
1579
+ * @returns The container element
1580
+ */
1581
+ SearchInput.prototype.element = function () {
1582
+ return this._dom.container;
1583
+ };
1584
+ /**
1585
+ * Get the HTML input element for this control
1586
+ *
1587
+ * @returns HTML Input element
1588
+ */
1589
+ SearchInput.prototype.input = function () {
1590
+ return this._dom.input;
1591
+ };
1592
+ /**
1593
+ * Set the list of options for the dropdown
1594
+ *
1595
+ * @param opts List of options
1596
+ * @returns Self for chaining
1597
+ */
1598
+ SearchInput.prototype.options = function (opts) {
1599
+ var select = this._dom.select;
1600
+ for (var i = 0; i < opts.length; i++) {
1601
+ select.add(new Option(opts[i].label, opts[i].value));
1602
+ }
1603
+ // Initial icon
1604
+ this._dom.typeIcon.innerHTML = icons[opts[0].value];
1605
+ return this;
1606
+ };
1607
+ /**
1608
+ * Set the placeholder attribute for the input element
1609
+ *
1610
+ * @param placeholder Placeholder string
1611
+ * @returns Self for chaining
1612
+ */
1613
+ SearchInput.prototype.placeholder = function (placeholder) {
1614
+ if (placeholder) {
1615
+ var columnTitle = this._dt.column(this._idx).title();
1616
+ this._dom.input.placeholder = placeholder.replace('[title]', columnTitle);
1617
+ }
1618
+ return this;
1619
+ };
1620
+ /**
1621
+ * Run the search method
1622
+ */
1623
+ SearchInput.prototype.runSearch = function () {
1624
+ var dom = this._dom;
1625
+ var isActive = dom.select.value === 'empty' ||
1626
+ dom.select.value === 'notEmpty' ||
1627
+ dom.input.value !== '';
1628
+ dom.container.classList.toggle('dtcc-search_active', isActive);
1629
+ if (this._search &&
1630
+ (this._lastValue !== dom.input.value || this._lastType !== dom.select.value)) {
1631
+ this._search(dom.select.value, dom.input.value, this._loadingState);
1632
+ this._lastValue = dom.input.value;
1633
+ this._lastType = dom.select.value;
1634
+ }
1635
+ };
1636
+ /**
1637
+ * Set the function that will be run when a search operation is required. Note that this can
1638
+ * trigger the function to run if there is a saved state.
1639
+ *
1640
+ * @param fn Search callback
1641
+ * @returns Self for chaining
1642
+ */
1643
+ SearchInput.prototype.search = function (fn) {
1644
+ this._search = fn;
1645
+ // If there is a saved state, load it now that set up is done.
1646
+ this._stateLoad(this._dt.state.loaded());
1647
+ return this;
1648
+ };
1649
+ /**
1650
+ * Set a value for the search input
1651
+ *
1652
+ * @param logic Logic type
1653
+ * @param val Value
1654
+ * @returns Self for chaining
1655
+ */
1656
+ SearchInput.prototype.set = function (logic, val) {
1657
+ var dom = this._dom;
1658
+ dom.input.value = val;
1659
+ dom.select.value = logic;
1660
+ dom.typeIcon.innerHTML = icons[dom.select.value];
1661
+ this.runSearch();
1662
+ return this;
1663
+ };
1664
+ /**
1665
+ * Set a function to transform the input value before SSP data submission
1666
+ *
1667
+ * @param fn Transform function
1668
+ * @returns Self for chaining
1669
+ */
1670
+ SearchInput.prototype.sspTransform = function (fn) {
1671
+ this._sspTransform = fn;
1672
+ return this;
1673
+ };
1674
+ /**
1675
+ * Set extra information to be send to the server for server-side processing
1676
+ *
1677
+ * @param data Data object
1678
+ * @returns Self for chaining
1679
+ */
1680
+ SearchInput.prototype.sspData = function (data) {
1681
+ this._sspData = data;
1682
+ return this;
1683
+ };
1684
+ /**
1685
+ * Set the text that will be shown as the title for the control
1686
+ *
1687
+ * @param text Set the title text
1688
+ * @returns Self for chaining
1689
+ */
1690
+ SearchInput.prototype.title = function (text) {
1691
+ if (text) {
1692
+ var columnTitle = this._dt.column(this._idx).title();
1693
+ this._dom.title.innerHTML = text.replace('[title]', columnTitle);
1694
+ }
1695
+ return this;
1696
+ };
1697
+ /**
1698
+ * Set the title attribute for the input element
1699
+ *
1700
+ * @param title Title attribute string
1701
+ * @returns Self for chaining
1702
+ */
1703
+ SearchInput.prototype.titleAttr = function (title) {
1704
+ if (title) {
1705
+ var columnTitle = this._dt.column(this._idx).title();
1706
+ this._dom.input.title = title.replace('[title]', columnTitle);
1707
+ }
1708
+ return this;
1709
+ };
1710
+ SearchInput.prototype.type = function (t) {
1711
+ this._type = t;
1712
+ return this;
1713
+ };
1714
+ /**
1715
+ * Load a DataTables state
1716
+ *
1717
+ * @param state State object being loaded
1718
+ */
1719
+ SearchInput.prototype._stateLoad = function (state) {
1720
+ var _a, _b;
1721
+ var dom = this._dom;
1722
+ var idx = this._idx;
1723
+ var loadedState = (_b = (_a = state === null || state === void 0 ? void 0 : state.columnControl) === null || _a === void 0 ? void 0 : _a[idx]) === null || _b === void 0 ? void 0 : _b.searchInput;
1724
+ if (loadedState) {
1725
+ // The search callback needs to know if we are loading an existing state or not
1726
+ // so it can determine if it needs to draw the table. If it was a user input, then
1727
+ // it redraws, if it was a state load, then there should be no redraw.
1728
+ this._loadingState = true;
1729
+ dom.select.value = loadedState.logic;
1730
+ dom.input.value = loadedState.value;
1731
+ dom.select.dispatchEvent(new Event('input'));
1732
+ this._loadingState = false;
1733
+ }
1734
+ };
1735
+ SearchInput.classes = {
1736
+ container: ['dtcc-content', 'dtcc-search'],
1737
+ input: '',
1738
+ select: ''
1739
+ };
1740
+ return SearchInput;
1741
+ }());
1742
+
1743
+ var searchDateTime = {
1744
+ defaults: {
1745
+ clear: true,
1746
+ format: '',
1747
+ mask: '',
1748
+ placeholder: '',
1749
+ title: '',
1750
+ titleAttr: ''
1751
+ },
1752
+ init: function (config) {
1753
+ var _this = this;
1754
+ var fromPicker = false;
1755
+ var moment = DataTable.use('moment');
1756
+ var luxon = DataTable.use('luxon');
1757
+ var dt = this.dt();
1758
+ var i18nBase = 'columnControl.search.datetime.';
1759
+ var pickerFormat = '';
1760
+ var dataSrcFormat = '';
1761
+ var dateTime;
1762
+ var searchInput = new SearchInput(dt, this.idx())
1763
+ .type('date')
1764
+ .addClass('dtcc-searchDateTime')
1765
+ .sspTransform(function (val) { return toISO(val, pickerFormat, moment, luxon); })
1766
+ .sspData({ mask: config.mask })
1767
+ .clearable(config.clear)
1768
+ .placeholder(config.placeholder)
1769
+ .title(config.title)
1770
+ .titleAttr(config.titleAttr)
1771
+ .options([
1772
+ { label: dt.i18n(i18nBase + 'equal', 'Equals'), value: 'equal' },
1773
+ { label: dt.i18n(i18nBase + 'notEqual', 'Does not equal'), value: 'notEqual' },
1774
+ { label: dt.i18n(i18nBase + 'greater', 'After'), value: 'greater' },
1775
+ { label: dt.i18n(i18nBase + 'less', 'Before'), value: 'less' },
1776
+ { label: dt.i18n(i18nBase + 'empty', 'Empty'), value: 'empty' },
1777
+ { label: dt.i18n(i18nBase + 'notEmpty', 'Not empty'), value: 'notEmpty' }
1778
+ ])
1779
+ .search(function (searchType, searchTerm, loadingState) {
1780
+ // When SSP, don't apply a filter here, SearchInput will add to the submit data
1781
+ if (dt.page.info().serverSide) {
1782
+ if (!loadingState) {
1783
+ dt.draw();
1784
+ }
1785
+ return;
1786
+ }
1787
+ var mask = config.mask;
1788
+ var column = dt.column(_this.idx());
1789
+ var search = searchTerm === ''
1790
+ ? ''
1791
+ : dateToNum(dateTime && fromPicker ? dateTime.val() : searchTerm.trim(), pickerFormat, moment, luxon, mask);
1792
+ if (searchType === 'empty') {
1793
+ column.search.fixed('dtcc', function (haystack) { return !haystack; });
1794
+ }
1795
+ else if (searchType === 'notEmpty') {
1796
+ column.search.fixed('dtcc', function (haystack) { return !!haystack; });
1797
+ }
1798
+ else if (column.search.fixed('dtcc') === '' && search === '') {
1799
+ // No change - don't do anything
1800
+ return;
1801
+ }
1802
+ else if (!search) {
1803
+ // Clear search
1804
+ column.search.fixed('dtcc', '');
1805
+ }
1806
+ else if (searchType === 'equal') {
1807
+ // Use a function for matching - weak typing
1808
+ // Note that the haystack in the search function is the rendered date - it
1809
+ // might need to be converted back to a date
1810
+ column.search.fixed('dtcc', function (haystack) {
1811
+ return dateToNum(haystack, dataSrcFormat, moment, luxon, mask) == search;
1812
+ });
1813
+ }
1814
+ else if (searchType === 'notEqual') {
1815
+ column.search.fixed('dtcc', function (haystack) {
1816
+ return dateToNum(haystack, dataSrcFormat, moment, luxon, mask) != search;
1817
+ });
1818
+ }
1819
+ else if (searchType === 'greater') {
1820
+ column.search.fixed('dtcc', function (haystack) {
1821
+ return dateToNum(haystack, dataSrcFormat, moment, luxon, mask) > search;
1822
+ });
1823
+ }
1824
+ else if (searchType === 'less') {
1825
+ column.search.fixed('dtcc', function (haystack) {
1826
+ return dateToNum(haystack, dataSrcFormat, moment, luxon, mask) < search;
1827
+ });
1828
+ }
1829
+ // If in a dropdown, set the parent levels as active
1830
+ if (config._parents) {
1831
+ config._parents.forEach(function (btn) {
1832
+ return btn.activeList(_this.unique(), !!column.search.fixed('dtcc'));
1833
+ });
1834
+ }
1835
+ if (!loadingState) {
1836
+ column.draw();
1837
+ }
1838
+ });
1839
+ // Once data has been loaded we can run DateTime with the specified format
1840
+ dt.ready(function () {
1841
+ var DateTime = DataTable.use('datetime');
1842
+ dataSrcFormat = getFormat(dt, _this.idx());
1843
+ pickerFormat = config.format
1844
+ ? config.format
1845
+ : dataSrcFormat;
1846
+ if (DateTime) {
1847
+ dateTime = new DateTime(searchInput.input(), {
1848
+ format: pickerFormat,
1849
+ i18n: dt.settings()[0].oLanguage.datetime, // could be undefined
1850
+ onChange: function () {
1851
+ fromPicker = true;
1852
+ searchInput.runSearch();
1853
+ fromPicker = false;
1854
+ }
1855
+ });
1856
+ }
1857
+ });
1858
+ return searchInput.element();
1859
+ }
1860
+ };
1861
+ /**
1862
+ * Determine the formatting string for the date time information in the colum
1863
+ *
1864
+ * @param dt DataTable instance
1865
+ * @param column Column index
1866
+ * @returns Date / time formatting string
1867
+ */
1868
+ function getFormat(dt, column) {
1869
+ var type = dt.column(column).type();
1870
+ if (!type) {
1871
+ // Assume that it is ISO unless otherwise specified - that is all DataTables can do anyway
1872
+ return 'YYYY-MM-DD';
1873
+ }
1874
+ else if (type === 'datetime') {
1875
+ // If no format was specified in the DT type, a Javascript native toLocaleDateString
1876
+ // was used. Need to work out what that format is in Moment or Luxon. We need to pass
1877
+ // a known value though the renderer and work out the format
1878
+ var renderer = dt.settings()[0].aoColumns[column].mRender;
1879
+ var resultPm = renderer('1999-08-07T23:05:04Z', 'display');
1880
+ var resultAm = renderer('1999-08-07T03:05:04Z', 'display');
1881
+ var leadingZero = resultAm.includes('03');
1882
+ // What formatter are we using?
1883
+ if (DataTable.use('moment')) {
1884
+ return resultPm
1885
+ .replace('23', leadingZero ? 'HH' : 'H')
1886
+ .replace('11', leadingZero ? 'hh' : 'h')
1887
+ .replace('05', 'mm')
1888
+ .replace('04', 'ss')
1889
+ .replace('PM', 'A')
1890
+ .replace('pm', 'a')
1891
+ .replace('07', 'DD')
1892
+ .replace('7', 'D')
1893
+ .replace('08', 'MM')
1894
+ .replace('8', 'M')
1895
+ .replace('1999', 'YYYY')
1896
+ .replace('99', 'YY');
1897
+ }
1898
+ else if (DataTable.use('luxon')) {
1899
+ return resultPm
1900
+ .replace('23', leadingZero ? 'HH' : 'H')
1901
+ .replace('11', leadingZero ? 'hh' : 'h')
1902
+ .replace('05', 'mm')
1903
+ .replace('04', 'ss')
1904
+ .replace('PM', 'a')
1905
+ .replace('07', 'dd')
1906
+ .replace('7', 'd')
1907
+ .replace('08', 'MM')
1908
+ .replace('8', 'M')
1909
+ .replace('1999', 'yyyy')
1910
+ .replace('99', 'yy');
1911
+ }
1912
+ else if (resultPm.includes('23') && resultPm.includes('1999')) {
1913
+ return 'YYYY-MM-DD hh:mm:ss';
1914
+ }
1915
+ else if (resultPm.includes('23')) {
1916
+ return 'hh:mm:ss';
1917
+ }
1918
+ // fall through to final return
1919
+ }
1920
+ else if (type.includes('datetime-')) {
1921
+ // Column was specified with a particular display format - we can extract that format from
1922
+ // the type, as it is part of the type name.
1923
+ return type.replace(/datetime-/g, '');
1924
+ }
1925
+ else if (type.includes('moment')) {
1926
+ return type.replace(/moment-/g, '');
1927
+ }
1928
+ else if (type.includes('luxon')) {
1929
+ return type.replace(/luxon-/g, '');
1930
+ }
1931
+ return 'YYYY-MM-DD';
1932
+ }
1933
+ /**
1934
+ * Convert from a source date / time value (usually a string) to a timestamp for comparisons.
1935
+ *
1936
+ * @param input Input value
1937
+ * @param srcFormat String format of the input
1938
+ * @param moment Moment instance, if it is available
1939
+ * @param luxon Luxon object, if it is available
1940
+ * @returns Time stamp - milliseconds
1941
+ */
1942
+ function dateToNum(input, srcFormat, moment, luxon, mask) {
1943
+ var d;
1944
+ if (input === '') {
1945
+ return '';
1946
+ }
1947
+ if (input instanceof Date) {
1948
+ d = input;
1949
+ }
1950
+ else if (srcFormat !== 'YYYY-MM-DD' && (moment || luxon)) {
1951
+ d = new Date(moment
1952
+ ? moment(input, srcFormat).unix() * 1000
1953
+ : luxon.DateTime.fromFormat(input, srcFormat).toMillis());
1954
+ }
1955
+ else {
1956
+ // new Date() with `/` separators will treat the input as local time, but with `-` it will
1957
+ // treat it as UTC. We want UTC so do a replacement
1958
+ d = new Date(input.replace(/\//g, '-'));
1959
+ }
1960
+ if (mask) {
1961
+ if (!mask.includes('YYYY')) {
1962
+ d.setFullYear(1970);
1963
+ }
1964
+ if (!mask.includes('MM')) {
1965
+ d.setUTCMonth(0);
1966
+ }
1967
+ if (!mask.includes('DD')) {
1968
+ d.setUTCDate(1);
1969
+ }
1970
+ if (!mask.includes('hh')) {
1971
+ d.setUTCHours(0);
1972
+ }
1973
+ if (!mask.includes('mm')) {
1974
+ d.setUTCMinutes(0);
1975
+ }
1976
+ if (!mask.includes('ss')) {
1977
+ // This will match milliseconds as well, but that's fine, you won't match mS but not S
1978
+ d.setUTCSeconds(0);
1979
+ }
1980
+ if (!mask.includes('sss')) {
1981
+ d.setUTCMilliseconds(0);
1982
+ }
1983
+ }
1984
+ return d.getTime();
1985
+ }
1986
+ /**
1987
+ * Convert an input string to an ISO formatted date
1988
+ *
1989
+ * @param input Input value
1990
+ * @param srcFormat String format of the input
1991
+ * @param moment Moment instance, if it is available
1992
+ * @param luxon Luxon object, if it is available
1993
+ * @returns Value in ISO
1994
+ */
1995
+ function toISO(input, srcFormat, moment, luxon) {
1996
+ if (input === '') {
1997
+ return '';
1998
+ }
1999
+ else if (srcFormat !== 'YYYY-MM-DD' && moment) {
2000
+ // TODO Does it have a time component?
2001
+ return moment.utc(input, srcFormat).toISOString();
2002
+ }
2003
+ else if (srcFormat !== 'YYYY-MM-DD' && luxon) {
2004
+ // TODO Does it have a time component?
2005
+ return luxon.DateTime.fromFormat(input, srcFormat).toISO();
2006
+ }
2007
+ // new Date() with `/` separators will treat the input as local time, but with `-` it will
2008
+ // treat it as UTC. We want UTC so do a replacement
2009
+ input = input.replace(/\//g, '-');
2010
+ return input;
2011
+ }
2012
+
2013
+ /** Set the options to show in the list */
2014
+ function setOptions(checkList, opts) {
2015
+ var existing = checkList.values();
2016
+ checkList.clear();
2017
+ for (var i = 0; i < opts.length; i++) {
2018
+ if (typeof opts[i] === 'object') {
2019
+ checkList.add({
2020
+ active: false,
2021
+ label: opts[i].label,
2022
+ value: opts[i].value
2023
+ }, i === opts.length - 1);
2024
+ }
2025
+ else {
2026
+ checkList.add({
2027
+ active: false,
2028
+ label: opts[i],
2029
+ value: opts[i]
2030
+ }, i === opts.length - 1);
2031
+ }
2032
+ }
2033
+ if (existing.length) {
2034
+ checkList.values(existing);
2035
+ }
2036
+ }
2037
+ /** Load a saved state */
2038
+ function getState(columnIdx, state) {
2039
+ var _a, _b;
2040
+ var loadedState = (_b = (_a = state === null || state === void 0 ? void 0 : state.columnControl) === null || _a === void 0 ? void 0 : _a[columnIdx]) === null || _b === void 0 ? void 0 : _b.searchList;
2041
+ if (loadedState) {
2042
+ return loadedState;
2043
+ }
2044
+ }
2045
+ /** Get the options for a column from a DT JSON object */
2046
+ function getJsonOptions(dt, idx) {
2047
+ var _a;
2048
+ var json = (_a = dt.ajax.json()) === null || _a === void 0 ? void 0 : _a.columnControl;
2049
+ var column = dt.column(idx);
2050
+ var name = column.name();
2051
+ var dataSrc = column.dataSrc();
2052
+ if (json && json[name]) {
2053
+ // Found options matching the column's name - top priority
2054
+ return json[name];
2055
+ }
2056
+ else if (json && typeof dataSrc === 'string' && json[dataSrc]) {
2057
+ // Found options matching the column's data source string
2058
+ return json[dataSrc];
2059
+ }
2060
+ else if (json && json[idx]) {
2061
+ // Found options matching the column's data index
2062
+ return json[idx];
2063
+ }
2064
+ return null;
2065
+ }
2066
+ function reloadOptions(dt, config, idx, checkList, loadedValues) {
2067
+ var _a;
2068
+ // Was there options specified in the Ajax return?
2069
+ var json = (_a = dt.ajax.json()) === null || _a === void 0 ? void 0 : _a.columnControl;
2070
+ var options = [];
2071
+ var jsonOptions = getJsonOptions(dt, idx);
2072
+ if (jsonOptions) {
2073
+ options = jsonOptions;
2074
+ }
2075
+ else if (json && config.ajaxOnly) {
2076
+ if (config.hidable) {
2077
+ // Ajax only options - need to hide the search list
2078
+ checkList.element().style.display = 'none';
2079
+ // Check if the parent buttons should be hidden as well (they will be if there
2080
+ // is no visible content in them)
2081
+ if (config._parents) {
2082
+ config._parents.forEach(function (btn) { return btn.checkDisplay(); });
2083
+ }
2084
+ }
2085
+ // No point in doing any further processing here
2086
+ return;
2087
+ }
2088
+ else if (!dt.page.info().serverSide) {
2089
+ // Either no ajax object (i.e. not an Ajax table), or no matching ajax options
2090
+ // for this column - get the values for the column, taking into account
2091
+ // orthogonal rendering
2092
+ var found = {};
2093
+ var rows = dt.rows({ order: idx }).indexes().toArray();
2094
+ var settings = dt.settings()[0];
2095
+ for (var i = 0; i < rows.length; i++) {
2096
+ var raw = settings.fastData(rows[i], idx, 'filter');
2097
+ var filter = raw !== null && raw !== undefined
2098
+ ? raw.toString()
2099
+ : '';
2100
+ if (!found[filter]) {
2101
+ found[filter] = true;
2102
+ options.push({
2103
+ label: settings.fastData(rows[i], idx, config.orthogonal),
2104
+ value: filter
2105
+ });
2106
+ }
2107
+ }
2108
+ }
2109
+ setOptions(checkList, options);
2110
+ // If there was a state loaded at start up, then we need to set the visual
2111
+ // appearance to match
2112
+ if (loadedValues) {
2113
+ checkList.values(loadedValues);
2114
+ }
2115
+ }
2116
+ var searchList = {
2117
+ defaults: {
2118
+ ajaxOnly: true,
2119
+ className: 'searchList',
2120
+ hidable: true,
2121
+ options: null,
2122
+ orthogonal: 'display',
2123
+ search: true,
2124
+ select: true,
2125
+ title: ''
2126
+ },
2127
+ init: function (config) {
2128
+ var _this = this;
2129
+ var loadedValues = null;
2130
+ var dt = this.dt();
2131
+ // The search can be applied from a stored start at start up before the options are
2132
+ // available. It can also be applied by user input, so it is generalised into this function.
2133
+ var applySearch = function (values) {
2134
+ // When SSP, don't do any client-side filtering
2135
+ if (dt.page.info().serverSide) {
2136
+ return;
2137
+ }
2138
+ var col = dt.column(_this.idx());
2139
+ if (!values) {
2140
+ return;
2141
+ }
2142
+ else if (values.length === 0) {
2143
+ // Nothing selected - clear the filter
2144
+ col.search.fixed('dtcc-list', '');
2145
+ }
2146
+ else {
2147
+ // Find all matching options from the list of values
2148
+ col.search.fixed('dtcc-list', function (val) {
2149
+ return values.includes(val);
2150
+ });
2151
+ }
2152
+ // If in a dropdown, set the parent levels as active
2153
+ if (config._parents) {
2154
+ config._parents.forEach(function (btn) { return btn.activeList(_this.unique(), !!values.length); });
2155
+ }
2156
+ };
2157
+ var checkList = new CheckList(dt, this, {
2158
+ search: config.search,
2159
+ select: config.select
2160
+ })
2161
+ .searchListener(dt)
2162
+ .title(dt
2163
+ .i18n('columnControl.searchList', config.title)
2164
+ .replace('[title]', dt.column(this.idx()).title()))
2165
+ .handler(function (e, btn, btns, redraw) {
2166
+ if (btn) {
2167
+ btn.active(!btn.active());
2168
+ }
2169
+ applySearch(checkList.values());
2170
+ if (redraw) {
2171
+ dt.draw();
2172
+ }
2173
+ });
2174
+ if (config.options) {
2175
+ setOptions(checkList, config.options);
2176
+ }
2177
+ else {
2178
+ dt.ready(function () {
2179
+ reloadOptions(dt, config, _this.idx(), checkList, loadedValues);
2180
+ });
2181
+ // Xhr event listener for updates of options
2182
+ dt.on('xhr', function (e, s, json) {
2183
+ // Need to wait for the draw to complete so the table has the latest data
2184
+ dt.one('draw', function () {
2185
+ reloadOptions(dt, config, _this.idx(), checkList, loadedValues);
2186
+ });
2187
+ });
2188
+ }
2189
+ // Data for server-side processing
2190
+ if (dt.page.info().serverSide) {
2191
+ dt.on('preXhr.DT', function (e, s, d) {
2192
+ // The column has been removed from the submit data - can't do anything
2193
+ if (!d.columns || !d.columns[_this.idx()]) {
2194
+ return;
2195
+ }
2196
+ if (!d.columns[_this.idx()].columnControl) {
2197
+ d.columns[_this.idx()].columnControl = {};
2198
+ }
2199
+ // We need the indexes in the HTTP parameter names (for .NET), so use an object.
2200
+ d.columns[_this.idx()].columnControl.list = Object.assign({}, checkList.values());
2201
+ });
2202
+ }
2203
+ // Unlike the SearchInput based search contents, CheckList does not handle state saving
2204
+ // (since the mechanism for column visibility is different), so state saving is handled
2205
+ // here.
2206
+ dt.on('stateLoaded', function (e, s, state) {
2207
+ var values = getState(_this.idx(), state);
2208
+ if (values) {
2209
+ checkList.values(values);
2210
+ applySearch(values);
2211
+ }
2212
+ });
2213
+ dt.on('stateSaveParams', function (e, s, data) {
2214
+ var idx = _this.idx();
2215
+ if (!data.columnControl) {
2216
+ data.columnControl = {};
2217
+ }
2218
+ if (!data.columnControl[idx]) {
2219
+ data.columnControl[idx] = {};
2220
+ }
2221
+ // If the table isn't yet ready, then the options for the list won't have been
2222
+ // populated (above) and therefore there can't be an values. In such a case
2223
+ // use the last saved values and this will refresh on the next draw.
2224
+ data.columnControl[idx].searchList = dt.ready()
2225
+ ? checkList.values()
2226
+ : loadedValues;
2227
+ });
2228
+ dt.settings()[0].aoColumns[this.idx()].columnControlSearchList = function (options) {
2229
+ if (options === 'refresh') {
2230
+ reloadOptions(dt, config, _this.idx(), checkList, null);
2231
+ }
2232
+ else {
2233
+ setOptions(checkList, options);
2234
+ }
2235
+ };
2236
+ loadedValues = getState(this.idx(), dt.state.loaded());
2237
+ applySearch(loadedValues);
2238
+ return checkList.element();
2239
+ }
2240
+ };
2241
+
2242
+ var searchNumber = {
2243
+ defaults: {
2244
+ clear: true,
2245
+ placeholder: '',
2246
+ title: '',
2247
+ titleAttr: ''
2248
+ },
2249
+ init: function (config) {
2250
+ var _this = this;
2251
+ var dt = this.dt();
2252
+ var i18nBase = 'columnControl.search.number.';
2253
+ var searchInput = new SearchInput(dt, this.idx())
2254
+ .type('num')
2255
+ .addClass('dtcc-searchNumber')
2256
+ .clearable(config.clear)
2257
+ .placeholder(config.placeholder)
2258
+ .title(config.title)
2259
+ .titleAttr(config.titleAttr)
2260
+ .options([
2261
+ { label: dt.i18n(i18nBase + 'equal', 'Equals'), value: 'equal' },
2262
+ { label: dt.i18n(i18nBase + 'notEqual', 'Does not equal'), value: 'notEqual' },
2263
+ { label: dt.i18n(i18nBase + 'greater', 'Greater than'), value: 'greater' },
2264
+ {
2265
+ label: dt.i18n(i18nBase + 'greaterOrEqual', 'Greater or equal'),
2266
+ value: 'greaterOrEqual'
2267
+ },
2268
+ { label: dt.i18n(i18nBase + 'less', 'Less than'), value: 'less' },
2269
+ { label: dt.i18n(i18nBase + 'lessOrEqual', 'Less or equal'), value: 'lessOrEqual' },
2270
+ { label: dt.i18n(i18nBase + 'empty', 'Empty'), value: 'empty' },
2271
+ { label: dt.i18n(i18nBase + 'notEmpty', 'Not empty'), value: 'notEmpty' }
2272
+ ])
2273
+ .search(function (searchType, searchTerm, loadingState) {
2274
+ // When SSP, don't apply a filter here, SearchInput will add to the submit data
2275
+ if (dt.page.info().serverSide) {
2276
+ if (!loadingState) {
2277
+ dt.draw();
2278
+ }
2279
+ return;
2280
+ }
2281
+ var column = dt.column(_this.idx());
2282
+ if (searchType === 'empty') {
2283
+ column.search.fixed('dtcc', function (haystack) { return !haystack; });
2284
+ }
2285
+ else if (searchType === 'notEmpty') {
2286
+ column.search.fixed('dtcc', function (haystack) { return !!haystack; });
2287
+ }
2288
+ else if (column.search.fixed('dtcc') === '' && searchTerm === '') {
2289
+ // No change - don't do anything
2290
+ return;
2291
+ }
2292
+ else if (searchTerm === '') {
2293
+ // Clear search
2294
+ column.search.fixed('dtcc', '');
2295
+ }
2296
+ else if (searchType === 'equal') {
2297
+ // Use a function for matching - weak typing
2298
+ column.search.fixed('dtcc', function (haystack) { return stringToNum(haystack) == searchTerm; });
2299
+ }
2300
+ else if (searchType === 'notEqual') {
2301
+ column.search.fixed('dtcc', function (haystack) { return stringToNum(haystack) != searchTerm; });
2302
+ }
2303
+ else if (searchType === 'greater') {
2304
+ column.search.fixed('dtcc', function (haystack) { return stringToNum(haystack) > searchTerm; });
2305
+ }
2306
+ else if (searchType === 'greaterOrEqual') {
2307
+ column.search.fixed('dtcc', function (haystack) { return stringToNum(haystack) >= searchTerm; });
2308
+ }
2309
+ else if (searchType === 'less') {
2310
+ column.search.fixed('dtcc', function (haystack) { return stringToNum(haystack) < searchTerm; });
2311
+ }
2312
+ else if (searchType === 'lessOrEqual') {
2313
+ column.search.fixed('dtcc', function (haystack) { return stringToNum(haystack) <= searchTerm; });
2314
+ }
2315
+ // If in a dropdown, set the parents as active
2316
+ if (config._parents) {
2317
+ config._parents.forEach(function (btn) {
2318
+ return btn.activeList(_this.unique(), !!column.search.fixed('dtcc'));
2319
+ });
2320
+ }
2321
+ if (!loadingState) {
2322
+ column.draw();
2323
+ }
2324
+ });
2325
+ // Set a numeric input type, per BBC's guidelines
2326
+ searchInput.input().setAttribute('inputmode', 'numeric');
2327
+ searchInput.input().setAttribute('pattern', '[0-9]*');
2328
+ return searchInput.element();
2329
+ }
2330
+ };
2331
+ var _re_html = /<([^>]*>)/g;
2332
+ var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
2333
+ function stringToNum(d) {
2334
+ if (d !== 0 && (!d || d === '-')) {
2335
+ return -Infinity;
2336
+ }
2337
+ var type = typeof d;
2338
+ if (type === 'number' || type === 'bigint') {
2339
+ return d;
2340
+ }
2341
+ if (d.replace) {
2342
+ d = d.replace(_re_html, '').replace(_re_formatted_numeric, '');
2343
+ }
2344
+ return d * 1;
2345
+ }
2346
+
2347
+ var searchText = {
2348
+ defaults: {
2349
+ clear: true,
2350
+ placeholder: '',
2351
+ title: '',
2352
+ titleAttr: ''
2353
+ },
2354
+ init: function (config) {
2355
+ var _this = this;
2356
+ var dt = this.dt();
2357
+ var i18nBase = 'columnControl.search.text.';
2358
+ var searchInput = new SearchInput(dt, this.idx())
2359
+ .addClass('dtcc-searchText')
2360
+ .clearable(config.clear)
2361
+ .placeholder(config.placeholder)
2362
+ .title(config.title)
2363
+ .titleAttr(config.titleAttr)
2364
+ .options([
2365
+ { label: dt.i18n(i18nBase + 'contains', 'Contains'), value: 'contains' },
2366
+ {
2367
+ label: dt.i18n(i18nBase + 'notContains', 'Does not contain'),
2368
+ value: 'notContains'
2369
+ },
2370
+ { label: dt.i18n(i18nBase + 'equal', 'Equals'), value: 'equal' },
2371
+ { label: dt.i18n(i18nBase + 'notEqual', 'Does not equal'), value: 'notEqual' },
2372
+ { label: dt.i18n(i18nBase + 'starts', 'Starts'), value: 'starts' },
2373
+ { label: dt.i18n(i18nBase + 'ends', 'Ends'), value: 'ends' },
2374
+ { label: dt.i18n(i18nBase + 'empty', 'Empty'), value: 'empty' },
2375
+ { label: dt.i18n(i18nBase + 'notEmpty', 'Not empty'), value: 'notEmpty' }
2376
+ ])
2377
+ .search(function (searchType, searchTerm, loadingState) {
2378
+ // When SSP, don't apply a filter here, SearchInput will add to the submit data
2379
+ if (dt.page.info().serverSide) {
2380
+ if (!loadingState) {
2381
+ dt.draw();
2382
+ }
2383
+ return;
2384
+ }
2385
+ var column = dt.column(_this.idx());
2386
+ searchTerm = searchTerm.toLowerCase();
2387
+ if (searchType === 'empty') {
2388
+ column.search.fixed('dtcc', function (haystack) { return !haystack; });
2389
+ }
2390
+ else if (searchType === 'notEmpty') {
2391
+ column.search.fixed('dtcc', function (haystack) { return !!haystack; });
2392
+ }
2393
+ else if (column.search.fixed('dtcc') === '' && searchTerm === '') {
2394
+ // No change - don't do anything
2395
+ return;
2396
+ }
2397
+ else if (searchTerm === '') {
2398
+ // Clear search
2399
+ column.search.fixed('dtcc', '');
2400
+ }
2401
+ else if (searchType === 'equal') {
2402
+ // Use a function for exact matching
2403
+ column.search.fixed('dtcc', function (haystack) { return haystack.toLowerCase() == searchTerm; });
2404
+ }
2405
+ else if (searchType === 'notEqual') {
2406
+ column.search.fixed('dtcc', function (haystack) { return haystack.toLowerCase() != searchTerm; });
2407
+ }
2408
+ else if (searchType === 'contains') {
2409
+ // Use the built in smart search
2410
+ column.search.fixed('dtcc', searchTerm);
2411
+ }
2412
+ else if (searchType === 'notContains') {
2413
+ // Use the built in smart search
2414
+ column.search.fixed('dtcc', function (haystack) { return !haystack.toLowerCase().includes(searchTerm); });
2415
+ }
2416
+ else if (searchType === 'starts') {
2417
+ // Use a function for startsWith case insensitive search
2418
+ column.search.fixed('dtcc', function (haystack) {
2419
+ return haystack.toLowerCase().startsWith(searchTerm);
2420
+ });
2421
+ }
2422
+ else if (searchType === 'ends') {
2423
+ column.search.fixed('dtcc', function (haystack) {
2424
+ return haystack.toLowerCase().endsWith(searchTerm);
2425
+ });
2426
+ }
2427
+ // If in a dropdown, set the parent levels as active
2428
+ if (config._parents) {
2429
+ config._parents.forEach(function (btn) {
2430
+ return btn.activeList(_this.unique(), !!column.search.fixed('dtcc'));
2431
+ });
2432
+ }
2433
+ if (!loadingState) {
2434
+ column.draw();
2435
+ }
2436
+ });
2437
+ return searchInput.element();
2438
+ }
2439
+ };
2440
+
2441
+ var search = {
2442
+ defaults: {
2443
+ allowSearchList: false
2444
+ },
2445
+ init: function (config) {
2446
+ var _this = this;
2447
+ var _a, _b, _c;
2448
+ var dt = this.dt();
2449
+ var idx = this.idx();
2450
+ var displayEl;
2451
+ var loadedState = (_c = (_b = (_a = dt.state.loaded()) === null || _a === void 0 ? void 0 : _a.columnControl) === null || _b === void 0 ? void 0 : _b[idx]) === null || _c === void 0 ? void 0 : _c.searchInput;
2452
+ var initType = function (type) {
2453
+ var json = getJsonOptions(dt, idx);
2454
+ // Attempt to match what type of search should be shown
2455
+ if (config.allowSearchList && json) {
2456
+ // We've got a list of JSON options, and are allowed to show the searchList
2457
+ return searchList.init.call(_this, Object.assign({}, searchList.defaults, config));
2458
+ }
2459
+ else if (type === 'date' || type.startsWith('datetime')) {
2460
+ // Date types
2461
+ return searchDateTime.init.call(_this, Object.assign({}, searchDateTime.defaults, config));
2462
+ }
2463
+ else if (type.includes('num')) {
2464
+ // Number types
2465
+ return searchNumber.init.call(_this, Object.assign({}, searchNumber.defaults, config));
2466
+ }
2467
+ else {
2468
+ // Everything else
2469
+ return searchText.init.call(_this, Object.assign({}, searchText.defaults, config));
2470
+ }
2471
+ };
2472
+ // If we know the type from the saved state, we can load it immediately. This is required
2473
+ // to allow the state to be applied to the table and the first draw to have a filter
2474
+ // applied (if it is needed).
2475
+ if (loadedState) {
2476
+ displayEl = initType(loadedState.type);
2477
+ }
2478
+ else {
2479
+ // Wait until we can get the data type for the column and the run the corresponding type
2480
+ displayEl = document.createElement('div');
2481
+ dt.ready(function () {
2482
+ var column = dt.column(idx);
2483
+ var display = initType(column.type());
2484
+ displayEl.replaceWith(display);
2485
+ });
2486
+ }
2487
+ return displayEl;
2488
+ }
2489
+ };
2490
+
2491
+ var searchClear$1 = {
2492
+ defaults: {
2493
+ className: 'searchClear',
2494
+ icon: 'searchClear',
2495
+ text: 'Clear Search'
2496
+ },
2497
+ init: function (config) {
2498
+ var _this = this;
2499
+ var dt = this.dt();
2500
+ var btn = new Button(dt, this)
2501
+ .text(dt.i18n('columnControl.searchClear', config.text))
2502
+ .icon(config.icon)
2503
+ .className(config.className)
2504
+ .handler(function () {
2505
+ dt.column(_this.idx()).columnControl.searchClear().draw();
2506
+ })
2507
+ .enable(false);
2508
+ dt.on('draw', function () {
2509
+ // change enable state
2510
+ var search = dt.column(_this.idx()).search.fixed('dtcc');
2511
+ var searchList = dt.column(_this.idx()).search.fixed('dtcc-list');
2512
+ btn.enable(!!(search || searchList));
2513
+ });
2514
+ return btn.element();
2515
+ }
2516
+ };
2517
+
2518
+ var searchDropdown = {
2519
+ defaults: {
2520
+ ajaxOnly: true,
2521
+ allowSearchList: true,
2522
+ className: 'searchDropdown',
2523
+ clear: true,
2524
+ columns: '',
2525
+ hidable: true,
2526
+ options: null,
2527
+ orthogonal: 'display',
2528
+ placeholder: '',
2529
+ search: true,
2530
+ select: true,
2531
+ text: 'Search',
2532
+ title: '',
2533
+ titleAttr: ''
2534
+ },
2535
+ extend: function (config) {
2536
+ var dt = this.dt();
2537
+ return {
2538
+ extend: 'dropdown',
2539
+ icon: 'search',
2540
+ text: dt.i18n('columnControl.searchDropdown', config.text),
2541
+ content: [
2542
+ Object.assign(config, {
2543
+ extend: 'search'
2544
+ })
2545
+ ]
2546
+ };
2547
+ }
2548
+ };
2549
+
2550
+ var spacer = {
2551
+ defaults: {
2552
+ className: 'dtcc-spacer',
2553
+ text: ''
2554
+ },
2555
+ init: function (config) {
2556
+ var dt = this.dt();
2557
+ var spacer = createElement('div', config.className, dt.i18n('columnControl.spacer', config.text));
2558
+ spacer.setAttribute('role', 'separator');
2559
+ return spacer;
2560
+ }
2561
+ };
2562
+
2563
+ var title = {
2564
+ defaults: {
2565
+ className: 'dtcc-title',
2566
+ text: null
2567
+ },
2568
+ init: function (config) {
2569
+ var dt = this.dt();
2570
+ var title = dt.column(this.idx()).title();
2571
+ var text = config.text === null ? '[title]' : config.text;
2572
+ var el = createElement('div', config.className, text.replace('[title]', title));
2573
+ return el;
2574
+ }
2575
+ };
2576
+
2577
+ var contentTypes = {
2578
+ colVis: colVis,
2579
+ colVisDropdown: colVisDropdown,
2580
+ dropdown: dropdownContent,
2581
+ reorder: reorder,
2582
+ reorderLeft: reorderLeft,
2583
+ reorderRight: reorderRight,
2584
+ rowGroup: rowGroup,
2585
+ rowGroupAdd: rowGroupAdd,
2586
+ rowGroupClear: rowGroupClear,
2587
+ rowGroupRemove: rowGroupRemove,
2588
+ order: order,
2589
+ orderAddAsc: orderAddAsc,
2590
+ orderAddDesc: orderAddDesc,
2591
+ orderAsc: orderAsc,
2592
+ orderClear: orderClear,
2593
+ orderDesc: orderDesc,
2594
+ orderRemove: orderRemove,
2595
+ orderStatus: orderStatus,
2596
+ search: search,
2597
+ searchClear: searchClear$1,
2598
+ searchDropdown: searchDropdown,
2599
+ searchDateTime: searchDateTime,
2600
+ searchList: searchList,
2601
+ searchNumber: searchNumber,
2602
+ searchText: searchText,
2603
+ spacer: spacer,
2604
+ title: title
2605
+ };
2606
+
2607
+ /**
2608
+ *
2609
+ */
2610
+ var ColumnControl = /** @class */ (function () {
2611
+ /**
2612
+ * Create a new ColumnControl instance to control a DataTables column.
2613
+ *
2614
+ * @param dt DataTables API instance
2615
+ * @param columnIdx Column index to operation on
2616
+ * @param opts Configuration options
2617
+ */
2618
+ function ColumnControl(dt, columnIdx, opts) {
2619
+ var _this = this;
2620
+ this._dom = {
2621
+ target: null,
2622
+ wrapper: null
2623
+ };
2624
+ this._c = {};
2625
+ this._s = {
2626
+ columnIdx: null,
2627
+ unique: null,
2628
+ toDestroy: []
2629
+ };
2630
+ this._dt = dt;
2631
+ this._s.columnIdx = columnIdx;
2632
+ this._s.unique = Math.random();
2633
+ var originalIdx = columnIdx;
2634
+ Object.assign(this._c, ColumnControl.defaults, opts);
2635
+ this._dom.target = this._target();
2636
+ if (opts.className) {
2637
+ addClass(this._dom.target.closest('tr'), opts.className);
2638
+ }
2639
+ if (this._c.content) {
2640
+ // If column reordering can be done, we reassign the column index here, and before the
2641
+ // plugins can add their own listeners.
2642
+ dt.on('columns-reordered', function (e, details) {
2643
+ _this._s.columnIdx = dt.colReorder.transpose(originalIdx, 'fromOriginal');
2644
+ });
2645
+ this._dom.wrapper = document.createElement('span');
2646
+ this._dom.wrapper.classList.add('dtcc');
2647
+ this._dom.target.appendChild(this._dom.wrapper);
2648
+ this._c.content.forEach(function (content) {
2649
+ var _a = _this.resolve(content), plugin = _a.plugin, config = _a.config;
2650
+ var el = plugin.init.call(_this, config);
2651
+ _this._dom.wrapper.appendChild(el);
2652
+ });
2653
+ dt.on('destroy', function () {
2654
+ _this._s.toDestroy.slice().forEach(function (el) {
2655
+ el.destroy();
2656
+ });
2657
+ _this._dom.wrapper.remove();
2658
+ });
2659
+ }
2660
+ }
2661
+ /**
2662
+ * Add a component to the destroy list. This is so there is a single destroy event handler,
2663
+ * which is much better for performance.
2664
+ *
2665
+ * @param component Any instance with a `destroy` method
2666
+ */
2667
+ ColumnControl.prototype.destroyAdd = function (component) {
2668
+ this._s.toDestroy.push(component);
2669
+ };
2670
+ /**
2671
+ * Remove an instance from the destroy list (it has been destroyed itself)
2672
+ *
2673
+ * @param component Any instance with a `destroy` method
2674
+ */
2675
+ ColumnControl.prototype.destroyRemove = function (component) {
2676
+ var idx = this._s.toDestroy.indexOf(component);
2677
+ if (idx !== -1) {
2678
+ this._s.toDestroy.splice(idx, 1);
2679
+ }
2680
+ };
2681
+ /**
2682
+ * Get the DataTables API instance that hosts this instance of ColumnControl
2683
+ *
2684
+ * @returns DataTables API instance
2685
+ */
2686
+ ColumnControl.prototype.dt = function () {
2687
+ return this._dt;
2688
+ };
2689
+ /**
2690
+ * Get what column index this instance of ColumnControl is operating on
2691
+ *
2692
+ * @returns Column index
2693
+ */
2694
+ ColumnControl.prototype.idx = function () {
2695
+ return this._s.columnIdx;
2696
+ };
2697
+ /**
2698
+ * Covert the options from `content` in the DataTable initialisation for this instance into a
2699
+ * resolved plugin and options.
2700
+ *
2701
+ * @param content The dev's supplied configuration for the content
2702
+ * @returns Resolved plugin information
2703
+ */
2704
+ ColumnControl.prototype.resolve = function (content) {
2705
+ var plugin = null;
2706
+ var config = null;
2707
+ var type = null;
2708
+ if (typeof content === 'string') {
2709
+ // Simple content - uses default options
2710
+ type = content;
2711
+ plugin = ColumnControl.content[type];
2712
+ config = Object.assign({}, plugin === null || plugin === void 0 ? void 0 : plugin.defaults);
2713
+ }
2714
+ else if (Array.isArray(content)) {
2715
+ // An array is a shorthand for a dropdown with its default options
2716
+ type = 'dropdown';
2717
+ plugin = ColumnControl.content[type];
2718
+ config = Object.assign({}, plugin === null || plugin === void 0 ? void 0 : plugin.defaults, {
2719
+ content: content
2720
+ });
2721
+ }
2722
+ else if (content.extend) {
2723
+ // Content with custom options
2724
+ type = content.extend;
2725
+ plugin = ColumnControl.content[type];
2726
+ config = Object.assign({}, plugin === null || plugin === void 0 ? void 0 : plugin.defaults, content);
2727
+ }
2728
+ if (!plugin) {
2729
+ throw new Error('Unknown ColumnControl content type: ' + type);
2730
+ }
2731
+ // If the plugin is a wrapper around another type - e.g. the colVisDropdown
2732
+ if (plugin.extend) {
2733
+ var self_1 = plugin.extend.call(this, config);
2734
+ return this.resolve(self_1);
2735
+ }
2736
+ return {
2737
+ config: config,
2738
+ type: type,
2739
+ plugin: plugin
2740
+ };
2741
+ };
2742
+ /**
2743
+ * Get the unique id for the instance
2744
+ *
2745
+ * @returns Instant unique id
2746
+ */
2747
+ ColumnControl.prototype.unique = function () {
2748
+ return this._s.unique;
2749
+ };
2750
+ /**
2751
+ * Resolve the configured target into a DOM element
2752
+ */
2753
+ ColumnControl.prototype._target = function () {
2754
+ var target = this._c.target;
2755
+ var column = this._dt.column(this._s.columnIdx);
2756
+ var node;
2757
+ var className = 'header';
2758
+ // Header row index
2759
+ if (typeof target === 'number') {
2760
+ node = column.header(target);
2761
+ }
2762
+ else {
2763
+ var parts = target.split(':');
2764
+ var isHeader = parts[0] === 'tfoot' ? false : true;
2765
+ var row = parts[1] ? parseInt(parts[1]) : 0;
2766
+ if (isHeader) {
2767
+ node = column.header(row);
2768
+ }
2769
+ else {
2770
+ node = column.footer(row);
2771
+ className = 'footer';
2772
+ }
2773
+ }
2774
+ return node.querySelector('div.dt-column-' + className);
2775
+ };
2776
+ // Classes for common UI
2777
+ ColumnControl.Button = Button;
2778
+ ColumnControl.CheckList = CheckList;
2779
+ ColumnControl.SearchInput = SearchInput;
2780
+ /** Content plugins */
2781
+ ColumnControl.content = contentTypes;
2782
+ /** Defaults for ColumnControl */
2783
+ ColumnControl.defaults = {
2784
+ className: '',
2785
+ content: null,
2786
+ target: 0,
2787
+ };
2788
+ /** SVG icons that can be used by the content plugins */
2789
+ ColumnControl.icons = icons;
2790
+ /** Version */
2791
+ ColumnControl.version = '1.1.1';
2792
+ return ColumnControl;
2793
+ }());
2794
+
2795
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2796
+ * DataTables API integration
2797
+ */
2798
+ DataTable.ColumnControl = ColumnControl;
2799
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2800
+ * DataTables listeners for initialisation
2801
+ */
2802
+ // Create header / footer rows that don't exist, but have been referenced in the ColumnControl
2803
+ // targets. This needs to be done _before_ the header / footer structure is detected.
2804
+ $(document).on('i18n.dt', function (e, settings) {
2805
+ if (e.namespace !== 'dt') {
2806
+ return;
2807
+ }
2808
+ var api = new DataTable.Api(settings);
2809
+ var thead = api.table().header();
2810
+ var tableInit = settings.oInit.columnControl;
2811
+ var defaultInit = ColumnControl.defaults;
2812
+ var baseTargets = [];
2813
+ var ackTargets = {};
2814
+ // Determine if there is only one header row initially. If there is, we might append more
2815
+ // after it. Mark the top row as the header row using `titleRow` in the DataTables configuration
2816
+ if (thead.querySelectorAll('tr').length <= 1 && settings.titleRow === null) {
2817
+ settings.titleRow = 0;
2818
+ }
2819
+ identifyTargets(baseTargets, tableInit);
2820
+ if (ColumnControl.defaults.content) {
2821
+ identifyTargets(baseTargets, defaultInit);
2822
+ }
2823
+ api.columns().every(function (i) {
2824
+ var columnInit = this.init().columnControl;
2825
+ identifyTargets(baseTargets, columnInit);
2826
+ });
2827
+ for (var i = 0; i < baseTargets.length; i++) {
2828
+ assetTarget(ackTargets, baseTargets[i], api);
2829
+ }
2830
+ });
2831
+ // Initialisation of ColumnControl instances - has to be done _after_ the header / footer structure
2832
+ // is detected by DataTables.
2833
+ $(document).on('preInit.dt', function (e, settings) {
2834
+ if (e.namespace !== 'dt') {
2835
+ return;
2836
+ }
2837
+ var api = new DataTable.Api(settings);
2838
+ var tableInit = settings.oInit.columnControl;
2839
+ var defaultInit = ColumnControl.defaults;
2840
+ var baseTargets = [];
2841
+ identifyTargets(baseTargets, tableInit);
2842
+ // Only add the default target if there is actually content for it
2843
+ if (ColumnControl.defaults.content) {
2844
+ identifyTargets(baseTargets, defaultInit);
2845
+ }
2846
+ api.columns().every(function (i) {
2847
+ var columnInit = this.init().columnControl;
2848
+ var targets = identifyTargets(baseTargets.slice(), columnInit);
2849
+ for (var i_1 = 0; i_1 < targets.length; i_1++) {
2850
+ // Each of the column, table and defaults configuration can be an array of config
2851
+ // objects, an array of content, or a configuration object. There might be multiple
2852
+ // targets for each one, and they might not exist! Therefore this is more complex
2853
+ // than it might be desirable.
2854
+ var columnTargetInit = getOptionsForTarget(targets[i_1], columnInit);
2855
+ var tableTargetInit = getOptionsForTarget(targets[i_1], tableInit);
2856
+ var defaultTargetInit = getOptionsForTarget(targets[i_1], defaultInit);
2857
+ if (defaultTargetInit || tableTargetInit || columnTargetInit) {
2858
+ new ColumnControl(api, this.index(), Object.assign({}, defaultTargetInit || {}, tableTargetInit || {}, columnTargetInit || {}));
2859
+ }
2860
+ }
2861
+ });
2862
+ });
2863
+ function searchClear() {
2864
+ var ctx = this;
2865
+ return this.iterator('column', function (settings, idx) {
2866
+ // Note that the listeners for this will not redraw the table.
2867
+ ctx.trigger('cc-search-clear', [idx]);
2868
+ });
2869
+ }
2870
+ DataTable.Api.registerPlural('columns().columnControl.searchClear()', 'column().columnControl.searchClear()', searchClear);
2871
+ // Legacy (1.0.x)) - was never documented, but was mentioned in the forum
2872
+ DataTable.Api.registerPlural('columns().ccSearchClear()', 'column().ccSearchClear()', searchClear);
2873
+ DataTable.Api.registerPlural('columns().columnControl.searchList()', 'column().columnControl.searchList()', function (options) {
2874
+ return this.iterator('column', function (settings, idx) {
2875
+ var fn = settings.aoColumns[idx].columnControlSearchList;
2876
+ if (fn) {
2877
+ fn(options);
2878
+ }
2879
+ });
2880
+ });
2881
+ DataTable.ext.buttons.ccSearchClear = {
2882
+ text: function (dt) {
2883
+ return dt.i18n('columnControl.buttons.searchClear', 'Clear search');
2884
+ },
2885
+ init: function (dt, node, config) {
2886
+ var _this = this;
2887
+ dt.on('draw.DT', function () {
2888
+ var enabled = false;
2889
+ var glob = !!dt.search();
2890
+ // No point in wasting clock cycles if we already know it will be enabled
2891
+ if (!glob) {
2892
+ dt.columns().every(function () {
2893
+ if (this.search.fixed('dtcc') || this.search.fixed('dtcc-list')) {
2894
+ enabled = true;
2895
+ }
2896
+ });
2897
+ }
2898
+ _this.enable(glob || enabled);
2899
+ });
2900
+ this.enable(false);
2901
+ },
2902
+ action: function (e, dt, node, config) {
2903
+ dt.search('');
2904
+ dt.columns().columnControl.searchClear();
2905
+ dt.draw();
2906
+ }
2907
+ };
2908
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2909
+ * Initialisation support - this is more involved than normal as targets might
2910
+ * need to be created, and also options needs to be resolved into a standard
2911
+ * ColumnControl configuration object, from the various forms allowed in the
2912
+ * DataTables configuration.
2913
+ */
2914
+ /**
2915
+ * Given a ColumnControl target, make sure that it exists. If not, create it.
2916
+ *
2917
+ * @param ackTargets Cache for list of targets that have already been found or created
2918
+ * @param target Current target
2919
+ * @param dt DataTable API
2920
+ * @returns Void
2921
+ */
2922
+ function assetTarget(ackTargets, target, dt) {
2923
+ // Check if we already know about the target - if so, we know that it must already be in place
2924
+ if (ackTargets[target]) {
2925
+ return;
2926
+ }
2927
+ var isHeader = true; // false for footer
2928
+ var row = 0;
2929
+ if (typeof target === 'number') {
2930
+ row = target;
2931
+ }
2932
+ else {
2933
+ var parts = target.split(':');
2934
+ if (parts[0] === 'tfoot') {
2935
+ isHeader = false;
2936
+ }
2937
+ if (parts[1]) {
2938
+ row = parseInt(parts[1]);
2939
+ }
2940
+ }
2941
+ // The header / footer have not yet had their structure read, so they aren't available via
2942
+ // the API. As such we need to do our own DOM tweaking
2943
+ var node = isHeader ? dt.table().header() : dt.table().footer();
2944
+ // If the node doesn't exist yet, we need to create it
2945
+ if (!node.querySelectorAll('tr')[row]) {
2946
+ var columns = dt.columns().count();
2947
+ var tr = createElement('tr');
2948
+ tr.setAttribute('data-dt-order', 'disable');
2949
+ for (var i = 0; i < columns; i++) {
2950
+ tr.appendChild(createElement('td'));
2951
+ }
2952
+ node.appendChild(tr);
2953
+ }
2954
+ ackTargets[target] = true;
2955
+ }
2956
+ /**
2957
+ * Given a target, get the config object for it from the parameter passed in
2958
+ *
2959
+ * @param target ColumnControl target
2960
+ * @param input The dev's configuration
2961
+ * @returns The resolved config object, if found
2962
+ */
2963
+ function getOptionsForTarget(target, input) {
2964
+ var defaultTarget = ColumnControl.defaults.target;
2965
+ var selfTarget;
2966
+ if (isIContentArray(input)) {
2967
+ // Top level content array - e.g. `columnControl: ['order']`
2968
+ if (defaultTarget === target) {
2969
+ return {
2970
+ target: defaultTarget,
2971
+ content: input
2972
+ };
2973
+ }
2974
+ }
2975
+ else if (Array.isArray(input)) {
2976
+ // Top level array, some items of which will be configuration objects (possibly not all)
2977
+ for (var i = 0; i < input.length; i++) {
2978
+ var item = input[i];
2979
+ if (isIContentArray(item)) {
2980
+ // A content array, e.g. the inner array from: `columnControl: [['order']]
2981
+ if (defaultTarget === target) {
2982
+ return {
2983
+ target: defaultTarget,
2984
+ content: item
2985
+ };
2986
+ }
2987
+ }
2988
+ else if (isIConfig(item)) {
2989
+ // A config object, e.g. the object from: `columnControl: [{content: []}]`
2990
+ selfTarget = item.target !== undefined ? item.target : defaultTarget;
2991
+ if (target === selfTarget) {
2992
+ return item;
2993
+ }
2994
+ }
2995
+ else {
2996
+ // A content object
2997
+ if (target === defaultTarget) {
2998
+ return {
2999
+ target: defaultTarget,
3000
+ content: input
3001
+ };
3002
+ }
3003
+ }
3004
+ }
3005
+ }
3006
+ else if (typeof input === 'object') {
3007
+ // An object can be either a config object, or an extending content object
3008
+ if (isIConfig(input)) {
3009
+ // Config object: columnControl: {content: []}
3010
+ selfTarget = input.target !== undefined ? input.target : defaultTarget;
3011
+ if (target === selfTarget) {
3012
+ return input;
3013
+ }
3014
+ }
3015
+ else {
3016
+ // content object: columnControl: [{extend: 'order'}]
3017
+ if (target === defaultTarget) {
3018
+ return {
3019
+ target: defaultTarget,
3020
+ content: input
3021
+ };
3022
+ }
3023
+ }
3024
+ }
3025
+ }
3026
+ /**
3027
+ * Get a list of all targets from the configuration objects / arrays
3028
+ *
3029
+ * @param targets Established list of targets - mutated
3030
+ * @param input Configuration object / array
3031
+ * @returns Updated array
3032
+ */
3033
+ function identifyTargets(targets, input) {
3034
+ function add(target) {
3035
+ if (!targets.includes(target)) {
3036
+ targets.push(target);
3037
+ }
3038
+ }
3039
+ if (Array.isArray(input)) {
3040
+ if (input.length === 0) {
3041
+ // Empty array - assume it is empty content
3042
+ add(ColumnControl.defaults.target);
3043
+ }
3044
+ else {
3045
+ // Array of options, or an array of content
3046
+ input.forEach(function (item) {
3047
+ add(typeof item === 'object' && item.target !== undefined
3048
+ ? item.target
3049
+ : ColumnControl.defaults.target);
3050
+ });
3051
+ }
3052
+ }
3053
+ else if (typeof input === 'object') {
3054
+ // Full options defined: { target: x, content: [] }
3055
+ add(input.target !== undefined ? input.target : ColumnControl.defaults.target);
3056
+ }
3057
+ return targets;
3058
+ }
3059
+ /**
3060
+ * Check if an item is a configuration object or not
3061
+ *
3062
+ * @param item Item to check
3063
+ * @returns true if it is a config object
3064
+ */
3065
+ function isIConfig(item) {
3066
+ return typeof item === 'object' && item.target !== undefined ? true : false;
3067
+ }
3068
+ /**
3069
+ * Determine if an array contains only content items or not
3070
+ *
3071
+ * @param arr Array to check
3072
+ * @returns true if is content only, false if not (i.e. is an array with configuration objects).
3073
+ */
3074
+ function isIContentArray(arr) {
3075
+ var detectedConfig = false;
3076
+ if (!Array.isArray(arr)) {
3077
+ return false;
3078
+ }
3079
+ for (var i = 0; i < arr.length; i++) {
3080
+ if (isIConfig(arr[i])) {
3081
+ detectedConfig = true;
3082
+ break;
3083
+ }
3084
+ }
3085
+ return !detectedConfig;
3086
+ }
3087
+
3088
+
3089
+ return DataTable;
3090
+ }));