selectic 3.0.18 → 3.0.20
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/.tool-versions +5 -0
- package/README.md +42 -27
- package/dist/selectic.common.js +163 -31
- package/dist/selectic.esm.js +163 -31
- package/doc/changeText.md +10 -8
- package/doc/css.md +1 -1
- package/doc/domProperties.md +7 -7
- package/doc/dynamic.md +11 -11
- package/doc/extendedProperties.md +12 -12
- package/doc/images/example1.png +0 -0
- package/doc/images/example2.png +0 -0
- package/doc/images/selectic_example.png +0 -0
- package/doc/list.md +28 -15
- package/doc/methods.md +2 -2
- package/doc/params.md +56 -56
- package/package.json +2 -2
- package/src/ExtendedList.tsx +54 -16
- package/src/MainInput.tsx +66 -7
- package/src/Store.tsx +36 -12
- package/src/css/selectic.css +8 -0
- package/src/tools.ts +31 -0
- package/test/Store/Store_creation.spec.js +1 -1
- package/test/Store/commit.spec.js +180 -0
- package/test/helper.js +10 -2
- package/types/ExtendedList.d.ts +4 -0
- package/types/MainInput.d.ts +7 -1
- package/types/Store.d.ts +1 -0
- package/types/tools.d.ts +5 -0
package/.tool-versions
ADDED
package/README.md
CHANGED
|
@@ -12,51 +12,66 @@ reverse selection, and many other possibilities.
|
|
|
12
12
|
|
|
13
13
|
It integrates well with VueJS and is reactive to option changes.
|
|
14
14
|
|
|
15
|
+
Typescript types are provided.
|
|
16
|
+
|
|
15
17
|
There are very few dependencies and code stays very small (~90kB).
|
|
16
18
|
|
|
19
|
+

