j1-template 2024.1.5 → 2024.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/_includes/themes/j1/layouts/content_generator_page.html +0 -34
  3. data/_includes/themes/j1/modules/searcher/generator.html +4 -1
  4. data/_includes/themes/j1/modules/searcher/procedures/topsearch.proc +59 -56
  5. data/assets/data/authclient.html +1 -8
  6. data/assets/data/banner.html +1 -7
  7. data/assets/data/fab.html +2 -13
  8. data/assets/data/footer.html +0 -3
  9. data/assets/data/galeries.html +2 -13
  10. data/assets/data/gemini-ui.html +74 -21
  11. data/assets/data/iframes.html +1 -4
  12. data/assets/data/masonry.html +1 -13
  13. data/assets/data/masterslider.html +10 -21
  14. data/assets/data/menu.html +6 -14
  15. data/assets/data/mmenu.html +6 -5
  16. data/assets/data/mmenu_toc.html +2 -1
  17. data/assets/data/panel.html +4 -11
  18. data/assets/data/particles.yml +8 -8
  19. data/assets/data/quicklinks.html +4 -23
  20. data/assets/data/rtext_resizer.html +3 -1
  21. data/assets/data/slick.html +9 -11
  22. data/assets/data/translator.html +0 -1
  23. data/assets/themes/j1/adapter/js/advertising.js +143 -182
  24. data/assets/themes/j1/adapter/js/algolia.js +61 -54
  25. data/assets/themes/j1/adapter/js/analytics.js +68 -52
  26. data/assets/themes/j1/adapter/js/asciidoctor.js +32 -20
  27. data/assets/themes/j1/adapter/js/attic.js +75 -69
  28. data/assets/themes/j1/adapter/js/bmd.js +44 -26
  29. data/assets/themes/j1/adapter/js/carousel.js +117 -92
  30. data/assets/themes/j1/adapter/js/chatbot.js +77 -35
  31. data/assets/themes/j1/adapter/js/clipboard.js +67 -49
  32. data/assets/themes/j1/adapter/js/comments.js +93 -70
  33. data/assets/themes/j1/adapter/js/cookieConsent.js +157 -159
  34. data/assets/themes/j1/adapter/js/customFunctions.js +52 -35
  35. data/assets/themes/j1/adapter/js/customModule.js +61 -50
  36. data/assets/themes/j1/adapter/js/docsearch.js +55 -34
  37. data/assets/themes/j1/adapter/js/dropdowns.js +66 -52
  38. data/assets/themes/j1/adapter/js/fab.js +124 -109
  39. data/assets/themes/j1/adapter/js/gallery.js +68 -49
  40. data/assets/themes/j1/adapter/js/gemini.js +961 -301
  41. data/assets/themes/j1/adapter/js/iconPicker.js +76 -54
  42. data/assets/themes/j1/adapter/js/iconPickerPage.js +279 -0
  43. data/assets/themes/j1/adapter/js/iframer.js +84 -63
  44. data/assets/themes/j1/adapter/js/j1.js +605 -542
  45. data/assets/themes/j1/adapter/js/lazyLoader.js +43 -24
  46. data/assets/themes/j1/adapter/js/lightbox.js +53 -52
  47. data/assets/themes/j1/adapter/js/logger.js +78 -66
  48. data/assets/themes/j1/adapter/js/lunr.js +684 -86
  49. data/assets/themes/j1/adapter/js/masonry.js +84 -68
  50. data/assets/themes/j1/adapter/js/masterslider.js +136 -137
  51. data/assets/themes/j1/adapter/js/mmenu.js +102 -66
  52. data/assets/themes/j1/adapter/js/navigator.js +291 -356
  53. data/assets/themes/j1/adapter/js/particles.js +62 -40
  54. data/assets/themes/j1/adapter/js/rangeSlider.js +66 -48
  55. data/assets/themes/j1/adapter/js/rouge.js +63 -44
  56. data/assets/themes/j1/adapter/js/rtable.js +56 -40
  57. data/assets/themes/j1/adapter/js/rtextResizer.js +57 -44
  58. data/assets/themes/j1/adapter/js/scroller.js +170 -133
  59. data/assets/themes/j1/adapter/js/slick.js +99 -97
  60. data/assets/themes/j1/adapter/js/slimSelect.js +288 -0
  61. data/assets/themes/j1/adapter/js/speak2me.js +124 -128
  62. data/assets/themes/j1/adapter/js/themeToggler.js +118 -97
  63. data/assets/themes/j1/adapter/js/{themer.js → themes.js} +144 -113
  64. data/assets/themes/j1/adapter/js/toccer.js +88 -54
  65. data/assets/themes/j1/adapter/js/translator.js +74 -70
  66. data/assets/themes/j1/adapter/js/waves.js +75 -58
  67. data/assets/themes/j1/core/css/themes/unolight/bootstrap.css +29 -11
  68. data/assets/themes/j1/core/css/themes/unolight/bootstrap.min.css +2 -2
  69. data/assets/themes/j1/core/js/template.js +474 -420
  70. data/assets/themes/j1/core/js/template.min.js +7 -7
  71. data/assets/themes/j1/core/js/template.min.js.map +1 -1
  72. data/assets/themes/j1/modules/carousel/css/theme/uno.css +4 -4
  73. data/assets/themes/j1/modules/carousel/css/theme/uno.min.css +1 -1
  74. data/assets/themes/j1/modules/clipboard/js/clipboard.js +0 -1
  75. data/assets/themes/j1/modules/cookieConsent/js/cookieConsent.js +27 -21
  76. data/assets/themes/j1/modules/iconPicker/css/theme/uno.css +58 -0
  77. data/assets/themes/j1/modules/iconPicker/css/theme/uno.min.css +16 -0
  78. data/assets/themes/j1/modules/iconPicker/js/universal-icon-picker.0.js +493 -0
  79. data/assets/themes/j1/modules/iconPicker/js/universal-icon-picker.js +7 -7
  80. data/assets/themes/j1/modules/js-cookies/js/js.cookie.js +147 -0
  81. data/assets/themes/j1/modules/js-cookies/js/js.cookie.min.js +2 -0
  82. data/assets/themes/j1/modules/lightGallery/js/plugins/lg-video.js +4 -4
  83. data/assets/themes/j1/modules/lightGallery/js/plugins/lg-video.min.js +2 -10
  84. data/assets/themes/j1/modules/lunr/css/j1.css +12 -6
  85. data/assets/themes/j1/modules/lunr/css/j1.min.css +1 -1
  86. data/assets/themes/j1/modules/lunr/js/j1.js +46 -43
  87. data/assets/themes/j1/modules/lunr/js/j1.min.js +1 -1
  88. data/assets/themes/j1/modules/masterslider/js/masterslider.js +1 -1
  89. data/assets/themes/j1/modules/scroller/js/scroller.js +64 -74
  90. data/assets/themes/j1/modules/scroller/js/scroller.min.js +1 -1
  91. data/assets/themes/j1/modules/slick/slider/css/theme/uno.css +4 -4
  92. data/assets/themes/j1/modules/slick/slider/css/theme/uno.min.css +1 -1
  93. data/assets/themes/j1/modules/slimSelect/js/select.js +1865 -1821
  94. data/assets/themes/j1/modules/slimSelect/js/select.min.js +2 -1
  95. data/assets/themes/j1/modules/themeSwitcher/js/switcher.js +87 -89
  96. data/assets/themes/j1/modules/themeSwitcher/js/switcher.min.js +1 -1
  97. data/assets/themes/j1/modules/videojs/js/plugins/vm/api/player.min.js +5 -7
  98. data/assets/themes/j1/modules/videojs/js/plugins/vm/api/v2.20.1/player.min.js +23 -0
  99. data/lib/j1/version.rb +1 -1
  100. data/lib/starter_web/Gemfile +2 -2
  101. data/lib/starter_web/README.md +5 -5
  102. data/lib/starter_web/_config.yml +1 -1
  103. data/lib/starter_web/_data/blocks/_panel.yml +775 -0
  104. data/lib/starter_web/_data/blocks/panel.yml +53 -53
  105. data/lib/starter_web/_data/j1_config.yml +3 -2
  106. data/lib/starter_web/_data/layouts/default.yml +0 -2
  107. data/lib/starter_web/_data/modules/_scroller.yml +102 -0
  108. data/lib/starter_web/_data/modules/carousel.yml +3 -3
  109. data/lib/starter_web/_data/modules/defaults/attics.yml +5 -5
  110. data/lib/starter_web/_data/modules/defaults/docsearch.yml +1 -1
  111. data/lib/starter_web/_data/modules/defaults/gemini.yml +204 -46
  112. data/lib/starter_web/_data/modules/defaults/{iconPicker.yml → icon_picker.yml} +6 -12
  113. data/lib/starter_web/_data/modules/defaults/lunr.yml +20 -5
  114. data/lib/starter_web/_data/modules/defaults/masterslider.yml +4 -4
  115. data/lib/starter_web/_data/modules/defaults/navigator.yml +20 -24
  116. data/lib/starter_web/_data/modules/defaults/particles.yml +3 -3
  117. data/lib/starter_web/_data/modules/defaults/slim_select.yml +54 -0
  118. data/lib/starter_web/_data/modules/defaults/{themer.yml → themes.yml} +10 -10
  119. data/lib/starter_web/_data/modules/defaults/toccer.yml +1 -1
  120. data/lib/starter_web/_data/modules/gallery.yml +33 -38
  121. data/lib/starter_web/_data/modules/gemini.yml +42 -3
  122. data/lib/starter_web/_data/modules/{iconPicker.yml → icon_picker.yml} +31 -3
  123. data/lib/starter_web/_data/modules/lunr.yml +12 -1
  124. data/lib/starter_web/_data/modules/masonry.yml +37 -38
  125. data/lib/starter_web/_data/modules/masterslider.yml +78 -95
  126. data/lib/starter_web/_data/modules/navigator_menu.yml +12 -20
  127. data/lib/starter_web/_data/modules/particles.yml +3 -3
  128. data/lib/starter_web/_data/modules/scroller.yml +3 -3
  129. data/lib/starter_web/_data/modules/slim_select.yml +110 -0
  130. data/lib/starter_web/_data/modules/{themer.yml → themes.yml} +4 -4
  131. data/lib/starter_web/_data/resources.yml +83 -47
  132. data/lib/starter_web/_data/templates/feed.xml +1 -1
  133. data/lib/starter_web/_includes/attributes.asciidoc +354 -355
  134. data/lib/starter_web/_plugins/asciidoctor/gemini-ui-block.rb +1 -1
  135. data/lib/starter_web/_plugins/asciidoctor/slim-select-block.rb +45 -0
  136. data/lib/starter_web/_plugins/index/lunr.rb +1 -1
  137. data/lib/starter_web/collections/asciidoc_skeletons/simple-post/_posts/yyyy-mm-dd-your-post-name.asciidoc +5 -2
  138. data/lib/starter_web/collections/posts/public/featured/_posts/0000-00-00-welcome-to-j1.adoc.erb +3 -3
  139. data/lib/starter_web/collections/posts/public/featured/_posts/2021-01-01-about-cookies.adoc +9 -9
  140. data/lib/starter_web/collections/posts/public/featured/_posts/2021-02-01-static-site-generators.adoc +4 -4
  141. data/lib/starter_web/collections/posts/public/featured/_posts/2022-02-01-about-j1.adoc +3 -2
  142. data/lib/starter_web/collections/posts/public/featured/_posts/2023-10-18-url-types.adoc +12 -12
  143. data/lib/starter_web/package.json +1 -1
  144. data/lib/starter_web/pages/public/about/features.adoc +1 -1
  145. data/lib/starter_web/pages/public/about/reporting_issues.adoc +1 -0
  146. data/lib/starter_web/pages/public/asciidoc_skeletons/documentation/_includes/attributes.asciidoc +44 -44
  147. data/lib/starter_web/pages/public/asciidoc_skeletons/documentation/documentation.adoc +1 -0
  148. data/lib/starter_web/pages/public/asciidoc_skeletons/multi-document/_includes/attributes.asciidoc +12 -12
  149. data/lib/starter_web/pages/public/blog/navigator/archive/allview.html +1 -1
  150. data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/attributes.asciidoc +42 -28
  151. data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/highlghter_rouge.adoc +1 -0
  152. data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/lunr_search.adoc +1 -0
  153. data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/present_audio_video.adoc +18 -2
  154. data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/present_images.adoc +43 -50
  155. data/lib/starter_web/pages/public/legal/en/100_copyright.adoc +6 -11
  156. data/lib/starter_web/pages/public/legal/en/200_impress.adoc +4 -11
  157. data/lib/starter_web/pages/public/legal/en/300_privacy.adoc +5 -12
  158. data/lib/starter_web/pages/public/legal/en/400_comment_policy.adoc +5 -10
  159. data/lib/starter_web/pages/public/tools/previewer/_includes/attributes.asciidoc +10 -9
  160. data/lib/starter_web/pages/public/tools/previewer/preview_bootstrap_theme.adoc +77 -75
  161. metadata +52 -46
  162. data/lib/starter_web/pages/public/manuals/integrations/gemini/_includes/attributes.asciidoc +0 -47
  163. data/lib/starter_web/pages/public/manuals/integrations/gemini/_includes/documents/preview_google_adsense.asciidoc +0 -448
  164. data/lib/starter_web/pages/public/manuals/integrations/gemini/_includes/documents/readme +0 -0
  165. data/lib/starter_web/pages/public/manuals/integrations/gemini/_includes/tables/readme +0 -0
  166. data/lib/starter_web/pages/public/manuals/integrations/gemini/gemini.adoc +0 -525
  167. data/lib/starter_web/pages/public/manuals/integrations/gemini/security.asccidoc +0 -274
  168. data/lib/starter_web/pages/public/manuals/integrations/gemini/security.hrml +0 -560
  169. /data/lib/starter_web/pages/public/{legal/learn → learn}/bookshelf/article_previewer/viewer_biography.adoc +0 -0
  170. /data/lib/starter_web/pages/public/{legal/learn → learn}/bookshelf/article_previewer/viewer_fantasy.adoc +0 -0
  171. /data/lib/starter_web/pages/public/{legal/learn → learn}/bookshelf/article_previewer/viewer_romance.adoc +0 -0
  172. /data/lib/starter_web/pages/public/{legal/learn → learn}/bookshelf/jekyll_collections.adoc +0 -0
  173. /data/lib/starter_web/pages/public/{legal/learn → learn}/bookshelf/viewer_all_books.adoc +0 -0
  174. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/100_gistblock.asciidoc +0 -0
  175. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_bottom_info.asciidoc +0 -0
  176. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_bottom_left_warning.asciidoc +0 -0
  177. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_bottom_right_danger.asciidoc +0 -0
  178. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_central_success.asciidoc +0 -0
  179. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_full_height_left_info.asciidoc +0 -0
  180. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_full_height_right_success.asciidoc +0 -0
  181. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_table_bs_modal_examples.asciidoc +0 -0
  182. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_top_info.asciidoc +0 -0
  183. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_top_left_info.asciidoc +0 -0
  184. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/410_top_right_success.asciidoc +0 -0
  185. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/419_advanced_modals_demo.asciidoc +0 -0
  186. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/tables/bs_modal_examples.asciidoc +0 -0
  187. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/themes_bootstrap.asciidoc +0 -0
  188. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/_includes/documents/themes_rouge.asciidoc +0 -0
  189. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/asciidoc_extensions.adoc +0 -0
  190. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/bootstrap_themes.adoc +0 -0
  191. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/icon_fonts.adoc +0 -0
  192. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/modal_extentions.adoc +0 -0
  193. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/responsive_tables.adoc +0 -0
  194. /data/lib/starter_web/pages/public/{legal/learn → learn}/roundtrip/typography.adoc +0 -0
  195. /data/lib/starter_web/pages/public/{legal/learn → learn}/where_to_go.adoc +0 -0
@@ -1,1834 +1,1878 @@
1
- /*!
2
- * slim-select.js v2.5.1
1
+ /*
2
+ * slim-select.js v2.8.2
3
3
  * https://github.com/brianvoe/slim-select/tree/master
4
4
  *
5
5
  * Licensed MIT © Brian Voelker
6
6
  * https://github.com/brianvoe/slim-select/blob/master/LICENSE
7
7
  */
