Blame view

src/components/select/select.vue 26 KB
e355dd49   梁灏   add Select Component
1
  <template>
2fbe636b   梁灏   Select support a ...
2
      <div
2fbe636b   梁灏   Select support a ...
3
          :class="classes"
c9b86944   Sergio Crisostomo   Refactor Select!
4
5
          v-click-outside.capture="onClickOutside"
      >
e355dd49   梁灏   add Select Component
6
          <div
4aec6a66   梁灏   support Select
7
              ref="reference"
c9b86944   Sergio Crisostomo   Refactor Select!
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  
              :class="selectionCls"
              :tabindex="selectTabindex"
  
              @blur="toggleHeaderFocus"
              @focus="toggleHeaderFocus"
  
              @click="toggleMenu"
              @keydown.esc="handleKeydown"
              @keydown.enter="handleKeydown"
              @keydown.up="handleKeydown"
              @keydown.down="handleKeydown"
              @keydown.tab="handleKeydown"
              @keydown.delete="handleKeydown"
  
  
              @mouseenter="hasMouseHoverHead = true"
              @mouseleave="hasMouseHoverHead = false"
  
          >
fed3e09d   梁灏   add AutoComplete ...
28
              <slot name="input">
c9b86944   Sergio Crisostomo   Refactor Select!
29
30
31
32
33
34
                  <input type="hidden" :name="name" :value="publicValue">
                  <select-head
                      :filterable="filterable"
                      :multiple="multiple"
                      :values="values"
                      :clearable="canBeCleared"
fed3e09d   梁灏   add AutoComplete ...
35
                      :disabled="disabled"
c9b86944   Sergio Crisostomo   Refactor Select!
36
37
38
39
40
41
42
43
44
                      :remote="remote"
                      :input-element-id="elementId"
                      :initial-label="initialLabel"
                      :placeholder="placeholder"
                      :query-prop="query"
  
                      @on-query-change="onQueryChange"
                      @on-input-focus="isFocused = true"
                      @on-input-blur="isFocused = false"
c9b86944   Sergio Crisostomo   Refactor Select!
45
                  />
fed3e09d   梁灏   add AutoComplete ...
46
              </slot>
e355dd49   梁灏   add Select Component
47
          </div>
e09b07b7   huanghong   解决drop弹出动画异常
48
          <transition name="transition-drop">
595cfa72   梁灏   fixed #1187 #844 ...
49
              <Drop
ecaf8d51   梁灏   Date add transfer...
50
                  :class="dropdownCls"
595cfa72   梁灏   fixed #1187 #844 ...
51
52
53
54
                  v-show="dropVisible"
                  :placement="placement"
                  ref="dropdown"
                  :data-transfer="transfer"
c9b86944   Sergio Crisostomo   Refactor Select!
55
56
57
58
59
60
61
62
63
64
65
                  v-transfer-dom
              >
                  <ul v-show="showNotFoundLabel" :class="[prefixCls + '-not-found']"><li>{{ localeNotFoundText }}</li></ul>
                  <ul :class="prefixCls + '-dropdown-list'">
                    <functional-options
                        v-if="(!remote) || (remote && !loading)"
                        :options="selectOptions"
                        :slot-update-hook="updateSlotOptions"
                        :slot-options="slotOptions"
                    ></functional-options>
                  </ul>
01b54e30   梁灏   Select support re...
66
                  <ul v-show="loading" :class="[prefixCls + '-loading']">{{ localeLoadingText }}</ul>
4aec6a66   梁灏   support Select
67
68
              </Drop>
          </transition>
e355dd49   梁灏   add Select Component
69
70
71
72
      </div>
  </template>
  <script>
      import Icon from '../icon';
4aec6a66   梁灏   support Select
73
      import Drop from './dropdown.vue';
c9b86944   Sergio Crisostomo   Refactor Select!
74
      import vClickOutside from 'v-click-outside-x/index';
595cfa72   梁灏   fixed #1187 #844 ...
75
      import TransferDom from '../../directives/transfer-dom';
c9b86944   Sergio Crisostomo   Refactor Select!
76
      import { oneOf } from '../../utils/assist';
4aec6a66   梁灏   support Select
77
      import Emitter from '../../mixins/emitter';
e5337c81   梁灏   fixed some compon...
78
      import Locale from '../../mixins/locale';
c9b86944   Sergio Crisostomo   Refactor Select!
79
80
      import SelectHead from './select-head.vue';
      import FunctionalOptions from './functional-options.vue';
e355dd49   梁灏   add Select Component
81
82
  
      const prefixCls = 'ivu-select';
523e2c81   Sergio Crisostomo   correct match log...
83
84
      const optionRegexp = /^i-option$|^Option$/;
      const optionGroupRegexp = /option-?group/i;
