@afeefa/vue-app 0.0.121 → 0.0.122

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1 @@
1
- 0.0.121
1
+ 0.0.122
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.121",
3
+ "version": "0.0.122",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
@@ -2,12 +2,13 @@
2
2
  <div :class="['a-search-select', widthClass]">
3
3
  <div
4
4
  class="activator"
5
- style="width: max-content;"
6
5
  @click="open"
7
6
  >
8
7
  <slot
9
8
  v-if="!autoOpen"
10
9
  name="activator"
10
+ :open="open"
11
+ :close="close"
11
12
  >
12
13
  <a-icon class="contextButton">
13
14
  $dotsHorizontalIcon
@@ -15,6 +16,12 @@
15
16
  </slot>
16
17
  </div>
17
18
 
19
+ <v-overlay
20
+ :value="isOpen"
21
+ :z-index="299"
22
+ :opacity="0"
23
+ />
24
+
18
25
  <div :class="panelCssClass">
19
26
  <div
20
27
  v-if="isOpen"
@@ -24,7 +31,7 @@
24
31
  <div class="background elevation-6" />
25
32
 
26
33
  <search-select-filters
27
- v-if="filtersInitialized"
34
+ v-if="filtersInitialized && showFilters"
28
35
  :filters="filters"
29
36
  :count="count"
30
37
  >
@@ -32,6 +39,9 @@
32
39
  name="filters"
33
40
  :filters="filters"
34
41
  :count="count"
42
+ :onSearchInputKey="{
43
+ 'keydown': searchFilterKeyDown
44
+ }"
35
45
  />
36
46
  </search-select-filters>
37
47
 
@@ -39,7 +49,7 @@
39
49
  absolute
40
50
  top
41
51
  left
42
- class="loadingIndicator"
52
+ :class="['loadingIndicator', {showFilters}]"
43
53
  :isLoading="isLoading"
44
54
  />
45
55
  </div>
@@ -48,21 +58,23 @@
48
58
  <div :class="listCssClass">
49
59
  <search-select-list
50
60
  v-if="isOpen"
61
+ ref="list"
51
62
  :listAction="listAction"
52
63
  :q="q"
53
64
  :selectedItems="selectedItems"
54
65
  :events="false"
55
66
  :history="false"
56
67
  :filterSource="filterSource"
57
- :loadOnlyIfKeyword="_loadOnlyIfKeyword"
68
+ :loadOnlyIfKeyword="loadOnlyIfKeyword"
58
69
  :filters.sync="filters"
59
70
  :count.sync="count"
60
71
  :isLoading.sync="isLoading"
61
72
  :style="cwm_widthStyle"
73
+ @onLoad="onLoad"
74
+ @enter="selectItem"
75
+ @backtab="setFocusToSearchInput"
62
76
  >
63
77
  <template #header>
64
- <div />
65
-
66
78
  <slot name="header" />
67
79
  </template>
68
80
 
