slim-select 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +8 -0
  2. package/dist/render.d.ts +9 -2
  3. package/dist/select.d.ts +6 -6
  4. package/dist/settings.d.ts +0 -3
  5. package/dist/slimselect.cjs.js +148 -51
  6. package/dist/slimselect.css +1 -1
  7. package/dist/slimselect.css.map +1 -1
  8. package/dist/slimselect.es.js +148 -51
  9. package/dist/slimselect.global.js +148 -51
  10. package/dist/slimselect.js +148 -51
  11. package/dist/slimselect.min.js +1 -1
  12. package/dist/slimselect.umd.js +148 -51
  13. package/dist/slimselect.umd.min.js +1 -1
  14. package/dist/store.d.ts +5 -0
  15. package/docs/assets/data.js +7 -3
  16. package/docs/assets/home.css +1 -1
  17. package/docs/assets/home.js +1 -1
  18. package/docs/assets/index.css +1 -1
  19. package/docs/assets/index.js +7 -7
  20. package/docs/assets/index2.js +119 -35
  21. package/docs/assets/index3.js +22 -15
  22. package/docs/assets/index4.js +1 -1
  23. package/docs/assets/index5.js +4 -2
  24. package/docs/assets/install.js +4 -4
  25. package/docs/assets/selects.js +1 -1
  26. package/package.json +2 -2
  27. package/src/docs/app.vue +2 -1
  28. package/src/docs/pages/data.vue +4 -0
  29. package/src/docs/pages/events/search.vue +29 -15
  30. package/src/docs/pages/frameworks/vue.vue +3 -1
  31. package/src/docs/pages/home.vue +104 -57
  32. package/src/docs/pages/settings/closable.vue +128 -0
  33. package/src/docs/pages/settings/index.vue +6 -3
  34. package/src/docs/pages/settings/select_all.vue +88 -0
  35. package/src/slim-select/index.ts +3 -1
  36. package/src/slim-select/render.ts +164 -34
  37. package/src/slim-select/select.ts +35 -27
  38. package/src/slim-select/settings.ts +0 -4
  39. package/src/slim-select/slimselect.scss +112 -11
  40. package/src/slim-select/store.ts +19 -1
  41. package/src/vue/README.md +48 -0
  42. package/src/vue/dist/slimselectvue.es.js +148 -51
  43. package/src/vue/dist/slimselectvue.global.js +148 -51
  44. package/src/vue/dist/slimselectvue.ssr.js +148 -51
  45. package/src/vue/package.json +3 -2
  46. package/src/docs/pages/settings/select_by_group.vue +0 -46
