glib-web 4.30.1 → 4.32.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/browsers/detectCountry.js +38 -31
- package/actions/fields/reset.js +5 -9
- package/actions/http/delete.js +3 -3
- package/actions/http/get.js +1 -26
- package/actions/http/patch.js +2 -3
- package/actions/http/post.js +3 -4
- package/actions/http/put.js +3 -3
- package/actions/http/retry.js +54 -0
- package/actions/logics/run.js +7 -7
- package/actions/util.js +22 -0
- package/app.vue +13 -0
- package/components/composable/form.js +7 -1
- package/components/fields/_patternText.vue +5 -2
- package/components/fields/textarea.vue +6 -3
- package/components/mixins/styles.js +0 -22
- package/components/mixins/table/import.js +5 -5
- package/components/mixins/tooltip.js +29 -16
- package/components/panels/flow.vue +11 -8
- package/components/panels/form.vue +2 -1
- package/components/panels/split.vue +10 -1
- package/nav/dialog.vue +7 -2
- package/package.json +1 -1
- package/store.js +0 -1
- package/utils/launch/dialog.js +4 -0
- package/components/composable/conditional.js +0 -12
|
@@ -1,49 +1,56 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
import HttpGet from '../http/get';
|
|
4
3
|
import countries from "moment-timezone/data/meta/latest.json";
|
|
5
4
|
import Action from "../../action";
|
|
5
|
+
import http from "../../utils/http";
|
|
6
|
+
import merge from 'lodash.merge';
|
|
6
7
|
|
|
7
8
|
export default class {
|
|
8
9
|
async execute(spec, component) {
|
|
9
10
|
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
10
11
|
const countriesWithTimeZone = Object.values(countries.countries).filter((country) => country.zones.includes(timeZone));
|
|
11
12
|
|
|
12
|
-
let data;
|
|
13
|
-
|
|
14
13
|
if (countriesWithTimeZone.length === 1) {
|
|
15
|
-
|
|
16
|
-
formData: {
|
|
17
|
-
country: countriesWithTimeZone[0].name,
|
|
18
|
-
iso: countriesWithTimeZone[0].abbr
|
|
19
|
-
}
|
|
20
|
-
});
|
|
14
|
+
this.handleWithTimezone(countriesWithTimeZone, spec, component);
|
|
21
15
|
} else {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
url: 'http://ip-api.com/json/',
|
|
26
|
-
};
|
|
16
|
+
this.handleWithIp(spec, component);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
handleWithTimezone(countriesWithTimeZone, spec, component) {
|
|
21
|
+
const data = merge({}, spec.onDetect, {
|
|
22
|
+
formData: {
|
|
23
|
+
country: {
|
|
24
|
+
iso_short_name: countriesWithTimeZone[0].name,
|
|
25
|
+
alpha2: countriesWithTimeZone[0].abbr
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
Action.execute(data, component);
|
|
30
|
+
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
handleWithIp(spec, component) {
|
|
33
|
+
http.execute(
|
|
34
|
+
{ url: 'http://ip-api.com/json/' },
|
|
35
|
+
'GET',
|
|
36
|
+
component,
|
|
37
|
+
(page) => {
|
|
38
|
+
const data = merge(
|
|
39
|
+
{},
|
|
40
|
+
spec.onDetect,
|
|
41
|
+
{
|
|
42
|
+
formData: {
|
|
43
|
+
country: {
|
|
44
|
+
iso_short_name: page.country,
|
|
45
|
+
alpha2: page.countryCode
|
|
46
|
+
}
|
|
47
|
+
}
|
|
35
48
|
}
|
|
36
|
-
|
|
37
|
-
} catch ({ error }) {
|
|
38
|
-
console.error('Error:', error);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
49
|
+
);
|
|
42
50
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
51
|
+
Action.execute(data, component);
|
|
52
|
+
},
|
|
53
|
+
(err) => console.error(err)
|
|
54
|
+
);
|
|
48
55
|
}
|
|
49
56
|
}
|
package/actions/fields/reset.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { nextTick } from "vue";
|
|
2
|
+
import { forEachTargets } from "../util";
|
|
2
3
|
|
|
3
4
|
export default class {
|
|
4
5
|
execute(properties, component) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
target.action_resetValue();
|
|
13
|
-
|
|
6
|
+
forEachTargets(
|
|
7
|
+
properties,
|
|
8
|
+
(component) => component.action_resetValue()
|
|
9
|
+
);
|
|
14
10
|
nextTick(() => {
|
|
15
11
|
GLib.action.execute(properties["onReset"], component);
|
|
16
12
|
});
|
package/actions/http/delete.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { httpExecuteWithRetry } from "./retry";
|
|
2
|
+
|
|
1
3
|
export default class {
|
|
2
4
|
execute(properties, controller) {
|
|
3
|
-
|
|
4
|
-
GLib.action.handleResponse(response, controller)
|
|
5
|
-
);
|
|
5
|
+
httpExecuteWithRetry('DELETE', properties, controller);
|
|
6
6
|
}
|
|
7
7
|
}
|
package/actions/http/get.js
CHANGED
|
@@ -1,30 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { retryWithDelay } from "./retry";
|
|
2
2
|
|
|
3
|
-
const wait = ms => new Promise((resolve) => {
|
|
4
|
-
setTimeout(() => resolve(), ms);
|
|
5
|
-
});
|
|
6
|
-
|
|
7
|
-
const retryWithDelay = async (
|
|
8
|
-
fn, retries = settings.httpGet.retries, interval = settings.httpGet.interval,
|
|
9
|
-
finalErr = 'Retry failed'
|
|
10
|
-
) => {
|
|
11
|
-
try {
|
|
12
|
-
// try
|
|
13
|
-
await fn();
|
|
14
|
-
} catch (err) {
|
|
15
|
-
// if no retries left
|
|
16
|
-
// throw error
|
|
17
|
-
if (retries <= 0) {
|
|
18
|
-
return Promise.reject(finalErr);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
//delay the next call
|
|
22
|
-
await wait(interval);
|
|
23
|
-
|
|
24
|
-
//recursively call the same func
|
|
25
|
-
return retryWithDelay(fn, (retries - 1), interval, finalErr);
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
3
|
|
|
29
4
|
export default class {
|
|
30
5
|
execute(spec, component) {
|
package/actions/http/patch.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { httpExecuteWithRetry } from "./retry";
|
|
1
2
|
|
|
2
3
|
export default class {
|
|
3
4
|
execute(properties, controller, params) {
|
|
4
|
-
|
|
5
|
-
GLib.action.handleResponse(response, controller)
|
|
6
|
-
);
|
|
5
|
+
httpExecuteWithRetry('PATCH', properties, controller);
|
|
7
6
|
}
|
|
8
7
|
}
|
package/actions/http/post.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { httpExecuteWithRetry } from "./retry";
|
|
2
|
+
|
|
1
3
|
export default class {
|
|
2
4
|
execute(properties, controller, params) {
|
|
3
|
-
|
|
4
|
-
GLib.http.execute(properties, "POST", controller, response =>
|
|
5
|
-
GLib.action.handleResponse(response, controller)
|
|
6
|
-
);
|
|
5
|
+
httpExecuteWithRetry('POST', properties, controller);
|
|
7
6
|
}
|
|
8
7
|
}
|
package/actions/http/put.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { httpExecuteWithRetry } from "./retry";
|
|
2
|
+
|
|
1
3
|
export default class {
|
|
2
4
|
execute(properties, controller, params) {
|
|
3
|
-
|
|
4
|
-
GLib.action.handleResponse(response, controller)
|
|
5
|
-
);
|
|
5
|
+
httpExecuteWithRetry('PUT', properties, controller);
|
|
6
6
|
}
|
|
7
7
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import Action from "../../action";
|
|
2
|
+
import http from "../../utils/http";
|
|
3
|
+
import { settings } from "../../utils/settings";
|
|
4
|
+
|
|
5
|
+
const wait = ms => new Promise((resolve) => {
|
|
6
|
+
setTimeout(() => resolve(), ms);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const retryWithDelay = async (
|
|
10
|
+
fn, retries = settings.httpGet.retries, interval = settings.httpGet.interval,
|
|
11
|
+
finalErr = 'Retry failed'
|
|
12
|
+
) => {
|
|
13
|
+
try {
|
|
14
|
+
// try
|
|
15
|
+
await fn();
|
|
16
|
+
} catch (err) {
|
|
17
|
+
// if no retries left
|
|
18
|
+
// throw error
|
|
19
|
+
if (retries <= 0) {
|
|
20
|
+
return Promise.reject(finalErr);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//delay the next call
|
|
24
|
+
await wait(interval);
|
|
25
|
+
|
|
26
|
+
//recursively call the same func
|
|
27
|
+
return retryWithDelay(fn, (retries - 1), interval, finalErr);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const httpExecuteWithRetry = (methodName, spec, component) => {
|
|
32
|
+
const func = async () => {
|
|
33
|
+
let err;
|
|
34
|
+
const { promise } = http.execute(
|
|
35
|
+
spec,
|
|
36
|
+
methodName,
|
|
37
|
+
component,
|
|
38
|
+
response => {
|
|
39
|
+
Action.handleResponse(response, component);
|
|
40
|
+
},
|
|
41
|
+
error => {
|
|
42
|
+
if (error == 'Server error') err = new Error(error);
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
await promise;
|
|
47
|
+
|
|
48
|
+
if (err) throw err;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
retryWithDelay(func, spec.retryLimit);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export { retryWithDelay, httpExecuteWithRetry };
|
package/actions/logics/run.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import jsonLogic from 'json-logic-js';
|
|
2
|
-
import {
|
|
2
|
+
import { getAllFormData } from "../../components/composable/form";
|
|
3
3
|
|
|
4
4
|
export default class {
|
|
5
5
|
execute(spec, component) {
|
|
6
|
-
let condition = spec.condition
|
|
6
|
+
let condition = spec.condition;
|
|
7
7
|
|
|
8
|
-
const dynamicGroupEntry = component.$closest("fields/internalDynamicGroupEntry");
|
|
9
|
-
if (dynamicGroupEntry) {
|
|
10
|
-
|
|
11
|
-
}
|
|
8
|
+
// const dynamicGroupEntry = component.$closest("fields/internalDynamicGroupEntry");
|
|
9
|
+
// if (dynamicGroupEntry) {
|
|
10
|
+
// condition = dynamicGroupEntry.$populateIndexes(condition);
|
|
11
|
+
// }
|
|
12
12
|
|
|
13
|
-
const result = jsonLogic.apply(condition, Object.assign({},
|
|
13
|
+
const result = jsonLogic.apply(condition, Object.assign({}, getAllFormData(), spec.variables));
|
|
14
14
|
if (result) {
|
|
15
15
|
this.executeWithPassthroughParams(spec.onTrue, spec, component);
|
|
16
16
|
} else {
|
package/actions/util.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function forEachTargets(spec, cb) {
|
|
2
|
+
if (spec.targetId) {
|
|
3
|
+
const comp = getTarget(spec.targetId);
|
|
4
|
+
cb(comp);
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const components = spec.targetIds.map((id) => getTarget(id)).filter((comp) => comp);
|
|
9
|
+
|
|
10
|
+
components.forEach((comp) => cb(comp));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function getTarget(id) {
|
|
14
|
+
const target = GLib.component.findById(id);
|
|
15
|
+
|
|
16
|
+
if (!target) {
|
|
17
|
+
console.warn("Component ID not found", id);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return target;
|
|
22
|
+
}
|
package/app.vue
CHANGED
|
@@ -391,6 +391,19 @@ body,
|
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
/******/
|
|
394
|
+
|
|
395
|
+
// override textarea style
|
|
396
|
+
.fields-textarea .v-input--disabled {
|
|
397
|
+
pointer-events: unset;
|
|
398
|
+
|
|
399
|
+
.v-field--disabled {
|
|
400
|
+
pointer-events: unset;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.fields-textarea .v-input--readonly {
|
|
405
|
+
pointer-events: unset;
|
|
406
|
+
}
|
|
394
407
|
</style>
|
|
395
408
|
|
|
396
409
|
<style scoped>
|
|
@@ -38,6 +38,12 @@ const getFormData = (el, ignoredFields = new Set()) => {
|
|
|
38
38
|
return obj;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
function getAllFormData() {
|
|
42
|
+
return Array.from(document.querySelectorAll('form')).reduce((prev, curr) => {
|
|
43
|
+
return Object.assign({}, prev, getFormData(curr));
|
|
44
|
+
}, {});
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
function useGlibForm({ formRef }) {
|
|
42
48
|
const initFormData = ref({});
|
|
43
49
|
const currentFormData = ref({});
|
|
@@ -112,4 +118,4 @@ function useGlibInput({ props, cacheValue = true }) {
|
|
|
112
118
|
|
|
113
119
|
}
|
|
114
120
|
|
|
115
|
-
export { setBusy, triggerOnChange, triggerOnInput, useGlibForm, useGlibInput, getFormData };
|
|
121
|
+
export { setBusy, triggerOnChange, triggerOnInput, useGlibForm, useGlibInput, getFormData, getAllFormData };
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
<div :style="$styles()" :class="$classes()" v-if="loadIf">
|
|
3
3
|
<button-date v-if="spec.template" :type="type" :spec="spec" @datePicked="handleDatePicked"></button-date>
|
|
4
4
|
<!-- See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date for why we need to use `pattern` -->
|
|
5
|
-
<v-text-field v-else :color="gcolor" v-model="fieldModel" :name="fieldName" :label="spec.label"
|
|
6
|
-
:type="type" :readonly="spec.readOnly" :disabled="inputDisabled" :min="sanitizeValue(spec.min)"
|
|
5
|
+
<v-text-field v-else ref="field" :color="gcolor" v-model="fieldModel" :name="fieldName" :label="spec.label"
|
|
6
|
+
:hint="spec.hint" :type="type" :readonly="spec.readOnly" :disabled="inputDisabled" :min="sanitizeValue(spec.min)"
|
|
7
7
|
:max="sanitizeValue(spec.max)" :pattern="pattern" :rules="$validation()" :style="$styles()"
|
|
8
8
|
:density="$classes().includes('compact') ? 'compact' : 'default'" :clearable="spec.clearable" @change="onChange"
|
|
9
9
|
:variant="variant" validate-on="blur" persistent-placeholder />
|
|
@@ -43,6 +43,9 @@ export default {
|
|
|
43
43
|
this.fieldModel = value;
|
|
44
44
|
this.$executeOnChange();
|
|
45
45
|
},
|
|
46
|
+
action_focus() {
|
|
47
|
+
this.$refs.field.focus();
|
|
48
|
+
},
|
|
46
49
|
$registryEnabled() {
|
|
47
50
|
return false;
|
|
48
51
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :style="styles()" :class="$classes()" v-if="loadIf">
|
|
3
|
-
<v-textarea :color="gcolor" v-model="fieldModel" :label="spec.label" :name="fieldName" :hint="spec.hint"
|
|
3
|
+
<v-textarea ref="field" :color="gcolor" v-model="fieldModel" :label="spec.label" :name="fieldName" :hint="spec.hint"
|
|
4
4
|
:placeholder="spec.placeholder" :maxlength="spec.maxLength || 255" :readonly="spec.readOnly" :height="height"
|
|
5
5
|
:rules="$validation()" counter :outlined="$classes().includes('outlined')" :disabled="inputDisabled"
|
|
6
6
|
:no-resize="$classes().includes('no-resize')" validate-on="blur" :variant="variant" :density="density"
|
|
@@ -41,8 +41,11 @@ export default {
|
|
|
41
41
|
},
|
|
42
42
|
onChange: eventFiltering.debounce(function () {
|
|
43
43
|
this.$executeOnChange();
|
|
44
|
-
}, 300)
|
|
45
|
-
|
|
44
|
+
}, 300),
|
|
45
|
+
action_focus() {
|
|
46
|
+
this.$refs.field.focus();
|
|
47
|
+
},
|
|
48
|
+
},
|
|
46
49
|
};
|
|
47
50
|
</script>
|
|
48
51
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import Hash from "../../utils/hash";
|
|
2
|
-
import { fieldModels, watchFieldModels } from "../composable/conditional";
|
|
3
2
|
import { determineColor } from "../../utils/constant";
|
|
4
|
-
import Action from "../../action";
|
|
5
3
|
import { triggerOnChange } from "../composable/form";
|
|
6
4
|
import { realComponent } from "../helper";
|
|
7
5
|
import set from "lodash.set";
|
|
@@ -118,7 +116,6 @@ export default {
|
|
|
118
116
|
val = "";
|
|
119
117
|
}
|
|
120
118
|
|
|
121
|
-
Object.assign(fieldModels, { [this.fieldName]: val });
|
|
122
119
|
},
|
|
123
120
|
spec: {
|
|
124
121
|
handler(spec, oldSpec) {
|
|
@@ -128,17 +125,11 @@ export default {
|
|
|
128
125
|
valueChanged = false;
|
|
129
126
|
}
|
|
130
127
|
this._linkFieldModels(valueChanged);
|
|
131
|
-
this._initConditional(oldSpec);
|
|
132
128
|
}
|
|
133
129
|
},
|
|
134
130
|
immediate: true
|
|
135
131
|
}
|
|
136
132
|
},
|
|
137
|
-
unmounted() {
|
|
138
|
-
if (fieldModels[this.fieldName]) {
|
|
139
|
-
delete fieldModels[this.fieldName];
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
133
|
methods: {
|
|
143
134
|
viewKey(item, index) {
|
|
144
135
|
if (!item || !item.view) return '';
|
|
@@ -152,19 +143,6 @@ export default {
|
|
|
152
143
|
const childViewLength = item.childViews ? item.childViews.length : 0;
|
|
153
144
|
return `${item.view}_${index}_${childViewLength}`;
|
|
154
145
|
},
|
|
155
|
-
_initConditional(oldSpec) {
|
|
156
|
-
// unreg old fieldName
|
|
157
|
-
if (oldSpec && fieldModels[oldSpec.name] && oldSpec.name != this.spec.name) {
|
|
158
|
-
delete fieldModels[oldSpec.name];
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
},
|
|
162
|
-
setFieldModel(name, value) {
|
|
163
|
-
fieldModels[name] = value;
|
|
164
|
-
},
|
|
165
|
-
getFieldModel(name) {
|
|
166
|
-
return fieldModels[name];
|
|
167
|
-
},
|
|
168
146
|
// NOTE: Styles are dynamic, do not save it in $ready().
|
|
169
147
|
$styles(spec) {
|
|
170
148
|
const properties = spec || this.spec;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getAllFormData } from "../../composable/form";
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
|
-
data: function() {
|
|
4
|
+
data: function () {
|
|
5
5
|
return {
|
|
6
6
|
importable: false,
|
|
7
7
|
importSubmitUrl: null,
|
|
@@ -18,7 +18,7 @@ export default {
|
|
|
18
18
|
});
|
|
19
19
|
},
|
|
20
20
|
rowSelected(sectionIndex, rowIndex) {
|
|
21
|
-
return
|
|
21
|
+
return getAllFormData()[this.rowCheckId(sectionIndex, rowIndex)];
|
|
22
22
|
},
|
|
23
23
|
selectedRowCount(section) {
|
|
24
24
|
const sectionIndex = section.index;
|
|
@@ -57,7 +57,7 @@ export default {
|
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
_submitEachRow(rows) {
|
|
60
|
-
const url = Utils.type.string(this.importSubmitUrl)
|
|
60
|
+
const url = Utils.type.string(this.importSubmitUrl);
|
|
61
61
|
if (!url) {
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
@@ -96,7 +96,7 @@ export default {
|
|
|
96
96
|
// Reset value so it will trigger again the next time the same file is selected.
|
|
97
97
|
event.target.value = null;
|
|
98
98
|
},
|
|
99
|
-
_parseCsv: function(csvString) {
|
|
99
|
+
_parseCsv: function (csvString) {
|
|
100
100
|
// https://stackoverflow.com/a/41563966/9970813
|
|
101
101
|
let prevLetter = "",
|
|
102
102
|
row = [""],
|
|
@@ -3,6 +3,11 @@ import launch from "../../utils/launch";
|
|
|
3
3
|
import { htmlElement } from "../helper";
|
|
4
4
|
|
|
5
5
|
export default defineComponent({
|
|
6
|
+
data() {
|
|
7
|
+
return {
|
|
8
|
+
key: Math.random().toString(36).slice(2, 7)
|
|
9
|
+
};
|
|
10
|
+
},
|
|
6
11
|
computed: {
|
|
7
12
|
properties() {
|
|
8
13
|
return {
|
|
@@ -13,6 +18,18 @@ export default defineComponent({
|
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
methods: {
|
|
21
|
+
handleMouseEnter() {
|
|
22
|
+
const properties = {
|
|
23
|
+
body: { childViews: [this.properties] },
|
|
24
|
+
key: this.key,
|
|
25
|
+
placement: this.spec.tooltip.placement || 'top',
|
|
26
|
+
styleClass: 'views-tooltip'
|
|
27
|
+
};
|
|
28
|
+
launch.popover.open(properties, this);
|
|
29
|
+
},
|
|
30
|
+
handleMouseLeave() {
|
|
31
|
+
launch.popover.close({ key: this.key });
|
|
32
|
+
},
|
|
16
33
|
$mounted() {
|
|
17
34
|
const tooltip = this.spec.tooltip;
|
|
18
35
|
|
|
@@ -20,26 +37,22 @@ export default defineComponent({
|
|
|
20
37
|
|
|
21
38
|
this.initTooltip();
|
|
22
39
|
},
|
|
23
|
-
|
|
24
|
-
const
|
|
40
|
+
$tearDown() {
|
|
41
|
+
const el = htmlElement(this);
|
|
42
|
+
|
|
43
|
+
if (el) {
|
|
44
|
+
el.removeEventListener('mouseenter', this.handleMouseEnter);
|
|
45
|
+
el.removeEventListener('mouseleave', this.handleMouseLeave);
|
|
46
|
+
}
|
|
25
47
|
|
|
26
|
-
const handleMouseEnter = () => {
|
|
27
|
-
const properties = {
|
|
28
|
-
body: { childViews: [this.properties] },
|
|
29
|
-
key: key,
|
|
30
|
-
placement: this.spec.tooltip.placement || 'top',
|
|
31
|
-
styleClass: 'views-tooltip'
|
|
32
|
-
};
|
|
33
|
-
launch.popover.open(properties, this);
|
|
34
|
-
};
|
|
35
|
-
const handleMouseLeave = () => {
|
|
36
|
-
launch.popover.close({ key: key });
|
|
37
|
-
};
|
|
38
48
|
|
|
49
|
+
this.handleMouseLeave();
|
|
50
|
+
},
|
|
51
|
+
initTooltip() {
|
|
39
52
|
const el = htmlElement(this);
|
|
40
53
|
|
|
41
|
-
el.addEventListener('mouseenter', handleMouseEnter);
|
|
42
|
-
el.addEventListener('mouseleave', handleMouseLeave);
|
|
54
|
+
el.addEventListener('mouseenter', this.handleMouseEnter);
|
|
55
|
+
el.addEventListener('mouseleave', this.handleMouseLeave);
|
|
43
56
|
}
|
|
44
57
|
}
|
|
45
58
|
});
|
|
@@ -31,14 +31,17 @@ export default {
|
|
|
31
31
|
computed: {
|
|
32
32
|
cssClasses: function () {
|
|
33
33
|
const classes = this.$classes().concat("layouts-flow");
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
|
|
35
|
+
const configs = {
|
|
36
|
+
'top': 'align-start',
|
|
37
|
+
'middle': 'align-center',
|
|
38
|
+
'bottom': 'align-end'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const alignClass = configs[this.spec.align] || 'align-start';
|
|
42
|
+
|
|
43
|
+
classes.push(alignClass);
|
|
44
|
+
|
|
42
45
|
return classes;
|
|
43
46
|
},
|
|
44
47
|
cssStyles: function () {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
<script>
|
|
16
16
|
import { onMounted, provide, ref } from "vue";
|
|
17
17
|
import { useGlibForm } from "../composable/form";
|
|
18
|
+
import eventFiltering from "../../utils/eventFiltering";
|
|
18
19
|
|
|
19
20
|
export default {
|
|
20
21
|
props: {
|
|
@@ -138,7 +139,7 @@ export default {
|
|
|
138
139
|
this.formCtx = { form: this.$refs.form };
|
|
139
140
|
if (onChange) this.$executeOnChange();
|
|
140
141
|
};
|
|
141
|
-
this.formElement.onchange = (
|
|
142
|
+
this.formElement.onchange = eventFiltering.debounce(onChangeHandler, 300);
|
|
142
143
|
|
|
143
144
|
this.formElement.oninput = (event) => this.glibForm.updateDirtyState(event);
|
|
144
145
|
}
|
|
@@ -24,7 +24,16 @@ export default {
|
|
|
24
24
|
},
|
|
25
25
|
methods: {
|
|
26
26
|
classes: function () {
|
|
27
|
-
|
|
27
|
+
// This class is provided by Vuetify: https://vuetifyjs.com/en/styles/flex/#flex-align.
|
|
28
|
+
const configs = {
|
|
29
|
+
'top': 'align-start',
|
|
30
|
+
'middle': 'align-center',
|
|
31
|
+
'bottom': 'align-end'
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const alignClass = configs[this.spec.align] || 'align-start';
|
|
35
|
+
|
|
36
|
+
return this.$classes().concat(["layouts-split", alignClass]);
|
|
28
37
|
}
|
|
29
38
|
}
|
|
30
39
|
};
|
package/nav/dialog.vue
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
</h1>
|
|
11
11
|
<div v-else></div>
|
|
12
12
|
|
|
13
|
-
<v-btn v-if="!spec.disableCloseButton" size="small" icon @click="close" variant="text">
|
|
13
|
+
<v-btn v-if="!spec.disableCloseButton" class="close-btn" size="small" icon @click="close" variant="text">
|
|
14
14
|
<v-icon>close</v-icon>
|
|
15
15
|
</v-btn>
|
|
16
16
|
</div>
|
|
@@ -231,7 +231,6 @@ export default {
|
|
|
231
231
|
}
|
|
232
232
|
};
|
|
233
233
|
</script>
|
|
234
|
-
|
|
235
234
|
<style lang="scss">
|
|
236
235
|
.dialog-message {
|
|
237
236
|
padding: 16px 20px;
|
|
@@ -247,6 +246,12 @@ export default {
|
|
|
247
246
|
width: 100%;
|
|
248
247
|
z-index: 999;
|
|
249
248
|
padding: 8px 16px;
|
|
249
|
+
position: relative;
|
|
250
|
+
|
|
251
|
+
.close-btn {
|
|
252
|
+
position: fixed;
|
|
253
|
+
right: 16px;
|
|
254
|
+
}
|
|
250
255
|
}
|
|
251
256
|
|
|
252
257
|
.dialog-absolute {
|
package/package.json
CHANGED
package/store.js
CHANGED
package/utils/launch/dialog.js
CHANGED
|
@@ -48,6 +48,10 @@ export default class LaunchDialog {
|
|
|
48
48
|
Utils.type.ifObject(dialogs.value.last(), dialog => {
|
|
49
49
|
dialog.reload(properties);
|
|
50
50
|
});
|
|
51
|
+
|
|
52
|
+
nextTick(() => {
|
|
53
|
+
Action.execute(properties.onReload, component);
|
|
54
|
+
});
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
static close(properties, component) {
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { reactive, watchEffect } from "vue";
|
|
2
|
-
import jsonLogic from 'json-logic-js';
|
|
3
|
-
|
|
4
|
-
// TODO: support multiple form
|
|
5
|
-
const fieldModels = reactive({});
|
|
6
|
-
|
|
7
|
-
const watchFieldModels = (logic, cb) => watchEffect(() => {
|
|
8
|
-
const value = jsonLogic.apply(logic, fieldModels);
|
|
9
|
-
cb(value);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export { fieldModels, watchFieldModels };
|