slim-select 2.0.2 → 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 (66) hide show
  1. package/README.md +8 -0
  2. package/dist/index.d.ts +1 -1
  3. package/dist/render.d.ts +10 -3
  4. package/dist/select.d.ts +6 -6
  5. package/dist/settings.d.ts +0 -3
  6. package/dist/slimselect.cjs.js +202 -67
  7. package/dist/slimselect.css +1 -1
  8. package/dist/slimselect.css.map +1 -1
  9. package/dist/slimselect.es.js +202 -67
  10. package/dist/slimselect.global.js +202 -67
  11. package/dist/slimselect.js +202 -67
  12. package/dist/slimselect.min.js +1 -1
  13. package/dist/slimselect.umd.js +202 -67
  14. package/dist/slimselect.umd.min.js +1 -1
  15. package/dist/store.d.ts +5 -0
  16. package/docs/assets/data.js +7 -3
  17. package/docs/assets/home.css +1 -1
  18. package/docs/assets/home.js +1 -1
  19. package/docs/assets/index.css +1 -1
  20. package/docs/assets/index.js +7 -7
  21. package/docs/assets/index2.js +119 -35
  22. package/docs/assets/index3.js +39 -23
  23. package/docs/assets/index4.js +1 -1
  24. package/docs/assets/index5.js +147 -9
  25. package/docs/assets/install.js +4 -4
  26. package/docs/assets/selects.js +1 -1
  27. package/package.json +11 -3
  28. package/src/docs/app.vue +6 -5
  29. package/src/docs/{images → assets/images}/check-mark.svg +0 -0
  30. package/src/docs/{images → assets/images}/chrome.svg +0 -0
  31. package/src/docs/{images → assets/images}/firefox.svg +0 -0
  32. package/src/docs/{images → assets/images}/github.png +0 -0
  33. package/src/docs/{images → assets/images}/ie.svg +0 -0
  34. package/src/docs/{images → assets/images}/npm.png +0 -0
  35. package/src/docs/{images → assets/images}/opera.svg +0 -0
  36. package/src/docs/{images → assets/images}/safari.svg +0 -0
  37. package/src/docs/assets/scss/misc.scss +7 -0
  38. package/src/docs/env.d.ts +1 -0
  39. package/src/docs/pages/data.vue +4 -0
  40. package/src/docs/pages/events/addable.vue +22 -6
  41. package/src/docs/pages/events/before_after_change.vue +15 -1
  42. package/src/docs/pages/events/search.vue +31 -16
  43. package/src/docs/pages/frameworks/vue.vue +375 -7
  44. package/src/docs/pages/home.vue +104 -57
  45. package/src/docs/pages/methods/get_data.vue +2 -1
  46. package/src/docs/pages/methods/open_close.vue +1 -1
  47. package/src/docs/pages/settings/closable.vue +128 -0
  48. package/src/docs/pages/settings/index.vue +6 -3
  49. package/src/docs/pages/settings/select_all.vue +88 -0
  50. package/src/slim-select/index.ts +4 -2
  51. package/src/slim-select/render.ts +247 -59
  52. package/src/slim-select/rollup.config.mjs +5 -0
  53. package/src/slim-select/select.ts +48 -31
  54. package/src/slim-select/settings.ts +0 -4
  55. package/src/slim-select/slimselect.scss +112 -11
  56. package/src/slim-select/store.ts +19 -1
  57. package/src/vue/README.md +48 -0
  58. package/src/vue/dist/slimselectvue.es.js +1752 -0
  59. package/src/vue/dist/slimselectvue.global.js +1755 -0
  60. package/src/vue/dist/slimselectvue.ssr.js +1754 -0
  61. package/src/vue/hello.ts +5 -0
  62. package/src/vue/package.json +28 -0
  63. package/src/vue/rollup.config.mjs +44 -0
  64. package/src/vue/slimselect.vue +39 -5
  65. package/src/vue/tsconfig.json +14 -0
  66. package/src/docs/pages/settings/select_by_group.vue +0 -46
@@ -5,7 +5,7 @@ import Store, { DataArray, Optgroup, Option, OptionOptional } from './store'
5
5
  export interface Callbacks {
6
6
  open: () => void
7
7
  close: () => void
8
- addable?: (value: string) => OptionOptional | string
8
+ addable?: (value: string) => Promise<OptionOptional | string> | OptionOptional | string
9
9
  setSelected: (value: string[]) => void
10
10
  addOption: (option: Option) => void
11
11
  search: (search: string) => void
@@ -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
  }
