glib-web 0.5.77
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/.eslintrc.js +37 -0
- package/LICENSE +201 -0
- package/README.md +33 -0
- package/action.js +167 -0
- package/actions/analytics/logEvent.js +26 -0
- package/actions/auth/creditCard.js +29 -0
- package/actions/auth/restart.js +5 -0
- package/actions/auth/saveCsrfToken.js +12 -0
- package/actions/cables/push.js +38 -0
- package/actions/dialogs/alert.js +15 -0
- package/actions/dialogs/close.js +7 -0
- package/actions/dialogs/notification.js +14 -0
- package/actions/dialogs/oauth.js +6 -0
- package/actions/dialogs/open.js +7 -0
- package/actions/dialogs/options.js +5 -0
- package/actions/dialogs/show.js +5 -0
- package/actions/forms/submit.js +15 -0
- package/actions/http/delete.js +7 -0
- package/actions/http/patch.js +7 -0
- package/actions/http/post.js +7 -0
- package/actions/http/put.js +7 -0
- package/actions/panels/scrollTo.js +18 -0
- package/actions/panels/scrollToBottom.js +11 -0
- package/actions/runMultiple.js +11 -0
- package/actions/sheets/select.js +5 -0
- package/actions/snackbars/alert.js +15 -0
- package/actions/snackbars/select.js +5 -0
- package/actions/timeouts/set.js +20 -0
- package/actions/windows/close.js +13 -0
- package/actions/windows/closeAll.js +16 -0
- package/actions/windows/closeWithReload.js +18 -0
- package/actions/windows/open.js +5 -0
- package/actions/windows/openWeb.js +5 -0
- package/actions/windows/refreshState.js +5 -0
- package/actions/windows/reload.js +24 -0
- package/actions/ws/push.js +35 -0
- package/app.vue +180 -0
- package/components/_button.vue +101 -0
- package/components/_dropdownMenu.vue +76 -0
- package/components/_icon.vue +50 -0
- package/components/_message.vue +25 -0
- package/components/avatar.vue +16 -0
- package/components/banners/alert.vue +49 -0
- package/components/banners/select.vue +82 -0
- package/components/button.vue +13 -0
- package/components/calendar.vue +105 -0
- package/components/charts/column.vue +26 -0
- package/components/charts/line.vue +61 -0
- package/components/chip.vue +24 -0
- package/components/component.vue +222 -0
- package/components/datetime.vue +54 -0
- package/components/fab.vue +33 -0
- package/components/fields/_patternText.vue +61 -0
- package/components/fields/_select.vue +86 -0
- package/components/fields/autocomplete.vue +73 -0
- package/components/fields/check.vue +104 -0
- package/components/fields/checkGroup.vue +51 -0
- package/components/fields/country/countries.js +251 -0
- package/components/fields/country/field.vue +81 -0
- package/components/fields/country/regions.js +12 -0
- package/components/fields/creditCard.vue +105 -0
- package/components/fields/date.vue +24 -0
- package/components/fields/datetime.vue +49 -0
- package/components/fields/dynamicGroup.vue +106 -0
- package/components/fields/dynamicSelect.vue +173 -0
- package/components/fields/file.vue +166 -0
- package/components/fields/googlePlace.vue +158 -0
- package/components/fields/hidden.vue +18 -0
- package/components/fields/location.vue +223 -0
- package/components/fields/newRichText.vue +191 -0
- package/components/fields/phone/countries.js +315 -0
- package/components/fields/phone/field.vue +348 -0
- package/components/fields/phone/sprite.css +1071 -0
- package/components/fields/radio.vue +64 -0
- package/components/fields/radioGroup.vue +93 -0
- package/components/fields/rating.vue +26 -0
- package/components/fields/richText.vue +172 -0
- package/components/fields/select.vue +17 -0
- package/components/fields/stripe/stripeFields.vue +93 -0
- package/components/fields/stripe/stripeIndividualFields.vue +207 -0
- package/components/fields/stripeExternalAccount.vue +135 -0
- package/components/fields/stripeToken.vue +59 -0
- package/components/fields/submit.vue +23 -0
- package/components/fields/text.vue +144 -0
- package/components/fields/textarea.vue +59 -0
- package/components/fields/timeZone.vue +22 -0
- package/components/fields/timer.vue +83 -0
- package/components/h1.vue +28 -0
- package/components/h2.vue +20 -0
- package/components/h3.vue +22 -0
- package/components/h4.vue +20 -0
- package/components/h5.vue +20 -0
- package/components/h6.vue +20 -0
- package/components/hr.vue +13 -0
- package/components/html.vue +13 -0
- package/components/icon.vue +25 -0
- package/components/image.vue +87 -0
- package/components/label.vue +62 -0
- package/components/map.vue +206 -0
- package/components/markdown.vue +52 -0
- package/components/mixins/events.js +178 -0
- package/components/mixins/generic.js +58 -0
- package/components/mixins/list/autoload.js +144 -0
- package/components/mixins/longClick.js +56 -0
- package/components/mixins/scrolling.js +35 -0
- package/components/mixins/styles.js +221 -0
- package/components/mixins/table/autoload.js +131 -0
- package/components/mixins/table/export.js +52 -0
- package/components/mixins/table/import.js +106 -0
- package/components/mixins/text.js +20 -0
- package/components/mixins/ws/actionCable.js +48 -0
- package/components/mixins/ws/phoenixSocket.js +117 -0
- package/components/p.vue +36 -0
- package/components/panels/carousel.vue +55 -0
- package/components/panels/column.vue +117 -0
- package/components/panels/custom.vue +52 -0
- package/components/panels/flow.vue +81 -0
- package/components/panels/form.vue +126 -0
- package/components/panels/horizontal.vue +73 -0
- package/components/panels/list.vue +241 -0
- package/components/panels/responsive.vue +88 -0
- package/components/panels/scroll.vue +68 -0
- package/components/panels/split.vue +52 -0
- package/components/panels/table.vue +234 -0
- package/components/panels/ul.vue +34 -0
- package/components/panels/vertical.vue +71 -0
- package/components/panels/web.vue +11 -0
- package/components/spacer.vue +11 -0
- package/components/switch.vue +42 -0
- package/components/tabBar.vue +44 -0
- package/extensions/array.js +20 -0
- package/extensions/string.js +21 -0
- package/index.js +195 -0
- package/keys.js +12 -0
- package/nav/appbar.vue +117 -0
- package/nav/content.vue +40 -0
- package/nav/dialog.vue +127 -0
- package/nav/drawer.vue +88 -0
- package/nav/drawerButton.vue +28 -0
- package/nav/drawerLabel.vue +21 -0
- package/nav/sheet.vue +57 -0
- package/nav/snackbar.vue +72 -0
- package/package.json +42 -0
- package/settings.json.example +21 -0
- package/static/plugins/alignment/alignment.js +76 -0
- package/static/plugins/alignment/alignment.min.js +1 -0
- package/static/plugins/beyondgrammar/beyondgrammar.js +46 -0
- package/static/plugins/beyondgrammar/beyondgrammar.min.js +1 -0
- package/static/plugins/blockcode/blockcode.js +110 -0
- package/static/plugins/blockcode/blockcode.min.js +1 -0
- package/static/plugins/clips/clips.js +44 -0
- package/static/plugins/clips/clips.min.js +1 -0
- package/static/plugins/counter/counter.js +60 -0
- package/static/plugins/counter/counter.min.js +1 -0
- package/static/plugins/definedlinks/definedlinks.js +64 -0
- package/static/plugins/definedlinks/definedlinks.min.js +1 -0
- package/static/plugins/handle/handle.js +173 -0
- package/static/plugins/handle/handle.min.js +1 -0
- package/static/plugins/icons/icons.js +72 -0
- package/static/plugins/icons/icons.min.js +1 -0
- package/static/plugins/imageposition/imageposition.js +85 -0
- package/static/plugins/imageposition/imageposition.min.js +1 -0
- package/static/plugins/inlineformat/inlineformat.js +85 -0
- package/static/plugins/inlineformat/inlineformat.min.js +1 -0
- package/static/plugins/removeformat/removeformat.js +28 -0
- package/static/plugins/removeformat/removeformat.min.js +1 -0
- package/static/plugins/selector/selector.js +96 -0
- package/static/plugins/selector/selector.min.js +1 -0
- package/static/plugins/specialchars/specialchars.js +63 -0
- package/static/plugins/specialchars/specialchars.min.js +1 -0
- package/static/plugins/textdirection/textdirection.js +55 -0
- package/static/plugins/textdirection/textdirection.min.js +1 -0
- package/static/plugins/textexpander/textexpander.js +46 -0
- package/static/plugins/textexpander/textexpander.min.js +1 -0
- package/static/plugins/underline/underline.js +27 -0
- package/static/plugins/underline/underline.min.js +1 -0
- package/static/redactorx.css +1344 -0
- package/static/redactorx.js +14254 -0
- package/static/redactorx.min.css +1 -0
- package/static/redactorx.min.js +1 -0
- package/static/redactorx.usm.min.js +2 -0
- package/styles/test.sass +3 -0
- package/styles/test.scss +5 -0
- package/templates/_menu.vue +38 -0
- package/templates/comment.vue +202 -0
- package/templates/featured.vue +32 -0
- package/templates/thumbnail.vue +138 -0
- package/templates/unsupported.vue +12 -0
- package/utils/app.js +14 -0
- package/utils/dom.js +13 -0
- package/utils/form.js +34 -0
- package/utils/format.js +14 -0
- package/utils/hash.js +29 -0
- package/utils/helper.js +44 -0
- package/utils/history.js +70 -0
- package/utils/http.js +209 -0
- package/utils/launch.js +135 -0
- package/utils/private/ws.js +22 -0
- package/utils/public.js +23 -0
- package/utils/settings.js +48 -0
- package/utils/storage.js +9 -0
- package/utils/type.js +69 -0
- package/utils/uploader.js +121 -0
- package/utils/url.js +132 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-form
|
|
3
|
+
ref="form"
|
|
4
|
+
:style="parentStyles"
|
|
5
|
+
:action="url"
|
|
6
|
+
:method="spec.method"
|
|
7
|
+
:data-local="spec.local"
|
|
8
|
+
@submit="onSubmit"
|
|
9
|
+
>
|
|
10
|
+
<template v-for="(value, key, index) in params">
|
|
11
|
+
<input
|
|
12
|
+
:key="`hidden_${index}`"
|
|
13
|
+
type="hidden"
|
|
14
|
+
:name="key"
|
|
15
|
+
:value="value"
|
|
16
|
+
/>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<panels-responsive :spec="modifiedSpec" />
|
|
20
|
+
</v-form>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script>
|
|
24
|
+
// import ActionsFormsSubmit from "../../actions/forms/submit";
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
props: {
|
|
28
|
+
spec: { type: Object, required: true }
|
|
29
|
+
},
|
|
30
|
+
data: () => ({
|
|
31
|
+
url: null,
|
|
32
|
+
params: null,
|
|
33
|
+
parentStyles: {},
|
|
34
|
+
formElement: null,
|
|
35
|
+
submitButtons: [],
|
|
36
|
+
modifiedSpec: {}
|
|
37
|
+
}),
|
|
38
|
+
watch: {
|
|
39
|
+
$isBusy: function(val, oldVal) {
|
|
40
|
+
for (const button of this.submitButtons) {
|
|
41
|
+
button._isBusy = val;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
methods: {
|
|
46
|
+
$ready: function() {
|
|
47
|
+
this.$onEvent("forms/addSubmit", e => {
|
|
48
|
+
this.submitButtons.push(e.data);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
this.$onEvent("forms/setBusy", e => {
|
|
52
|
+
if (e.data.value) {
|
|
53
|
+
Utils.http.startIndicator(this);
|
|
54
|
+
} else {
|
|
55
|
+
Utils.http.stopIndicator(this);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.formElement = this.$refs.form.$el;
|
|
60
|
+
this.parentStyles = this.genericStyles({ width: this.spec.width });
|
|
61
|
+
|
|
62
|
+
const { url: url, params: params } = Utils.url.extractFormActionData(
|
|
63
|
+
this.spec.url,
|
|
64
|
+
this.spec.local
|
|
65
|
+
);
|
|
66
|
+
this.url = url;
|
|
67
|
+
this.params = params;
|
|
68
|
+
|
|
69
|
+
let firstAutoFocus = false;
|
|
70
|
+
this.modifiedSpec = this.spec;
|
|
71
|
+
this.modifiedSpec.childViews.map(childView => {
|
|
72
|
+
if (
|
|
73
|
+
childView.view.startsWith("fields/") &&
|
|
74
|
+
childView.view !== "fields/hidden-v1" &&
|
|
75
|
+
!firstAutoFocus
|
|
76
|
+
) {
|
|
77
|
+
childView.autoFocus = true;
|
|
78
|
+
firstAutoFocus = true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return childView;
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
onSubmit(event) {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
event.stopPropagation();
|
|
87
|
+
|
|
88
|
+
this.submit();
|
|
89
|
+
},
|
|
90
|
+
submit() {
|
|
91
|
+
if (this.$refs.form.validate()) {
|
|
92
|
+
// Remove focus from current input field to avoid double submit if the user presses ENTER again.
|
|
93
|
+
document.activeElement.blur();
|
|
94
|
+
|
|
95
|
+
Utils.type.ifObject(
|
|
96
|
+
this.spec.onSubmit,
|
|
97
|
+
onSubmit => {
|
|
98
|
+
const formData = Utils.url.toMap(new FormData(this.formElement));
|
|
99
|
+
const params = {
|
|
100
|
+
[this.spec.paramNameForFormData || "formData"]: formData
|
|
101
|
+
};
|
|
102
|
+
const data = Object.assign({}, onSubmit, params);
|
|
103
|
+
GLib.action.execute(data, null, this);
|
|
104
|
+
},
|
|
105
|
+
() => {
|
|
106
|
+
GLib.form.submitData(this.formElement, this);
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
} else {
|
|
110
|
+
Utils.launch.alert("Make sure all fields are valid");
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
action_clear() {
|
|
114
|
+
this.formElement.reset();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
</script>
|
|
119
|
+
|
|
120
|
+
<style scoped>
|
|
121
|
+
/* .panels-form {
|
|
122
|
+
display: flex;
|
|
123
|
+
flex-direction: column;
|
|
124
|
+
align-items: flex-start;
|
|
125
|
+
} */
|
|
126
|
+
</style>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="cssClasses" :style="cssStyles">
|
|
3
|
+
<template v-for="(item, index) in spec.childViews">
|
|
4
|
+
<ui-component :key="index" :spec="item" />
|
|
5
|
+
</template>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
export default {
|
|
11
|
+
props: {
|
|
12
|
+
spec: { type: Object, required: true }
|
|
13
|
+
},
|
|
14
|
+
computed: {
|
|
15
|
+
cssClasses: function() {
|
|
16
|
+
const classes = this.$classes().concat("layouts-horizontal");
|
|
17
|
+
switch (this.spec.distribution) {
|
|
18
|
+
case "fillEqually":
|
|
19
|
+
classes.push("layouts-horizontal--fill-equally");
|
|
20
|
+
break;
|
|
21
|
+
case "spaceEqually":
|
|
22
|
+
classes.push("layouts-horizontal--space-equally");
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
return classes;
|
|
26
|
+
},
|
|
27
|
+
cssStyles: function() {
|
|
28
|
+
const styles = this.genericStyles();
|
|
29
|
+
switch (this.spec.align) {
|
|
30
|
+
case "middle":
|
|
31
|
+
styles["align-items"] = "center";
|
|
32
|
+
break;
|
|
33
|
+
case "bottom":
|
|
34
|
+
styles["align-items"] = "flex-end";
|
|
35
|
+
break;
|
|
36
|
+
default:
|
|
37
|
+
styles["align-items"] = "flex-start";
|
|
38
|
+
}
|
|
39
|
+
return styles;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
methods: {
|
|
43
|
+
$displayValue() {
|
|
44
|
+
return "flex";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<style scoped>
|
|
51
|
+
.layouts-horizontal {
|
|
52
|
+
display: flex;
|
|
53
|
+
/* overflow: hidden; */
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* From https://stackoverflow.com/questions/13483331/make-buttons-same-width-without-specifying-exact-size */
|
|
57
|
+
.layouts-horizontal--space-equally {
|
|
58
|
+
justify-content: space-around;
|
|
59
|
+
}
|
|
60
|
+
</style>
|
|
61
|
+
|
|
62
|
+
<style>
|
|
63
|
+
.layouts-horizontal--fill-equally > * {
|
|
64
|
+
flex: initial;
|
|
65
|
+
width: 100%;
|
|
66
|
+
}
|
|
67
|
+
.layouts-horizontal--space-equally > * {
|
|
68
|
+
flex: initial;
|
|
69
|
+
}
|
|
70
|
+
/* .layouts-horizontal > div {
|
|
71
|
+
display: inline-block;
|
|
72
|
+
} */
|
|
73
|
+
</style>
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-list
|
|
3
|
+
:two-line="twoLine"
|
|
4
|
+
:three-line="threeLine"
|
|
5
|
+
class="py-0"
|
|
6
|
+
:style="genericStyles()"
|
|
7
|
+
>
|
|
8
|
+
<div ref="topAnchor"></div>
|
|
9
|
+
|
|
10
|
+
<template v-for="(section, sectionIndex) in sections">
|
|
11
|
+
<div :key="`section${sectionIndex}`">
|
|
12
|
+
<panels-responsive v-if="section.header" :spec="section.header" />
|
|
13
|
+
|
|
14
|
+
<draggable
|
|
15
|
+
v-model="section.rows"
|
|
16
|
+
ghost-class="ghost"
|
|
17
|
+
group="a"
|
|
18
|
+
handle=".handle"
|
|
19
|
+
:data-index="sectionIndex"
|
|
20
|
+
@end="onDragEnd"
|
|
21
|
+
>
|
|
22
|
+
<div
|
|
23
|
+
v-for="(row, rowIndex) in section.rows"
|
|
24
|
+
:key="`${sectionIndex}_${rowIndex}`"
|
|
25
|
+
:class="row.styleClasses"
|
|
26
|
+
>
|
|
27
|
+
<v-divider v-if="rowIndex == 0" />
|
|
28
|
+
|
|
29
|
+
<component :is="template(row)" :spec="row" :index="rowIndex" />
|
|
30
|
+
<v-divider
|
|
31
|
+
v-if="
|
|
32
|
+
rowIndex != section.rows.length - 1 ||
|
|
33
|
+
sectionIndex != sections.length - 1
|
|
34
|
+
"
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
</draggable>
|
|
38
|
+
|
|
39
|
+
<panels-responsive v-if="section.footer" :spec="section.footer" />
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<div ref="bottomAnchor" class="py-3 px-4" :style="bottomAnchorStyles">
|
|
44
|
+
Loading...
|
|
45
|
+
</div>
|
|
46
|
+
</v-list>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script>
|
|
50
|
+
import draggable from "vuedraggable";
|
|
51
|
+
import autoloadMixin from "../mixins/list/autoload.js";
|
|
52
|
+
import ThumbnailTemplate from "../../templates/thumbnail";
|
|
53
|
+
import FeaturedTemplate from "../../templates/featured";
|
|
54
|
+
import CommentTemplate from "../../templates/comment";
|
|
55
|
+
import actionCableMixin from "../mixins/ws/actionCable.js";
|
|
56
|
+
|
|
57
|
+
export default {
|
|
58
|
+
components: {
|
|
59
|
+
draggable,
|
|
60
|
+
"template-thumbnail": ThumbnailTemplate,
|
|
61
|
+
"template-featured": FeaturedTemplate,
|
|
62
|
+
"template-commentOutgoing": CommentTemplate,
|
|
63
|
+
"template-commentIncoming": CommentTemplate
|
|
64
|
+
},
|
|
65
|
+
mixins: [autoloadMixin, actionCableMixin],
|
|
66
|
+
props: {
|
|
67
|
+
spec: { type: Object, required: true }
|
|
68
|
+
},
|
|
69
|
+
data: function() {
|
|
70
|
+
return {
|
|
71
|
+
sections: []
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
computed: {
|
|
75
|
+
twoLine() {
|
|
76
|
+
for (const section of this.sections) {
|
|
77
|
+
const rows = section.rows || [];
|
|
78
|
+
for (const row of rows) {
|
|
79
|
+
if (row.subtitle) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
},
|
|
86
|
+
threeLine() {
|
|
87
|
+
for (const section of this.sections) {
|
|
88
|
+
const rows = section.rows || [];
|
|
89
|
+
for (const row of rows) {
|
|
90
|
+
if (row.subsubtitle) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
methods: {
|
|
99
|
+
$ready() {
|
|
100
|
+
this.sections = this.spec.sections || [];
|
|
101
|
+
this.autoloadAll(this.spec.nextPage);
|
|
102
|
+
this.enableInfiniteScrollIfApplicable();
|
|
103
|
+
this.$wsSubscribeEvents(this.spec.phoenixSocket);
|
|
104
|
+
this.$wsInitActionCable(this.spec.actionCable);
|
|
105
|
+
|
|
106
|
+
for (const section of this.sections) {
|
|
107
|
+
section.rows = section.rows || [];
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
action_loadNext(spec) {
|
|
111
|
+
console.log("TODO: load new comments and append to this list", spec);
|
|
112
|
+
// TODO
|
|
113
|
+
// - Load next rows/items from the Rails server
|
|
114
|
+
// - You can pass some parameters (e.g. currentItemId) for pagination
|
|
115
|
+
// - For example, if currentItemId is 56, the server will know that it needs to
|
|
116
|
+
// return items that are newer than 56
|
|
117
|
+
// - You may use other ways for pagination as well
|
|
118
|
+
// - Append the rows to this list
|
|
119
|
+
},
|
|
120
|
+
action_append(spec) {
|
|
121
|
+
for (const [index, appendedSection] of spec.sections.entries()) {
|
|
122
|
+
const section = this.sections[index] || {};
|
|
123
|
+
|
|
124
|
+
if (!section.rows) {
|
|
125
|
+
this.$set(section, "rows", []);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
Utils.type.ifArray(appendedSection.rows, rows => {
|
|
129
|
+
for (const row of rows) {
|
|
130
|
+
section.rows.push(row);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
action_update(spec) {
|
|
136
|
+
const updatedRows = {};
|
|
137
|
+
|
|
138
|
+
Utils.type.ifArray(spec.rows, rows => {
|
|
139
|
+
for (const row of rows) {
|
|
140
|
+
updatedRows[row.id] = row;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
for (const section of this.sections) {
|
|
145
|
+
section.rows = section.rows.map(row => {
|
|
146
|
+
const updatedRow = updatedRows[row.id];
|
|
147
|
+
if (updatedRow) {
|
|
148
|
+
return updatedRow;
|
|
149
|
+
} else {
|
|
150
|
+
return row;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
action_delete(spec) {
|
|
156
|
+
const deletedRows = {};
|
|
157
|
+
Utils.type.ifArray(spec.rows, rows => {
|
|
158
|
+
for (const row of rows) {
|
|
159
|
+
deletedRows[row.id] = row;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
for (const section of this.sections) {
|
|
164
|
+
section.rows = section.rows.filter(row => {
|
|
165
|
+
// return !rows.includes(row.id);
|
|
166
|
+
return !deletedRows[row.id];
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
$tearDown() {
|
|
171
|
+
this.cancelAutoloadRequest();
|
|
172
|
+
},
|
|
173
|
+
template(row) {
|
|
174
|
+
const name = `template-${row.template.replace("/", "-")}`;
|
|
175
|
+
const strict = true;
|
|
176
|
+
if (strict) {
|
|
177
|
+
return name;
|
|
178
|
+
} else {
|
|
179
|
+
if (this.$options.components[name]) {
|
|
180
|
+
return name;
|
|
181
|
+
}
|
|
182
|
+
console.warn(`Invalid template: ${row.template}`);
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
serializedSpec(row) {
|
|
187
|
+
return JSON.stringify(row);
|
|
188
|
+
},
|
|
189
|
+
onDragEnd(event) {
|
|
190
|
+
const targetSectionedRowIndex = event.newIndex;
|
|
191
|
+
if (event.from == event.to && event.oldIndex == targetSectionedRowIndex) {
|
|
192
|
+
console.log("Reordering canceled");
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const targetSectionIndex = this.getSectionIndex(event.to);
|
|
197
|
+
const targetSection = this.getSection(targetSectionIndex);
|
|
198
|
+
// The dragged row is now on the new index
|
|
199
|
+
const draggedRow = targetSection.rows[targetSectionedRowIndex];
|
|
200
|
+
|
|
201
|
+
const targetAbsoluteIndex =
|
|
202
|
+
this.previousSectionsRowCount(event.to) + targetSectionedRowIndex;
|
|
203
|
+
|
|
204
|
+
const mergedSpec = Object.assign(draggedRow.onReorder, {
|
|
205
|
+
[draggedRow.paramNameForFormData || "formData"]: {
|
|
206
|
+
[draggedRow.paramNameForNewIndex]: targetAbsoluteIndex, // Deprecated
|
|
207
|
+
[draggedRow.paramNameForNewAbsoluteIndex ||
|
|
208
|
+
"newAbsoluteIndex"]: targetAbsoluteIndex,
|
|
209
|
+
[draggedRow.paramNameForNewSectionIndex ||
|
|
210
|
+
"newSectionIndex"]: targetSectionIndex,
|
|
211
|
+
[draggedRow.paramNameForNewSectionedRowIndex ||
|
|
212
|
+
"newSectionedRowIndex"]: targetSectionedRowIndex
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
GLib.action.execute(mergedSpec, null, this);
|
|
217
|
+
},
|
|
218
|
+
getSectionIndex(element) {
|
|
219
|
+
return element.dataset.index;
|
|
220
|
+
},
|
|
221
|
+
getSection(sectionIndex) {
|
|
222
|
+
return this.sections[sectionIndex];
|
|
223
|
+
},
|
|
224
|
+
previousSectionsRowCount(element) {
|
|
225
|
+
const sectionIndex = this.getSectionIndex(element);
|
|
226
|
+
let count = 0;
|
|
227
|
+
for (let i = 0; i < sectionIndex; i++) {
|
|
228
|
+
count += this.getSection(i).rows.length;
|
|
229
|
+
}
|
|
230
|
+
return count;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
</script>
|
|
235
|
+
|
|
236
|
+
<style lang="scss" scoped>
|
|
237
|
+
.ghost {
|
|
238
|
+
opacity: 0.5;
|
|
239
|
+
background: #dddddd;
|
|
240
|
+
}
|
|
241
|
+
</style>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="cssClasses"
|
|
4
|
+
:style="$styles()"
|
|
5
|
+
:href="$href()"
|
|
6
|
+
@click="$onClick()"
|
|
7
|
+
>
|
|
8
|
+
<v-row no-gutters class="full-height">
|
|
9
|
+
<template v-for="(item, index) in spec.childViews">
|
|
10
|
+
<ui-component
|
|
11
|
+
v-if="isColumn(item)"
|
|
12
|
+
:key="viewKey(item, index)"
|
|
13
|
+
:spec="item"
|
|
14
|
+
/>
|
|
15
|
+
<div
|
|
16
|
+
v-else
|
|
17
|
+
:key="viewKey(item, index)"
|
|
18
|
+
class="full-width"
|
|
19
|
+
:style="innerStyles"
|
|
20
|
+
>
|
|
21
|
+
<ui-component :spec="item" />
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
</v-row>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script>
|
|
29
|
+
import Vue from "vue";
|
|
30
|
+
|
|
31
|
+
export default {
|
|
32
|
+
props: {
|
|
33
|
+
spec: { type: Object, required: true }
|
|
34
|
+
},
|
|
35
|
+
data() {
|
|
36
|
+
return {
|
|
37
|
+
innerStyles: {}
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
computed: {
|
|
41
|
+
cssClasses() {
|
|
42
|
+
// This panel will be nameless when used in predefined layout (e.g. page.body, list.header, etc.)
|
|
43
|
+
this.spec.view = this.spec.view || "panels/responsive";
|
|
44
|
+
return this.$classes();
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
methods: {
|
|
48
|
+
$ready() {
|
|
49
|
+
let align = null;
|
|
50
|
+
switch (this.spec.align) {
|
|
51
|
+
case "center":
|
|
52
|
+
align = "center";
|
|
53
|
+
break;
|
|
54
|
+
case "right":
|
|
55
|
+
align = "flex-end";
|
|
56
|
+
break;
|
|
57
|
+
default:
|
|
58
|
+
align = "flex-start";
|
|
59
|
+
}
|
|
60
|
+
Vue.set(this.innerStyles, "align-items", align);
|
|
61
|
+
},
|
|
62
|
+
isColumn(item) {
|
|
63
|
+
return item.view == "panels/column-v1";
|
|
64
|
+
},
|
|
65
|
+
viewKey(item, index) {
|
|
66
|
+
// Use view name for key to avoid component reuse issue
|
|
67
|
+
return `view${index}_${item.view}`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<style scoped>
|
|
74
|
+
.row {
|
|
75
|
+
margin-left: 0;
|
|
76
|
+
margin-right: 0;
|
|
77
|
+
}
|
|
78
|
+
.full-width {
|
|
79
|
+
width: 100%;
|
|
80
|
+
flex: 0 0 100%;
|
|
81
|
+
display: flex;
|
|
82
|
+
flex-direction: column;
|
|
83
|
+
}
|
|
84
|
+
/* Needed to ensure that split's sub panels have the same height */
|
|
85
|
+
.full-height {
|
|
86
|
+
height: 100%;
|
|
87
|
+
}
|
|
88
|
+
</style>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="cssClasses" :style="cssStyles">
|
|
3
|
+
<!-- <template v-for="(item, index) in spec.childViews">
|
|
4
|
+
<ui-component :key="`${index}_${item.view}`" :spec="item" />
|
|
5
|
+
</template> -->
|
|
6
|
+
<panels-responsive :spec="spec" />
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script>
|
|
11
|
+
// import Hash from "../../utils/hash";
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
props: {
|
|
15
|
+
spec: { type: Object, required: true }
|
|
16
|
+
},
|
|
17
|
+
computed: {
|
|
18
|
+
cssClasses() {
|
|
19
|
+
const classes = this.$classes().concat("layouts-scroll");
|
|
20
|
+
return classes;
|
|
21
|
+
},
|
|
22
|
+
cssStyles() {
|
|
23
|
+
// // Let the styles be handled by the child panel.
|
|
24
|
+
// const outerSpec = {};
|
|
25
|
+
// outerSpec["padding"] = this.spec["outerPadding"];
|
|
26
|
+
// console.log("outerSpec", outerSpec);
|
|
27
|
+
// const styles = this.$styles(outerSpec);
|
|
28
|
+
//
|
|
29
|
+
// const styles = this.genericStyles();
|
|
30
|
+
// styles.remove("padding-top");
|
|
31
|
+
// styles.remove("padding-bottom");
|
|
32
|
+
// styles.remove("padding-left");
|
|
33
|
+
// styles.remove("padding-right");
|
|
34
|
+
//
|
|
35
|
+
// const styles = this.$styles({
|
|
36
|
+
// width: this.spec.width,
|
|
37
|
+
// height: this.spec.height
|
|
38
|
+
// });
|
|
39
|
+
//
|
|
40
|
+
// console.log("styles", styles);
|
|
41
|
+
|
|
42
|
+
// Let the specified styles be handled by the child panel.
|
|
43
|
+
const styles = this.$styles({
|
|
44
|
+
width: "matchParent"
|
|
45
|
+
});
|
|
46
|
+
return styles;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<style lang="scss" scoped>
|
|
53
|
+
.layouts-scroll {
|
|
54
|
+
overflow: auto;
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
|
|
58
|
+
&::-webkit-scrollbar {
|
|
59
|
+
width: 5px;
|
|
60
|
+
height: 8px;
|
|
61
|
+
background-color: #eee;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
&::-webkit-scrollbar-thumb {
|
|
65
|
+
background: #aaa;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<template v-if="content">
|
|
2
|
+
<div :class="classes()" :style="genericStyles()">
|
|
3
|
+
<div v-if="spec.left" class="layouts-split__side">
|
|
4
|
+
<panels-responsive :spec="spec.left" />
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<div class="layouts-split__expand">
|
|
8
|
+
<panels-responsive v-if="spec.center" :spec="spec.center" />
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<!-- <ui-component :spec="spec.centerView" v-if="spec.centerView" class="panels-split__expand"/>
|
|
12
|
+
<div class="panels-split__expand" v-else></div> -->
|
|
13
|
+
|
|
14
|
+
<div v-if="spec.right" class="layouts-split__side layouts-split__right">
|
|
15
|
+
<panels-responsive :spec="spec.right" />
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script>
|
|
21
|
+
export default {
|
|
22
|
+
props: {
|
|
23
|
+
spec: { type: Object, required: true }
|
|
24
|
+
},
|
|
25
|
+
methods: {
|
|
26
|
+
classes: function() {
|
|
27
|
+
return this.$classes().concat("layouts-split");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<style scoped>
|
|
34
|
+
.layouts-split {
|
|
35
|
+
display: flex;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.layouts-split__expand {
|
|
39
|
+
flex: 1 auto;
|
|
40
|
+
line-height: 1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.layouts-split__side {
|
|
44
|
+
/* Make the side panels take full height */
|
|
45
|
+
display: flex;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.layouts-split__right {
|
|
49
|
+
/* Prevent unnecessary squashing, i.e. text broken into multiple lines */
|
|
50
|
+
flex-shrink: 0;
|
|
51
|
+
}
|
|
52
|
+
</style>
|