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
package/styles/test.sass
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-list-item-action v-if="editMenu">
|
|
3
|
+
<common-dropdownMenu :spec="editMenu" :disabled="$isBusy" />
|
|
4
|
+
</v-list-item-action>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
props: {
|
|
10
|
+
editButtons: { type: Array, required: true }
|
|
11
|
+
},
|
|
12
|
+
computed: {
|
|
13
|
+
// This needs to be computed so that it is always up-to-date, regardless of whether:
|
|
14
|
+
// 1. The page is navigated away and the parent component gets reused or
|
|
15
|
+
// 2. There is just a delay in the initialization of the menu variable in ($ready())
|
|
16
|
+
editMenu() {
|
|
17
|
+
if (this.editButtons.length > 0) {
|
|
18
|
+
return {
|
|
19
|
+
icon: { material: { name: "more_vert" } },
|
|
20
|
+
childButtons: this.editButtons
|
|
21
|
+
};
|
|
22
|
+
} else {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
methods: {
|
|
28
|
+
buttonSpec(item) {
|
|
29
|
+
return Object.assign({}, item, {
|
|
30
|
+
view: "button-v1",
|
|
31
|
+
styleClasses: ["text"]
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<style lang="scss" scoped></style>
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-longclick="$onLongPress" class="outer-container">
|
|
3
|
+
<div :class="[spec.editButtons ? 'container-edit' : 'container']">
|
|
4
|
+
<v-card flat :class="mode" class="py-1">
|
|
5
|
+
<v-card-title v-if="mode === 'system'" class="caption">{{
|
|
6
|
+
spec.subtitle
|
|
7
|
+
}}</v-card-title>
|
|
8
|
+
<v-avatar
|
|
9
|
+
v-if="spec.imageUrl && mode !== 'outgoing'"
|
|
10
|
+
class="avatar"
|
|
11
|
+
size="30px"
|
|
12
|
+
>
|
|
13
|
+
<img :src="spec.imageUrl" alt="avatar" />
|
|
14
|
+
</v-avatar>
|
|
15
|
+
<v-card-title
|
|
16
|
+
v-if="spec.title"
|
|
17
|
+
class="font-weight-bold body-2 subtitle"
|
|
18
|
+
>{{ spec.title }}</v-card-title
|
|
19
|
+
>
|
|
20
|
+
<div v-if="mode !== 'system'" class="comment-bubble pa-2">
|
|
21
|
+
{{ spec.subtitle }}
|
|
22
|
+
</div>
|
|
23
|
+
<img
|
|
24
|
+
v-if="spec.image"
|
|
25
|
+
:src="spec.image"
|
|
26
|
+
class="comment-image pa-2"
|
|
27
|
+
:href="taHref(spec)"
|
|
28
|
+
@click="taClick($event, spec)"
|
|
29
|
+
/>
|
|
30
|
+
<v-card-title v-if="spec.subsubtitle" class="subsubtitle caption">{{
|
|
31
|
+
spec.subsubtitle
|
|
32
|
+
}}</v-card-title>
|
|
33
|
+
|
|
34
|
+
<div class="mt-1 chips">
|
|
35
|
+
<template v-for="(spec, index) in chips">
|
|
36
|
+
<v-chip :key="index" class="ma-1" :color="spec.color">
|
|
37
|
+
{{ spec.text }}
|
|
38
|
+
</v-chip>
|
|
39
|
+
</template>
|
|
40
|
+
</div>
|
|
41
|
+
</v-card>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<script>
|
|
47
|
+
export default {
|
|
48
|
+
props: {
|
|
49
|
+
spec: { type: Object, required: true }
|
|
50
|
+
},
|
|
51
|
+
data: function() {
|
|
52
|
+
return {
|
|
53
|
+
position: null,
|
|
54
|
+
mode: null,
|
|
55
|
+
chips: []
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
methods: {
|
|
59
|
+
$ready() {
|
|
60
|
+
const template = this.spec.template;
|
|
61
|
+
this.mode = this.determineMode(template);
|
|
62
|
+
|
|
63
|
+
this.chips = (this.spec.chips || []).map(spec => {
|
|
64
|
+
var color = null;
|
|
65
|
+
this.$type.ifArray(spec.styleClasses, classes => {
|
|
66
|
+
for (const val of ["success", "info", "warning", "error"]) {
|
|
67
|
+
if (classes.includes(val)) {
|
|
68
|
+
color = val;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return Object.assign({}, spec, { color: color });
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
determineMode(template) {
|
|
76
|
+
switch (template) {
|
|
77
|
+
case "commentIncoming":
|
|
78
|
+
case "commentImageIncoming":
|
|
79
|
+
case "commentVideoIncoming":
|
|
80
|
+
return "incoming";
|
|
81
|
+
case "commentOutgoing":
|
|
82
|
+
case "commentImageOutgoing":
|
|
83
|
+
case "commentVideoOutgoing":
|
|
84
|
+
return "outgoing";
|
|
85
|
+
case "systemComment":
|
|
86
|
+
return "system";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<style lang="scss" scoped>
|
|
94
|
+
.outer-container {
|
|
95
|
+
width: 100%;
|
|
96
|
+
display: grid;
|
|
97
|
+
grid-template-columns: 1fr 56px;
|
|
98
|
+
}
|
|
99
|
+
.edit-actions {
|
|
100
|
+
grid-column: 2/3;
|
|
101
|
+
justify-content: center;
|
|
102
|
+
}
|
|
103
|
+
.container,
|
|
104
|
+
.container-edit {
|
|
105
|
+
width: 100%;
|
|
106
|
+
display: grid;
|
|
107
|
+
grid-template-columns: 30% 20% 20% 30%;
|
|
108
|
+
}
|
|
109
|
+
.container-edit {
|
|
110
|
+
padding: 0px;
|
|
111
|
+
grid-column: 1/2;
|
|
112
|
+
}
|
|
113
|
+
.container {
|
|
114
|
+
grid-column: 1/3;
|
|
115
|
+
}
|
|
116
|
+
.system {
|
|
117
|
+
max-height: auto;
|
|
118
|
+
grid-column: 1/5;
|
|
119
|
+
color: #bdbdbd;
|
|
120
|
+
justify-self: center;
|
|
121
|
+
}
|
|
122
|
+
.incoming {
|
|
123
|
+
display: grid;
|
|
124
|
+
grid-template-columns: 36px auto;
|
|
125
|
+
grid-template-rows: 1fr auto 0.5fr;
|
|
126
|
+
grid-column: 1/4;
|
|
127
|
+
|
|
128
|
+
> * {
|
|
129
|
+
justify-self: start;
|
|
130
|
+
grid-column: 2/3;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
> .chips {
|
|
134
|
+
grid-row: 4/4;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
> .comment-bubble {
|
|
138
|
+
background-color: #e6e5ea;
|
|
139
|
+
border-radius: 0px 10px 10px 10px;
|
|
140
|
+
grid-row: 2/3;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
> .comment-image {
|
|
144
|
+
max-width: 100%;
|
|
145
|
+
height: 300px;
|
|
146
|
+
border-radius: 10px !important;
|
|
147
|
+
grid-row: 2/3;
|
|
148
|
+
padding: 0px !important;
|
|
149
|
+
cursor: pointer;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
> .subsubtitle {
|
|
153
|
+
grid-row: 3/4;
|
|
154
|
+
padding: 0;
|
|
155
|
+
color: #9e9e9e;
|
|
156
|
+
padding-top: 4px;
|
|
157
|
+
align-self: start;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
.avatar {
|
|
161
|
+
grid-row: 1/2;
|
|
162
|
+
grid-column: 1/2;
|
|
163
|
+
padding: 0;
|
|
164
|
+
justify-self: center;
|
|
165
|
+
}
|
|
166
|
+
.subtitle {
|
|
167
|
+
grid-row: 1/2;
|
|
168
|
+
grid-column: 2/3;
|
|
169
|
+
padding: 0;
|
|
170
|
+
}
|
|
171
|
+
.outgoing {
|
|
172
|
+
display: grid;
|
|
173
|
+
grid-template-rows: auto 1fr;
|
|
174
|
+
grid-column: 2/5;
|
|
175
|
+
|
|
176
|
+
> * {
|
|
177
|
+
justify-self: end;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
> .comment-bubble {
|
|
181
|
+
background-color: #0084ff;
|
|
182
|
+
color: #fff;
|
|
183
|
+
border-radius: 10px 10px 0px 10px !important;
|
|
184
|
+
grid-row: 1/2;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
> .comment-image {
|
|
188
|
+
max-width: 100%;
|
|
189
|
+
height: 300px;
|
|
190
|
+
border-radius: 10px !important;
|
|
191
|
+
grid-row: 1/2;
|
|
192
|
+
padding: 0px !important;
|
|
193
|
+
cursor: pointer;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
> .subsubtitle {
|
|
197
|
+
grid-row: 2/3;
|
|
198
|
+
padding: 0;
|
|
199
|
+
color: #9e9e9e;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card :href="$href()" @click="$onClick()">
|
|
3
|
+
<v-img :src="spec.imageUrl" height="200" :style="genericStyles()" />
|
|
4
|
+
|
|
5
|
+
<v-list-item v-if="spec.template != 'spacer'">
|
|
6
|
+
<v-list-item-content>
|
|
7
|
+
<v-list-item-title>{{ spec.title }}</v-list-item-title>
|
|
8
|
+
<v-list-item-subtitle v-if="spec.subtitle">{{
|
|
9
|
+
spec.subtitle
|
|
10
|
+
}}</v-list-item-subtitle>
|
|
11
|
+
<v-list-item-subtitle v-if="spec.subsubtitle">{{
|
|
12
|
+
spec.subsubtitle
|
|
13
|
+
}}</v-list-item-subtitle>
|
|
14
|
+
</v-list-item-content>
|
|
15
|
+
|
|
16
|
+
<template-menu :edit-buttons="spec.editButtons || []" />
|
|
17
|
+
</v-list-item>
|
|
18
|
+
</v-card>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script>
|
|
22
|
+
// import Menu from "./menu";
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
// components: {
|
|
26
|
+
// "template-menu": Menu
|
|
27
|
+
// },
|
|
28
|
+
props: {
|
|
29
|
+
spec: { type: Object, required: true }
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-list-item
|
|
3
|
+
v-longclick="$onLongPress"
|
|
4
|
+
:href="$href()"
|
|
5
|
+
style="padding-left: 0"
|
|
6
|
+
@[clickCondition]="$onClick()"
|
|
7
|
+
>
|
|
8
|
+
<v-icon v-if="spec.onReorder" class="handle">drag_indicator</v-icon>
|
|
9
|
+
|
|
10
|
+
<div class="left-universal">
|
|
11
|
+
<template v-for="(item, index) in spec.leftButtons">
|
|
12
|
+
<common-button
|
|
13
|
+
:key="index"
|
|
14
|
+
:spec="buttonSpec(item)"
|
|
15
|
+
:disabled="$isBusy"
|
|
16
|
+
/>
|
|
17
|
+
</template>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<v-list-item-avatar
|
|
21
|
+
v-if="$type.isString(spec.imageUrl)"
|
|
22
|
+
:tile="!spec.avatar"
|
|
23
|
+
class="left-thumbnail"
|
|
24
|
+
>
|
|
25
|
+
<img :src="spec.imageUrl" />
|
|
26
|
+
</v-list-item-avatar>
|
|
27
|
+
<!-- <v-list-item-avatar v-else-if="$type.isObject(spec.icon)">
|
|
28
|
+
<common-icon :spec="spec.icon" />
|
|
29
|
+
</v-list-item-avatar> -->
|
|
30
|
+
<div v-else class="left-icon">
|
|
31
|
+
<v-list-item-avatar v-if="$type.isObject(spec.icon)">
|
|
32
|
+
<common-icon :spec="spec.icon" />
|
|
33
|
+
</v-list-item-avatar>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<v-list-item-content>
|
|
37
|
+
<v-list-item-title>{{ spec.title }}</v-list-item-title>
|
|
38
|
+
<v-list-item-subtitle v-if="spec.subtitle">{{
|
|
39
|
+
spec.subtitle
|
|
40
|
+
}}</v-list-item-subtitle>
|
|
41
|
+
<v-list-item-subtitle v-if="spec.subsubtitle">{{
|
|
42
|
+
spec.subsubtitle
|
|
43
|
+
}}</v-list-item-subtitle>
|
|
44
|
+
|
|
45
|
+
<div>
|
|
46
|
+
<template v-for="(item, index) in chips">
|
|
47
|
+
<v-chip :key="index" class="ma-1" :color="item.color" small>
|
|
48
|
+
{{ item.text }}
|
|
49
|
+
</v-chip>
|
|
50
|
+
</template>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<!-- NOTE: Experimental -->
|
|
54
|
+
<panels-responsive :spec="accessory" />
|
|
55
|
+
</v-list-item-content>
|
|
56
|
+
|
|
57
|
+
<template v-for="(item, index) in spec.rightButtons">
|
|
58
|
+
<common-button
|
|
59
|
+
:key="index"
|
|
60
|
+
:spec="buttonSpec(item)"
|
|
61
|
+
:disabled="$isBusy"
|
|
62
|
+
/>
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<templates-menu :edit-buttons="editButtons" />
|
|
66
|
+
</v-list-item>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<script>
|
|
70
|
+
export default {
|
|
71
|
+
props: {
|
|
72
|
+
spec: { type: Object, required: true }
|
|
73
|
+
},
|
|
74
|
+
data() {
|
|
75
|
+
return {
|
|
76
|
+
accessory: {},
|
|
77
|
+
editButtons: []
|
|
78
|
+
// chips: []
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
computed: {
|
|
82
|
+
clickCondition() {
|
|
83
|
+
if (this.spec.onClick || this.spec.onLongPress) {
|
|
84
|
+
// This will show the clickable indication
|
|
85
|
+
return "click";
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
},
|
|
89
|
+
// Implemented as computed so that it gets reflected when reordering
|
|
90
|
+
chips() {
|
|
91
|
+
return (this.spec.chips || []).map(item => {
|
|
92
|
+
var color = null;
|
|
93
|
+
this.$type.ifArray(item.styleClasses, classes => {
|
|
94
|
+
for (const val of ["success", "info", "warning", "error"]) {
|
|
95
|
+
if (classes.includes(val)) {
|
|
96
|
+
color = val;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return Object.assign({}, item, { color: color });
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
methods: {
|
|
105
|
+
$ready() {
|
|
106
|
+
this.accessory = { childViews: this.spec.accessoryViews };
|
|
107
|
+
this.editButtons = this.spec.editButtons || [];
|
|
108
|
+
},
|
|
109
|
+
buttonSpec(item) {
|
|
110
|
+
return Object.assign({}, item, {
|
|
111
|
+
view: "button-v1",
|
|
112
|
+
styleClasses: item.text ? ["text"] : ["icon"]
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<style lang="scss" scoped>
|
|
120
|
+
@media (min-width: 600px) {
|
|
121
|
+
.left-thumbnail.v-avatar.v-list-item__avatar {
|
|
122
|
+
margin: 6px 6px 6px 6px;
|
|
123
|
+
width: 60px;
|
|
124
|
+
height: 60px;
|
|
125
|
+
}
|
|
126
|
+
.left-icon {
|
|
127
|
+
// margin-left: 16px;
|
|
128
|
+
margin-left: 4px;
|
|
129
|
+
}
|
|
130
|
+
.left-universal {
|
|
131
|
+
padding-left: 16px;
|
|
132
|
+
}
|
|
133
|
+
.handle {
|
|
134
|
+
margin-left: 10px;
|
|
135
|
+
cursor: move;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
</style>
|
package/utils/app.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default class {
|
|
2
|
+
static componentName(jsonName) {
|
|
3
|
+
const name = `${jsonName.replace("/", "-").replace(/-v1$/, "")}`;
|
|
4
|
+
if (!name.includes("-")) {
|
|
5
|
+
// Avoid conflicting with builtin html elements
|
|
6
|
+
return "views-" + name;
|
|
7
|
+
}
|
|
8
|
+
return name;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
static vueName(component) {
|
|
12
|
+
return component.$options._componentTag;
|
|
13
|
+
}
|
|
14
|
+
}
|
package/utils/dom.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default class {
|
|
2
|
+
static get csrfElement() {
|
|
3
|
+
return document.querySelector(`meta[name="csrf-token"]`);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
static getCsrf() {
|
|
7
|
+
return this.csrfElement.getAttribute("content");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static setCsrf(value) {
|
|
11
|
+
return this.csrfElement.setAttribute("content", value);
|
|
12
|
+
}
|
|
13
|
+
}
|
package/utils/form.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export default class {
|
|
2
|
+
// Execution flows:
|
|
3
|
+
// Button -> Button.onClick() -> Utils.http.execute() -- doesn't save autofill values
|
|
4
|
+
// Button -> Button.onClick() -> form.submit() -- doesn't execute Form.onSubmit(), so cannot call Utils.http.execute() there
|
|
5
|
+
// Submit -> Form.onSubmit() -> Utils.http.execute() -- save autofill values, but cannot have submit action nested in another action
|
|
6
|
+
// TOTRY: Button -> Button.onClick() -> form.clickSubmit() -> submit.click() -> Form.onSubmit() -> Utils.http.execute()
|
|
7
|
+
static submitData(form, component) {
|
|
8
|
+
// const form = target.closest("form");
|
|
9
|
+
// const form = this.formElement;
|
|
10
|
+
|
|
11
|
+
// Analogous to Rails' form_with's local
|
|
12
|
+
if (form.dataset.local) {
|
|
13
|
+
form.submit();
|
|
14
|
+
} else {
|
|
15
|
+
const url = form.getAttribute("action");
|
|
16
|
+
const formData = new FormData(form);
|
|
17
|
+
const method = form.getAttribute("method");
|
|
18
|
+
if (method.toUpperCase() === "GET") {
|
|
19
|
+
const data = {
|
|
20
|
+
url: Utils.url.appendParams(url, formData)
|
|
21
|
+
};
|
|
22
|
+
Utils.http.load(data, null, component);
|
|
23
|
+
} else {
|
|
24
|
+
const data = {
|
|
25
|
+
url: url,
|
|
26
|
+
formData: formData
|
|
27
|
+
};
|
|
28
|
+
Utils.http.execute(data, method, component, response => {
|
|
29
|
+
GLib.action.handleResponse(response, component);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/utils/format.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import marked from "marked";
|
|
2
|
+
|
|
3
|
+
export default class {
|
|
4
|
+
static markdown(text) {
|
|
5
|
+
return marked(text, { sanitize: true });
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
static local_iso8601(date) {
|
|
9
|
+
// See https://stackoverflow.com/a/29774197
|
|
10
|
+
const offset = date.getTimezoneOffset();
|
|
11
|
+
return new Date(date.getTime() - offset * 60 * 1000).toISOString();
|
|
12
|
+
// return yourDate.toISOString().split("T")[0];
|
|
13
|
+
}
|
|
14
|
+
}
|
package/utils/hash.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export default class Hash {
|
|
2
|
+
constructor(object) {
|
|
3
|
+
for (const key in object) {
|
|
4
|
+
this[key] = object[key];
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
remove(key) {
|
|
9
|
+
const value = this[key];
|
|
10
|
+
delete this[key];
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
without(...keys) {
|
|
15
|
+
for (const key of keys) {
|
|
16
|
+
this.remove(key);
|
|
17
|
+
}
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
with(...keys) {
|
|
22
|
+
for (const key in this) {
|
|
23
|
+
if (!keys.includes(key)) {
|
|
24
|
+
this.remove(key);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
}
|
package/utils/helper.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import History from "./history";
|
|
2
|
+
import Settings from "./settings";
|
|
3
|
+
import Url from "./url";
|
|
4
|
+
import Http from "./http";
|
|
5
|
+
import Type from "./type";
|
|
6
|
+
import App from "./app";
|
|
7
|
+
import Dom from "./dom";
|
|
8
|
+
import Launch from "./launch";
|
|
9
|
+
import Format from "./format";
|
|
10
|
+
import Ws from "./private/ws";
|
|
11
|
+
|
|
12
|
+
export default class {
|
|
13
|
+
static get history() {
|
|
14
|
+
return History;
|
|
15
|
+
}
|
|
16
|
+
static get settings() {
|
|
17
|
+
return Settings;
|
|
18
|
+
}
|
|
19
|
+
static get url() {
|
|
20
|
+
return Url;
|
|
21
|
+
}
|
|
22
|
+
static get http() {
|
|
23
|
+
return Http;
|
|
24
|
+
}
|
|
25
|
+
static get type() {
|
|
26
|
+
return Type;
|
|
27
|
+
}
|
|
28
|
+
static get app() {
|
|
29
|
+
return App;
|
|
30
|
+
}
|
|
31
|
+
static get dom() {
|
|
32
|
+
return Dom;
|
|
33
|
+
}
|
|
34
|
+
static get format() {
|
|
35
|
+
return Format;
|
|
36
|
+
}
|
|
37
|
+
static get ws() {
|
|
38
|
+
return Ws;
|
|
39
|
+
}
|
|
40
|
+
// Move this to Glib/public ?
|
|
41
|
+
static get launch() {
|
|
42
|
+
return Launch;
|
|
43
|
+
}
|
|
44
|
+
}
|
package/utils/history.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import Vue from "vue";
|
|
2
|
+
|
|
3
|
+
export default class {
|
|
4
|
+
static saveInitialContent(content) {
|
|
5
|
+
// History only handles document's scroll position. It doesn't handle our body div's position
|
|
6
|
+
this.bodyScrollTops = [];
|
|
7
|
+
// This differs from window.history.length in that this only counts internal navigation
|
|
8
|
+
this.navigationCount = 0;
|
|
9
|
+
// Set initial state so we can go back to it
|
|
10
|
+
window.history.replaceState(this._data(content), "", window.location.href);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static get _pageBody() {
|
|
14
|
+
return document.getElementById("page_body");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static _data(content) {
|
|
18
|
+
return { content: content, navigationCount: this.navigationCount };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static pushPage(content, url) {
|
|
22
|
+
// Save scroll position of the current page when navigating to the next page
|
|
23
|
+
this.bodyScrollTops[this.navigationCount] = this._pageBody.scrollTop;
|
|
24
|
+
|
|
25
|
+
this.navigationCount++;
|
|
26
|
+
|
|
27
|
+
// Save data of the next page (page getting pushed)
|
|
28
|
+
window.history.pushState(this._data(content), "", url);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static resetScroll() {
|
|
32
|
+
this._pageBody.scrollTop = 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static restoreOnBackOrForward() {
|
|
36
|
+
const vm = this;
|
|
37
|
+
window.onpopstate = event => {
|
|
38
|
+
// Save scroll position of the current page when navigating through back/forward button
|
|
39
|
+
this.bodyScrollTops[this.navigationCount] = this._pageBody.scrollTop;
|
|
40
|
+
|
|
41
|
+
const data = event.state;
|
|
42
|
+
data.content.__poppedState = true;
|
|
43
|
+
window.vueApp.page = data.content;
|
|
44
|
+
vm.navigationCount = data.navigationCount;
|
|
45
|
+
|
|
46
|
+
Vue.nextTick(() => {
|
|
47
|
+
const scrollTop = this.bodyScrollTops[this.navigationCount];
|
|
48
|
+
this._pageBody.scrollTop = scrollTop;
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static isPoppedState(page) {
|
|
54
|
+
return page.__poppedState == true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static updatePage(url = window.location.href) {
|
|
58
|
+
window.history.replaceState(this._data(window.vueApp.page), "", url);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static back() {
|
|
62
|
+
if (this.navigationCount > 0) {
|
|
63
|
+
window.history.back();
|
|
64
|
+
return true;
|
|
65
|
+
} else {
|
|
66
|
+
console.log("Reached beginning of navigation stack");
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|