@@ -0,0 +1,128 @@
1
+ <script lang="ts">
2
+ import { defineComponent } from 'vue'
3
+
4
+ import SlimSelect from '../../../slim-select'
5
+
6
+ export default defineComponent({
7
+ name: 'Closable',
8
+ mounted() {
9
+ new SlimSelect({
10
+ select: this.$refs.closableSingle as HTMLSelectElement,
11
+ })
12
+ new SlimSelect({
13
+ select: this.$refs.closableMultiple as HTMLSelectElement,
14
+ })
15
+ },
16
+ })
17
+ </script>
18
+
19
+ <template>
20
+ <div id="closable" class="content">
21
+ <h2 class="header">closable</h2>
22
+ <p>closable is a optgroup settings that adds the ability to have closable optgroup options.</p>
23
+ <p>Values: <strong>"off"</strong> | <strong>"open"</strong> | <strong>"close"</strong></p>
24
+ <p>Default: <strong>"off"</strong></p>
25
+
26
+ <div class="alert info">You can set closable either by data or by html dataset added to the optgroup element</div>
27
+
28
+ <div class="row">
29
+ <select ref="closableSingle">
30
+ <optgroup label="Label 1" data-closable="off">
31
+ <option value="value1">Value 1</option>
32
+ <option value="value2">Value 2</option>
33
+ <option value="value3">Value 3</option>
34
+ </optgroup>
35
+ <optgroup label="Label 2" data-closable="open">
36
+ <option value="value4">Value 4</option>
37
+ <option value="value5">Value 5</option>
38
+ <option value="value6">Value 6</option>
39
+ </optgroup>
40
+ <optgroup label="Label 3" data-closable="close">
41
+ <option value="value7">Value 7</option>
42
+ <option value="value8">Value 8</option>
43
+ <option value="value9">Value 9</option>
44
+ </optgroup>
45
+ </select>
46
+ <select ref="closableMultiple" multiple>
47
+ <optgroup label="Label 1" data-selectall="true" data-closable="off">
48
+ <option value="value1">Value 1</option>
49
+ <option value="value2">Value 2</option>
50
+ <option value="value3">Value 3</option>
51
+ </optgroup>
52
+ <optgroup label="Label 2" data-selectall="true" data-closable="open">
53
+ <option value="value4">Value 4</option>
54
+ <option value="value5">Value 5</option>
55
+ <option value="value6">Value 6</option>
56
+ </optgroup>
57
+ <optgroup label="Label 3" data-selectall="true" data-closable="close">
58
+ <option value="value7">Value 7</option>
59
+ <option value="value8">Value 8</option>
60
+ <option value="value9">Value 9</option>
61
+ </optgroup>
62
+ </select>
63
+ </div>
64
+ <br />
65
+
66
+ <h3>Via data</h3>
67
+ <pre>
68
+ <code class="language-javascript">
69
+ new SlimSelect({
70
+ select: '#selectElement',
71
+ data: [
72
+ {
73
+ label: 'Label 1',
74
+ closable: 'off',
75
+ options: [
76
+ { text: 'Option 1', value: '1' },
77
+ { text: 'Option 2', value: '2' },
78
+ { text: 'Option 3', value: '3' },
79
+ ],
80
+ },
81
+ {
82
+ label: 'Label 2',
83
+ closable: 'open',
84
+ options: [
85
+ { text: 'Option 4', value: '4' },
86
+ { text: 'Option 5', value: '5' },
87
+ { text: 'Option 6', value: '6' },
88
+ ],
89
+ },
90
+ {
91
+ label: 'Label 3',
92
+ closable: 'close',
93
+ options: [
94
+ { text: 'Option 7', value: '7' },
95
+ { text: 'Option 8', value: '8' },
96
+ { text: 'Option 9', value: '9' },
97
+ ],
98
+ },
99
+ ],
100
+ })
101
+ </code>
102
+ </pre>
103
+ <br />
104
+
105
+ <h3>Via html</h3>
106
+ <pre>
107
+ <code class="language-html">
108
+ &lt;select ref="closable" multiple&gt;
109
+ &lt;optgroup label="Label 1" data-closable="off"&gt;
110
+ &lt;option value="value1"&gt;Value 1&lt;/option&gt;
111
+ &lt;option value="value2"&gt;Value 2&lt;/option&gt;
112
+ &lt;option value="value3"&gt;Value 3&lt;/option&gt;
113
+ &lt;/optgroup&gt;
114
+ &lt;optgroup label="Label 2" data-closable="open"&gt;
115
+ &lt;option value="value4"&gt;Value 4&lt;/option&gt;
116
+ &lt;option value="value5"&gt;Value 5&lt;/option&gt;
117
+ &lt;option value="value6"&gt;Value 6&lt;/option&gt;
118
+ &lt;/optgroup&gt;
119
+ &lt;optgroup label="Label 3" data-closable="close"&gt;
120
+ &lt;option value="value7"&gt;Value 7&lt;/option&gt;
121
+ &lt;option value="value8"&gt;Value 8&lt;/option&gt;
122
+ &lt;option value="value9"&gt;Value 9&lt;/option&gt;
123
+ &lt;/optgroup&gt;
124
+ &lt;/select&gt;
125
+ </code>
126
+ </pre>
127
+ </div>
128
+ </template>
@@ -3,6 +3,7 @@ import { defineComponent } from 'vue'
3
3
 
