glib-web 2.2.1 → 2.3.0
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/LICENSE +0 -0
- package/action.js +24 -2
- package/actions/auth/restart.js +0 -0
- package/actions/commands/custom.js +10 -0
- package/actions/components/update.js +7 -4
- package/actions/dialogs/oauth.js +0 -0
- package/actions/dialogs/options.js +0 -0
- package/actions/windows/openWeb.js +0 -0
- package/app.vue +51 -29
- package/components/_button.vue +3 -1
- package/components/_chip.vue +20 -28
- package/components/_message.vue +0 -0
- package/components/_responsive.vue +14 -12
- package/components/_tooltip.vue +50 -0
- package/components/avatar.vue +3 -22
- package/components/button.vue +5 -31
- package/components/charts/column.vue +2 -2
- package/components/charts/line.vue +2 -2
- package/components/chip.vue +0 -19
- package/components/datetime.vue +0 -0
- package/components/fab.vue +0 -0
- package/components/fields/_select.vue +12 -6
- package/components/fields/country/countries.js +0 -0
- package/components/fields/country/field.vue +0 -0
- package/components/fields/country/regions.js +0 -0
- package/components/fields/datetime.vue +0 -0
- package/components/fields/dynamicSelect.vue +0 -0
- package/components/fields/radio.vue +24 -18
- package/components/fields/richText.vue +1 -1
- package/components/fields/select.vue +15 -1
- package/components/fields/timeZone.vue +0 -0
- package/components/hr.vue +0 -0
- package/components/html.vue +0 -0
- package/components/image.vue +6 -13
- package/components/mixins/longClick.js +0 -0
- package/components/mixins/scrolling.js +0 -0
- package/components/mixins/table/export.js +0 -0
- package/components/mixins/table/import.js +0 -0
- package/components/p.vue +0 -0
- package/components/panels/column.vue +14 -2
- package/components/panels/responsive.vue +8 -2
- package/components/panels/ul.vue +3 -0
- package/index.js +3 -0
- package/keys.js +0 -0
- package/nav/drawerButton.vue +0 -0
- package/package.json +1 -1
- package/plugins/updatableComponent.js +14 -5
- package/settings.json.example +0 -0
- package/styles/test.sass +0 -0
- package/styles/test.scss +0 -0
- package/templates/unsupported.vue +0 -0
- package/utils/app.js +1 -0
- package/utils/component.js +12 -0
- package/utils/dom.js +0 -0
- package/utils/public.js +4 -0
- package/utils/settings.js +0 -0
- package/utils/storage.js +0 -0
- package/utils/url.js +0 -0
- package/components/mixins/tooltip.js +0 -20
- package/nav/content.vue +0 -40
package/LICENSE
CHANGED
|
File without changes
|
package/action.js
CHANGED
|
@@ -49,6 +49,7 @@ import ActionsCreditCard from "./actions/auth/creditCard";
|
|
|
49
49
|
import ActionsAnalyticsLogEvent from "./actions/analytics/logEvent";
|
|
50
50
|
|
|
51
51
|
import ActionCommandsCopy from "./actions/commands/copy";
|
|
52
|
+
import ActionCommandsCustom from "./actions/commands/custom";
|
|
52
53
|
|
|
53
54
|
import ActionToursStart from "./actions/tours/start";
|
|
54
55
|
|
|
@@ -102,11 +103,16 @@ const actions = {
|
|
|
102
103
|
"auth/creditCard": ActionsCreditCard,
|
|
103
104
|
|
|
104
105
|
"analytics/logEvent": ActionsAnalyticsLogEvent,
|
|
106
|
+
|
|
105
107
|
"commands/copy": ActionCommandsCopy,
|
|
108
|
+
"commands/custom": ActionCommandsCustom,
|
|
109
|
+
|
|
106
110
|
"tours/start": ActionToursStart,
|
|
107
111
|
"components/update": ActionComponentsUpdate
|
|
108
112
|
};
|
|
109
113
|
|
|
114
|
+
const customActions = {};
|
|
115
|
+
|
|
110
116
|
export default class Action {
|
|
111
117
|
static execute(spec, component, params = {}) {
|
|
112
118
|
if (!TypeUtils.isObject(spec)) {
|
|
@@ -148,17 +154,21 @@ export default class Action {
|
|
|
148
154
|
}
|
|
149
155
|
|
|
150
156
|
static executeGlobal(name, spec, component, params) {
|
|
157
|
+
this._executeInternal(name, spec, component, params, actions);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static _executeInternal(name, spec, component, params, registry) {
|
|
151
161
|
const actionName = name.replace(/-v1$/, "");
|
|
152
162
|
|
|
153
163
|
try {
|
|
154
|
-
const action = new
|
|
164
|
+
const action = new registry[actionName]();
|
|
155
165
|
const logDisabled = action.logDisabled && action.logDisabled();
|
|
156
166
|
if (!logDisabled) {
|
|
157
167
|
console.log(`Executing "${actionName}"`);
|
|
158
168
|
}
|
|
159
169
|
action.execute(spec, component, params);
|
|
160
170
|
} catch (e) {
|
|
161
|
-
console.
|
|
171
|
+
console.error(
|
|
162
172
|
"Failed executing command",
|
|
163
173
|
actionName,
|
|
164
174
|
`Error: '${e.message}'`
|
|
@@ -178,6 +188,18 @@ export default class Action {
|
|
|
178
188
|
GLib.action.execute(response.onResponse, component);
|
|
179
189
|
window.vueApp.temp.analytics = null;
|
|
180
190
|
}
|
|
191
|
+
|
|
192
|
+
static registerCustom(actionName, action) {
|
|
193
|
+
if (customActions[actionName]) {
|
|
194
|
+
console.error("Command already registered", actionName);
|
|
195
|
+
} else {
|
|
196
|
+
customActions[actionName] = action;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
static executeCustom(name, spec, component, params) {
|
|
201
|
+
this._executeInternal(name, spec, component, params, customActions);
|
|
202
|
+
}
|
|
181
203
|
}
|
|
182
204
|
|
|
183
205
|
window.Action = Action;
|
package/actions/auth/restart.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Hash from "../../utils/hash";
|
|
2
|
+
|
|
3
|
+
export default class {
|
|
4
|
+
execute(spec, component) {
|
|
5
|
+
const properties = new Hash(spec.properties);
|
|
6
|
+
// `spec` might contain params that were coming from other actions (e.g. `formData`).
|
|
7
|
+
Object.assign(properties, spec);
|
|
8
|
+
GLib.action.executeCustom(spec.name, properties, component);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -5,11 +5,14 @@ export default class {
|
|
|
5
5
|
if (!spec.views.length > 1) {
|
|
6
6
|
console.warn("Make sure views only have 1 child!");
|
|
7
7
|
}
|
|
8
|
-
const target = component.updatables[spec.targetId];
|
|
9
|
-
if (!target) console.error("no component found :" + spec.targetId);
|
|
8
|
+
// const target = component.updatables[spec.targetId];
|
|
9
|
+
// if (!target) console.error("no component found :" + spec.targetId);
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const target = GLib.component.findById(spec.targetId);
|
|
12
|
+
if (target) {
|
|
13
|
+
Object.assign(target.spec, spec.views[0]);
|
|
14
|
+
this.updateComponent(target);
|
|
15
|
+
}
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
updateComponent(component) {
|
package/actions/dialogs/oauth.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/app.vue
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-app :class="page.styleClasses">
|
|
3
|
-
<component
|
|
4
|
-
|
|
3
|
+
<component
|
|
4
|
+
:is="containerComponent"
|
|
5
|
+
:spec="formSpec"
|
|
6
|
+
:style="'height: 100%;'"
|
|
7
|
+
>
|
|
8
|
+
<nav-appbar ref="appBar" :page="page" />
|
|
5
9
|
|
|
6
10
|
<v-progress-linear
|
|
7
11
|
v-if="$root.vueApp.indicator"
|
|
@@ -11,29 +15,24 @@
|
|
|
11
15
|
>
|
|
12
16
|
</v-progress-linear>
|
|
13
17
|
|
|
14
|
-
<
|
|
15
|
-
<
|
|
16
|
-
:
|
|
17
|
-
:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
:template="page.template"
|
|
33
|
-
:spec="footer"
|
|
34
|
-
:full-height="false"
|
|
35
|
-
/>
|
|
36
|
-
</div>
|
|
18
|
+
<v-main :style="`height: ${mainHeight}px;`">
|
|
19
|
+
<v-container
|
|
20
|
+
:fluid="page.template == 'fullWidth'"
|
|
21
|
+
:class="containerClasses"
|
|
22
|
+
>
|
|
23
|
+
<div class="pages-header">
|
|
24
|
+
<panels-responsive :spec="header" />
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div id="page_body" class="pages-body body-wrapper">
|
|
28
|
+
<panels-responsive :spec="body" />
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="pages-footer">
|
|
32
|
+
<panels-responsive :spec="footer" />
|
|
33
|
+
</div>
|
|
34
|
+
</v-container>
|
|
35
|
+
</v-main>
|
|
37
36
|
</component>
|
|
38
37
|
</v-app>
|
|
39
38
|
</template>
|
|
@@ -41,7 +40,6 @@
|
|
|
41
40
|
<script>
|
|
42
41
|
import NavAppBar from "./nav/appbar";
|
|
43
42
|
import Utils from "./utils/helper";
|
|
44
|
-
import ContentLayout from "./nav/content";
|
|
45
43
|
import phoenixSocketMixin from "./components/mixins/ws/phoenixSocket.js";
|
|
46
44
|
import actionCableMixin from "./components/mixins/ws/actionCable.js";
|
|
47
45
|
import FormPanel from "./components/panels/form";
|
|
@@ -49,7 +47,6 @@ import FormPanel from "./components/panels/form";
|
|
|
49
47
|
export default {
|
|
50
48
|
components: {
|
|
51
49
|
"nav-appbar": NavAppBar,
|
|
52
|
-
"layouts-content": ContentLayout,
|
|
53
50
|
"panels-form": FormPanel
|
|
54
51
|
},
|
|
55
52
|
mixins: [phoenixSocketMixin, actionCableMixin],
|
|
@@ -58,7 +55,8 @@ export default {
|
|
|
58
55
|
},
|
|
59
56
|
data() {
|
|
60
57
|
return {
|
|
61
|
-
title: "..."
|
|
58
|
+
title: "...",
|
|
59
|
+
mainHeight: 0
|
|
62
60
|
};
|
|
63
61
|
},
|
|
64
62
|
computed: {
|
|
@@ -77,6 +75,11 @@ export default {
|
|
|
77
75
|
}
|
|
78
76
|
return "div";
|
|
79
77
|
},
|
|
78
|
+
containerClasses() {
|
|
79
|
+
const classes = ["hamburger"];
|
|
80
|
+
classes.push(this.page.containerStyleClasses || []);
|
|
81
|
+
return classes;
|
|
82
|
+
},
|
|
80
83
|
// Use computed to ensure that the spec gets updated when the user navigates to another page.
|
|
81
84
|
formSpec() {
|
|
82
85
|
return this.page.fullPageForm;
|
|
@@ -96,6 +99,15 @@ export default {
|
|
|
96
99
|
Utils.http.promptIfDirtyOnUnload();
|
|
97
100
|
},
|
|
98
101
|
methods: {
|
|
102
|
+
$mounted() {
|
|
103
|
+
window.addEventListener(
|
|
104
|
+
"resize",
|
|
105
|
+
event => {
|
|
106
|
+
this.updateMainHeight();
|
|
107
|
+
},
|
|
108
|
+
true
|
|
109
|
+
);
|
|
110
|
+
},
|
|
99
111
|
$ready() {
|
|
100
112
|
document.title = this.page.title;
|
|
101
113
|
|
|
@@ -125,6 +137,15 @@ export default {
|
|
|
125
137
|
GLib.action.execute(this.page.onLoad, this);
|
|
126
138
|
});
|
|
127
139
|
}
|
|
140
|
+
|
|
141
|
+
// Use nextTick() to allow time for the appBar to complete initialization.
|
|
142
|
+
this.$nextTick(() => {
|
|
143
|
+
this.updateMainHeight();
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
updateMainHeight() {
|
|
147
|
+
console.debug("Setting body height");
|
|
148
|
+
this.mainHeight = window.innerHeight - this.$refs.appBar.$el.offsetHeight;
|
|
128
149
|
}
|
|
129
150
|
}
|
|
130
151
|
};
|
|
@@ -178,11 +199,12 @@ body,
|
|
|
178
199
|
|
|
179
200
|
<style scoped>
|
|
180
201
|
/*** Header/footer support ***/
|
|
181
|
-
.
|
|
202
|
+
.hamburger {
|
|
182
203
|
display: flex;
|
|
183
204
|
flex-direction: column;
|
|
184
205
|
justify-content: space-between;
|
|
185
206
|
height: 100%;
|
|
207
|
+
padding: 0;
|
|
186
208
|
}
|
|
187
209
|
|
|
188
210
|
.body-wrapper {
|
package/components/_button.vue
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
:rounded="$classes().includes('rounded')"
|
|
16
16
|
:depressed="$classes().includes('depressed')"
|
|
17
17
|
@click="type == 'submit' ? null : $onClick()"
|
|
18
|
+
v-on="eventHandlers"
|
|
18
19
|
>
|
|
19
20
|
<span><common-icon :spec="spec.icon || {}"/></span>
|
|
20
21
|
<div :class="hideTextOnXs && spec.icon ? 'd-none d-sm-flex' : null">
|
|
@@ -30,7 +31,8 @@ export default {
|
|
|
30
31
|
spec: { type: Object, required: true },
|
|
31
32
|
type: { type: String, default: "button" },
|
|
32
33
|
disabled: { type: Boolean, required: true },
|
|
33
|
-
hideTextOnXs: { type: Boolean }
|
|
34
|
+
hideTextOnXs: { type: Boolean },
|
|
35
|
+
eventHandlers: { type: Object, default: null }
|
|
34
36
|
},
|
|
35
37
|
data: function() {
|
|
36
38
|
return {
|
package/components/_chip.vue
CHANGED
|
@@ -1,37 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:disabled="!spec.tooltip"
|
|
4
|
-
:top="tooltipPositionMatches('top')"
|
|
5
|
-
:right="tooltipPositionMatches('right')"
|
|
6
|
-
:bottom="tooltipPositionMatches('bottom')"
|
|
7
|
-
:left="tooltipPositionMatches('left')"
|
|
8
|
-
>
|
|
2
|
+
<common-tooltip :spec="spec">
|
|
9
3
|
<template v-slot:activator="{ on }">
|
|
10
|
-
<
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
</span>
|
|
4
|
+
<common-badge :spec="spec">
|
|
5
|
+
<v-chip
|
|
6
|
+
v-if="spec.onClick"
|
|
7
|
+
:style="genericStyles()"
|
|
8
|
+
:class="$classes()"
|
|
9
|
+
:href="$href()"
|
|
10
|
+
@click="$onClick()"
|
|
11
|
+
v-on="on"
|
|
12
|
+
>
|
|
13
|
+
{{ spec.text }}
|
|
14
|
+
</v-chip>
|
|
15
|
+
<v-chip v-else :style="genericStyles()" :class="$classes()" v-on="on">
|
|
16
|
+
{{ spec.text }}
|
|
17
|
+
</v-chip>
|
|
18
|
+
</common-badge>
|
|
26
19
|
</template>
|
|
27
|
-
|
|
28
|
-
</v-tooltip>
|
|
20
|
+
</common-tooltip>
|
|
29
21
|
</template>
|
|
30
22
|
|
|
31
23
|
<script>
|
|
32
|
-
import TooltipMixins from "./mixins/tooltip";
|
|
24
|
+
// import TooltipMixins from "./mixins/tooltip";
|
|
33
25
|
export default {
|
|
34
|
-
mixins: [TooltipMixins],
|
|
26
|
+
// mixins: [TooltipMixins],
|
|
35
27
|
props: {
|
|
36
28
|
spec: { type: Object, required: true }
|
|
37
29
|
},
|
|
@@ -50,7 +42,7 @@ export default {
|
|
|
50
42
|
|
|
51
43
|
<style lang="scss" scoped>
|
|
52
44
|
// Prevent hover effect if the chip is not clickable.
|
|
53
|
-
|
|
45
|
+
.v-chip:not(.v-chip--clickable).theme--light:hover:before {
|
|
54
46
|
opacity: 0;
|
|
55
47
|
}
|
|
56
48
|
</style>
|
package/components/_message.vue
CHANGED
|
File without changes
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
:style="$styles()"
|
|
6
6
|
:href="$href()"
|
|
7
7
|
@click="$onClick()"
|
|
8
|
+
v-on="eventHandlers"
|
|
8
9
|
>
|
|
9
10
|
<v-row no-gutters class="full-height">
|
|
10
11
|
<template v-for="(item, index) in spec.childViews">
|
|
@@ -31,13 +32,8 @@ import Vue from "vue";
|
|
|
31
32
|
|
|
32
33
|
export default {
|
|
33
34
|
props: {
|
|
34
|
-
spec: {
|
|
35
|
-
|
|
36
|
-
required: true,
|
|
37
|
-
default: function() {
|
|
38
|
-
return {};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
35
|
+
spec: { type: Object, required: true },
|
|
36
|
+
eventHandlers: { type: Object, default: null }
|
|
41
37
|
},
|
|
42
38
|
data() {
|
|
43
39
|
return {
|
|
@@ -46,12 +42,18 @@ export default {
|
|
|
46
42
|
},
|
|
47
43
|
computed: {
|
|
48
44
|
cssClasses() {
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
// Provide a default name so the panel will not be nameless when used in predefined layouts (e.g. page.body, list.header, etc.)
|
|
46
|
+
return this.$classes(
|
|
47
|
+
Object.assign(
|
|
48
|
+
{
|
|
49
|
+
view: "panels/responsive"
|
|
50
|
+
},
|
|
51
|
+
this.spec
|
|
52
|
+
)
|
|
53
|
+
);
|
|
52
54
|
},
|
|
53
55
|
componentName() {
|
|
54
|
-
return this
|
|
56
|
+
return this.spec.onClick ? "a" : "div";
|
|
55
57
|
}
|
|
56
58
|
},
|
|
57
59
|
methods: {
|
|
@@ -91,7 +93,7 @@ export default {
|
|
|
91
93
|
display: flex;
|
|
92
94
|
flex-direction: column;
|
|
93
95
|
}
|
|
94
|
-
|
|
96
|
+
// Needed to ensure that split's sub panels have the same height
|
|
95
97
|
.full-height {
|
|
96
98
|
height: 100%;
|
|
97
99
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-tooltip
|
|
3
|
+
:disabled="tooltip.disabled"
|
|
4
|
+
:top="tooltipPositionMatches('top')"
|
|
5
|
+
:right="tooltipPositionMatches('right')"
|
|
6
|
+
:bottom="tooltipPositionMatches('bottom')"
|
|
7
|
+
:left="tooltipPositionMatches('left')"
|
|
8
|
+
>
|
|
9
|
+
<template v-slot:activator="{ on }">
|
|
10
|
+
<!-- Pass the slot props through to the caller using the same slot name (i.e. `activator`) -->
|
|
11
|
+
<slot name="activator" :on="on" />
|
|
12
|
+
</template>
|
|
13
|
+
<span> {{ tooltip.text }} </span>
|
|
14
|
+
</v-tooltip>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
// import tooltipMixin from "./mixins/tooltip";
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
// mixins: [tooltipMixin],
|
|
22
|
+
props: {
|
|
23
|
+
spec: { type: Object, required: true }
|
|
24
|
+
},
|
|
25
|
+
data() {
|
|
26
|
+
return {
|
|
27
|
+
tooltip: {},
|
|
28
|
+
childSpec: Object.assign({}, this.spec, { id: undefined })
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
methods: {
|
|
32
|
+
$ready() {
|
|
33
|
+
this.tooltip = this.spec.tooltip || { disabled: true };
|
|
34
|
+
this.childSpec = Object.assign({}, this.spec, { id: undefined });
|
|
35
|
+
},
|
|
36
|
+
// $initAccessories() {
|
|
37
|
+
// this.tooltip = this.spec.tooltip || { disabled: true };
|
|
38
|
+
// },
|
|
39
|
+
tooltipPositionMatches(position) {
|
|
40
|
+
if (this.spec.tooltip && this.spec.tooltip.position) {
|
|
41
|
+
return position == this.spec.tooltip.position;
|
|
42
|
+
} else {
|
|
43
|
+
return position == "bottom";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<style lang="scss" scoped></style>
|
package/components/avatar.vue
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:disabled="tooltip.disabled"
|
|
4
|
-
:top="tooltipPositionMatches('top')"
|
|
5
|
-
:right="tooltipPositionMatches('right')"
|
|
6
|
-
:bottom="tooltipPositionMatches('bottom')"
|
|
7
|
-
:left="tooltipPositionMatches('left')"
|
|
8
|
-
>
|
|
2
|
+
<common-tooltip :spec="spec">
|
|
9
3
|
<template v-slot:activator="{ on }">
|
|
10
4
|
<common-badge :spec="spec">
|
|
11
5
|
<v-avatar :size="spec.size">
|
|
@@ -14,31 +8,18 @@
|
|
|
14
8
|
:style="$styles()"
|
|
15
9
|
:src="spec.url || spec.base64Data"
|
|
16
10
|
@click="$onClick()"
|
|
11
|
+
v-on="on"
|
|
17
12
|
/>
|
|
18
13
|
</v-avatar>
|
|
19
14
|
</common-badge>
|
|
20
15
|
</template>
|
|
21
|
-
|
|
22
|
-
</v-tooltip>
|
|
16
|
+
</common-tooltip>
|
|
23
17
|
</template>
|
|
24
18
|
|
|
25
19
|
<script>
|
|
26
|
-
import TooltipMixins from "./mixins/tooltip";
|
|
27
|
-
|
|
28
20
|
export default {
|
|
29
|
-
mixins: [TooltipMixins],
|
|
30
21
|
props: {
|
|
31
22
|
spec: { type: Object, required: true }
|
|
32
|
-
},
|
|
33
|
-
data() {
|
|
34
|
-
return {
|
|
35
|
-
styles: {}
|
|
36
|
-
};
|
|
37
|
-
},
|
|
38
|
-
methods: {
|
|
39
|
-
$ready() {
|
|
40
|
-
this.$initAccessories();
|
|
41
|
-
}
|
|
42
23
|
}
|
|
43
24
|
};
|
|
44
25
|
</script>
|
package/components/button.vue
CHANGED
|
@@ -1,41 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<v-
|
|
4
|
-
:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
:bottom="tooltipPositionMatches('bottom')"
|
|
8
|
-
:left="tooltipPositionMatches('left')"
|
|
9
|
-
>
|
|
10
|
-
<template v-slot:activator="{ on }">
|
|
11
|
-
<div v-on="on">
|
|
12
|
-
<common-button :spec="childSpec" :disabled="$isBusy" />
|
|
13
|
-
</div>
|
|
14
|
-
</template>
|
|
15
|
-
<span> {{ tooltip.text }} </span>
|
|
16
|
-
</v-tooltip>
|
|
17
|
-
</div>
|
|
2
|
+
<common-tooltip :spec="spec">
|
|
3
|
+
<template v-slot:activator="{ on }">
|
|
4
|
+
<common-button :spec="spec" :disabled="$isBusy" :event-handlers="on" />
|
|
5
|
+
</template>
|
|
6
|
+
</common-tooltip>
|
|
18
7
|
</template>
|
|
19
8
|
|
|
20
9
|
<script>
|
|
21
|
-
import tooltipMixin from "./mixins/tooltip";
|
|
22
|
-
|
|
23
10
|
export default {
|
|
24
|
-
mixins: [tooltipMixin],
|
|
25
11
|
props: {
|
|
26
12
|
spec: { type: Object, required: true }
|
|
27
|
-
},
|
|
28
|
-
data() {
|
|
29
|
-
return {
|
|
30
|
-
tooltip: {},
|
|
31
|
-
childSpec: Object.assign({}, this.spec, { id: undefined })
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
methods: {
|
|
35
|
-
$ready() {
|
|
36
|
-
this.tooltip = this.spec.tooltip || { disabled: true };
|
|
37
|
-
this.childSpec = Object.assign({}, this.spec, { id: undefined });
|
|
38
|
-
}
|
|
39
13
|
}
|
|
40
14
|
};
|
|
41
15
|
</script>
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
// https://chartkick.com/vue
|
|
11
11
|
|
|
12
12
|
import annotation from "../mixins/chart/annotation.js";
|
|
13
|
-
import tooltip from "../mixins/chart/tooltip.js";
|
|
13
|
+
// import tooltip from "../mixins/chart/tooltip.js";
|
|
14
14
|
|
|
15
15
|
export default {
|
|
16
|
-
mixins: [annotation
|
|
16
|
+
mixins: [annotation],
|
|
17
17
|
props: {
|
|
18
18
|
spec: { type: Object, required: true }
|
|
19
19
|
},
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
<script>
|
|
11
11
|
import annotation from "../mixins/chart/annotation.js";
|
|
12
|
-
import tooltip from "../mixins/chart/tooltip.js";
|
|
12
|
+
// import tooltip from "../mixins/chart/tooltip.js";
|
|
13
13
|
|
|
14
14
|
export default {
|
|
15
|
-
mixins: [annotation
|
|
15
|
+
mixins: [annotation],
|
|
16
16
|
props: {
|
|
17
17
|
spec: { type: Object, required: true }
|
|
18
18
|
},
|
package/components/chip.vue
CHANGED
|
@@ -3,28 +3,9 @@
|
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script>
|
|
6
|
-
import TooltipMixins from "./mixins/tooltip";
|
|
7
6
|
export default {
|
|
8
|
-
mixins: [TooltipMixins],
|
|
9
7
|
props: {
|
|
10
8
|
spec: { type: Object, required: true }
|
|
11
|
-
},
|
|
12
|
-
data: function() {
|
|
13
|
-
return {
|
|
14
|
-
tooltip: {}
|
|
15
|
-
};
|
|
16
|
-
},
|
|
17
|
-
methods: {
|
|
18
|
-
$ready() {
|
|
19
|
-
this.tooltip = this.spec.tooltip || {};
|
|
20
|
-
}
|
|
21
9
|
}
|
|
22
10
|
};
|
|
23
11
|
</script>
|
|
24
|
-
|
|
25
|
-
<style lang="scss" scoped>
|
|
26
|
-
// Prevent hover effect if the chip is not clickable.
|
|
27
|
-
span.theme--light.v-chip:hover:before {
|
|
28
|
-
opacity: 0;
|
|
29
|
-
}
|
|
30
|
-
</style>
|
package/components/datetime.vue
CHANGED
|
File without changes
|
package/components/fab.vue
CHANGED
|
File without changes
|
|
@@ -60,12 +60,7 @@ export default {
|
|
|
60
60
|
},
|
|
61
61
|
methods: {
|
|
62
62
|
$ready() {
|
|
63
|
-
this.
|
|
64
|
-
this.append = this.spec.append || {};
|
|
65
|
-
this.rules = this.$validation();
|
|
66
|
-
if (this.defaultValue) {
|
|
67
|
-
this.fieldModel = this.defaultValue;
|
|
68
|
-
}
|
|
63
|
+
this.updateData();
|
|
69
64
|
},
|
|
70
65
|
normalizedOptions() {
|
|
71
66
|
return this.spec.options.map(i => {
|
|
@@ -88,6 +83,17 @@ export default {
|
|
|
88
83
|
GLib.action.execute(onChange, this);
|
|
89
84
|
});
|
|
90
85
|
});
|
|
86
|
+
},
|
|
87
|
+
updateData() {
|
|
88
|
+
this.options = this.normalizedOptions();
|
|
89
|
+
this.append = this.spec.append || {};
|
|
90
|
+
this.rules = this.$validation();
|
|
91
|
+
if (this.defaultValue) {
|
|
92
|
+
this.fieldModel = this.defaultValue;
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
$registryEnabled() {
|
|
96
|
+
return false;
|
|
91
97
|
}
|
|
92
98
|
}
|
|
93
99
|
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<v-
|
|
2
|
+
<common-tooltip :spec="spec">
|
|
3
|
+
<template v-slot:activator="{ on }">
|
|
4
|
+
<!-- <common-button :spec="spec" :disabled="$isBusy" :event-handlers="on" /> -->
|
|
5
|
+
|
|
6
|
+
<div :class="$classes()">
|
|
7
|
+
<!-- <v-tooltip
|
|
4
8
|
:disabled="tooltip.disabled"
|
|
5
9
|
:top="tooltipPositionMatches('top')"
|
|
6
10
|
:right="tooltipPositionMatches('right')"
|
|
7
11
|
:bottom="tooltipPositionMatches('bottom')"
|
|
8
12
|
:left="tooltipPositionMatches('left')"
|
|
9
13
|
>
|
|
10
|
-
<template v-slot:activator="{ on }">
|
|
14
|
+
<template v-slot:activator="{ on }"> -->
|
|
11
15
|
<v-radio
|
|
12
16
|
:label="spec.label"
|
|
13
17
|
:value="spec.value.presence() || vuetifyEmptyString"
|
|
@@ -22,29 +26,31 @@
|
|
|
22
26
|
<glib-component :spec="item" />
|
|
23
27
|
</div>
|
|
24
28
|
</div>
|
|
25
|
-
|
|
29
|
+
<!-- </template>
|
|
26
30
|
<span>{{ tooltip.text }}</span>
|
|
27
|
-
</v-tooltip>
|
|
28
|
-
|
|
31
|
+
</v-tooltip> -->
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
</common-tooltip>
|
|
29
35
|
</template>
|
|
30
36
|
|
|
31
37
|
<script>
|
|
32
|
-
import TooltipMixins from "../mixins/tooltip";
|
|
38
|
+
// import TooltipMixins from "../mixins/tooltip";
|
|
33
39
|
|
|
34
40
|
export default {
|
|
35
|
-
mixins: [TooltipMixins],
|
|
41
|
+
// mixins: [TooltipMixins],
|
|
36
42
|
props: {
|
|
37
43
|
spec: { type: Object, required: true }
|
|
38
|
-
},
|
|
39
|
-
data() {
|
|
40
|
-
return {
|
|
41
|
-
tooltip: {}
|
|
42
|
-
};
|
|
43
|
-
},
|
|
44
|
-
methods: {
|
|
45
|
-
$ready() {
|
|
46
|
-
this.tooltip = this.spec.tooltip || { disabled: true };
|
|
47
|
-
}
|
|
48
44
|
}
|
|
45
|
+
// data() {
|
|
46
|
+
// return {
|
|
47
|
+
// tooltip: {}
|
|
48
|
+
// };
|
|
49
|
+
// },
|
|
50
|
+
// methods: {
|
|
51
|
+
// $ready() {
|
|
52
|
+
// this.tooltip = this.spec.tooltip || { disabled: true };
|
|
53
|
+
// }
|
|
54
|
+
// }
|
|
49
55
|
};
|
|
50
56
|
</script>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<fields-genericSelect :spec="
|
|
2
|
+
<fields-genericSelect ref="delegate" :spec="updatedSpec" />
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script>
|
|
@@ -12,6 +12,20 @@ export default {
|
|
|
12
12
|
},
|
|
13
13
|
props: {
|
|
14
14
|
spec: { type: Object, required: true }
|
|
15
|
+
},
|
|
16
|
+
data() {
|
|
17
|
+
return {
|
|
18
|
+
updatedSpec: this.spec
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
methods: {
|
|
22
|
+
$ready() {
|
|
23
|
+
this.updatedSpec = this.spec;
|
|
24
|
+
},
|
|
25
|
+
action_merge(mergedSpec) {
|
|
26
|
+
Object.assign(this.updatedSpec, mergedSpec);
|
|
27
|
+
this.$refs.delegate.updateData();
|
|
28
|
+
}
|
|
15
29
|
}
|
|
16
30
|
};
|
|
17
31
|
</script>
|
|
File without changes
|
package/components/hr.vue
CHANGED
|
File without changes
|
package/components/html.vue
CHANGED
|
File without changes
|
package/components/image.vue
CHANGED
|
@@ -1,34 +1,27 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:disabled="tooltip.disabled"
|
|
4
|
-
:top="tooltipPositionMatches('top')"
|
|
5
|
-
:right="tooltipPositionMatches('right')"
|
|
6
|
-
:bottom="tooltipPositionMatches('bottom')"
|
|
7
|
-
:left="tooltipPositionMatches('left')"
|
|
8
|
-
>
|
|
2
|
+
<common-tooltip :spec="spec">
|
|
9
3
|
<template v-slot:activator="{ on }">
|
|
10
4
|
<common-badge :spec="spec">
|
|
11
5
|
<!-- TODO: Add support for href and :rel="$rel()" -->
|
|
12
6
|
<v-img
|
|
13
7
|
:src="spec.url || spec.base64Data"
|
|
14
8
|
:style="styles"
|
|
15
|
-
v-on="on"
|
|
16
9
|
@click="$onClick()"
|
|
10
|
+
v-on="on"
|
|
17
11
|
>
|
|
18
12
|
<!-- <v-progress-circular v-if="$isBusy" indeterminate /> -->
|
|
19
13
|
</v-img>
|
|
20
14
|
</common-badge>
|
|
21
15
|
</template>
|
|
22
|
-
|
|
23
|
-
</v-tooltip>
|
|
16
|
+
</common-tooltip>
|
|
24
17
|
</template>
|
|
25
18
|
|
|
26
19
|
<script>
|
|
27
20
|
import Vue from "vue";
|
|
28
|
-
import TooltipMixins from "./mixins/tooltip";
|
|
21
|
+
// import TooltipMixins from "./mixins/tooltip";
|
|
29
22
|
|
|
30
23
|
export default {
|
|
31
|
-
mixins: [TooltipMixins],
|
|
24
|
+
// mixins: [TooltipMixins],
|
|
32
25
|
props: {
|
|
33
26
|
spec: { type: Object, required: true }
|
|
34
27
|
},
|
|
@@ -39,7 +32,7 @@ export default {
|
|
|
39
32
|
},
|
|
40
33
|
methods: {
|
|
41
34
|
$ready() {
|
|
42
|
-
this.$initAccessories();
|
|
35
|
+
// this.$initAccessories();
|
|
43
36
|
|
|
44
37
|
const styles = this.genericStyles(Object.assign({}, this.spec));
|
|
45
38
|
this.styles = styles;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/components/p.vue
CHANGED
|
File without changes
|
|
@@ -5,13 +5,21 @@
|
|
|
5
5
|
:md="md.cols"
|
|
6
6
|
:sm="sm.cols"
|
|
7
7
|
:style="cssStyles()"
|
|
8
|
+
:class="$classes()"
|
|
8
9
|
:cols="xs.cols || 12"
|
|
10
|
+
:order-xl="xl.order"
|
|
11
|
+
:order-lg="lg.order"
|
|
12
|
+
:order-md="md.order"
|
|
13
|
+
:order-sm="sm.order"
|
|
14
|
+
:order="xs.order"
|
|
9
15
|
>
|
|
10
|
-
<panels-responsive :spec="
|
|
16
|
+
<panels-responsive :spec="innerSpec()" />
|
|
11
17
|
</v-col>
|
|
12
18
|
</template>
|
|
13
19
|
|
|
14
20
|
<script>
|
|
21
|
+
import Hash from "../../utils/hash";
|
|
22
|
+
|
|
15
23
|
export default {
|
|
16
24
|
props: {
|
|
17
25
|
spec: { type: Object, required: true }
|
|
@@ -33,8 +41,12 @@ export default {
|
|
|
33
41
|
this.sm = this.spec.sm || this.sm;
|
|
34
42
|
this.xs = this.spec.xs || this.xs;
|
|
35
43
|
},
|
|
44
|
+
innerSpec() {
|
|
45
|
+
// Remove properties that are handled by the container (i.e. v-col).
|
|
46
|
+
return new Hash(this.spec).without("padding").without("styleClasses");
|
|
47
|
+
},
|
|
36
48
|
cssStyles() {
|
|
37
|
-
const styles = this.$styles();
|
|
49
|
+
const styles = Object.assign({}, this.$styles());
|
|
38
50
|
switch (this.$vuetify.breakpoint.name) {
|
|
39
51
|
case "xl":
|
|
40
52
|
this.applyStyles(styles, this.xs);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div style="display: contents;">
|
|
3
|
-
<common-responsive v-if="!hoverViewsSpec" :spec="spec" />
|
|
3
|
+
<!-- <common-responsive v-if="!hoverViewsSpec" :spec="spec" /> -->
|
|
4
4
|
<v-menu
|
|
5
|
-
v-
|
|
5
|
+
v-if="hoverViewsSpec"
|
|
6
6
|
:close-on-content-click="false"
|
|
7
7
|
open-on-hover
|
|
8
8
|
offset-x
|
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
<common-responsive :spec="hoverViewsSpec" />
|
|
19
19
|
</v-card>
|
|
20
20
|
</v-menu>
|
|
21
|
+
<common-tooltip v-else :spec="spec">
|
|
22
|
+
<template v-slot:activator="{ on }">
|
|
23
|
+
<common-responsive :spec="spec" :event-handlers="on" />
|
|
24
|
+
<!-- <common-button :spec="spec" :disabled="$isBusy" :event-handlers="on" /> -->
|
|
25
|
+
</template>
|
|
26
|
+
</common-tooltip>
|
|
21
27
|
</div>
|
|
22
28
|
</template>
|
|
23
29
|
|
package/components/panels/ul.vue
CHANGED
package/index.js
CHANGED
|
@@ -50,6 +50,7 @@ import ResponsivePanel from "./components/panels/responsive";
|
|
|
50
50
|
import Component from "./components/component";
|
|
51
51
|
import CommonIcon from "./components/_icon";
|
|
52
52
|
import CommonBadge from "./components/_badge";
|
|
53
|
+
import CommonTooltip from "./components/_tooltip";
|
|
53
54
|
import CommonButton from "./components/_button";
|
|
54
55
|
import CommonChip from "./components/_chip";
|
|
55
56
|
import CommonMessage from "./components/_message";
|
|
@@ -61,6 +62,7 @@ Vue.component("panels-responsive", ResponsivePanel);
|
|
|
61
62
|
Vue.component("common-button", CommonButton);
|
|
62
63
|
Vue.component("common-icon", CommonIcon);
|
|
63
64
|
Vue.component("common-badge", CommonBadge);
|
|
65
|
+
Vue.component("common-tooltip", CommonTooltip);
|
|
64
66
|
Vue.component("common-chip", CommonChip);
|
|
65
67
|
Vue.component("common-message", CommonMessage);
|
|
66
68
|
Vue.component("common-dropdownMenu", CommonDropdownMenu);
|
|
@@ -174,6 +176,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
174
176
|
stateUpdatedAt: null,
|
|
175
177
|
webSocket: { channels: {}, header: {} },
|
|
176
178
|
actionCable: { channels: {} },
|
|
179
|
+
registeredComponents: [],
|
|
177
180
|
temp: {}
|
|
178
181
|
};
|
|
179
182
|
new Vue({
|
package/keys.js
CHANGED
|
File without changes
|
package/nav/drawerButton.vue
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
install: (Vue, options) => {
|
|
3
|
-
Vue.prototype.updatables = {};
|
|
3
|
+
// Vue.prototype.updatables = {};
|
|
4
|
+
|
|
4
5
|
Vue.mixin({
|
|
5
6
|
created: function() {
|
|
6
7
|
let spec = this.spec;
|
|
7
|
-
if (spec && spec.id) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
if (spec && spec.id && this.$registryEnabled()) {
|
|
9
|
+
GLib.component.register(spec.id, this);
|
|
10
|
+
// Object.assign(this.updatables, {
|
|
11
|
+
// [spec.id]: this
|
|
12
|
+
// });
|
|
13
|
+
// console.log("U", this.updatables);
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
methods: {
|
|
17
|
+
$registryEnabled() {
|
|
18
|
+
// Common classes such as `_select` need to return false so that it doesn't override its parent (e.g. `select`).
|
|
19
|
+
return true;
|
|
11
20
|
}
|
|
12
21
|
}
|
|
13
22
|
});
|
package/settings.json.example
CHANGED
|
File without changes
|
package/styles/test.sass
CHANGED
|
File without changes
|
package/styles/test.scss
CHANGED
|
File without changes
|
|
File without changes
|
package/utils/app.js
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default class {
|
|
2
|
+
static findById(id) {
|
|
3
|
+
const component = window.vueApp.registeredComponents[id];
|
|
4
|
+
if (component) {
|
|
5
|
+
return component;
|
|
6
|
+
}
|
|
7
|
+
console.error("Component not found: " + id);
|
|
8
|
+
}
|
|
9
|
+
static register(id, component) {
|
|
10
|
+
window.vueApp.registeredComponents[id] = component;
|
|
11
|
+
}
|
|
12
|
+
}
|
package/utils/dom.js
CHANGED
|
File without changes
|
package/utils/public.js
CHANGED
|
@@ -3,6 +3,7 @@ import Url from "./url";
|
|
|
3
3
|
import Http from "./http";
|
|
4
4
|
import Type from "./type";
|
|
5
5
|
import Form from "./form";
|
|
6
|
+
import Component from "./component";
|
|
6
7
|
|
|
7
8
|
export default class {
|
|
8
9
|
static get action() {
|
|
@@ -20,4 +21,7 @@ export default class {
|
|
|
20
21
|
static get form() {
|
|
21
22
|
return Form;
|
|
22
23
|
}
|
|
24
|
+
static get component() {
|
|
25
|
+
return Component;
|
|
26
|
+
}
|
|
23
27
|
}
|
package/utils/settings.js
CHANGED
|
File without changes
|
package/utils/storage.js
CHANGED
|
File without changes
|
package/utils/url.js
CHANGED
|
File without changes
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// TODO: Make tooltip reusable component. See _badge.vue
|
|
2
|
-
export default {
|
|
3
|
-
data() {
|
|
4
|
-
return {
|
|
5
|
-
tooltip: {}
|
|
6
|
-
};
|
|
7
|
-
},
|
|
8
|
-
methods: {
|
|
9
|
-
$initAccessories() {
|
|
10
|
-
this.tooltip = this.spec.tooltip || { disabled: true };
|
|
11
|
-
},
|
|
12
|
-
tooltipPositionMatches(position) {
|
|
13
|
-
if (this.spec.tooltip && this.spec.tooltip.position) {
|
|
14
|
-
return position == this.spec.tooltip.position;
|
|
15
|
-
} else {
|
|
16
|
-
return position == "bottom";
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
};
|
package/nav/content.vue
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<v-main :style="outerStyle()">
|
|
3
|
-
<panels-responsive v-if="template == 'fullWidth'" :spec="spec" />
|
|
4
|
-
<v-col v-else cols="12" md="8" offset-md="2" :style="innerStyle()">
|
|
5
|
-
<template v-if="spec">
|
|
6
|
-
<panels-responsive v-if="template == 'flatCentered'" :spec="spec" />
|
|
7
|
-
<v-card v-else :height="$length(spec.height)">
|
|
8
|
-
<panels-responsive :spec="spec" />
|
|
9
|
-
</v-card>
|
|
10
|
-
</template>
|
|
11
|
-
</v-col>
|
|
12
|
-
</v-main>
|
|
13
|
-
</template>
|
|
14
|
-
|
|
15
|
-
<script>
|
|
16
|
-
export default {
|
|
17
|
-
props: {
|
|
18
|
-
spec: { type: Object, required: true },
|
|
19
|
-
template: { type: String, default: null },
|
|
20
|
-
fullHeight: { type: Boolean, required: true }
|
|
21
|
-
},
|
|
22
|
-
methods: {
|
|
23
|
-
outerStyle() {
|
|
24
|
-
if (this.fullHeight) {
|
|
25
|
-
return { height: "100%" };
|
|
26
|
-
}
|
|
27
|
-
return {};
|
|
28
|
-
},
|
|
29
|
-
innerStyle() {
|
|
30
|
-
const style = { padding: "0" };
|
|
31
|
-
if (this.fullHeight) {
|
|
32
|
-
return Object.assign(style, { height: "100%" });
|
|
33
|
-
}
|
|
34
|
-
return style;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
</script>
|
|
39
|
-
|
|
40
|
-
<style scoped></style>
|