8
- (function (global, factory) {
9
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
10
- typeof define === 'function' && define.amd ? define(factory) :
11
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.SlimSelect = factory());
12
- })(this, (function () { 'use strict';
13
8
 
14
- function generateID() {
15
- return Math.random().toString(36).substring(2, 10);
16
- }
17
- function hasClassInTree(element, className) {
18
- function hasClass(e, c) {
19
- if (c && e && e.classList && e.classList.contains(c)) {
20
- return e;
21
- }
22
- if (c && e && e.dataset && e.dataset.id && e.dataset.id === className) {
23
- return e;
24
- }
25
- return null;
26
- }
27
- function parentByClass(e, c) {
28
- if (!e || e === document) {
29
- return null;
30
- }
31
- else if (hasClass(e, c)) {
32
- return e;
33
- }
34
- else {
35
- return parentByClass(e.parentNode, c);
36
- }
37
- }
38
- return hasClass(element, className) || parentByClass(element, className);
39
- }
40
- function debounce(func, wait = 50, immediate = false) {
41
- let timeout;
42
- return function (...args) {
43
- const context = self;
44
- const later = () => {
45
- timeout = null;
46
- if (!immediate) {
47
- func.apply(context, args);
48
- }
49
- };
50
- const callNow = immediate && !timeout;
51
- clearTimeout(timeout);
52
- timeout = setTimeout(later, wait);
53
- if (callNow) {
54
- func.apply(context, args);
55
- }
56
- };
57
- }
58
- function isEqual(a, b) {
59
- return JSON.stringify(a) === JSON.stringify(b);
60
- }
61
- function kebabCase(str) {
62
- const result = str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => '-' + match.toLowerCase());
63
- return str[0] === str[0].toUpperCase() ? result.substring(1) : result;
64
- }
9
+ (function (global, factory) {
10
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11
+ typeof define === 'function' && define.amd ? define(factory) :
12
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.SlimSelect = factory());
13
+ })(this, (function () { 'use strict';
65
14
 
66
- class Settings {
67
- constructor(settings) {
68
- this.id = '';
69
- this.style = '';
70
- this.class = [];
71
- this.isMultiple = false;
72
- this.isOpen = false;
73
- this.isFullOpen = false;
74
- this.intervalMove = null;
75
- if (!settings) {
76
- settings = {};
77
- }
78
- this.id = 'ss-' + generateID();
79
- this.style = settings.style || '';
80
- this.class = settings.class || [];
81
- this.disabled = settings.disabled !== undefined ? settings.disabled : false;
82
- this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false;
83
- this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true;
84
- this.searchPlaceholder = settings.searchPlaceholder || 'Search';
85
- this.searchText = settings.searchText || 'No Results';
86
- this.searchingText = settings.searchingText || 'Searching...';
87
- this.searchHighlight = settings.searchHighlight !== undefined ? settings.searchHighlight : false;
88
- this.closeOnSelect = settings.closeOnSelect !== undefined ? settings.closeOnSelect : true;
89
- this.contentLocation = settings.contentLocation || document.body;
90
- this.contentPosition = settings.contentPosition || 'absolute';
91
- this.openPosition = settings.openPosition || 'auto';
92
- this.placeholderText = settings.placeholderText !== undefined ? settings.placeholderText : 'Select Value';
93
- this.allowDeselect = settings.allowDeselect !== undefined ? settings.allowDeselect : false;
94
- this.hideSelected = settings.hideSelected !== undefined ? settings.hideSelected : false;
95
- this.showOptionTooltips = settings.showOptionTooltips !== undefined ? settings.showOptionTooltips : false;
96
- this.minSelected = settings.minSelected || 0;
97
- this.maxSelected = settings.maxSelected || 1000;
98
- this.timeoutDelay = settings.timeoutDelay || 200;
99
- this.maxValuesShown = settings.maxValuesShown || 20;
100
- this.maxValuesMessage = settings.maxValuesMessage || '{number} selected';
101
- }
102
- }
15
+ function generateID() {
16
+ return Math.random().toString(36).substring(2, 10);
17
+ }
18
+ function hasClassInTree(element, className) {
19
+ function hasClass(e, c) {
20
+ if (c && e && e.classList && e.classList.contains(c)) {
21
+ return e;
22
+ }
23
+ if (c && e && e.dataset && e.dataset.id && e.dataset.id === className) {
24
+ return e;
25
+ }
26
+ return null;
27
+ }
28
+ function parentByClass(e, c) {
29
+ if (!e || e === document) {
30
+ return null;
31
+ }
32
+ else if (hasClass(e, c)) {
33
+ return e;
34
+ }
35
+ else {
36
+ return parentByClass(e.parentNode, c);
37
+ }
38
+ }
39
+ return hasClass(element, className) || parentByClass(element, className);
40
+ }
41
+ function debounce(func, wait = 50, immediate = false) {
42
+ let timeout;
43
+ return function (...args) {
44
+ const context = self;
45
+ const later = () => {
46
+ timeout = null;
47
+ if (!immediate) {
48
+ func.apply(context, args);
49
+ }
50
+ };
51
+ const callNow = immediate && !timeout;
52
+ clearTimeout(timeout);
53
+ timeout = setTimeout(later, wait);
54
+ if (callNow) {
55
+ func.apply(context, args);
56
+ }
57
+ };
58
+ }
59
+ function isEqual(a, b) {
60
+ return JSON.stringify(a) === JSON.stringify(b);
61
+ }
62
+ function kebabCase(str) {
63
+ const result = str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => '-' + match.toLowerCase());
64
+ return str[0] === str[0].toUpperCase() ? result.substring(1) : result;
65
+ }
103
66
 
104
- class Optgroup {
105
- constructor(optgroup) {
106
- this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id;
107
- this.label = optgroup.label || '';
108
- this.selectAll = optgroup.selectAll === undefined ? false : optgroup.selectAll;
109
- this.selectAllText = optgroup.selectAllText || 'Select All';
110
- this.closable = optgroup.closable || 'off';
111
- this.options = [];
112
- if (optgroup.options) {
113
- for (const o of optgroup.options) {
114
- this.options.push(new Option(o));
115
- }
116
- }
117
- }
118
- }
119
- class Option {
120
- constructor(option) {
121
- this.id = !option.id || option.id === '' ? generateID() : option.id;
122
- this.value = option.value === undefined ? option.text : option.value;
123
- this.text = option.text || '';
124
- this.html = option.html || '';
125
- this.selected = option.selected !== undefined ? option.selected : false;
126
- this.display = option.display !== undefined ? option.display : true;
127
- this.disabled = option.disabled !== undefined ? option.disabled : false;
128
- this.mandatory = option.mandatory !== undefined ? option.mandatory : false;
129
- this.placeholder = option.placeholder !== undefined ? option.placeholder : false;
130
- this.class = option.class || '';
131
- this.style = option.style || '';
132
- this.data = option.data || {};
133
- }
134
- }
135
- class Store {
136
- constructor(type, data) {
137
- this.selectType = 'single';
138
- this.data = [];
139
- this.selectType = type;
140
- this.setData(data);
141
- }
142
- validateDataArray(data) {
143
- if (!Array.isArray(data)) {
144
- return new Error('Data must be an array');
145
- }
146
- for (let dataObj of data) {
147
- if (dataObj instanceof Optgroup || 'label' in dataObj) {
148
- if (!('label' in dataObj)) {
149
- return new Error('Optgroup must have a label');
150
- }
151
- if ('options' in dataObj && dataObj.options) {
152
- for (let option of dataObj.options) {
153
- return this.validateOption(option);
154
- }
155
- }
156
- }
157
- else if (dataObj instanceof Option || 'text' in dataObj) {
158
- return this.validateOption(dataObj);
159
- }
160
- else {
161
- return new Error('Data object must be a valid optgroup or option');
162
- }
163
- }
164
- return null;
165
- }
166
- validateOption(option) {
167
- if (!('text' in option)) {
168
- return new Error('Option must have a text');
169
- }
170
- return null;
171
- }
172
- partialToFullData(data) {
173
- let dataFinal = [];
174
- data.forEach((dataObj) => {
175
- if (dataObj instanceof Optgroup || 'label' in dataObj) {
176
- let optOptions = [];
177
- if ('options' in dataObj && dataObj.options) {
178
- dataObj.options.forEach((option) => {
179
- optOptions.push(new Option(option));
180
- });
181
- }
182
- if (optOptions.length > 0) {
183
- dataFinal.push(new Optgroup(dataObj));
184
- }
185
- }
186
- if (dataObj instanceof Option || 'text' in dataObj) {
187
- dataFinal.push(new Option(dataObj));
188
- }
189
- });
190
- return dataFinal;
191
- }
192
- setData(data) {
193
- this.data = this.partialToFullData(data);
194
- if (this.selectType === 'single') {
195
- this.setSelectedBy('value', this.getSelected());
196
- }
197
- }
198
- getData() {
199
- return this.filter(null, true);
200
- }
201
- getDataOptions() {
202
- return this.filter(null, false);
203
- }
204
- addOption(option) {
205
- this.setData(this.getData().concat(new Option(option)));
206
- }
207
- setSelectedBy(selectedType, selectedValues) {
208
- let firstOption = null;
209
- let hasSelected = false;
210
- for (let dataObj of this.data) {
211
- if (dataObj instanceof Optgroup) {
212
- for (let option of dataObj.options) {
213
- if (!firstOption) {
214
- firstOption = option;
215
- }
216
- option.selected = hasSelected ? false : selectedValues.includes(option[selectedType]);
217
- if (option.selected && this.selectType === 'single') {
218
- hasSelected = true;
219
- }
220
- }
221
- }
222
- if (dataObj instanceof Option) {
223
- if (!firstOption) {
224
- firstOption = dataObj;
225
- }
226
- dataObj.selected = hasSelected ? false : selectedValues.includes(dataObj[selectedType]);
227
- if (dataObj.selected && this.selectType === 'single') {
228
- hasSelected = true;
229
- }
230
- }
231
- }
232
- if (this.selectType === 'single' && firstOption && !hasSelected) {
233
- firstOption.selected = true;
234
- }
235
- }
236
- getSelected() {
237
- let selectedOptions = this.getSelectedOptions();
238
- let selectedValues = [];
239
- selectedOptions.forEach((option) => {
240
- selectedValues.push(option.value);
241
- });
242
- return selectedValues;
243
- }
244
- getSelectedOptions() {
245
- return this.filter((opt) => {
246
- return opt.selected;
247
- }, false);
248
- }
249
- getSelectedIDs() {
250
- let selectedOptions = this.getSelectedOptions();
251
- let selectedIDs = [];
252
- selectedOptions.forEach((op) => {
253
- selectedIDs.push(op.id);
254
- });
255
- return selectedIDs;
256
- }
257
- getOptgroupByID(id) {
258
- for (let dataObj of this.data) {
259
- if (dataObj instanceof Optgroup && dataObj.id === id) {
260
- return dataObj;
261
- }
262
- }
263
- return null;
264
- }
265
- getOptionByID(id) {
266
- let options = this.filter((opt) => {
267
- return opt.id === id;
268
- }, false);
269
- return options.length ? options[0] : null;
270
- }
271
- search(search, searchFilter) {
272
- search = search.trim();
273
- if (search === '') {
274
- return this.getData();
275
- }
276
- return this.filter((opt) => {
277
- return searchFilter(opt, search);
278
- }, true);
279
- }
280
- filter(filter, includeOptgroup) {
281
- const dataSearch = [];
282
- this.data.forEach((dataObj) => {
283
- if (dataObj instanceof Optgroup) {
284
- let optOptions = [];
285
- dataObj.options.forEach((option) => {
286
- if (!filter || filter(option)) {
287
- if (!includeOptgroup) {
288
- dataSearch.push(new Option(option));
289
- }
290
- else {
291
- optOptions.push(new Option(option));
292
- }
293
- }
294
- });
295
- if (optOptions.length > 0) {
296
- let optgroup = new Optgroup(dataObj);
297
- optgroup.options = optOptions;
298
- dataSearch.push(optgroup);
299
- }
300
- }
301
- if (dataObj instanceof Option) {
302
- if (!filter || filter(dataObj)) {
303
- dataSearch.push(new Option(dataObj));
304
- }
305
- }
306
- });
307
- return dataSearch;
308
- }
309
- getSelectType() {
310
- return this.selectType;
311
- }
312
- }
67
+ class Optgroup {
68
+ constructor(optgroup) {
69
+ this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id;
70
+ this.label = optgroup.label || '';
71
+ this.selectAll = optgroup.selectAll === undefined ? false : optgroup.selectAll;
72
+ this.selectAllText = optgroup.selectAllText || 'Select All';
73
+ this.closable = optgroup.closable || 'off';
74
+ this.options = [];
75
+ if (optgroup.options) {
76
+ for (const o of optgroup.options) {
77
+ this.options.push(new Option(o));
78
+ }
79
+ }
80
+ }
81
+ }
82
+ class Option {
83
+ constructor(option) {
84
+ this.id = !option.id || option.id === '' ? generateID() : option.id;
85
+ this.value = option.value === undefined ? option.text : option.value;
86
+ this.text = option.text || '';
87
+ this.html = option.html || '';
88
+ this.selected = option.selected !== undefined ? option.selected : false;
89
+ this.display = option.display !== undefined ? option.display : true;
90
+ this.disabled = option.disabled !== undefined ? option.disabled : false;
91
+ this.mandatory = option.mandatory !== undefined ? option.mandatory : false;
92
+ this.placeholder = option.placeholder !== undefined ? option.placeholder : false;
93
+ this.class = option.class || '';
94
+ this.style = option.style || '';
95
+ this.data = option.data || {};
96
+ }
97
+ }
98
+ class Store {
99
+ constructor(type, data) {
100
+ this.selectType = 'single';
101
+ this.data = [];
102
+ this.selectType = type;
103
+ this.setData(data);
104
+ }
105
+ validateDataArray(data) {
106
+ if (!Array.isArray(data)) {
107
+ return new Error('Data must be an array');
108
+ }
109
+ for (let dataObj of data) {
110
+ if (dataObj instanceof Optgroup || 'label' in dataObj) {
111
+ if (!('label' in dataObj)) {
112
+ return new Error('Optgroup must have a label');
113
+ }
114
+ if ('options' in dataObj && dataObj.options) {
115
+ for (let option of dataObj.options) {
116
+ return this.validateOption(option);
117
+ }
118
+ }
119
+ }
120
+ else if (dataObj instanceof Option || 'text' in dataObj) {
121
+ return this.validateOption(dataObj);
122
+ }
123
+ else {
124
+ return new Error('Data object must be a valid optgroup or option');
125
+ }
126
+ }
127
+ return null;
128
+ }
129
+ validateOption(option) {
130
+ if (!('text' in option)) {
131
+ return new Error('Option must have a text');
132
+ }
133
+ return null;
134
+ }
135
+ partialToFullData(data) {
136
+ let dataFinal = [];
137
+ data.forEach((dataObj) => {
138
+ if (dataObj instanceof Optgroup || 'label' in dataObj) {
139
+ let optOptions = [];
140
+ if ('options' in dataObj && dataObj.options) {
141
+ dataObj.options.forEach((option) => {
142
+ optOptions.push(new Option(option));
143
+ });
144
+ }
145
+ if (optOptions.length > 0) {
146
+ dataFinal.push(new Optgroup(dataObj));
147
+ }
148
+ }
149
+ if (dataObj instanceof Option || 'text' in dataObj) {
150
+ dataFinal.push(new Option(dataObj));
151
+ }
152
+ });
153
+ return dataFinal;
154
+ }
155
+ setData(data) {
156
+ this.data = this.partialToFullData(data);
157
+ if (this.selectType === 'single') {
158
+ this.setSelectedBy('value', this.getSelected());
159
+ }
160
+ }
161
+ getData() {
162
+ return this.filter(null, true);
163
+ }
164
+ getDataOptions() {
165
+ return this.filter(null, false);
166
+ }
167
+ addOption(option) {
168
+ this.setData(this.getData().concat(new Option(option)));
169
+ }
170
+ setSelectedBy(selectedType, selectedValues) {
171
+ let firstOption = null;
172
+ let hasSelected = false;
173
+ for (let dataObj of this.data) {
174
+ if (dataObj instanceof Optgroup) {
175
+ for (let option of dataObj.options) {
176
+ if (!firstOption) {
177
+ firstOption = option;
178
+ }
179
+ option.selected = hasSelected ? false : selectedValues.includes(option[selectedType]);
180
+ if (option.selected && this.selectType === 'single') {
181
+ hasSelected = true;
182
+ }
183
+ }
184
+ }
185
+ if (dataObj instanceof Option) {
186
+ if (!firstOption) {
187
+ firstOption = dataObj;
188
+ }
189
+ dataObj.selected = hasSelected ? false : selectedValues.includes(dataObj[selectedType]);
190
+ if (dataObj.selected && this.selectType === 'single') {
191
+ hasSelected = true;
192
+ }
193
+ }
194
+ }
195
+ if (this.selectType === 'single' && firstOption && !hasSelected) {
196
+ firstOption.selected = true;
197
+ }
198
+ }
199
+ getSelected() {
200
+ let selectedOptions = this.getSelectedOptions();
201
+ let selectedValues = [];
202
+ selectedOptions.forEach((option) => {
203
+ selectedValues.push(option.value);
204
+ });
205
+ return selectedValues;
206
+ }
207
+ getSelectedOptions() {
208
+ return this.filter((opt) => {
209
+ return opt.selected;
210
+ }, false);
211
+ }
212
+ getSelectedIDs() {
213
+ let selectedOptions = this.getSelectedOptions();
214
+ let selectedIDs = [];
215
+ selectedOptions.forEach((op) => {
216
+ selectedIDs.push(op.id);
217
+ });
218
+ return selectedIDs;
219
+ }
220
+ getOptgroupByID(id) {
221
+ for (let dataObj of this.data) {
222
+ if (dataObj instanceof Optgroup && dataObj.id === id) {
223
+ return dataObj;
224
+ }
225
+ }
226
+ return null;
227
+ }
228
+ getOptionByID(id) {
229
+ let options = this.filter((opt) => {
230
+ return opt.id === id;
231
+ }, false);
232
+ return options.length ? options[0] : null;
233
+ }
234
+ getSelectType() {
235
+ return this.selectType;
236
+ }
237
+ getFirstOption() {
238
+ let option = null;
239
+ for (let dataObj of this.data) {
240
+ if (dataObj instanceof Optgroup) {
241
+ option = dataObj.options[0];
242
+ }
243
+ else if (dataObj instanceof Option) {
244
+ option = dataObj;
245
+ }
246
+ if (option) {
247
+ break;
248
+ }
249
+ }
250
+ return option;
251
+ }
252
+ search(search, searchFilter) {
253
+ search = search.trim();
254
+ if (search === '') {
255
+ return this.getData();
256
+ }
257
+ return this.filter((opt) => {
258
+ return searchFilter(opt, search);
259
+ }, true);
260
+ }
261
+ filter(filter, includeOptgroup) {
262
+ const dataSearch = [];
263
+ this.data.forEach((dataObj) => {
264
+ if (dataObj instanceof Optgroup) {
265
+ let optOptions = [];
266
+ dataObj.options.forEach((option) => {
267
+ if (!filter || filter(option)) {
268
+ if (!includeOptgroup) {
269
+ dataSearch.push(new Option(option));
270
+ }
271
+ else {
272
+ optOptions.push(new Option(option));
273
+ }
274
+ }
275
+ });
276
+ if (optOptions.length > 0) {
277
+ let optgroup = new Optgroup(dataObj);
278
+ optgroup.options = optOptions;
279
+ dataSearch.push(optgroup);
280
+ }
281
+ }
282
+ if (dataObj instanceof Option) {
283
+ if (!filter || filter(dataObj)) {
284
+ dataSearch.push(new Option(dataObj));
285
+ }
286
+ }
287
+ });
288
+ return dataSearch;
289
+ }
290
+ }
313
291
 
314
- class Render {
315
- constructor(settings, store, callbacks) {
316
- this.classes = {
317
- main: 'ss-main',
318
- placeholder: 'ss-placeholder',
319
- values: 'ss-values',
320
- single: 'ss-single',
321
- max: 'ss-max',
322
- value: 'ss-value',
323
- valueText: 'ss-value-text',
324
- valueDelete: 'ss-value-delete',
325
- valueOut: 'ss-value-out',
326
- deselect: 'ss-deselect',
327
- deselectPath: 'M10,10 L90,90 M10,90 L90,10',
328
- arrow: 'ss-arrow',
329
- arrowClose: 'M10,30 L50,70 L90,30',
330
- arrowOpen: 'M10,70 L50,30 L90,70',
331
- content: 'ss-content',
332
- openAbove: 'ss-open-above',
333
- openBelow: 'ss-open-below',
334
- search: 'ss-search',
335
- searchHighlighter: 'ss-search-highlight',
336
- searching: 'ss-searching',
337
- addable: 'ss-addable',
338
- addablePath: 'M50,10 L50,90 M10,50 L90,50',
339
- list: 'ss-list',
340
- optgroup: 'ss-optgroup',
341
- optgroupLabel: 'ss-optgroup-label',
342
- optgroupLabelText: 'ss-optgroup-label-text',
343
- optgroupActions: 'ss-optgroup-actions',
344
- optgroupSelectAll: 'ss-selectall',
345
- optgroupSelectAllBox: 'M60,10 L10,10 L10,90 L90,90 L90,50',
346
- optgroupSelectAllCheck: 'M30,45 L50,70 L90,10',
347
- optgroupClosable: 'ss-closable',
348
- option: 'ss-option',
349
- optionDelete: 'M10,10 L90,90 M10,90 L90,10',
350
- highlighted: 'ss-highlighted',
351
- open: 'ss-open',
352
- close: 'ss-close',
353
- selected: 'ss-selected',
354
- error: 'ss-error',
355
- disabled: 'ss-disabled',
356
- hide: 'ss-hide',
357
- };
358
- this.store = store;
359
- this.settings = settings;
360
- this.callbacks = callbacks;
361
- this.main = this.mainDiv();
362
- this.content = this.contentDiv();
363
- this.updateClassStyles();
364
- this.updateAriaAttributes();
365
- this.settings.contentLocation.appendChild(this.content.main);
366
- }
367
- enable() {
368
- this.main.main.classList.remove(this.classes.disabled);
369
- this.content.search.input.disabled = false;
370
- }
371
- disable() {
372
- this.main.main.classList.add(this.classes.disabled);
373
- this.content.search.input.disabled = true;
374
- }
375
- open() {
376
- this.main.arrow.path.setAttribute('d', this.classes.arrowOpen);
377
- this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
378
- this.main.main.setAttribute('aria-expanded', 'true');
379
- this.moveContent();
380
- const selectedOptions = this.store.getSelectedOptions();
381
- if (selectedOptions.length) {
382
- const selectedId = selectedOptions[selectedOptions.length - 1].id;
383
- const selectedOption = this.content.list.querySelector('[data-id="' + selectedId + '"]');
384
- if (selectedOption) {
385
- this.ensureElementInView(this.content.list, selectedOption);
386
- }
387
- }
388
- }
389
- close() {
390
- this.main.main.classList.remove(this.classes.openAbove);
391
- this.main.main.classList.remove(this.classes.openBelow);
392
- this.main.main.setAttribute('aria-expanded', 'false');
393
- this.content.main.classList.remove(this.classes.openAbove);
394
- this.content.main.classList.remove(this.classes.openBelow);
395
- this.main.arrow.path.setAttribute('d', this.classes.arrowClose);
396
- }
397
- updateClassStyles() {
398
- this.main.main.className = '';
399
- this.main.main.removeAttribute('style');
400
- this.content.main.className = '';
401
- this.content.main.removeAttribute('style');
402
- this.main.main.classList.add(this.classes.main);
403
- this.content.main.classList.add(this.classes.content);
404
- if (this.settings.style !== '') {
405
- this.main.main.style.cssText = this.settings.style;
406
- this.content.main.style.cssText = this.settings.style;
407
- }
408
- if (this.settings.class.length) {
409
- for (const c of this.settings.class) {
410
- if (c.trim() !== '') {
411
- this.main.main.classList.add(c.trim());
412
- this.content.main.classList.add(c.trim());
413
- }
414
- }
415
- }
416
- if (this.settings.contentPosition === 'relative') {
417
- this.content.main.classList.add('ss-' + this.settings.contentPosition);
418
- }
419
- }
420
- updateAriaAttributes() {
421
- this.main.main.role = 'combobox';
422
- this.main.main.setAttribute('aria-haspopup', 'listbox');
423
- this.main.main.setAttribute('aria-controls', this.content.main.id);
424
- this.main.main.setAttribute('aria-expanded', 'false');
425
- this.content.main.setAttribute('role', 'listbox');
426
- }
427
- mainDiv() {
428
- var _a;
429
- const main = document.createElement('div');
430
- main.dataset.id = this.settings.id;
431
- main.id = this.settings.id;
432
- main.tabIndex = 0;
433
- main.onkeydown = (e) => {
434
- switch (e.key) {
435
- case 'ArrowUp':
436
- case 'ArrowDown':
437
- this.callbacks.open();
438
- e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
439
- return false;
440
- case 'Tab':
441
- this.callbacks.close();
442
- return true;
443
- case 'Enter':
444
- case ' ':
445
- this.callbacks.open();
446
- const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
447
- if (highlighted) {
448
- highlighted.click();
449
- }
450
- return false;
451
- case 'Escape':
452
- this.callbacks.close();
453
- return false;
454
- }
455
- };
456
- main.onclick = (e) => {
457
- if (this.settings.disabled) {
458
- return;
459
- }
460
- this.settings.isOpen ? this.callbacks.close() : this.callbacks.open();
461
- };
462
- const values = document.createElement('div');
463
- values.classList.add(this.classes.values);
464
- main.appendChild(values);
465
- const deselect = document.createElement('div');
466
- deselect.classList.add(this.classes.deselect);
467
- const selectedOptions = (_a = this.store) === null || _a === void 0 ? void 0 : _a.getSelectedOptions();
468
- if (!this.settings.allowDeselect || (this.settings.isMultiple && selectedOptions && selectedOptions.length <= 0)) {
469
- deselect.classList.add(this.classes.hide);
470
- }
471
- else {
472
- deselect.classList.remove(this.classes.hide);
473
- }
474
- deselect.onclick = (e) => {
475
- e.stopPropagation();
476
- if (this.settings.disabled) {
477
- return;
478
- }
479
- let shouldDelete = true;
480
- const before = this.store.getSelectedOptions();
481
- const after = [];
482
- if (this.callbacks.beforeChange) {
483
- shouldDelete = this.callbacks.beforeChange(after, before) === true;
484
- }
485
- if (shouldDelete) {
486
- if (this.settings.isMultiple) {
487
- this.callbacks.setSelected([], false);
488
- this.updateDeselectAll();
489
- }
490
- else {
491
- this.callbacks.setSelected([''], false);
492
- }
493
- if (this.settings.closeOnSelect) {
494
- this.callbacks.close();
495
- }
496
- if (this.callbacks.afterChange) {
497
- this.callbacks.afterChange(after);
498
- }
499
- }
500
- };
501
- const deselectSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
502
- deselectSvg.setAttribute('viewBox', '0 0 100 100');
503
- const deselectPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
504
- deselectPath.setAttribute('d', this.classes.deselectPath);
505
- deselectSvg.appendChild(deselectPath);
506
- deselect.appendChild(deselectSvg);
507
- main.appendChild(deselect);
508
- const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
509
- arrow.classList.add(this.classes.arrow);
510
- arrow.setAttribute('viewBox', '0 0 100 100');
511
- const arrowPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
512
- arrowPath.setAttribute('d', this.classes.arrowClose);
513
- if (this.settings.alwaysOpen) {
514
- arrow.classList.add(this.classes.hide);
515
- }
516
- arrow.appendChild(arrowPath);
517
- main.appendChild(arrow);
518
- return {
519
- main: main,
520
- values: values,
521
- deselect: {
522
- main: deselect,
523
- svg: deselectSvg,
524
- path: deselectPath,
525
- },
526
- arrow: {
527
- main: arrow,
528
- path: arrowPath,
529
- },
530
- };
531
- }
532
- mainFocus(eventType) {
533
- if (eventType !== 'click') {
534
- this.main.main.focus({ preventScroll: true });
535
- }
536
- }
537
- placeholder() {
538
- const placeholderOption = this.store.filter((o) => o.placeholder, false);
539
- let placeholderText = this.settings.placeholderText;
540
- if (placeholderOption.length) {
541
- if (placeholderOption[0].html !== '') {
542
- placeholderText = placeholderOption[0].html;
543
- }
544
- else if (placeholderOption[0].text !== '') {
545
- placeholderText = placeholderOption[0].text;
546
- }
547
- }
548
- const placeholder = document.createElement('div');
549
- placeholder.classList.add(this.classes.placeholder);
550
- placeholder.innerHTML = placeholderText;
551
- return placeholder;
552
- }
553
- renderValues() {
554
- if (!this.settings.isMultiple) {
555
- this.renderSingleValue();
556
- return;
557
- }
558
- this.renderMultipleValues();
559
- }
560
- renderSingleValue() {
561
- const selected = this.store.filter((o) => {
562
- return o.selected && !o.placeholder;
563
- }, false);
564
- const selectedSingle = selected.length > 0 ? selected[0] : null;
565
- if (!selectedSingle) {
566
- this.main.values.innerHTML = this.placeholder().outerHTML;
567
- }
568
- else {
569
- const singleValue = document.createElement('div');
570
- singleValue.classList.add(this.classes.single);
571
- if (selectedSingle.html) {
572
- singleValue.innerHTML = selectedSingle.html;
573
- }
574
- else {
575
- singleValue.innerText = selectedSingle.text;
576
- }
577
- this.main.values.innerHTML = singleValue.outerHTML;
578
- }
579
- if (!this.settings.allowDeselect || !selected.length) {
580
- this.main.deselect.main.classList.add(this.classes.hide);
581
- }
582
- else {
583
- this.main.deselect.main.classList.remove(this.classes.hide);
584
- }
585
- }
586
- renderMultipleValues() {
587
- let currentNodes = this.main.values.childNodes;
588
- let selectedOptions = this.store.filter((opt) => {
589
- return opt.selected && opt.display;
590
- }, false);
591
- if (selectedOptions.length === 0) {
592
- this.main.values.innerHTML = this.placeholder().outerHTML;
593
- return;
594
- }
595
- else {
596
- const placeholder = this.main.values.querySelector('.' + this.classes.placeholder);
597
- if (placeholder) {
598
- placeholder.remove();
599
- }
600
- }
601
- if (selectedOptions.length > this.settings.maxValuesShown) {
602
- const singleValue = document.createElement('div');
603
- singleValue.classList.add(this.classes.max);
604
- singleValue.textContent = this.settings.maxValuesMessage.replace('{number}', selectedOptions.length.toString());
605
- this.main.values.innerHTML = singleValue.outerHTML;
606
- return;
607
- }
608
- else {
609
- const maxValuesMessage = this.main.values.querySelector('.' + this.classes.max);
610
- if (maxValuesMessage) {
611
- maxValuesMessage.remove();
612
- }
613
- }
614
- let removeNodes = [];
615
- for (let i = 0; i < currentNodes.length; i++) {
616
- const node = currentNodes[i];
617
- const id = node.getAttribute('data-id');
618
- if (id) {
619
- const found = selectedOptions.filter((opt) => {
620
- return opt.id === id;
621
- }, false);
622
- if (!found.length) {
623
- removeNodes.push(node);
624
- }
625
- }
626
- }
627
- for (const n of removeNodes) {
628
- n.classList.add(this.classes.valueOut);
629
- setTimeout(() => {
630
- if (this.main.values.hasChildNodes() && this.main.values.contains(n)) {
631
- this.main.values.removeChild(n);
632
- }
633
- }, 100);
634
- }
635
- currentNodes = this.main.values.childNodes;
636
- for (let d = 0; d < selectedOptions.length; d++) {
637
- let shouldAdd = true;
638
- for (let i = 0; i < currentNodes.length; i++) {
639
- if (selectedOptions[d].id === String(currentNodes[i].dataset.id)) {
640
- shouldAdd = false;
641
- }
642
- }
643
- if (shouldAdd) {
644
- if (currentNodes.length === 0) {
645
- this.main.values.appendChild(this.multipleValue(selectedOptions[d]));
646
- }
647
- else if (d === 0) {
648
- this.main.values.insertBefore(this.multipleValue(selectedOptions[d]), currentNodes[d]);
649
- }
650
- else {
651
- currentNodes[d - 1].insertAdjacentElement('afterend', this.multipleValue(selectedOptions[d]));
652
- }
653
- }
654
- }
655
- this.updateDeselectAll();
656
- }
657
- multipleValue(option) {
658
- const value = document.createElement('div');
659
- value.classList.add(this.classes.value);
660
- value.dataset.id = option.id;
661
- const text = document.createElement('div');
662
- text.classList.add(this.classes.valueText);
663
- text.innerText = option.text;
664
- value.appendChild(text);
665
- if (!option.mandatory) {
666
- const deleteDiv = document.createElement('div');
667
- deleteDiv.classList.add(this.classes.valueDelete);
668
- deleteDiv.onclick = (e) => {
669
- e.preventDefault();
670
- e.stopPropagation();
671
- if (this.settings.disabled) {
672
- return;
673
- }
674
- let shouldDelete = true;
675
- const before = this.store.getSelectedOptions();
676
- const after = before.filter((o) => {
677
- return o.selected && o.id !== option.id;
678
- }, true);
679
- if (this.settings.minSelected && after.length < this.settings.minSelected) {
680
- return;
681
- }
682
- if (this.callbacks.beforeChange) {
683
- shouldDelete = this.callbacks.beforeChange(after, before) === true;
684
- }
685
- if (shouldDelete) {
686
- let selectedValues = [];
687
- for (const o of after) {
688
- if (o instanceof Optgroup) {
689
- for (const c of o.options) {
690
- selectedValues.push(c.value);
691
- }
692
- }
693
- if (o instanceof Option) {
694
- selectedValues.push(o.value);
695
- }
696
- }
697
- this.callbacks.setSelected(selectedValues, false);
698
- if (this.settings.closeOnSelect) {
699
- this.callbacks.close();
700
- }
701
- if (this.callbacks.afterChange) {
702
- this.callbacks.afterChange(after);
703
- }
704
- this.updateDeselectAll();
705
- }
706
- };
707
- const deleteSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
708
- deleteSvg.setAttribute('viewBox', '0 0 100 100');
709
- const deletePath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
710
- deletePath.setAttribute('d', this.classes.optionDelete);
711
- deleteSvg.appendChild(deletePath);
712
- deleteDiv.appendChild(deleteSvg);
713
- value.appendChild(deleteDiv);
714
- }
715
- return value;
716
- }
717
- contentDiv() {
718
- const main = document.createElement('div');
719
- main.dataset.id = this.settings.id;
720
- main.id = this.settings.id;
721
- const search = this.searchDiv();
722
- main.appendChild(search.main);
723
- const list = this.listDiv();
724
- main.appendChild(list);
725
- return {
726
- main: main,
727
- search: search,
728
- list: list,
729
- };
730
- }
731
- moveContent() {
732
- if (this.settings.contentPosition === 'relative') {
733
- this.moveContentBelow();
734
- return;
735
- }
736
- if (this.settings.openPosition === 'down') {
737
- this.moveContentBelow();
738
- return;
739
- }
740
- else if (this.settings.openPosition === 'up') {
741
- this.moveContentAbove();
742
- return;
743
- }
744
- if (this.putContent() === 'up') {
745
- this.moveContentAbove();
746
- }
747
- else {
748
- this.moveContentBelow();
749
- }
750
- }
751
- searchDiv() {
752
- const main = document.createElement('div');
753
- const input = document.createElement('input');
754
- const addable = document.createElement('div');
755
- main.classList.add(this.classes.search);
756
- const searchReturn = {
757
- main,
758
- input,
759
- };
760
- if (!this.settings.showSearch) {
761
- main.classList.add(this.classes.hide);
762
- input.readOnly = true;
763
- }
764
- input.type = 'search';
765
- input.placeholder = this.settings.searchPlaceholder;
766
- input.tabIndex = -1;
767
- input.setAttribute('aria-label', this.settings.searchPlaceholder);
768
- input.setAttribute('autocapitalize', 'off');
769
- input.setAttribute('autocomplete', 'off');
770
- input.setAttribute('autocorrect', 'off');
771
- input.oninput = debounce((e) => {
772
- this.callbacks.search(e.target.value);
773
- }, 100);
774
- input.onkeydown = (e) => {
775
- switch (e.key) {
776
- case 'ArrowUp':
777
- case 'ArrowDown':
778
- e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
779
- return false;
780
- case 'Tab':
781
- this.callbacks.close();
782
- return true;
783
- case 'Escape':
784
- this.callbacks.close();
785
- return false;
786
- case 'Enter':
787
- case ' ':
788
- if (this.callbacks.addable && e.ctrlKey) {
789
- addable.click();
790
- return false;
791
- }
792
- else {
793
- const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
794
- if (highlighted) {
795
- highlighted.click();
796
- return false;
797
- }
798
- }
799
- return true;
800
- }
801
- };
802
- main.appendChild(input);
803
- if (this.callbacks.addable) {
804
- addable.classList.add(this.classes.addable);
805
- const plus = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
806
- plus.setAttribute('viewBox', '0 0 100 100');
807
- const plusPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
808
- plusPath.setAttribute('d', this.classes.addablePath);
809
- plus.appendChild(plusPath);
810
- addable.appendChild(plus);
811
- addable.onclick = (e) => {
812
- e.preventDefault();
813
- e.stopPropagation();
814
- if (!this.callbacks.addable) {
815
- return;
816
- }
817
- const inputValue = this.content.search.input.value.trim();
818
- if (inputValue === '') {
819
- this.content.search.input.focus();
820
- return;
821
- }
822
- const runFinish = (oo) => {
823
- let newOption = new Option(oo);
824
- this.callbacks.addOption(newOption);
825
- if (this.settings.isMultiple) {
826
- let values = this.store.getSelected();
827
- values.push(newOption.value);
828
- this.callbacks.setSelected(values, true);
829
- }
830
- else {
831
- this.callbacks.setSelected([newOption.value], true);
832
- }
833
- this.callbacks.search('');
834
- if (this.settings.closeOnSelect) {
835
- setTimeout(() => {
836
- this.callbacks.close();
837
- }, 100);
838
- }
839
- };
840
- const addableValue = this.callbacks.addable(inputValue);
841
- if (addableValue === false || addableValue === undefined || addableValue === null) {
842
- return;
843
- }
844
- if (addableValue instanceof Promise) {
845
- addableValue.then((value) => {
846
- if (typeof value === 'string') {
847
- runFinish({
848
- text: value,
849
- value: value,
850
- });
851
- }
852
- else {
853
- runFinish(value);
854
- }
855
- });
856
- }
857
- else if (typeof addableValue === 'string') {
858
- runFinish({
859
- text: addableValue,
860
- value: addableValue,
861
- });
862
- }
863
- else {
864
- runFinish(addableValue);
865
- }
866
- return;
867
- };
868
- main.appendChild(addable);
869
- searchReturn.addable = {
870
- main: addable,
871
- svg: plus,
872
- path: plusPath,
873
- };
874
- }
875
- return searchReturn;
876
- }
877
- searchFocus() {
878
- this.content.search.input.focus();
879
- }
880
- getOptions(notPlaceholder = false, notDisabled = false, notHidden = false) {
881
- let query = '.' + this.classes.option;
882
- if (notPlaceholder) {
883
- query += ':not(.' + this.classes.placeholder + ')';
884
- }
885
- if (notDisabled) {
886
- query += ':not(.' + this.classes.disabled + ')';
887
- }
888
- if (notHidden) {
889
- query += ':not(.' + this.classes.hide + ')';
890
- }
891
- return Array.from(this.content.list.querySelectorAll(query));
892
- }
893
- highlight(dir) {
894
- const options = this.getOptions(true, true, true);
895
- if (options.length === 0) {
896
- return;
897
- }
898
- if (options.length === 1) {
899
- if (!options[0].classList.contains(this.classes.highlighted)) {
900
- options[0].classList.add(this.classes.highlighted);
901
- return;
902
- }
903
- }
904
- for (let i = 0; i < options.length; i++) {
905
- if (options[i].classList.contains(this.classes.highlighted)) {
906
- const prevOption = options[i];
907
- prevOption.classList.remove(this.classes.highlighted);
908
- const prevParent = prevOption.parentElement;
909
- if (prevParent && prevParent.classList.contains(this.classes.open)) {
910
- const optgroupLabel = prevParent.querySelector('.' + this.classes.optgroupLabel);
911
- if (optgroupLabel) {
912
- optgroupLabel.click();
913
- }
914
- }
915
- let selectOption = options[dir === 'down' ? (i + 1 < options.length ? i + 1 : 0) : i - 1 >= 0 ? i - 1 : options.length - 1];
916
- selectOption.classList.add(this.classes.highlighted);
917
- this.ensureElementInView(this.content.list, selectOption);
918
- const selectParent = selectOption.parentElement;
919
- if (selectParent && selectParent.classList.contains(this.classes.close)) {
920
- const optgroupLabel = selectParent.querySelector('.' + this.classes.optgroupLabel);
921
- if (optgroupLabel) {
922
- optgroupLabel.click();
923
- }
924
- }
925
- return;
926
- }
927
- }
928
- options[dir === 'down' ? 0 : options.length - 1].classList.add(this.classes.highlighted);
929
- this.ensureElementInView(this.content.list, options[dir === 'down' ? 0 : options.length - 1]);
930
- }
931
- listDiv() {
932
- const options = document.createElement('div');
933
- options.classList.add(this.classes.list);
934
- return options;
935
- }
936
- renderError(error) {
937
- this.content.list.innerHTML = '';
938
- const errorDiv = document.createElement('div');
939
- errorDiv.classList.add(this.classes.error);
940
- errorDiv.textContent = error;
941
- this.content.list.appendChild(errorDiv);
942
- }
943
- renderSearching() {
944
- this.content.list.innerHTML = '';
945
- const searchingDiv = document.createElement('div');
946
- searchingDiv.classList.add(this.classes.searching);
947
- searchingDiv.textContent = this.settings.searchingText;
948
- this.content.list.appendChild(searchingDiv);
949
- }
950
- renderOptions(data) {
951
- this.content.list.innerHTML = '';
952
- if (data.length === 0) {
953
- const noResults = document.createElement('div');
954
- noResults.classList.add(this.classes.search);
955
- noResults.innerHTML = this.settings.searchText;
956
- this.content.list.appendChild(noResults);
957
- return;
958
- }
959
- for (const d of data) {
960
- if (d instanceof Optgroup) {
961
- const optgroupEl = document.createElement('div');
962
- optgroupEl.classList.add(this.classes.optgroup);
963
- const optgroupLabel = document.createElement('div');
964
- optgroupLabel.classList.add(this.classes.optgroupLabel);
965
- optgroupEl.appendChild(optgroupLabel);
966
- const optgroupLabelText = document.createElement('div');
967
- optgroupLabelText.classList.add(this.classes.optgroupLabelText);
968
- optgroupLabelText.textContent = d.label;
969
- optgroupLabel.appendChild(optgroupLabelText);
970
- const optgroupActions = document.createElement('div');
971
- optgroupActions.classList.add(this.classes.optgroupActions);
972
- optgroupLabel.appendChild(optgroupActions);
973
- if (this.settings.isMultiple && d.selectAll) {
974
- const selectAll = document.createElement('div');
975
- selectAll.classList.add(this.classes.optgroupSelectAll);
976
- let allSelected = true;
977
- for (const o of d.options) {
978
- if (!o.selected) {
979
- allSelected = false;
980
- break;
981
- }
982
- }
983
- if (allSelected) {
984
- selectAll.classList.add(this.classes.selected);
985
- }
986
- const selectAllText = document.createElement('span');
987
- selectAllText.textContent = d.selectAllText;
988
- selectAll.appendChild(selectAllText);
989
- const selectAllSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
990
- selectAllSvg.setAttribute('viewBox', '0 0 100 100');
991
- selectAll.appendChild(selectAllSvg);
992
- const selectAllBox = document.createElementNS('http://www.w3.org/2000/svg', 'path');
993
- selectAllBox.setAttribute('d', this.classes.optgroupSelectAllBox);
994
- selectAllSvg.appendChild(selectAllBox);
995
- const selectAllCheck = document.createElementNS('http://www.w3.org/2000/svg', 'path');
996
- selectAllCheck.setAttribute('d', this.classes.optgroupSelectAllCheck);
997
- selectAllSvg.appendChild(selectAllCheck);
998
- selectAll.addEventListener('click', (e) => {
999
- e.preventDefault();
1000
- e.stopPropagation();
1001
- const currentSelected = this.store.getSelected();
1002
- if (allSelected) {
1003
- const newSelected = currentSelected.filter((s) => {
1004
- for (const o of d.options) {
1005
- if (s === o.value) {
1006
- return false;
1007
- }
1008
- }
1009
- return true;
1010
- });
1011
- this.callbacks.setSelected(newSelected, true);
1012
- return;
1013
- }
1014
- else {
1015
- const newSelected = currentSelected.concat(d.options.map((o) => o.value));
1016
- for (const o of d.options) {
1017
- if (!this.store.getOptionByID(o.id)) {
1018
- this.callbacks.addOption(o);
1019
- }
1020
- }
1021
- this.callbacks.setSelected(newSelected, true);
1022
- return;
1023
- }
1024
- });
1025
- optgroupActions.appendChild(selectAll);
1026
- }
1027
- if (d.closable !== 'off') {
1028
- const optgroupClosable = document.createElement('div');
1029
- optgroupClosable.classList.add(this.classes.optgroupClosable);
1030
- const optgroupClosableSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
1031
- optgroupClosableSvg.setAttribute('viewBox', '0 0 100 100');
1032
- optgroupClosableSvg.classList.add(this.classes.arrow);
1033
- optgroupClosable.appendChild(optgroupClosableSvg);
1034
- const optgroupClosableArrow = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1035
- optgroupClosableSvg.appendChild(optgroupClosableArrow);
1036
- if (d.options.some((o) => o.selected) || this.content.search.input.value.trim() !== '') {
1037
- optgroupClosable.classList.add(this.classes.open);
1038
- optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen);
1039
- }
1040
- else if (d.closable === 'open') {
1041
- optgroupEl.classList.add(this.classes.open);
1042
- optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen);
1043
- }
1044
- else if (d.closable === 'close') {
1045
- optgroupEl.classList.add(this.classes.close);
1046
- optgroupClosableArrow.setAttribute('d', this.classes.arrowClose);
1047
- }
1048
- optgroupLabel.addEventListener('click', (e) => {
1049
- e.preventDefault();
1050
- e.stopPropagation();
1051
- if (optgroupEl.classList.contains(this.classes.close)) {
1052
- optgroupEl.classList.remove(this.classes.close);
1053
- optgroupEl.classList.add(this.classes.open);
1054
- optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen);
1055
- }
1056
- else {
1057
- optgroupEl.classList.remove(this.classes.open);
1058
- optgroupEl.classList.add(this.classes.close);
1059
- optgroupClosableArrow.setAttribute('d', this.classes.arrowClose);
1060
- }
1061
- });
1062
- optgroupActions.appendChild(optgroupClosable);
1063
- }
1064
- optgroupEl.appendChild(optgroupLabel);
1065
- for (const o of d.options) {
1066
- optgroupEl.appendChild(this.option(o));
1067
- }
1068
- this.content.list.appendChild(optgroupEl);
1069
- }
1070
- if (d instanceof Option) {
1071
- this.content.list.appendChild(this.option(d));
1072
- }
1073
- }
1074
- }
1075
- option(option) {
1076
- if (option.placeholder) {
1077
- const placeholder = document.createElement('div');
1078
- placeholder.classList.add(this.classes.option);
1079
- placeholder.classList.add(this.classes.hide);
1080
- return placeholder;
1081
- }
1082
- const optionEl = document.createElement('div');
1083
- optionEl.dataset.id = option.id;
1084
- optionEl.id = option.id;
1085
- optionEl.classList.add(this.classes.option);
1086
- optionEl.setAttribute('role', 'option');
1087
- if (option.class) {
1088
- option.class.split(' ').forEach((dataClass) => {
1089
- optionEl.classList.add(dataClass);
1090
- });
1091
- }
1092
- if (option.style) {
1093
- optionEl.style.cssText = option.style;
1094
- }
1095
- if (this.settings.searchHighlight && this.content.search.input.value.trim() !== '') {
1096
- optionEl.innerHTML = this.highlightText(option.html !== '' ? option.html : option.text, this.content.search.input.value, this.classes.searchHighlighter);
1097
- }
1098
- else if (option.html !== '') {
1099
- optionEl.innerHTML = option.html;
1100
- }
1101
- else {
1102
- optionEl.textContent = option.text;
1103
- }
1104
- if (this.settings.showOptionTooltips && optionEl.textContent) {
1105
- optionEl.setAttribute('title', optionEl.textContent);
1106
- }
1107
- if (!option.display) {
1108
- optionEl.classList.add(this.classes.hide);
1109
- }
1110
- if (option.disabled) {
1111
- optionEl.classList.add(this.classes.disabled);
1112
- }
1113
- if (option.selected && this.settings.hideSelected) {
1114
- optionEl.classList.add(this.classes.hide);
1115
- }
1116
- if (option.selected) {
1117
- optionEl.classList.add(this.classes.selected);
1118
- optionEl.setAttribute('aria-selected', 'true');
1119
- this.main.main.setAttribute('aria-activedescendant', optionEl.id);
1120
- }
1121
- else {
1122
- optionEl.classList.remove(this.classes.selected);
1123
- optionEl.setAttribute('aria-selected', 'false');
1124
- }
1125
- optionEl.addEventListener('click', (e) => {
1126
- e.preventDefault();
1127
- e.stopPropagation();
1128
- const selectedOptions = this.store.getSelected();
1129
- const element = e.currentTarget;
1130
- const elementID = String(element.dataset.id);
1131
- if (option.disabled || (option.selected && !this.settings.allowDeselect)) {
1132
- return;
1133
- }
1134
- if ((this.settings.isMultiple && this.settings.maxSelected <= selectedOptions.length && !option.selected) ||
1135
- (this.settings.isMultiple && this.settings.minSelected >= selectedOptions.length && option.selected)) {
1136
- return;
1137
- }
1138
- let shouldUpdate = false;
1139
- const before = this.store.getSelectedOptions();
1140
- let after = [];
1141
- if (this.settings.isMultiple) {
1142
- if (option.selected) {
1143
- after = before.filter((o) => o.id !== elementID);
1144
- }
1145
- else {
1146
- after = before.concat(option);
1147
- }
1148
- }
1149
- if (!this.settings.isMultiple) {
1150
- if (option.selected) {
1151
- after = [];
1152
- }
1153
- else {
1154
- after = [option];
1155
- }
1156
- }
1157
- if (!this.callbacks.beforeChange) {
1158
- shouldUpdate = true;
1159
- }
1160
- if (this.callbacks.beforeChange) {
1161
- if (this.callbacks.beforeChange(after, before) === false) {
1162
- shouldUpdate = false;
1163
- }
1164
- else {
1165
- shouldUpdate = true;
1166
- }
1167
- }
1168
- if (shouldUpdate) {
1169
- if (!this.store.getOptionByID(elementID)) {
1170
- this.callbacks.addOption(option);
1171
- }
1172
- this.callbacks.setSelected(after.map((o) => o.value), false);
1173
- if (this.settings.closeOnSelect) {
1174
- this.callbacks.close();
1175
- }
1176
- if (this.callbacks.afterChange) {
1177
- this.callbacks.afterChange(after);
1178
- }
1179
- }
1180
- });
1181
- return optionEl;
1182
- }
1183
- destroy() {
1184
- this.main.main.remove();
1185
- this.content.main.remove();
1186
- }
1187
- highlightText(str, search, className) {
1188
- let completedString = str;
1189
- const regex = new RegExp('(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
1190
- if (!str.match(regex)) {
1191
- return str;
1192
- }
1193
- const matchStartPosition = str.match(regex).index;
1194
- const matchEndPosition = matchStartPosition + str.match(regex)[0].toString().length;
1195
- const originalTextFoundByRegex = str.substring(matchStartPosition, matchEndPosition);
1196
- completedString = completedString.replace(regex, `<mark class="${className}">${originalTextFoundByRegex}</mark>`);
1197
- return completedString;
1198
- }
1199
- moveContentAbove() {
1200
- const mainHeight = this.main.main.offsetHeight;
1201
- const contentHeight = this.content.main.offsetHeight;
1202
- this.main.main.classList.remove(this.classes.openBelow);
1203
- this.main.main.classList.add(this.classes.openAbove);
1204
- this.content.main.classList.remove(this.classes.openBelow);
1205
- this.content.main.classList.add(this.classes.openAbove);
1206
- const containerRect = this.main.main.getBoundingClientRect();
1207
- this.content.main.style.margin = '-' + (mainHeight + contentHeight - 1) + 'px 0px 0px 0px';
1208
- this.content.main.style.top = containerRect.top + containerRect.height + window.scrollY + 'px';
1209
- this.content.main.style.left = containerRect.left + window.scrollX + 'px';
1210
- this.content.main.style.width = containerRect.width + 'px';
1211
- }
1212
- moveContentBelow() {
1213
- this.main.main.classList.remove(this.classes.openAbove);
1214
- this.main.main.classList.add(this.classes.openBelow);
1215
- this.content.main.classList.remove(this.classes.openAbove);
1216
- this.content.main.classList.add(this.classes.openBelow);
1217
- const containerRect = this.main.main.getBoundingClientRect();
1218
- this.content.main.style.margin = '-1px 0px 0px 0px';
1219
- if (this.settings.contentPosition !== 'relative') {
1220
- this.content.main.style.top = containerRect.top + containerRect.height + window.scrollY + 'px';
1221
- this.content.main.style.left = containerRect.left + window.scrollX + 'px';
1222
- this.content.main.style.width = containerRect.width + 'px';
1223
- }
1224
- }
1225
- ensureElementInView(container, element) {
1226
- const cTop = container.scrollTop + container.offsetTop;
1227
- const cBottom = cTop + container.clientHeight;
1228
- const eTop = element.offsetTop;
1229
- const eBottom = eTop + element.clientHeight;
1230
- if (eTop < cTop) {
1231
- container.scrollTop -= cTop - eTop;
1232
- }
1233
- else if (eBottom > cBottom) {
1234
- container.scrollTop += eBottom - cBottom;
1235
- }
1236
- }
1237
- putContent() {
1238
- const mainHeight = this.main.main.offsetHeight;
1239
- const mainRect = this.main.main.getBoundingClientRect();
1240
- const contentHeight = this.content.main.offsetHeight;
1241
- const spaceBelow = window.innerHeight - (mainRect.top + mainHeight);
1242
- if (spaceBelow <= contentHeight) {
1243
- if (mainRect.top > contentHeight) {
1244
- return 'up';
1245
- }
1246
- else {
1247
- return 'down';
1248
- }
1249
- }
1250
- return 'down';
1251
- }
1252
- updateDeselectAll() {
1253
- if (!this.store || !this.settings) {
1254
- return;
1255
- }
1256
- const selected = this.store.getSelectedOptions();
1257
- const hasSelectedItems = selected && selected.length > 0;
1258
- const isMultiple = this.settings.isMultiple;
1259
- const allowDeselect = this.settings.allowDeselect;
1260
- const deselectButton = this.main.deselect.main;
1261
- const hideClass = this.classes.hide;
1262
- if (allowDeselect && !(isMultiple && !hasSelectedItems)) {
1263
- deselectButton.classList.remove(hideClass);
1264
- }
1265
- else {
1266
- deselectButton.classList.add(hideClass);
1267
- }
1268
- }
1269
- }
292
+ class Render {
293
+ constructor(settings, store, callbacks) {
294
+ this.classes = {
295
+ main: 'ss-main',
296
+ placeholder: 'ss-placeholder',
297
+ values: 'ss-values',
298
+ single: 'ss-single',
299
+ max: 'ss-max',
300
+ value: 'ss-value',
301
+ valueText: 'ss-value-text',
302
+ valueDelete: 'ss-value-delete',
303
+ valueOut: 'ss-value-out',
304
+ deselect: 'ss-deselect',
305
+ deselectPath: 'M10,10 L90,90 M10,90 L90,10',
306
+ arrow: 'ss-arrow',
307
+ arrowClose: 'M10,30 L50,70 L90,30',
308
+ arrowOpen: 'M10,70 L50,30 L90,70',
309
+ content: 'ss-content',
310
+ openAbove: 'ss-open-above',
311
+ openBelow: 'ss-open-below',
312
+ search: 'ss-search',
313
+ searchHighlighter: 'ss-search-highlight',
314
+ searching: 'ss-searching',
315
+ addable: 'ss-addable',
316
+ addablePath: 'M50,10 L50,90 M10,50 L90,50',
317
+ list: 'ss-list',
318
+ optgroup: 'ss-optgroup',
319
+ optgroupLabel: 'ss-optgroup-label',
320
+ optgroupLabelText: 'ss-optgroup-label-text',
321
+ optgroupActions: 'ss-optgroup-actions',
322
+ optgroupSelectAll: 'ss-selectall',
323
+ optgroupSelectAllBox: 'M60,10 L10,10 L10,90 L90,90 L90,50',
324
+ optgroupSelectAllCheck: 'M30,45 L50,70 L90,10',
325
+ optgroupClosable: 'ss-closable',
326
+ option: 'ss-option',
327
+ optionDelete: 'M10,10 L90,90 M10,90 L90,10',
328
+ highlighted: 'ss-highlighted',
329
+ open: 'ss-open',
330
+ close: 'ss-close',
331
+ selected: 'ss-selected',
332
+ error: 'ss-error',
333
+ disabled: 'ss-disabled',
334
+ hide: 'ss-hide',
335
+ };
336
+ this.store = store;
337
+ this.settings = settings;
338
+ this.callbacks = callbacks;
339
+ this.main = this.mainDiv();
340
+ this.content = this.contentDiv();
341
+ this.updateClassStyles();
342
+ this.updateAriaAttributes();
343
+ this.settings.contentLocation.appendChild(this.content.main);
344
+ }
345
+ enable() {
346
+ this.main.main.classList.remove(this.classes.disabled);
347
+ this.content.search.input.disabled = false;
348
+ }
349
+ disable() {
350
+ this.main.main.classList.add(this.classes.disabled);
351
+ this.content.search.input.disabled = true;
352
+ }
353
+ open() {
354
+ this.main.arrow.path.setAttribute('d', this.classes.arrowOpen);
355
+ this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
356
+ this.main.main.setAttribute('aria-expanded', 'true');
357
+ this.moveContent();
358
+ const selectedOptions = this.store.getSelectedOptions();
359
+ if (selectedOptions.length) {
360
+ const selectedId = selectedOptions[selectedOptions.length - 1].id;
361
+ const selectedOption = this.content.list.querySelector('[data-id="' + selectedId + '"]');
362
+ if (selectedOption) {
363
+ this.ensureElementInView(this.content.list, selectedOption);
364
+ }
365
+ }
366
+ }
367
+ close() {
368
+ this.main.main.classList.remove(this.classes.openAbove);
369
+ this.main.main.classList.remove(this.classes.openBelow);
370
+ this.main.main.setAttribute('aria-expanded', 'false');
371
+ this.content.main.classList.remove(this.classes.openAbove);
372
+ this.content.main.classList.remove(this.classes.openBelow);
373
+ this.main.arrow.path.setAttribute('d', this.classes.arrowClose);
374
+ }
375
+ updateClassStyles() {
376
+ this.main.main.className = '';
377
+ this.main.main.removeAttribute('style');
378
+ this.content.main.className = '';
379
+ this.content.main.removeAttribute('style');
380
+ this.main.main.classList.add(this.classes.main);
381
+ this.content.main.classList.add(this.classes.content);
382
+ if (this.settings.style !== '') {
383
+ this.main.main.style.cssText = this.settings.style;
384
+ this.content.main.style.cssText = this.settings.style;
385
+ }
386
+ if (this.settings.class.length) {
387
+ for (const c of this.settings.class) {
388
+ if (c.trim() !== '') {
389
+ this.main.main.classList.add(c.trim());
390
+ this.content.main.classList.add(c.trim());
391
+ }
392
+ }
393
+ }
394
+ if (this.settings.contentPosition === 'relative') {
395
+ this.content.main.classList.add('ss-' + this.settings.contentPosition);
396
+ }
397
+ }
398
+ updateAriaAttributes() {
399
+ this.main.main.role = 'combobox';
400
+ this.main.main.setAttribute('aria-haspopup', 'listbox');
401
+ this.main.main.setAttribute('aria-controls', this.content.main.id);
402
+ this.main.main.setAttribute('aria-expanded', 'false');
403
+ this.content.main.setAttribute('role', 'listbox');
404
+ }
405
+ mainDiv() {
406
+ var _a;
407
+ const main = document.createElement('div');
408
+ main.dataset.id = this.settings.id;
409
+ main.setAttribute('aria-label', this.settings.ariaLabel);
410
+ main.tabIndex = 0;
411
+ main.onkeydown = (e) => {
412
+ switch (e.key) {
413
+ case 'ArrowUp':
414
+ case 'ArrowDown':
415
+ this.callbacks.open();
416
+ e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
417
+ return false;
418
+ case 'Tab':
419
+ this.callbacks.close();
420
+ return true;
421
+ case 'Enter':
422
+ case ' ':
423
+ this.callbacks.open();
424
+ const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
425
+ if (highlighted) {
426
+ highlighted.click();
427
+ }
428
+ return false;
429
+ case 'Escape':
430
+ this.callbacks.close();
431
+ return false;
432
+ }
433
+ return false;
434
+ };
435
+ main.onclick = (e) => {
436
+ if (this.settings.disabled) {
437
+ return;
438
+ }
439
+ this.settings.isOpen ? this.callbacks.close() : this.callbacks.open();
440
+ };
441
+ const values = document.createElement('div');
442
+ values.classList.add(this.classes.values);
443
+ main.appendChild(values);
444
+ const deselect = document.createElement('div');
445
+ deselect.classList.add(this.classes.deselect);
446
+ const selectedOptions = (_a = this.store) === null || _a === void 0 ? void 0 : _a.getSelectedOptions();
447
+ if (!this.settings.allowDeselect || (this.settings.isMultiple && selectedOptions && selectedOptions.length <= 0)) {
448
+ deselect.classList.add(this.classes.hide);
449
+ }
450
+ else {
451
+ deselect.classList.remove(this.classes.hide);
452
+ }
453
+ deselect.onclick = (e) => {
454
+ // jadams
455
+ // e.preventDefault();
456
+ e.stopPropagation();
457
+ if (this.settings.disabled) {
458
+ return;
459
+ }
460
+ let shouldDelete = true;
461
+ const before = this.store.getSelectedOptions();
462
+ const after = [];
463
+ if (this.callbacks.beforeChange) {
464
+ shouldDelete = this.callbacks.beforeChange(after, before) === true;
465
+ }
466
+ if (shouldDelete) {
467
+ if (this.settings.isMultiple) {
468
+ this.callbacks.setSelected([], false);
469
+ this.updateDeselectAll();
470
+ }
471
+ else {
472
+ const firstOption = this.store.getFirstOption();
473
+ const value = firstOption ? firstOption.value : '';
474
+ this.callbacks.setSelected(value, false);
475
+ }
476
+ if (this.settings.closeOnSelect) {
477
+ this.callbacks.close();
478
+ }
479
+ if (this.callbacks.afterChange) {
480
+ this.callbacks.afterChange(this.store.getSelectedOptions());
481
+ }
482
+ }
483
+ };
484
+ const deselectSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
485
+ deselectSvg.setAttribute('viewBox', '0 0 100 100');
486
+ const deselectPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
487
+ deselectPath.setAttribute('d', this.classes.deselectPath);
488
+ deselectSvg.appendChild(deselectPath);
489
+ deselect.appendChild(deselectSvg);
490
+ main.appendChild(deselect);
491
+ const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
492
+ arrow.classList.add(this.classes.arrow);
493
+ arrow.setAttribute('viewBox', '0 0 100 100');
494
+ const arrowPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
495
+ arrowPath.setAttribute('d', this.classes.arrowClose);
496
+ if (this.settings.alwaysOpen) {
497
+ arrow.classList.add(this.classes.hide);
498
+ }
499
+ arrow.appendChild(arrowPath);
500
+ main.appendChild(arrow);
501
+ return {
502
+ main: main,
503
+ values: values,
504
+ deselect: {
505
+ main: deselect,
506
+ svg: deselectSvg,
507
+ path: deselectPath,
508
+ },
509
+ arrow: {
510
+ main: arrow,
511
+ path: arrowPath,
512
+ },
513
+ };
514
+ }
515
+ mainFocus(eventType) {
516
+ if (eventType !== 'click') {
517
+ this.main.main.focus({ preventScroll: true });
518
+ }
519
+ }
520
+ placeholder() {
521
+ const placeholderOption = this.store.filter((o) => o.placeholder, false);
522
+ let placeholderText = this.settings.placeholderText;
523
+ if (placeholderOption.length) {
524
+ if (placeholderOption[0].html !== '') {
525
+ placeholderText = placeholderOption[0].html;
526
+ }
527
+ else if (placeholderOption[0].text !== '') {
528
+ placeholderText = placeholderOption[0].text;
529
+ }
530
+ }
531
+ const placeholder = document.createElement('div');
532
+ placeholder.classList.add(this.classes.placeholder);
533
+ placeholder.innerHTML = placeholderText;
534
+ return placeholder;
535
+ }
536
+ renderValues() {
537
+ if (!this.settings.isMultiple) {
538
+ this.renderSingleValue();
539
+ return;
540
+ }
541
+ this.renderMultipleValues();
542
+ this.updateDeselectAll();
543
+ }
544
+ renderSingleValue() {
545
+ const selected = this.store.filter((o) => {
546
+ return o.selected && !o.placeholder;
547
+ }, false);
548
+ const selectedSingle = selected.length > 0 ? selected[0] : null;
549
+ if (!selectedSingle) {
550
+ this.main.values.innerHTML = this.placeholder().outerHTML;
551
+ }
552
+ else {
553
+ const singleValue = document.createElement('div');
554
+ singleValue.classList.add(this.classes.single);
555
+ if (selectedSingle.html) {
556
+ singleValue.innerHTML = selectedSingle.html;
557
+ }
558
+ else {
559
+ singleValue.innerText = selectedSingle.text;
560
+ }
561
+ this.main.values.innerHTML = singleValue.outerHTML;
562
+ }
563
+ if (!this.settings.allowDeselect || !selected.length) {
564
+ this.main.deselect.main.classList.add(this.classes.hide);
565
+ }
566
+ else {
567
+ this.main.deselect.main.classList.remove(this.classes.hide);
568
+ }
569
+ }
570
+ renderMultipleValues() {
571
+ let currentNodes = this.main.values.childNodes;
572
+ let selectedOptions = this.store.filter((opt) => {
573
+ return opt.selected && opt.display;
574
+ }, false);
575
+ if (selectedOptions.length === 0) {
576
+ this.main.values.innerHTML = this.placeholder().outerHTML;
577
+ return;
578
+ }
579
+ else {
580
+ const placeholder = this.main.values.querySelector('.' + this.classes.placeholder);
581
+ if (placeholder) {
582
+ placeholder.remove();
583
+ }
584
+ }
585
+ if (selectedOptions.length > this.settings.maxValuesShown) {
586
+ const singleValue = document.createElement('div');
587
+ singleValue.classList.add(this.classes.max);
588
+ singleValue.textContent = this.settings.maxValuesMessage.replace('{number}', selectedOptions.length.toString());
589
+ this.main.values.innerHTML = singleValue.outerHTML;
590
+ return;
591
+ }
592
+ else {
593
+ const maxValuesMessage = this.main.values.querySelector('.' + this.classes.max);
594
+ if (maxValuesMessage) {
595
+ maxValuesMessage.remove();
596
+ }
597
+ }
598
+ let removeNodes = [];
599
+ for (let i = 0; i < currentNodes.length; i++) {
600
+ const node = currentNodes[i];
601
+ const id = node.getAttribute('data-id');
602
+ if (id) {
603
+ const found = selectedOptions.filter((opt) => {
604
+ return opt.id === id;
605
+ }, false);
606
+ if (!found.length) {
607
+ removeNodes.push(node);
608
+ }
609
+ }
610
+ }
611
+ for (const n of removeNodes) {
612
+ n.classList.add(this.classes.valueOut);
613
+ setTimeout(() => {
614
+ if (this.main.values.hasChildNodes() && this.main.values.contains(n)) {
615
+ this.main.values.removeChild(n);
616
+ }
617
+ }, 100);
618
+ }
619
+ currentNodes = this.main.values.childNodes;
620
+ for (let d = 0; d < selectedOptions.length; d++) {
621
+ let shouldAdd = true;
622
+ for (let i = 0; i < currentNodes.length; i++) {
623
+ if (selectedOptions[d].id === String(currentNodes[i].dataset.id)) {
624
+ shouldAdd = false;
625
+ }
626
+ }
627
+ if (shouldAdd) {
628
+ if (this.settings.keepOrder) {
629
+ this.main.values.appendChild(this.multipleValue(selectedOptions[d]));
630
+ }
631
+ else {
632
+ if (currentNodes.length === 0) {
633
+ this.main.values.appendChild(this.multipleValue(selectedOptions[d]));
634
+ }
635
+ else if (d === 0) {
636
+ this.main.values.insertBefore(this.multipleValue(selectedOptions[d]), currentNodes[d]);
637
+ }
638
+ else {
639
+ currentNodes[d - 1].insertAdjacentElement('afterend', this.multipleValue(selectedOptions[d]));
640
+ }
641
+ }
642
+ }
643
+ }
644
+ }
645
+ multipleValue(option) {
646
+ const value = document.createElement('div');
647
+ value.classList.add(this.classes.value);
648
+ value.dataset.id = option.id;
649
+ const text = document.createElement('div');
650
+ text.classList.add(this.classes.valueText);
651
+ text.innerText = option.text;
652
+ value.appendChild(text);
653
+ if (!option.mandatory) {
654
+ const deleteDiv = document.createElement('div');
655
+ deleteDiv.classList.add(this.classes.valueDelete);
656
+ deleteDiv.onclick = (e) => {
657
+ e.preventDefault();
658
+ e.stopPropagation();
659
+ if (this.settings.disabled) {
660
+ return;
661
+ }
662
+ let shouldDelete = true;
663
+ const before = this.store.getSelectedOptions();
664
+ const after = before.filter((o) => {
665
+ return o.selected && o.id !== option.id;
666
+ }, true);
667
+ if (this.settings.minSelected && after.length < this.settings.minSelected) {
668
+ return;
669
+ }
670
+ if (this.callbacks.beforeChange) {
671
+ shouldDelete = this.callbacks.beforeChange(after, before) === true;
672
+ }
673
+ if (shouldDelete) {
674
+ let selectedValues = [];
675
+ for (const o of after) {
676
+ if (o instanceof Optgroup) {
677
+ for (const c of o.options) {
678
+ selectedValues.push(c.value);
679
+ }
680
+ }
681
+ if (o instanceof Option) {
682
+ selectedValues.push(o.value);
683
+ }
684
+ }
685
+ this.callbacks.setSelected(selectedValues, false);
686
+ if (this.settings.closeOnSelect) {
687
+ this.callbacks.close();
688
+ }
689
+ if (this.callbacks.afterChange) {
690
+ this.callbacks.afterChange(after);
691
+ }
692
+ this.updateDeselectAll();
693
+ }
694
+ };
695
+ const deleteSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
696
+ deleteSvg.setAttribute('viewBox', '0 0 100 100');
697
+ const deletePath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
698
+ deletePath.setAttribute('d', this.classes.optionDelete);
699
+ deleteSvg.appendChild(deletePath);
700
+ deleteDiv.appendChild(deleteSvg);
701
+ value.appendChild(deleteDiv);
702
+ }
703
+ return value;
704
+ }
705
+ contentDiv() {
706
+ const main = document.createElement('div');
707
+ main.dataset.id = this.settings.id;
708
+ const search = this.searchDiv();
709
+ main.appendChild(search.main);
710
+ const list = this.listDiv();
711
+ main.appendChild(list);
712
+ return {
713
+ main: main,
714
+ search: search,
715
+ list: list,
716
+ };
717
+ }
718
+ moveContent() {
719
+ if (this.settings.contentPosition === 'relative') {
720
+ this.moveContentBelow();
721
+ return;
722
+ }
723
+ if (this.settings.openPosition === 'down') {
724
+ this.moveContentBelow();
725
+ return;
726
+ }
727
+ else if (this.settings.openPosition === 'up') {
728
+ this.moveContentAbove();
729
+ return;
730
+ }
731
+ if (this.putContent() === 'up') {
732
+ this.moveContentAbove();
733
+ }
734
+ else {
735
+ this.moveContentBelow();
736
+ }
737
+ }
738
+ searchDiv() {
739
+ const main = document.createElement('div');
740
+ const input = document.createElement('input');
741
+ const addable = document.createElement('div');
742
+ main.classList.add(this.classes.search);
743
+ const searchReturn = {
744
+ main,
745
+ input,
746
+ };
747
+ if (!this.settings.showSearch) {
748
+ main.classList.add(this.classes.hide);
749
+ input.readOnly = true;
750
+ }
751
+ input.type = 'search';
752
+ input.placeholder = this.settings.searchPlaceholder;
753
+ input.tabIndex = -1;
754
+ input.setAttribute('aria-label', this.settings.searchPlaceholder);
755
+ input.setAttribute('autocapitalize', 'off');
756
+ input.setAttribute('autocomplete', 'off');
757
+ input.setAttribute('autocorrect', 'off');
758
+ input.oninput = debounce((e) => {
759
+ this.callbacks.search(e.target.value);
760
+ }, 100);
761
+ input.onkeydown = (e) => {
762
+ switch (e.key) {
763
+ case 'ArrowUp':
764
+ case 'ArrowDown':
765
+ e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
766
+ return false;
767
+ case 'Tab':
768
+ this.callbacks.close();
769
+ return true;
770
+ case 'Escape':
771
+ this.callbacks.close();
772
+ return false;
773
+ case 'Enter':
774
+ case ' ':
775
+ if (this.callbacks.addable && e.ctrlKey) {
776
+ addable.click();
777
+ return false;
778
+ }
779
+ else {
780
+ const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
781
+ if (highlighted) {
782
+ highlighted.click();
783
+ return false;
784
+ }
785
+ }
786
+ return true;
787
+ }
788
+ return true;
789
+ };
790
+ main.appendChild(input);
791
+ if (this.callbacks.addable) {
792
+ addable.classList.add(this.classes.addable);
793
+ const plus = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
794
+ plus.setAttribute('viewBox', '0 0 100 100');
795
+ const plusPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
796
+ plusPath.setAttribute('d', this.classes.addablePath);
797
+ plus.appendChild(plusPath);
798
+ addable.appendChild(plus);
799
+ addable.onclick = (e) => {
800
+ e.preventDefault();
801
+ e.stopPropagation();
802
+ if (!this.callbacks.addable) {
803
+ return;
804
+ }
805
+ const inputValue = this.content.search.input.value.trim();
806
+ if (inputValue === '') {
807
+ this.content.search.input.focus();
808
+ return;
809
+ }
810
+ const runFinish = (oo) => {
811
+ let newOption = new Option(oo);
812
+ this.callbacks.addOption(newOption);
813
+ if (this.settings.isMultiple) {
814
+ let values = this.store.getSelected();
815
+ values.push(newOption.value);
816
+ this.callbacks.setSelected(values, true);
817
+ }
818
+ else {
819
+ this.callbacks.setSelected([newOption.value], true);
820
+ }
821
+ this.callbacks.search('');
822
+ if (this.settings.closeOnSelect) {
823
+ setTimeout(() => {
824
+ this.callbacks.close();
825
+ }, 100);
826
+ }
827
+ };
828
+ const addableValue = this.callbacks.addable(inputValue);
829
+ if (addableValue === false || addableValue === undefined || addableValue === null) {
830
+ return;
831
+ }
832
+ if (addableValue instanceof Promise) {
833
+ addableValue.then((value) => {
834
+ if (typeof value === 'string') {
835
+ runFinish({
836
+ text: value,
837
+ value: value,
838
+ });
839
+ }
840
+ else {
841
+ runFinish(value);
842
+ }
843
+ });
844
+ }
845
+ else if (typeof addableValue === 'string') {
846
+ runFinish({
847
+ text: addableValue,
848
+ value: addableValue,
849
+ });
850
+ }
851
+ else {
852
+ runFinish(addableValue);
853
+ }
854
+ return;
855
+ };
856
+ main.appendChild(addable);
857
+ searchReturn.addable = {
858
+ main: addable,
859
+ svg: plus,
860
+ path: plusPath,
861
+ };
862
+ }
863
+ return searchReturn;
864
+ }
865
+ searchFocus() {
866
+ this.content.search.input.focus();
867
+ }
868
+ getOptions(notPlaceholder = false, notDisabled = false, notHidden = false) {
869
+ let query = '.' + this.classes.option;
870
+ if (notPlaceholder) {
871
+ query += ':not(.' + this.classes.placeholder + ')';
872
+ }
873
+ if (notDisabled) {
874
+ query += ':not(.' + this.classes.disabled + ')';
875
+ }
876
+ if (notHidden) {
877
+ query += ':not(.' + this.classes.hide + ')';
878
+ }
879
+ return Array.from(this.content.list.querySelectorAll(query));
880
+ }
881
+ highlight(dir) {
882
+ const options = this.getOptions(true, true, true);
883
+ if (options.length === 0) {
884
+ return;
885
+ }
886
+ if (options.length === 1) {
887
+ if (!options[0].classList.contains(this.classes.highlighted)) {
888
+ options[0].classList.add(this.classes.highlighted);
889
+ return;
890
+ }
891
+ }
892
+ let highlighted = false;
893
+ for (const o of options) {
894
+ if (o.classList.contains(this.classes.highlighted)) {
895
+ highlighted = true;
896
+ }
897
+ }
898
+ if (!highlighted) {
899
+ for (const o of options) {
900
+ if (o.classList.contains(this.classes.selected)) {
901
+ o.classList.add(this.classes.highlighted);
902
+ break;
903
+ }
904
+ }
905
+ }
906
+ for (let i = 0; i < options.length; i++) {
907
+ if (options[i].classList.contains(this.classes.highlighted)) {
908
+ const prevOption = options[i];
909
+ prevOption.classList.remove(this.classes.highlighted);
910
+ const prevParent = prevOption.parentElement;
911
+ if (prevParent && prevParent.classList.contains(this.classes.open)) {
912
+ const optgroupLabel = prevParent.querySelector('.' + this.classes.optgroupLabel);
913
+ if (optgroupLabel) {
914
+ optgroupLabel.click();
915
+ }
916
+ }
917
+ let selectOption = options[dir === 'down' ? (i + 1 < options.length ? i + 1 : 0) : i - 1 >= 0 ? i - 1 : options.length - 1];
918
+ selectOption.classList.add(this.classes.highlighted);
919
+ this.ensureElementInView(this.content.list, selectOption);
920
+ const selectParent = selectOption.parentElement;
921
+ if (selectParent && selectParent.classList.contains(this.classes.close)) {
922
+ const optgroupLabel = selectParent.querySelector('.' + this.classes.optgroupLabel);
923
+ if (optgroupLabel) {
924
+ optgroupLabel.click();
925
+ }
926
+ }
927
+ return;
928
+ }
929
+ }
930
+ options[dir === 'down' ? 0 : options.length - 1].classList.add(this.classes.highlighted);
931
+ this.ensureElementInView(this.content.list, options[dir === 'down' ? 0 : options.length - 1]);
932
+ }
933
+ listDiv() {
934
+ const options = document.createElement('div');
935
+ options.classList.add(this.classes.list);
936
+ return options;
937
+ }
938
+ renderError(error) {
939
+ this.content.list.innerHTML = '';
940
+ const errorDiv = document.createElement('div');
941
+ errorDiv.classList.add(this.classes.error);
942
+ errorDiv.textContent = error;
943
+ this.content.list.appendChild(errorDiv);
944
+ }
945
+ renderSearching() {
946
+ this.content.list.innerHTML = '';
947
+ const searchingDiv = document.createElement('div');
948
+ searchingDiv.classList.add(this.classes.searching);
949
+ searchingDiv.textContent = this.settings.searchingText;
950
+ this.content.list.appendChild(searchingDiv);
951
+ }
952
+ renderOptions(data) {
953
+ this.content.list.innerHTML = '';
954
+ if (data.length === 0) {
955
+ const noResults = document.createElement('div');
956
+ noResults.classList.add(this.classes.search);
957
+ noResults.innerHTML = this.settings.searchText;
958
+ this.content.list.appendChild(noResults);
959
+ return;
960
+ }
961
+ for (const d of data) {
962
+ if (d instanceof Optgroup) {
963
+ const optgroupEl = document.createElement('div');
964
+ optgroupEl.classList.add(this.classes.optgroup);
965
+ const optgroupLabel = document.createElement('div');
966
+ optgroupLabel.classList.add(this.classes.optgroupLabel);
967
+ optgroupEl.appendChild(optgroupLabel);
968
+ const optgroupLabelText = document.createElement('div');
969
+ optgroupLabelText.classList.add(this.classes.optgroupLabelText);
970
+ optgroupLabelText.textContent = d.label;
971
+ optgroupLabel.appendChild(optgroupLabelText);
972
+ const optgroupActions = document.createElement('div');
973
+ optgroupActions.classList.add(this.classes.optgroupActions);
974
+ optgroupLabel.appendChild(optgroupActions);
975
+ if (this.settings.isMultiple && d.selectAll) {
976
+ const selectAll = document.createElement('div');
977
+ selectAll.classList.add(this.classes.optgroupSelectAll);
978
+ let allSelected = true;
979
+ for (const o of d.options) {
980
+ if (!o.selected) {
981
+ allSelected = false;
982
+ break;
983
+ }
984
+ }
985
+ if (allSelected) {
986
+ selectAll.classList.add(this.classes.selected);
987
+ }
988
+ const selectAllText = document.createElement('span');
989
+ selectAllText.textContent = d.selectAllText;
990
+ selectAll.appendChild(selectAllText);
991
+ const selectAllSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
992
+ selectAllSvg.setAttribute('viewBox', '0 0 100 100');
993
+ selectAll.appendChild(selectAllSvg);
994
+ const selectAllBox = document.createElementNS('http://www.w3.org/2000/svg', 'path');
995
+ selectAllBox.setAttribute('d', this.classes.optgroupSelectAllBox);
996
+ selectAllSvg.appendChild(selectAllBox);
997
+ const selectAllCheck = document.createElementNS('http://www.w3.org/2000/svg', 'path');
998
+ selectAllCheck.setAttribute('d', this.classes.optgroupSelectAllCheck);
999
+ selectAllSvg.appendChild(selectAllCheck);
1000
+ selectAll.addEventListener('click', (e) => {
1001
+ e.preventDefault();
1002
+ e.stopPropagation();
1003
+ const currentSelected = this.store.getSelected();
1004
+ if (allSelected) {
1005
+ const newSelected = currentSelected.filter((s) => {
1006
+ for (const o of d.options) {
1007
+ if (s === o.value) {
1008
+ return false;
1009
+ }
1010
+ }
1011
+ return true;
1012
+ });
1013
+ this.callbacks.setSelected(newSelected, true);
1014
+ return;
1015
+ }
1016
+ else {
1017
+ const newSelected = currentSelected.concat(d.options.map((o) => o.value));
1018
+ for (const o of d.options) {
1019
+ if (!this.store.getOptionByID(o.id)) {
1020
+ this.callbacks.addOption(o);
1021
+ }
1022
+ }
1023
+ this.callbacks.setSelected(newSelected, true);
1024
+ return;
1025
+ }
1026
+ });
1027
+ optgroupActions.appendChild(selectAll);
1028
+ }
1029
+ if (d.closable !== 'off') {
1030
+ const optgroupClosable = document.createElement('div');
1031
+ optgroupClosable.classList.add(this.classes.optgroupClosable);
1032
+ const optgroupClosableSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
1033
+ optgroupClosableSvg.setAttribute('viewBox', '0 0 100 100');
1034
+ optgroupClosableSvg.classList.add(this.classes.arrow);
1035
+ optgroupClosable.appendChild(optgroupClosableSvg);
1036
+ const optgroupClosableArrow = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1037
+ optgroupClosableSvg.appendChild(optgroupClosableArrow);
1038
+ if (d.options.some((o) => o.selected) || this.content.search.input.value.trim() !== '') {
1039
+ optgroupClosable.classList.add(this.classes.open);
1040
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen);
1041
+ }
1042
+ else if (d.closable === 'open') {
1043
+ optgroupEl.classList.add(this.classes.open);
1044
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen);
1045
+ }
1046
+ else if (d.closable === 'close') {
1047
+ optgroupEl.classList.add(this.classes.close);
1048
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowClose);
1049
+ }
1050
+ optgroupLabel.addEventListener('click', (e) => {
1051
+ e.preventDefault();
1052
+ e.stopPropagation();
1053
+ if (optgroupEl.classList.contains(this.classes.close)) {
1054
+ optgroupEl.classList.remove(this.classes.close);
1055
+ optgroupEl.classList.add(this.classes.open);
1056
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen);
1057
+ }
1058
+ else {
1059
+ optgroupEl.classList.remove(this.classes.open);
1060
+ optgroupEl.classList.add(this.classes.close);
1061
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowClose);
1062
+ }
1063
+ });
1064
+ optgroupActions.appendChild(optgroupClosable);
1065
+ }
1066
+ optgroupEl.appendChild(optgroupLabel);
1067
+ for (const o of d.options) {
1068
+ optgroupEl.appendChild(this.option(o));
1069
+ }
1070
+ this.content.list.appendChild(optgroupEl);
1071
+ }
1072
+ if (d instanceof Option) {
1073
+ this.content.list.appendChild(this.option(d));
1074
+ }
1075
+ }
1076
+ }
1077
+ option(option) {
1078
+ if (option.placeholder) {
1079
+ const placeholder = document.createElement('div');
1080
+ placeholder.classList.add(this.classes.option);
1081
+ placeholder.classList.add(this.classes.hide);
1082
+ return placeholder;
1083
+ }
1084
+ const optionEl = document.createElement('div');
1085
+ optionEl.dataset.id = option.id;
1086
+ optionEl.id = option.id;
1087
+ optionEl.classList.add(this.classes.option);
1088
+ optionEl.setAttribute('role', 'option');
1089
+ if (option.class) {
1090
+ option.class.split(' ').forEach((dataClass) => {
1091
+ optionEl.classList.add(dataClass);
1092
+ });
1093
+ }
1094
+ if (option.style) {
1095
+ optionEl.style.cssText = option.style;
1096
+ }
1097
+ if (this.settings.searchHighlight && this.content.search.input.value.trim() !== '') {
1098
+ optionEl.innerHTML = this.highlightText(option.html !== '' ? option.html : option.text, this.content.search.input.value, this.classes.searchHighlighter);
1099
+ }
1100
+ else if (option.html !== '') {
1101
+ optionEl.innerHTML = option.html;
1102
+ }
1103
+ else {
1104
+ optionEl.textContent = option.text;
1105
+ }
1106
+ if (this.settings.showOptionTooltips && optionEl.textContent) {
1107
+ optionEl.setAttribute('title', optionEl.textContent);
1108
+ }
1109
+ if (!option.display) {
1110
+ optionEl.classList.add(this.classes.hide);
1111
+ }
1112
+ if (option.disabled) {
1113
+ optionEl.classList.add(this.classes.disabled);
1114
+ }
1115
+ if (option.selected && this.settings.hideSelected) {
1116
+ optionEl.classList.add(this.classes.hide);
1117
+ }
1118
+ if (option.selected) {
1119
+ optionEl.classList.add(this.classes.selected);
1120
+ optionEl.setAttribute('aria-selected', 'true');
1121
+ this.main.main.setAttribute('aria-activedescendant', optionEl.id);
1122
+ }
1123
+ else {
1124
+ optionEl.classList.remove(this.classes.selected);
1125
+ optionEl.setAttribute('aria-selected', 'false');
1126
+ }
1127
+ optionEl.addEventListener('click', (e) => {
1128
+ e.preventDefault();
1129
+ e.stopPropagation();
1130
+ const selectedOptions = this.store.getSelected();
1131
+ const element = e.currentTarget;
1132
+ const elementID = String(element.dataset.id);
1133
+ if (option.disabled || (option.selected && !this.settings.allowDeselect)) {
1134
+ return;
1135
+ }
1136
+ if ((this.settings.isMultiple && this.settings.maxSelected <= selectedOptions.length && !option.selected) ||
1137
+ (this.settings.isMultiple && this.settings.minSelected >= selectedOptions.length && option.selected)) {
1138
+ return;
1139
+ }
1140
+ let shouldUpdate = false;
1141
+ const before = this.store.getSelectedOptions();
1142
+ let after = [];
1143
+ if (this.settings.isMultiple) {
1144
+ if (option.selected) {
1145
+ after = before.filter((o) => o.id !== elementID);
1146
+ }
1147
+ else {
1148
+ after = before.concat(option);
1149
+ }
1150
+ }
1151
+ if (!this.settings.isMultiple) {
1152
+ if (option.selected) {
1153
+ after = [];
1154
+ }
1155
+ else {
1156
+ after = [option];
1157
+ }
1158
+ }
1159
+ if (!this.callbacks.beforeChange) {
1160
+ shouldUpdate = true;
1161
+ }
1162
+ if (this.callbacks.beforeChange) {
1163
+ if (this.callbacks.beforeChange(after, before) === false) {
1164
+ shouldUpdate = false;
1165
+ }
1166
+ else {
1167
+ shouldUpdate = true;
1168
+ }
1169
+ }
1170
+ if (shouldUpdate) {
1171
+ if (!this.store.getOptionByID(elementID)) {
1172
+ this.callbacks.addOption(option);
1173
+ }
1174
+ this.callbacks.setSelected(after.map((o) => o.value), false);
1175
+ if (this.settings.closeOnSelect) {
1176
+ this.callbacks.close();
1177
+ }
1178
+ if (this.callbacks.afterChange) {
1179
+ this.callbacks.afterChange(after);
1180
+ }
1181
+ }
1182
+ });
1183
+ return optionEl;
1184
+ }
1185
+ destroy() {
1186
+ this.main.main.remove();
1187
+ this.content.main.remove();
1188
+ }
1189
+ highlightText(str, search, className) {
1190
+ let completedString = str;
1191
+ const regex = new RegExp('(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
1192
+ if (!str.match(regex)) {
1193
+ return str;
1194
+ }
1195
+ const matchStartPosition = str.match(regex).index;
1196
+ const matchEndPosition = matchStartPosition + str.match(regex)[0].toString().length;
1197
+ const originalTextFoundByRegex = str.substring(matchStartPosition, matchEndPosition);
1198
+ completedString = completedString.replace(regex, `<mark class="${className}">${originalTextFoundByRegex}</mark>`);
1199
+ return completedString;
1200
+ }
1201
+ moveContentAbove() {
1202
+ const mainHeight = this.main.main.offsetHeight;
1203
+ const contentHeight = this.content.main.offsetHeight;
1204
+ this.main.main.classList.remove(this.classes.openBelow);
1205
+ this.main.main.classList.add(this.classes.openAbove);
1206
+ this.content.main.classList.remove(this.classes.openBelow);
1207
+ this.content.main.classList.add(this.classes.openAbove);
1208
+ const containerRect = this.main.main.getBoundingClientRect();
1209
+ this.content.main.style.margin = '-' + (mainHeight + contentHeight - 1) + 'px 0px 0px 0px';
1210
+ this.content.main.style.top = containerRect.top + containerRect.height + window.scrollY + 'px';
1211
+ this.content.main.style.left = containerRect.left + window.scrollX + 'px';
1212
+ this.content.main.style.width = containerRect.width + 'px';
1213
+ }
1214
+ moveContentBelow() {
1215
+ this.main.main.classList.remove(this.classes.openAbove);
1216
+ this.main.main.classList.add(this.classes.openBelow);
1217
+ this.content.main.classList.remove(this.classes.openAbove);
1218
+ this.content.main.classList.add(this.classes.openBelow);
1219
+ const containerRect = this.main.main.getBoundingClientRect();
1220
+ this.content.main.style.margin = '-1px 0px 0px 0px';
1221
+ if (this.settings.contentPosition !== 'relative') {
1222
+ this.content.main.style.top = containerRect.top + containerRect.height + window.scrollY + 'px';
1223
+ this.content.main.style.left = containerRect.left + window.scrollX + 'px';
1224
+ this.content.main.style.width = containerRect.width + 'px';
1225
+ }
1226
+ }
1227
+ ensureElementInView(container, element) {
1228
+ const cTop = container.scrollTop + container.offsetTop;
1229
+ const cBottom = cTop + container.clientHeight;
1230
+ const eTop = element.offsetTop;
1231
+ const eBottom = eTop + element.clientHeight;
1232
+ if (eTop < cTop) {
1233
+ container.scrollTop -= cTop - eTop;
1234
+ }
1235
+ else if (eBottom > cBottom) {
1236
+ container.scrollTop += eBottom - cBottom;
1237
+ }
1238
+ }
1239
+ putContent() {
1240
+ const mainHeight = this.main.main.offsetHeight;
1241
+ const mainRect = this.main.main.getBoundingClientRect();
1242
+ const contentHeight = this.content.main.offsetHeight;
1243
+ const spaceBelow = window.innerHeight - (mainRect.top + mainHeight);
1244
+ if (spaceBelow <= contentHeight) {
1245
+ if (mainRect.top > contentHeight) {
1246
+ return 'up';
1247
+ }
1248
+ else {
1249
+ return 'down';
1250
+ }
1251
+ }
1252
+ return 'down';
1253
+ }
1254
+ updateDeselectAll() {
1255
+ if (!this.store || !this.settings) {
1256
+ return;
1257
+ }
1258
+ const selected = this.store.getSelectedOptions();
1259
+ const hasSelectedItems = selected && selected.length > 0;
1260
+ const isMultiple = this.settings.isMultiple;
1261
+ const allowDeselect = this.settings.allowDeselect;
1262
+ const deselectButton = this.main.deselect.main;
1263
+ const hideClass = this.classes.hide;
1264
+ if (allowDeselect && !(isMultiple && !hasSelectedItems)) {
1265
+ deselectButton.classList.remove(hideClass);
1266
+ }
1267
+ else {
1268
+ deselectButton.classList.add(hideClass);
1269
+ }
1270
+ }
1271
+ }
1270
1272
 
