@afeefa/vue-app 0.0.62 → 0.0.65

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. package/.afeefa/package/release/version.txt +1 -1
  2. package/README.md +3 -1
  3. package/package.json +1 -1
  4. package/src/components/ABreadcrumbs.vue +3 -2
  5. package/src/components/AModal.vue +21 -3
  6. package/src/components/ARichTextArea.vue +95 -85
  7. package/src/components/ATableRow.vue +4 -0
  8. package/src/components/flying-context/FlyingContextEvent.js +5 -0
  9. package/src/components/form/EditForm.vue +13 -3
  10. package/src/components/form/EditModal.vue +52 -35
  11. package/src/components/form/NestedEditForm.vue +4 -0
  12. package/src/components/form/fields/FormFieldRichTextArea.vue +5 -3
  13. package/src/components/list/ListViewMixin.js +14 -2
  14. package/src/components/search-select/SearchSelectList.vue +0 -1
  15. package/src/components/vue/Component.js +9 -2
  16. package/src/events.js +2 -0
  17. package/src-admin/bootstrap.js +1 -0
  18. package/src-admin/components/App.vue +55 -6
  19. package/src-admin/components/FlyingContext.vue +77 -0
  20. package/src-admin/components/FlyingContextContainer.vue +85 -0
  21. package/src-admin/components/StickyFooter.vue +42 -0
  22. package/src-admin/components/StickyFooterContainer.vue +66 -0
  23. package/src-admin/components/form/EditFormButtons.vue +8 -3
  24. package/src-admin/components/index.js +4 -7
  25. package/src-admin/components/list/ListView.vue +22 -9
  26. package/src-admin/components/pages/EditPage.vue +23 -9
  27. package/src-admin/components/routes/DataRouteMixin.js +24 -15
  28. package/src-admin/config/routing.js +0 -11
  29. package/src-admin/config/vuetify.js +7 -1
  30. package/src-admin/directives/index.js +26 -0
  31. package/src-admin/styles.scss +1 -4
  32. package/src-admin/components/pages/CreatePage.vue +0 -114
  33. package/src-admin/components/pages/DetailPage.vue +0 -143
  34. package/src-admin/components/pages/EditPageMixin.js +0 -96
  35. package/src-admin/components/pages/ListPage.vue +0 -55
  36. package/src-admin/components/routes/CreateRoute.vue +0 -15
  37. package/src-admin/components/routes/DetailRoute.vue +0 -85
  38. package/src-admin/components/routes/EditRoute.vue +0 -78
  39. package/src-admin/components/routes/ListRoute.vue +0 -110