4
4
  // Components
5
5
  import AlwaysOpen from './always_open.vue'
6
+ import Closable from './closable.vue'
6
7
  import CloseOnSelect from './close_on_select.vue'
7
8
  import ContentLocation from './content_location.vue'
8
9
  import ContentPosition from './content_position.vue'
@@ -18,7 +19,7 @@ import OpenPosition from './open_position.vue'
18
19
  import Placeholder from './placeholder.vue'
19
20
  import Search from './search.vue'
20
21
  import Select from './select.vue'
21
- import SelectByGroup from './select_by_group.vue'
22
+ import SelectAll from './select_all.vue'
22
23
  import ShowTooltip from './show_tooltip.vue'
23
24
  import Styles from './styles.vue'
24
25
 
@@ -42,7 +43,8 @@ export default defineComponent({
42
43
  Search,
43
44
  CloseOnSelect,
44
45
  ShowTooltip,
45
- SelectByGroup,
46
+ SelectAll,
47
+ Closable,
46
48
  HideSelected,
47
49
  },
48
50
  })
@@ -67,7 +69,8 @@ export default defineComponent({
67
69
  <Search />
68
70
  <CloseOnSelect />
69
71
  <ShowTooltip />
70
- <SelectByGroup />
72
+ <SelectAll />
73
+ <Closable />
71
74
  <HideSelected />
72
75
  </div>
73
76
  </template>
@@ -0,0 +1,88 @@
1
+ <script lang="ts">
2
+ import { defineComponent } from 'vue'
3
+
4
+ import SlimSelect from '../../../slim-select'
5
+
6
+ export default defineComponent({
7
+ name: 'SelectAll',
8
+ mounted() {
9
+ new SlimSelect({
10
+ select: this.$refs.selectAll as HTMLSelectElement,
11
+ })
12
+ },
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <div id="selectAll" class="content">
18
+ <h2 class="header">selectAll</h2>
19
+ <p>
20
+ selectAll is a setting that can be used to add a select all action to an optgroup. This setting can be set to true
21
+ or false. If set to true, a select all option will be added to the top of the selected values. If set to false or
22
+ not set at all, no select all action will be added to the optgroup.
23
+ </p>
24
+ <div class="alert info">You can set selectAll either by data or by html dataset added to the optgroup element</div>
25
+
26
+ <select ref="selectAll" multiple>
27
+ <optgroup label="Label 1" data-selectall="true">
28
+ <option value="value1">Value 1</option>
29
+ <option value="value2">Value 2</option>
30
+ <option value="value3">Value 3</option>
31
+ </optgroup>
32
+ <optgroup label="Label 2">
33
+ <option value="value4">Value 4</option>
34
+ <option value="value5">Value 5</option>
35
+ <option value="value6">Value 6</option>
36
+ </optgroup>
37
+ </select>
38
+ <br />
39
+
40
+ <h3>Via data</h3>
41
+ <pre>
42
+ <code class="language-javascript">
43
+ new SlimSelect({
44
+ select: '#selectElement',
45
+ data: [
46
+ {
47
+ label: 'Label 1',
48
+ selectAll: true,
49
+ options: [
50
+ { text: 'Option 1', value: '1' },
51
+ { text: 'Option 2', value: '2' },
52
+ { text: 'Option 3', value: '3' },
53
+ ],
54
+ },
55
+ {
56
+ label: 'Label 2',
57
+ selectAll: false,
58
+ options: [
59
+ { text: 'Option 4', value: '4' },
60
+ { text: 'Option 5', value: '5' },
61
+ { text: 'Option 6', value: '6' },
62
+ ],
63
+ },
64
+ ],
65
+ })
66
+ </code>
67
+ </pre>
68
+ <br />
69
+
70
+ <h3>Via html</h3>
71
+ <pre>
72
+ <code class="language-html">
73
+ &lt;select ref="selectAll" multiple&gt;
74
+ &lt;optgroup label="Label 1" data-selectall="true"&gt;
75
+ &lt;option value="value1"&gt;Value 1&lt;/option&gt;
76
+ &lt;option value="value2"&gt;Value 2&lt;/option&gt;
77
+ &lt;option value="value3"&gt;Value 3&lt;/option&gt;
78
+ &lt;/optgroup&gt;
79
+ &lt;optgroup label="Label 2"&gt;
80
+ &lt;option value="value4"&gt;Value 4&lt;/option&gt;
81
+ &lt;option value="value5"&gt;Value 5&lt;/option&gt;
82
+ &lt;option value="value6"&gt;Value 6&lt;/option&gt;
83
+ &lt;/optgroup&gt;
84
+ &lt;/select&gt;
85
+ </code>
86
+ </pre>
87
+ </div>
88
+ </template>
@@ -92,7 +92,7 @@ export default class SlimSelect {
92
92
  this.select.hideUI() // Hide the original select element
93
93
 
94
94
  // Add select listeners
95
- this.select.addSelectChangeListener((data: DataArray) => {
95
+ this.select.addSelectChangeListener((data: DataArrayPartial) => {
96
96
  // Run set data from the values given
97
97
  this.setData(data)
98
98
  })
@@ -126,6 +126,8 @@ export default class SlimSelect {
126
126
 
127
127
  // Setup render class
128
128
  this.render = new Render(this.settings, this.store, callbacks)
129
+ this.render.renderValues()
130
+ this.render.renderOptions(this.store.getData())
129
131
 
130
132
  // Add render after original select element
131
133
  if (this.selectEl.parentNode) {
@@ -89,17 +89,28 @@ export default class Render {
89
89
  addable: 'ss-addable',
90
90
  addablePath: 'M50,10 L50,90 M10,50 L90,50', // Not a class but whatever
91
91
 
92
- // List options
92
+ // List optgroups/options
93
93
  list: 'ss-list',
94
+
95
+ // Optgroup
94
96
  optgroup: 'ss-optgroup',
95
97
  optgroupLabel: 'ss-optgroup-label',
96
- optgroupSelectable: 'ss-optgroup-selectable',
98
+ optgroupLabelText: 'ss-optgroup-label-text',
99
+ optgroupActions: 'ss-optgroup-actions',
100
+ optgroupSelectAll: 'ss-selectall', // optgroup select all
101
+ optgroupSelectAllBox: 'M60,10 L10,10 L10,90 L90,90 L90,50', // Not a class but whatever
102
+ optgroupSelectAllCheck: 'M30,45 L50,70 L90,10', // Not a class but whatever
103
+ optgroupClosable: 'ss-closable',
104
+
105
+ // Option
97
106
  option: 'ss-option',
98
- optionSelected: 'ss-option-selected',
99
107
  optionDelete: 'M10,10 L90,90 M10,90 L90,10', // Not a class but whatever
100
108
  highlighted: 'ss-highlighted',
101
109
 
102
110
  // Misc
111
+ open: 'ss-open',
112
+ close: 'ss-close',
113
+ selected: 'ss-selected',
103
114
  error: 'ss-error',
104
115
  disabled: 'ss-disabled',
105
116
  hide: 'ss-hide',
@@ -113,12 +124,6 @@ export default class Render {
113
124
  this.main = this.mainDiv()
114
125
  this.content = this.contentDiv()
115
126
 
116
- // Render the values
117
- this.renderValues()
118
-
119
- // Render the options
120
- this.renderOptions(this.store.getData())
121
-
122
127
  // Add content to the content location settings
123
128
  this.settings.contentLocation.appendChild(this.content.main)
124
129
  }
@@ -826,25 +831,31 @@ export default class Render {
826
831
  // Loop through options and find the highlighted one
827
832
  for (let i = 0; i < options.length; i++) {
828
833
  if (options[i].classList.contains(this.classes.highlighted)) {
834
+ const prevOption = options[i]
829
835
  // Remove highlighted class from current one
830
- options[i].classList.remove(this.classes.highlighted)
836
+ prevOption.classList.remove(this.classes.highlighted)
837
+
838
+ // If previous option has parent classes ss-optgroup with ss-open then click it
839
+ const prevParent = prevOption.parentElement
840
+ if (prevParent && prevParent.classList.contains(this.classes.open)) {
841
+ const optgroupLabel = prevParent.querySelector('.' + this.classes.optgroupLabel) as HTMLDivElement
842
+ if (optgroupLabel) {
843
+ optgroupLabel.click()
844
+ }
845
+ }
831
846
 
832
847
  // Highlight the next one
833
- if (dir === 'down') {
834
- if (i + 1 < options.length) {
835
- options[i + 1].classList.add(this.classes.highlighted)
836
- this.ensureElementInView(this.content.list, options[i + 1])
837
- } else {
838
- options[0].classList.add(this.classes.highlighted)
839
- this.ensureElementInView(this.content.list, options[0])
840
- }
841
- } else {
842
- if (i - 1 >= 0) {
843
- options[i - 1].classList.add(this.classes.highlighted)
844
- this.ensureElementInView(this.content.list, options[i - 1])
845
- } else {
846
- options[options.length - 1].classList.add(this.classes.highlighted)
847
- this.ensureElementInView(this.content.list, options[options.length - 1])
848
+ let selectOption =
849
+ options[dir === 'down' ? (i + 1 < options.length ? i + 1 : 0) : i - 1 >= 0 ? i - 1 : options.length - 1]
850
+ selectOption.classList.add(this.classes.highlighted)
851
+ this.ensureElementInView(this.content.list, selectOption)
852
+
853
+ // If selected option has parent classes ss-optgroup with ss-close then click it
854
+ const selectParent = selectOption.parentElement
855
+ if (selectParent && selectParent.classList.contains(this.classes.close)) {
856
+ const optgroupLabel = selectParent.querySelector('.' + this.classes.optgroupLabel) as HTMLDivElement
857
+ if (optgroupLabel) {
858
+ optgroupLabel.click()
848
859
  }
849
860
  }
850
861
 
@@ -915,21 +926,140 @@ export default class Render {
915
926
  // Create label
916
927
  const optgroupLabel = document.createElement('div')
917
928
  optgroupLabel.classList.add(this.classes.optgroupLabel)
918
- optgroupLabel.innerHTML = d.label
929
+ optgroupEl.appendChild(optgroupLabel)
930
+
931
+ // Create label text div element
932
+ const optgroupLabelText = document.createElement('div')
933
+ optgroupLabelText.classList.add(this.classes.optgroupLabelText)
934
+ optgroupLabelText.textContent = d.label
935
+ optgroupLabel.appendChild(optgroupLabelText)
936
+
937
+ // Create options container
938
+ const optgroupActions = document.createElement('div')
939
+ optgroupActions.classList.add(this.classes.optgroupActions)
940
+ optgroupLabel.appendChild(optgroupActions)
919
941
 
920
942
  // If selectByGroup is true and isMultiple then add click event to label
921
- if (this.settings.selectByGroup && this.settings.isMultiple) {
922
- optgroupLabel.classList.add(this.classes.optgroupSelectable)
943
+ if (this.settings.isMultiple && d.selectAll) {
944
+ // Create new div to hold a checkbox svg
945
+ const selectAll = document.createElement('div')
946
+ selectAll.classList.add(this.classes.optgroupSelectAll)
947
+
948
+ // Check options and if all are selected, if so add class selected
949
+ let allSelected = true
950
+ for (const o of d.options) {
951
+ if (!o.selected) {
952
+ allSelected = false
953
+ break
954
+ }
955
+ }
956
+
957
+ // Add class if all selected
958
+ if (allSelected) {
959
+ selectAll.classList.add(this.classes.selected)
960
+ }
961
+
962
+ // Add select all text span
963
+ const selectAllText = document.createElement('span')
964
+ selectAllText.textContent = 'Select All'
965
+ selectAll.appendChild(selectAllText)
966
+
967
+ // Create new svg for checkbox
968
+ const selectAllSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
969
+ selectAllSvg.setAttribute('viewBox', '0 0 100 100')
970
+ selectAll.appendChild(selectAllSvg)
971
+
972
+ // Create new path for box
973
+ const selectAllBox = document.createElementNS('http://www.w3.org/2000/svg', 'path')
974
+ selectAllBox.setAttribute('d', this.classes.optgroupSelectAllBox)
975
+ selectAllSvg.appendChild(selectAllBox)
976
+
977
+ // Create new path for check
978
+ const selectAllCheck = document.createElementNS('http://www.w3.org/2000/svg', 'path')
979
+ selectAllCheck.setAttribute('d', this.classes.optgroupSelectAllCheck)
980
+ selectAllSvg.appendChild(selectAllCheck)
981
+
982
+ // Add click event listener to select all
983
+ selectAll.addEventListener('click', (e: MouseEvent) => {
984
+ e.preventDefault()
985
+ e.stopPropagation()
986
+
987
+ // Get the store current selected values
988
+ const currentSelected = this.store.getSelected()
989
+
990
+ // If all selected, remove all options from selected
991
+ // call setSelected and return
992
+ if (allSelected) {
993
+ // Put together new list minus all options in this optgroup
994
+ const newSelected = currentSelected.filter((s) => {
995
+ for (const o of d.options) {
996
+ if (s === o.value) {
997
+ return false
998
+ }
999
+ }
1000
+
1001
+ return true
1002
+ })
1003
+
1004
+ this.callbacks.setSelected(newSelected)
1005
+ return
1006
+ } else {
1007
+ // Put together new list with all options in this optgroup
1008
+ const newSelected = currentSelected.concat(d.options.map((o) => o.value))
1009
+
1010
+ this.callbacks.setSelected(newSelected)
1011
+ }
1012
+ })
1013
+
1014
+ // Append select all to label
1015
+ optgroupActions.appendChild(selectAll)
1016
+ }
1017
+
1018
+ // If optgroup has collapsable
1019
+ if (d.closable !== 'off') {
1020
+ // Create new div to hold a checkbox svg
1021
+ const optgroupClosable = document.createElement('div')
1022
+ optgroupClosable.classList.add(this.classes.optgroupClosable)
1023
+
1024
+ // Create svg arrow
1025
+ const optgroupClosableSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
1026
+ optgroupClosableSvg.setAttribute('viewBox', '0 0 100 100')
1027
+ optgroupClosableSvg.classList.add(this.classes.arrow)
1028
+ optgroupClosable.appendChild(optgroupClosableSvg)
1029
+
1030
+ // Create new path for arrow
1031
+ const optgroupClosableArrow = document.createElementNS('http://www.w3.org/2000/svg', 'path')
1032
+ optgroupClosableArrow.setAttribute('d', this.classes.arrow)
1033
+ optgroupClosableSvg.appendChild(optgroupClosableArrow)
1034
+
1035
+ // Add primary open or close class to optgroupEl
1036
+ if (d.closable === 'open') {
1037
+ optgroupEl.classList.add(this.classes.open)
1038
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)
1039
+ } else if (d.closable === 'close') {
1040
+ optgroupEl.classList.add(this.classes.close)
1041
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowClose)
1042
+ }
1043
+
1044
+ // Add click event listener to close
923
1045
  optgroupLabel.addEventListener('click', (e: MouseEvent) => {
924
1046
  e.preventDefault()
925
1047
  e.stopPropagation()
926
1048
 
927
- for (const childEl of optgroupEl.children as any as HTMLDivElement[]) {
928
- if (childEl.className.indexOf(this.classes.option) !== -1) {
929
- childEl.click()
930
- }
1049
+ // If optgroup is closed, open it
1050
+ if (optgroupEl.classList.contains(this.classes.close)) {
1051
+ optgroupEl.classList.remove(this.classes.close)
1052
+ optgroupEl.classList.add(this.classes.open)
1053
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)
1054
+ } else {
1055
+ optgroupEl.classList.remove(this.classes.open)
1056
+ optgroupEl.classList.add(this.classes.close)
1057
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowClose)
931
1058
  }
932
1059
  })
1060
+
1061
+ // Append close to label
1062
+ optgroupActions.appendChild(optgroupClosable)
933
1063
  }
934
1064
 
935
1065
  // Add optgroup label
@@ -1006,9 +1136,9 @@ export default class Render {
1006
1136
 
1007
1137
  // If option is selected
1008
1138
  if (option.selected) {
1009
- optionEl.classList.add(this.classes.optionSelected)
1139
+ optionEl.classList.add(this.classes.selected)
1010
1140
  } else {
1011
- optionEl.classList.remove(this.classes.optionSelected)
1141
+ optionEl.classList.remove(this.classes.selected)
1012
1142
  }
1013
1143
 
1014
1144
  // Add click event listener
@@ -1,12 +1,12 @@
1
1
  import { generateID, kebabCase } from './helpers'
2
- import { DataArray, Optgroup, Option } from './store'
2
+ import { DataArray, DataArrayPartial, Optgroup, OptgroupOptional, Option } from './store'
3
3
 
4
4
  export default class Select {
5
5
  public select: HTMLSelectElement
6
6
  public listen: boolean = false
7
7
 
8
8
  // Mutation observer fields
9
- public onSelectChange?: (data: DataArray) => void
9
+ public onSelectChange?: (data: DataArrayPartial) => void
10
10
  public onValueChange?: (value: string[]) => void
11
11
  private observer: MutationObserver | null = null
12
12
 
@@ -55,7 +55,7 @@ export default class Select {
55
55
  }
56
56
 
57
57
  // Add change listener to original select
58
- public addSelectChangeListener(func: (data: DataArray) => void): void {
58
+ public addSelectChangeListener(func: (data: DataArrayPartial) => void): void {
59
59
  this.onSelectChange = func
60
60
  this.addObserver()
61
61
  this.connectObserver()
@@ -129,8 +129,8 @@ export default class Select {
129
129
  }
130
130
 
131
131
  // From the select element pull optgroup and options into data
132
- public getData(): DataArray {
133
- let data = []
132
+ public getData(): DataArrayPartial {
133
+ let data = [] as DataArrayPartial
134
134
 
135
135
  // Loop through nodes and get data
136
136
  const nodes = this.select.childNodes as any as HTMLOptGroupElement[] | HTMLOptionElement[]
@@ -149,23 +149,43 @@ export default class Select {
149
149
  return data
150
150
  }
151
151
 
152
- public getDataFromOptgroup(optgroup: HTMLOptGroupElement): Optgroup {
152
+ public getDataFromOptgroup(optgroup: HTMLOptGroupElement): OptgroupOptional {
153
153
  let data = {
154
- id: '',
154
+ id: (optgroup.dataset ? optgroup.dataset.id : false) || '',
155
155
  label: optgroup.label,
156
+ selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
157
+ closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
156
158
  options: [],
157
- } as Optgroup
159
+ } as OptgroupOptional
158
160
 
159
161
  const options = optgroup.childNodes as any as HTMLOptionElement[]
160
162
  for (const o of options) {
161
163
  if (o.nodeName === 'OPTION') {
162
- data.options.push(this.getDataFromOption(o as HTMLOptionElement))
164
+ data.options!.push(this.getDataFromOption(o as HTMLOptionElement))
163
165
  }
164
166
  }
165
167
 
166
168
  return data
167
169
  }
168
170
 
171
+ // From passed in option pull pieces of usable information
172
+ public getDataFromOption(option: HTMLOptionElement): Option {
173
+ return {
174
+ id: (option.dataset ? option.dataset.id : false) || '',
175
+ value: option.value,
176
+ text: option.text,
177
+ html: option.innerHTML,
178
+ selected: option.selected,
179
+ display: option.style.display === 'none' ? false : true,
180
+ disabled: option.disabled,
181
+ mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
182
+ placeholder: option.dataset.placeholder === 'true',
183
+ class: option.className,
184
+ style: option.style.cssText,
185
+ data: option.dataset,
186
+ } as Option
187
+ }
188
+
169
189
  public getSelectedValues(): string[] {
170
190
  let values = []
171
191
 
@@ -195,24 +215,6 @@ export default class Select {
195
215
  return values
196
216
  }
197
217
 
198
- // From passed in option pull pieces of usable information
199
- public getDataFromOption(option: HTMLOptionElement): Option {
200
- return {
201
- id: (option.dataset ? option.dataset.id : false) || generateID(),
202
- value: option.value,
203
- text: option.text,
204
- html: option.innerHTML,
205
- selected: option.selected,
206
- display: option.style.display === 'none' ? false : true,
207
- disabled: option.disabled,
208
- mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
209
- placeholder: option.dataset.placeholder === 'true',
210
- class: option.className,
211
- style: option.style.cssText,
212
- data: option.dataset,
213
- } as Option
214
- }
215
-
216
218
  public setSelected(value: string[]): void {
217
219
  // Loop through options and set selected
218
220
  const options = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]
@@ -288,6 +290,12 @@ export default class Select {
288
290
  const optgroupEl = document.createElement('optgroup')
289
291
  optgroupEl.id = optgroup.id
290
292
  optgroupEl.label = optgroup.label
293
+ if (optgroup.selectAll) {
294
+ optgroupEl.dataset.selectAll = 'true'
295
+ }
296
+ if (optgroup.closable !== 'off') {
297
+ optgroupEl.dataset.closable = optgroup.closable
298
+ }
291
299
  if (optgroup.options) {
292
300
  for (const o of optgroup.options) {
293
301
  optgroupEl.appendChild(this.createOption(o))
@@ -14,8 +14,6 @@ export default class Settings {
14
14
  public intervalMove: NodeJS.Timeout | null = null
15
15
 
16
16
  // Fields set from constructor
17
- public mainHeight: number = 30
18
- public contentHeight: number = 0
19
17
  public isEnabled: boolean
20
18
  public alwaysOpen: boolean
21
19
  public showSearch: boolean
@@ -31,7 +29,6 @@ export default class Settings {
31
29
  public allowDeselect: boolean
32
30
  public hideSelected: boolean
33
31
  public showOptionTooltips: boolean
34
- public selectByGroup: boolean
35
32
  public minSelected: number
36
33
  public maxSelected: number
37
34
  public timeoutDelay: number
@@ -60,7 +57,6 @@ export default class Settings {
60
57
  this.allowDeselect = settings.allowDeselect !== undefined ? settings.allowDeselect : false
61
58
  this.hideSelected = settings.hideSelected !== undefined ? settings.hideSelected : false
62
59
  this.showOptionTooltips = settings.showOptionTooltips !== undefined ? settings.showOptionTooltips : false
63
- this.selectByGroup = settings.selectByGroup !== undefined ? settings.selectByGroup : false
64
60
  this.minSelected = settings.minSelected || 0
65
61
  this.maxSelected = settings.maxSelected || 1000
66
62
  this.timeoutDelay = settings.timeoutDelay || 200