goodteditor-ui 1.0.26 → 1.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/.eslintrc.js +7 -7
  2. package/.prettierrc +14 -14
  3. package/README.md +35 -35
  4. package/babel.config.js +5 -5
  5. package/index.js +53 -53
  6. package/jsconfig.json +13 -13
  7. package/package.json +67 -67
  8. package/src/App.vue +36 -36
  9. package/src/components/ui/Avatar.md +68 -68
  10. package/src/components/ui/Avatar.vue +180 -180
  11. package/src/components/ui/Badge.md +20 -20
  12. package/src/components/ui/Badge.vue +75 -75
  13. package/src/components/ui/Collapse.md +90 -90
  14. package/src/components/ui/Collapse.vue +86 -86
  15. package/src/components/ui/ColorPicker/Alpha.vue +114 -114
  16. package/src/components/ui/ColorPicker/Colors.vue +117 -117
  17. package/src/components/ui/ColorPicker/Hue.vue +113 -113
  18. package/src/components/ui/ColorPicker/Preview.vue +55 -55
  19. package/src/components/ui/ColorPicker/Saturation.vue +123 -123
  20. package/src/components/ui/ColorPicker/mixin.js +105 -105
  21. package/src/components/ui/ColorPicker.md +17 -17
  22. package/src/components/ui/ColorPicker.vue +314 -314
  23. package/src/components/ui/Datalist.md +41 -41
  24. package/src/components/ui/Datalist.vue +164 -164
  25. package/src/components/ui/DatePicker.md +168 -168
  26. package/src/components/ui/DatePicker.vue +527 -527
  27. package/src/components/ui/FileSelector.md +105 -105
  28. package/src/components/ui/FileSelector.vue +82 -82
  29. package/src/components/ui/Grid.md +130 -130
  30. package/src/components/ui/Grid.vue +92 -92
  31. package/src/components/ui/Image.md +59 -59
  32. package/src/components/ui/Image.vue +57 -57
  33. package/src/components/ui/InputAutocomplete.md +115 -115
  34. package/src/components/ui/InputAutocomplete.vue +374 -349
  35. package/src/components/ui/InputColorPicker.md +51 -51
  36. package/src/components/ui/InputColorPicker.vue +151 -151
  37. package/src/components/ui/InputDatePicker.md +121 -121
  38. package/src/components/ui/InputDatePicker.vue +326 -326
  39. package/src/components/ui/InputTags.md +51 -51
  40. package/src/components/ui/InputTags.vue +184 -184
  41. package/src/components/ui/InputTimePicker.md +25 -25
  42. package/src/components/ui/InputTimePicker.vue +253 -253
  43. package/src/components/ui/InputUnits.md +20 -20
  44. package/src/components/ui/InputUnits.vue +257 -257
  45. package/src/components/ui/Lazy.md +37 -37
  46. package/src/components/ui/Lazy.vue +92 -92
  47. package/src/components/ui/Pagination.md +74 -74
  48. package/src/components/ui/Pagination.vue +138 -138
  49. package/src/components/ui/Paginator.md +34 -34
  50. package/src/components/ui/Paginator.vue +83 -83
  51. package/src/components/ui/Popover.md +34 -34
  52. package/src/components/ui/Popover.vue +274 -274
  53. package/src/components/ui/Popup.md +59 -59
  54. package/src/components/ui/Popup.vue +150 -150
  55. package/src/components/ui/ResponsiveContainer.md +58 -58
  56. package/src/components/ui/ResponsiveContainer.vue +99 -99
  57. package/src/components/ui/Select.md +187 -187
  58. package/src/components/ui/Select.vue +421 -421
  59. package/src/components/ui/TimePicker.md +50 -50
  60. package/src/components/ui/TimePicker.vue +252 -252
  61. package/src/components/ui/Tooltip.md +54 -54
  62. package/src/components/ui/Tooltip.vue +113 -113
  63. package/src/components/ui/WysiwygEditor/WysiwygEditor.d.ts +128 -128
  64. package/src/components/ui/WysiwygEditor/constants.js +273 -273
  65. package/src/components/ui/WysiwygEditor/extensions/blockquote.js +15 -15
  66. package/src/components/ui/WysiwygEditor/extensions/bold.js +15 -15
  67. package/src/components/ui/WysiwygEditor/extensions/bullet-list.js +15 -15
  68. package/src/components/ui/WysiwygEditor/extensions/code-block.js +13 -13
  69. package/src/components/ui/WysiwygEditor/extensions/code.js +13 -13
  70. package/src/components/ui/WysiwygEditor/extensions/font-size.js +34 -34
  71. package/src/components/ui/WysiwygEditor/extensions/formatting.js +14 -14
  72. package/src/components/ui/WysiwygEditor/extensions/heading.js +13 -13
  73. package/src/components/ui/WysiwygEditor/extensions/horizontal-rule.js +15 -15
  74. package/src/components/ui/WysiwygEditor/extensions/image.js +37 -33
  75. package/src/components/ui/WysiwygEditor/extensions/index.d.ts +32 -32
  76. package/src/components/ui/WysiwygEditor/extensions/index.js +32 -32
  77. package/src/components/ui/WysiwygEditor/extensions/italic.js +15 -15
  78. package/src/components/ui/WysiwygEditor/extensions/link.js +16 -16
  79. package/src/components/ui/WysiwygEditor/extensions/list-item.js +15 -15
  80. package/src/components/ui/WysiwygEditor/extensions/ordered-list.js +15 -15
  81. package/src/components/ui/WysiwygEditor/extensions/paragraph.js +23 -23
  82. package/src/components/ui/WysiwygEditor/extensions/strike.js +15 -15
  83. package/src/components/ui/WysiwygEditor/extensions/table-cell.js +13 -13
  84. package/src/components/ui/WysiwygEditor/extensions/table-header.js +15 -15
  85. package/src/components/ui/WysiwygEditor/extensions/table-row.js +15 -15
  86. package/src/components/ui/WysiwygEditor/extensions/table.js +29 -29
  87. package/src/components/ui/WysiwygEditor/extensions/text-align.js +6 -6
  88. package/src/components/ui/WysiwygEditor/extensions/text-style.js +12 -12
  89. package/src/components/ui/WysiwygEditor/extensions/underline.js +15 -15
  90. package/src/components/ui/WysiwygEditor/index.d.ts +4 -4
  91. package/src/components/ui/WysiwygEditor/index.js +4 -4
  92. package/src/components/ui/WysiwygEditor/renders/Button.vue +28 -28
  93. package/src/components/ui/WysiwygEditor/renders/ColorPicker.vue +41 -41
  94. package/src/components/ui/WysiwygEditor/renders/Image.vue +200 -162
  95. package/src/components/ui/WysiwygEditor/renders/InputAuto.vue +34 -34
  96. package/src/components/ui/WysiwygEditor/renders/InputUnits.vue +37 -37
  97. package/src/components/ui/WysiwygEditor/renders/Link.vue +82 -82
  98. package/src/components/ui/WysiwygEditor/renders/Select.vue +47 -47
  99. package/src/components/ui/WysiwygEditor/renders/ToolbarPopover.vue +49 -49
  100. package/src/components/ui/WysiwygEditor/renders/components/Popover.vue +15 -0
  101. package/src/components/ui/WysiwygEditor/renders/components/WithPopover.vue +35 -35
  102. package/src/components/ui/WysiwygEditor/renders/index.d.ts +8 -8
  103. package/src/components/ui/WysiwygEditor/renders/index.js +8 -8
  104. package/src/components/ui/WysiwygEditor/renders/mixins/RenderMixin.js +39 -39
  105. package/src/components/ui/WysiwygEditor/renders/mixins/index.js +1 -1
  106. package/src/components/ui/WysiwygEditor/tools-and-commands.js +709 -702
  107. package/src/components/ui/WysiwygEditor/utils.js +72 -72
  108. package/src/components/ui/WysiwygEditor.md +18 -18
  109. package/src/components/ui/WysiwygEditor.vue +266 -266
  110. package/src/components/ui/utils/FormComponent.js +107 -107
  111. package/src/components/ui/utils/Helpers.js +84 -84
  112. package/src/components/ui/utils/WithPopover.js +81 -81
  113. package/src/main.js +8 -8
  114. package/styleguide.config.js +37 -37
  115. package/vue.config.js +8 -8
  116. package/dist/js.png +0 -0