1271
- class Select {
1272
- constructor(select) {
1273
- this.listen = false;
1274
- this.observer = null;
1275
- this.select = select;
1276
- this.select.addEventListener('change', this.valueChange.bind(this), {
1277
- passive: true,
1278
- });
1279
- this.observer = new MutationObserver(this.observeCall.bind(this));
1280
- this.changeListen(true);
1281
- }
1282
- enable() {
1283
- this.select.disabled = false;
1284
- }
1285
- disable() {
1286
- this.select.disabled = true;
1287
- }
1288
- hideUI() {
1289
- this.select.tabIndex = -1;
1290
- this.select.style.display = 'none';
1291
- this.select.setAttribute('aria-hidden', 'true');
1292
- }
1293
- showUI() {
1294
- this.select.removeAttribute('tabindex');
1295
- this.select.style.display = '';
1296
- this.select.removeAttribute('aria-hidden');
1297
- }
1298
- changeListen(listen) {
1299
- this.listen = listen;
1300
- if (listen) {
1301
- if (this.observer) {
1302
- this.observer.observe(this.select, {
1303
- subtree: true,
1304
- childList: true,
1305
- attributes: true,
1306
- });
1307
- }
1308
- }
1309
- if (!listen) {
1310
- if (this.observer) {
1311
- this.observer.disconnect();
1312
- }
1313
- }
1314
- }
1315
- valueChange(ev) {
1316
- if (this.listen && this.onValueChange) {
1317
- this.onValueChange(this.getSelectedValues());
1318
- }
1319
- return true;
1320
- }
1321
- observeCall(mutations) {
1322
- if (!this.listen) {
1323
- return;
1324
- }
1325
- let classChanged = false;
1326
- let disabledChanged = false;
1327
- let optgroupOptionChanged = false;
1328
- for (const m of mutations) {
1329
- if (m.target === this.select) {
1330
- if (m.attributeName === 'disabled') {
1331
- disabledChanged = true;
1332
- }
1333
- if (m.attributeName === 'class') {
1334
- classChanged = true;
1335
- }
1336
- }
1337
- if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {
1338
- optgroupOptionChanged = true;
1339
- }
1340
- }
1341
- if (classChanged && this.onClassChange) {
1342
- this.onClassChange(this.select.className.split(' '));
1343
- }
1344
- if (disabledChanged && this.onDisabledChange) {
1345
- this.changeListen(false);
1346
- this.onDisabledChange(this.select.disabled);
1347
- this.changeListen(true);
1348
- }
1349
- if (optgroupOptionChanged && this.onOptionsChange) {
1350
- this.changeListen(false);
1351
- this.onOptionsChange(this.getData());
1352
- this.changeListen(true);
1353
- }
1354
- }
1355
- getData() {
1356
- let data = [];
1357
- const nodes = this.select.childNodes;
1358
- for (const n of nodes) {
1359
- if (n.nodeName === 'OPTGROUP') {
1360
- data.push(this.getDataFromOptgroup(n));
1361
- }
1362
- if (n.nodeName === 'OPTION') {
1363
- data.push(this.getDataFromOption(n));
1364
- }
1365
- }
1366
- return data;
1367
- }
1368
- getDataFromOptgroup(optgroup) {
1369
- let data = {
1370
- id: optgroup.id,
1371
- label: optgroup.label,
1372
- selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
1373
- selectAllText: optgroup.dataset ? optgroup.dataset.selectalltext : 'Select all',
1374
- closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
1375
- options: [],
1376
- };
1377
- const options = optgroup.childNodes;
1378
- for (const o of options) {
1379
- if (o.nodeName === 'OPTION') {
1380
- data.options.push(this.getDataFromOption(o));
1381
- }
1382
- }
1383
- return data;
1384
- }
1385
- getDataFromOption(option) {
1386
- return {
1387
- id: option.id,
1388
- value: option.value,
1389
- text: option.text,
1390
- html: option.dataset && option.dataset.html ? option.dataset.html : '',
1391
- selected: option.selected,
1392
- display: option.style.display === 'none' ? false : true,
1393
- disabled: option.disabled,
1394
- mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
1395
- placeholder: option.dataset.placeholder === 'true',
1396
- class: option.className,
1397
- style: option.style.cssText,
1398
- data: option.dataset,
1399
- };
1400
- }
1401
- getSelectedValues() {
1402
- let values = [];
1403
- const options = this.select.childNodes;
1404
- for (const o of options) {
1405
- if (o.nodeName === 'OPTGROUP') {
1406
- const optgroupOptions = o.childNodes;
1407
- for (const oo of optgroupOptions) {
1408
- if (oo.nodeName === 'OPTION') {
1409
- const option = oo;
1410
- if (option.selected) {
1411
- values.push(option.value);
1412
- }
1413
- }
1414
- }
1415
- }
1416
- if (o.nodeName === 'OPTION') {
1417
- const option = o;
1418
- if (option.selected) {
1419
- values.push(option.value);
1420
- }
1421
- }
1422
- }
1423
- return values;
1424
- }
1425
- setSelected(value) {
1426
- this.changeListen(false);
1427
- const options = this.select.childNodes;
1428
- for (const o of options) {
1429
- if (o.nodeName === 'OPTGROUP') {
1430
- const optgroup = o;
1431
- const optgroupOptions = optgroup.childNodes;
1432
- for (const oo of optgroupOptions) {
1433
- if (oo.nodeName === 'OPTION') {
1434
- const option = oo;
1435
- option.selected = value.includes(option.value);
1436
- }
1437
- }
1438
- }
1439
- if (o.nodeName === 'OPTION') {
1440
- const option = o;
1441
- option.selected = value.includes(option.value);
1442
- }
1443
- }
1444
- this.changeListen(true);
1445
- }
1446
- updateSelect(id, style, classes) {
1447
- this.changeListen(false);
1448
- if (id) {
1449
- this.select.dataset.id = id;
1450
- }
1451
- if (style) {
1452
- this.select.style.cssText = style;
1453
- }
1454
- if (classes) {
1455
- this.select.className = '';
1456
- classes.forEach((c) => {
1457
- if (c.trim() !== '') {
1458
- this.select.classList.add(c.trim());
1459
- }
1460
- });
1461
- }
1462
- this.changeListen(true);
1463
- }
1464
- updateOptions(data) {
1465
- this.changeListen(false);
1466
- this.select.innerHTML = '';
1467
- for (const d of data) {
1468
- if (d instanceof Optgroup) {
1469
- this.select.appendChild(this.createOptgroup(d));
1470
- }
1471
- if (d instanceof Option) {
1472
- this.select.appendChild(this.createOption(d));
1473
- }
1474
- }
1475
- this.select.dispatchEvent(new Event('change'));
1476
- this.changeListen(true);
1477
- }
1478
- createOptgroup(optgroup) {
1479
- const optgroupEl = document.createElement('optgroup');
1480
- optgroupEl.id = optgroup.id;
1481
- optgroupEl.label = optgroup.label;
1482
- if (optgroup.selectAll) {
1483
- optgroupEl.dataset.selectAll = 'true';
1484
- }
1485
- if (optgroup.closable !== 'off') {
1486
- optgroupEl.dataset.closable = optgroup.closable;
1487
- }
1488
- if (optgroup.options) {
1489
- for (const o of optgroup.options) {
1490
- optgroupEl.appendChild(this.createOption(o));
1491
- }
1492
- }
1493
- return optgroupEl;
1494
- }
1495
- createOption(info) {
1496
- const optionEl = document.createElement('option');
1497
- optionEl.id = info.id;
1498
- optionEl.value = info.value;
1499
- optionEl.innerHTML = info.text;
1500
- if (info.html !== '') {
1501
- optionEl.setAttribute('data-html', info.html);
1502
- }
1503
- if (info.selected) {
1504
- optionEl.selected = info.selected;
1505
- }
1506
- if (info.disabled) {
1507
- optionEl.disabled = true;
1508
- }
1509
- if (info.display === false) {
1510
- optionEl.style.display = 'none';
1511
- }
1512
- if (info.placeholder) {
1513
- optionEl.setAttribute('data-placeholder', 'true');
1514
- }
1515
- if (info.mandatory) {
1516
- optionEl.setAttribute('data-mandatory', 'true');
1517
- }
1518
- if (info.class) {
1519
- info.class.split(' ').forEach((optionClass) => {
1520
- optionEl.classList.add(optionClass);
1521
- });
1522
- }
1523
- if (info.data && typeof info.data === 'object') {
1524
- Object.keys(info.data).forEach((key) => {
1525
- optionEl.setAttribute('data-' + kebabCase(key), info.data[key]);
1526
- });
1527
- }
1528
- return optionEl;
1529
- }
1530
- destroy() {
1531
- this.changeListen(false);
1532
- this.select.removeEventListener('change', this.valueChange.bind(this));
1533
- if (this.observer) {
1534
- this.observer.disconnect();
1535
- this.observer = null;
1536
- }
1537
- delete this.select.dataset.id;
1538
- this.showUI();
1539
- }
1540
- }
1273
+ class Select {
1274
+ constructor(select) {
1275
+ this.listen = false;
1276
+ this.observer = null;
1277
+ this.select = select;
1278
+ this.valueChange = this.valueChange.bind(this);
1279
+ this.select.addEventListener('change', this.valueChange, {
1280
+ passive: true,
1281
+ });
1282
+ this.observer = new MutationObserver(this.observeCall.bind(this));
1283
+ this.changeListen(true);
1284
+ }
1285
+ enable() {
1286
+ this.select.disabled = false;
1287
+ }
1288
+ disable() {
1289
+ this.select.disabled = true;
1290
+ }
1291
+ hideUI() {
1292
+ this.select.tabIndex = -1;
1293
+ this.select.style.display = 'none';
1294
+ this.select.setAttribute('aria-hidden', 'true');
1295
+ }
1296
+ showUI() {
1297
+ this.select.removeAttribute('tabindex');
1298
+ this.select.style.display = '';
1299
+ this.select.removeAttribute('aria-hidden');
1300
+ }
1301
+ changeListen(listen) {
1302
+ this.listen = listen;
1303
+ if (listen) {
1304
+ if (this.observer) {
1305
+ this.observer.observe(this.select, {
1306
+ subtree: true,
1307
+ childList: true,
1308
+ attributes: true,
1309
+ });
1310
+ }
1311
+ }
1312
+ if (!listen) {
1313
+ if (this.observer) {
1314
+ this.observer.disconnect();
1315
+ }
1316
+ }
1317
+ }
1318
+ valueChange(ev) {
1319
+ if (this.listen && this.onValueChange) {
1320
+ this.onValueChange(this.getSelectedValues());
1321
+ }
1322
+ return true;
1323
+ }
1324
+ observeCall(mutations) {
1325
+ if (!this.listen) {
1326
+ return;
1327
+ }
1328
+ let classChanged = false;
1329
+ let disabledChanged = false;
1330
+ let optgroupOptionChanged = false;
1331
+ for (const m of mutations) {
1332
+ if (m.target === this.select) {
1333
+ if (m.attributeName === 'disabled') {
1334
+ disabledChanged = true;
1335
+ }
1336
+ if (m.attributeName === 'class') {
1337
+ classChanged = true;
1338
+ }
1339
+ }
1340
+ if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {
1341
+ optgroupOptionChanged = true;
1342
+ }
1343
+ }
1344
+ if (classChanged && this.onClassChange) {
1345
+ this.onClassChange(this.select.className.split(' '));
1346
+ }
1347
+ if (disabledChanged && this.onDisabledChange) {
1348
+ this.changeListen(false);
1349
+ this.onDisabledChange(this.select.disabled);
1350
+ this.changeListen(true);
1351
+ }
1352
+ if (optgroupOptionChanged && this.onOptionsChange) {
1353
+ this.changeListen(false);
1354
+ this.onOptionsChange(this.getData());
1355
+ this.changeListen(true);
1356
+ }
1357
+ }
1358
+ getData() {
1359
+ let data = [];
1360
+ const nodes = this.select.childNodes;
1361
+ for (const n of nodes) {
1362
+ if (n.nodeName === 'OPTGROUP') {
1363
+ data.push(this.getDataFromOptgroup(n));
1364
+ }
1365
+ if (n.nodeName === 'OPTION') {
1366
+ data.push(this.getDataFromOption(n));
1367
+ }
1368
+ }
1369
+ return data;
1370
+ }
1371
+ getDataFromOptgroup(optgroup) {
1372
+ let data = {
1373
+ id: optgroup.id,
1374
+ label: optgroup.label,
1375
+ selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
1376
+ selectAllText: optgroup.dataset ? optgroup.dataset.selectalltext : 'Select all',
1377
+ closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
1378
+ options: [],
1379
+ };
1380
+ const options = optgroup.childNodes;
1381
+ for (const o of options) {
1382
+ if (o.nodeName === 'OPTION') {
1383
+ data.options.push(this.getDataFromOption(o));
1384
+ }
1385
+ }
1386
+ return data;
1387
+ }
1388
+ getDataFromOption(option) {
1389
+ return {
1390
+ id: option.id,
1391
+ value: option.value,
1392
+ text: option.text,
1393
+ html: option.dataset && option.dataset.html ? option.dataset.html : '',
1394
+ selected: option.selected,
1395
+ display: option.style.display === 'none' ? false : true,
1396
+ disabled: option.disabled,
1397
+ mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
1398
+ placeholder: option.dataset.placeholder === 'true',
1399
+ class: option.className,
1400
+ style: option.style.cssText,
1401
+ data: option.dataset,
1402
+ };
1403
+ }
1404
+ getSelectedValues() {
1405
+ let values = [];
1406
+ const options = this.select.childNodes;
1407
+ for (const o of options) {
1408
+ if (o.nodeName === 'OPTGROUP') {
1409
+ const optgroupOptions = o.childNodes;
1410
+ for (const oo of optgroupOptions) {
1411
+ if (oo.nodeName === 'OPTION') {
1412
+ const option = oo;
1413
+ if (option.selected) {
1414
+ values.push(option.value);
1415
+ }
1416
+ }
1417
+ }
1418
+ }
1419
+ if (o.nodeName === 'OPTION') {
1420
+ const option = o;
1421
+ if (option.selected) {
1422
+ values.push(option.value);
1423
+ }
1424
+ }
1425
+ }
1426
+ return values;
1427
+ }
1428
+ setSelected(value) {
1429
+ this.changeListen(false);
1430
+ const options = this.select.childNodes;
1431
+ for (const o of options) {
1432
+ if (o.nodeName === 'OPTGROUP') {
1433
+ const optgroup = o;
1434
+ const optgroupOptions = optgroup.childNodes;
1435
+ for (const oo of optgroupOptions) {
1436
+ if (oo.nodeName === 'OPTION') {
1437
+ const option = oo;
1438
+ option.selected = value.includes(option.value);
1439
+ }
1440
+ }
1441
+ }
1442
+ if (o.nodeName === 'OPTION') {
1443
+ const option = o;
1444
+ option.selected = value.includes(option.value);
1445
+ }
1446
+ }
1447
+ this.changeListen(true);
1448
+ }
1449
+ updateSelect(id, style, classes) {
1450
+ this.changeListen(false);
1451
+ if (id) {
1452
+ this.select.dataset.id = id;
1453
+ }
1454
+ if (style) {
1455
+ this.select.style.cssText = style;
1456
+ }
1457
+ if (classes) {
1458
+ this.select.className = '';
1459
+ classes.forEach((c) => {
1460
+ if (c.trim() !== '') {
1461
+ this.select.classList.add(c.trim());
1462
+ }
1463
+ });
1464
+ }
1465
+ this.changeListen(true);
1466
+ }
1467
+ updateOptions(data) {
1468
+ this.changeListen(false);
1469
+ this.select.innerHTML = '';
1470
+ for (const d of data) {
1471
+ if (d instanceof Optgroup) {
1472
+ this.select.appendChild(this.createOptgroup(d));
1473
+ }
1474
+ if (d instanceof Option) {
1475
+ this.select.appendChild(this.createOption(d));
1476
+ }
1477
+ }
1478
+ this.select.dispatchEvent(new Event('change'));
1479
+ this.changeListen(true);
1480
+ }
1481
+ createOptgroup(optgroup) {
1482
+ const optgroupEl = document.createElement('optgroup');
1483
+ optgroupEl.id = optgroup.id;
1484
+ optgroupEl.label = optgroup.label;
1485
+ if (optgroup.selectAll) {
1486
+ optgroupEl.dataset.selectAll = 'true';
1487
+ }
1488
+ if (optgroup.closable !== 'off') {
1489
+ optgroupEl.dataset.closable = optgroup.closable;
1490
+ }
1491
+ if (optgroup.options) {
1492
+ for (const o of optgroup.options) {
1493
+ optgroupEl.appendChild(this.createOption(o));
1494
+ }
1495
+ }
1496
+ return optgroupEl;
1497
+ }
1498
+ createOption(info) {
1499
+ const optionEl = document.createElement('option');
1500
+ optionEl.id = info.id;
1501
+ optionEl.value = info.value;
1502
+ optionEl.innerHTML = info.text;
1503
+ if (info.html !== '') {
1504
+ optionEl.setAttribute('data-html', info.html);
1505
+ }
1506
+ if (info.selected) {
1507
+ optionEl.selected = info.selected;
1508
+ }
1509
+ if (info.disabled) {
1510
+ optionEl.disabled = true;
1511
+ }
1512
+ if (info.display === false) {
1513
+ optionEl.style.display = 'none';
1514
+ }
1515
+ if (info.placeholder) {
1516
+ optionEl.setAttribute('data-placeholder', 'true');
1517
+ }
1518
+ if (info.mandatory) {
1519
+ optionEl.setAttribute('data-mandatory', 'true');
1520
+ }
1521
+ if (info.class) {
1522
+ info.class.split(' ').forEach((optionClass) => {
1523
+ optionEl.classList.add(optionClass);
1524
+ });
1525
+ }
1526
+ if (info.data && typeof info.data === 'object') {
1527
+ Object.keys(info.data).forEach((key) => {
1528
+ optionEl.setAttribute('data-' + kebabCase(key), info.data[key]);
1529
+ });
1530
+ }
1531
+ return optionEl;
1532
+ }
1533
+ destroy() {
1534
+ this.changeListen(false);
1535
+ this.select.removeEventListener('change', this.valueChange);
1536
+ if (this.observer) {
1537
+ this.observer.disconnect();
1538
+ this.observer = null;
1539
+ }
1540
+ delete this.select.dataset.id;
1541
+ this.showUI();
1542
+ }
1543
+ }
1541
1544
 