c9b86944   Sergio Crisostomo   Refactor Select!
85
86
87
88
89
90
91
92
93
94
  
      const findChild = (instance, checkFn) => {
          let match = checkFn(instance);
          if (match) return instance;
          for (let i = 0, l = instance.$children.length; i < l; i++){
              const child = instance.$children[i];
              match = findChild(child, checkFn);
              if (match) return match;
          }
      };
e355dd49   梁灏   add Select Component
95
  
06a74f9e   Sergio Crisostomo   Allow select to n...
96
97
      const findOptionsInVNode = (node) => {
          const opts = node.componentOptions;
523e2c81   Sergio Crisostomo   correct match log...
98
          if (opts && opts.tag.match(optionRegexp)) return [node];
06a74f9e   Sergio Crisostomo   Allow select to n...
99
100
101
102
103
104
105
106
107
108
109
          if (!node.children) return [];
          const options = node.children.reduce(
              (arr, el) => [...arr, ...findOptionsInVNode(el)], []
          ).filter(Boolean);
          return options.length > 0 ? options : [];
      };
  
      const extractOptions = (options) => options.reduce((options, slotEntry) => {
          return options.concat(findOptionsInVNode(slotEntry));
      }, []);
  
e355dd49   梁灏   add Select Component
110
      export default {
8f5b1686   梁灏   fixed #196
111
          name: 'iSelect',
e5337c81   梁灏   fixed some compon...
112
          mixins: [ Emitter, Locale ],
c9b86944   Sergio Crisostomo   Refactor Select!
113
114
          components: { FunctionalOptions, Drop, Icon, SelectHead },
          directives: { clickOutside: vClickOutside.directive, TransferDom },
e355dd49   梁灏   add Select Component
115
          props: {
4aec6a66   梁灏   support Select
116
              value: {
e355dd49   梁灏   add Select Component
117
118
119
                  type: [String, Number, Array],
                  default: ''
              },
98bf25b3   梁灏   fixed #1286
120
              // 使用时,也得设置 value 才行
ddc35c9a   梁灏   fixed #952
121
122
123
124
              label: {
                  type: [String, Number, Array],
                  default: ''
              },
e355dd49   梁灏   add Select Component
125
126
127
128
129
130
131
132
133
134
135
136
137
              multiple: {
                  type: Boolean,
                  default: false
              },
              disabled: {
                  type: Boolean,
                  default: false
              },
              clearable: {
                  type: Boolean,
                  default: false
              },
              placeholder: {
e5337c81   梁灏   fixed some compon...
138
                  type: String
e355dd49   梁灏   add Select Component
139
140
141
142
143
144
145
146
              },
              filterable: {
                  type: Boolean,
                  default: false
              },
              filterMethod: {
                  type: Function
              },
01b54e30   梁灏   Select support re...
147
148
149
150
151
152
153
154
155
156
              remoteMethod: {
                  type: Function
              },
              loading: {
                  type: Boolean,
                  default: false
              },
              loadingText: {
                  type: String
              },
e355dd49   梁灏   add Select Component
157
158
              size: {
                  validator (value) {
6932b4d7   梁灏   update Page compo...
159
                      return oneOf(value, ['small', 'large', 'default']);
e355dd49   梁灏   add Select Component
160
161
162
163
164
                  }
              },
              labelInValue: {
                  type: Boolean,
                  default: false
294e2412   梁灏   update Select com...
165
166
              },
              notFoundText: {
e5337c81   梁灏   fixed some compon...
167
                  type: String
f89dd9c2   梁灏   Paeg、Select add p...
168
169
170
171
172
173
              },
              placement: {
                  validator (value) {
                      return oneOf(value, ['top', 'bottom']);
                  },
                  default: 'bottom'
595cfa72   梁灏   fixed #1187 #844 ...
174
175
176
177
              },
              transfer: {
                  type: Boolean,
                  default: false
fed3e09d   梁灏   add AutoComplete ...
178
179
180
181
182
              },
              // Use for AutoComplete
              autoComplete: {
                  type: Boolean,
                  default: false
0460a1e8   梁灏   fixed #812
183
184
185
              },
              name: {
                  type: String
acb79ba3   梁灏   fixed #433
186
187
188
              },
              elementId: {
                  type: String
e355dd49   梁灏   add Select Component
189
190
              }
          },
c9b86944   Sergio Crisostomo   Refactor Select!
191
192
193
194
          mounted(){
              this.$on('on-select-selected', this.onOptionClick);
  
              // set the initial values if there are any
7f63e58c   Sergio Crisostomo   Make possible for...
195
              if (this.values.length > 0 && !this.remote && this.selectOptions.length > 0){
c9b86944   Sergio Crisostomo   Refactor Select!
196
197
                  this.values = this.values.map(this.getOptionData);
              }
7f63e58c   Sergio Crisostomo   Make possible for...
198
199
200
201
  
              if (this.values.length > 0 && this.selectOptions.length === 0){
                  this.hasExpectedValue = this.values;
              }
c9b86944   Sergio Crisostomo   Refactor Select!
202
          },
e355dd49   梁灏   add Select Component
203
          data () {
c9b86944   Sergio Crisostomo   Refactor Select!
204
  
e355dd49   梁灏   add Select Component
205
206
              return {
                  prefixCls: prefixCls,
c9b86944   Sergio Crisostomo   Refactor Select!
207
208
                  values: this.getInitialValue(),
                  dropDownWidth: 0,
e355dd49   梁灏   add Select Component
209
                  visible: false,
c9b86944   Sergio Crisostomo   Refactor Select!
210
211
                  focusIndex: -1,
                  isFocused: false,
e355dd49   梁灏   add Select Component
212
                  query: '',
c9b86944   Sergio Crisostomo   Refactor Select!
213
214
215
216
217
                  initialLabel: this.label,
                  hasMouseHoverHead: false,
                  slotOptions: this.$slots.default,
                  caretPosition: -1,
                  lastRemoteQuery: '',
7f63e58c   Sergio Crisostomo   Make possible for...
218
                  hasExpectedValue: false,
45bcc14d   Sergio Crisostomo   prevent calling r...
219
                  preventRemoteCall: false,
b0893113   jingsam   :art: add eslint
220
              };
e355dd49   梁灏   add Select Component
221
222
223
224
          },
          computed: {
              classes () {
                  return [
4b7138b9   梁灏   fixed some bugs
225
                      `${prefixCls}`,
e355dd49   梁灏   add Select Component
226
                      {
4b7138b9   梁灏   fixed some bugs
227
228
229
230
231
232
                          [`${prefixCls}-visible`]: this.visible,
                          [`${prefixCls}-disabled`]: this.disabled,
                          [`${prefixCls}-multiple`]: this.multiple,
                          [`${prefixCls}-single`]: !this.multiple,
                          [`${prefixCls}-show-clear`]: this.showCloseIcon,
                          [`${prefixCls}-${this.size}`]: !!this.size
e355dd49   梁灏   add Select Component
233
                      }
b0893113   jingsam   :art: add eslint
234
                  ];
e355dd49   梁灏   add Select Component
235
              },
ecaf8d51   梁灏   Date add transfer...
236
237
238
              dropdownCls () {
                  return {
                      [prefixCls + '-dropdown-transfer']: this.transfer,
fed3e09d   梁灏   add AutoComplete ...
239
240
241
242
243
244
                      [prefixCls + '-multiple']: this.multiple && this.transfer,
                      ['ivu-auto-complete']: this.autoComplete,
                  };
              },
              selectionCls () {
                  return {
c9b86944   Sergio Crisostomo   Refactor Select!
245
246
                      [`${prefixCls}-selection`]: !this.autoComplete,
                      [`${prefixCls}-selection-focused`]: this.isFocused
ecaf8d51   梁灏   Date add transfer...
247
248
                  };
              },
e5337c81   梁灏   fixed some compon...
249
              localeNotFoundText () {
c9b86944   Sergio Crisostomo   Refactor Select!
250
                  if (typeof this.notFoundText === 'undefined') {
e5337c81   梁灏   fixed some compon...
251
252
253
254
                      return this.t('i.select.noMatch');
                  } else {
                      return this.notFoundText;
                  }
f89dd9c2   梁灏   Paeg、Select add p...
255
              },
01b54e30   梁灏   Select support re...
256
              localeLoadingText () {
c9b86944   Sergio Crisostomo   Refactor Select!
257
                  if (typeof this.loadingText === 'undefined') {
01b54e30   梁灏   Select support re...
258
259
260
261
262
                      return this.t('i.select.loading');
                  } else {
                      return this.loadingText;
                  }
              },
f89dd9c2   梁灏   Paeg、Select add p...
263
264
              transitionName () {
                  return this.placement === 'bottom' ? 'slide-up' : 'slide-down';
ec98f3c3   梁灏   update Select
265
266
267
              },
              dropVisible () {
                  let status = true;
bc348e7e   Sergio Crisostomo   adapt to auto-com...
268
269
                  const noOptions = !this.selectOptions || this.selectOptions.length === 0;
                  if (!this.loading && this.remote && this.query === '' && noOptions) status = false;
fed3e09d   梁灏   add AutoComplete ...
270
  
bc348e7e   Sergio Crisostomo   adapt to auto-com...
271
                  if (this.autoComplete && noOptions) status = false;
fed3e09d   梁灏   add AutoComplete ...
272
  
ec98f3c3   梁灏   update Select
273
                  return this.visible && status;
29264399   梁灏   update Select
274
              },
c9b86944   Sergio Crisostomo   Refactor Select!
275
276
              showNotFoundLabel () {
                  const {loading, remote, selectOptions} = this;
bc348e7e   Sergio Crisostomo   adapt to auto-com...
277
                  return selectOptions && selectOptions.length === 0 && (!remote || (remote && !loading));
e355dd49   梁灏   add Select Component
278
              },
c9b86944   Sergio Crisostomo   Refactor Select!
279
280
281
              publicValue(){
                  if (this.labelInValue){
                      return this.multiple ? this.values : this.values[0];
e355dd49   梁灏   add Select Component
282
                  } else {
c9b86944   Sergio Crisostomo   Refactor Select!
283
                      return this.multiple ? this.values.map(option => option.value) : (this.values[0] || {}).value;
e355dd49   梁灏   add Select Component
284
285
                  }
              },
c9b86944   Sergio Crisostomo   Refactor Select!
286
287
288
289
290
291
292
              canBeCleared(){
                  const uiStateMatch = this.hasMouseHoverHead || this.active;
                  const qualifiesForClear = !this.multiple && this.clearable;
                  return uiStateMatch && qualifiesForClear && this.reset; // we return a function
              },
              selectOptions() {
                  const selectOptions = [];
06a74f9e   Sergio Crisostomo   Allow select to n...
293
                  const slotOptions = (this.slotOptions || []);
c9b86944   Sergio Crisostomo   Refactor Select!
294
295
296
                  let optionCounter = -1;
                  const currentIndex = this.focusIndex;
                  const selectedValues = this.values.map(({value}) => value);
06a74f9e   Sergio Crisostomo   Allow select to n...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
                  if (this.autoComplete) {
                      const copyChildren = (node, fn) => {
                          return {
                              ...node,
                              children: (node.children || []).map(fn).map(child => copyChildren(child, fn))
                          };
                      };
                      const autoCompleteOptions = extractOptions(slotOptions);
                      const selectedSlotOption = autoCompleteOptions[currentIndex];
  
                      return slotOptions.map(node => copyChildren(node, (child) => {
                          if (child !== selectedSlotOption) return child;
                          return {
                              ...child,
                              componentOptions: {
                                  ...child.componentOptions,
                                  propsData: {
                                      ...child.componentOptions.propsData,
                                      isFocused: true,
                                  }
                              }
                          };
                      }));
                  }
bc348e7e   Sergio Crisostomo   adapt to auto-com...
321
  
06a74f9e   Sergio Crisostomo   Allow select to n...
322
                  for (let option of slotOptions) {
e355dd49   梁灏   add Select Component
323
  
b6c069ca   Sergio Crisostomo   reset query if op...
324
325
                      const cOptions = option.componentOptions;
                      if (!cOptions) continue;
b6c069ca   Sergio Crisostomo   reset query if op...
326
327
                      if (cOptions.tag.match(optionGroupRegexp)){
                          let children = cOptions.children;
e355dd49   梁灏   add Select Component
328
  
c9b86944   Sergio Crisostomo   Refactor Select!
329
330
331
332
333
334
                          // remove filtered children
                          if (this.filterable){
                              children = children.filter(
                                  ({componentOptions}) => this.validateOption(componentOptions)
                              );
                          }
e355dd49   梁灏   add Select Component
335
  
b6c069ca   Sergio Crisostomo   reset query if op...
336
                          cOptions.children = children.map(opt => {
c9b86944   Sergio Crisostomo   Refactor Select!
337
338
339
                              optionCounter = optionCounter + 1;
                              return this.processOption(opt, selectedValues, optionCounter === currentIndex);
                          });
3e855e34   梁灏   fixed #46
340
  
c9b86944   Sergio Crisostomo   Refactor Select!
341
                          // keep the group if it still has children
b6c069ca   Sergio Crisostomo   reset query if op...
342
                          if (cOptions.children.length > 0) selectOptions.push({...option});
c9b86944   Sergio Crisostomo   Refactor Select!
343
344
                      } else {
                          // ignore option if not passing filter
b6c069ca   Sergio Crisostomo   reset query if op...
345
                          const optionPassesFilter = this.filterable ? this.validateOption(cOptions) : option;
c9b86944   Sergio Crisostomo   Refactor Select!
346
                          if (!optionPassesFilter) continue;
3e855e34   梁灏   fixed #46
347
  
c9b86944   Sergio Crisostomo   Refactor Select!
348
349
                          optionCounter = optionCounter + 1;
                          selectOptions.push(this.processOption(option, selectedValues, optionCounter === currentIndex));
3e855e34   梁灏   fixed #46
350
                      }
e355dd49   梁灏   add Select Component
351
352
                  }
  
c9b86944   Sergio Crisostomo   Refactor Select!
353
                  return selectOptions;
e355dd49   梁灏   add Select Component
354
              },
c9b86944   Sergio Crisostomo   Refactor Select!
355
              flatOptions(){
06a74f9e   Sergio Crisostomo   Allow select to n...
356
                  return extractOptions(this.selectOptions);
c9b86944   Sergio Crisostomo   Refactor Select!
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
              },
              selectTabindex(){
                  return this.disabled || this.filterable ? -1 : 0;
              },
              remote(){
                  return typeof this.remoteMethod === 'function';
              }
          },
          methods: {
              setQuery(query){ // PUBLIC API
                  if (query) {
                      this.onQueryChange(query);
                      return;
                  }
                  if (query === null) {
                      this.onQueryChange('');
                      this.values = [];
e355dd49   梁灏   add Select Component
374
375
                  }
              },
c9b86944   Sergio Crisostomo   Refactor Select!
376
377
378
379
380
              clearSingleSelect(){ // PUBLIC API
                  if (this.clearable) this.values = [];
              },
              getOptionData(value){
                  const option = this.flatOptions.find(({componentOptions}) => componentOptions.propsData.value === value);
7f63e58c   Sergio Crisostomo   Make possible for...
381
                  if (!option) return null;
c9b86944   Sergio Crisostomo   Refactor Select!
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
                  const textContent = option.componentOptions.children.reduce((str, child) => str + (child.text || ''), '');
                  const label = option.componentOptions.propsData.label || textContent || '';
                  return {
                      value: value,
                      label: label,
                  };
              },
              getInitialValue(){
                  const {multiple, value} = this;
                  let initialValue = Array.isArray(value) ? value : [value];
                  if (!multiple && (typeof initialValue[0] === 'undefined' || String(initialValue[0]).trim() === '')) initialValue = [];
                  return initialValue;
              },
              processOption(option, values, isFocused){
                  if (!option.componentOptions) return option;
                  const optionValue = option.componentOptions.propsData.value;
                  const disabled = option.componentOptions.propsData.disabled;
                  const isSelected = values.includes(optionValue);
  
                  const propsData = {
                      ...option.componentOptions.propsData,
                      selected: isSelected,
                      isFocused: isFocused,
                      disabled: typeof disabled === 'undefined' ? false : disabled !== false,
                  };
e355dd49   梁灏   add Select Component
407
  
c9b86944   Sergio Crisostomo   Refactor Select!
408
409
410
411
412
                  return {
                      ...option,
                      componentOptions: {
                          ...option.componentOptions,
                          propsData: propsData
e355dd49   梁灏   add Select Component
413
                      }
c9b86944   Sergio Crisostomo   Refactor Select!
414
415
                  };
              },
e355dd49   梁灏   add Select Component
416
  
c9b86944   Sergio Crisostomo   Refactor Select!
417
418
419
420
421
422
              validateOption({elm, propsData}){
                  const value = propsData.value;
                  const label = propsData.label || '';
                  const textContent = elm && elm.textContent || '';
                  const stringValues = JSON.stringify([value, label, textContent]);
                  return stringValues.toLowerCase().includes(this.query.toLowerCase());
e355dd49   梁灏   add Select Component
423
              },
d87ce40a   梁灏   update Select
424
  
c9b86944   Sergio Crisostomo   Refactor Select!
425
426
427
              toggleMenu (e, force) {
                  if (this.disabled || this.autoComplete) {
                      return false;
d87ce40a   梁灏   update Select
428
                  }
c9b86944   Sergio Crisostomo   Refactor Select!
429
                  this.focusIndex = -1;
d87ce40a   梁灏   update Select
430
  
c9b86944   Sergio Crisostomo   Refactor Select!
431
432
433
                  this.visible = typeof force !== 'undefined' ? force : !this.visible;
                  if (this.visible){
                      this.dropDownWidth = this.$el.getBoundingClientRect().width;
cf753854   Sergio Crisostomo   Corrections after...
434
                      this.broadcast('Drop', 'on-update-popper');
e4ce9917   梁灏   update Select com...
435
                  }
e355dd49   梁灏   add Select Component
436
              },
c9b86944   Sergio Crisostomo   Refactor Select!
437
438
              hideMenu () {
                  this.toggleMenu(null, false);
e355dd49   梁灏   add Select Component
439
              },
c9b86944   Sergio Crisostomo   Refactor Select!
440
441
442
443
              onClickOutside(event){
                  if (this.visible) {
  
                      if (this.filterable) {
ae7579e9   Sergio Crisostomo   Fix input getters...
444
                          const input = this.$el.querySelector('input[type="text"]');
c9b86944   Sergio Crisostomo   Refactor Select!
445
446
447
448
                          this.caretPosition = input.selectionStart;
                          this.$nextTick(() => {
                              const caretPosition = this.caretPosition === -1 ? input.value.length : this.caretPosition;
                              input.setSelectionRange(caretPosition, caretPosition);
e355dd49   梁灏   add Select Component
449
450
451
                          });
                      }
  
ae7579e9   Sergio Crisostomo   Fix input getters...
452
                      if (!this.autoComplete) event.stopPropagation();
c9b86944   Sergio Crisostomo   Refactor Select!
453
454
455
456
457
458
                      event.preventDefault();
                      this.hideMenu();
                      this.isFocused = true;
                  } else {
                      this.caretPosition = -1;
                      this.isFocused = false;
e355dd49   梁灏   add Select Component
459
460
                  }
              },
c9b86944   Sergio Crisostomo   Refactor Select!
461
462
              reset(){
                  this.values = [];
e355dd49   梁灏   add Select Component
463
464
              },
              handleKeydown (e) {
c9b86944   Sergio Crisostomo   Refactor Select!
465
466
467
468
                  if (e.key === 'Backspace'){
                      return; // so we don't call preventDefault
                  }
  
e355dd49   梁灏   add Select Component
469
                  if (this.visible) {
c9b86944   Sergio Crisostomo   Refactor Select!
470
471
472
473
474
                      e.preventDefault();
                      if (e.key === 'Tab'){
                          e.stopPropagation();
                      }
  
e355dd49   梁灏   add Select Component
475
                      // Esc slide-up
c9b86944   Sergio Crisostomo   Refactor Select!
476
                      if (e.key === 'Escape') {
e355dd49   梁灏   add Select Component
477
478
479
                          this.hideMenu();
                      }
                      // next
c9b86944   Sergio Crisostomo   Refactor Select!
480
481
                      if (e.key === 'ArrowUp') {
                          this.navigateOptions(-1);
e355dd49   梁灏   add Select Component
482
483
                      }
                      // prev
c9b86944   Sergio Crisostomo   Refactor Select!
484
485
                      if (e.key === 'ArrowDown') {
                          this.navigateOptions(1);
e355dd49   梁灏   add Select Component
486
487
                      }
                      // enter
c9b86944   Sergio Crisostomo   Refactor Select!
488
489
490
491
                      if (e.key === 'Enter' && this.focusIndex > -1) {
                          const optionComponent = this.flatOptions[this.focusIndex];
                          const option = this.getOptionData(optionComponent.componentOptions.propsData.value);
                          this.onOptionClick(option);
e355dd49   梁灏   add Select Component
492
                      }
c9b86944   Sergio Crisostomo   Refactor Select!
493
494
495
                  } else {
                      const keysThatCanOpenSelect = ['ArrowUp', 'ArrowDown'];
                      if (keysThatCanOpenSelect.includes(e.key)) this.toggleMenu(null, true);
e355dd49   梁灏   add Select Component
496
497
                  }
  
e355dd49   梁灏   add Select Component
498
  
c9b86944   Sergio Crisostomo   Refactor Select!
499
500
501
              },
              navigateOptions(direction){
                  const optionsLength = this.flatOptions.length - 1;
e4ebd304   梁灏   update Select com...
502
  
c9b86944   Sergio Crisostomo   Refactor Select!
503
504
505
                  let index = this.focusIndex + direction;
                  if (index < 0) index = optionsLength;
                  if (index > optionsLength) index = 0;
e355dd49   梁灏   add Select Component
506
  
c9b86944   Sergio Crisostomo   Refactor Select!
507
508
509
510
511
512
513
                  // find nearest option in case of disabled options in between
                  if (direction > 0){
                      let nearestActiveOption = -1;
                      for (let i = 0; i < this.flatOptions.length; i++){
                          const optionIsActive = !this.flatOptions[i].componentOptions.propsData.disabled;
                          if (optionIsActive) nearestActiveOption = i;
                          if (nearestActiveOption >= index) break;
e355dd49   梁灏   add Select Component
514
                      }
c9b86944   Sergio Crisostomo   Refactor Select!
515
516
517
518
519
520
521
                      index = nearestActiveOption;
                  } else {
                      let nearestActiveOption = this.flatOptions.length;
                      for (let i = optionsLength; i >= 0; i--){
                          const optionIsActive = !this.flatOptions[i].componentOptions.propsData.disabled;
                          if (optionIsActive) nearestActiveOption = i;
                          if (nearestActiveOption <= index) break;
e4ebd304   梁灏   update Select com...
522
                      }
c9b86944   Sergio Crisostomo   Refactor Select!
523
                      index = nearestActiveOption;
e355dd49   梁灏   add Select Component
524
                  }
e355dd49   梁灏   add Select Component
525
  
c9b86944   Sergio Crisostomo   Refactor Select!
526
                  this.focusIndex = index;
e4ebd304   梁灏   update Select com...
527
              },
c9b86944   Sergio Crisostomo   Refactor Select!
528
529
530
531
532
533
              onOptionClick(option) {
                  if (this.multiple){
  
                      // keep the query for remote select
                      if (this.remote) this.lastRemoteQuery = this.lastRemoteQuery || this.query;
                      else this.lastRemoteQuery = '';
e4ebd304   梁灏   update Select com...
534
  
c9b86944   Sergio Crisostomo   Refactor Select!
535
536
537
                      const valueIsSelected = this.values.find(({value}) => value === option.value);
                      if (valueIsSelected){
                          this.values = this.values.filter(({value}) => value !== option.value);
e4ebd304   梁灏   update Select com...
538
                      } else {
c9b86944   Sergio Crisostomo   Refactor Select!
539
                          this.values = this.values.concat(option);
e4ebd304   梁灏   update Select com...
540
                      }
c9b86944   Sergio Crisostomo   Refactor Select!
541
542
543
544
545
546
547
548
549
  
                      this.isFocused = true; // so we put back focus after clicking with mouse on option elements
                  } else {
                      this.values = [option];
                      this.lastRemoteQuery = '';
                      this.hideMenu();
                  }
  
                  if (this.filterable){
ae7579e9   Sergio Crisostomo   Fix input getters...
550
551
                      const inputField = this.$el.querySelector('input[type="text"]');
                      if (!this.autoComplete) this.$nextTick(() => inputField.focus());
e4ce9917   梁灏   update Select com...
552
                  }
88ef37f5   Aresn   fixed in multiple...
553
                  this.broadcast('Drop', 'on-update-popper');
3e855e34   梁灏   fixed #46
554
              },
c9b86944   Sergio Crisostomo   Refactor Select!
555
              onQueryChange(query) {
2f0b086d   梁灏   fixed #116
556
                  this.query = query;
c9b86944   Sergio Crisostomo   Refactor Select!
557
                  if (this.query.length > 0) this.visible = true;
9c3a3e7d   YikaJ   更新 Select 组件
558
              },
c9b86944   Sergio Crisostomo   Refactor Select!
559
560
561
              toggleHeaderFocus({type}){
                  if (this.disabled) {
                      return;
15b72d31   梁灏   fixed #566
562
                  }
c9b86944   Sergio Crisostomo   Refactor Select!
563
                  this.isFocused = type === 'focus';
98bf25b3   梁灏   fixed #1286
564
              },
c9b86944   Sergio Crisostomo   Refactor Select!
565
566
              updateSlotOptions(){
                  this.slotOptions = this.$slots.default;
e355dd49   梁灏   add Select Component
567
568
              }
          },
e355dd49   梁灏   add Select Component
569
          watch: {
c9b86944   Sergio Crisostomo   Refactor Select!
570
571
572
573
574
575
              value(value){
                  const {getInitialValue, getOptionData, publicValue} = this;
  
                  if (value === '') this.values = [];
                  else if (JSON.stringify(value) !== JSON.stringify(publicValue)) {
                      this.$nextTick(() => this.values = getInitialValue().map(getOptionData));
e355dd49   梁灏   add Select Component
576
                  }
c9b86944   Sergio Crisostomo   Refactor Select!
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
              },
              values(now, before){
                  const newValue = JSON.stringify(now);
                  const oldValue = JSON.stringify(before);
                  const shouldEmitInput = newValue !== oldValue;
  
                  if (shouldEmitInput) {
                      // v-model is always just the value, event with labelInValue === true
                      const vModelValue = this.labelInValue ?
                          (this.multiple ? this.publicValue.map(({value}) => value)
                          :
                          this.publicValue.value) : this.publicValue;
                      this.$emit('input', vModelValue); // to update v-model
                      this.$emit('on-change', this.publicValue);
                      this.dispatch('FormItem', 'on-form-change', this.publicValue);
219e5c92   梁灏   fixed #957
592
                  }
e355dd49   梁灏   add Select Component
593
              },
c9b86944   Sergio Crisostomo   Refactor Select!
594
595
596
597
              query (query) {
                  this.$emit('on-query-change', query);
                  const {remoteMethod, lastRemoteQuery} = this;
                  const hasValidQuery = query !== '' && (query !== lastRemoteQuery || !lastRemoteQuery);
45bcc14d   Sergio Crisostomo   prevent calling r...
598
599
                  const shouldCallRemoteMethod = remoteMethod && hasValidQuery && !this.preventRemoteCall;
                  this.preventRemoteCall = false; // remove the flag
c9b86944   Sergio Crisostomo   Refactor Select!
600
601
602
603
604
605
606
607
608
  
                  if (shouldCallRemoteMethod){
                      this.focusIndex = -1;
                      const promise = this.remoteMethod(query);
                      this.initialLabel = '';
                      if (promise && promise.then){
                          promise.then(options => {
                              if (options) this.options = options;
                          });
b7cf983e   梁灏   update Select com...
609
                      }
e355dd49   梁灏   add Select Component
610
                  }
c9b86944   Sergio Crisostomo   Refactor Select!
611
                  if (query !== '' && this.remote) this.lastRemoteQuery = query;
e4ebd304   梁灏   update Select com...
612
              },
c9b86944   Sergio Crisostomo   Refactor Select!
613
614
615
616
617
618
              loading(state){
                  if (state === false){
                      this.updateSlotOptions();
                  }
              },
              isFocused(focused){
ae7579e9   Sergio Crisostomo   Fix input getters...
619
                  const el = this.filterable ? this.$el.querySelector('input[type="text"]') : this.$el;
c9b86944   Sergio Crisostomo   Refactor Select!
620
                  el[this.isFocused ? 'focus' : 'blur']();
d8bb1771   windywany   let select compon...
621
  
c9b86944   Sergio Crisostomo   Refactor Select!
622
623
624
625
                  // restore query value in filterable single selects
                  const [selectedOption] = this.values;
                  if (selectedOption && this.filterable && !this.multiple && !focused){
                      const selectedLabel = selectedOption.label || selectedOption.value;
9ca6671c   Sergio Crisostomo   Check for selecte...
626
                      if (selectedLabel && this.query !== selectedLabel) {
45bcc14d   Sergio Crisostomo   prevent calling r...
627
628
629
                          this.preventRemoteCall = true;
                          this.query = selectedLabel;
                      }
c9b86944   Sergio Crisostomo   Refactor Select!
630
631
632
                  }
              },
              focusIndex(index){
06a74f9e   Sergio Crisostomo   Allow select to n...
633
                  if (index < 0 || this.autoComplete) return;
c9b86944   Sergio Crisostomo   Refactor Select!
634
635
636
637
638
                  // update scroll
                  const optionValue = this.flatOptions[index].componentOptions.propsData.value;
                  const optionInstance = findChild(this, ({$options}) => {
                      return $options.componentName === 'select-item' && $options.propsData.value === optionValue;
                  });
e4ce9917   梁灏   update Select com...
639
  
c9b86944   Sergio Crisostomo   Refactor Select!
640
641
642
643
644
645
646
                  let bottomOverflowDistance = optionInstance.$el.getBoundingClientRect().bottom - this.$refs.dropdown.$el.getBoundingClientRect().bottom;
                  let topOverflowDistance = optionInstance.$el.getBoundingClientRect().top - this.$refs.dropdown.$el.getBoundingClientRect().top;
                  if (bottomOverflowDistance > 0) {
                      this.$refs.dropdown.$el.scrollTop += bottomOverflowDistance;
                  }
                  if (topOverflowDistance < 0) {
                      this.$refs.dropdown.$el.scrollTop += topOverflowDistance;
01b54e30   梁灏   Select support re...
647
                  }
cf753854   Sergio Crisostomo   Corrections after...
648
649
650
              },
              dropVisible(open){
                  this.broadcast('Drop', open ? 'on-update-popper' : 'on-destroy-popper');
7f63e58c   Sergio Crisostomo   Make possible for...
651
              },
f7f65c84   Sergio Crisostomo   reset query only ...
652
              selectOptions(){
7f63e58c   Sergio Crisostomo   Make possible for...
653
654
655
656
                  if (this.hasExpectedValue){
                      this.values = this.values.map(this.getOptionData);
                      this.hasExpectedValue = false;
                  }
b6c069ca   Sergio Crisostomo   reset query if op...
657
  
f7f65c84   Sergio Crisostomo   reset query only ...
658
                  if (this.slotOptions && this.slotOptions.length === 0){
b6c069ca   Sergio Crisostomo   reset query if op...
659
660
                      this.query = '';
                  }
e355dd49   梁灏   add Select Component
661
662
              }
          }
b0893113   jingsam   :art: add eslint
663
      };
d6342fe1   jingsam   fixed ie bug
664
  </script>