glib-web 3.11.0 → 3.12.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/action.js +19 -11
- package/actions/components/find.js +6 -0
- package/actions/popovers/close.js +9 -3
- package/components/composable/dirtyState.js +5 -6
- package/components/fields/_otp.vue +2 -2
- package/components/fields/check.vue +4 -10
- package/components/fields/dynamicGroup.vue +21 -20
- package/components/fields/file.vue +0 -2
- package/components/fields/richText.vue +1 -1
- package/components/mixins/events.js +1 -1
- package/components/mixins/generic.js +7 -1
- package/components/mixins/styles.js +1 -1
- package/nav/appbar.vue +2 -1
- package/nav/dialog.vue +10 -4
- package/package.json +1 -1
- package/store.js +2 -0
- package/utils/form.js +2 -2
- package/utils/http.js +7 -6
- package/utils/launch.js +5 -3
package/action.js
CHANGED
|
@@ -57,11 +57,12 @@ import ActionCommandsCustom from "./actions/commands/custom";
|
|
|
57
57
|
const ActionToursStart = import("./actions/tours/start");
|
|
58
58
|
const ActionToursStop = import("./actions/tours/stop");
|
|
59
59
|
|
|
60
|
-
import ActionComponentsUpdate from "./actions/components/update";
|
|
61
|
-
|
|
62
60
|
import ActionPopoversOpen from "./actions/popovers/open";
|
|
63
61
|
import ActionPopoversClose from "./actions/popovers/close";
|
|
64
62
|
|
|
63
|
+
import ActionComponentsUpdate from "./actions/components/update";
|
|
64
|
+
import ActionComponentsFind from "./actions/components/find";
|
|
65
|
+
|
|
65
66
|
import { vueApp } from "./store";
|
|
66
67
|
|
|
67
68
|
const actions = {
|
|
@@ -119,11 +120,13 @@ const actions = {
|
|
|
119
120
|
"commands/custom": ActionCommandsCustom,
|
|
120
121
|
|
|
121
122
|
"tours/start": ActionToursStart,
|
|
122
|
-
"
|
|
123
|
+
"tours/stop": ActionToursStop,
|
|
124
|
+
|
|
123
125
|
"popovers/open": ActionPopoversOpen,
|
|
124
126
|
"popovers/close": ActionPopoversClose,
|
|
125
|
-
|
|
126
|
-
"components/update": ActionComponentsUpdate
|
|
127
|
+
|
|
128
|
+
"components/update": ActionComponentsUpdate,
|
|
129
|
+
"components/find": ActionComponentsFind
|
|
127
130
|
};
|
|
128
131
|
|
|
129
132
|
const customActions = {};
|
|
@@ -179,17 +182,22 @@ export default class Action {
|
|
|
179
182
|
}
|
|
180
183
|
}
|
|
181
184
|
|
|
182
|
-
static handleResponse(response, component
|
|
185
|
+
static handleResponse(response, component) {
|
|
186
|
+
vueApp.temp.analytics = response.analytics;
|
|
187
|
+
GLib.action.execute(response.onResponse, component);
|
|
188
|
+
vueApp.temp.analytics = null;
|
|
189
|
+
|
|
183
190
|
// TODO: The execution should be in the following order: onResponse, page render, onLoad
|
|
184
191
|
if (response.header || response.body || response.footer) {
|
|
185
192
|
Utils.http.forceComponentUpdate(() => {
|
|
186
|
-
|
|
193
|
+
const dialog = component.$closest("dialog");
|
|
194
|
+
if (dialog) {
|
|
195
|
+
dialog.updateContent(response)
|
|
196
|
+
} else {
|
|
197
|
+
vueApp.page = response;
|
|
198
|
+
}
|
|
187
199
|
});
|
|
188
200
|
}
|
|
189
|
-
|
|
190
|
-
vueApp.temp.analytics = response.analytics;
|
|
191
|
-
GLib.action.execute(response.onResponse, component);
|
|
192
|
-
vueApp.temp.analytics = null;
|
|
193
201
|
}
|
|
194
202
|
|
|
195
203
|
static registerCustom(actionName, action) {
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import { nextTick } from "vue";
|
|
2
|
+
|
|
1
3
|
export default class {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
execute(properties, component) {
|
|
5
|
+
Utils.launch.popover.close(properties);
|
|
6
|
+
|
|
7
|
+
nextTick(() => {
|
|
8
|
+
GLib.action.execute(properties.onClose, component);
|
|
9
|
+
})
|
|
10
|
+
}
|
|
5
11
|
}
|
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import { watchEffect } from "vue";
|
|
2
|
-
import {
|
|
2
|
+
import { glibevent, ctx } from "../../store";
|
|
3
3
|
|
|
4
4
|
export function useDirtyState() {
|
|
5
|
-
const ctx = dialogStates.slice(-1)[0] || vueApp;
|
|
6
5
|
const prompt = "Changes you made have not been saved. Are you sure?";
|
|
7
6
|
|
|
8
7
|
const isDirty = () => {
|
|
9
|
-
return ctx.isFormDirty && !ctx.isFormSubmitted && !confirm(prompt);
|
|
8
|
+
return ctx().isFormDirty && !ctx().isFormSubmitted && !confirm(prompt);
|
|
10
9
|
};
|
|
11
10
|
|
|
12
11
|
const clearDirtyState = () => {
|
|
13
|
-
ctx.isFormDirty = false;
|
|
12
|
+
ctx().isFormDirty = false;
|
|
14
13
|
};
|
|
15
14
|
|
|
16
15
|
const updateDirtyState = (val, oldVal, spec) => {
|
|
17
16
|
if (!spec.disableDirtyCheck && val != oldVal && val != spec.value) {
|
|
18
|
-
ctx.isFormDirty = true;
|
|
17
|
+
ctx().isFormDirty = true;
|
|
19
18
|
}
|
|
20
19
|
};
|
|
21
20
|
|
|
22
21
|
const watchDirtyState = () => {
|
|
23
22
|
return watchEffect(() => {
|
|
24
|
-
if (ctx.isFormDirty) {
|
|
23
|
+
if (ctx().isFormDirty) {
|
|
25
24
|
window.onbeforeunload = () => !isDirty();
|
|
26
25
|
glibevent.onbeforewindowsopen = () => !isDirty();
|
|
27
26
|
glibevent.onbeforewindowsclose = () => !isDirty();
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<input v-model="uncheckValue" type="hidden" :name="fieldName" />
|
|
6
6
|
<v-checkbox v-model="fieldModel" :name="fieldName" :readonly="spec.readOnly" :disabled="inputDisabled"
|
|
7
7
|
:label="fieldModel ? spec.onLabel || spec.label : spec.label" :true-icon="spec.onIcon" :false-icon="spec.offIcon"
|
|
8
|
-
:value="spec.checkValue" hide-details @change="changed" color="primary"></v-checkbox>
|
|
8
|
+
:value="spec.value" :true-value="spec.checkValue" hide-details @change="changed" color="primary"></v-checkbox>
|
|
9
9
|
</div>
|
|
10
10
|
</template>
|
|
11
11
|
|
|
@@ -37,12 +37,6 @@ export default {
|
|
|
37
37
|
this.$executeOnChange();
|
|
38
38
|
// }, 500);
|
|
39
39
|
},
|
|
40
|
-
$internalizeValue(val) {
|
|
41
|
-
if (val == this.spec.checkValue) {
|
|
42
|
-
return val;
|
|
43
|
-
}
|
|
44
|
-
return this.spec.uncheckValue;
|
|
45
|
-
},
|
|
46
40
|
action_merge(mergedSpec) {
|
|
47
41
|
Object.assign(this.spec, mergedSpec);
|
|
48
42
|
this.updateData();
|
|
@@ -58,9 +52,9 @@ export default {
|
|
|
58
52
|
|
|
59
53
|
this.fieldName = this.spec.name || groupName;
|
|
60
54
|
|
|
61
|
-
this.fieldModel = this.spec.checked
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
// this.fieldModel = this.spec.checked
|
|
56
|
+
// ? this.spec.checkValue
|
|
57
|
+
// : this.spec.value;
|
|
64
58
|
|
|
65
59
|
Utils.type.ifArray(this.spec.styleClasses, classes => {
|
|
66
60
|
if (classes.remove("switch")) {
|
|
@@ -20,6 +20,7 @@ export default {
|
|
|
20
20
|
},
|
|
21
21
|
data() {
|
|
22
22
|
return {
|
|
23
|
+
localFieldModels: {},
|
|
23
24
|
groupValues: [],
|
|
24
25
|
template: {},
|
|
25
26
|
templateViews: [],
|
|
@@ -35,9 +36,9 @@ export default {
|
|
|
35
36
|
|
|
36
37
|
spec.groupFieldProperties.forEach((group, groupIndex) => {
|
|
37
38
|
group.forEach((properties) => {
|
|
38
|
-
const fullName = this.prefixFieldName(groupIndex, properties.name)
|
|
39
|
-
this.
|
|
40
|
-
})
|
|
39
|
+
const fullName = this.prefixFieldName(groupIndex, properties.name);
|
|
40
|
+
this.localFieldModels[fullName] = properties.value;
|
|
41
|
+
});
|
|
41
42
|
});
|
|
42
43
|
|
|
43
44
|
this.groupValues = spec.groupFieldProperties;
|
|
@@ -46,10 +47,10 @@ export default {
|
|
|
46
47
|
},
|
|
47
48
|
groupValues: {
|
|
48
49
|
handler(groupValues) {
|
|
49
|
-
var actualIndex = 0
|
|
50
|
+
var actualIndex = 0;
|
|
50
51
|
this.groupSpecs = groupValues.map((group, groupIndex) => {
|
|
51
52
|
if (!this.isDeleted(groupIndex)) {
|
|
52
|
-
++actualIndex
|
|
53
|
+
++actualIndex;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
const viewSpecs = this.processTemplate(
|
|
@@ -74,24 +75,24 @@ export default {
|
|
|
74
75
|
// Replace every occurrence of `{{index}}` within any string.
|
|
75
76
|
populateIndexes(object, groupIndex) {
|
|
76
77
|
if (this.$type.isString(object)) {
|
|
77
|
-
return object.replace('{{index}}', groupIndex)
|
|
78
|
+
return object.replace('{{index}}', groupIndex);
|
|
78
79
|
}
|
|
79
80
|
if (this.$type.isArray(object)) {
|
|
80
81
|
return object.map((o) => this.populateIndexes(o, groupIndex));
|
|
81
82
|
|
|
82
83
|
} else if (this.$type.isObject(object)) {
|
|
83
|
-
const newObject = {}
|
|
84
|
+
const newObject = {};
|
|
84
85
|
for (const key in object) {
|
|
85
|
-
newObject[key] = this.populateIndexes(object[key], groupIndex)
|
|
86
|
+
newObject[key] = this.populateIndexes(object[key], groupIndex);
|
|
86
87
|
}
|
|
87
|
-
return newObject
|
|
88
|
+
return newObject;
|
|
88
89
|
}
|
|
89
|
-
return object
|
|
90
|
+
return object;
|
|
90
91
|
},
|
|
91
92
|
processTemplate(properties, groupIndex, processField, processNonField) {
|
|
92
93
|
return this.processViews(
|
|
93
94
|
this.templateViews, properties, groupIndex, processField, processNonField
|
|
94
|
-
)
|
|
95
|
+
);
|
|
95
96
|
},
|
|
96
97
|
prefixFieldName(groupIndex, fieldName) {
|
|
97
98
|
if (fieldName.search(/\[.*\]/) >= 0) {
|
|
@@ -101,33 +102,33 @@ export default {
|
|
|
101
102
|
}
|
|
102
103
|
},
|
|
103
104
|
processField(viewSpec, name, groupIndex, properties) {
|
|
104
|
-
const fullName = this.prefixFieldName(groupIndex, name)
|
|
105
|
-
const indexedName = this.populateIndexes(fullName, groupIndex)
|
|
105
|
+
const fullName = this.prefixFieldName(groupIndex, name);
|
|
106
|
+
const indexedName = this.populateIndexes(fullName, groupIndex);
|
|
106
107
|
|
|
107
108
|
// Note that `properties` might contain any properties such as fileTitle/fileUrl which
|
|
108
109
|
// are needed by file components.
|
|
109
110
|
Object.assign(viewSpec, properties[name], {
|
|
110
111
|
name: fullName,
|
|
111
|
-
value: this.
|
|
112
|
+
value: this.localFieldModels[indexedName]
|
|
112
113
|
});
|
|
113
|
-
return viewSpec
|
|
114
|
+
return viewSpec;
|
|
114
115
|
},
|
|
115
116
|
processViews(viewSpecs, properties, groupIndex) {
|
|
116
117
|
return viewSpecs.map(origSpec => {
|
|
117
|
-
const viewSpec = Object.assign({}, origSpec)
|
|
118
|
+
const viewSpec = Object.assign({}, origSpec);
|
|
118
119
|
|
|
119
|
-
viewSpec.showIf = this.populateIndexes(viewSpec.showIf, groupIndex)
|
|
120
|
-
viewSpec.loadIf = this.populateIndexes(viewSpec.loadIf, groupIndex)
|
|
120
|
+
viewSpec.showIf = this.populateIndexes(viewSpec.showIf, groupIndex);
|
|
121
|
+
viewSpec.loadIf = this.populateIndexes(viewSpec.loadIf, groupIndex);
|
|
121
122
|
|
|
122
123
|
if (Utils.type.isString(viewSpec.name)) { // This is a field
|
|
123
124
|
return this.processField(viewSpec, viewSpec.name, groupIndex, properties);
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
if (Utils.type.isObject(viewSpec.childViews)) {
|
|
127
|
-
viewSpec.childViews = this.processViews(viewSpec.childViews, properties, groupIndex)
|
|
128
|
+
viewSpec.childViews = this.processViews(viewSpec.childViews, properties, groupIndex);
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
return viewSpec
|
|
131
|
+
return viewSpec;
|
|
131
132
|
});
|
|
132
133
|
},
|
|
133
134
|
addGroup() {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
use-custom-image-handler :editor-options="editorSettings" @text-change="onRichTextEditorChanged"
|
|
13
13
|
@image-added="uploadImage" /> -->
|
|
14
14
|
<QuillEditor v-if="!rawMode" ref="quilEditor" theme="snow" :toolbar="customToolbar" :content="richEditorValue"
|
|
15
|
-
contentType="html" :modules="modules" @textChange="onRichTextEditorChanged" class="rich-editor" />
|
|
15
|
+
contentType="html" :modules="modules" @textChange="onRichTextEditorChanged" class="rich-editor" :placeholder="spec.placeholder" />
|
|
16
16
|
<!-- Hide these fields but don't remove them because these are the values that will get submitted. -->
|
|
17
17
|
<div :style="{ display: rawMode ? 'block' : 'none' }">
|
|
18
18
|
<v-textarea class="raw-editor" v-model="rawEditorValue" :style="$styles()" :class="$classes()"
|
|
@@ -2,12 +2,18 @@ import { vueApp } from "../../store";
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
methods: {
|
|
5
|
+
$componentName() { // Can be overridden
|
|
6
|
+
if (this.spec) {
|
|
7
|
+
return this.spec.view;
|
|
8
|
+
}
|
|
9
|
+
},
|
|
5
10
|
$closest(name) {
|
|
6
11
|
var parent = this.$parent;
|
|
7
12
|
while (parent != null) {
|
|
8
13
|
if (
|
|
9
14
|
(Utils.type.isObject(parent.spec) || Utils.type.isObject(parent.formSpec)) &&
|
|
10
|
-
|
|
15
|
+
parent.$componentName() == name
|
|
16
|
+
// GLib.component.vueName(parent) == name
|
|
11
17
|
) {
|
|
12
18
|
return parent;
|
|
13
19
|
}
|
|
@@ -73,7 +73,7 @@ export default {
|
|
|
73
73
|
methods: {
|
|
74
74
|
_initConditional(oldSpec) {
|
|
75
75
|
// unreg old fieldName
|
|
76
|
-
if (oldSpec && fieldModels[oldSpec.name]) {
|
|
76
|
+
if (oldSpec && fieldModels[oldSpec.name] && oldSpec.name != this.spec.name) {
|
|
77
77
|
delete fieldModels[oldSpec.name];
|
|
78
78
|
}
|
|
79
79
|
// unreg watchers if there is
|
package/nav/appbar.vue
CHANGED
package/nav/dialog.vue
CHANGED
|
@@ -174,13 +174,10 @@ export default {
|
|
|
174
174
|
Http.execute({ url: url }, "GET", this, (response) => {
|
|
175
175
|
Utils.http.forceComponentUpdate(() => {
|
|
176
176
|
this.urlLoaded = true;
|
|
177
|
-
this.title = response.title;
|
|
178
177
|
this.message = "";
|
|
179
178
|
this.formSpec = response.fullPageForm;
|
|
180
|
-
this.header = response.header;
|
|
181
|
-
this.body = response.body;
|
|
182
|
-
this.footer = response.footer;
|
|
183
179
|
this.disableCloseButton = this.spec.disableCloseButton || false;
|
|
180
|
+
this.updateContent(response)
|
|
184
181
|
|
|
185
182
|
Action.execute(response.onLoad, this);
|
|
186
183
|
});
|
|
@@ -196,8 +193,17 @@ export default {
|
|
|
196
193
|
|
|
197
194
|
this.model = true;
|
|
198
195
|
},
|
|
196
|
+
updateContent(response) {
|
|
197
|
+
this.title = response.title;
|
|
198
|
+
this.header = response.header;
|
|
199
|
+
this.body = response.body;
|
|
200
|
+
this.footer = response.footer;
|
|
201
|
+
},
|
|
199
202
|
updateMainHeight() {
|
|
200
203
|
this.mainHeight = window.innerHeight - 140;
|
|
204
|
+
},
|
|
205
|
+
$componentName() {
|
|
206
|
+
return "dialog";
|
|
201
207
|
}
|
|
202
208
|
}
|
|
203
209
|
};
|
package/package.json
CHANGED
package/store.js
CHANGED
package/utils/form.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ctx } from "../store";
|
|
2
2
|
|
|
3
3
|
export default class {
|
|
4
4
|
// Execution flows:
|
|
@@ -17,7 +17,7 @@ export default class {
|
|
|
17
17
|
|
|
18
18
|
// Use nextTick to wait for overrideUrl get picked up.
|
|
19
19
|
component.$nextTick(() => {
|
|
20
|
-
|
|
20
|
+
ctx().isFormDirty = false;
|
|
21
21
|
form.submit();
|
|
22
22
|
});
|
|
23
23
|
} else {
|
package/utils/http.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Type from "./type";
|
|
2
2
|
import Action from "../action";
|
|
3
3
|
import { nextTick } from 'vue';
|
|
4
|
-
import { vueApp } from "../store";
|
|
4
|
+
import { ctx, vueApp } from "../store";
|
|
5
5
|
|
|
6
6
|
let loading = false;
|
|
7
7
|
|
|
@@ -80,7 +80,8 @@ export default class {
|
|
|
80
80
|
const htmlUrl = Utils.url.htmlUrl(properties["url"]);
|
|
81
81
|
|
|
82
82
|
Utils.http.execute(properties, "GET", component, (data, response) => {
|
|
83
|
-
|
|
83
|
+
const dialog = component.$closest("dialog");
|
|
84
|
+
if (htmlUrl !== currentUrl && !Utils.type.isObject(dialog)) {
|
|
84
85
|
const redirectUrl = Utils.url.htmlUrl(response.url);
|
|
85
86
|
Utils.history.pushPage(data, redirectUrl);
|
|
86
87
|
}
|
|
@@ -88,7 +89,7 @@ export default class {
|
|
|
88
89
|
this.forceComponentUpdate(() => {
|
|
89
90
|
Utils.history.resetScroll();
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
GLib.action.handleResponse(data, component)
|
|
92
93
|
|
|
93
94
|
Action.execute(properties["onOpen"], component);
|
|
94
95
|
});
|
|
@@ -258,8 +259,8 @@ export default class {
|
|
|
258
259
|
static forceComponentUpdate(handler) {
|
|
259
260
|
// GLib.component.clearRegistry();
|
|
260
261
|
vueApp.isStale = true;
|
|
261
|
-
|
|
262
|
-
|
|
262
|
+
ctx().isFormSubmitted = false;
|
|
263
|
+
ctx().isFormDirty = false;
|
|
263
264
|
handler();
|
|
264
265
|
|
|
265
266
|
// Queue the execution so the first isStale has time to resets state before handler gets executed
|
|
@@ -273,7 +274,7 @@ export default class {
|
|
|
273
274
|
// }
|
|
274
275
|
|
|
275
276
|
static notifyFormSubmitted() {
|
|
276
|
-
|
|
277
|
+
ctx().isFormSubmitted = true;
|
|
277
278
|
}
|
|
278
279
|
|
|
279
280
|
// `context` can be either window or dialog.
|
package/utils/launch.js
CHANGED
|
@@ -149,9 +149,11 @@ class LaunchDialog {
|
|
|
149
149
|
dialog.close();
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
Action.execute(properties.onClose, component);
|
|
153
|
+
|
|
154
|
+
// Utils.type.ifObject(properties["onClose"], it => {
|
|
155
|
+
// Action.execute(it, component);
|
|
156
|
+
// });
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
// This is only meant to be used internally
|