@@ -1,8 +1,11 @@
1
1
  import {
2
2
  mdiAlarmLightOutline,
3
3
  mdiCalendar,
4
+ mdiCheck,
5
+ mdiCheckBold,
4
6
  mdiChevronRight,
5
7
  mdiClose,
8
+ mdiCloseThick,
6
9
  mdiDelete,
7
10
  mdiDotsHorizontal,
8
11
  mdiDotsVertical,
@@ -26,6 +29,7 @@ export default new Vuetify({
26
29
  thumbsUpIcon: mdiThumbUpOutline,
27
30
  alarmIcon: mdiAlarmLightOutline,
28
31
  closeIcon: mdiClose,
32
+ closeBoldIcon: mdiCloseThick,
29
33
  dotsVerticalIcon: mdiDotsVertical,
30
34
  dotsHorizontalIcon: mdiDotsHorizontal,
31
35
  logoutIcon: mdiLogoutVariant,
@@ -34,7 +38,9 @@ export default new Vuetify({
34
38
  trashCanIcon: mdiDelete,
35
39
  calendarIcon: mdiCalendar,
36
40
  searchIcon: mdiMagnify,
37
- lockIcon: mdiLock
41
+ lockIcon: mdiLock,
42
+ checkIcon: mdiCheck,
43
+ checkBoldIcon: mdiCheckBold
38
44
  }
39
45
  },
40
46
  breakpoint: {
@@ -0,0 +1,26 @@
1
+ import { Vue } from '@a-vue'
2
+
3
+ Vue.directive('flying-context-trigger', {
4
+ bind: function (el, bindings) {
5
+ if (bindings.value) {
6
+ el.$flyingContextObserver = new MutationObserver(() => {
7
+ if (!el.classList.contains('flyingContextTrigger')) {
8
+ el.classList.add('flyingContextTrigger')
9
+ }
10
+ })
11
+
12
+ el.$flyingContextObserver.observe(el, {
13
+ attributes: true,
14
+ attributeFilter: ['class']
15
+ })
16
+
17
+ el.classList.add('flyingContextTrigger')
18
+ }
19
+ },
20
+
21
+ unbind: function (el) {
22
+ if (el.$flyingContextObserver) {
23
+ el.$flyingContextObserver.disconnect()
24
+ }
25
+ }
26
+ })
@@ -15,6 +15,7 @@
15
15
  .contextButton {
16
16
  color: #AAAAAA !important;
17
17
  cursor: pointer;
18
+
18
19
  &:hover {
19
20
  color: #333333 !important;
20
21
  }
@@ -27,10 +28,6 @@
27
28
  }
28
29
  }
29
30
 
30
- .v-main {
31
- margin-bottom: 2rem;
32
- }
33
-
34
31
  .theme--light.v-btn.v-btn--has-bg {
35
32
  background-color: #E9E9E9;
36
33
  }
@@ -1,114 +0,0 @@
1
- <template>
2
- <div class="createPage">
3
- <app-bar-title
4
- :icon="_icon"
5
- :title="_title"
6
- />
7
-
8
- <app-bar-button>
9
- <v-btn
10
- :to="_listLink"
11
- small
12
- >
13
- Liste
14
- </v-btn>
15
- </app-bar-button>
16
-
17
- <edit-form
18
- :model="modelToEdit"
19
- :valid.sync="valid"
20
- :changed.sync="changed"
21
- >
22
- <template #fields>
23
- <slot
24
- name="fields"
25
- :model="modelToEdit"
26
- />
27
- </template>
28
- </edit-form>
29
-
30
- <a-row class="mt-6">
31
- <v-btn
32
- :disabled="!changed || !valid"
33
- color="green white--text"
34
- @click="save"
35
- >
36
- Anlegen
37
- </v-btn>
38
-
39
- <v-btn
40
- v-if="changed"
41
- text
42
- @click="reset"
43
- >
44
- Zurücksetzen
45
- </v-btn>
46
- </a-row>
47
- </div>
48
- </template>
49
-
50
- <script>
51
- import { Component, Mixins } from '@a-vue'
52
- import { EditPageMixin } from './EditPageMixin'
53
-
54
- @Component({
55
- props: ['icon', 'title', 'createModel', 'listLink']
56
- })
57
- export default class CreatePage extends Mixins(EditPageMixin) {
58
- created () {
59
- if (!this.$parent.constructor.getCreateRouteConfig) {
60
- console.warn('<create-page> owner must provide a static createRouteConfig method.')
61
- }
62
-
63
- this.reset()
64
- }
65
-
66
- get editConfig () {
67
- return this.$parent.constructor.getCreateRouteConfig(this.$route)
68
- }
69
-
70
- get modelUpateAction () {
71
- return this.editConfig.createAction || this.ModelClass.getAction('save')
72
- }
73
-
74
- get _icon () {
75
- return this.icon || this.modelToEdit.getIcon()
76
- }
77
-
78
- get _title () {
79
- const title = this.modelToEdit.getTitle()
80
- if (title) {
81
- return title
82
- }
83
-
84
- if (this.title) {
85
- return this.title
86
- }
87
-
88
- return this.$t('Admin.Types', this.ModelClass.type, null, 'TITLE_NEW', 'de')
89
- }
90
-
91
- get _listLink () {
92
- if (this.listLink) {
93
- if (typeof this.listLink === 'function') {
94
- return this.listLink()
95
- } else {
96
- return this.listLink
97
- }
98
- }
99
- return this.modelToEdit.getLink('list')
100
- }
101
-
102
- createModelToEdit () {
103
- if (this.createModel) {
104
- return this.createModel(this.fields)
105
- }
106
- return this.ModelClass.createForNew(this.fields)
107
- }
108
-
109
- saved (model) {
110
- this.ignoreChanged = true
111
- this.$router.push(model.getLink('edit'))
112
- }
113
- }
114
- </script>
@@ -1,143 +0,0 @@
1
- <template>
2
- <div class="detailPage ml-4 mt-12">
3
- <app-bar-title
4
- :icon="_icon"
5
- :title="_title"
6
- />
7
-
8
- <app-bar-button v-if="$has.remove">
9
- <v-btn
10
- small
11
- color="red white--text"
12
- class="removeButton"
13
- @click="remove"
14
- >
15
- Löschen
16
- </v-btn>
17
- </app-bar-button>
18
-
19
- <app-bar-button v-if="$has.edit">
20
- <a-icon-button
21
- :to="model.getLink('edit')"
22
- icon="$pencilIcon"
23
- text="Bearbeiten"
24
- color="green white--text"
25
- />
26
- </app-bar-button>
27
-
28
- <slot
29
- name="model"
30
- :model="model"
31
- />
32
-
33
- <a-dialog
34
- id="detailPageRemoveDialog"
35
- :anchor="[document, '.removeButton']"
36
- :active="protectRemove ? removeKey === removeConfirmed : true"
37
- >
38
- <template v-if="protectRemove">
39
- <div>Bitte folgenden Key eingeben: <strong class="removeKey">{{ removeKey }}</strong></div>
40
-
41
- <a-text-field
42
- v-model="removeConfirmed"
43
- label="Key"
44
- :focus="true"
45
- width="100"
46
- />
47
- </template>
48
- </a-dialog>
49
- </div>
50
- </template>
51
-
52
-
53
- <script>
54
- import { Component, Vue, Watch } from '@a-vue'
55
- import { RemoveAction } from '@a-vue/api-resources/ApiActions'
56
-
57
- @Component({
58
- props: ['model', 'title', 'icon', 'protectRemove', 'listLink']
59
- })
60
- export default class DetailPage extends Vue {
61
- $hasOptions = ['edit', 'remove', 'list']
62
-
63
- removeKey = null
64
- removeConfirmed = null
65
-
66
- created () {
67
- if (!this.$parent.constructor.getDetailRouteConfig) {
68
- console.warn('<detail-page> owner must provide a static getDetailRouteConfig method.')
69
- }
70
- this.$emit('model', this.model)
71
- }
72
-
73
- @Watch('model')
74
- modelChanged () {
75
- this.$emit('model', this.model)
76
- }
77
-
78
- get _title () {
79
- return this.title || this.model.getTitle()
80
- }
81
-
82
- get detailConfig () {
83
- return this.$parent.constructor.getDetailRouteConfig(this.$route)
84
- }
85
-
86
- get document () {
87
- return document
88
- }
89
-
90
- get ModelClass () {
91
- return this.detailConfig.ModelClass
92
- }
93
-
94
- get _listLink () {
95
- if (this.listLink) {
96
- if (typeof this.listLink === 'function') {
97
- return this.listLink()
98
- } else {
99
- return this.listLink
100
- }
101
- }
102
- return this.model.getLink('list')
103
- }
104
-
105
- get _icon () {
106
- if (this.icon) {
107
- return this.icon
108
- }
109
- return this.model.getIcon()
110
- }
111
-
112
- get _deleteAction () {
113
- return this.detailConfig.removeAction || this.ModelClass.getAction('save')
114
- }
115
-
116
- async remove () {
117
- this.removeKey = [...Array(6)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')
118
-
119
- const result = await new RemoveAction()
120
- .setAction(this._deleteAction)
121
- .setId(this.model.id)
122
- .setDialog({
123
- id: 'detailPageRemoveDialog',
124
- title: this.model.getTitle() + ' löschen?',
125
- message: 'Soll ' + this.model.getTitle() + ' gelöscht werden?',
126
- yesButton: 'Löschen',
127
- yesColor: 'red white--text'
128
- })
129
- .delete()
130
-
131
- if (result) {
132
- this.$router.push(this.model.getLink('list'))
133
- }
134
- }
135
- }
136
- </script>
137
-
138
-
139
- <style lang="scss" scoped>
140
- .removeKey {
141
- user-select: none;
142
- }
143
- </style>
@@ -1,96 +0,0 @@
1
- import { Component, Vue } from '@a-vue'
2
- import { SaveAction } from '@a-vue/api-resources/ApiActions'
3
- import { DialogEvent } from '@a-vue/events'
4
-
5
- @Component({
6
- props: ['saveAction']
7
- })
8
- export class EditPageMixin extends Vue {
9
- valid = false
10
- changed = false
11
- modelToEdit = null
12
- ignoreChanged = false
13
-
14
- unregisterRouterHook = null
15
-
16
- created () {
17
- this.unregisterRouterHook = this.$router.beforeEach(async (to, from, next) => {
18
- if (!this.ignoreChanged && this.changed) {
19
- const result = await this.$events.dispatch(new DialogEvent(DialogEvent.SHOW, {
20
- title: 'Änderungen verwerfen?',
21
- message: 'Im Formular sind nicht gespeicherte Änderungen. Sollen diese verworfen werden?',
22
- yesButton: 'Verwerfen'
23
- }))
24
- if (result === DialogEvent.RESULT_YES) {
25
- next()
26
- }
27
- return
28
- }
29
- next()
30
- })
31
- }
32
-
33
- destroyed () {
34
- this.unregisterRouterHook()
35
- }
36
-
37
- createModelToEdit () {
38
- return null
39
- }
40
-
41
- get editConfig () {
42
- return null
43
- }
44
-
45
- get ModelClass () {
46
- return this.editConfig.ModelClass
47
- }
48
-
49
- get _saveAction () {
50
- if (this.saveAction) {
51
- return this.saveAction
52
- }
53
- return this.modelUpateAction
54
- }
55
-
56
- get modelUpateAction () {
57
- return null
58
- }
59
-
60
- get fields () {
61
- return this.editConfig.fields
62
- }
63
-
64
- get saveParams () {
65
- return {}
66
- }
67
-
68
- async save () {
69
- const model = await new SaveAction()
70
- .setAction(this._saveAction)
71
- .setFields(this.fields)
72
- .setId(this.modelToEdit.id)
73
- .setData(this.modelToEdit.serialize(this.fields))
74
- .setAfterSaveHook(this.afterSave)
75
- .save()
76
-
77
- this.saved(model)
78
- }
79
-
80
- reset () {
81
- const modelToEdit = this.createModelToEdit()
82
- if (this.editConfig.createModelToEdit) {
83
- this.editConfig.createModelToEdit(modelToEdit)
84
- }
85
- this.modelToEdit = modelToEdit // this assignment makes modelToEdit recursively reactive
86
- this.$emit('model', this.modelToEdit)
87
- }
88
-
89
- afterSave (_model) {
90
- // e.g. reload model
91
- }
92
-
93
- saved (_model) {
94
- // e.g. redirect after save
95
- }
96
- }
@@ -1,55 +0,0 @@
1
- <template>
2
- <div class="listPage">
3
- <app-bar-title
4
- :icon="_icon"
5
- :title="_title"
6
- />
7
-
8
- <app-bar-button v-if="$has.add">
9
- <a-icon-button
10
- v-if="$has.add"
11
- :to="_newLink"
12
- icon="$plusIcon"
13
- :text="_newTitle"
14
- color="green white--text"
15
- />
16
- </app-bar-button>
17
-
18
- <slot />
19
- </div>
20
- </template>
21
-
22
- <script>
23
- import { Component, Vue } from '@a-vue'
24
-
25
- @Component({
26
- props: ['icon', 'title', 'newTitle', 'newLink', 'Model']
27
- })
28
- export default class ListPage extends Vue {
29
- $hasOptions = ['add']
30
-
31
- get _icon () {
32
- return this.icon || this.Model.icon
33
- }
34
-
35
- get _title () {
36
- if (this.title) {
37
- return this.title
38
- }
39
-
40
- return this.$t('Admin.Types', this.Model.type, null, 'TITLE_PLURAL', 'de')
41
- }
42
-
43
- get _newTitle () {
44
- if (this.newTitle) {
45
- return this.newTitle
46
- }
47
-
48
- return this.$t('Admin.Types', this.Model.type, null, 'TITLE_SINGULAR', 'de')
49
- }
50
-
51
- get _newLink () {
52
- return this.newLink || this.Model.getLink('new')
53
- }
54
- }
55
- </script>
@@ -1,15 +0,0 @@
1
- <template>
2
- <component :is="Component" />
3
- </template>
4
-
5
-
6
- <script>
7
- import { Component, Vue } from '@a-vue'
8
-
9
- @Component
10
- export default class CreateRoute extends Vue {
11
- get Component () {
12
- return this.$routeDefinition.config.new
13
- }
14
- }
15
- </script>
@@ -1,85 +0,0 @@
1
- <template>
2
- <component
3
- :is="Component"
4
- v-if="model"
5
- :model="model"
6
- />
7
- </template>
8
-
9
- <script>
10
- import { Component, Vue, Watch } from '@a-vue'
11
- import { GetAction } from '@a-vue/api-resources/ApiActions'
12
-
13
- Component.registerHooks([
14
- 'beforeRouteEnter',
15
- 'beforeRouteUpdate'
16
- ])
17
-
18
- function load (route) {
19
- const routeDefinition = route.meta.routeDefinition
20
- const Component = routeDefinition.config.detail
21
-
22
- if (!Component.getDetailRouteConfig) {
23
- console.warn('A detail route component must implement a static getDetailRouteConfig property.')
24
- }
25
-
26
- const detailConfig = Component.getDetailRouteConfig(route)
27
- const action = detailConfig.action || detailConfig.ModelClass.getAction('get')
28
-
29
- return new GetAction()
30
- .setAction(action)
31
- .setFields(detailConfig.fields)
32
- .setId(detailConfig.id || route.params[routeDefinition.idKey])
33
- .load()
34
- }
35
-
36
- let routerHookCalled = false
37
-
38
- @Component
39
- export default class DetailRoute extends Vue {
40
- model = null
41
-
42
- /**
43
- * triggered, when the route name changes
44
- * not triggered, when only route params change
45
- */
46
- async beforeRouteEnter (to, from, next) {
47
- routerHookCalled = true
48
- const result = await load(to)
49
- next(vm => {
50
- if (result !== false) {
51
- vm.model = result
52
- }
53
- routerHookCalled = false
54
- })
55
- }
56
-
57
- /**
58
- * triggered both, if route name or route params change
59
- */
60
- @Watch('$route.params')
61
- async routeParamsChanged () {
62
- if (routerHookCalled) {
63
- // set model to null in order to not recreate detail route's
64
- // child components with the stale model which is still active
65
- // in between resolving the route with next() + creating the
66
- // route detail component and resetting vm.model later in the callback
67
- this.model = null
68
- return
69
- }
70
- this.model = await load(this.$route)
71
- }
72
-
73
- // probably not needed
74
- // @Watch('$route.name')
75
- // async routeNameChanged () {
76
- // if (routerHookCalled) {
77
- // // this.model = null
78
- // }
79
- // }
80
-
81
- get Component () {
82
- return this.$routeDefinition.config.detail
83
- }
84
- }
85
- </script>
@@ -1,78 +0,0 @@
1
- <template>
2
- <component
3
- :is="Component"
4
- v-if="model"
5
- :model="model"
6
- />
7
- </template>
8
-
9
-
10
- <script>
11
- import { Component, Vue, Watch } from '@a-vue'
12
- import { GetAction } from '@a-vue/api-resources/ApiActions'
13
-
14
- Component.registerHooks([
15
- 'beforeRouteEnter',
16
- 'beforeRouteUpdate'
17
- ])
18
-
19
- function load (route) {
20
- const routeDefinition = route.meta.routeDefinition
21
- const Component = routeDefinition.config.edit
22
-
23
- if (!Component.getEditRouteConfig) {
24
- console.warn('An edit route component must implement a static getEditRouteConfig property.')
25
- }
26
-
27
- const editConfig = Component.getEditRouteConfig(route)
28
- const action = editConfig.getAction || editConfig.ModelClass.getAction('get')
29
-
30
- return new GetAction()
31
- .setAction(action)
32
- .setFields(editConfig.fields)
33
- .setId(editConfig.id || route.params[routeDefinition.idKey])
34
- .load()
35
- }
36
-
37
- let routerHookCalled = false
38
-
39
- @Component
40
- export default class EditRoute extends Vue {
41
- model = null
42
-
43
- /**
44
- * triggered, when the route name changes
45
- * not triggered, when only route params change
46
- */
47
- async beforeRouteEnter (to, from, next) {
48
- routerHookCalled = true
49
- const result = await load(to)
50
- next(vm => {
51
- if (result !== false) {
52
- vm.model = result
53
- }
54
- routerHookCalled = false
55
- })
56
- }
57
-
58
- /**
59
- * triggered both, if route name or route params change
60
- */
61
- @Watch('$route.params')
62
- async routeParamsChanged () {
63
- if (routerHookCalled) {
64
- // set model to null in order to not recreate detail route's
65
- // child components with the stale model which is still active
66
- // in between resolving the route with next() + creating the
67
- // route edit component and resetting vm.model later in the callback
68
- this.model = null
69
- return
70
- }
71
- this.model = await load(this.$route)
72
- }
73
-
74
- get Component () {
75
- return this.$routeDefinition.config.edit
76
- }
77
- }
78
- </script>