@@ -1,349 +1,374 @@
1
- <template>
2
- <div
3
- class="ui-input-autocomplete form-elem"
4
- :class="cssClass"
5
- @focus="onRootFocus"
6
- tabindex="0"
7
- :data-popover="popoverTargetId"
8
- >
9
- <div style="flex: 1 0 0">
10
- <!--
11
- @slot Custom input slot
12
- @binding {String} id input id attribute value
13
- @binding {String} value input value
14
- @binding {Object} inputBinds input props (use v-bind)
15
- @binding {Object} inputEvents input events (use v-on)
16
- -->
17
- <slot name="input" v-bind="{ id: inputId, value, inputBinds, inputEvents }">
18
- <input
19
- :id="inputId"
20
- class="ui-input-autocomplete-input w-100"
21
- type="text"
22
- :value="value"
23
- v-bind="inputBinds"
24
- v-on="inputEvents"
25
- />
26
- </slot>
27
- </div>
28
- <!--
29
- @slot Loading custom content
30
- -->
31
- <slot name="loading" v-if="loading">
32
- <div class="icon w-auto h-auto">
33
- <div class="preloader"></div>
34
- </div>
35
- </slot>
36
- <ui-popover :show.sync="popoverShow" v-bind="popoverOptions">
37
- <ui-datalist
38
- class="w-100 pull-left"
39
- @select-option="onDatalistSelectOption"
40
- v-bind="{ size, maxHeight: dropdownMaxHeight, options: suggestedOptions }"
41
- :cursorIndex.sync="dataListCursorIndex"
42
- ref="datalist"
43
- >
44
- <template #header>
45
- <!--
46
- @slot Dropdown header content
47
- -->
48
- <slot name="dropdown-header"></slot>
49
- <!--
50
- @slot No results content
51
- -->
52
- <slot name="noresults" v-if="!loading && !suggestedOptions.length"></slot>
53
- </template>
54
- <template #option="{ option, index, cursorIndex, setCursorIndex }">
55
- <!--
56
- @slot Dropdown option
57
- @binding {String} option option label
58
- @binding {Number} optionIndex option index
59
- @binding {String} value current value
60
- @binding {String} valueLocal current delimited value
61
- @binding {Number} cursorIndex current dropdown selection index
62
- @binding {Function} selectOption function that select's the option
63
- @binding {Function} setCursorIndex function that sets the cursor index
64
- -->
65
- <slot
66
- name="option"
67
- v-bind="{
68
- option: option,
69
- optionIndex: index,
70
- value,
71
- valueLocal: delimitedValue,
72
- cursorIndex,
73
- selectOption,
74
- setCursorIndex,
75
- }"
76
- ></slot>
77
- </template>
78
- <template #footer>
79
- <slot name="dropdown-footer"></slot>
80
- </template>
81
- </ui-datalist>
82
- </ui-popover>
83
- </div>
84
- </template>
85
- <style lang="less" scoped>
86
- .ui-input-autocomplete {
87
- display: inline-flex;
88
- align-items: center;
89
- &-input {
90
- border: none;
91
- line-height: 1.5;
92
- margin: 0;
93
- padding: 0;
94
- color: inherit;
95
- background: transparent;
96
- outline: none;
97
- }
98
- }
99
- </style>
100
- <script>
101
- import { Key } from './utils/Helpers';
102
- import FormComponent from './utils/FormComponent';
103
- import WithPopover from './utils/WithPopover';
104
- import UiDatalist from './Datalist.vue';
105
- import UiPopover from './Popover.vue';
106
-
107
- export default {
108
- mixins: [FormComponent, WithPopover],
109
- components: { UiDatalist, UiPopover },
110
- props: {
111
- /**
112
- * Dropdown option (suggestions)
113
- */
114
- options: {
115
- type: Array,
116
- default() {
117
- return [];
118
- },
119
- },
120
- /**
121
- * Function which filters suggestions function(val, options):Promise<Array>
122
- */
123
- filter: {
124
- type: Function,
125
- default: null,
126
- },
127
- /**
128
- * Filter debounce delay in ms
129
- */
130
- filterDebounce: {
131
- type: Number,
132
- default: 0,
133
- },
134
- /**
135
- * Value delimiter for multiple autocomplete suggestions
136
- */
137
- delimiter: {
138
- type: String,
139
- default: ',',
140
- },
141
- /**
142
- * Show suggestions on focus event
143
- */
144
- suggestOnFocus: {
145
- type: Boolean,
146
- default: true,
147
- },
148
- /**
149
- * Min length to show suggestions
150
- */
151
- minLength: {
152
- type: Number,
153
- default: 0,
154
- },
155
- /**
156
- * Defines the dropdown's max-height
157
- */
158
- dropdownMaxHeight: {
159
- default: '',
160
- },
161
- /**
162
- * Auto width
163
- */
164
- autoWidth: {
165
- type: Boolean,
166
- default: true,
167
- },
168
- },
169
- data() {
170
- return {
171
- loading: false,
172
- suggestedOptions: [],
173
- caretIndex: 0,
174
- dataListCursorIndex: -1,
175
- filterTID: null,
176
- inputBinds: {
177
- placeholder: this.placeholder,
178
- readonly: this.readonly,
179
- },
180
- inputEvents: {
181
- change: this.onInputChange,
182
- input: this.onInputInput,
183
- keydown: this.onInputKeyDown,
184
- focus: this.onInputFocus,
185
- blur: this.onInputBlur,
186
- },
187
- delimitedValuePrev: null,
188
- };
189
- },
190
- computed: {
191
- delimitedIndex() {
192
- let sub = this.value.substring(0, this.caretIndex);
193
- let m = [];
194
- let i = -1;
195
- while ((i = sub.indexOf(this.delimiter, i + 1)) != -1) {
196
- m.push(i);
197
- }
198
- return m ? m.length : 0;
199
- },
200
- delimitedValue() {
201
- if (this.delimiter) {
202
- return this.value.split(this.delimiter)[this.delimitedIndex];
203
- }
204
- return this.value;
205
- },
206
- },
207
- methods: {
208
- defaultFilter(val, options) {
209
- return new Promise(resolve => {
210
- let arr = options.filter(opt => opt.toLowerCase().indexOf(val.toLowerCase()) === 0);
211
- resolve(arr);
212
- });
213
- },
214
- callFilter(val) {
215
- let prev = this.delimitedValuePrev;
216
- this.delimitedValuePrev = val;
217
- if (val === prev) {
218
- return;
219
- }
220
- if (!val.length && !this.filter) {
221
- this.suggestedOptions = this.options;
222
- this.dataListCursorIndex = -1;
223
- return;
224
- }
225
- this.loading = true;
226
- let h = this.filter ? this.filter : this.defaultFilter;
227
- h(val, this.options)
228
- .then(arr => {
229
- this.suggestedOptions = arr;
230
- this.dataListCursorIndex = -1;
231
- })
232
- .finally(() => (this.loading = false));
233
- },
234
- callFilterDebounced(val) {
235
- this.clearFilterTimeout();
236
- this.filterTID = setTimeout(() => this.callFilter(val), this.filterDebounce);
237
- },
238
- clearFilterTimeout() {
239
- if (this.filterTID) {
240
- clearTimeout(this.filterTID);
241
- this.filterTID = null;
242
- }
243
- },
244
- selectOption(opt) {
245
- let val = opt;
246
- if (this.delimiter) {
247
- let arr = this.value.split(this.delimiter);
248
- arr[this.delimitedIndex] = opt;
249
- val = arr.join(this.delimiter);
250
- }
251
- /**
252
- * Value change event
253
- * @property {String} value
254
- */
255
- this.$emit('input', val);
256
- /**
257
- * Value change event
258
- * @property {String} value
259
- */
260
- this.$emit('change', val);
261
- this.popoverShow = false;
262
- },
263
- getDatalistRef() {
264
- return this.$refs.datalist;
265
- },
266
- onRootFocus(e) {
267
- let input = this.getInputRef();
268
- input && input.focus();
269
- },
270
- onInputBlur(e) {
271
- this.rootHasFocus = false;
272
- /**
273
- * Blur event reemit
274
- * @property {Event} event
275
- */
276
- this.$emit('blur', e);
277
- },
278
- onInputFocus(e) {
279
- this.rootHasFocus = true;
280
- /**
281
- * Input focus event
282
- * @property {Node} node
283
- */
284
- this.$emit('focus', e.target);
285
-
286
- if (!this.suggestOnFocus) {
287
- return;
288
- }
289
-
290
- this.popoverShow = true;
291
- this.caretIndex = e.target ? e.target.selectionStart : 0;
292
- this.$nextTick(() => {
293
- if (this.delimitedValue.length < this.minLength) {
294
- this.popoverShow = false;
295
- this.suggestedOptions = [];
296
- this.delimitedValuePrev = this.delimitedValue;
297
- return;
298
- }
299
- this.callFilterDebounced(this.delimitedValue);
300
- });
301
- },
302
- onInputChange(e) {
303
- let val = e.target.value;
304
- /**
305
- * Change event
306
- * @property {String} value
307
- */
308
- this.$emit('change', val);
309
- },
310
- onInputInput(e) {
311
- let val = e.target.value;
312
- /**
313
- * input event
314
- * @property {String} value
315
- */
316
- this.$emit('input', val);
317
-
318
- this.popoverShow = true;
319
- this.caretIndex = e.target ? e.target.selectionStart : 0;
320
- this.$nextTick(() => {
321
- if (this.delimitedValue.length < this.minLength) {
322
- this.popoverShow = false;
323
- this.suggestedOptions = [];
324
- this.delimitedValuePrev = this.delimitedValue;
325
- return;
326
- }
327
- this.callFilterDebounced(this.delimitedValue);
328
- });
329
- },
330
- onInputKeyDown(e) {
331
- let list = this.getDatalistRef();
332
- if (e.key === Key.ESC) {
333
- this.popoverShow = false;
334
- }
335
- if (e.key === Key.ENTER) {
336
- if (!this.popoverShow) {
337
- this.popoverShow = true;
338
- }
339
- }
340
- if (this.popoverShow) {
341
- list && list.onKeyDown(e);
342
- }
343
- },
344
- onDatalistSelectOption({ option }) {
345
- this.selectOption(option);
346
- },
347
- },
348
- };
349
- </script>
1
+ <template>
2
+ <div
3
+ class="ui-input-autocomplete form-elem"
4
+ :class="cssClass"
5
+ @focus="onRootFocus"
6
+ tabindex="0"
7
+ :data-popover="popoverTargetId"
8
+ >
9
+ <div style="flex: 1 0 0">
10
+ <!--
11
+ @slot Custom input slot
12
+ @binding {String} id input id attribute value
13
+ @binding {String} value input value
14
+ @binding {Object} inputBinds input props (use v-bind)
15
+ @binding {Object} inputEvents input events (use v-on)
16
+ -->
17
+ <slot name="input" v-bind="{ id: inputId, value, inputBinds, inputEvents }">
18
+ <input
19
+ :id="inputId"
20
+ class="ui-input-autocomplete-input w-100"
21
+ type="text"
22
+ :value="value"
23
+ v-bind="inputBinds"
24
+ v-on="inputEvents"
25
+ />
26
+ </slot>
27
+ </div>
28
+ <!--
29
+ @slot Loading custom content
30
+ -->
31
+ <slot name="loading" v-if="loading">
32
+ <div class="icon w-auto h-auto">
33
+ <div class="preloader"></div>
34
+ </div>
35
+ </slot>
36
+ <ui-popover :show.sync="popoverShow" v-bind="popoverOptions">
37
+ <ui-datalist
38
+ class="w-100 pull-left"
39
+ @select-option="onDatalistSelectOption"
40
+ v-bind="{ size, maxHeight: dropdownMaxHeight, options: suggestedOptions }"
41
+ :cursorIndex.sync="dataListCursorIndex"
42
+ ref="datalist"
43
+ >
44
+ <template #header>
45
+ <!--
46
+ @slot Dropdown header content
47
+ -->
48
+ <slot name="dropdown-header"></slot>
49
+ <!--
50
+ @slot No results content
51
+ -->
52
+ <slot name="noresults" v-if="!loading && !suggestedOptions.length"></slot>
53
+ </template>
54
+ <template #option="{ option, index, cursorIndex, setCursorIndex }">
55
+ <!--
56
+ @slot Dropdown option
57
+ @binding {String} option option label
58
+ @binding {Number} optionIndex option index
59
+ @binding {String} value current value
60
+ @binding {String} valueLocal current delimited value
61
+ @binding {Number} cursorIndex current dropdown selection index
62
+ @binding {Function} selectOption function that select's the option
63
+ @binding {Function} setCursorIndex function that sets the cursor index
64
+ -->
65
+ <slot
66
+ name="option"
67
+ v-bind="{
68
+ option: option,
69
+ optionIndex: index,
70
+ value,
71
+ valueLocal: delimitedValue,
72
+ cursorIndex,
73
+ selectOption,
74
+ setCursorIndex,
75
+ }"
76
+ ></slot>
77
+ </template>
78
+ <template #footer>
79
+ <slot name="dropdown-footer"></slot>
80
+ </template>
81
+ </ui-datalist>
82
+ </ui-popover>
83
+ <!--
84
+ @slot Custom clear btn slot
85
+ @binding {Function} clear function that clears the value
86
+ -->
87
+ <slot
88
+ name="clear-btn"
89
+ v-if="useClearBtn && value.length > 0"
90
+ v-bind="{ clear: clearValue }"
91
+ >
92
+ <i class="mdi mdi-close cursor-pointer" @click="clearValue"></i>
93
+ </slot>
94
+ </div>
95
+ </template>
96
+ <style lang="less" scoped>
97
+ .ui-input-autocomplete {
98
+ display: inline-flex;
99
+ align-items: center;
100
+ &-input {
101
+ border: none;
102
+ line-height: 1.5;
103
+ margin: 0;
104
+ padding: 0;
105
+ color: inherit;
106
+ background: transparent;
107
+ outline: none;
108
+ }
109
+ }
110
+ </style>
111
+ <script>
112
+ import { Key } from './utils/Helpers';
113
+ import FormComponent from './utils/FormComponent';
114
+ import WithPopover from './utils/WithPopover';
115
+ import UiDatalist from './Datalist.vue';
116
+ import UiPopover from './Popover.vue';
117
+
118
+ export default {
119
+ mixins: [FormComponent, WithPopover],
120
+ components: { UiDatalist, UiPopover },
121
+ props: {
122
+ /**
123
+ * Dropdown option (suggestions)
124
+ */
125
+ options: {
126
+ type: Array,
127
+ default() {
128
+ return [];
129
+ },
130
+ },
131
+ /**
132
+ * Function which filters suggestions function(val, options):Promise<Array>
133
+ */
134
+ filter: {
135
+ type: Function,
136
+ default: null,
137
+ },
138
+ /**
139
+ * Filter debounce delay in ms
140
+ */
141
+ filterDebounce: {
142
+ type: Number,
143
+ default: 0,
144
+ },
145
+ /**
146
+ * Value delimiter for multiple autocomplete suggestions
147
+ */
148
+ delimiter: {
149
+ type: String,
150
+ default: ',',
151
+ },
152
+ /**
153
+ * Show suggestions on focus event
154
+ */
155
+ suggestOnFocus: {
156
+ type: Boolean,
157
+ default: true,
158
+ },
159
+ /**
160
+ * Min length to show suggestions
161
+ */
162
+ minLength: {
163
+ type: Number,
164
+ default: 0,
165
+ },
166
+ /**
167
+ * Defines the dropdown's max-height
168
+ */
169
+ dropdownMaxHeight: {
170
+ default: '',
171
+ },
172
+ /**
173
+ * Auto width
174
+ */
175
+ autoWidth: {
176
+ type: Boolean,
177
+ default: true,
178
+ },
179
+ /**
180
+ * Clear data btn
181
+ */
182
+ useClearBtn: {
183
+ type: Boolean,
184
+ default: false,
185
+ },
186
+ },
187
+ data() {
188
+ return {
189
+ loading: false,
190
+ suggestedOptions: [],
191
+ caretIndex: 0,
192
+ dataListCursorIndex: -1,
193
+ filterTID: null,
194
+ inputBinds: {
195
+ placeholder: this.placeholder,
196
+ readonly: this.readonly,
197
+ },
198
+ inputEvents: {
199
+ change: this.onInputChange,
200
+ input: this.onInputInput,
201
+ keydown: this.onInputKeyDown,
202
+ focus: this.onInputFocus,
203
+ blur: this.onInputBlur,
204
+ },
205
+ delimitedValuePrev: null,
206
+ };
207
+ },
208
+ computed: {
209
+ delimitedIndex() {
210
+ let sub = this.value.substring(0, this.caretIndex);
211
+ let m = [];
212
+ let i = -1;
213
+ while ((i = sub.indexOf(this.delimiter, i + 1)) != -1) {
214
+ m.push(i);
215
+ }
216
+ return m ? m.length : 0;
217
+ },
218
+ delimitedValue() {
219
+ if (this.delimiter) {
220
+ return this.value.split(this.delimiter)[this.delimitedIndex];
221
+ }
222
+ return this.value;
223
+ },
224
+ },
225
+ methods: {
226
+ clearValue() {
227
+ this.$emit('input', '');
228
+ this.caretIndex = 0;
229
+ this.delimitedValuePrev = null;
230
+ this.filterTID = null;
231
+ this.suggestedOptions = [];
232
+ },
233
+ defaultFilter(val, options) {
234
+ return new Promise(resolve => {
235
+ let arr = options.filter(opt => opt.toLowerCase().indexOf(val.toLowerCase()) === 0);
236
+ resolve(arr);
237
+ });
238
+ },
239
+ callFilter(val) {
240
+ let prev = this.delimitedValuePrev;
241
+ this.delimitedValuePrev = val;
242
+ if (val === prev) {
243
+ return;
244
+ }
245
+ if (!val.length && !this.filter) {
246
+ this.suggestedOptions = this.options;
247
+ this.dataListCursorIndex = -1;
248
+ return;
249
+ }
250
+ this.loading = true;
251
+ let h = this.filter ? this.filter : this.defaultFilter;
252
+ h(val, this.options)
253
+ .then(arr => {
254
+ this.suggestedOptions = arr;
255
+ this.dataListCursorIndex = -1;
256
+ })
257
+ .finally(() => (this.loading = false));
258
+ },
259
+ callFilterDebounced(val) {
260
+ this.clearFilterTimeout();
261
+ this.filterTID = setTimeout(() => this.callFilter(val), this.filterDebounce);
262
+ },
263
+ clearFilterTimeout() {
264
+ if (this.filterTID) {
265
+ clearTimeout(this.filterTID);
266
+ this.filterTID = null;
267
+ }
268
+ },
269
+ selectOption(opt) {
270
+ let val = opt;
271
+ if (this.delimiter) {
272
+ let arr = this.value.split(this.delimiter);
273
+ arr[this.delimitedIndex] = opt;
274
+ val = arr.join(this.delimiter);
275
+ }
276
+ /**
277
+ * Value change event
278
+ * @property {String} value
279
+ */
280
+ this.$emit('input', val);
281
+ /**
282
+ * Value change event
283
+ * @property {String} value
284
+ */
285
+ this.$emit('change', val);
286
+ this.popoverShow = false;
287
+ },
288
+ getDatalistRef() {
289
+ return this.$refs.datalist;
290
+ },
291
+ onRootFocus(e) {
292
+ let input = this.getInputRef();
293
+ input && input.focus();
294
+ },
295
+ onInputBlur(e) {
296
+ this.rootHasFocus = false;
297
+ /**
298
+ * Blur event reemit
299
+ * @property {Event} event
300
+ */
301
+ this.$emit('blur', e);
302
+ },
303
+ onInputFocus(e) {
304
+ this.rootHasFocus = true;
305
+ /**
306
+ * Input focus event
307
+ * @property {Node} node
308
+ */
309
+ this.$emit('focus', e.target);
310
+
311
+ if (!this.suggestOnFocus) {
312
+ return;
313
+ }
314
+
315
+ this.popoverShow = true;
316
+ this.caretIndex = e.target ? e.target.selectionStart : 0;
317
+ this.$nextTick(() => {
318
+ if (this.delimitedValue.length < this.minLength) {
319
+ this.popoverShow = false;
320
+ this.suggestedOptions = [];
321
+ this.delimitedValuePrev = this.delimitedValue;
322
+ return;
323
+ }
324
+ this.callFilterDebounced(this.delimitedValue);
325
+ });
326
+ },
327
+ onInputChange(e) {
328
+ let val = e.target.value;
329
+ /**
330
+ * Change event
331
+ * @property {String} value
332
+ */
333
+ this.$emit('change', val);
334
+ },
335
+ onInputInput(e) {
336
+ let val = e.target.value;
337
+ /**
338
+ * input event
339
+ * @property {String} value
340
+ */
341
+ this.$emit('input', val);
342
+
343
+ this.popoverShow = true;
344
+ this.caretIndex = e.target ? e.target.selectionStart : 0;
345
+ this.$nextTick(() => {
346
+ if (this.delimitedValue.length < this.minLength) {
347
+ this.popoverShow = false;
348
+ this.suggestedOptions = [];
349
+ this.delimitedValuePrev = this.delimitedValue;
350
+ return;
351
+ }
352
+ this.callFilterDebounced(this.delimitedValue);
353
+ });
354
+ },
355
+ onInputKeyDown(e) {
356
+ let list = this.getDatalistRef();
357
+ if (e.key === Key.ESC) {
358
+ this.popoverShow = false;
359
+ }
360
+ if (e.key === Key.ENTER) {
361
+ if (!this.popoverShow) {
362
+ this.popoverShow = true;
363
+ }
364
+ }
365
+ if (this.popoverShow) {
366
+ list && list.onKeyDown(e);
367
+ }
368
+ },
369
+ onDatalistSelectOption({ option }) {
370
+ this.selectOption(option);
371
+ },
372
+ },
373
+ };
374
+ </script>