@@ -101,9 +113,13 @@ import { ComponentWidthMixin } from './mixins/ComponentWidthMixin'
101
113
  props: [
102
114
  'listAction',
103
115
  'q',
104
- 'width',
105
- 'loadOnlyIfKeyword',
106
116
  {
117
+ diffXControls: '-1rem',
118
+ diffYControls: '-1rem',
119
+ getSearchInput: {
120
+ default: () => () => {}
121
+ },
122
+ loadOnlyIfKeyword: false,
107
123
  autoOpen: false,
108
124
  closeOnSelect: true,
109
125
  selectedItems: []
@@ -123,6 +139,7 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
123
139
  isLoading = false
124
140
  filters = []
125
141
  count = 0
142
+ showFilters = false
126
143
 
127
144
  mounted () {
128
145
  if (this.autoOpen) {
@@ -173,10 +190,6 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
173
190
  return container.querySelector('.' + this.listCssClass)
174
191
  }
175
192
 
176
- get _loadOnlyIfKeyword () {
177
- return this.loadOnlyIfKeyword === undefined || this.loadOnlyIfKeyword
178
- }
179
-
180
193
  positionize () {
181
194
  const position = new PositionConfig()
182
195
  .setAnchor(this, '.activator')
@@ -186,7 +199,7 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
186
199
  )
187
200
  .anchorTop().targetTop()
188
201
  .anchorLeft().targetLeft()
189
- .diffX('-1rem').diffY('-1rem')
202
+ .diffX(this.diffXControls).diffY(this.diffYControls)
190
203
  .onPosition(this.onListPositionChanged)
191
204
 
192
205
  this.urp_registerPositionWatcher(position)
@@ -216,6 +229,10 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
216
229
  }
217
230
 
218
231
  open () {
232
+ this.showFilters = false
233
+
234
+ this.$emit('beforeOpen')
235
+
219
236
  window.addEventListener('mousedown', this.onClickOutside)
220
237
 
221
238
  const container = this.getContainer()
@@ -253,6 +270,13 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
253
270
  this.$emit('close')
254
271
  }
255
272
 
273
+ selectItem (model) {
274
+ if (this.closeOnSelect) {
275
+ this.close()
276
+ }
277
+ this.$emit('select', model)
278
+ }
279
+
256
280
  selectHandler (model) {
257
281
  return event => {
258
282
  if (this.closeOnSelect) {
@@ -266,6 +290,7 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
266
290
 
267
291
  coe_cancelOnEsc () {
268
292
  this.close()
293
+ return false // stop esc propagation
269
294
  }
270
295
 
271
296
  onClickOutside (e) {
@@ -300,12 +325,42 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
300
325
  const controls = this.popUp.querySelector('.controls')
301
326
  const list = this.listPopUp.querySelector('.searchSelectList')
302
327
  const padding = '.5rem'
328
+ const vPadding = this.showFilters ? '.5rem' : '0px'
303
329
 
304
330
  const top = Math.min(0, list.offsetTop - controls.offsetTop)
305
331
  background.style.left = `calc(0px - ${padding})`
306
- background.style.top = `calc(${top}px - ${padding})`
332
+ background.style.top = `calc(${top}px - ${vPadding})`
307
333
  background.style.width = `calc(${list.offsetWidth}px + 2 * ${padding})`
308
- background.style.height = `calc(${controls.clientHeight}px + ${list.clientHeight}px + 3 * ${padding})`
334
+ background.style.height = `calc(${controls.clientHeight}px + ${list.clientHeight}px + 2 * ${padding} + ${vPadding})`
335
+ }
336
+
337
+ onLoad ({models, meta}) {
338
+ this.showFilters = meta.used_filters.page_size < meta.count_all
339
+ if (!this.showFilters) {
340
+ this.setFocusToList()
341
+ }
342
+ }
343
+
344
+ setFocusToList () {
345
+ this.$refs.list.setFocus()
346
+ }
347
+
348
+ setFocusToSearchInput () {
349
+ const searchInput = this.getSearchInput()
350
+ if (searchInput) {
351
+ searchInput.setFocus(true)
352
+ }
353
+ }
354
+
355
+ setWidth (width) {
356
+ this.cwm_width_ = width
357
+ }
358
+
359
+ searchFilterKeyDown (event) {
360
+ if (['Tab', 'ArrowUp', 'ArrowDown'].includes(event.key)) {
361
+ this.setFocusToList()
362
+ event.preventDefault()
363
+ }
309
364
  }
310
365
  }
311
366
  </script>
@@ -315,16 +370,23 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
315
370
  .background {
316
371
  background: white;
317
372
  position: absolute;
318
- z-index: -1;
373
+ z-index: 300;
319
374
  }
320
375
 
321
376
  .controls {
322
377
  width: 400px;
323
378
  position: absolute;
324
- z-index: 300;
379
+ z-index: 301;
325
380
  display: block;
381
+
326
382
  padding: 0 .5rem;
327
383
 
384
+ > .searchSelectFilters {
385
+ padding: .5rem 0;
386
+ position: relative;
387
+ z-index: 302;
388
+ }
389
+
328
390
  :deep(.a-row) {
329
391
  overflow: unset;
330
392
  }
@@ -344,6 +406,7 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
344
406
  &:not(.selected) {
345
407
  cursor: pointer;
346
408
  }
409
+
347
410
  &.selected {
348
411
  pointer-events: none;
349
412
  }
@@ -351,7 +414,13 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
351
414
  }
352
415
 
353
416
  .loadingIndicator {
354
- margin: -.5rem;
417
+ z-index: 303;
418
+ margin: 0 -.5rem;
355
419
  width: calc(100% + 1rem);
420
+ transition: none;
421
+
422
+ &.showFilters {
423
+ margin-top: -.5rem;
424
+ }
356
425
  }
357
426
  </style>
@@ -46,6 +46,7 @@ export default class ATableRow extends Vue {
46
46
  > * {
47
47
  padding: .15rem;
48
48
  padding-right: 1.5rem;
49
+
49
50
  &:last-child {
50
51
  padding-right: .1rem;
51
52
  }
@@ -54,8 +55,10 @@ export default class ATableRow extends Vue {
54
55
 
55
56
  &.border {
56
57
  border-bottom: 1px solid #E5E5E5;
58
+
57
59
  > * {
58
60
  padding: .4rem 1.5rem .4rem .4rem;
61
+
59
62
  &:last-child {
60
63
  padding-right: .4rem;
61
64
  }
@@ -70,6 +73,10 @@ export default class ATableRow extends Vue {
70
73
  background: #F4F4F4;
71
74
  }
72
75
 
76
+ &.active {
77
+ background: #EEEEFF;
78
+ }
79
+
73
80
  &:last-child {
74
81
  border: none;
75
82
  }
@@ -153,8 +153,8 @@ export default class ATextField extends Mixins(ComponentWidthMixin) {
153
153
  this.setFocus()
154
154
  }
155
155
 
156
- setFocus () {
157
- const focus = this.focus || false
156
+ setFocus (force = false) {
157
+ const focus = this.focus || force // set focus if this.focus or else if forced from outside
158
158
  if (focus) {
159
159
  // if run in a v-dialog, the dialog background would
160
160
  // steal the focus without requestAnimationFrame
@@ -165,8 +165,8 @@ export default class ATextField extends Mixins(ComponentWidthMixin) {
165
165
  }
166
166
 
167
167
  get validationRules () {
168
- if (this.$attrs.rules) {
169
- return this.$attrs.rules
168
+ if (this.rules) {
169
+ return this.rules
170
170
  }
171
171
  const label = this.$attrs.label
172
172
  return (this.validator && this.validator.getRules(label)) || []
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <v-form
3
+ ref="form"
3
4
  v-model="valid"
4
5
  autocomplete="off"
5
6
  @submit.prevent
@@ -33,7 +34,6 @@ export default class EditForm extends Vue {
33
34
  lastJson = null
34
35
  forcedUnchange = false
35
36
 
36
-
37
37
  created () {
38
38
  this.reset()
39
39
  }
@@ -94,8 +94,8 @@ export default class EditForm extends Vue {
94
94
  if (this.forcedUnchange) {
95
95
  return false
96
96
  }
97
- // console.log(this.json)
98
97
  // console.log(this.lastJson)
98
+ // console.log(this.json)
99
99
  return this.json !== this.lastJson
100
100
  }
101
101
 
@@ -1,42 +1,70 @@
1
1
  <template>
2
- <div>
3
- <a-search-select
4
- :listConfig="listConfig"
5
- :q="q"
6
- v-on="$listeners"
7
- >
8
- <template #activator>
9
- <slot name="activator" />
10
- </template>
11
-
12
- <template #filters="{filters, count}">
13
- <slot
14
- name="filters"
15
- :filters="filters"
16
- :count="count"
2
+ <a-search-select
3
+ ref="select"
4
+ :listAction="listAction"
5
+ :selectedItems="selectedItems"
6
+ :getSearchInput="() => $refs.searchInput"
7
+ diffXControls="-.5rem"
8
+ diffYControls="-.5rem"
9
+ @select="itemSelected"
10
+ @close="focusInput"
11
+ @beforeOpen="calculateSelectorSize"
12
+ >
13
+ <template #activator="{open}">
14
+ <a-text-field
15
+ ref="input"
16
+ v-model="inputModel"
17
+ readonly
18
+ :label="label"
19
+ :rules="validationRules"
20
+ placeholder="Mausklick oder Space-Taste zum Auswählen"
21
+ @keydown.space.prevent="open"
22
+ @keydown.down.prevent="open"
23
+ @keydown.enter.prevent="open"
24
+ />
25
+ </template>
26
+
27
+ <template #filters="{onSearchInputKey}">
28
+ <a-row gap="4">
29
+ <list-filter-search
30
+ ref="searchInput"
31
+ :focus="true"
32
+ tabindex="1"
33
+ maxWidth="100%"
34
+ :label="'Suche ' + label"
35
+ v-on="onSearchInputKey"
17
36
  />
18
- </template>
19
37
 
20
- <template #row="{ model, on }">
21
- <slot
22
- name="row"
23
- :model="model"
24
- :on="on"
38
+ <list-filter-page
39
+ :has="{page_size: false, page_number: true}"
40
+ :totalVisible="0"
25
41
  />
26
- </template>
27
- </a-search-select>
28
-
29
- <v-input
30
- ref="input"
31
- v-model="model[name]"
32
- :rules="validationRules"
33
- />
34
- </div>
42
+ </a-row>
43
+ </template>
44
+
45
+ <template #row="{ model, on }">
46
+ <v-icon
47
+ :color="model.getIcon().color"
48
+ size="1.5rem"
49
+ class="mr-2"
50
+ v-on="on"
51
+ v-text="model.getIcon().icon"
52
+ />
53
+
54
+ <div
55
+ style="width:100%;"
56
+ v-on="on"
57
+ >
58
+ {{ model.getTitle() }}
59
+ </div>
60
+ </template>
61
+ </a-search-select>
35
62
  </template>
36
63
 
37
64
  <script>
38
65
  import { Component, Mixins } from '@a-vue'
39
66
  import { FormFieldMixin } from '../FormFieldMixin'
67
+ import { ListAction } from '@a-vue/api-resources/ApiActions'
40
68
 
41
69
  @Component({
42
70
  props: ['value', 'q', 'listConfig']
@@ -44,8 +72,43 @@ import { FormFieldMixin } from '../FormFieldMixin'
44
72
  export default class FormFieldSearchSelect extends Mixins(FormFieldMixin) {
45
73
  mounted () {
46
74
  if (this.validator) {
47
- this.$refs.input.validate(true)
75
+ this.$refs.input.validate()
48
76
  }
49
77
  }
78
+
79
+ get inputModel () {
80
+ return (this.model[this.name] && this.model[this.name].getTitle()) || null
81
+ }
82
+
83
+ calculateSelectorSize () {
84
+ const input = this.$refs.input.$el
85
+ const inputWidth = input.offsetWidth
86
+ this.$refs.select.setWidth(`calc(${inputWidth}px + 1rem)`)
87
+ }
88
+
89
+ get selectedItems () {
90
+ return [this.model[this.name]].filter(a => a)
91
+ }
92
+
93
+ get listAction () {
94
+ return ListAction.fromRequest(this.field.getOptionsRequest())
95
+ }
96
+
97
+ itemSelected (model) {
98
+ this.model[this.name] = model
99
+ this.$emit('select', model)
100
+ }
101
+
102
+ focusInput () {
103
+ this.$refs.input.setFocus(true)
104
+ }
50
105
  }
51
106
  </script>
107
+
108
+
109
+ <style lang="scss" scoped>
110
+ .selectedItem,
111
+ :deep(.a-table-row) {
112
+ cursor: pointer;
113
+ }
114
+ </style>
@@ -1,5 +1,6 @@
1
1
  import { Component, Vue, Watch } from '@a-vue'
2
2
  import { ListAction } from '@a-vue/api-resources/ApiActions'
3
+ import { sleep } from '@a-vue/utils/timeout'
3
4
  import { ListViewModel } from '@afeefa/api-resources-client'
4
5
 
5
6
  import { CurrentRouteFilterSource } from './CurrentRouteFilterSource'
@@ -10,10 +11,10 @@ import { FilterSourceType } from './FilterSourceType'
10
11
  'models', 'meta', // given, if already loaded
11
12
  'listAction',
12
13
  'filterHistoryKey',
13
- 'loadOnlyIfKeyword',
14
14
  'checkBeforeLoad',
15
15
  {
16
16
  filterSource: FilterSourceType.QUERY_STRING,
17
+ loadOnlyIfKeyword: false,
17
18
  events: true,
18
19
  history: true
19
20
  }
@@ -75,6 +76,8 @@ export class ListViewMixin extends Vue {
75
76
  models: this.models_,
76
77
  meta: this.meta_
77
78
  })
79
+
80
+ this._listLoaded()
78
81
  } else {
79
82
  this.load()
80
83
  }
@@ -96,6 +99,9 @@ export class ListViewMixin extends Vue {
96
99
  _filtersInitialized () {
97
100
  }
98
101
 
102
+ _listLoaded () {
103
+ }
104
+
99
105
  filtersChanged () {
100
106
  this.load()
101
107
  }
@@ -116,10 +122,6 @@ export class ListViewMixin extends Vue {
116
122
  return this.meta_.count_search || 0
117
123
  }
118
124
 
119
- get _loadOnlyIfKeyword () {
120
- return this.loadOnlyIfKeyword
121
- }
122
-
123
125
  async load () {
124
126
  if (this.checkBeforeLoad) {
125
127
  const canLoad = await this.checkBeforeLoad()
@@ -131,7 +133,7 @@ export class ListViewMixin extends Vue {
131
133
  }
132
134
  }
133
135
 
134
- if (this._loadOnlyIfKeyword && !this.filters.q.value) {
136
+ if (this.loadOnlyIfKeyword && !this.filters.q.value) {
135
137
  this.models_ = []
136
138
  this.meta_ = {}
137
139
  this.$emit('update:count', 0)
@@ -148,6 +150,8 @@ export class ListViewMixin extends Vue {
148
150
  .dispatchGlobalLoadingEvents(this.events)
149
151
  .load()
150
152
 
153
+ // await sleep(1)
154
+
151
155
  if (!models) { // error happened
152
156
  this.isLoading = false
153
157
  this.$emit('update:isLoading', false)
@@ -170,5 +174,7 @@ export class ListViewMixin extends Vue {
170
174
  models,
171
175
  meta
172
176
  })
177
+
178
+ this._listLoaded()
173
179
  }
174
180
  }
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <a-text-field
3
+ ref="input"
3
4
  v-model="filter.value"
4
5
  :maxWidth="$attrs.maxWidth || maxWidth_"
5
6
  :label="label || 'Suche'"
@@ -8,6 +9,7 @@
8
9
  clearable
9
10
  hide-details
10
11
  @keyup.esc="clearValue"
12
+ v-on="$listeners"
11
13
  />
12
14
  </template>
13
15
 
@@ -27,5 +29,9 @@ export default class ListFilterSearch extends Mixins(ListFilterMixin) {
27
29
  this.filter.value = null
28
30
  }
29
31
  }
32
+
33
+ setFocus (force) {
34
+ this.$refs.input.setFocus(force)
35
+ }
30
36
  }
31
37
  </script>
@@ -1,5 +1,14 @@
1
1
  <template>
2
- <div :class="['searchSelectList', {isLoading}]">
2
+ <div
3
+ :class="['searchSelectList', {isLoading}]"
4
+ tabindex="0"
5
+ @keydown.down.prevent="keydown"
6
+ @keydown.up.prevent="keyup"
7
+ @keydown.enter="keyenter"
8
+ @keydown.tab.prevent.exact="keyenter"
9
+ @keydown.space.prevent="keyenter"
10
+ @keydown.tab.shift.prevent="$emit('backtab')"
11
+ >
3
12
  <template v-if="models_.length">
4
13
  <a-table v-bind="$attrs">
5
14
  <a-table-header
@@ -10,10 +19,10 @@
10
19
  </a-table-header>
11
20
 
12
21
  <a-table-row
13
- v-for="model in models_"
22
+ v-for="(model, index) in models_"
14
23
  :key="model.id"
15
24
  small
16
- :class="{selected: isSelected(model)}"
25
+ :class="['row-' + index, {selected: isSelected(model), active: activeModelIndex === index}]"
17
26
  >
18
27
  <slot
19
28
  name="row"
@@ -46,13 +55,15 @@ import { ListViewMixin } from '@a-vue/components/list/ListViewMixin'
46
55
  props: ['q', 'selectedItems']
47
56
  })
48
57
  export default class SearchSelectList extends Mixins(ListViewMixin) {
58
+ activeModelIndex = -1
59
+
49
60
  get hasHeader () {
50
61
  return this.$slots.header && this.$slots.header.length > 1
51
62
  }
52
63
 
53
64
  get showNotFound () {
54
65
  if (!this.models_.length && !this.isLoading) {
55
- if (this._loadOnlyIfKeyword && !this.filters.q.value) {
66
+ if (this.loadOnlyIfKeyword && !this.filters.q.value) {
56
67
  return false
57
68
  }
58
69
  return true
@@ -68,11 +79,67 @@ export default class SearchSelectList extends Mixins(ListViewMixin) {
68
79
  this.filters.q.value = this.q
69
80
  }
70
81
  }
82
+
83
+ setFocus () {
84
+ this.$el.focus()
85
+
86
+ if (this.models_.length) {
87
+ this.activeModelIndex = Math.max(0, this.findActiveIndexForSelectedModel())
88
+ }
89
+ }
90
+
91
+ keydown () {
92
+ this.activeModelIndex++
93
+ if (this.activeModelIndex > this.models_.length - 1) {
94
+ this.activeModelIndex = 0
95
+ }
96
+
97
+ const row = this.$el.querySelector('.row-' + this.activeModelIndex)
98
+ if (row) {
99
+ row.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
100
+ }
101
+ }
102
+
103
+ keyup () {
104
+ this.activeModelIndex--
105
+ if (this.activeModelIndex < 0) {
106
+ this.activeModelIndex = this.models_.length - 1
107
+ }
108
+
109
+ const row = this.$el.querySelector('.row-' + this.activeModelIndex)
110
+ if (row) {
111
+ row.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
112
+ }
113
+ }
114
+
115
+ keyenter () {
116
+ const model = this.models_[this.activeModelIndex]
117
+ if (model) {
118
+ this.$emit('enter', model)
119
+ }
120
+ }
121
+
122
+ _listLoaded () {
123
+ this.activeModelIndex = this.findActiveIndexForSelectedModel()
124
+ }
125
+
126
+ findActiveIndexForSelectedModel () {
127
+ for (const [index, model] of this.models_.entries()) {
128
+ if (this.isSelected(model)) {
129
+ return index
130
+ }
131
+ }
132
+ return -1
133
+ }
71
134
  }
72
135
  </script>
73
136
 
74
137
 
75
138
  <style scoped lang="scss">
139
+ .searchSelectList {
140
+ outline: none;
141
+ }
142
+
76
143
  .isLoading {
77
144
  opacity: .6;
78
145
  }
@@ -13,7 +13,7 @@ import { randomCssClass } from '@a-vue/utils/random'
13
13
  import { CancelOnEscMixin } from '@a-vue/services/escape/CancelOnEscMixin'
14
14
 
15
15
  @Component({
16
- props: [{show: false}]
16
+ props: [{show: false}, 'beforeClose']
17
17
  })
18
18
  export default class FlyingContext extends Mixins(CancelOnEscMixin) {
19
19
  isVisible = false
@@ -62,8 +62,15 @@ export default class FlyingContext extends Mixins(CancelOnEscMixin) {
62
62
  this.$events.off(FlyingContextEvent.HIDE_ALL, this.onHide)
63
63
  }
64
64
 
65
- onHide () {
65
+ async onHide () {
66
66
  if (this.isVisible) {
67
+ if (this.beforeClose) {
68
+ const result = await this.beforeClose()
69
+ if (!result) {
70
+ return
71
+ }
72
+ }
73
+
67
74
  this.$el.appendChild(this.getContent())
68
75
  this.coe_unwatchCancel() // hide context -> do not watch esc any more
69
76
  this.isVisible = false
@@ -45,6 +45,12 @@ export default class FlyingContextContainer extends Vue {
45
45
  domChanged () {
46
46
  const container = this.getChildrenContainer()
47
47
  this.visible = !!container.children.length
48
+
49
+ if (this.visible) {
50
+ document.documentElement.style.overflow = 'hidden'
51
+ } else {
52
+ document.documentElement.style.overflow = 'auto'
53
+ }
48
54
  }
49
55
 
50
56
  hide () {
@@ -58,6 +64,10 @@ export default class FlyingContextContainer extends Vue {
58
64
  }
59
65
 
60
66
  onClickOutside (e) {
67
+ if (!this.visible) {
68
+ return
69
+ }
70
+
61
71
  // check if trigger is clicked
62
72
  let parent = e.target
63
73
  while (parent) {
@@ -100,8 +110,8 @@ export default class FlyingContextContainer extends Vue {
100
110
  }
101
111
 
102
112
  .v-navigation-drawer__border {
103
- background-color: rgba(0, 0, 0, .12);
104
- left: 0;
113
+ background-color: rgba(0, 0, 0, .12);
114
+ left: 0;
105
115
  }
106
116
 
107
117
  .closeButton {
@@ -61,7 +61,6 @@
61
61
 
62
62
  <a-search-select
63
63
  :listAction="selectableConfig.listAction"
64
- :loadOnlyIfKeyword="false"
65
64
  :selectedItems="selectableSelectedItems"
66
65
  :width="selectableWidth"
67
66
  @select="addItem"
@@ -63,6 +63,10 @@
63
63
  color: #616161 !important;
64
64
  }
65
65
 
66
+ .theme--light.v-input--is-focused fieldset {
67
+ border-color: #1976D2;
68
+ }
69
+
66
70
  .theme--light.v-btn.v-btn--disabled,
67
71
  .theme--light.v-btn.v-btn--disabled span,
68
72
  .theme--light.v-btn.v-btn--disabled .v-icon,