glib-web 4.27.2 → 4.28.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/actions/sheets/open.js +2 -1
- package/app.vue +1 -1
- package/components/_internal_button.vue +10 -6
- package/components/charts/series.js +29 -2
- package/components/fields/richText2.vue +107 -7
- package/components/helper.js +5 -1
- package/components/mixins/events.js +2 -1
- package/components/progressCircle.vue +36 -4
- package/components/progressbar.vue +1 -0
- package/nav/dialog.vue +5 -2
- package/package.json +1 -1
- package/utils/settings.js +1 -0
package/actions/sheets/open.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { strandom } from "../../components/helper";
|
|
1
2
|
import { vueApp } from "../../store";
|
|
2
3
|
import http from "../../utils/http";
|
|
3
4
|
|
|
@@ -12,7 +13,7 @@ export default class {
|
|
|
12
13
|
component,
|
|
13
14
|
(response) => {
|
|
14
15
|
vueApp.sheet = {
|
|
15
|
-
spec: response.body,
|
|
16
|
+
spec: Object.assign({}, response.body, { key: strandom() }),
|
|
16
17
|
show: true,
|
|
17
18
|
placement
|
|
18
19
|
};
|
package/app.vue
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<Transition name="slide-fade">
|
|
33
33
|
<v-sheet v-if="vueApp.sheet.show" position="fixed" :class="`views-sheet ${vueApp.sheet.placement}`">
|
|
34
34
|
<glib-component v-for="(rbSpec, index) in vueApp.sheet.spec.childViews" :spec="rbSpec"
|
|
35
|
-
:key="index"></glib-component>
|
|
35
|
+
:key="`${vueApp.sheet.spec.key}-${index}`"></glib-component>
|
|
36
36
|
</v-sheet>
|
|
37
37
|
</Transition>
|
|
38
38
|
<div class="glib-bottomBanner">
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<!-- Use `click.prevent` to prevent bubbling when clicking a dropdown button that is
|
|
3
|
-
located in a list row that has href. -->
|
|
4
2
|
<v-btn :type="type" :disabled="spec.disabled" :style="styles()" :class="$classes()" :href="$href()" :rel="$rel()"
|
|
5
3
|
:variant="variant" :rounded="$classes().includes('rounded') || null" :density="density" :size="size" :color="color"
|
|
6
|
-
:active="$classesInclude('active')" :icon="$classes().includes('icon') ? $vuetify : null" @click
|
|
7
|
-
type == 'submit' ? $dispatchEvent('forms/submit') : $onClick()
|
|
8
|
-
">
|
|
4
|
+
:active="$classesInclude('active')" :icon="$classes().includes('icon') ? $vuetify : null" @click="onClick">
|
|
9
5
|
<!-- <span v-if="spec.icon"><common-icon :spec="spec.icon || {}" /></span> -->
|
|
10
6
|
<common-icon v-if="spec.icon" :spec="spec.icon || {}" />
|
|
11
7
|
<div :class="hideTextOnXs && spec.icon ? 'd-none d-sm-flex' : null">
|
|
@@ -15,7 +11,6 @@
|
|
|
15
11
|
</template>
|
|
16
12
|
|
|
17
13
|
<script>
|
|
18
|
-
import { nextTick } from "vue";
|
|
19
14
|
import { determineColor, determineDensity, determineVariant, determineSize } from '../utils/constant';
|
|
20
15
|
|
|
21
16
|
|
|
@@ -42,6 +37,15 @@ export default {
|
|
|
42
37
|
}
|
|
43
38
|
},
|
|
44
39
|
methods: {
|
|
40
|
+
onClick(e) {
|
|
41
|
+
if (this.type == 'submit') {
|
|
42
|
+
e.preventDefault(); // prevent get submitted twice
|
|
43
|
+
this.$dispatchEvent('forms/submit');
|
|
44
|
+
}
|
|
45
|
+
e.stopPropagation(); // prevent event bubbling
|
|
46
|
+
|
|
47
|
+
this.$onClick();
|
|
48
|
+
},
|
|
45
49
|
// $ready() {
|
|
46
50
|
// this.$type.ifArray(this.spec.styleClasses, val => {
|
|
47
51
|
// this.linkStyling = val.includes("link");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Chart, Colors } from "chart.js";
|
|
2
2
|
import chartDataLabels from 'chartjs-plugin-datalabels';
|
|
3
3
|
import doughnutLabel from 'chartjs-plugin-doughnutlabel-v3';
|
|
4
|
-
import { Vue, vueApp } from "../..";
|
|
4
|
+
import { settings, Vue, vueApp } from "../..";
|
|
5
5
|
import { computePosition, flip, offset } from '@floating-ui/dom';
|
|
6
6
|
|
|
7
7
|
import 'chartkick/chart.js';
|
|
@@ -12,6 +12,8 @@ Chart.register(chartDataLabels);
|
|
|
12
12
|
Chart.register(doughnutLabel);
|
|
13
13
|
Chart.register(Colors);
|
|
14
14
|
|
|
15
|
+
if (settings.chartPlugin.htmlLegendPlugin) Chart.register(settings.chartPlugin.htmlLegendPlugin);
|
|
16
|
+
|
|
15
17
|
import VueChartkick from 'vue-chartkick';
|
|
16
18
|
import { computed } from "vue";
|
|
17
19
|
Vue.use(VueChartkick);
|
|
@@ -122,7 +124,24 @@ function useChart({ dataSeries, spec, multiple = true }) {
|
|
|
122
124
|
let colors = undefined;
|
|
123
125
|
if (spec.colors) colors = spec.colors;
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
let options = {}
|
|
128
|
+
|
|
129
|
+
if (spec.formatYAxis) {
|
|
130
|
+
options = {
|
|
131
|
+
scales: {
|
|
132
|
+
y: {
|
|
133
|
+
ticks: {
|
|
134
|
+
callback: function (value) {
|
|
135
|
+
return `${spec.prefix || ''}${value.toLocaleString()}${spec.suffix || ''}`;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
plugins: {}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
126
145
|
options.plugins = {};
|
|
127
146
|
if (legend) options.plugins.legend = legend;
|
|
128
147
|
if (isDonut) options.cutout = '75%';
|
|
@@ -169,6 +188,14 @@ function useChart({ dataSeries, spec, multiple = true }) {
|
|
|
169
188
|
};
|
|
170
189
|
}
|
|
171
190
|
|
|
191
|
+
if (legend.override) {
|
|
192
|
+
options.plugins.htmlLegend = {
|
|
193
|
+
display: true
|
|
194
|
+
};
|
|
195
|
+
options.plugins.legend = {
|
|
196
|
+
display: false
|
|
197
|
+
};
|
|
198
|
+
}
|
|
172
199
|
return { series, colors, options };
|
|
173
200
|
}
|
|
174
201
|
|
|
@@ -153,19 +153,87 @@ export default defineComponent({
|
|
|
153
153
|
]
|
|
154
154
|
};
|
|
155
155
|
if (props.spec.mentionList) {
|
|
156
|
+
const simpleSource = (searchTerm, renderList, mentionChar) => {
|
|
157
|
+
const matches = props.spec.mentionList.toSorted().map((v, index) => ({ id: index + 1, value: v }));
|
|
158
|
+
|
|
159
|
+
if (searchTerm.length === 0) {
|
|
160
|
+
renderList(matches, searchTerm);
|
|
161
|
+
} else {
|
|
162
|
+
renderList(matches.filter((v) => v.value.toLowerCase().includes(searchTerm)), searchTerm);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const advancedSource = (searchTerm, renderList, mentionChar) => {
|
|
167
|
+
|
|
168
|
+
const compareFn = (a, b) => a.value > b.value;
|
|
169
|
+
const options = props.spec.mentionList.toSorted(compareFn);
|
|
170
|
+
const isGrouped = !!props.spec.mentionList[0].group;
|
|
171
|
+
let matches;
|
|
172
|
+
|
|
173
|
+
if (searchTerm.length === 0) {
|
|
174
|
+
matches = options;
|
|
175
|
+
} else {
|
|
176
|
+
matches = options.filter((v) => v.value.toLowerCase().includes(searchTerm));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (isGrouped) {
|
|
180
|
+
const groupedMatches = Object.groupBy(matches, ({ group }) => group);
|
|
181
|
+
let tmpMatches = [];
|
|
182
|
+
Object.keys(groupedMatches).toSorted().forEach((group) => {
|
|
183
|
+
tmpMatches.push({ id: group, value: group, disabled: true });
|
|
184
|
+
groupedMatches[group].forEach((item) => {
|
|
185
|
+
tmpMatches.push(item);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
matches = tmpMatches;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
renderList(matches, searchTerm);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const source = typeof props.spec.mentionList[0] == 'object' ? advancedSource : simpleSource;
|
|
195
|
+
|
|
156
196
|
Quill.register({ "blots/mention": MentionBlot, "modules/mention": Mention });
|
|
157
197
|
modules.mention = {
|
|
158
198
|
allowedChars: /^[A-Za-z\sÅÄÖåäö]*$/,
|
|
159
199
|
mentionDenotationChars: ["@"],
|
|
160
|
-
|
|
161
|
-
|
|
200
|
+
renderItem: (data) => {
|
|
201
|
+
if (data.disabled) {
|
|
202
|
+
const div = document.createElement("div");
|
|
203
|
+
div.classList.add('glib-quill-group');
|
|
204
|
+
div.innerText = data.value;
|
|
205
|
+
return div;
|
|
206
|
+
}
|
|
207
|
+
const div = document.createElement("div");
|
|
208
|
+
div.classList.add('glib-quill-item');
|
|
209
|
+
|
|
210
|
+
if (data.avatar) {
|
|
211
|
+
const img = document.createElement('img');
|
|
212
|
+
img.src = data.avatar;
|
|
213
|
+
img.classList.add('avatar');
|
|
214
|
+
div.appendChild(img);
|
|
215
|
+
}
|
|
162
216
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
217
|
+
const childDiv = document.createElement('div');
|
|
218
|
+
div.appendChild(childDiv);
|
|
219
|
+
|
|
220
|
+
if (data.text) {
|
|
221
|
+
const title = document.createElement('div');
|
|
222
|
+
title.style.lineHeight = '170%';
|
|
223
|
+
title.innerText = data.text;
|
|
224
|
+
childDiv.appendChild(title);
|
|
167
225
|
}
|
|
168
|
-
|
|
226
|
+
|
|
227
|
+
const subtitle = document.createElement('div');
|
|
228
|
+
subtitle.innerText = data.value;
|
|
229
|
+
childDiv.appendChild(subtitle);
|
|
230
|
+
|
|
231
|
+
return div;
|
|
232
|
+
},
|
|
233
|
+
renderLoading: () => {
|
|
234
|
+
return "Loading...";
|
|
235
|
+
},
|
|
236
|
+
source: source
|
|
169
237
|
};
|
|
170
238
|
}
|
|
171
239
|
onMounted(() => {
|
|
@@ -218,4 +286,36 @@ export default defineComponent({
|
|
|
218
286
|
.ql-container {
|
|
219
287
|
height: fit-content;
|
|
220
288
|
}
|
|
289
|
+
|
|
290
|
+
.glib-quill-group {
|
|
291
|
+
/* padding: 16px 0; */
|
|
292
|
+
color: #A7ADB5;
|
|
293
|
+
font-size: 12px;
|
|
294
|
+
height: 12px;
|
|
295
|
+
line-height: 12px;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.glib-quill-item {
|
|
299
|
+
padding: 8px 0;
|
|
300
|
+
display: flex;
|
|
301
|
+
gap: 12px;
|
|
302
|
+
flex-wrap: nowrap;
|
|
303
|
+
align-items: center;
|
|
304
|
+
|
|
305
|
+
.avatar {
|
|
306
|
+
width: 40px;
|
|
307
|
+
height: 40px;
|
|
308
|
+
border-radius: calc(infinity * 1px);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
div {
|
|
312
|
+
font-size: 14px;
|
|
313
|
+
line-height: 100%;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.ql-mention-list-container {
|
|
318
|
+
padding-top: 8px !important;
|
|
319
|
+
padding-bottom: 8px !important;
|
|
320
|
+
}
|
|
221
321
|
</style>
|
package/components/helper.js
CHANGED
|
@@ -30,4 +30,8 @@ function closest(component, name) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
function strandom() {
|
|
34
|
+
return (Math.random() + 1).toString(36).substring(7) + Date.now().toString();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { realComponent, htmlElement, closest, strandom };
|
|
@@ -1,17 +1,44 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:
|
|
4
|
-
|
|
2
|
+
<div ref="container" :class="containerClass" :style="containerStyle">
|
|
3
|
+
<v-progress-circular ref="progress" :class="$classes()" :rotate="rotate" :size="spec.size || 100"
|
|
4
|
+
:width="spec.width || 20" :color="spec.color" :model-value="model" :indeterminate="spec.indeterminate">
|
|
5
|
+
<div :style="middleTextStyle">
|
|
5
6
|
<div class="value-style text-center">{{ spec.value }}%</div>
|
|
6
7
|
<span v-if="spec.text" class="text-style">{{ spec.text }}</span>
|
|
7
8
|
</div>
|
|
8
|
-
|
|
9
|
+
</v-progress-circular>
|
|
10
|
+
</div>
|
|
9
11
|
</template>
|
|
10
12
|
|
|
11
13
|
<script>
|
|
14
|
+
import { onMounted, ref } from "vue";
|
|
15
|
+
|
|
12
16
|
export default {
|
|
13
17
|
props: {
|
|
14
18
|
spec: { type: Object, required: true }
|
|
19
|
+
},
|
|
20
|
+
setup(props) {
|
|
21
|
+
const container = ref(null);
|
|
22
|
+
const progress = ref(null);
|
|
23
|
+
const model = ref(props.spec.half ? props.spec.value / 2 : props.spec.value);
|
|
24
|
+
const rotate = ref(props.spec.half ? 270 : 0);
|
|
25
|
+
const containerStyle = ref({ width: '100%', height: '100%' });
|
|
26
|
+
const middleTextStyle = ref({});
|
|
27
|
+
const containerClass = ref([]);
|
|
28
|
+
|
|
29
|
+
function getHeight() {
|
|
30
|
+
return parseInt(progress.value.$el.style.height.replace('px', ''));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
onMounted(() => {
|
|
34
|
+
if (props.spec.half) {
|
|
35
|
+
middleTextStyle.value = { marginBottom: `${getHeight() / 3}px` };
|
|
36
|
+
containerStyle.value = { width: '100%', height: `${getHeight() / 2}px` };
|
|
37
|
+
containerClass.value = ['half-circle'];
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return { container, containerClass, containerStyle, middleTextStyle, model, rotate, progress };
|
|
15
42
|
}
|
|
16
43
|
};
|
|
17
44
|
</script>
|
|
@@ -28,4 +55,9 @@ export default {
|
|
|
28
55
|
line-height: 150%;
|
|
29
56
|
font-weight: 400;
|
|
30
57
|
}
|
|
58
|
+
|
|
59
|
+
.half-circle {
|
|
60
|
+
overflow-y: hidden;
|
|
61
|
+
position: relative;
|
|
62
|
+
}
|
|
31
63
|
</style>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
+
|
|
2
3
|
<v-progress-linear :class="$classes()" :height="spec.height" :color="spec.color"
|
|
3
4
|
:background-color="spec.backgroundColor" :disabled="true" :model-value="value_in_percentage"
|
|
4
5
|
:striped="$classes().includes('striped')" :reverse="spec.reversed || false" :rounded="spec.rounded">
|
package/nav/dialog.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-dialog :class="spec.styleClass" :model-value="model" :width="spec.width || 600" :dark="false"
|
|
3
3
|
:fullscreen="fullscreen" :sm-and-down="false" :persistent="true" @click:outside="clickOutside">
|
|
4
|
-
<v-card :style="hamburgerStyles" class="dialog-hamburger">
|
|
4
|
+
<v-card :style="hamburgerStyles" class="dialog-hamburger" :key="dialogKey">
|
|
5
5
|
|
|
6
6
|
<panels-responsive v-if="header" :spec="header" />
|
|
7
7
|
<div :class="`dialog-title ${title ? '' : 'dialog-absolute'}`">
|
|
@@ -46,6 +46,7 @@ import FormPanel from "../components/panels/form.vue";
|
|
|
46
46
|
import { confirmDirty, dialogs } from "../store";
|
|
47
47
|
import { onMounted, ref } from "vue";
|
|
48
48
|
import { usePasteable } from "../components/composable/pasteable";
|
|
49
|
+
import { strandom } from "../components/helper.js";
|
|
49
50
|
|
|
50
51
|
export default {
|
|
51
52
|
expose: ['model', 'close', 'isFormDirty'],
|
|
@@ -84,7 +85,8 @@ export default {
|
|
|
84
85
|
url: null,
|
|
85
86
|
urlLoaded: false,
|
|
86
87
|
isMobile: false,
|
|
87
|
-
formSpec: null
|
|
88
|
+
formSpec: null,
|
|
89
|
+
dialogKey: 'init',
|
|
88
90
|
};
|
|
89
91
|
},
|
|
90
92
|
computed: {
|
|
@@ -157,6 +159,7 @@ export default {
|
|
|
157
159
|
this.url = newSpec.url;
|
|
158
160
|
this.urlLoaded = false;
|
|
159
161
|
this.show(true);
|
|
162
|
+
this.dialogKey = strandom();
|
|
160
163
|
},
|
|
161
164
|
onResize() {
|
|
162
165
|
this.isMobile = window.innerWidth < 600;
|
package/package.json
CHANGED