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.
- package/README.md +8 -0
- package/dist/render.d.ts +9 -2
- package/dist/select.d.ts +6 -6
- package/dist/settings.d.ts +0 -3
- package/dist/slimselect.cjs.js +148 -51
- package/dist/slimselect.css +1 -1
- package/dist/slimselect.css.map +1 -1
- package/dist/slimselect.es.js +148 -51
- package/dist/slimselect.global.js +148 -51
- package/dist/slimselect.js +148 -51
- package/dist/slimselect.min.js +1 -1
- package/dist/slimselect.umd.js +148 -51
- package/dist/slimselect.umd.min.js +1 -1
- package/dist/store.d.ts +5 -0
- package/docs/assets/data.js +7 -3
- package/docs/assets/home.css +1 -1
- package/docs/assets/home.js +1 -1
- package/docs/assets/index.css +1 -1
- package/docs/assets/index.js +7 -7
- package/docs/assets/index2.js +119 -35
- package/docs/assets/index3.js +22 -15
- package/docs/assets/index4.js +1 -1
- package/docs/assets/index5.js +4 -2
- package/docs/assets/install.js +4 -4
- package/docs/assets/selects.js +1 -1
- package/package.json +2 -2
- package/src/docs/app.vue +2 -1
- package/src/docs/pages/data.vue +4 -0
- package/src/docs/pages/events/search.vue +29 -15
- package/src/docs/pages/frameworks/vue.vue +3 -1
- package/src/docs/pages/home.vue +104 -57
- package/src/docs/pages/settings/closable.vue +128 -0
- package/src/docs/pages/settings/index.vue +6 -3
- package/src/docs/pages/settings/select_all.vue +88 -0
- package/src/slim-select/index.ts +3 -1
- package/src/slim-select/render.ts +164 -34
- package/src/slim-select/select.ts +35 -27
- package/src/slim-select/settings.ts +0 -4
- package/src/slim-select/slimselect.scss +112 -11
- package/src/slim-select/store.ts +19 -1
- package/src/vue/README.md +48 -0
- package/src/vue/dist/slimselectvue.es.js +148 -51
- package/src/vue/dist/slimselectvue.global.js +148 -51
- package/src/vue/dist/slimselectvue.ssr.js +148 -51
- package/src/vue/package.json +3 -2
- 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
|
+
<select ref="closable" multiple>
|
|
109
|
+
<optgroup label="Label 1" data-closable="off">
|
|
110
|
+
<option value="value1">Value 1</option>
|
|
111
|
+
<option value="value2">Value 2</option>
|
|
112
|
+
<option value="value3">Value 3</option>
|
|
113
|
+
</optgroup>
|
|
114
|
+
<optgroup label="Label 2" data-closable="open">
|
|
115
|
+
<option value="value4">Value 4</option>
|
|
116
|
+
<option value="value5">Value 5</option>
|
|
117
|
+
<option value="value6">Value 6</option>
|
|
118
|
+
</optgroup>
|
|
119
|
+
<optgroup label="Label 3" data-closable="close">
|
|
120
|
+
<option value="value7">Value 7</option>
|
|
121
|
+
<option value="value8">Value 8</option>
|
|
122
|
+
<option value="value9">Value 9</option>
|
|
123
|
+
</optgroup>
|
|
124
|
+
</select>
|
|
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
|
|
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
|
-
|
|
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
|
-
<
|
|
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
|
+
<select ref="selectAll" multiple>
|
|
74
|
+
<optgroup label="Label 1" data-selectall="true">
|
|
75
|
+
<option value="value1">Value 1</option>
|
|
76
|
+
<option value="value2">Value 2</option>
|
|
77
|
+
<option value="value3">Value 3</option>
|
|
78
|
+
</optgroup>
|
|
79
|
+
<optgroup label="Label 2">
|
|
80
|
+
<option value="value4">Value 4</option>
|
|
81
|
+
<option value="value5">Value 5</option>
|
|
82
|
+
<option value="value6">Value 6</option>
|
|
83
|
+
</optgroup>
|
|
84
|
+
</select>
|
|
85
|
+
</code>
|
|
86
|
+
</pre>
|
|
87
|
+
</div>
|
|
88
|
+
</template>
|
package/src/slim-select/index.ts
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
if (
|
|
843
|
-
|
|
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
|
|
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.
|
|
922
|
-
|
|
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
|
-
|
|
928
|
-
|
|
929
|
-
|
|
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.
|
|
1139
|
+
optionEl.classList.add(this.classes.selected)
|
|
1010
1140
|
} else {
|
|
1011
|
-
optionEl.classList.remove(this.classes.
|
|
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:
|
|
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:
|
|
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():
|
|
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):
|
|
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
|
|
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
|
|
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
|