@@ -266,6 +271,8 @@ export default class Render {
266
271
  if (!this.settings.allowDeselect || this.settings.isMultiple) {
267
272
  deselect.classList.add(this.classes.hide)
268
273
  }
274
+
275
+ // Add deselect onclick event
269
276
  deselect.onclick = (e: Event) => {
270
277
  e.stopPropagation()
271
278
 
@@ -274,7 +281,29 @@ export default class Render {
274
281
  return
275
282
  }
276
283
 
277
- this.callbacks.setSelected([''])
284
+ // By Default we will delete
285
+ let shouldDelete = true
286
+ const before = this.store.getSelectedOptions()
287
+ const after = [] as Option[]
288
+
289
+ // Add beforeChange callback
290
+ if (this.callbacks.beforeChange) {
291
+ shouldDelete = this.callbacks.beforeChange(after, before) === true
292
+ }
293
+
294
+ if (shouldDelete) {
295
+ this.callbacks.setSelected([''])
296
+
297
+ // Check if we need to close the dropdown
298
+ if (this.settings.closeOnSelect) {
299
+ this.callbacks.close()
300
+ }
301
+
302
+ // Run afterChange callback
303
+ if (this.callbacks.afterChange) {
304
+ this.callbacks.afterChange(after)
305
+ }
306
+ }
278
307
  }
279
308
 
280
309
  // Add deselect svg
@@ -466,8 +495,11 @@ export default class Render {
466
495
 
467
496
  // Only add deletion if the option is not mandatory
468
497
  if (!option.mandatory) {
498
+ // Create delete div element
469
499
  const deleteDiv = document.createElement('div')
470
500
  deleteDiv.classList.add(this.classes.valueDelete)
501
+
502
+ // Add delete onclick event
471
503
  deleteDiv.onclick = (e: Event) => {
472
504
  e.preventDefault()
473
505
  e.stopPropagation()
@@ -656,13 +688,18 @@ export default class Render {
656
688
 
657
689
  // If addable is enabled, add the addable div
658
690
  if (this.callbacks.addable) {
691
+ // Add main class
659
692
  addable.classList.add(this.classes.addable)
693
+
694
+ // Add svg icon
660
695
  const plus = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
661
696
  plus.setAttribute('viewBox', '0 0 100 100')
662
697
  const plusPath = document.createElementNS('http://www.w3.org/2000/svg', 'path')
663
698
  plusPath.setAttribute('d', this.classes.addablePath)
664
699
  plus.appendChild(plusPath)
665
700
  addable.appendChild(plus)
701
+
702
+ // Add click event to addable div
666
703
  addable.onclick = (e: Event) => {
667
704
  e.preventDefault()
668
705
  e.stopPropagation()
@@ -679,35 +716,61 @@ export default class Render {
679
716
  return
680
717
  }
681
718
 
719
+ // Run finish will be ran at the end of the addable function.
720
+ // Reason its in a function is so we can run it after the
721
+ // addable function is done for promise based addables
722
+ const runFinish = (oo: OptionOptional) => {
723
+ let newOption = new Option(oo)
724
+
725
+ // Call addOption to add the new option
726
+ this.callbacks.addOption(newOption)
727
+
728
+ // set selected value for single and multiple
729
+ if (this.settings.isMultiple) {
730
+ let values = this.store.getSelected()
731
+ values.push(newOption.value)
732
+ this.callbacks.setSelected(values)
733
+ } else {
734
+ this.callbacks.setSelected([newOption.value])
735
+ }
736
+
737
+ // Clear search
738
+ this.callbacks.search('')
739
+
740
+ // Close it only if closeOnSelect = true
741
+ if (this.settings.closeOnSelect) {
742
+ setTimeout(() => {
743
+ // Give it a little padding for a better looking animation
744
+ this.callbacks.close()
745
+ }, 100)
746
+ }
747
+ }
748
+
682
749
  // Call addable callback
683
750
  const addableValue = this.callbacks.addable(inputValue)
684
751
 
685
- // If the addableValue is a string, we will add it as a new option
686
- // Otherwise we will assume it is an option object
687
- if (typeof addableValue === 'string') {
688
- this.callbacks.addOption(
689
- new Option({
690
- text: addableValue,
691
- value: addableValue,
692
- }),
693
- )
752
+ // If addableValue is a promise, wait for it to resolve
753
+ if (addableValue instanceof Promise) {
754
+ addableValue.then((value) => {
755
+ if (typeof value === 'string') {
756
+ runFinish({
757
+ text: value,
758
+ value: value,
759
+ })
760
+ } else {
761
+ runFinish(value)
762
+ }
763
+ })
764
+ } else if (typeof addableValue === 'string') {
765
+ runFinish({
766
+ text: addableValue,
767
+ value: addableValue,
768
+ })
694
769
  } else {
695
- this.callbacks.addOption(new Option(addableValue))
770
+ runFinish(addableValue)
696
771
  }
697
772
 
698
- // Add option to selected
699
- this.callbacks.setSelected([inputValue])
700
-
701
- // Clear search
702
- this.callbacks.search('')
703
-
704
- // Close it only if closeOnSelect = true
705
- if (this.settings.closeOnSelect) {
706
- setTimeout(() => {
707
- // Give it a little padding for a better looking animation
708
- this.callbacks.close()
709
- }, 100)
710
- }
773
+ return
711
774
  }
712
775
  main.appendChild(addable)
713
776
 
@@ -768,25 +831,31 @@ export default class Render {
768
831
  // Loop through options and find the highlighted one
769
832
  for (let i = 0; i < options.length; i++) {
770
833
  if (options[i].classList.contains(this.classes.highlighted)) {
834
+ const prevOption = options[i]
771
835
  // Remove highlighted class from current one
772
- 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
+ }
773
846
 
774
847
  // Highlight the next one
775
- if (dir === 'down') {
776
- if (i + 1 < options.length) {
777
- options[i + 1].classList.add(this.classes.highlighted)
778
- this.ensureElementInView(this.content.list, options[i + 1])
779
- } else {
780
- options[0].classList.add(this.classes.highlighted)
781
- this.ensureElementInView(this.content.list, options[0])
782
- }
783
- } else {
784
- if (i - 1 >= 0) {
785
- options[i - 1].classList.add(this.classes.highlighted)
786
- this.ensureElementInView(this.content.list, options[i - 1])
787
- } else {
788
- options[options.length - 1].classList.add(this.classes.highlighted)
789
- 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()
790
859
  }
791
860
  }
792
861
 
@@ -857,21 +926,140 @@ export default class Render {
857
926
  // Create label
858
927
  const optgroupLabel = document.createElement('div')
859
928
  optgroupLabel.classList.add(this.classes.optgroupLabel)
860
- 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)
861
941
 
862
942
  // If selectByGroup is true and isMultiple then add click event to label
863
- if (this.settings.selectByGroup && this.settings.isMultiple) {
864
- 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
865
1045
  optgroupLabel.addEventListener('click', (e: MouseEvent) => {
866
1046
  e.preventDefault()
867
1047
  e.stopPropagation()
868
1048
 
869
- for (const childEl of optgroupEl.children as any as HTMLDivElement[]) {
870
- if (childEl.className.indexOf(this.classes.option) !== -1) {
871
- childEl.click()
872
- }
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)
873
1058
  }
874
1059
  })
1060
+
1061
+ // Append close to label
1062
+ optgroupActions.appendChild(optgroupClosable)
875
1063
  }
876
1064
 
877
1065
  // Add optgroup label
@@ -948,9 +1136,9 @@ export default class Render {
948
1136
 
949
1137
  // If option is selected
950
1138
  if (option.selected) {
951
- optionEl.classList.add(this.classes.optionSelected)
1139
+ optionEl.classList.add(this.classes.selected)
952
1140
  } else {
953
- optionEl.classList.remove(this.classes.optionSelected)
1141
+ optionEl.classList.remove(this.classes.selected)
954
1142
  }
955
1143
 
956
1144
  // Add click event listener
@@ -18,6 +18,7 @@ export default [
18
18
  resolve(),
19
19
  commonjs(),
20
20
  babel({
21
+ babelHelpers: 'bundled',
21
22
  exclude: 'node_modules/**',
22
23
  babelrc: false,
23
24
  presets: [
@@ -54,6 +55,7 @@ export default [
54
55
  resolve(),
55
56
  commonjs(),
56
57
  babel({
58
+ babelHelpers: 'bundled',
57
59
  exclude: 'node_modules/**',
58
60
  }),
59
61
  ],
@@ -79,6 +81,7 @@ export default [
79
81
  resolve(),
80
82
  commonjs(),
81
83
  babel({
84
+ babelHelpers: 'bundled',
82
85
  exclude: 'node_modules/**',
83
86
  }),
84
87
  terser(),
@@ -97,6 +100,7 @@ export default [
97
100
  resolve(),
98
101
  commonjs(),
99
102
  babel({
103
+ babelHelpers: 'bundled',
100
104
  exclude: 'node_modules/**',
101
105
  }),
102
106
  ],
@@ -115,6 +119,7 @@ export default [
115
119
  resolve(),
116
120
  commonjs(),
117
121
  babel({
122
+ babelHelpers: 'bundled',
118
123
  exclude: 'node_modules/**',
119
124
  }),
120
125
  ],
@@ -1,12 +1,12 @@
1
1
  import { generateID, kebabCase } from './helpers'
2
- import { DataArray, DataObject, 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()
@@ -86,7 +86,11 @@ export default class Select {
86
86
 
87
87
  private observeWrapper(mutations: MutationRecord[]): void {
88
88
  if (this.onSelectChange) {
89
+ // Just in case this triggers a change in the select
90
+ // we want to stop listening to it while we run onSelectChange
91
+ this.changeListen(false)
89
92
  this.onSelectChange(this.getData())
93
+ this.changeListen(true)
90
94
  }
91
95
  }
92
96
 
@@ -99,16 +103,21 @@ export default class Select {
99
103
  }
100
104
 
101
105
  // If anything changes in the select then update the data
102
- this.observer = new MutationObserver(this.observeWrapper)
106
+ this.observer = new MutationObserver(this.observeWrapper.bind(this))
103
107
  }
104
108
 
109
+ // Start observing the select
105
110
  private connectObserver(): void {
106
111
  if (this.observer) {
107
112
  this.observer.observe(this.select, {
108
- attributes: true,
113
+ // For now we only care about if the children change
109
114
  childList: true,
110
- characterData: true,
111
- subtree: true,
115
+
116
+ // We dont care about attributes for now
117
+ // might need to add this later
118
+ // attributes: true,
119
+ // characterData: true,
120
+ // subtree: true,
112
121
  })
113
122
  }
114
123
  }
@@ -120,8 +129,8 @@ export default class Select {
120
129
  }
121
130
 
122
131
  // From the select element pull optgroup and options into data
123
- public getData(): DataArray {
124
- let data = []
132
+ public getData(): DataArrayPartial {
133
+ let data = [] as DataArrayPartial
125
134
 
126
135
  // Loop through nodes and get data
127
136
  const nodes = this.select.childNodes as any as HTMLOptGroupElement[] | HTMLOptionElement[]
@@ -140,23 +149,43 @@ export default class Select {
140
149
  return data
141
150
  }
142
151
 
143
- public getDataFromOptgroup(optgroup: HTMLOptGroupElement): Optgroup {
152
+ public getDataFromOptgroup(optgroup: HTMLOptGroupElement): OptgroupOptional {
144
153
  let data = {
145
- id: '',
154
+ id: (optgroup.dataset ? optgroup.dataset.id : false) || '',
146
155
  label: optgroup.label,
156
+ selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
157
+ closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
147
158
  options: [],
148
- } as Optgroup
159
+ } as OptgroupOptional
149
160
 
150
161
  const options = optgroup.childNodes as any as HTMLOptionElement[]
151
162
  for (const o of options) {
152
163
  if (o.nodeName === 'OPTION') {
153
- data.options.push(this.getDataFromOption(o as HTMLOptionElement))
164
+ data.options!.push(this.getDataFromOption(o as HTMLOptionElement))
154
165
  }
155
166
  }
156
167
 
157
168
  return data
158
169
  }
159
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
+
160
189
  public getSelectedValues(): string[] {
161
190
  let values = []
162
191
 
@@ -186,24 +215,6 @@ export default class Select {
186
215
  return values
187
216
  }
188
217
 
189
- // From passed in option pull pieces of usable information
190
- public getDataFromOption(option: HTMLOptionElement): Option {
191
- return {
192
- id: (option.dataset ? option.dataset.id : false) || generateID(),
193
- value: option.value,
194
- text: option.text,
195
- html: option.innerHTML,
196
- selected: option.selected,
197
- display: option.style.display === 'none' ? false : true,
198
- disabled: option.disabled,
199
- mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
200
- placeholder: option.dataset.placeholder === 'true',
201
- class: option.className,
202
- style: option.style.cssText,
203
- data: option.dataset,
204
- } as Option
205
- }
206
-
207
218
  public setSelected(value: string[]): void {
208
219
  // Loop through options and set selected
209
220
  const options = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]
@@ -279,6 +290,12 @@ export default class Select {
279
290
  const optgroupEl = document.createElement('optgroup')
280
291
  optgroupEl.id = optgroup.id
281
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
+ }
282
299
  if (optgroup.options) {
283
300
  for (const o of optgroup.options) {
284
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