@afeefa/vue-app 0.0.61 → 0.0.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.afeefa/package/release/version.txt +1 -1
- package/README.md +3 -1
- package/package.json +1 -1
- package/src/api-resources/ApiAction.js +87 -0
- package/src/api-resources/ApiActions2.js +13 -0
- package/src/api-resources/DeleteAction.js +21 -0
- package/src/api-resources/GetAction.js +18 -0
- package/src/api-resources/ListAction.js +27 -0
- package/src/api-resources/SaveAction.js +15 -0
- package/src/components/AModal.vue +21 -3
- package/src/components/ASearchSelect.vue +2 -2
- package/src/components/ATableRow.vue +4 -0
- package/src/components/flying-context/FlyingContextEvent.js +5 -0
- package/src/components/form/EditForm.vue +30 -8
- package/src/components/form/EditModal.vue +50 -35
- package/src/components/form/FormFieldMixin.js +1 -1
- package/src/components/form/NestedEditForm.vue +4 -0
- package/src/components/list/ListViewMixin.js +2 -2
- package/src/events.js +1 -0
- package/src-admin/bootstrap.js +1 -0
- package/src-admin/components/App.vue +5 -1
- package/src-admin/components/FlyingContext.vue +77 -0
- package/src-admin/components/FlyingContextContainer.vue +85 -0
- package/src-admin/components/app/AppBarButton.vue +10 -2
- package/src-admin/components/controls/SearchSelectFormField.vue +1 -1
- package/src-admin/components/form/EditFormButtons.vue +40 -0
- package/src-admin/components/form/RemoveButton.vue +71 -0
- package/src-admin/components/index.js +7 -8
- package/src-admin/components/list/ListView.vue +19 -5
- package/src-admin/components/pages/EditPage.vue +48 -134
- package/src-admin/components/routes/DataRouteMixin.js +84 -0
- package/src-admin/config/routing.js +0 -11
- package/src-admin/directives/index.js +26 -0
- package/src-admin/models/Model.js +3 -3
- package/src-admin/components/pages/CreatePage.vue +0 -114
- package/src-admin/components/pages/DetailPage.vue +0 -143
- package/src-admin/components/pages/EditPageMixin.js +0 -96
- package/src-admin/components/pages/ListPage.vue +0 -55
- package/src-admin/components/routes/CreateRoute.vue +0 -15
- package/src-admin/components/routes/DetailRoute.vue +0 -85
- package/src-admin/components/routes/EditRoute.vue +0 -78
- package/src-admin/components/routes/ListRoute.vue +0 -110
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.64
|
package/README.md
CHANGED
package/package.json
CHANGED
@@ -0,0 +1,87 @@
|
|
1
|
+
import { AlertEvent, LoadingEvent } from '@a-vue/events'
|
2
|
+
import { eventBus } from '@a-vue/plugins/event-bus/EventBus'
|
3
|
+
import { sleep } from '@a-vue/utils/timeout'
|
4
|
+
import { ApiAction as ApiResourcesApiAction } from '@afeefa/api-resources-client'
|
5
|
+
|
6
|
+
import { SaveEvent } from '../events'
|
7
|
+
|
8
|
+
export class ApiAction extends ApiResourcesApiAction {
|
9
|
+
_dispatchGlobalLoadingEvents = false
|
10
|
+
_dispatchGlobalSaveEvents = false
|
11
|
+
_minDuration = 100
|
12
|
+
_startTime = 0
|
13
|
+
|
14
|
+
id (id) {
|
15
|
+
this.param('id', id)
|
16
|
+
return this
|
17
|
+
}
|
18
|
+
|
19
|
+
dispatchGlobalLoadingEvents (dispatch = true) {
|
20
|
+
this._dispatchGlobalLoadingEvents = dispatch
|
21
|
+
return this
|
22
|
+
}
|
23
|
+
|
24
|
+
dispatchGlobalSaveEvents (dispatch = true) {
|
25
|
+
this._dispatchGlobalSaveEvents = dispatch
|
26
|
+
return this
|
27
|
+
}
|
28
|
+
|
29
|
+
async beforeRequest () {
|
30
|
+
this._startTime = Date.now()
|
31
|
+
|
32
|
+
if (this._dispatchGlobalLoadingEvents) {
|
33
|
+
eventBus.dispatch(new LoadingEvent(LoadingEvent.START_LOADING))
|
34
|
+
}
|
35
|
+
|
36
|
+
if (this._dispatchGlobalSaveEvents) {
|
37
|
+
eventBus.dispatch(new SaveEvent(SaveEvent.START_SAVING))
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
async beforeBulkRequest () {
|
42
|
+
if (this._dispatchGlobalLoadingEvents) {
|
43
|
+
eventBus.dispatch(new LoadingEvent(LoadingEvent.START_LOADING))
|
44
|
+
}
|
45
|
+
|
46
|
+
if (this._dispatchGlobalSaveEvents) {
|
47
|
+
eventBus.dispatch(new SaveEvent(SaveEvent.START_SAVING))
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
async afterRequest () {
|
52
|
+
if (this._minDuration) {
|
53
|
+
const diffTime = Date.now() - this._startTime
|
54
|
+
const restTime = Math.max(0, this._minDuration - diffTime)
|
55
|
+
if (restTime) {
|
56
|
+
await sleep(restTime / 1000)
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
if (this._dispatchGlobalLoadingEvents) {
|
61
|
+
eventBus.dispatch(new LoadingEvent(LoadingEvent.STOP_LOADING))
|
62
|
+
}
|
63
|
+
|
64
|
+
if (this._dispatchGlobalSaveEvents) {
|
65
|
+
eventBus.dispatch(new SaveEvent(SaveEvent.STOP_SAVING))
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
async afterBulkRequest () {
|
70
|
+
if (this._dispatchGlobalLoadingEvents) {
|
71
|
+
eventBus.dispatch(new LoadingEvent(LoadingEvent.STOP_LOADING))
|
72
|
+
}
|
73
|
+
|
74
|
+
if (this._dispatchGlobalSaveEvents) {
|
75
|
+
eventBus.dispatch(new SaveEvent(SaveEvent.STOP_SAVING))
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
alert (message) {
|
80
|
+
eventBus.dispatch(new AlertEvent(AlertEvent.MESSAGE, {
|
81
|
+
message
|
82
|
+
}))
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
export class BulkAction extends ApiAction {
|
87
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { BulkAction } from './ApiAction'
|
2
|
+
import { DeleteAction } from './DeleteAction'
|
3
|
+
import { GetAction } from './GetAction'
|
4
|
+
import { ListAction } from './ListAction'
|
5
|
+
import { SaveAction } from './SaveAction'
|
6
|
+
|
7
|
+
export {
|
8
|
+
BulkAction,
|
9
|
+
ListAction,
|
10
|
+
GetAction,
|
11
|
+
SaveAction,
|
12
|
+
DeleteAction
|
13
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { ApiAction } from './ApiAction'
|
2
|
+
|
3
|
+
export class DeleteAction extends ApiAction {
|
4
|
+
_minDuration = 400
|
5
|
+
|
6
|
+
delete () {
|
7
|
+
this.data(null)
|
8
|
+
|
9
|
+
return this.execute()
|
10
|
+
}
|
11
|
+
|
12
|
+
async afterRequest () {
|
13
|
+
await super.afterRequest()
|
14
|
+
|
15
|
+
this.alert('Die Daten wurden gelöscht.')
|
16
|
+
}
|
17
|
+
|
18
|
+
processResult () {
|
19
|
+
return true
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { AlertEvent } from '@a-vue/events'
|
2
|
+
import { eventBus } from '@a-vue/plugins/event-bus/EventBus'
|
3
|
+
|
4
|
+
import { ApiAction } from './ApiAction'
|
5
|
+
|
6
|
+
export class GetAction extends ApiAction {
|
7
|
+
load () {
|
8
|
+
return this.execute()
|
9
|
+
}
|
10
|
+
|
11
|
+
processError (result) {
|
12
|
+
eventBus.dispatch(new AlertEvent(AlertEvent.ERROR, {
|
13
|
+
headline: 'Die Daten konntent nicht geladen werden.',
|
14
|
+
message: result.message,
|
15
|
+
detail: result.detail
|
16
|
+
}))
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { NextRouteFilterSource } from '@a-vue/components/list/NextRouteFilterSource'
|
2
|
+
import { ListViewModel } from '@afeefa/api-resources-client'
|
3
|
+
|
4
|
+
import { ApiAction } from './ApiAction'
|
5
|
+
|
6
|
+
export class ListAction extends ApiAction {
|
7
|
+
load () {
|
8
|
+
return this.execute()
|
9
|
+
}
|
10
|
+
|
11
|
+
initFiltersForRoute (route) {
|
12
|
+
const request = new ListViewModel(this)
|
13
|
+
// read from next route query string, but do not push
|
14
|
+
// list component will be init with used_filters
|
15
|
+
.filterSource(new NextRouteFilterSource(route), false)
|
16
|
+
// read from history, but do not push
|
17
|
+
// list component will be init with used_filters
|
18
|
+
.historyKey(route.path, false)
|
19
|
+
.initFilters({
|
20
|
+
source: true,
|
21
|
+
history: true
|
22
|
+
})
|
23
|
+
.getApiRequest()
|
24
|
+
|
25
|
+
return ListAction.fromRequest(request)
|
26
|
+
}
|
27
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { ApiAction } from './ApiAction'
|
2
|
+
|
3
|
+
export class SaveAction extends ApiAction {
|
4
|
+
_minDuration = 400
|
5
|
+
|
6
|
+
save () {
|
7
|
+
return this.execute()
|
8
|
+
}
|
9
|
+
|
10
|
+
async afterRequest () {
|
11
|
+
await super.afterRequest()
|
12
|
+
|
13
|
+
this.alert('Die Daten wurden gespeichert.')
|
14
|
+
}
|
15
|
+
}
|
@@ -7,6 +7,8 @@
|
|
7
7
|
v-bind="$attrs"
|
8
8
|
:contentClass="modalId"
|
9
9
|
transition="v-fade-transition"
|
10
|
+
:persistent="true"
|
11
|
+
:no-click-animation="true"
|
10
12
|
@click:outside="cancel"
|
11
13
|
@keydown.esc="cancel"
|
12
14
|
>
|
@@ -41,7 +43,7 @@ import { getZIndex } from 'vuetify/lib/util/helpers'
|
|
41
43
|
import { ComponentWidthMixin } from './mixins/ComponentWidthMixin'
|
42
44
|
|
43
45
|
@Component({
|
44
|
-
props: ['show', 'title', 'triggerClass', 'anchorPosition']
|
46
|
+
props: ['show', 'title', 'beforeClose', 'triggerClass', 'anchorPosition']
|
45
47
|
})
|
46
48
|
export default class ADialog extends Mixins(UsesPositionServiceMixin, ComponentWidthMixin) {
|
47
49
|
modalId = randomCssClass(10)
|
@@ -83,7 +85,15 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin, ComponentW
|
|
83
85
|
* and emit a visibility event
|
84
86
|
*/
|
85
87
|
@Watch('show')
|
86
|
-
showChanged () {
|
88
|
+
async showChanged () {
|
89
|
+
// check if a modal is allowed to be closed
|
90
|
+
if (this.modal && !this.show && this.beforeClose) {
|
91
|
+
const result = await this.beforeClose()
|
92
|
+
if (!result) {
|
93
|
+
return
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
87
97
|
this.modal = this.show
|
88
98
|
}
|
89
99
|
|
@@ -121,7 +131,15 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin, ComponentW
|
|
121
131
|
this.urp_registerPositionWatcher(this.position)
|
122
132
|
}
|
123
133
|
|
124
|
-
cancel () {
|
134
|
+
async cancel () {
|
135
|
+
// check if a modal is allowed to be closed
|
136
|
+
if (this.modal && this.beforeClose) {
|
137
|
+
const result = await this.beforeClose()
|
138
|
+
if (!result) {
|
139
|
+
return
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
125
143
|
this.modal = false
|
126
144
|
}
|
127
145
|
|
@@ -45,7 +45,7 @@
|
|
45
45
|
<div :class="listCssClass">
|
46
46
|
<search-select-list
|
47
47
|
v-if="isOpen"
|
48
|
-
:
|
48
|
+
:listAction="listAction"
|
49
49
|
:q="q"
|
50
50
|
:selectedItems="selectedItems"
|
51
51
|
:events="false"
|
@@ -96,7 +96,7 @@ import { ComponentWidthMixin } from './mixins/ComponentWidthMixin'
|
|
96
96
|
|
97
97
|
@Component({
|
98
98
|
props: [
|
99
|
-
'
|
99
|
+
'listAction',
|
100
100
|
'q',
|
101
101
|
'width',
|
102
102
|
'closeOnSelect',
|
@@ -3,12 +3,11 @@
|
|
3
3
|
v-model="valid"
|
4
4
|
autocomplete="off"
|
5
5
|
>
|
6
|
-
<slot name="fields" />
|
7
|
-
|
8
6
|
<slot
|
7
|
+
name="form"
|
9
8
|
:changed="changed"
|
10
9
|
:valid="valid"
|
11
|
-
:
|
10
|
+
:modelToEdit="modelToEdit"
|
12
11
|
/>
|
13
12
|
</v-form>
|
14
13
|
</template>
|
@@ -18,14 +17,31 @@
|
|
18
17
|
import { Component, Vue, Watch } from '@a-vue'
|
19
18
|
|
20
19
|
@Component({
|
21
|
-
props: [
|
20
|
+
props: [
|
21
|
+
'model',
|
22
|
+
'createModelToEdit'
|
23
|
+
]
|
22
24
|
})
|
23
25
|
export default class EditForm extends Vue {
|
24
26
|
EDIT_FORM = true
|
25
27
|
|
28
|
+
modelToEdit = null
|
26
29
|
valid = false
|
27
30
|
lastJson = null
|
28
31
|
|
32
|
+
created () {
|
33
|
+
this.reset()
|
34
|
+
}
|
35
|
+
|
36
|
+
reset () {
|
37
|
+
if (this.createModelToEdit) {
|
38
|
+
this.modelToEdit = this.createModelToEdit(this.model)
|
39
|
+
} else if (this.model) {
|
40
|
+
this.modelToEdit = this.model.cloneForEdit()
|
41
|
+
}
|
42
|
+
this.lastJson = this.json
|
43
|
+
}
|
44
|
+
|
29
45
|
/**
|
30
46
|
* This will be triggered after the this.model has been set
|
31
47
|
* but before sub components may have changed model values
|
@@ -33,14 +49,20 @@ export default class EditForm extends Vue {
|
|
33
49
|
* Using the created() method would result in already having set
|
34
50
|
* the default date, hence not detecting a valid "change" anymore.
|
35
51
|
*/
|
36
|
-
@Watch('
|
52
|
+
// @Watch('modelToEdit', {immediate: true})
|
53
|
+
// @Watch('modelToEdit')
|
54
|
+
// modelToEditChanged () {
|
55
|
+
// this.lastJson = this.json
|
56
|
+
// this.$emit('update:changed', this.changed)
|
57
|
+
// }
|
58
|
+
|
59
|
+
@Watch('model')
|
37
60
|
modelChanged () {
|
38
|
-
this.
|
39
|
-
this.$emit('update:changed', this.changed)
|
61
|
+
this.reset()
|
40
62
|
}
|
41
63
|
|
42
64
|
get json () {
|
43
|
-
return JSON.stringify(this.
|
65
|
+
return JSON.stringify(this.modelToEdit)
|
44
66
|
}
|
45
67
|
|
46
68
|
get changed () {
|
@@ -1,6 +1,7 @@
|
|
1
1
|
<template>
|
2
2
|
<a-modal
|
3
3
|
:title="title"
|
4
|
+
:beforeClose="beforeClose"
|
4
5
|
:show.sync="show_"
|
5
6
|
v-bind="$attrs"
|
6
7
|
>
|
@@ -10,16 +11,18 @@
|
|
10
11
|
|
11
12
|
<edit-form
|
12
13
|
v-if="show_"
|
14
|
+
ref="form"
|
13
15
|
:model="model"
|
16
|
+
:createModelToEdit="createModelToEdit"
|
14
17
|
>
|
15
|
-
<template #
|
18
|
+
<template #form="{modelToEdit, changed, valid}">
|
16
19
|
<slot
|
17
|
-
name="
|
18
|
-
:
|
20
|
+
name="form"
|
21
|
+
:modelToEdit="modelToEdit"
|
22
|
+
:changed="changed"
|
23
|
+
:valid="valid"
|
19
24
|
/>
|
20
|
-
</template>
|
21
25
|
|
22
|
-
<template #default="{changed, valid}">
|
23
26
|
<a-row
|
24
27
|
class="mt-8 mb-1 pb-1 gap-4"
|
25
28
|
right
|
@@ -31,25 +34,14 @@
|
|
31
34
|
Schließen
|
32
35
|
</v-btn>
|
33
36
|
|
34
|
-
<
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
</v-btn>
|
43
|
-
|
44
|
-
<v-icon
|
45
|
-
v-if="changed"
|
46
|
-
small
|
47
|
-
text
|
48
|
-
@click="reset"
|
49
|
-
>
|
50
|
-
{{ undoIcon }}
|
51
|
-
</v-icon>
|
52
|
-
</a-row>
|
37
|
+
<edit-form-buttons
|
38
|
+
:changed="changed"
|
39
|
+
:valid="valid"
|
40
|
+
small
|
41
|
+
:has="{reset: !!modelToEdit.id}"
|
42
|
+
@save="$emit('save', modelToEdit, ignoreChangesOnClose)"
|
43
|
+
@reset="$refs.form.reset()"
|
44
|
+
/>
|
53
45
|
</a-row>
|
54
46
|
</template>
|
55
47
|
</edit-form>
|
@@ -59,21 +51,26 @@
|
|
59
51
|
|
60
52
|
<script>
|
61
53
|
import { Component, Vue, Watch } from '@a-vue'
|
62
|
-
import {
|
54
|
+
import { DialogEvent } from '@a-vue/events'
|
63
55
|
|
64
56
|
@Component({
|
65
|
-
props: ['model', 'title', 'show']
|
57
|
+
props: ['model', 'createModelToEdit', 'title', 'show']
|
66
58
|
})
|
67
59
|
export default class EditModal extends Vue {
|
68
60
|
show_ = false
|
61
|
+
ignoreChangesOnClose_ = false
|
69
62
|
|
70
|
-
|
63
|
+
created () {
|
64
|
+
if (this.show) { // open on create with v-show
|
65
|
+
this.open()
|
66
|
+
}
|
67
|
+
}
|
71
68
|
|
72
69
|
/**
|
73
70
|
* visiblility changes from outside
|
74
71
|
* this will trigger the show_ watcher,
|
75
72
|
* forward the change to the modal and
|
76
|
-
* later emit
|
73
|
+
* later emit an open/close event
|
77
74
|
*/
|
78
75
|
@Watch('show')
|
79
76
|
showChanged () {
|
@@ -90,7 +87,6 @@ export default class EditModal extends Vue {
|
|
90
87
|
@Watch('show_')
|
91
88
|
show_Changed () {
|
92
89
|
if (this.show_) {
|
93
|
-
this.reset()
|
94
90
|
this.$emit('open')
|
95
91
|
} else {
|
96
92
|
this.$emit('close')
|
@@ -101,16 +97,35 @@ export default class EditModal extends Vue {
|
|
101
97
|
this.show_ = true
|
102
98
|
}
|
103
99
|
|
104
|
-
|
105
|
-
|
100
|
+
async beforeClose () {
|
101
|
+
// run only if show_ is true to prevent double checks with a-modal
|
102
|
+
if (this.show_ && this.$refs.form.changed && !this.ignoreChangesOnClose_) {
|
103
|
+
const result = await this.$events.dispatch(new DialogEvent(DialogEvent.SHOW, {
|
104
|
+
title: 'Änderungen verwerfen?',
|
105
|
+
message: 'Im Formular sind nicht gespeicherte Änderungen. Sollen diese verworfen werden?',
|
106
|
+
yesButton: 'Verwerfen'
|
107
|
+
}))
|
108
|
+
if (result !== DialogEvent.RESULT_YES) {
|
109
|
+
return false
|
110
|
+
}
|
111
|
+
}
|
112
|
+
return true
|
106
113
|
}
|
107
114
|
|
108
|
-
|
109
|
-
this
|
115
|
+
async close () {
|
116
|
+
const result = await this.beforeClose()
|
117
|
+
if (!result) {
|
118
|
+
return
|
119
|
+
}
|
120
|
+
|
121
|
+
this.show_ = false
|
110
122
|
}
|
111
123
|
|
112
|
-
|
113
|
-
|
124
|
+
/**
|
125
|
+
* hook to allow to leave a just created (saved) model
|
126
|
+
*/
|
127
|
+
ignoreChangesOnClose () {
|
128
|
+
this.ignoreChangesOnClose_ = true
|
114
129
|
}
|
115
130
|
}
|
116
131
|
</script>
|
@@ -8,7 +8,7 @@ import { FilterSourceType } from './FilterSourceType'
|
|
8
8
|
@Component({
|
9
9
|
props: [
|
10
10
|
'models', 'meta', // given, if already loaded
|
11
|
-
'
|
11
|
+
'listAction',
|
12
12
|
'filterHistoryKey',
|
13
13
|
'loadOnlyIfKeyword',
|
14
14
|
{
|
@@ -52,7 +52,7 @@ export class ListViewMixin extends Vue {
|
|
52
52
|
this.meta_ = this.meta
|
53
53
|
}
|
54
54
|
|
55
|
-
this.listViewModel = new ListViewModel(this.
|
55
|
+
this.listViewModel = new ListViewModel(this.listAction)
|
56
56
|
.filterSource(filterSource, !!filterSource)
|
57
57
|
.historyKey(historyKey, this.history)
|
58
58
|
.usedFilters(this.meta_.used_filters || null, this.meta_.count_search || 0)
|
package/src/events.js
CHANGED
@@ -2,3 +2,4 @@ export { LoadingEvent } from './components/loading-indicator/LoadingEvent'
|
|
2
2
|
export { SaveEvent } from './components/save-indicator/SaveEvent'
|
3
3
|
export { AlertEvent } from './components/alert/AlertEvent'
|
4
4
|
export { DialogEvent } from './components/dialog/DialogEvent'
|
5
|
+
export { FlyingContextEvent } from './components/flying-context/FlyingContextEvent'
|
package/src-admin/bootstrap.js
CHANGED
@@ -91,6 +91,8 @@
|
|
91
91
|
</v-list>
|
92
92
|
</v-navigation-drawer>
|
93
93
|
|
94
|
+
<flying-context-container />
|
95
|
+
|
94
96
|
<v-app-bar
|
95
97
|
app
|
96
98
|
flat
|
@@ -142,12 +144,14 @@ import { appConfig } from '@a-admin/config/AppConfig'
|
|
142
144
|
import { sleep } from '@a-vue/utils/timeout'
|
143
145
|
import AppBarButtons from './app/AppBarButtons'
|
144
146
|
import AppBarTitleContainer from './app/AppBarTitleContainer'
|
147
|
+
import FlyingContextContainer from './FlyingContextContainer'
|
145
148
|
import '../styles.scss'
|
146
149
|
|
147
150
|
@Component({
|
148
151
|
components: {
|
149
152
|
AppBarButtons,
|
150
|
-
AppBarTitleContainer
|
153
|
+
AppBarTitleContainer,
|
154
|
+
FlyingContextContainer
|
151
155
|
}
|
152
156
|
})
|
153
157
|
export default class App extends Vue {
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="flyingContext">
|
3
|
+
<div :class="contextId">
|
4
|
+
<slot v-if="isVisible" />
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
</template>
|
8
|
+
|
9
|
+
<script>
|
10
|
+
import { Component, Watch, Vue } from '@a-vue'
|
11
|
+
import { FlyingContextEvent } from '@a-vue/events'
|
12
|
+
import { randomCssClass } from '@a-vue/utils/random'
|
13
|
+
|
14
|
+
@Component({
|
15
|
+
props: [{show: false}]
|
16
|
+
})
|
17
|
+
export default class FlyingContext extends Vue {
|
18
|
+
isVisible = false
|
19
|
+
contextId = randomCssClass(10)
|
20
|
+
|
21
|
+
created () {
|
22
|
+
this.$events.on(FlyingContextEvent.HIDE_ALL, this.onHide)
|
23
|
+
}
|
24
|
+
|
25
|
+
mounted () {
|
26
|
+
if (this.show) {
|
27
|
+
this.showChanged()
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
@Watch('show')
|
32
|
+
showChanged () {
|
33
|
+
if (this.isVisible === this.show) {
|
34
|
+
return
|
35
|
+
}
|
36
|
+
|
37
|
+
this.isVisible = this.show
|
38
|
+
|
39
|
+
if (this.isVisible) {
|
40
|
+
const container = this.getSidebarContainer()
|
41
|
+
container.appendChild(this.getContent())
|
42
|
+
} else {
|
43
|
+
this.$el.appendChild(this.getContent())
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
destroyed () {
|
48
|
+
const container = this.getSidebarContainer()
|
49
|
+
const el = this.getContent()
|
50
|
+
if (container.contains(el)) {
|
51
|
+
container.removeChild(el)
|
52
|
+
}
|
53
|
+
|
54
|
+
this.$events.off(FlyingContextEvent.HIDE_ALL, this.onHide)
|
55
|
+
}
|
56
|
+
|
57
|
+
onHide () {
|
58
|
+
if (this.isVisible) {
|
59
|
+
this.$el.appendChild(this.getContent())
|
60
|
+
this.isVisible = false
|
61
|
+
this.$emit('hide')
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
getContent () {
|
66
|
+
return document.querySelector('.' + this.contextId)
|
67
|
+
}
|
68
|
+
|
69
|
+
getSidebarContainer () {
|
70
|
+
return document.getElementById('flyingContextContainer__children')
|
71
|
+
}
|
72
|
+
}
|
73
|
+
</script>
|
74
|
+
|
75
|
+
|
76
|
+
<style lang="scss" scoped>
|
77
|
+
</style>
|