slim-select 1.27.0 → 2.0.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/.nvmrc +1 -0
- package/.prettierrc +6 -0
- package/.vscode/extensions.json +3 -0
- package/.vscode/settings.json +15 -5
- package/README.md +2 -1
- package/dist/helper.d.ts +1 -4
- package/dist/index.d.ts +38 -58
- package/dist/render.d.ts +109 -0
- package/dist/select.d.ts +31 -20
- package/dist/settings.d.ts +33 -0
- package/dist/slimselect.cjs.js +2 -0
- package/dist/slimselect.cjs.js.map +1 -0
- package/dist/slimselect.css +1 -2
- package/dist/slimselect.css.map +1 -0
- package/dist/slimselect.es.js +2 -0
- package/dist/slimselect.es.js.map +1 -0
- package/dist/slimselect.global.js +2 -0
- package/dist/slimselect.global.js.map +1 -0
- package/dist/slimselect.js +2 -1956
- package/dist/slimselect.js.map +1 -0
- package/dist/slimselect.umd.js +2 -0
- package/dist/slimselect.umd.js.map +1 -0
- package/dist/store.d.ts +71 -0
- package/docs/assets/check-mark.svg +6 -0
- package/docs/assets/data.js +59 -0
- package/docs/assets/home.css +1 -0
- package/docs/assets/home.js +1 -0
- package/docs/assets/index.css +1 -0
- package/docs/assets/index.js +16 -0
- package/docs/assets/index2.js +274 -0
- package/docs/assets/index3.js +126 -0
- package/docs/assets/index4.js +60 -0
- package/docs/assets/install.js +34 -0
- package/docs/assets/selects.js +55 -0
- package/docs/index.html +18 -5
- package/docs.go +3 -1
- package/index.html +16 -0
- package/jest.config.js +7 -0
- package/package.json +39 -39
- package/src/docs/app.vue +185 -76
- package/src/docs/assets/scss/_variables.scss +26 -10
- package/src/docs/assets/scss/alert.scss +12 -0
- package/src/docs/assets/scss/animations.scss +5 -3
- package/src/docs/assets/scss/button.scss +21 -0
- package/src/docs/assets/scss/index.scss +8 -6
- package/src/docs/assets/scss/input.scss +2 -2
- package/src/docs/assets/scss/layout.scss +195 -65
- package/src/docs/assets/scss/misc.scss +144 -34
- package/src/docs/assets/scss/prism.scss +155 -153
- package/src/docs/env.d.ts +12 -0
- package/src/docs/images/check-mark.svg +6 -0
- package/src/docs/images/chrome.svg +22 -0
- package/src/docs/images/firefox.svg +58 -0
- package/src/docs/images/github.png +0 -0
- package/src/docs/images/ie.svg +11 -0
- package/src/docs/images/npm.png +0 -0
- package/src/docs/images/opera.svg +15 -0
- package/src/docs/images/safari.svg +22 -0
- package/src/docs/main.ts +27 -0
- package/src/docs/pages/data.vue +130 -0
- package/src/docs/pages/events/addable.vue +79 -0
- package/src/docs/pages/events/before_after_change.vue +140 -0
- package/src/docs/pages/events/before_after_open_close.vue +122 -0
- package/src/docs/pages/events/error.vue +59 -0
- package/src/docs/pages/events/index.vue +33 -0
- package/src/docs/pages/events/search.vue +154 -0
- package/src/docs/pages/events/search_filter.vue +45 -0
- package/src/docs/pages/home.vue +96 -116
- package/src/docs/pages/install.vue +47 -74
- package/src/docs/pages/methods/destroy.vue +66 -0
- package/src/docs/pages/methods/enable_disable.vue +70 -0
- package/src/docs/pages/methods/get_data.vue +81 -0
- package/src/docs/pages/methods/get_selected.vue +78 -0
- package/src/docs/pages/methods/index.vue +36 -0
- package/src/docs/pages/methods/open_close.vue +63 -0
- package/src/docs/pages/methods/search.vue +62 -0
- package/src/docs/pages/methods/set_data.vue +106 -0
- package/src/docs/pages/methods/set_selected.vue +70 -0
- package/src/docs/pages/selects.vue +108 -114
- package/src/docs/pages/settings/always_open.vue +88 -0
- package/src/docs/pages/settings/close_on_select.vue +69 -0
- package/src/docs/pages/settings/content_location.vue +64 -0
- package/src/docs/pages/settings/content_position.vue +86 -0
- package/src/docs/pages/settings/css.vue +73 -0
- package/src/docs/pages/settings/data_attributes.vue +39 -0
- package/src/docs/pages/settings/deselect.vue +69 -0
- package/src/docs/pages/settings/display.vue +88 -0
- package/src/docs/pages/settings/hide_selected.vue +73 -0
- package/src/docs/pages/settings/html.vue +86 -0
- package/src/docs/pages/settings/index.vue +73 -0
- package/src/docs/pages/settings/mandatory.vue +91 -0
- package/src/docs/pages/settings/min_max.vue +61 -0
- package/src/docs/pages/settings/open_position.vue +60 -0
- package/src/docs/pages/settings/placeholder.vue +72 -0
- package/src/docs/pages/settings/search.vue +140 -0
- package/src/docs/pages/settings/select.vue +32 -0
- package/src/docs/pages/settings/select_by_group.vue +46 -0
- package/src/docs/pages/settings/show_tooltip.vue +44 -0
- package/src/docs/pages/settings/styles.vue +51 -0
- package/src/docs/router.ts +41 -13
- package/src/slim-select/helper.ts +25 -86
- package/src/slim-select/index.ts +318 -413
- package/src/slim-select/render.test.ts +39 -0
- package/src/slim-select/render.ts +1129 -0
- package/src/slim-select/rollup.config.mjs +39 -0
- package/src/slim-select/select.test.ts +155 -0
- package/src/slim-select/select.ts +280 -107
- package/src/slim-select/settings.ts +68 -0
- package/src/slim-select/slimselect.scss +263 -278
- package/src/slim-select/store.test.ts +220 -0
- package/src/slim-select/store.ts +320 -0
- package/src/slim-select/tsconfig.json +11 -5
- package/src/vue/slimselect.vue +61 -0
- package/tsconfig.json +10 -29
- package/vite.config.ts +18 -0
- package/.browserslistrc +0 -4
- package/.postcssrc.js +0 -5
- package/.travis.yml +0 -22
- package/babel.config.js +0 -5
- package/dist/config.d.ts +0 -83
- package/dist/data.d.ts +0 -50
- package/dist/slim.d.ts +0 -50
- package/dist/slimselect.min.css +0 -1
- package/dist/slimselect.min.js +0 -1
- package/dist/slimselect.min.mjs +0 -1
- package/docs/css/app.d5840d21.css +0 -1
- package/docs/css/chunk-vendors.4db6930d.css +0 -1
- package/docs/css/home.57020178.css +0 -1
- package/docs/css/install.baa5d3fb.css +0 -1
- package/docs/css/methods.728c742a.css +0 -1
- package/docs/css/options.b28a32ef.css +0 -1
- package/docs/css/selects.1a7e1e6a.css +0 -1
- package/docs/js/app.db13c724.js +0 -2
- package/docs/js/app.db13c724.js.map +0 -1
- package/docs/js/chunk-vendors.cc40aa28.js +0 -28
- package/docs/js/chunk-vendors.cc40aa28.js.map +0 -1
- package/docs/js/home.8bcb44fd.js +0 -2
- package/docs/js/home.8bcb44fd.js.map +0 -1
- package/docs/js/install.02f31028.js +0 -2
- package/docs/js/install.02f31028.js.map +0 -1
- package/docs/js/methods.1b31e988.js +0 -11
- package/docs/js/methods.1b31e988.js.map +0 -1
- package/docs/js/options.39fe1005.js +0 -2
- package/docs/js/options.39fe1005.js.map +0 -1
- package/docs/js/selects.f4d0b859.js +0 -2
- package/docs/js/selects.f4d0b859.js.map +0 -1
- package/src/docs/pages/methods.vue +0 -427
- package/src/docs/pages/options.vue +0 -1480
- package/src/main.ts +0 -29
- package/src/shims-vue.d.ts +0 -8
- package/src/slim-select/config.ts +0 -118
- package/src/slim-select/data.ts +0 -377
- package/src/slim-select/slim.ts +0 -770
- package/tslint.json +0 -26
- package/vue.config.js +0 -23
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import typescript from '@rollup/plugin-typescript'
|
|
2
|
+
import { terser } from 'rollup-plugin-terser'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
input: './index.ts',
|
|
6
|
+
output: [
|
|
7
|
+
{
|
|
8
|
+
name: 'SlimSelect',
|
|
9
|
+
file: '../../dist/slimselect.js',
|
|
10
|
+
format: 'es',
|
|
11
|
+
sourcemap: true,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'SlimSelect',
|
|
15
|
+
file: '../../dist/slimselect.es.js',
|
|
16
|
+
format: 'es',
|
|
17
|
+
sourcemap: true,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'SlimSelect',
|
|
21
|
+
file: '../../dist/slimselect.cjs.js',
|
|
22
|
+
format: 'cjs',
|
|
23
|
+
sourcemap: true,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'SlimSelect',
|
|
27
|
+
file: '../../dist/slimselect.global.js',
|
|
28
|
+
format: 'iife',
|
|
29
|
+
sourcemap: true,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'SlimSelect',
|
|
33
|
+
file: '../../dist/slimselect.umd.js',
|
|
34
|
+
format: 'umd',
|
|
35
|
+
sourcemap: true,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
plugins: [typescript(), terser()],
|
|
39
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict'
|
|
6
|
+
|
|
7
|
+
import { describe, expect, test } from '@jest/globals'
|
|
8
|
+
import Select from './select'
|
|
9
|
+
import Store, { Optgroup, Option } from './store'
|
|
10
|
+
|
|
11
|
+
describe('select module', () => {
|
|
12
|
+
test('constructor', () => {
|
|
13
|
+
document.body.innerHTML = '<select id="test"></select>'
|
|
14
|
+
|
|
15
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
16
|
+
let select = new Select(selectElement)
|
|
17
|
+
expect(select).toBeInstanceOf(Select)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('get data from select options', () => {
|
|
21
|
+
document.body.innerHTML = `<select id="test">
|
|
22
|
+
<option value="1">One</option>
|
|
23
|
+
<option value="2">Two</option>
|
|
24
|
+
</select>`
|
|
25
|
+
|
|
26
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
27
|
+
let select = new Select(selectElement)
|
|
28
|
+
let data = select.getData() as Option[]
|
|
29
|
+
expect(data.length).toBe(2)
|
|
30
|
+
expect(data[0].value).toBe('1')
|
|
31
|
+
expect(data[0].text).toBe('One')
|
|
32
|
+
expect(data[1].value).toBe('2')
|
|
33
|
+
expect(data[1].text).toBe('Two')
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('get data from select optgroups', () => {
|
|
37
|
+
document.body.innerHTML = `<select id="test">
|
|
38
|
+
<optgroup label="test1">
|
|
39
|
+
<option value="1">One</option>
|
|
40
|
+
<option value="2">Two</option>
|
|
41
|
+
</optgroup>
|
|
42
|
+
<optgroup label="test2">
|
|
43
|
+
<option value="3">Three</option>
|
|
44
|
+
<option value="4">Four</option>
|
|
45
|
+
<option value="5">Five</option>
|
|
46
|
+
</optgroup>
|
|
47
|
+
</select>`
|
|
48
|
+
|
|
49
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
50
|
+
let select = new Select(selectElement)
|
|
51
|
+
let data = select.getData() as Optgroup[]
|
|
52
|
+
expect(data.length).toBe(2)
|
|
53
|
+
expect(data[0].label).toBe('test1')
|
|
54
|
+
expect(data[0].options.length).toBe(2)
|
|
55
|
+
expect(data[0].options[0].value).toBe('1')
|
|
56
|
+
expect(data[0].options[0].text).toBe('One')
|
|
57
|
+
expect(data[0].options[1].value).toBe('2')
|
|
58
|
+
expect(data[0].options[1].text).toBe('Two')
|
|
59
|
+
expect(data[1].label).toBe('test2')
|
|
60
|
+
expect(data[1].options.length).toBe(3)
|
|
61
|
+
expect(data[1].options[0].value).toBe('3')
|
|
62
|
+
expect(data[1].options[0].text).toBe('Three')
|
|
63
|
+
expect(data[1].options[1].value).toBe('4')
|
|
64
|
+
expect(data[1].options[1].text).toBe('Four')
|
|
65
|
+
expect(data[1].options[2].value).toBe('5')
|
|
66
|
+
expect(data[1].options[2].text).toBe('Five')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('update select from data', () => {
|
|
70
|
+
document.body.innerHTML = '<select id="test"></select>'
|
|
71
|
+
|
|
72
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
73
|
+
let select = new Select(selectElement)
|
|
74
|
+
let store = new Store('single', [
|
|
75
|
+
{
|
|
76
|
+
id: '1',
|
|
77
|
+
value: '1',
|
|
78
|
+
text: 'One',
|
|
79
|
+
selected: false,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: '2',
|
|
83
|
+
value: '2',
|
|
84
|
+
text: 'Two',
|
|
85
|
+
selected: false,
|
|
86
|
+
},
|
|
87
|
+
])
|
|
88
|
+
let data = store.getData()
|
|
89
|
+
select.updateOptions(data)
|
|
90
|
+
|
|
91
|
+
expect(selectElement.innerHTML).toBe('<option value="1">One</option><option value="2">Two</option>')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('event change value listener', () => {
|
|
95
|
+
document.body.innerHTML = `<select id="test">
|
|
96
|
+
<option value="1">One</option>
|
|
97
|
+
<option value="2">Two</option>
|
|
98
|
+
<option value="3">Three</option>
|
|
99
|
+
</select>`
|
|
100
|
+
|
|
101
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
102
|
+
let select = new Select(selectElement)
|
|
103
|
+
|
|
104
|
+
let data = select.getData() as Option[]
|
|
105
|
+
|
|
106
|
+
expect(data[0].selected).toBe(true)
|
|
107
|
+
|
|
108
|
+
let didChange = false
|
|
109
|
+
select.addValueChangeListener(() => {
|
|
110
|
+
didChange = true
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
selectElement.value = '2'
|
|
114
|
+
|
|
115
|
+
data = select.getData() as Option[]
|
|
116
|
+
|
|
117
|
+
expect(data[1].selected).toBe(true)
|
|
118
|
+
|
|
119
|
+
// Give the mutation observer time to run
|
|
120
|
+
setTimeout(() => {
|
|
121
|
+
expect(didChange).toBe(true)
|
|
122
|
+
}, 100)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test('mutation observer listener', () => {
|
|
126
|
+
document.body.innerHTML = `<select id="test">
|
|
127
|
+
<option value="1">One</option>
|
|
128
|
+
<option value="2">Two</option>
|
|
129
|
+
<option value="3">Three</option>
|
|
130
|
+
</select>`
|
|
131
|
+
|
|
132
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
133
|
+
let select = new Select(selectElement)
|
|
134
|
+
|
|
135
|
+
let data = select.getData() as Option[]
|
|
136
|
+
|
|
137
|
+
expect(data.length).toBe(3)
|
|
138
|
+
|
|
139
|
+
let didChange = false
|
|
140
|
+
select.addSelectChangeListener(() => {
|
|
141
|
+
didChange = true
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
selectElement.innerHTML = '<option value="1">One</option><option value="2">Two</option>'
|
|
145
|
+
|
|
146
|
+
data = select.getData() as Option[]
|
|
147
|
+
|
|
148
|
+
expect(data.length).toBe(2)
|
|
149
|
+
|
|
150
|
+
// Give the mutation observer time to run
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
expect(didChange).toBe(true)
|
|
153
|
+
}, 100)
|
|
154
|
+
})
|
|
155
|
+
})
|
|
@@ -1,148 +1,311 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { kebabCase } from './helper'
|
|
1
|
+
import { generateID, kebabCase } from './helper'
|
|
2
|
+
import { DataArray, DataObject, Optgroup, Option } from './store'
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
select: HTMLSelectElement
|
|
7
|
-
|
|
8
|
-
}
|
|
4
|
+
export default class Select {
|
|
5
|
+
public select: HTMLSelectElement
|
|
6
|
+
public listen: boolean = false
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
public
|
|
12
|
-
public
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
constructor(
|
|
16
|
-
this.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
8
|
+
// Mutation observer fields
|
|
9
|
+
public onSelectChange?: (data: DataArray) => void
|
|
10
|
+
public onValueChange?: (value: string[]) => void
|
|
11
|
+
private observer: MutationObserver | null = null
|
|
12
|
+
|
|
13
|
+
constructor(select: HTMLSelectElement) {
|
|
14
|
+
this.select = select
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Set to enabled
|
|
18
|
+
public enable(): void {
|
|
19
|
+
// Disable original select but dont trigger observer
|
|
20
|
+
this.disconnectObserver()
|
|
21
|
+
this.select.disabled = false
|
|
22
|
+
this.connectObserver()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Set to disabled
|
|
26
|
+
public disable(): void {
|
|
27
|
+
// Enable original select but dont trigger observer
|
|
28
|
+
this.disconnectObserver()
|
|
29
|
+
this.select.disabled = true
|
|
30
|
+
this.connectObserver()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Set misc attributes on the main select element
|
|
34
|
+
public hideUI(): void {
|
|
35
|
+
this.select.tabIndex = -1
|
|
36
|
+
this.select.style.display = 'none'
|
|
37
|
+
this.select.setAttribute('aria-hidden', 'true')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public showUI(): void {
|
|
41
|
+
this.select.removeAttribute('tabindex')
|
|
42
|
+
this.select.style.display = ''
|
|
43
|
+
this.select.removeAttribute('aria-hidden')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public changeListen(on: boolean) {
|
|
47
|
+
this.listen = on
|
|
48
|
+
|
|
49
|
+
// Deal with some observer situations
|
|
50
|
+
if (this.listen) {
|
|
51
|
+
this.connectObserver()
|
|
47
52
|
} else {
|
|
48
|
-
|
|
49
|
-
const selected = this.main.data.getSelected() as any
|
|
50
|
-
this.element.value = (selected ? selected.value : '')
|
|
53
|
+
this.disconnectObserver()
|
|
51
54
|
}
|
|
55
|
+
}
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
57
|
+
// Add change listener to original select
|
|
58
|
+
public addSelectChangeListener(func: (data: DataArray) => void): void {
|
|
59
|
+
this.onSelectChange = func
|
|
60
|
+
this.addObserver()
|
|
61
|
+
this.connectObserver()
|
|
62
|
+
this.changeListen(true) // Last start listening
|
|
57
63
|
}
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.
|
|
65
|
+
// remove change listener from original select
|
|
66
|
+
public removeSelectChangeListener(): void {
|
|
67
|
+
this.changeListen(false) // First stop listening
|
|
68
|
+
this.onSelectChange = undefined
|
|
69
|
+
}
|
|
62
70
|
|
|
63
|
-
|
|
64
|
-
this.
|
|
71
|
+
public addValueChangeListener(func: (value: string[]) => void): void {
|
|
72
|
+
this.onValueChange = func
|
|
73
|
+
this.select.addEventListener('change', this.valueChange.bind(this))
|
|
65
74
|
}
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
public removeValueChangeListener(): void {
|
|
77
|
+
this.onValueChange = undefined
|
|
78
|
+
this.select.removeEventListener('change', this.valueChange.bind(this))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public valueChange(ev: Event): any {
|
|
82
|
+
if (this.onValueChange) {
|
|
83
|
+
this.onValueChange(this.getSelectedValues())
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private observeWrapper(mutations: MutationRecord[]): void {
|
|
88
|
+
if (this.onSelectChange) {
|
|
89
|
+
this.onSelectChange(this.getData())
|
|
90
|
+
}
|
|
73
91
|
}
|
|
74
92
|
|
|
75
93
|
// Add MutationObserver to select
|
|
76
|
-
|
|
77
|
-
//
|
|
78
|
-
if (this.
|
|
94
|
+
private addObserver(): void {
|
|
95
|
+
// If mutation observer already exists then disconnect and
|
|
96
|
+
if (this.observer) {
|
|
97
|
+
this.disconnectObserver()
|
|
98
|
+
this.observer = null
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// If anything changes in the select then update the data
|
|
102
|
+
this.observer = new MutationObserver(this.observeWrapper)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private connectObserver(): void {
|
|
106
|
+
if (this.observer) {
|
|
107
|
+
this.observer.observe(this.select, {
|
|
108
|
+
attributes: true,
|
|
109
|
+
childList: true,
|
|
110
|
+
characterData: true,
|
|
111
|
+
subtree: true,
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private disconnectObserver(): void {
|
|
117
|
+
if (this.observer) {
|
|
118
|
+
this.observer.disconnect()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// From the select element pull optgroup and options into data
|
|
123
|
+
public getData(): DataArray {
|
|
124
|
+
let data = []
|
|
125
|
+
|
|
126
|
+
// Loop through nodes and get data
|
|
127
|
+
const nodes = this.select.childNodes as any as HTMLOptGroupElement[] | HTMLOptionElement[]
|
|
128
|
+
for (const n of nodes) {
|
|
129
|
+
// Optgroup
|
|
130
|
+
if (n.nodeName === 'OPTGROUP') {
|
|
131
|
+
data.push(this.getDataFromOptgroup(n as HTMLOptGroupElement))
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Option
|
|
135
|
+
if (n.nodeName === 'OPTION') {
|
|
136
|
+
data.push(this.getDataFromOption(n as HTMLOptionElement))
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return data
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public getDataFromOptgroup(optgroup: HTMLOptGroupElement): Optgroup {
|
|
144
|
+
let data = {
|
|
145
|
+
id: '',
|
|
146
|
+
label: optgroup.label,
|
|
147
|
+
options: [],
|
|
148
|
+
} as Optgroup
|
|
79
149
|
|
|
80
|
-
|
|
81
|
-
|
|
150
|
+
const options = optgroup.childNodes as any as HTMLOptionElement[]
|
|
151
|
+
for (const o of options) {
|
|
152
|
+
if (o.nodeName === 'OPTION') {
|
|
153
|
+
data.options.push(this.getDataFromOption(o as HTMLOptionElement))
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return data
|
|
158
|
+
}
|
|
82
159
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.main.render()
|
|
160
|
+
public getSelectedValues(): string[] {
|
|
161
|
+
let values = []
|
|
86
162
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
163
|
+
// Loop through options and set selected
|
|
164
|
+
const options = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]
|
|
165
|
+
for (const o of options) {
|
|
166
|
+
if (o.nodeName === 'OPTGROUP') {
|
|
167
|
+
const optgroupOptions = o.childNodes as any as HTMLOptionElement[]
|
|
168
|
+
for (const oo of optgroupOptions) {
|
|
169
|
+
if (oo.nodeName === 'OPTION') {
|
|
170
|
+
const option = oo as HTMLOptionElement
|
|
171
|
+
if (option.selected) {
|
|
172
|
+
values.push(option.value)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
90
175
|
}
|
|
91
|
-
}
|
|
92
|
-
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (o.nodeName === 'OPTION') {
|
|
179
|
+
const option = o as HTMLOptionElement
|
|
180
|
+
if (option.selected) {
|
|
181
|
+
values.push(option.value)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
93
185
|
|
|
94
|
-
|
|
186
|
+
return values
|
|
95
187
|
}
|
|
96
188
|
|
|
97
|
-
|
|
98
|
-
|
|
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
|
+
public setSelected(value: string[]): void {
|
|
208
|
+
// Loop through options and set selected
|
|
209
|
+
const options = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]
|
|
210
|
+
for (const o of options) {
|
|
211
|
+
if (o.nodeName === 'OPTGROUP') {
|
|
212
|
+
const optgroup = o as HTMLOptGroupElement
|
|
213
|
+
const optgroupOptions = optgroup.childNodes as any as HTMLOptionElement[]
|
|
214
|
+
for (const oo of optgroupOptions) {
|
|
215
|
+
if (oo.nodeName === 'OPTION') {
|
|
216
|
+
const option = oo as HTMLOptionElement
|
|
217
|
+
option.selected = value.includes(option.value)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
99
221
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
222
|
+
if (o.nodeName === 'OPTION') {
|
|
223
|
+
const option = o as HTMLOptionElement
|
|
224
|
+
option.selected = value.includes(option.value)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
105
227
|
}
|
|
106
228
|
|
|
107
|
-
public
|
|
108
|
-
|
|
109
|
-
|
|
229
|
+
public updateSelect(id?: string, style?: string, classes?: string[]): void {
|
|
230
|
+
// Stop listening to changes
|
|
231
|
+
this.changeListen(false)
|
|
232
|
+
|
|
233
|
+
// Update id
|
|
234
|
+
if (id) {
|
|
235
|
+
this.select.id = id
|
|
110
236
|
}
|
|
237
|
+
|
|
238
|
+
// Update style
|
|
239
|
+
if (style) {
|
|
240
|
+
this.select.style.cssText = style
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Update classes
|
|
244
|
+
if (classes) {
|
|
245
|
+
this.select.className = ''
|
|
246
|
+
classes.forEach((c) => {
|
|
247
|
+
if (c.trim() !== '') {
|
|
248
|
+
this.select.classList.add(c.trim())
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Start listening to changes
|
|
254
|
+
this.changeListen(true)
|
|
111
255
|
}
|
|
112
256
|
|
|
113
|
-
|
|
114
|
-
|
|
257
|
+
public updateOptions(data: DataArray): void {
|
|
258
|
+
// Stop listening to changes
|
|
259
|
+
this.changeListen(false)
|
|
260
|
+
|
|
115
261
|
// Clear out select
|
|
116
|
-
this.
|
|
262
|
+
this.select.innerHTML = ''
|
|
117
263
|
|
|
118
264
|
for (const d of data) {
|
|
119
|
-
if (d
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
optgroupEl.appendChild(this.createOption(oo))
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
this.element.appendChild(optgroupEl)
|
|
129
|
-
} else {
|
|
130
|
-
this.element.appendChild(this.createOption(d))
|
|
265
|
+
if (d instanceof Optgroup) {
|
|
266
|
+
this.select.appendChild(this.createOptgroup(d))
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (d instanceof Option) {
|
|
270
|
+
this.select.appendChild(this.createOption(d))
|
|
131
271
|
}
|
|
132
272
|
}
|
|
273
|
+
|
|
274
|
+
// Start listening to changes
|
|
275
|
+
this.changeListen(true)
|
|
133
276
|
}
|
|
134
277
|
|
|
135
|
-
public
|
|
278
|
+
public createOptgroup(optgroup: Optgroup): HTMLOptGroupElement {
|
|
279
|
+
const optgroupEl = document.createElement('optgroup')
|
|
280
|
+
optgroupEl.id = optgroup.id
|
|
281
|
+
optgroupEl.label = optgroup.label
|
|
282
|
+
if (optgroup.options) {
|
|
283
|
+
for (const o of optgroup.options) {
|
|
284
|
+
optgroupEl.appendChild(this.createOption(o))
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return optgroupEl
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
public createOption(info: Option): HTMLOptionElement {
|
|
136
291
|
const optionEl = document.createElement('option')
|
|
137
292
|
optionEl.value = info.value !== '' ? info.value : info.text
|
|
138
|
-
optionEl.innerHTML = info.
|
|
139
|
-
if (info.selected) {
|
|
293
|
+
optionEl.innerHTML = info.html || info.text
|
|
294
|
+
if (info.selected) {
|
|
295
|
+
optionEl.selected = info.selected
|
|
296
|
+
}
|
|
297
|
+
if (info.disabled) {
|
|
298
|
+
optionEl.disabled = true
|
|
299
|
+
}
|
|
140
300
|
if (info.display === false) {
|
|
141
301
|
optionEl.style.display = 'none'
|
|
142
302
|
}
|
|
143
|
-
if (info.
|
|
144
|
-
|
|
145
|
-
|
|
303
|
+
if (info.placeholder) {
|
|
304
|
+
optionEl.setAttribute('data-placeholder', 'true')
|
|
305
|
+
}
|
|
306
|
+
if (info.mandatory) {
|
|
307
|
+
optionEl.setAttribute('data-mandatory', 'true')
|
|
308
|
+
}
|
|
146
309
|
if (info.class) {
|
|
147
310
|
info.class.split(' ').forEach((optionClass: string) => {
|
|
148
311
|
optionEl.classList.add(optionClass)
|
|
@@ -156,4 +319,14 @@ export class Select {
|
|
|
156
319
|
|
|
157
320
|
return optionEl
|
|
158
321
|
}
|
|
322
|
+
|
|
323
|
+
public destroy() {
|
|
324
|
+
this.changeListen(false)
|
|
325
|
+
this.disconnectObserver()
|
|
326
|
+
this.removeSelectChangeListener()
|
|
327
|
+
this.removeValueChangeListener()
|
|
328
|
+
|
|
329
|
+
// show the original select
|
|
330
|
+
this.showUI()
|
|
331
|
+
}
|
|
159
332
|
}
|