@afeefa/vue-app 0.0.63 → 0.0.66
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/package.json +1 -1
- package/src/components/ABreadcrumbs.vue +75 -18
- package/src/components/ADatePicker.vue +1 -1
- package/src/components/AIcon.vue +3 -6
- package/src/components/AIconButton.vue +1 -2
- package/src/components/AModal.vue +21 -3
- package/src/components/ARichTextArea.vue +95 -85
- package/src/components/ARow.vue +0 -7
- package/src/components/ATableRow.vue +4 -0
- package/src/components/flying-context/FlyingContextEvent.js +5 -0
- package/src/components/form/EditForm.vue +13 -3
- package/src/components/form/EditModal.vue +52 -35
- package/src/components/form/fields/FormFieldRichTextArea.vue +5 -3
- package/src/components/list/ListViewMixin.js +25 -2
- package/src/components/mixins/ClickOutsideMixin.js +5 -1
- package/src/components/search-select/SearchSelectList.vue +0 -1
- package/src/components/vue/Component.js +9 -2
- package/src/events.js +2 -0
- package/src-admin/bootstrap.js +1 -0
- package/src-admin/components/App.vue +58 -59
- package/src-admin/components/FlyingContext.vue +77 -0
- package/src-admin/components/FlyingContextContainer.vue +85 -0
- package/src-admin/components/Sidebar.vue +66 -0
- package/src-admin/components/SidebarItem.vue +59 -0
- package/src-admin/components/StickyFooter.vue +42 -0
- package/src-admin/components/StickyFooterContainer.vue +66 -0
- package/src-admin/components/StickyHeader.vue +73 -0
- package/src-admin/components/app/AppBarButtons.vue +0 -7
- package/src-admin/components/app/AppBarTitle.vue +55 -11
- package/src-admin/components/app/AppBarTitleContainer.vue +2 -3
- package/src-admin/components/controls/SearchSelectFormField.vue +1 -0
- package/src-admin/components/detail/DetailProperty.vue +20 -16
- package/src-admin/components/form/EditFormButtons.vue +25 -6
- package/src-admin/components/form/RemoveButton.vue +17 -8
- package/src-admin/components/index.js +6 -7
- package/src-admin/components/list/ListView.vue +22 -9
- package/src-admin/components/pages/EditPage.vue +17 -8
- package/src-admin/components/routes/DataRouteMixin.js +24 -15
- package/src-admin/config/routing.js +0 -11
- package/src-admin/config/vuetify.js +22 -2
- package/src-admin/directives/index.js +26 -0
- package/src-admin/styles.scss +21 -4
- 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.66
|
package/package.json
CHANGED
@@ -1,19 +1,38 @@
|
|
1
1
|
<template>
|
2
|
-
<div class="d-flex
|
3
|
-
<div
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
<v-icon>$chevronRightIcon</v-icon>
|
9
|
-
|
10
|
-
<router-link
|
11
|
-
:to="breadcrumb.to"
|
12
|
-
:exact="true"
|
2
|
+
<div class="a-breadcrumbs d-flex align-start gap-2 mr-4">
|
3
|
+
<div :class="['breadcrumbs d-flex align-center', {'flex-wrap': wrapBreadcrumbs_}]">
|
4
|
+
<div
|
5
|
+
v-for="(breadcrumb, index) in breadcrumbs"
|
6
|
+
:key="index"
|
7
|
+
class="item mr-2 d-flex align-center"
|
13
8
|
>
|
14
|
-
|
15
|
-
|
9
|
+
<v-icon v-if="index > 0">
|
10
|
+
$chevronRightIcon
|
11
|
+
</v-icon>
|
12
|
+
|
13
|
+
<router-link
|
14
|
+
:to="breadcrumb.to"
|
15
|
+
:exact="true"
|
16
|
+
>
|
17
|
+
{{ breadcrumb.title }}
|
18
|
+
</router-link>
|
19
|
+
</div>
|
16
20
|
</div>
|
21
|
+
|
22
|
+
<v-avatar
|
23
|
+
v-if="expandVisible"
|
24
|
+
class="expand"
|
25
|
+
color="#EEE"
|
26
|
+
size="1.3rem"
|
27
|
+
@click="wrapBreadcrumbs"
|
28
|
+
>
|
29
|
+
<a-icon>$caret{{ wrapBreadcrumbs_ ? 'Up' : 'Down' }}Icon</a-icon>
|
30
|
+
</v-avatar>
|
31
|
+
|
32
|
+
<div
|
33
|
+
v-else
|
34
|
+
class="expandDummy"
|
35
|
+
/>
|
17
36
|
</div>
|
18
37
|
</template>
|
19
38
|
|
@@ -28,6 +47,8 @@ export default class ABreadcrumbs extends Vue {
|
|
28
47
|
breadcrumbs = []
|
29
48
|
titleCache = {}
|
30
49
|
lastRoute = null
|
50
|
+
expandVisible = false
|
51
|
+
wrapBreadcrumbs_ = false
|
31
52
|
|
32
53
|
created () {
|
33
54
|
this.$events.on(SaveEvent.STOP_SAVING, this.afterSave)
|
@@ -101,20 +122,46 @@ export default class ABreadcrumbs extends Vue {
|
|
101
122
|
}
|
102
123
|
|
103
124
|
this.breadcrumbs = breadcrumbs
|
125
|
+
this.wrapBreadcrumbs_ = false
|
126
|
+
|
127
|
+
this.scrollBreadcrumbs()
|
128
|
+
}
|
129
|
+
|
130
|
+
scrollBreadcrumbs () {
|
131
|
+
this.$nextTick(() => {
|
132
|
+
const objDiv = this.$el.querySelector('.breadcrumbs')
|
133
|
+
if (objDiv.scrollWidth > objDiv.offsetWidth) {
|
134
|
+
objDiv.scrollLeft = objDiv.scrollWidth
|
135
|
+
this.expandVisible = true
|
136
|
+
} else {
|
137
|
+
objDiv.scrollLeft = 0
|
138
|
+
this.expandVisible = false
|
139
|
+
}
|
140
|
+
})
|
104
141
|
}
|
105
142
|
|
106
|
-
|
107
|
-
|
108
|
-
if (
|
109
|
-
|
143
|
+
wrapBreadcrumbs () {
|
144
|
+
this.wrapBreadcrumbs_ = !this.wrapBreadcrumbs_
|
145
|
+
if (this.wrapBreadcrumbs_) {
|
146
|
+
const objDiv = this.$el.querySelector('.breadcrumbs')
|
147
|
+
objDiv.scrollLeft = 0
|
148
|
+
} else {
|
149
|
+
this.scrollBreadcrumbs()
|
110
150
|
}
|
111
|
-
return title.toUpperCase()
|
112
151
|
}
|
113
152
|
}
|
114
153
|
</script>
|
115
154
|
|
116
155
|
|
117
156
|
<style lang="scss" scoped>
|
157
|
+
.a-breadcrumbs {
|
158
|
+
overflow: hidden;
|
159
|
+
}
|
160
|
+
|
161
|
+
.breadcrumbs {
|
162
|
+
overflow: hidden;
|
163
|
+
}
|
164
|
+
|
118
165
|
.item {
|
119
166
|
white-space: nowrap;
|
120
167
|
|
@@ -130,4 +177,14 @@ export default class ABreadcrumbs extends Vue {
|
|
130
177
|
}
|
131
178
|
}
|
132
179
|
}
|
180
|
+
|
181
|
+
.expand {
|
182
|
+
cursor: pointer;
|
183
|
+
margin-top: 1px;
|
184
|
+
}
|
185
|
+
|
186
|
+
.expandDummy {
|
187
|
+
width: 1.5rem;
|
188
|
+
height: 1.5rem;
|
189
|
+
}
|
133
190
|
</style>
|
package/src/components/AIcon.vue
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
<template>
|
2
2
|
<v-icon
|
3
|
-
:class="{
|
3
|
+
:class="{button}"
|
4
4
|
v-bind="$attrs"
|
5
5
|
v-on="$listeners"
|
6
6
|
>
|
@@ -13,17 +13,14 @@
|
|
13
13
|
import { Component, Vue } from '@a-vue'
|
14
14
|
|
15
15
|
@Component({
|
16
|
-
props: [
|
16
|
+
props: [{button: false}]
|
17
17
|
})
|
18
18
|
export default class AIcon extends Vue {
|
19
|
-
get isButton () {
|
20
|
-
return this.button !== undefined
|
21
|
-
}
|
22
19
|
}
|
23
20
|
</script>
|
24
21
|
|
25
22
|
<style lang="scss" scoped>
|
26
|
-
.v-icon:not(.
|
23
|
+
.v-icon:not(.button)::after {
|
27
24
|
background: none;
|
28
25
|
}
|
29
26
|
</style>
|
@@ -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
|
|
@@ -4,85 +4,84 @@
|
|
4
4
|
v-if="editor"
|
5
5
|
class="menu-bar"
|
6
6
|
>
|
7
|
-
<
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
</v-btn>
|
7
|
+
<div>
|
8
|
+
<v-btn
|
9
|
+
small
|
10
|
+
:class="['menu-button', {'is-active': focus && editor.isActive('bold')}]"
|
11
|
+
@click="editor.chain().focus().toggleBold().run()"
|
12
|
+
>
|
13
|
+
<v-icon>{{ boldIcon }}</v-icon>
|
14
|
+
</v-btn>
|
15
|
+
|
16
|
+
<v-btn
|
17
|
+
small
|
18
|
+
:class="['menu-button', {'is-active': focus && editor.isActive('italic')}]"
|
19
|
+
@click="editor.chain().focus().toggleItalic().run()"
|
20
|
+
>
|
21
|
+
<v-icon>{{ italicIcon }}</v-icon>
|
22
|
+
</v-btn>
|
23
|
+
|
24
|
+
<v-btn
|
25
|
+
small
|
26
|
+
:class="['menu-button', 'strike', {'is-active': focus && editor.isActive('strike')}]"
|
27
|
+
@click="editor.chain().focus().toggleStrike().run()"
|
28
|
+
>
|
29
|
+
<v-icon>{{ strikeIcon }}</v-icon>
|
30
|
+
</v-btn>
|
31
|
+
|
32
|
+
<v-btn
|
33
|
+
small
|
34
|
+
:class="['menu-button', {'is-active': focus && editor.isActive('heading', {level: 1})}]"
|
35
|
+
@click="editor.chain().focus().toggleHeading({level: 1}).run()"
|
36
|
+
>
|
37
|
+
<v-icon>{{ h1Icon }}</v-icon>
|
38
|
+
</v-btn>
|
39
|
+
|
40
|
+
<v-btn
|
41
|
+
small
|
42
|
+
:class="['menu-button', {'is-active': focus && editor.isActive('heading', {level: 2})}]"
|
43
|
+
@click="editor.chain().focus().toggleHeading({level: 2}).run()"
|
44
|
+
>
|
45
|
+
<v-icon>{{ h2Icon }}</v-icon>
|
46
|
+
</v-btn>
|
47
|
+
|
48
|
+
<v-btn
|
49
|
+
small
|
50
|
+
:class="['menu-button', {'is-active': focus && editor.isActive('bulletList')}]"
|
51
|
+
@click="editor.chain().focus().toggleBulletList().run()"
|
52
|
+
>
|
53
|
+
<v-icon>{{ ulIcon }}</v-icon>
|
54
|
+
</v-btn>
|
55
|
+
|
56
|
+
<v-btn
|
57
|
+
small
|
58
|
+
:class="['menu-button', {'is-active': focus && editor.isActive('orderedList')}]"
|
59
|
+
@click="editor.chain().focus().toggleOrderedList().run()"
|
60
|
+
>
|
61
|
+
<v-icon>{{ olIcon }}</v-icon>
|
62
|
+
</v-btn>
|
63
|
+
|
64
|
+
<v-btn
|
65
|
+
small
|
66
|
+
:class="['menu-button', {'is-active': focus && editor.isActive('blockquote')}]"
|
67
|
+
@click="editor.chain().focus().toggleBlockquote().run()"
|
68
|
+
>
|
69
|
+
<v-icon>{{ commentIcon }}</v-icon>
|
70
|
+
</v-btn>
|
71
|
+
|
72
|
+
<v-btn
|
73
|
+
small
|
74
|
+
class="menu-button"
|
75
|
+
:disabled="initialValue === editor.getHTML()"
|
76
|
+
@click="editor.chain().focus().undo().run()"
|
77
|
+
>
|
78
|
+
<v-icon>{{ undoIcon }}</v-icon>
|
79
|
+
</v-btn>
|
80
|
+
</div>
|
81
|
+
|
82
|
+
<div>
|
83
|
+
<slot name="buttons" />
|
84
|
+
</div>
|
86
85
|
</div>
|
87
86
|
|
88
87
|
<editor-content
|
@@ -119,6 +118,7 @@ import {
|
|
119
118
|
export default class ARichTextArea extends Vue {
|
120
119
|
editor = null
|
121
120
|
internalValue = null
|
121
|
+
initialValue = null
|
122
122
|
focus = false
|
123
123
|
|
124
124
|
boldIcon = mdiFormatBold
|
@@ -133,6 +133,7 @@ export default class ARichTextArea extends Vue {
|
|
133
133
|
redoIcon = mdiRotateRight
|
134
134
|
|
135
135
|
created () {
|
136
|
+
this.initialValue = this.value
|
136
137
|
this.internalValue = this.value
|
137
138
|
}
|
138
139
|
|
@@ -158,14 +159,20 @@ export default class ARichTextArea extends Vue {
|
|
158
159
|
this.$emit('blur')
|
159
160
|
}
|
160
161
|
})
|
161
|
-
|
162
|
-
this.editor.commands.setContent(this.internalValue, false)
|
163
162
|
}
|
164
163
|
|
165
164
|
beforeDestroy () {
|
166
165
|
this.editor.destroy()
|
167
166
|
}
|
168
167
|
|
168
|
+
/**
|
169
|
+
* reset the text area to disable the undo button
|
170
|
+
* e.g. after saving the form while keeping it open
|
171
|
+
*/
|
172
|
+
reset () {
|
173
|
+
this.initialValue = this.value
|
174
|
+
}
|
175
|
+
|
169
176
|
@Watch('value')
|
170
177
|
valueChanged () {
|
171
178
|
this.internalValue = this.value
|
@@ -192,10 +199,6 @@ export default class ARichTextArea extends Vue {
|
|
192
199
|
|
193
200
|
|
194
201
|
<style lang="scss" scoped>
|
195
|
-
.v-input:not(.v-input--is-focused) ::v-deep .v-counter {
|
196
|
-
display: none;
|
197
|
-
}
|
198
|
-
|
199
202
|
.a-rich-text-editor {
|
200
203
|
::v-deep .ProseMirror {
|
201
204
|
&-focused {
|
@@ -205,9 +208,12 @@ export default class ARichTextArea extends Vue {
|
|
205
208
|
}
|
206
209
|
|
207
210
|
.menu-bar {
|
211
|
+
display: flex;
|
212
|
+
justify-content: space-between;
|
208
213
|
margin: -.2rem 0 .5rem -.2rem;
|
209
214
|
}
|
210
215
|
|
216
|
+
.menu-bar .v-btn,
|
211
217
|
.menu-button {
|
212
218
|
padding: 0 !important;
|
213
219
|
width: 30px !important;
|
@@ -239,6 +245,10 @@ export default class ARichTextArea extends Vue {
|
|
239
245
|
&.is-active {
|
240
246
|
background: #ECECEC !important;
|
241
247
|
}
|
248
|
+
|
249
|
+
&[disabled] {
|
250
|
+
background: none !important;
|
251
|
+
}
|
242
252
|
}
|
243
253
|
|
244
254
|
::v-deep .ProseMirror {
|
package/src/components/ARow.vue
CHANGED
@@ -58,13 +58,6 @@ export default class ARow extends Vue {
|
|
58
58
|
<style scoped lang="scss">
|
59
59
|
.a-row {
|
60
60
|
display: flex;
|
61
|
-
overflow: hidden;
|
62
|
-
@media (max-width: 900px), (orientation : portrait) {
|
63
|
-
flex-wrap: wrap;
|
64
|
-
& > * {
|
65
|
-
flex: 0 0 auto;
|
66
|
-
}
|
67
|
-
}
|
68
61
|
|
69
62
|
&.full {
|
70
63
|
width: 100%;
|
@@ -4,9 +4,10 @@
|
|
4
4
|
autocomplete="off"
|
5
5
|
>
|
6
6
|
<slot
|
7
|
+
name="form"
|
7
8
|
:changed="changed"
|
8
9
|
:valid="valid"
|
9
|
-
:
|
10
|
+
:modelToEdit="modelToEdit"
|
10
11
|
/>
|
11
12
|
</v-form>
|
12
13
|
</template>
|
@@ -27,16 +28,22 @@ export default class EditForm extends Vue {
|
|
27
28
|
modelToEdit = null
|
28
29
|
valid = false
|
29
30
|
lastJson = null
|
31
|
+
forcedUnchange = false
|
30
32
|
|
31
33
|
created () {
|
32
34
|
this.reset()
|
33
35
|
}
|
34
36
|
|
37
|
+
forceUnchanged () {
|
38
|
+
this.forcedUnchange = true
|
39
|
+
this.$emit('update:changed', false)
|
40
|
+
}
|
41
|
+
|
35
42
|
reset () {
|
36
43
|
if (this.createModelToEdit) {
|
37
44
|
this.modelToEdit = this.createModelToEdit(this.model)
|
38
|
-
} else {
|
39
|
-
this.modelToEdit = this.model
|
45
|
+
} else if (this.model) {
|
46
|
+
this.modelToEdit = this.model.cloneForEdit()
|
40
47
|
}
|
41
48
|
this.lastJson = this.json
|
42
49
|
}
|
@@ -65,6 +72,9 @@ export default class EditForm extends Vue {
|
|
65
72
|
}
|
66
73
|
|
67
74
|
get changed () {
|
75
|
+
if (this.forcedUnchange) {
|
76
|
+
return false
|
77
|
+
}
|
68
78
|
// console.log(this.json)
|
69
79
|
// console.log(this.lastJson)
|
70
80
|
return this.json !== this.lastJson
|