1542
- class SlimSelect {
1543
- constructor(config) {
1544
- var _a;
1545
- this.events = {
1546
- search: undefined,
1547
- searchFilter: (opt, search) => {
1548
- return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1;
1549
- },
1550
- addable: undefined,
1551
- beforeChange: undefined,
1552
- afterChange: undefined,
1553
- beforeOpen: undefined,
1554
- afterOpen: undefined,
1555
- beforeClose: undefined,
1556
- afterClose: undefined,
1557
- };
1558
- this.windowResize = debounce(() => {
1559
- if (!this.settings.isOpen && !this.settings.isFullOpen) {
1560
- return;
1561
- }
1562
- this.render.moveContent();
1563
- });
1564
- this.windowScroll = debounce(() => {
1565
- if (!this.settings.isOpen && !this.settings.isFullOpen) {
1566
- return;
1567
- }
1568
- this.render.moveContent();
1569
- });
1570
- this.documentClick = (e) => {
1571
- if (!this.settings.isOpen) {
1572
- return;
1573
- }
1574
- if (e.target && !hasClassInTree(e.target, this.settings.id)) {
1575
- this.close(e.type);
1576
- }
1577
- };
1578
- this.windowVisibilityChange = () => {
1579
- if (document.hidden) {
1580
- this.close();
1581
- }
1582
- };
1583
- this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
1584
- if (!this.selectEl) {
1585
- if (config.events && config.events.error) {
1586
- config.events.error(new Error('Could not find select element'));
1587
- }
1588
- return;
1589
- }
1590
- if (this.selectEl.tagName !== 'SELECT') {
1591
- if (config.events && config.events.error) {
1592
- config.events.error(new Error('Element isnt of type select'));
1593
- }
1594
- return;
1595
- }
1596
- if (this.selectEl.dataset.ssid) {
1597
- this.destroy();
1598
- }
1599
- this.settings = new Settings(config.settings);
1600
- const debounceEvents = ['afterChange', 'beforeOpen', 'afterOpen', 'beforeClose', 'afterClose'];
1601
- for (const key in config.events) {
1602
- if (!config.events.hasOwnProperty(key)) {
1603
- continue;
1604
- }
1605
- if (debounceEvents.indexOf(key) !== -1) {
1606
- this.events[key] = debounce(config.events[key], 100);
1607
- }
1608
- else {
1609
- this.events[key] = config.events[key];
1610
- }
1611
- }
1612
- this.settings.disabled = ((_a = config.settings) === null || _a === void 0 ? void 0 : _a.disabled) ? config.settings.disabled : this.selectEl.disabled;
1613
- this.settings.isMultiple = this.selectEl.multiple;
1614
- this.settings.style = this.selectEl.style.cssText;
1615
- this.settings.class = this.selectEl.className.split(' ');
1616
- this.select = new Select(this.selectEl);
1617
- this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class);
1618
- this.select.hideUI();
1619
- this.select.onValueChange = (values) => {
1620
- this.setSelected(values);
1621
- };
1622
- this.select.onClassChange = (classes) => {
1623
- this.settings.class = classes;
1624
- this.render.updateClassStyles();
1625
- };
1626
- this.select.onDisabledChange = (disabled) => {
1627
- if (disabled) {
1628
- this.disable();
1629
- }
1630
- else {
1631
- this.enable();
1632
- }
1633
- };
1634
- this.select.onOptionsChange = (data) => {
1635
- this.setData(data);
1636
- };
1637
- this.store = new Store(this.settings.isMultiple ? 'multiple' : 'single', config.data ? config.data : this.select.getData());
1638
- if (config.data) {
1639
- this.select.updateOptions(this.store.getData());
1640
- }
1641
- const callbacks = {
1642
- open: this.open.bind(this),
1643
- close: this.close.bind(this),
1644
- addable: this.events.addable ? this.events.addable : undefined,
1645
- setSelected: this.setSelected.bind(this),
1646
- addOption: this.addOption.bind(this),
1647
- search: this.search.bind(this),
1648
- beforeChange: this.events.beforeChange,
1649
- afterChange: this.events.afterChange,
1650
- };
1651
- this.render = new Render(this.settings, this.store, callbacks);
1652
- this.render.renderValues();
1653
- this.render.renderOptions(this.store.getData());
1654
- const selectAriaLabel = this.selectEl.getAttribute('aria-label');
1655
- const selectAriaLabelledBy = this.selectEl.getAttribute('aria-labelledby');
1656
- if (selectAriaLabel) {
1657
- this.render.main.main.setAttribute('aria-label', selectAriaLabel);
1658
- }
1659
- else if (selectAriaLabelledBy) {
1660
- this.render.main.main.setAttribute('aria-labelledby', selectAriaLabelledBy);
1661
- }
1662
- if (this.selectEl.parentNode) {
1663
- this.selectEl.parentNode.insertBefore(this.render.main.main, this.selectEl.nextSibling);
1664
- }
1665
- document.addEventListener('click', this.documentClick);
1666
- window.addEventListener('resize', this.windowResize, false);
1667
- if (this.settings.openPosition === 'auto') {
1668
- window.addEventListener('scroll', this.windowScroll, false);
1669
- }
1670
- document.addEventListener('visibilitychange', this.windowVisibilityChange);
1671
- if (this.settings.disabled) {
1672
- this.disable();
1673
- }
1674
- if (this.settings.alwaysOpen) {
1675
- this.open();
1676
- }
1677
- this.selectEl.slim = this;
1678
- }
1679
- enable() {
1680
- this.settings.disabled = false;
1681
- this.select.enable();
1682
- this.render.enable();
1683
- }
1684
- disable() {
1685
- this.settings.disabled = true;
1686
- this.select.disable();
1687
- this.render.disable();
1688
- }
1689
- getData() {
1690
- return this.store.getData();
1691
- }
1692
- setData(data) {
1693
- const selected = this.store.getSelected();
1694
- const err = this.store.validateDataArray(data);
1695
- if (err) {
1696
- if (this.events.error) {
1697
- this.events.error(err);
1698
- }
1699
- return;
1700
- }
1701
- this.store.setData(data);
1702
- const dataClean = this.store.getData();
1703
- this.select.updateOptions(dataClean);
1704
- this.render.renderValues();
1705
- this.render.renderOptions(dataClean);
1706
- if (this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
1707
- this.events.afterChange(this.store.getSelectedOptions());
1708
- }
1709
- }
1710
- getSelected() {
1711
- return this.store.getSelected();
1712
- }
1713
- setSelected(value, runAfterChange = true) {
1714
- const selected = this.store.getSelected();
1715
- this.store.setSelectedBy('value', Array.isArray(value) ? value : [value]);
1716
- const data = this.store.getData();
1717
- this.select.updateOptions(data);
1718
- this.render.renderValues();
1719
- if (this.render.content.search.input.value !== '') {
1720
- this.search(this.render.content.search.input.value);
1721
- }
1722
- else {
1723
- this.render.renderOptions(data);
1724
- }
1725
- if (runAfterChange && this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
1726
- this.events.afterChange(this.store.getSelectedOptions());
1727
- }
1728
- }
1729
- addOption(option) {
1730
- const selected = this.store.getSelected();
1731
- if (!this.store.getDataOptions().some((o) => { var _a; return o.value === ((_a = option.value) !== null && _a !== void 0 ? _a : option.text); })) {
1732
- this.store.addOption(option);
1733
- }
1734
- const data = this.store.getData();
1735
- this.select.updateOptions(data);
1736
- this.render.renderValues();
1737
- this.render.renderOptions(data);
1738
- if (this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
1739
- this.events.afterChange(this.store.getSelectedOptions());
1740
- }
1741
- }
1742
- open() {
1743
- if (this.settings.disabled || this.settings.isOpen) {
1744
- return;
1745
- }
1746
- if (this.events.beforeOpen) {
1747
- this.events.beforeOpen();
1748
- }
1749
- this.render.open();
1750
- if (this.settings.showSearch) {
1751
- this.render.searchFocus();
1752
- }
1753
- this.settings.isOpen = true;
1754
- setTimeout(() => {
1755
- if (this.events.afterOpen) {
1756
- this.events.afterOpen();
1757
- }
1758
- if (this.settings.isOpen) {
1759
- this.settings.isFullOpen = true;
1760
- }
1761
- }, this.settings.timeoutDelay);
1762
- if (this.settings.contentPosition === 'absolute') {
1763
- if (this.settings.intervalMove) {
1764
- clearInterval(this.settings.intervalMove);
1765
- }
1766
- this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
1767
- }
1768
- }
1769
- close(eventType = null) {
1770
- if (!this.settings.isOpen || this.settings.alwaysOpen) {
1771
- return;
1772
- }
1773
- if (this.events.beforeClose) {
1774
- this.events.beforeClose();
1775
- }
1776
- this.render.close();
1777
- if (this.render.content.search.input.value !== '') {
1778
- this.search('');
1779
- }
1780
- this.render.mainFocus(eventType);
1781
- this.settings.isOpen = false;
1782
- this.settings.isFullOpen = false;
1783
- setTimeout(() => {
1784
- if (this.events.afterClose) {
1785
- this.events.afterClose();
1786
- }
1787
- }, this.settings.timeoutDelay);
1788
- if (this.settings.intervalMove) {
1789
- clearInterval(this.settings.intervalMove);
1790
- }
1791
- }
1792
- search(value) {
1793
- if (this.render.content.search.input.value !== value) {
1794
- this.render.content.search.input.value = value;
1795
- }
1796
- if (!this.events.search) {
1797
- this.render.renderOptions(value === '' ? this.store.getData() : this.store.search(value, this.events.searchFilter));
1798
- return;
1799
- }
1800
- this.render.renderSearching();
1801
- const searchResp = this.events.search(value, this.store.getSelectedOptions());
1802
- if (searchResp instanceof Promise) {
1803
- searchResp
1804
- .then((data) => {
1805
- this.render.renderOptions(this.store.partialToFullData(data));
1806
- })
1807
- .catch((err) => {
1808
- this.render.renderError(typeof err === 'string' ? err : err.message);
1809
- });
1810
- return;
1811
- }
1812
- else if (Array.isArray(searchResp)) {
1813
- this.render.renderOptions(this.store.partialToFullData(searchResp));
1814
- }
1815
- else {
1816
- this.render.renderError('Search event must return a promise or an array of data');
1817
- }
1818
- }
1819
- destroy() {
1820
- document.removeEventListener('click', this.documentClick);
1821
- window.removeEventListener('resize', this.windowResize, false);
1822
- if (this.settings.openPosition === 'auto') {
1823
- window.removeEventListener('scroll', this.windowScroll, false);
1824
- }
1825
- document.removeEventListener('visibilitychange', this.windowVisibilityChange);
1826
- this.store.setData([]);
1827
- this.render.destroy();
1828
- this.select.destroy();
1829
- }
1830
- }
1545
+ class Settings {
1546
+ constructor(settings) {
1547
+ this.id = '';
1548
+ this.style = '';
1549
+ this.class = [];
1550
+ this.isMultiple = false;
1551
+ this.isOpen = false;
1552
+ this.isFullOpen = false;
1553
+ this.intervalMove = null;
1554
+ if (!settings) {
1555
+ settings = {};
1556
+ }
1557
+ this.id = 'ss-' + generateID();
1558
+ this.style = settings.style || '';
1559
+ this.class = settings.class || [];
1560
+ this.disabled = settings.disabled !== undefined ? settings.disabled : false;
1561
+ this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false;
1562
+ this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true;
1563
+ this.ariaLabel = settings.ariaLabel || 'Combobox';
1564
+ this.searchPlaceholder = settings.searchPlaceholder || 'Search';
1565
+ this.searchText = settings.searchText || 'No Results';
1566
+ this.searchingText = settings.searchingText || 'Searching...';
1567
+ this.searchHighlight = settings.searchHighlight !== undefined ? settings.searchHighlight : false;
1568
+ this.closeOnSelect = settings.closeOnSelect !== undefined ? settings.closeOnSelect : true;
1569
+ this.contentLocation = settings.contentLocation || document.body;
1570
+ this.contentPosition = settings.contentPosition || 'absolute';
1571
+ this.openPosition = settings.openPosition || 'auto';
1572
+ this.placeholderText = settings.placeholderText !== undefined ? settings.placeholderText : 'Select Value';
1573
+ this.allowDeselect = settings.allowDeselect !== undefined ? settings.allowDeselect : false;
1574
+ this.hideSelected = settings.hideSelected !== undefined ? settings.hideSelected : false;
1575
+ this.keepOrder = settings.keepOrder !== undefined ? settings.keepOrder : false;
1576
+ this.showOptionTooltips = settings.showOptionTooltips !== undefined ? settings.showOptionTooltips : false;
1577
+ this.minSelected = settings.minSelected || 0;
1578
+ this.maxSelected = settings.maxSelected || 1000;
1579
+ this.timeoutDelay = settings.timeoutDelay || 200;
1580
+ this.maxValuesShown = settings.maxValuesShown || 20;
1581
+ this.maxValuesMessage = settings.maxValuesMessage || '{number} selected';
1582
+ }
1583
+ }
1831
1584
 
