@afeefa/vue-app 0.0.121 → 0.0.123

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.
@@ -1 +1 @@
1
- 0.0.121
1
+ 0.0.123
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.123",
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"
@@ -81,6 +81,16 @@
81
81
  Nichts gefunden.
82
82
  </div>
83
83
  </div>
84
+ <div
85
+ v-if="$has.filters"
86
+ class="filters"
87
+ >
88
+ <slot
89
+ name="filters-below"
90
+ :filters="filters"
91
+ :count="count"
92
+ />
93
+ </div>
84
94
  </div>
85
95
  </template>
86
96
 
@@ -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,