|
|
20
|
+
|
|
17
21
|
## Example
|
|
18
22
|
|
|
19
23
|
```html
|
|
20
24
|
<Selectic
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
:options="['first choice', 'second choice', 'third choice']"
|
|
26
|
+
v-model="selection"
|
|
23
27
|
/>
|
|
24
28
|
|
|
25
29
|
<Selectic
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
30
|
+
multiple
|
|
31
|
+
value="item2"
|
|
32
|
+
:options="[{
|
|
33
|
+
id: 'item1',
|
|
34
|
+
text: 'The first item',
|
|
35
|
+
icon: 'fa fa-thumbs-o-up',
|
|
36
|
+
}, {
|
|
37
|
+
id: 'item2',
|
|
38
|
+
text: 'Another item',
|
|
39
|
+
title: 'second choice',
|
|
40
|
+
}, {
|
|
41
|
+
id: 'item3',
|
|
42
|
+
text: 'Disabled item',
|
|
43
|
+
disabled: true,
|
|
44
|
+
}]"
|
|
45
|
+
|
|
46
|
+
@input="onChange"
|
|
43
47
|
/>
|
|
44
48
|
|
|
45
|
-
<Selectic
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
<Selectic
|
|
50
|
+
:options="[{
|
|
51
|
+
id: 'animals',
|
|
52
|
+
text: 'Animals',
|
|
53
|
+
options: [{
|
|
54
|
+
id: 'cat',
|
|
55
|
+
text: 'Cat',
|
|
56
|
+
}, {
|
|
57
|
+
id: 'dog',
|
|
58
|
+
text: 'A dog',
|
|
59
|
+
}, {
|
|
60
|
+
id: 42,
|
|
61
|
+
text: '42 goldfishes',
|
|
62
|
+
}],
|
|
63
|
+
}]"
|
|
64
|
+
/>
|
|
52
65
|
```
|
|
53
66
|
|
|
67
|
+
[Full documentation](./doc/main.md)
|
|
68
|
+
|
|
54
69
|
## Features
|
|
55
70
|
|
|
56
71
|
* List of items (either string array or object array).
|
|
57
72
|
* Can load dynamically list from a server and the list can be paginate (with a
|
|
58
73
|
cache system to avoid reloading previous requests).
|
|
59
|
-
* Slots: options may be added from Vue template (by writing explicit `<option>` or `<optgroup>`) in a reactive way _(currently disabled in 3.0.0)_.
|
|
74
|
+
* ~~Slots: options may be added from Vue template (by writing explicit `<option>` or `<optgroup>`) in a reactive way~~ _(currently disabled in 3.0.0+)_.
|
|
60
75
|
* Multi-sources: Possibility to combine options from different sources (static, dynamic or slots) or to use the other as fallback (if the list is empty).
|
|
61
76
|
* Supports basic Select properties like `multiple`, `disabled`, `title`
|
|
62
77
|
* Supports group element (equivalent of optGroup), even for dynamic list.
|
package/dist/selectic.common.js
CHANGED
|
@@ -32,7 +32,7 @@ function styleInject(css, ref) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
var css_248z = "/* {{{ Variables */\n\n:root {\n --selectic-font-size: 14px;\n --selectic-cursor-disabled: not-allowed;\n\n /* The main element */\n --selectic-color: #555555;\n --selectic-bg: #ffffff;\n\n /* The main element (when disabled) */\n --selectic-color-disabled: #787878;\n --selectic-bg-disabled: #eeeeee;\n\n /* The list */\n --selectic-panel-bg: #f0f0f0;\n --selectic-separator-bordercolor: #cccccc;\n /* --selectic-item-color: var(--selectic-color); /* Can be set in any CSS configuration */\n\n /* The current selected item */\n --selectic-selected-item-color: #428bca;\n\n /* When mouse is over items or by selecting with key arrows */\n --selectic-active-item-color: #ffffff;\n --selectic-active-item-bg: #66afe9;\n\n /* Selected values in main element */\n --selectic-value-bg: #f0f0f0;\n /* --selectic-more-items-bg: var(--selectic-info-bg); /* can be set in any CSS configuration */\n /* --selectic-more-items-color: var(--selectic-info-color); /* can be set in any CSS configuration */\n --selectic-more-items-bg-disabled: #cccccc;\n\n /* Information message */\n --selectic-info-bg: #5bc0de;\n --selectic-info-color: #ffffff;\n\n /* Error message */\n --selectic-error-bg: #b72c29;\n --selectic-error-color: #ffffff;\n\n /* XXX: Currently it is important to keep this size for a correct scroll\n * height estimation */\n --selectic-input-height: 30px;\n}\n\n/* }}} */\n/* {{{ Bootstrap equivalent style */\n\n.selectic .form-control {\n display: block;\n width: 100%;\n height: calc(var(--selectic-input-height) - 2px);\n font-size: var(--selectic-font-size);\n line-height: 1.42857143;\n color: var(--selectic-color);\n background-color: var(--selectic-bg);\n background-image: none;\n border: 1px solid var(--selectic-separator-bordercolor); /* should use a better variable */\n border-radius: 4px;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n}\n.selectic .has-feedback {\n position: relative;\n}\n.selectic .has-feedback .form-control {\n padding-right: calc(var(--selectic-input-height) + 4px);\n}\n\n.selectic .form-control-feedback.fa,\n.selectic .form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: calc(var(--selectic-input-height) + 4px);\n height: calc(var(--selectic-input-height) + 4px);\n line-height: var(--selectic-input-height);\n text-align: center;\n pointer-events: none;\n}\n\n.selectic .alert-info {\n background-color: var(--selectic-info-bg);\n color: var(--selectic-info-color);\n}\n\n.selectic .alert-danger {\n background-color: var(--selectic-error-bg);\n color: var(--selectic-error-color);\n}\n\n/* }}} */\n\n.selectic * {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.selectic.form-control {\n display: inline-block;\n padding: 0;\n cursor: pointer;\n border: unset;\n}\n\n.has-feedback .selectic__icon-container.form-control-feedback {\n right: 0;\n}\n\n/* The input which contains the selected value\n * XXX: This input should stay hidden behind other elements, but is \"visible\"\n * (in term of DOM point of view) in order to get and to trigger the `focus`\n * DOM event. */\n.selectic__input-value {\n position: fixed;\n opacity: 0;\n z-index: -1000;\n top: -100px;\n}\n\n/* XXX: .form-control has been added to this selector to improve priority and\n * override some rules of the original .form-control */\n.selectic-input.form-control {\n display: inline-flex;\n justify-content: space-between;\n overflow: hidden;\n width: 100%;\n min-height: var(--selectic-input-height);\n padding-top: 0;\n padding-bottom: 0;\n padding-left: 5px;\n line-height: calc(var(--selectic-input-height) - 4px);\n color: var(--selectic-color);\n}\n\n.selectic-input__reverse-icon {\n align-self: center;\n margin-right: 3px;\n cursor: default;\n}\n.selectic-input__clear-icon {\n align-self: center;\n margin-left: 3px;\n cursor: pointer;\n}\n.selectic-input__clear-icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic-input.focused {\n border-bottom-left-radius: 0px;\n border-bottom-right-radius: 0px;\n}\n\n.selectic-input.disabled {\n cursor: var(--selectic-cursor-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n.selectic-input.disabled .more-items {\n\tbackground-color: var(--selectic-more-items-bg-disabled);\n}\n\n.selectic-input__selected-items {\n display: inline-flex;\n flex-wrap: nowrap;\n align-items: center;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__placeholder {\n font-style: italic;\n opacity: 0.7;\n white-space: nowrap;\n}\n\n.selectic-icon {\n color: var(--selectic-color);\n text-align: center;\n vertical-align: middle;\n}\n\n.selectic__extended-list {\n position: fixed;\n z-index: 2000;\n height: auto;\n background-color: var(--selectic-bg, #ffffff);\n box-shadow: 2px 5px 12px 0px #888888;\n border-radius: 0 0 4px 4px;\n padding: 0;\n min-width: 200px;\n}\n.selectic__extended-list__list-container{\n overflow: auto;\n}\n.selectic__extended-list__list-items {\n max-height: calc(var(--selectic-input-height) * 10);\n min-width: max-content;\n padding-left: 0;\n}\n\n.selectic-item {\n display: block;\n position: relative;\n box-sizing: border-box;\n padding: 2px 8px;\n color: var(--selectic-item-color, var(--selectic-color));\n min-height: calc(var(--selectic-input-height) - 3px);\n list-style-type: none;\n white-space: nowrap;\n cursor: pointer;\n}\n\n.selectic-item_text {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.selectic-item:not(.selected) .selectic-item_icon {\n opacity: 0;\n}\n\n.selectic-item_text {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.selectic-item__active {\n background-color: var(--selectic-active-item-bg);\n color: var(--selectic-active-item-color);\n}\n.selectic-item__active:not(.selected) .selectic-item_icon {\n opacity: 0.2;\n}\n\n.selectic-item__disabled {\n color: var(--selectic-color-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n\n.selectic-item__is-in-group {\n padding-left: 2em;\n}\n\n.selectic-item__is-group {\n font-weight: bold;\n cursor: default;\n}\n\n.selectic-item.selected {\n color: var(--selectic-selected-item-color);\n}\n.selectic-search-scope {\n color: #e0e0e0;\n left: auto;\n right: 10px;\n}\n.selectic .form-control-feedback.fa.selectic-search-scope {\n width: calc(var(--selectic-input-height) * 0.75);\n height: calc(var(--selectic-input-height) * 0.75);\n line-height: calc(var(--selectic-input-height) * 0.75);\n}\n\n.selectic__message {\n text-align: center;\n padding: 3px;\n}\n\n.selectic .filter-panel {\n padding: 3px;\n margin-left: 0px;\n margin-right: 0px;\n background-color: var(--selectic-panel-bg);\n border-bottom: 1px solid var(--selectic-separator-bordercolor);\n}\n\n.selectic .panelclosed {\n max-height: 0px;\n transition: max-height 0.3s ease-out;\n overflow: hidden;\n}\n\n.panelopened {\n max-height: 200px;\n transition: max-height 0.3s ease-in;\n overflow: hidden;\n}\n\n.selectic .filter-panel__input {\n padding-left: 0px;\n padding-right: 0px;\n padding-bottom: 10px;\n margin-bottom: 0px;\n}\n.selectic .filter-input {\n height: calc(var(--selectic-input-height) * 0.75);\n}\n\n.selectic .checkbox-filter {\n padding: 5px;\n text-align: center;\n}\n\n.selectic .curtain-handler {\n text-align: center;\n}\n\n.selectic .toggle-selectic {\n margin: 5px;\n padding-left: 0px;\n padding-right: 0px;\n}\n\n.selectic .toggle-boolean-select-all-toggle {\n display: inline;\n margin-right: 15px;\n}\n\n.selectic .toggle-boolean-excluding-toggle {\n display: inline;\n margin-right: 15px;\n}\n\n.selectic .single-value {\n display: grid;\n grid-template: \"value icon\" 1fr / max-content max-content;\n\n padding: 2px;\n padding-left: 5px;\n margin-left: 0;\n margin-right: 5px;\n /* margin top/bottom are mainly to create a gutter in multilines */\n margin-top: 2px;\n margin-bottom: 2px;\n\n border-radius: 3px;\n background-color: var(--selectic-value-bg);\n max-height: calc(var(--selectic-input-height) - 10px);\n max-width: 100%;\n min-width: 30px;\n\n overflow: hidden;\n white-space: nowrap;\n line-height: initial;\n vertical-align: middle;\n}\n\n.selectic .more-items {\n display: inline-block;\n\n padding-left: 5px;\n padding-right: 5px;\n border-radius: 10px;\n\n background-color: var(--selectic-more-items-bg, var(--selectic-info-bg));\n color: var(--selectic-more-items-color, var(--selectic-info-color));\n cursor: help;\n}\n.selectic-input__selected-items__value {\n grid-area: value;\n align-self: center;\n justify-self: normal;\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__icon {\n grid-area: icon;\n align-self: center;\n justify-self: center;\n margin-left: 5px;\n}\n.selectic-input__selected-items__icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic__label-disabled {\n opacity: 0.5;\n transition: opacity 400ms;\n}\n\n/* XXX: override padding of bootstrap input-sm.\n * This padding introduce a line shift. */\n.selectic.input-sm {\n padding: 0;\n}\n\n/* {{{ overflow multiline */\n\n.selectic--overflow-multiline,\n.selectic--overflow-multiline.form-control,\n.selectic--overflow-multiline .form-control {\n height: unset;\n}\n\n.selectic--overflow-multiline .selectic-input {\n overflow: unset;\n}\n\n.selectic--overflow-multiline .selectic-input__selected-items {\n flex-wrap: wrap;\n}\n\n/* }}} */\n";
|
|
35
|
+
var css_248z = "/* {{{ Variables */\n\n:root {\n --selectic-font-size: 14px;\n --selectic-cursor-disabled: not-allowed;\n\n /* The main element */\n --selectic-color: #555555;\n --selectic-bg: #ffffff;\n\n /* The main element (when disabled) */\n --selectic-color-disabled: #787878;\n --selectic-bg-disabled: #eeeeee;\n\n /* The list */\n --selectic-panel-bg: #f0f0f0;\n --selectic-separator-bordercolor: #cccccc;\n /* --selectic-item-color: var(--selectic-color); /* Can be set in any CSS configuration */\n\n /* The current selected item */\n --selectic-selected-item-color: #428bca;\n\n /* When mouse is over items or by selecting with key arrows */\n --selectic-active-item-color: #ffffff;\n --selectic-active-item-bg: #66afe9;\n\n /* Selected values in main element */\n --selectic-value-bg: #f0f0f0;\n /* --selectic-more-items-bg: var(--selectic-info-bg); /* can be set in any CSS configuration */\n /* --selectic-more-items-color: var(--selectic-info-color); /* can be set in any CSS configuration */\n --selectic-more-items-bg-disabled: #cccccc;\n\n /* Information message */\n --selectic-info-bg: #5bc0de;\n --selectic-info-color: #ffffff;\n\n /* Error message */\n --selectic-error-bg: #b72c29;\n --selectic-error-color: #ffffff;\n\n /* XXX: Currently it is important to keep this size for a correct scroll\n * height estimation */\n --selectic-input-height: 30px;\n}\n\n/* }}} */\n/* {{{ Bootstrap equivalent style */\n\n.selectic .form-control {\n display: block;\n width: 100%;\n height: calc(var(--selectic-input-height) - 2px);\n font-size: var(--selectic-font-size);\n line-height: 1.42857143;\n color: var(--selectic-color);\n background-color: var(--selectic-bg);\n background-image: none;\n border: 1px solid var(--selectic-separator-bordercolor); /* should use a better variable */\n border-radius: 4px;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n}\n.selectic .has-feedback {\n position: relative;\n}\n.selectic .has-feedback .form-control {\n padding-right: calc(var(--selectic-input-height) + 4px);\n}\n\n.selectic .form-control-feedback.fa,\n.selectic .form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: calc(var(--selectic-input-height) + 4px);\n height: calc(var(--selectic-input-height) + 4px);\n line-height: var(--selectic-input-height);\n text-align: center;\n pointer-events: none;\n}\n\n.selectic .alert-info {\n background-color: var(--selectic-info-bg);\n color: var(--selectic-info-color);\n}\n\n.selectic .alert-danger {\n background-color: var(--selectic-error-bg);\n color: var(--selectic-error-color);\n}\n\n/* }}} */\n\n.selectic * {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.selectic.form-control {\n display: inline-block;\n padding: 0;\n cursor: pointer;\n border: unset;\n}\n\n.has-feedback .selectic__icon-container.form-control-feedback {\n right: 0;\n}\n\n/* The input which contains the selected value\n * XXX: This input should stay hidden behind other elements, but is \"visible\"\n * (in term of DOM point of view) in order to get and to trigger the `focus`\n * DOM event. */\n.selectic__input-value {\n position: fixed;\n opacity: 0;\n z-index: -1000;\n top: -100px;\n}\n\n/* XXX: .form-control has been added to this selector to improve priority and\n * override some rules of the original .form-control */\n.selectic-input.form-control {\n display: inline-flex;\n justify-content: space-between;\n overflow: hidden;\n width: 100%;\n min-height: var(--selectic-input-height);\n padding-top: 0;\n padding-bottom: 0;\n padding-left: 5px;\n line-height: calc(var(--selectic-input-height) - 4px);\n color: var(--selectic-color);\n}\n\n.selectic-input__reverse-icon {\n align-self: center;\n margin-right: 3px;\n cursor: default;\n}\n.selectic-input__clear-icon {\n align-self: center;\n margin-left: 3px;\n cursor: pointer;\n}\n.selectic-input__clear-icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic-input.focused {\n border-bottom-left-radius: 0px;\n border-bottom-right-radius: 0px;\n}\n\n.selectic-input.disabled {\n cursor: var(--selectic-cursor-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n.selectic-input.disabled .more-items {\n\tbackground-color: var(--selectic-more-items-bg-disabled);\n}\n\n.selectic-input__selected-items {\n display: inline-flex;\n flex-wrap: nowrap;\n align-items: center;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__placeholder {\n font-style: italic;\n opacity: 0.7;\n white-space: nowrap;\n}\n\n.selectic-icon {\n color: var(--selectic-color);\n text-align: center;\n vertical-align: middle;\n}\n\n.selectic__extended-list {\n position: fixed;\n top: var(--top-position, 0);\n z-index: 2000;\n height: auto;\n max-height: var(--availableSpace);\n background-color: var(--selectic-bg, #ffffff);\n box-shadow: 2px 5px 12px 0px #888888;\n border-radius: 0 0 4px 4px;\n padding: 0;\n width: var(--list-width, 200px);\n min-width: 200px;\n display: grid;\n grid-template-rows: minmax(0, max-content) 1fr;\n}\n.selectic__extended-list.selectic-position-top {\n box-shadow: 2px -3px 12px 0px #888888;\n}\n.selectic__extended-list__list-container{\n overflow: auto;\n}\n.selectic__extended-list__list-items {\n max-height: calc(var(--selectic-input-height) * 10);\n min-width: max-content;\n padding-left: 0;\n}\n\n.selectic-item {\n display: block;\n position: relative;\n box-sizing: border-box;\n padding: 2px 8px;\n color: var(--selectic-item-color, var(--selectic-color));\n min-height: calc(var(--selectic-input-height) - 3px);\n list-style-type: none;\n white-space: nowrap;\n cursor: pointer;\n}\n\n.selectic-item_text {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.selectic-item:not(.selected) .selectic-item_icon {\n opacity: 0;\n}\n\n.selectic-item_text {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.selectic-item__active {\n background-color: var(--selectic-active-item-bg);\n color: var(--selectic-active-item-color);\n}\n.selectic-item__active:not(.selected) .selectic-item_icon {\n opacity: 0.2;\n}\n\n.selectic-item__disabled {\n color: var(--selectic-color-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n\n.selectic-item__is-in-group {\n padding-left: 2em;\n}\n\n.selectic-item__is-group {\n font-weight: bold;\n cursor: default;\n}\n\n.selectic-item.selected {\n color: var(--selectic-selected-item-color);\n}\n.selectic-search-scope {\n color: #e0e0e0;\n left: auto;\n right: 10px;\n}\n.selectic .form-control-feedback.fa.selectic-search-scope {\n width: calc(var(--selectic-input-height) * 0.75);\n height: calc(var(--selectic-input-height) * 0.75);\n line-height: calc(var(--selectic-input-height) * 0.75);\n}\n\n.selectic__message {\n text-align: center;\n padding: 3px;\n}\n\n.selectic .filter-panel {\n padding: 3px;\n margin-left: 0px;\n margin-right: 0px;\n background-color: var(--selectic-panel-bg);\n border-bottom: 1px solid var(--selectic-separator-bordercolor);\n}\n\n.selectic .panelclosed {\n max-height: 0px;\n transition: max-height 0.3s ease-out;\n overflow: hidden;\n}\n\n.panelopened {\n max-height: 200px;\n transition: max-height 0.3s ease-in;\n overflow: hidden;\n}\n\n.selectic .filter-panel__input {\n padding-left: 0px;\n padding-right: 0px;\n padding-bottom: 10px;\n margin-bottom: 0px;\n}\n.selectic .filter-input {\n height: calc(var(--selectic-input-height) * 0.75);\n}\n\n.selectic .checkbox-filter {\n padding: 5px;\n text-align: center;\n}\n\n.selectic .curtain-handler {\n text-align: center;\n}\n\n.selectic .toggle-selectic {\n margin: 5px;\n padding-left: 0px;\n padding-right: 0px;\n}\n\n.selectic .toggle-boolean-select-all-toggle {\n display: inline;\n margin-right: 15px;\n}\n\n.selectic .toggle-boolean-excluding-toggle {\n display: inline;\n margin-right: 15px;\n}\n\n.selectic .single-value {\n display: grid;\n grid-template: \"value icon\" 1fr / max-content max-content;\n\n padding: 2px;\n padding-left: 5px;\n margin-left: 0;\n margin-right: 5px;\n /* margin top/bottom are mainly to create a gutter in multilines */\n margin-top: 2px;\n margin-bottom: 2px;\n\n border-radius: 3px;\n background-color: var(--selectic-value-bg);\n max-height: calc(var(--selectic-input-height) - 10px);\n max-width: 100%;\n min-width: 30px;\n\n overflow: hidden;\n white-space: nowrap;\n line-height: initial;\n vertical-align: middle;\n}\n\n.selectic .more-items {\n display: inline-block;\n\n padding-left: 5px;\n padding-right: 5px;\n border-radius: 10px;\n\n background-color: var(--selectic-more-items-bg, var(--selectic-info-bg));\n color: var(--selectic-more-items-color, var(--selectic-info-color));\n cursor: help;\n}\n.selectic-input__selected-items__value {\n grid-area: value;\n align-self: center;\n justify-self: normal;\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__icon {\n grid-area: icon;\n align-self: center;\n justify-self: center;\n margin-left: 5px;\n}\n.selectic-input__selected-items__icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic__label-disabled {\n opacity: 0.5;\n transition: opacity 400ms;\n}\n\n/* XXX: override padding of bootstrap input-sm.\n * This padding introduce a line shift. */\n.selectic.input-sm {\n padding: 0;\n}\n\n/* {{{ overflow multiline */\n\n.selectic--overflow-multiline,\n.selectic--overflow-multiline.form-control,\n.selectic--overflow-multiline .form-control {\n height: unset;\n}\n\n.selectic--overflow-multiline .selectic-input {\n overflow: unset;\n}\n\n.selectic--overflow-multiline .selectic-input__selected-items {\n flex-wrap: wrap;\n}\n\n/* }}} */\n";
|
|
36
36
|
styleInject(css_248z);
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -111,6 +111,33 @@ function assignObject(obj, ...sourceObjects) {
|
|
|
111
111
|
}
|
|
112
112
|
return result;
|
|
113
113
|
}
|
|
114
|
+
/** Compare 2 list of options.
|
|
115
|
+
* @returns true if there are no difference
|
|
116
|
+
*/
|
|
117
|
+
function compareOptions(oldOptions, newOptions) {
|
|
118
|
+
if (oldOptions.length !== newOptions.length) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return oldOptions.every((oldOption, idx) => {
|
|
122
|
+
const newOption = newOptions[idx];
|
|
123
|
+
const keys = Object.keys(oldOption);
|
|
124
|
+
if (keys.length !== Object.keys(newOption).length) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return keys.every((optionKey) => {
|
|
128
|
+
const key = optionKey;
|
|
129
|
+
const oldValue = oldOption[key];
|
|
130
|
+
const newValue = newOption[key];
|
|
131
|
+
if (key === 'options') {
|
|
132
|
+
return compareOptions(oldValue, newValue);
|
|
133
|
+
}
|
|
134
|
+
if (key === 'data') {
|
|
135
|
+
return JSON.stringify(oldValue) === JSON.stringify(newValue);
|
|
136
|
+
}
|
|
137
|
+
return oldValue === newValue;
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
114
141
|
|
|
115
142
|
/* File Purpose:
|
|
116
143
|
* It keeps and computes all states at a single place.
|
|
@@ -140,6 +167,7 @@ let messages = {
|
|
|
140
167
|
moreSelectedItem: '+1 other',
|
|
141
168
|
moreSelectedItems: '+%d others',
|
|
142
169
|
unknownPropertyValue: 'property "%s" has incorrect values.',
|
|
170
|
+
wrongQueryResult: 'Query did not return all results.',
|
|
143
171
|
};
|
|
144
172
|
let closePreviousSelectic;
|
|
145
173
|
/* }}} */
|
|
@@ -767,7 +795,7 @@ class SelecticStore {
|
|
|
767
795
|
});
|
|
768
796
|
return childOptions;
|
|
769
797
|
}
|
|
770
|
-
buildAllOptions(keepFetched = false) {
|
|
798
|
+
buildAllOptions(keepFetched = false, stopFetch = false) {
|
|
771
799
|
const allOptions = [];
|
|
772
800
|
let listOptions = [];
|
|
773
801
|
let elementOptions = [];
|
|
@@ -838,12 +866,26 @@ class SelecticStore {
|
|
|
838
866
|
this.state.totalAllOptions = allOptions.length;
|
|
839
867
|
}
|
|
840
868
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
869
|
+
if (!stopFetch) {
|
|
870
|
+
this.state.filteredOptions = [];
|
|
871
|
+
this.state.totalFilteredOptions = Infinity;
|
|
872
|
+
this.buildFilteredOptions().then(() => {
|
|
873
|
+
/* XXX: To recompute for strict mode and auto-select */
|
|
874
|
+
this.assertCorrectValue();
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
else {
|
|
878
|
+
/* Do not fetch again just build filteredOptions */
|
|
879
|
+
const search = this.state.searchText;
|
|
880
|
+
if (!search) {
|
|
881
|
+
this.state.filteredOptions = this.buildGroupItems(allOptions);
|
|
882
|
+
this.state.totalFilteredOptions = this.state.filteredOptions.length;
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
const options = this.filterOptions(allOptions, search);
|
|
886
|
+
this.state.filteredOptions = options;
|
|
887
|
+
this.state.totalFilteredOptions = this.state.filteredOptions.length;
|
|
888
|
+
}
|
|
847
889
|
}
|
|
848
890
|
async buildFilteredOptions() {
|
|
849
891
|
if (!this.state.isOpen) {
|
|
@@ -975,6 +1017,7 @@ class SelecticStore {
|
|
|
975
1017
|
const requestId = ++this.requestId;
|
|
976
1018
|
const { total: rTotal, result } = await fetchCallback(search, offset, limit);
|
|
977
1019
|
let total = rTotal;
|
|
1020
|
+
let errorMessage = '';
|
|
978
1021
|
/* Assert result is correctly formatted */
|
|
979
1022
|
if (!Array.isArray(result)) {
|
|
980
1023
|
throw new Error(labels.wrongFormattedData);
|
|
@@ -990,8 +1033,17 @@ class SelecticStore {
|
|
|
990
1033
|
if (!search) {
|
|
991
1034
|
/* update cache */
|
|
992
1035
|
state.totalDynOptions = total;
|
|
993
|
-
state.dynOptions.splice(offset, limit, ...result);
|
|
994
|
-
|
|
1036
|
+
const old = state.dynOptions.splice(offset, limit, ...result);
|
|
1037
|
+
if (compareOptions(old, result)) {
|
|
1038
|
+
/* Added options are the same as previous ones.
|
|
1039
|
+
* Stop fetching to avoid infinite loop
|
|
1040
|
+
*/
|
|
1041
|
+
errorMessage = labels.wrongQueryResult;
|
|
1042
|
+
setTimeout(() => this.buildAllOptions(true, true), 0);
|
|
1043
|
+
}
|
|
1044
|
+
else {
|
|
1045
|
+
setTimeout(() => this.buildAllOptions(true), 0);
|
|
1046
|
+
}
|
|
995
1047
|
}
|
|
996
1048
|
/* Check request is not obsolete */
|
|
997
1049
|
if (requestId !== this.requestId) {
|
|
@@ -1014,13 +1066,13 @@ class SelecticStore {
|
|
|
1014
1066
|
if (search && state.totalFilteredOptions <= state.filteredOptions.length) {
|
|
1015
1067
|
this.addStaticFilteredOptions(true);
|
|
1016
1068
|
}
|
|
1017
|
-
state.status.errorMessage =
|
|
1069
|
+
state.status.errorMessage = errorMessage;
|
|
1018
1070
|
}
|
|
1019
1071
|
catch (e) {
|
|
1020
1072
|
state.status.errorMessage = e.message;
|
|
1021
1073
|
if (!search) {
|
|
1022
1074
|
state.totalDynOptions = 0;
|
|
1023
|
-
this.buildAllOptions(true);
|
|
1075
|
+
this.buildAllOptions(true, true);
|
|
1024
1076
|
}
|
|
1025
1077
|
}
|
|
1026
1078
|
this.state.status.searching = false;
|
|
@@ -1220,6 +1272,8 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
1220
1272
|
/* }}} */
|
|
1221
1273
|
/* {{{ data */
|
|
1222
1274
|
this.nbHiddenItems = 0;
|
|
1275
|
+
/* reactivity non needed */
|
|
1276
|
+
this.domObserver = null;
|
|
1223
1277
|
}
|
|
1224
1278
|
/* }}} */
|
|
1225
1279
|
/* {{{ computed */
|
|
@@ -1265,8 +1319,18 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
1265
1319
|
get singleSelectedItem() {
|
|
1266
1320
|
const state = this.store.state;
|
|
1267
1321
|
const isMultiple = state.multiple;
|
|
1268
|
-
|
|
1269
|
-
|
|
1322
|
+
if (isMultiple) {
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
return this.selectedOptions;
|
|
1326
|
+
}
|
|
1327
|
+
get singleSelectedItemText() {
|
|
1328
|
+
const item = this.singleSelectedItem;
|
|
1329
|
+
return (item === null || item === void 0 ? void 0 : item.text) || '';
|
|
1330
|
+
}
|
|
1331
|
+
get singleSelectedItemTitle() {
|
|
1332
|
+
const item = this.singleSelectedItem;
|
|
1333
|
+
return (item === null || item === void 0 ? void 0 : item.title) || (item === null || item === void 0 ? void 0 : item.text) || '';
|
|
1270
1334
|
}
|
|
1271
1335
|
get singleStyle() {
|
|
1272
1336
|
const selected = this.selectedOptions;
|
|
@@ -1364,6 +1428,11 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
1364
1428
|
* currently shown */
|
|
1365
1429
|
const el = this.$refs.selectedItems;
|
|
1366
1430
|
const parentEl = el.parentElement;
|
|
1431
|
+
if (!document.contains(parentEl)) {
|
|
1432
|
+
/* The element is currently not in DOM */
|
|
1433
|
+
this.createObserver(parentEl);
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1367
1436
|
const parentPadding = parseInt(getComputedStyle(parentEl).getPropertyValue('padding-right'), 10);
|
|
1368
1437
|
const clearEl = parentEl.querySelector('.selectic-input__clear-icon');
|
|
1369
1438
|
const clearWidth = clearEl ? clearEl.offsetWidth : 0;
|
|
@@ -1395,6 +1464,33 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
1395
1464
|
idx--;
|
|
1396
1465
|
this.nbHiddenItems = selectedOptions.length - idx;
|
|
1397
1466
|
}
|
|
1467
|
+
closeObserver() {
|
|
1468
|
+
const observer = this.domObserver;
|
|
1469
|
+
if (observer) {
|
|
1470
|
+
observer.disconnect();
|
|
1471
|
+
}
|
|
1472
|
+
this.domObserver = null;
|
|
1473
|
+
}
|
|
1474
|
+
createObserver(el) {
|
|
1475
|
+
this.closeObserver();
|
|
1476
|
+
const observer = new MutationObserver((mutationsList) => {
|
|
1477
|
+
for (const mutation of mutationsList) {
|
|
1478
|
+
if (mutation.type === 'childList') {
|
|
1479
|
+
for (const elMutated of Array.from(mutation.addedNodes)) {
|
|
1480
|
+
/* Check that element has been added to DOM */
|
|
1481
|
+
if (elMutated.contains(el)) {
|
|
1482
|
+
this.closeObserver();
|
|
1483
|
+
this.computeSize();
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
});
|
|
1490
|
+
const config = { childList: true, subtree: true };
|
|
1491
|
+
observer.observe(document, config);
|
|
1492
|
+
this.domObserver = observer;
|
|
1493
|
+
}
|
|
1398
1494
|
/* }}} */
|
|
1399
1495
|
/* {{{ watch */
|
|
1400
1496
|
onInternalChange() {
|
|
@@ -1405,6 +1501,9 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
1405
1501
|
updated() {
|
|
1406
1502
|
this.computeSize();
|
|
1407
1503
|
}
|
|
1504
|
+
beforeUnmount() {
|
|
1505
|
+
this.closeObserver();
|
|
1506
|
+
}
|
|
1408
1507
|
/* }}} */
|
|
1409
1508
|
render() {
|
|
1410
1509
|
return (vtyx.h("div", { class: "selectic-container has-feedback", on: {
|
|
@@ -1415,14 +1514,14 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
1415
1514
|
focused: this.store.state.isOpen,
|
|
1416
1515
|
disabled: this.store.state.disabled,
|
|
1417
1516
|
}] },
|
|
1418
|
-
this.hasValue && !this.store.state.multiple && (vtyx.h("span", { class: "selectic-item_text", style: this.singleStyle, title: this.
|
|
1517
|
+
this.hasValue && !this.store.state.multiple && (vtyx.h("span", { class: "selectic-item_text", style: this.singleStyle, title: this.singleSelectedItemTitle }, this.singleSelectedItemText)),
|
|
1419
1518
|
this.displayPlaceholder && (vtyx.h("span", { class: [
|
|
1420
1519
|
'selectic-input__selected-items__placeholder',
|
|
1421
1520
|
'selectic-item_text',
|
|
1422
1521
|
], title: this.store.state.placeholder }, this.store.state.placeholder)),
|
|
1423
1522
|
this.store.state.multiple && (vtyx.h("div", { class: "selectic-input__selected-items", ref: "selectedItems" },
|
|
1424
1523
|
this.isSelectionReversed && (vtyx.h("span", { class: "fa fa-strikethrough selectic-input__reverse-icon", title: this.reverseSelectionLabel })),
|
|
1425
|
-
this.showSelectedOptions.map((item) => (vtyx.h("div", { class: "single-value", style: item.style, title: item.text, on: {
|
|
1524
|
+
this.showSelectedOptions.map((item) => (vtyx.h("div", { class: "single-value", style: item.style, title: item.title || item.text, on: {
|
|
1426
1525
|
click: () => this.$emit('item:click', item.id),
|
|
1427
1526
|
} },
|
|
1428
1527
|
vtyx.h("span", { class: "selectic-input__selected-items__value" }, item.text),
|
|
@@ -1851,6 +1950,10 @@ var __decorate$1 = (this && this.__decorate) || function (decorators, target, ke
|
|
|
1851
1950
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1852
1951
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1853
1952
|
};
|
|
1953
|
+
/* list estimation height
|
|
1954
|
+
* 30px × 10 + 20px (for panel header)
|
|
1955
|
+
*/
|
|
1956
|
+
const DEFAULT_LIST_HEIGHT = 320;
|
|
1854
1957
|
let ExtendedList = class ExtendedList extends vtyx.Vue {
|
|
1855
1958
|
constructor() {
|
|
1856
1959
|
/* {{{ props */
|
|
@@ -1858,11 +1961,18 @@ let ExtendedList = class ExtendedList extends vtyx.Vue {
|
|
|
1858
1961
|
/* }}} */
|
|
1859
1962
|
/* {{{ data */
|
|
1860
1963
|
this.topGroup = ' ';
|
|
1861
|
-
this.listHeight =
|
|
1964
|
+
this.listHeight = 0;
|
|
1862
1965
|
this.listWidth = 200;
|
|
1966
|
+
this.availableSpace = 0;
|
|
1863
1967
|
}
|
|
1864
1968
|
/* }}} */
|
|
1865
1969
|
/* {{{ computed */
|
|
1970
|
+
/** check if the height of the box has been completely estimated. */
|
|
1971
|
+
get isFullyEstimated() {
|
|
1972
|
+
const listHeight = this.listHeight;
|
|
1973
|
+
const availableSpace = this.availableSpace;
|
|
1974
|
+
return listHeight !== 0 && listHeight < availableSpace;
|
|
1975
|
+
}
|
|
1866
1976
|
get searchingLabel() {
|
|
1867
1977
|
return this.store.data.labels.searching;
|
|
1868
1978
|
}
|
|
@@ -1923,17 +2033,30 @@ let ExtendedList = class ExtendedList extends vtyx.Vue {
|
|
|
1923
2033
|
}
|
|
1924
2034
|
get bestPosition() {
|
|
1925
2035
|
const windowHeight = window.innerHeight;
|
|
1926
|
-
const
|
|
2036
|
+
const isFullyEstimated = this.isFullyEstimated;
|
|
2037
|
+
/* XXX: The max() is because if listHeight is greater than default,
|
|
2038
|
+
* it means that the value is more accurate than the default. */
|
|
2039
|
+
const listHeight = isFullyEstimated ? this.listHeight
|
|
2040
|
+
: Math.max(DEFAULT_LIST_HEIGHT, this.listHeight);
|
|
1927
2041
|
const inputTop = this.elementTop;
|
|
1928
2042
|
const inputBottom = this.elementBottom;
|
|
1929
|
-
|
|
2043
|
+
const availableTop = inputTop;
|
|
2044
|
+
const availableBottom = windowHeight - inputBottom;
|
|
2045
|
+
if (listHeight < availableBottom) {
|
|
1930
2046
|
return 'bottom';
|
|
1931
2047
|
}
|
|
1932
|
-
if (listHeight <
|
|
2048
|
+
if (listHeight < availableTop) {
|
|
1933
2049
|
return 'top';
|
|
1934
2050
|
}
|
|
1935
2051
|
/* There are not enough space neither at bottom nor at top */
|
|
1936
|
-
return
|
|
2052
|
+
return availableBottom < availableTop ? 'top' : 'bottom';
|
|
2053
|
+
}
|
|
2054
|
+
get position() {
|
|
2055
|
+
const listPosition = this.store.state.listPosition;
|
|
2056
|
+
if (listPosition === 'auto') {
|
|
2057
|
+
return this.bestPosition;
|
|
2058
|
+
}
|
|
2059
|
+
return listPosition;
|
|
1937
2060
|
}
|
|
1938
2061
|
get horizontalStyle() {
|
|
1939
2062
|
const windowWidth = window.innerWidth;
|
|
@@ -1953,26 +2076,32 @@ let ExtendedList = class ExtendedList extends vtyx.Vue {
|
|
|
1953
2076
|
return `left: ${inputLeft}px; min-width: unset;`;
|
|
1954
2077
|
}
|
|
1955
2078
|
get positionStyle() {
|
|
1956
|
-
|
|
2079
|
+
const listPosition = this.position;
|
|
1957
2080
|
const horizontalStyle = this.horizontalStyle;
|
|
1958
|
-
|
|
1959
|
-
listPosition = this.bestPosition;
|
|
1960
|
-
}
|
|
2081
|
+
const width = this.width;
|
|
1961
2082
|
if (listPosition === 'top') {
|
|
1962
2083
|
const transform = horizontalStyle.includes('transform')
|
|
1963
2084
|
? 'transform: translateX(-100%) translateY(-100%);'
|
|
1964
2085
|
: 'transform: translateY(-100%);';
|
|
2086
|
+
const elementTop = this.elementTop;
|
|
2087
|
+
const availableSpace = this.elementTop;
|
|
2088
|
+
this.availableSpace = availableSpace;
|
|
1965
2089
|
return `
|
|
1966
|
-
top: ${
|
|
2090
|
+
--top-position: ${elementTop}px;
|
|
1967
2091
|
${horizontalStyle}
|
|
1968
|
-
width: ${
|
|
1969
|
-
${transform}
|
|
2092
|
+
--list-width: ${width}px;
|
|
2093
|
+
${transform};
|
|
2094
|
+
--availableSpace: ${availableSpace}px;
|
|
1970
2095
|
`;
|
|
1971
2096
|
}
|
|
2097
|
+
const elementBottom = this.elementBottom;
|
|
2098
|
+
const availableSpace = window.innerHeight - elementBottom;
|
|
2099
|
+
this.availableSpace = availableSpace;
|
|
1972
2100
|
return `
|
|
1973
|
-
top: ${
|
|
2101
|
+
--top-position: ${elementBottom}px;
|
|
1974
2102
|
${horizontalStyle}
|
|
1975
|
-
width: ${
|
|
2103
|
+
--list-width: ${width}px;
|
|
2104
|
+
--availableSpace: ${availableSpace}px;
|
|
1976
2105
|
`;
|
|
1977
2106
|
}
|
|
1978
2107
|
/* }}} */
|
|
@@ -2015,7 +2144,10 @@ let ExtendedList = class ExtendedList extends vtyx.Vue {
|
|
|
2015
2144
|
const state = store.state;
|
|
2016
2145
|
const isGroup = state.groups.size > 0 &&
|
|
2017
2146
|
state.totalFilteredOptions > store.data.itemsPerPage;
|
|
2018
|
-
return (vtyx.h("div", { style: this.positionStyle, class:
|
|
2147
|
+
return (vtyx.h("div", { style: this.positionStyle, class: [
|
|
2148
|
+
'selectic selectic__extended-list',
|
|
2149
|
+
`selectic-position-${this.position}`,
|
|
2150
|
+
] },
|
|
2019
2151
|
!state.hideFilter && (vtyx.h(Filter, { store: this.store })),
|
|
2020
2152
|
isGroup && (vtyx.h("span", { class: "selectic-item selectic-item--header selectic-item__is-group" }, this.topGroup)),
|
|
2021
2153
|
vtyx.h(List$1, { store: store, on: {
|