1832
- return SlimSelect;
1585
+ class SlimSelect {
1586
+ constructor(config) {
1587
+ var _a;
1588
+ this.events = {
1589
+ search: undefined,
1590
+ searchFilter: (opt, search) => {
1591
+ return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1;
1592
+ },
1593
+ addable: undefined,
1594
+ beforeChange: undefined,
1595
+ afterChange: undefined,
1596
+ beforeOpen: undefined,
1597
+ afterOpen: undefined,
1598
+ beforeClose: undefined,
1599
+ afterClose: undefined,
1600
+ };
1601
+ this.windowResize = debounce(() => {
1602
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1603
+ return;
1604
+ }
1605
+ this.render.moveContent();
1606
+ });
1607
+ this.windowScroll = debounce(() => {
1608
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1609
+ return;
1610
+ }
1611
+ this.render.moveContent();
1612
+ });
1613
+ this.documentClick = (e) => {
1614
+ if (!this.settings.isOpen) {
1615
+ return;
1616
+ }
1617
+ if (e.target && !hasClassInTree(e.target, this.settings.id)) {
1618
+ this.close(e.type);
1619
+ }
1620
+ };
1621
+ this.windowVisibilityChange = () => {
1622
+ if (document.hidden) {
1623
+ this.close();
1624
+ }
1625
+ };
1626
+ this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
1627
+ if (!this.selectEl) {
1628
+ if (config.events && config.events.error) {
1629
+ config.events.error(new Error('Could not find select element'));
1630
+ }
1631
+ return;
1632
+ }
1633
+ if (this.selectEl.tagName !== 'SELECT') {
1634
+ if (config.events && config.events.error) {
1635
+ config.events.error(new Error('Element isnt of type select'));
1636
+ }
1637
+ return;
1638
+ }
1639
+ if (this.selectEl.dataset.ssid) {
1640
+ this.destroy();
1641
+ }
1642
+ this.settings = new Settings(config.settings);
1643
+ const debounceEvents = ['afterChange', 'beforeOpen', 'afterOpen', 'beforeClose', 'afterClose'];
1644
+ for (const key in config.events) {
1645
+ if (!config.events.hasOwnProperty(key)) {
1646
+ continue;
1647
+ }
1648
+ if (debounceEvents.indexOf(key) !== -1) {
1649
+ this.events[key] = debounce(config.events[key], 100);
1650
+ }
1651
+ else {
1652
+ this.events[key] = config.events[key];
1653
+ }
1654
+ }
1655
+ this.settings.disabled = ((_a = config.settings) === null || _a === void 0 ? void 0 : _a.disabled) ? config.settings.disabled : this.selectEl.disabled;
1656
+ this.settings.isMultiple = this.selectEl.multiple;
1657
+ this.settings.style = this.selectEl.style.cssText;
1658
+ this.settings.class = this.selectEl.className.split(' ');
1659
+ this.select = new Select(this.selectEl);
1660
+ this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class);
1661
+ this.select.hideUI();
1662
+ this.select.onValueChange = (values) => {
1663
+ this.setSelected(values);
1664
+ };
1665
+ this.select.onClassChange = (classes) => {
1666
+ this.settings.class = classes;
1667
+ this.render.updateClassStyles();
1668
+ };
1669
+ this.select.onDisabledChange = (disabled) => {
1670
+ if (disabled) {
1671
+ this.disable();
1672
+ }
1673
+ else {
1674
+ this.enable();
1675
+ }
1676
+ };
1677
+ this.select.onOptionsChange = (data) => {
1678
+ this.setData(data);
1679
+ };
1680
+ this.store = new Store(this.settings.isMultiple ? 'multiple' : 'single', config.data ? config.data : this.select.getData());
1681
+ if (config.data) {
1682
+ this.select.updateOptions(this.store.getData());
1683
+ }
1684
+ const renderCallbacks = {
1685
+ open: this.open.bind(this),
1686
+ close: this.close.bind(this),
1687
+ addable: this.events.addable ? this.events.addable : undefined,
1688
+ setSelected: this.setSelected.bind(this),
1689
+ addOption: this.addOption.bind(this),
1690
+ search: this.search.bind(this),
1691
+ beforeChange: this.events.beforeChange,
1692
+ afterChange: this.events.afterChange,
1693
+ };
1694
+ this.render = new Render(this.settings, this.store, renderCallbacks);
1695
+ this.render.renderValues();
1696
+ this.render.renderOptions(this.store.getData());
1697
+ const selectAriaLabel = this.selectEl.getAttribute('aria-label');
1698
+ const selectAriaLabelledBy = this.selectEl.getAttribute('aria-labelledby');
1699
+ if (selectAriaLabel) {
1700
+ this.render.main.main.setAttribute('aria-label', selectAriaLabel);
1701
+ }
1702
+ else if (selectAriaLabelledBy) {
1703
+ this.render.main.main.setAttribute('aria-labelledby', selectAriaLabelledBy);
1704
+ }
1705
+ if (this.selectEl.parentNode) {
1706
+ this.selectEl.parentNode.insertBefore(this.render.main.main, this.selectEl.nextSibling);
1707
+ }
1708
+ window.addEventListener('resize', this.windowResize, false);
1709
+ if (this.settings.openPosition === 'auto') {
1710
+ window.addEventListener('scroll', this.windowScroll, false);
1711
+ }
1712
+ document.addEventListener('visibilitychange', this.windowVisibilityChange);
1713
+ if (this.settings.disabled) {
1714
+ this.disable();
1715
+ }
1716
+ if (this.settings.alwaysOpen) {
1717
+ this.open();
1718
+ }
1719
+ this.selectEl.slim = this;
1720
+ }
1721
+ enable() {
1722
+ this.settings.disabled = false;
1723
+ this.select.enable();
1724
+ this.render.enable();
1725
+ }
1726
+ disable() {
1727
+ this.settings.disabled = true;
1728
+ this.select.disable();
1729
+ this.render.disable();
1730
+ }
1731
+ getData() {
1732
+ return this.store.getData();
1733
+ }
1734
+ setData(data) {
1735
+ const selected = this.store.getSelected();
1736
+ const err = this.store.validateDataArray(data);
1737
+ if (err) {
1738
+ if (this.events.error) {
1739
+ this.events.error(err);
1740
+ }
1741
+ return;
1742
+ }
1743
+ this.store.setData(data);
1744
+ const dataClean = this.store.getData();
1745
+ this.select.updateOptions(dataClean);
1746
+ this.render.renderValues();
1747
+ this.render.renderOptions(dataClean);
1748
+ if (this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
1749
+ this.events.afterChange(this.store.getSelectedOptions());
1750
+ }
1751
+ }
1752
+ getSelected() {
1753
+ return this.store.getSelected();
1754
+ }
1755
+ setSelected(value, runAfterChange = true) {
1756
+ const selected = this.store.getSelected();
1757
+ this.store.setSelectedBy('value', Array.isArray(value) ? value : [value]);
1758
+ const data = this.store.getData();
1759
+ this.select.updateOptions(data);
1760
+ this.render.renderValues();
1761
+ if (this.render.content.search.input.value !== '') {
1762
+ this.search(this.render.content.search.input.value);
1763
+ }
1764
+ else {
1765
+ this.render.renderOptions(data);
1766
+ }
1767
+ if (runAfterChange && this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
1768
+ this.events.afterChange(this.store.getSelectedOptions());
1769
+ }
1770
+ }
1771
+ addOption(option) {
1772
+ const selected = this.store.getSelected();
1773
+ if (!this.store.getDataOptions().some((o) => { var _a; return o.value === ((_a = option.value) !== null && _a !== void 0 ? _a : option.text); })) {
1774
+ this.store.addOption(option);
1775
+ }
1776
+ const data = this.store.getData();
1777
+ this.select.updateOptions(data);
1778
+ this.render.renderValues();
1779
+ this.render.renderOptions(data);
1780
+ if (this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
1781
+ this.events.afterChange(this.store.getSelectedOptions());
1782
+ }
1783
+ }
1784
+ open() {
1785
+ if (this.settings.disabled || this.settings.isOpen) {
1786
+ return;
1787
+ }
1788
+ if (this.events.beforeOpen) {
1789
+ this.events.beforeOpen();
1790
+ }
1791
+ this.render.open();
1792
+ if (this.settings.showSearch) {
1793
+ this.render.searchFocus();
1794
+ }
1795
+ this.settings.isOpen = true;
1796
+ setTimeout(() => {
1797
+ if (this.events.afterOpen) {
1798
+ this.events.afterOpen();
1799
+ }
1800
+ if (this.settings.isOpen) {
1801
+ this.settings.isFullOpen = true;
1802
+ }
1803
+ document.addEventListener('click', this.documentClick);
1804
+ }, this.settings.timeoutDelay);
1805
+ if (this.settings.contentPosition === 'absolute') {
1806
+ if (this.settings.intervalMove) {
1807
+ clearInterval(this.settings.intervalMove);
1808
+ }
1809
+ this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
1810
+ }
1811
+ }
1812
+ close(eventType = null) {
1813
+ if (!this.settings.isOpen || this.settings.alwaysOpen) {
1814
+ return;
1815
+ }
1816
+ if (this.events.beforeClose) {
1817
+ this.events.beforeClose();
1818
+ }
1819
+ this.render.close();
1820
+ if (this.render.content.search.input.value !== '') {
1821
+ this.search('');
1822
+ }
1823
+ this.render.mainFocus(eventType);
1824
+ this.settings.isOpen = false;
1825
+ this.settings.isFullOpen = false;
1826
+ setTimeout(() => {
1827
+ if (this.events.afterClose) {
1828
+ this.events.afterClose();
1829
+ }
1830
+ document.removeEventListener('click', this.documentClick);
1831
+ }, this.settings.timeoutDelay);
1832
+ if (this.settings.intervalMove) {
1833
+ clearInterval(this.settings.intervalMove);
1834
+ }
1835
+ }
1836
+ search(value) {
1837
+ if (this.render.content.search.input.value !== value) {
1838
+ this.render.content.search.input.value = value;
1839
+ }
1840
+ if (!this.events.search) {
1841
+ this.render.renderOptions(value === '' ? this.store.getData() : this.store.search(value, this.events.searchFilter));
1842
+ return;
1843
+ }
1844
+ this.render.renderSearching();
1845
+ const searchResp = this.events.search(value, this.store.getSelectedOptions());
1846
+ if (searchResp instanceof Promise) {
1847
+ searchResp
1848
+ .then((data) => {
1849
+ this.render.renderOptions(this.store.partialToFullData(data));
1850
+ })
1851
+ .catch((err) => {
1852
+ this.render.renderError(typeof err === 'string' ? err : err.message);
1853
+ });
1854
+ return;
1855
+ }
1856
+ else if (Array.isArray(searchResp)) {
1857
+ this.render.renderOptions(this.store.partialToFullData(searchResp));
1858
+ }
1859
+ else {
1860
+ this.render.renderError('Search event must return a promise or an array of data');
1861
+ }
1862
+ }
1863
+ destroy() {
1864
+ document.removeEventListener('click', this.documentClick);
1865
+ window.removeEventListener('resize', this.windowResize, false);
1866
+ if (this.settings.openPosition === 'auto') {
1867
+ window.removeEventListener('scroll', this.windowScroll, false);
1868
+ }
1869
+ document.removeEventListener('visibilitychange', this.windowVisibilityChange);
1870
+ this.store.setData([]);
1871
+ this.render.destroy();
1872
+ this.select.destroy();
1873
+ }
1874
+ }
1833
1875
 
1834
- }));
1876
+ return SlimSelect;
1877
+
1878
+ }));