viur-ui 0.0.1 → 0.0.2
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/README.md +67 -41
- package/index.d.ts +18 -9
- package/index.js +6 -3
- package/package.json +3 -5
- package/src/components/Browser/Browser.vue +58 -58
- package/src/components/Browser/TreeNav.vue +32 -32
- package/src/components/Browser/ViurBrowser.d.vue.ts +21 -21
- package/src/components/Browser/ViurBrowser.vue +47 -44
- package/src/components/Browser/dragSession.ts +27 -27
- package/src/components/Browser/index.ts +3 -3
- package/src/components/Browser/types.ts +9 -9
- package/src/components/DataTable/ColumnFilterPanel.vue +7 -7
- package/src/components/DataTable/DataTable.vue +346 -346
- package/src/components/DataTable/ViurDataTable.d.vue.ts +26 -26
- package/src/components/DataTable/ViurDataTable.vue +51 -50
- package/src/components/DataTable/columns.ts +30 -30
- package/src/components/DataTable/index.ts +12 -12
- package/src/components/DataTable/rows.ts +71 -72
- package/src/components/DataTable/types.ts +55 -55
- package/src/components/DataTable/useColumnLayout.ts +28 -28
- package/src/components/DataTable/useGridNavigation.ts +15 -15
- package/src/components/DataTable/useVirtualRows.ts +10 -10
- package/src/components/DataTable/viurColumns.ts +69 -69
- package/src/forms/ViForm.d.vue.ts +32 -32
- package/src/forms/ViForm.vue +17 -16
- package/src/forms/ViFormCategory.vue +3 -1
- package/src/forms/bones/Bone.vue +125 -108
- package/src/forms/bones/BoneActions.vue +21 -21
- package/src/forms/bones/BoneLabel.vue +1 -1
- package/src/forms/bones/BoneMultipleWrapper.vue +3 -3
- package/src/forms/bones/BoneNestedWrapper.vue +3 -3
- package/src/forms/bones/BoneSingleEntry.vue +2 -2
- package/src/forms/bones/FilterBone.vue +3 -3
- package/src/forms/bones/actions/ActionDialog.vue +2 -2
- package/src/forms/bones/actions/Debug.vue +6 -6
- package/src/forms/bones/actions/Delete.vue +2 -2
- package/src/forms/bones/actions/DescribeImage.vue +4 -3
- package/src/forms/bones/actions/Download.vue +4 -4
- package/src/forms/bones/actions/Placeholder.vue +2 -2
- package/src/forms/bones/actions/index.js +72 -74
- package/src/forms/bones/bone.d.ts +19 -19
- package/src/forms/bones/uploadAdapter.js +3 -3
- package/src/forms/bones/utils.js +40 -41
- package/src/forms/bones/view/base_item.vue +1 -1
- package/src/forms/bones/view/boneLogic.js +1 -1
- package/src/forms/bones/widgets/booleanBone.vue +19 -19
- package/src/forms/bones/widgets/booleanBoneChoose.vue +2 -2
- package/src/forms/bones/widgets/booleanBoneSelect.vue +3 -3
- package/src/forms/bones/widgets/codeBone.vue +22 -22
- package/src/forms/bones/widgets/colorBone.vue +18 -18
- package/src/forms/bones/widgets/dateBone.vue +22 -22
- package/src/forms/bones/widgets/emailBone.vue +20 -20
- package/src/forms/bones/widgets/fileBone.vue +32 -31
- package/src/forms/bones/widgets/keyBone.vue +21 -21
- package/src/forms/bones/widgets/numericBone.vue +21 -21
- package/src/forms/bones/widgets/passwordBone.vue +34 -31
- package/src/forms/bones/widgets/phoneBone.vue +20 -20
- package/src/forms/bones/widgets/rawBone.vue +19 -19
- package/src/forms/bones/widgets/recordBone.vue +16 -16
- package/src/forms/bones/widgets/relationalBone.vue +26 -26
- package/src/forms/bones/widgets/selectBone.vue +23 -23
- package/src/forms/bones/widgets/selectBoneChoose.vue +2 -2
- package/src/forms/bones/widgets/spatialBone.vue +21 -21
- package/src/forms/bones/widgets/stringBone.vue +27 -27
- package/src/forms/bones/widgets/textBone.vue +28 -26
- package/src/forms/install.d.ts +1 -1
- package/src/forms/install.js +7 -0
- package/src/forms/layouts/LayloutList2Columns.vue +1 -1
- package/src/forms/layouts/LayoutCategory.vue +1 -1
- package/src/forms/layouts/LayoutList.vue +1 -1
- package/src/forms/utils.js +22 -22
- package/src/request/configStore.js +4 -4
- package/src/request/envelope.js +6 -6
- package/src/request/request.js +22 -22
- package/src/translations/de.js +31 -0
- package/src/translations/en.js +31 -0
- package/src/user/LoginScreen.d.vue.ts +24 -24
- package/src/user/LoginScreen.vue +6 -7
- package/src/user/store.d.ts +16 -16
- package/src/vite/safeHtml.js +73 -0
- package/src/vite/sanitizeVHtml.d.ts +4 -0
- package/src/vite/sanitizeVHtml.js +15 -0
- package/src/webawesomeCompat.css +0 -40
|
@@ -36,49 +36,49 @@ import { reactive, onMounted, inject, computed, watch } from "vue"
|
|
|
36
36
|
import { useListFetch } from "../../../request/index.js"
|
|
37
37
|
import Wrapper_nested from "../BoneNestedWrapper.vue"
|
|
38
38
|
/**
|
|
39
|
-
* Relational
|
|
39
|
+
* Relational selection widget for bones of type `relational` and `relational.select`.
|
|
40
40
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
41
|
+
* For type `relational`, a `<wa-combobox>` is shown that loads and filters
|
|
42
|
+
* entries from the configured `module` via `getList`. If a value is set,
|
|
43
|
+
* a locked `<wa-input>` with the formatted entry is shown instead.
|
|
44
|
+
* For type `relational.select`, a dropdown widget is rendered.
|
|
45
|
+
* If the structure contains a `using` object, a `Wrapper_nested`
|
|
46
|
+
* is additionally shown for the relational extra fields (`rel`).
|
|
47
47
|
*
|
|
48
48
|
* @displayName RelationalBone
|
|
49
49
|
*
|
|
50
|
-
* @cssClass bone-widget-record -
|
|
51
|
-
* @cssClass bone-widget -
|
|
52
|
-
* @cssClass bone-widget-relational -
|
|
53
|
-
* @cssClass bone-widget-relational-default -
|
|
54
|
-
* @cssClass bone-widget-relational-{name} -
|
|
55
|
-
* @cssClass bone-widget-single-entry -
|
|
50
|
+
* @cssClass bone-widget-record - Outer container of the widget
|
|
51
|
+
* @cssClass bone-widget - Base class of all bone widgets
|
|
52
|
+
* @cssClass bone-widget-relational - Identifies the bone type
|
|
53
|
+
* @cssClass bone-widget-relational-default - Default variant
|
|
54
|
+
* @cssClass bone-widget-relational-{name} - Dynamically set to the bone name
|
|
55
|
+
* @cssClass bone-widget-single-entry - Row with combobox/input
|
|
56
56
|
*/
|
|
57
57
|
defineOptions({
|
|
58
58
|
inheritAttrs: false,
|
|
59
59
|
})
|
|
60
60
|
const props = defineProps({
|
|
61
|
-
/** Bone
|
|
61
|
+
/** Bone name – passed as the first argument in every `change` event. */
|
|
62
62
|
name: String,
|
|
63
|
-
/**
|
|
63
|
+
/** Current bone value; object with `dest` and `rel` keys, or `null`. */
|
|
64
64
|
value: [Object, String, Number, Boolean, Array],
|
|
65
|
-
/** Index
|
|
65
|
+
/** Index in the multiple array; `undefined` for a single value. */
|
|
66
66
|
index: Number,
|
|
67
|
-
/**
|
|
67
|
+
/** Language key for multilingual bones, e.g. `"de"`. */
|
|
68
68
|
lang: String,
|
|
69
|
-
/** Bone
|
|
69
|
+
/** Bone structure; `using` controls whether a nested wrapper is shown. */
|
|
70
70
|
bone: Object,
|
|
71
|
-
/**
|
|
71
|
+
/** Currently not used. */
|
|
72
72
|
autofocus: Boolean,
|
|
73
73
|
})
|
|
74
74
|
|
|
75
75
|
const emit = defineEmits([
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
78
|
-
* @arg {string} name - Bone
|
|
79
|
-
* @arg {{ dest: object, rel: object|null }|string} value -
|
|
80
|
-
* @arg {string|undefined} lang -
|
|
81
|
-
* @arg {number|undefined} index - Index
|
|
77
|
+
* Fired when an entry is selected, when cleared, and on mount (initialization).
|
|
78
|
+
* @arg {string} name - Bone name
|
|
79
|
+
* @arg {{ dest: object, rel: object|null }|string} value - Selected relational object, or `""` when cleared
|
|
80
|
+
* @arg {string|undefined} lang - Language key
|
|
81
|
+
* @arg {number|undefined} index - Index in the multiple array
|
|
82
82
|
*/
|
|
83
83
|
"change",
|
|
84
84
|
])
|
|
@@ -148,8 +148,8 @@ function changeEventNested(data) {
|
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
//
|
|
152
|
-
//
|
|
151
|
+
// Keep state.selection in sync with props.value — important when the value
|
|
152
|
+
// is cleared from outside (e.g. via the delete action).
|
|
153
153
|
watch(
|
|
154
154
|
() => props.value,
|
|
155
155
|
(newVal) => {
|
|
@@ -26,48 +26,48 @@
|
|
|
26
26
|
<script setup>
|
|
27
27
|
import { reactive, onMounted, inject, computed } from "vue"
|
|
28
28
|
/**
|
|
29
|
-
* Dropdown
|
|
29
|
+
* Dropdown select field for predefined values (type `select`).
|
|
30
30
|
*
|
|
31
|
-
*
|
|
32
|
-
* `boneState.bonestructure.values
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
31
|
+
* Renders a `<wa-select>` with `<wa-option>` entries generated from
|
|
32
|
+
* `boneState.bonestructure.values`. `values` can be an array
|
|
33
|
+
* of `[key, label]` tuples or an object `{ key: label }`.
|
|
34
|
+
* With `multiple` enabled, several options can be selected at once.
|
|
35
|
+
* The bone type `select.choose` is handled by the separate component `SelectBoneChoose`
|
|
36
|
+
* and renders radio buttons or checkboxes.
|
|
37
|
+
* With `boneState.label === "placeholder"`, the bone name is shown as a placeholder.
|
|
38
38
|
*
|
|
39
39
|
* @displayName SelectBone
|
|
40
40
|
*
|
|
41
|
-
* @cssClass bone-widget -
|
|
42
|
-
* @cssClass bone-widget-select -
|
|
43
|
-
* @cssClass bone-widget-select-default -
|
|
44
|
-
* @cssClass bone-widget-select-{name} -
|
|
41
|
+
* @cssClass bone-widget - Base class of all bone widgets
|
|
42
|
+
* @cssClass bone-widget-select - Identifies the bone type
|
|
43
|
+
* @cssClass bone-widget-select-default - Default variant (dropdown)
|
|
44
|
+
* @cssClass bone-widget-select-{name} - Dynamically set to the bone name, e.g. `bone-widget-select-status`
|
|
45
45
|
*/
|
|
46
46
|
defineOptions({
|
|
47
47
|
inheritAttrs: false,
|
|
48
48
|
})
|
|
49
49
|
const props = defineProps({
|
|
50
|
-
/** Bone
|
|
50
|
+
/** Bone name – passed as the first argument in every `change` event. */
|
|
51
51
|
name: String,
|
|
52
|
-
/**
|
|
52
|
+
/** Current bone value (string, array with multiple). */
|
|
53
53
|
value: null,
|
|
54
|
-
/** Index
|
|
54
|
+
/** Index in the multiple array; `undefined` for a single value. */
|
|
55
55
|
index: Number,
|
|
56
|
-
/**
|
|
56
|
+
/** Language key for multilingual bones, e.g. `"de"`. */
|
|
57
57
|
lang: String,
|
|
58
|
-
/** Bone
|
|
58
|
+
/** Bone structure (currently not actively used). */
|
|
59
59
|
bone: Object,
|
|
60
|
-
/**
|
|
60
|
+
/** Focuses the select element (currently not implemented). */
|
|
61
61
|
autofocus: Boolean,
|
|
62
62
|
})
|
|
63
63
|
|
|
64
64
|
const emit = defineEmits([
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
67
|
-
* @arg {string} name - Bone
|
|
68
|
-
* @arg {string|string[]} value -
|
|
69
|
-
* @arg {string|undefined} lang -
|
|
70
|
-
* @arg {number|undefined} index - Index
|
|
66
|
+
* Fired on every value change and on mount (initialization).
|
|
67
|
+
* @arg {string} name - Bone name
|
|
68
|
+
* @arg {string|string[]} value - Selected value, or array with multiple
|
|
69
|
+
* @arg {string|undefined} lang - Language key
|
|
70
|
+
* @arg {number|undefined} index - Index in the multiple array
|
|
71
71
|
*/
|
|
72
72
|
"change",
|
|
73
73
|
])
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
</wa-checkbox>
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
|
-
<!-- readonly
|
|
20
|
-
|
|
19
|
+
<!-- readonly on the group (see booleanBoneChoose): disabled radios
|
|
20
|
+
would show no selection -->
|
|
21
21
|
<wa-radio-group
|
|
22
22
|
v-else
|
|
23
23
|
:value="state.value"
|
|
@@ -39,46 +39,46 @@
|
|
|
39
39
|
<script setup>
|
|
40
40
|
import { reactive, onMounted, inject, computed } from "vue"
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* Coordinate input for geographic points (latitude / longitude).
|
|
43
43
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
44
|
+
* Renders two `<wa-input type="number">` fields for latitude and longitude.
|
|
45
|
+
* The allowed value ranges are controlled via `boneState.bonestructure.boundslat`
|
|
46
|
+
* and `boneState.bonestructure.boundslng`. Supports neither
|
|
47
|
+
* multiple languages nor multiple values.
|
|
48
48
|
*
|
|
49
49
|
* @displayName SpatialBone
|
|
50
50
|
*
|
|
51
|
-
* @cssClass bone-widget -
|
|
52
|
-
* @cssClass bone-widget-spatial -
|
|
53
|
-
* @cssClass bone-widget-spatial-default -
|
|
54
|
-
* @cssClass bone-widget-spatial-{name}-lat -
|
|
55
|
-
* @cssClass bone-widget-spatial-{name}-long -
|
|
51
|
+
* @cssClass bone-widget - Base class of all bone widgets
|
|
52
|
+
* @cssClass bone-widget-spatial - Identifies the bone type
|
|
53
|
+
* @cssClass bone-widget-spatial-default - Default variant
|
|
54
|
+
* @cssClass bone-widget-spatial-{name}-lat - Dynamically set for the latitude field
|
|
55
|
+
* @cssClass bone-widget-spatial-{name}-long - Dynamically set for the longitude field
|
|
56
56
|
*/
|
|
57
57
|
defineOptions({
|
|
58
58
|
inheritAttrs: false,
|
|
59
59
|
})
|
|
60
60
|
const props = defineProps({
|
|
61
|
-
/** Bone
|
|
61
|
+
/** Bone name – passed as the first argument in every `change` event. */
|
|
62
62
|
name: String,
|
|
63
|
-
/**
|
|
63
|
+
/** Current bone value as an array `[lat, lng]` or an object `{ lat, lng }`. */
|
|
64
64
|
value: [Object, String, Number, Boolean, Array],
|
|
65
|
-
/** Index
|
|
65
|
+
/** Index in the multiple array; `undefined` for a single value. */
|
|
66
66
|
index: Number,
|
|
67
|
-
/**
|
|
67
|
+
/** Language key (SpatialBone does not support multilang). */
|
|
68
68
|
lang: String,
|
|
69
|
-
/** Bone
|
|
69
|
+
/** Bone structure (currently not actively used). */
|
|
70
70
|
bone: Object,
|
|
71
|
-
/**
|
|
71
|
+
/** Focuses the first input element after mount. */
|
|
72
72
|
autofocus: Boolean,
|
|
73
73
|
})
|
|
74
74
|
|
|
75
75
|
const emit = defineEmits([
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
78
|
-
* @arg {string} name - Bone
|
|
79
|
-
* @arg {[number, number]} value -
|
|
80
|
-
* @arg {string|undefined} lang -
|
|
81
|
-
* @arg {number|undefined} index - Index
|
|
77
|
+
* Fired on every value change and on mount (initialization).
|
|
78
|
+
* @arg {string} name - Bone name
|
|
79
|
+
* @arg {[number, number]} value - Coordinates as `[lat, lng]`
|
|
80
|
+
* @arg {string|undefined} lang - Language key
|
|
81
|
+
* @arg {number|undefined} index - Index in the multiple array
|
|
82
82
|
*/
|
|
83
83
|
"change",
|
|
84
84
|
])
|
|
@@ -22,49 +22,49 @@
|
|
|
22
22
|
<script setup>
|
|
23
23
|
import { reactive, onMounted, inject, computed, watchEffect, ref } from "vue"
|
|
24
24
|
import { useTimeoutFn } from "@vueuse/core"
|
|
25
|
-
import Utils from "../utils"
|
|
25
|
+
import Utils from "../utils.js"
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Single-line text field for simple strings.
|
|
28
28
|
*
|
|
29
|
-
*
|
|
30
|
-
* Constraint Validation API.
|
|
31
|
-
* via `boneState.params.pattern`
|
|
32
|
-
* `boneState.params.pattern_error`.
|
|
33
|
-
*
|
|
29
|
+
* Renders a `<wa-input>` and delegates validation to the native
|
|
30
|
+
* Constraint Validation API. Supports optional regex validation
|
|
31
|
+
* via `boneState.params.pattern` as well as a custom error message via
|
|
32
|
+
* `boneState.params.pattern_error`. With `boneState.label === "placeholder"`,
|
|
33
|
+
* the bone name is shown as a placeholder instead of as a label above.
|
|
34
34
|
*
|
|
35
35
|
* @displayName StringBone
|
|
36
36
|
*
|
|
37
|
-
* @cssClass bone-widget -
|
|
38
|
-
* @cssClass bone-widget-string -
|
|
39
|
-
* @cssClass bone-widget-string-default -
|
|
40
|
-
* @cssClass bone-widget-string-{name} -
|
|
37
|
+
* @cssClass bone-widget - Base class of all bone widgets
|
|
38
|
+
* @cssClass bone-widget-string - Identifies the bone type
|
|
39
|
+
* @cssClass bone-widget-string-default - Default variant
|
|
40
|
+
* @cssClass bone-widget-string-{name} - Dynamically set to the bone name, e.g. `bone-widget-string-title`
|
|
41
41
|
*/
|
|
42
42
|
defineOptions({
|
|
43
43
|
inheritAttrs: false,
|
|
44
44
|
})
|
|
45
45
|
const props = defineProps({
|
|
46
|
-
/** Bone
|
|
46
|
+
/** Bone name – passed as the first argument in every `change` event. */
|
|
47
47
|
name: String,
|
|
48
|
-
/**
|
|
48
|
+
/** Current bone value. */
|
|
49
49
|
value: [Object, String, Number, Boolean, Array],
|
|
50
|
-
/** Index
|
|
50
|
+
/** Index in the multiple array; `undefined` for a single value. */
|
|
51
51
|
index: Number,
|
|
52
|
-
/**
|
|
52
|
+
/** Language key for multilingual bones, e.g. `"de"`. */
|
|
53
53
|
lang: String,
|
|
54
|
-
/** Bone
|
|
54
|
+
/** Bone structure (currently not actively used). */
|
|
55
55
|
bone: Object,
|
|
56
|
-
/**
|
|
56
|
+
/** Focuses the input element after 600 ms. */
|
|
57
57
|
autofocus: Boolean,
|
|
58
58
|
})
|
|
59
59
|
|
|
60
60
|
const emit = defineEmits([
|
|
61
61
|
/**
|
|
62
|
-
*
|
|
63
|
-
* @arg {string} name - Bone
|
|
64
|
-
* @arg {string} value -
|
|
65
|
-
* @arg {string|undefined} lang -
|
|
66
|
-
* @arg {number|undefined} index - Index
|
|
67
|
-
* @arg {boolean} [valid] -
|
|
62
|
+
* Fired on every value change and on mount (initialization).
|
|
63
|
+
* @arg {string} name - Bone name
|
|
64
|
+
* @arg {string} value - Current input value
|
|
65
|
+
* @arg {string|undefined} lang - Language key
|
|
66
|
+
* @arg {number|undefined} index - Index in the multiple array
|
|
67
|
+
* @arg {boolean} [valid] - Validation status; missing on the init event
|
|
68
68
|
*/
|
|
69
69
|
"change",
|
|
70
70
|
])
|
|
@@ -104,11 +104,11 @@ const state = reactive({
|
|
|
104
104
|
const stringBone = ref(null)
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
107
|
+
* Handles `change` and `keyup` events of the `<wa-input>`.
|
|
108
|
+
* Checks the native validity, sets a custom error message on
|
|
109
|
+
* `patternMismatch` and emits the `change` event with the validation status.
|
|
110
110
|
*
|
|
111
|
-
* @param {Event} event -
|
|
111
|
+
* @param {Event} event - The DOM event from the input element
|
|
112
112
|
*/
|
|
113
113
|
function changeEvent(event) {
|
|
114
114
|
let valid = stringBone.value.reportValidity()
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
<script setup>
|
|
44
44
|
import { reactive, onMounted, inject, computed, watch, onBeforeMount } from "vue"
|
|
45
45
|
import { Ckeditor } from "@ckeditor/ckeditor5-vue"
|
|
46
|
+
import { useI18n } from "vue-i18n"
|
|
46
47
|
import {
|
|
47
48
|
ClassicEditor,
|
|
48
49
|
Essentials,
|
|
@@ -72,56 +73,57 @@ import {
|
|
|
72
73
|
RemoveFormat,
|
|
73
74
|
GeneralHtmlSupport,
|
|
74
75
|
} from "ckeditor5"
|
|
75
|
-
import coreTranslations from "ckeditor5/
|
|
76
|
-
import "ckeditor5/
|
|
77
|
-
import { ViURUploadAdapterPlugin } from "../uploadAdapter"
|
|
76
|
+
import coreTranslations from "ckeditor5/translations/de.js"
|
|
77
|
+
import "ckeditor5/ckeditor5.css"
|
|
78
|
+
import { ViURUploadAdapterPlugin } from "../uploadAdapter.js"
|
|
78
79
|
|
|
79
80
|
/**
|
|
80
|
-
*
|
|
81
|
+
* Multi-line text field for longer content, either as a textarea or a rich-text editor (CKEditor 5).
|
|
81
82
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
83
|
+
* If `boneState.bonestructure.valid_html` or `boneState.bonestructure.validHtml` is set,
|
|
84
|
+
* a CKEditor 5 (ClassicEditor) is rendered. The visible toolbar actions are filtered based on
|
|
85
|
+
* the allowed HTML tags (`validTags`). Without an HTML configuration, a simple
|
|
86
|
+
* `<wa-textarea>` is shown. With `boneState.label === "placeholder"`, the bone name is
|
|
87
|
+
* shown as a placeholder instead of as a label.
|
|
87
88
|
*
|
|
88
89
|
* @displayName TextBone
|
|
89
90
|
*
|
|
90
|
-
* @cssClass bone-widget -
|
|
91
|
-
* @cssClass bone-widget-text -
|
|
92
|
-
* @cssClass bone-widget-text-default -
|
|
93
|
-
* @cssClass bone-widget-text-{name} -
|
|
94
|
-
* @cssClass bone-widget-text-{name}-html -
|
|
91
|
+
* @cssClass bone-widget - Base class of all bone widgets
|
|
92
|
+
* @cssClass bone-widget-text - Identifies the bone type
|
|
93
|
+
* @cssClass bone-widget-text-default - Default variant (textarea or CKEditor)
|
|
94
|
+
* @cssClass bone-widget-text-{name} - Dynamically set to the bone name, e.g. `bone-widget-text-content`
|
|
95
|
+
* @cssClass bone-widget-text-{name}-html - Set when the bone contains HTML content
|
|
95
96
|
*/
|
|
96
97
|
defineOptions({
|
|
97
98
|
inheritAttrs: false,
|
|
98
99
|
})
|
|
99
100
|
const props = defineProps({
|
|
100
|
-
/** Bone
|
|
101
|
+
/** Bone name – passed as the first argument in every `change` event. */
|
|
101
102
|
name: String,
|
|
102
|
-
/**
|
|
103
|
+
/** Current bone value as plain text or an HTML string. */
|
|
103
104
|
value: [Object, String, Number, Boolean, Array],
|
|
104
|
-
/** Index
|
|
105
|
+
/** Index in the multiple array; `undefined` for a single value. */
|
|
105
106
|
index: Number,
|
|
106
|
-
/**
|
|
107
|
+
/** Language key for multilingual bones, e.g. `"de"`. */
|
|
107
108
|
lang: String,
|
|
108
|
-
/** Bone
|
|
109
|
+
/** Bone structure (currently not actively used). */
|
|
109
110
|
bone: Object,
|
|
110
|
-
/**
|
|
111
|
+
/** Focuses the input field (currently not implemented). */
|
|
111
112
|
autofocus: Boolean,
|
|
112
113
|
})
|
|
113
114
|
|
|
114
115
|
const emit = defineEmits([
|
|
115
116
|
/**
|
|
116
|
-
*
|
|
117
|
-
* @arg {string} name - Bone
|
|
118
|
-
* @arg {string} value -
|
|
119
|
-
* @arg {string|undefined} lang -
|
|
120
|
-
* @arg {number|undefined} index - Index
|
|
117
|
+
* Fired on every value change and on mount (initialization).
|
|
118
|
+
* @arg {string} name - Bone name
|
|
119
|
+
* @arg {string} value - Current text value or HTML string
|
|
120
|
+
* @arg {string|undefined} lang - Language key
|
|
121
|
+
* @arg {number|undefined} index - Index in the multiple array
|
|
121
122
|
*/
|
|
122
123
|
"change",
|
|
123
124
|
])
|
|
124
125
|
|
|
126
|
+
const { t } = useI18n()
|
|
125
127
|
const boneState = inject("boneState")
|
|
126
128
|
const state = reactive({
|
|
127
129
|
value: "",
|
|
@@ -235,7 +237,7 @@ onBeforeMount(() => {
|
|
|
235
237
|
decorators: [
|
|
236
238
|
{
|
|
237
239
|
mode: "manual",
|
|
238
|
-
label: "
|
|
240
|
+
label: t("bones.text.openInNewWindow"),
|
|
239
241
|
attributes: {
|
|
240
242
|
target: "_blank",
|
|
241
243
|
rel: "noopener noreferrer",
|
package/src/forms/install.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { App } from "vue"
|
|
2
2
|
|
|
3
|
-
/**
|
|
3
|
+
/** Registers the form wrappers used globally by name (`<bone>` etc.) and the `safeHtml` plugin (`v-safe-html`, `$sanitizeHtml`). */
|
|
4
4
|
export declare function installViurForms(app: App): void
|
package/src/forms/install.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineAsyncComponent } from "vue"
|
|
2
|
+
import safeHtml from "../vite/safeHtml.js"
|
|
2
3
|
|
|
3
4
|
// --------------------------------------------------------------------------- //
|
|
4
5
|
// Global registration of the form wrappers //
|
|
@@ -18,6 +19,11 @@ import { defineAsyncComponent } from "vue"
|
|
|
18
19
|
// Keeping the list here instead of in every consumer means a rename inside the
|
|
19
20
|
// package cannot silently break the apps that embed the forms.
|
|
20
21
|
//
|
|
22
|
+
// Also installs `safeHtml` (v-safe-html + $sanitizeHtml). Importing this module
|
|
23
|
+
// sets `window.__sanitizeHtml`, which an app-side v-html compiler transform can
|
|
24
|
+
// call. v-html itself is compiled into an innerHTML prop at build time and can't
|
|
25
|
+
// be replaced at runtime — that override belongs in the app's vite.config.js.
|
|
26
|
+
//
|
|
21
27
|
// import { installViurForms } from "viur-ui/src/forms/install.js"
|
|
22
28
|
// installViurForms(app)
|
|
23
29
|
//
|
|
@@ -40,4 +46,5 @@ export function installViurForms(app) {
|
|
|
40
46
|
for (const [name, loader] of Object.entries(components)) {
|
|
41
47
|
if (!app.component(name)) app.component(name, defineAsyncComponent(loader))
|
|
42
48
|
}
|
|
49
|
+
if (!app.directive("safe-html")) app.use(safeHtml)
|
|
43
50
|
}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
<script setup>
|
|
25
25
|
import { inject } from "vue"
|
|
26
|
-
import { getBoneWidget } from "../bones"
|
|
26
|
+
import { getBoneWidget } from "../bones/index.js"
|
|
27
27
|
import ViFormCategory from "../ViFormCategory.vue"
|
|
28
28
|
const formState = inject("formState")
|
|
29
29
|
const formUpdate = inject("formUpdate")
|
package/src/forms/utils.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createControllerFetch, normalizeEnvelope, normalizeStructure } from "../request/index.js"
|
|
2
2
|
import Logics from "logics-js"
|
|
3
3
|
import { inject, toRaw, reactive, markRaw } from "vue"
|
|
4
|
-
import Utils from "./bones/utils"
|
|
4
|
+
import Utils from "./bones/utils.js"
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Deep copy of plain data (skel values) that resolves Vue proxies on EVERY
|
|
8
|
+
* level. structuredClone alone fails at this: a record/using form
|
|
9
|
+
* receives the reactive value of the parent bone, and `{ ...proxy }` keeps the
|
|
10
|
+
* nested values as proxies. Other objects (Date, File) remain shared.
|
|
11
11
|
*/
|
|
12
12
|
function rawCopy(value) {
|
|
13
13
|
const raw = toRaw(value)
|
|
@@ -33,8 +33,8 @@ export function useFormUtils(props, state) {
|
|
|
33
33
|
path += `/${props.skeltype}`
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
//
|
|
37
|
-
// `edit`
|
|
36
|
+
// Only append with a key: a SINGLETON has exactly one entry, its
|
|
37
|
+
// `edit` takes no key. Without this check `/edit/undefined` resulted.
|
|
38
38
|
if (["edit", "clone"].includes(props.action) || (isTree && props.action === "add")) {
|
|
39
39
|
if (props.skelkey) {
|
|
40
40
|
path += `/${props.skelkey}`
|
|
@@ -93,12 +93,12 @@ export function useFormUtils(props, state) {
|
|
|
93
93
|
// normalizeEnvelope; accept `values` too for a raw body).
|
|
94
94
|
const values = data["data"] !== undefined ? data["data"] : data["values"]
|
|
95
95
|
if (updateStructure && data["structure"] != null) {
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
96
|
+
// The `values` prop prefills a freshly RENDERED form. The
|
|
97
|
+
// response to a submit mirrors what was sent — it must not
|
|
98
|
+
// overwrite that again.
|
|
99
99
|
initForm(values, data["structure"], presetValues ? state.values : null)
|
|
100
|
-
//
|
|
101
|
-
//
|
|
100
|
+
// New structure = server flags: apply visibleIf/readonlyIf/requiredIf/evaluate
|
|
101
|
+
// right away, not only on the next input.
|
|
102
102
|
logics()
|
|
103
103
|
} else if (values !== undefined) {
|
|
104
104
|
state.skel = values
|
|
@@ -147,10 +147,10 @@ export function useFormUtils(props, state) {
|
|
|
147
147
|
try {
|
|
148
148
|
await fetchResult.execute()
|
|
149
149
|
applyResponseState(fetchResult.data.value, { updateStructure: true, presetValues: true })
|
|
150
|
-
//
|
|
151
|
-
// params.action_url) —
|
|
152
|
-
//
|
|
153
|
-
//
|
|
150
|
+
// A v1 step carries no target (no `follow`, no next_url, no
|
|
151
|
+
// params.action_url) — there the step is sent back to the SAME URL
|
|
152
|
+
// it was rendered from. Without this, postUrl would be
|
|
153
|
+
// null after rendering and the submit button would do nothing.
|
|
154
154
|
if (!state.postUrl && url) {
|
|
155
155
|
state.postUrl = url
|
|
156
156
|
}
|
|
@@ -562,18 +562,18 @@ export function useFormUtils(props, state) {
|
|
|
562
562
|
}
|
|
563
563
|
|
|
564
564
|
state.skel = { ...skeldata, ...formvalues }
|
|
565
|
-
//
|
|
566
|
-
//
|
|
567
|
-
//
|
|
568
|
-
// markRaw:
|
|
565
|
+
// Keep the state as it came in: `state.skel` is the working copy and
|
|
566
|
+
// changes while typing. resetForm() restores from this without
|
|
567
|
+
// reloading ("discard changes").
|
|
568
|
+
// markRaw: read-only data, no reactive proxy.
|
|
569
569
|
state.pristine = markRaw(rawCopy(state.skel))
|
|
570
570
|
|
|
571
571
|
state.categories = updateCategories()
|
|
572
572
|
}
|
|
573
573
|
|
|
574
574
|
/**
|
|
575
|
-
*
|
|
576
|
-
*
|
|
575
|
+
* Discard changes: restore the values of the last server state,
|
|
576
|
+
* WITHOUT a new request (that's what reload() is for). Structure and categories remain.
|
|
577
577
|
*/
|
|
578
578
|
function resetForm() {
|
|
579
579
|
if (state.pristine === undefined || state.pristine === null) return
|
|
@@ -32,7 +32,7 @@ import { reactive, computed, markRaw } from "vue"
|
|
|
32
32
|
// its dotted vi path ("user", "shop.order"). adminInfo carries `name`,
|
|
33
33
|
// `handler`, `icon`, `display`, `sortIndex`, `moduleGroup`, `views`, … (see
|
|
34
34
|
// viur-core `Module.adminInfo`).
|
|
35
|
-
// • `groups`: `configuration["admin.module.groups"]` (
|
|
35
|
+
// • `groups`: `configuration["admin.module.groups"]` (this is how viur-core renders
|
|
36
36
|
// `conf.admin.module_groups`) —
|
|
37
37
|
// `{ [groupKey]: { name, icon, sortIndex, moduleGroup? } }`. A group may
|
|
38
38
|
// itself name a parent group via `moduleGroup` (nested groups).
|
|
@@ -366,9 +366,9 @@ export const useConfigStore = defineStore("viurConfig", () => {
|
|
|
366
366
|
const languages = computed(() => state.configuration["admin.languages"] ?? [])
|
|
367
367
|
const moduleNames = computed(() => Object.keys(state.modules ?? {}))
|
|
368
368
|
/**
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
369
|
+
* Groups of the module navigation. viur-core renders `conf.admin.module_groups`
|
|
370
|
+
* as the DOTTED key `admin.module.groups` (singular). The plural stays as a
|
|
371
|
+
* fallback in case a project/version delivers it that way.
|
|
372
372
|
*/
|
|
373
373
|
const groups = computed(
|
|
374
374
|
() => state.configuration["admin.module.groups"] ?? state.configuration["admin.modules.groups"] ?? {}
|