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.
Files changed (83) hide show
  1. package/README.md +67 -41
  2. package/index.d.ts +18 -9
  3. package/index.js +6 -3
  4. package/package.json +3 -5
  5. package/src/components/Browser/Browser.vue +58 -58
  6. package/src/components/Browser/TreeNav.vue +32 -32
  7. package/src/components/Browser/ViurBrowser.d.vue.ts +21 -21
  8. package/src/components/Browser/ViurBrowser.vue +47 -44
  9. package/src/components/Browser/dragSession.ts +27 -27
  10. package/src/components/Browser/index.ts +3 -3
  11. package/src/components/Browser/types.ts +9 -9
  12. package/src/components/DataTable/ColumnFilterPanel.vue +7 -7
  13. package/src/components/DataTable/DataTable.vue +346 -346
  14. package/src/components/DataTable/ViurDataTable.d.vue.ts +26 -26
  15. package/src/components/DataTable/ViurDataTable.vue +51 -50
  16. package/src/components/DataTable/columns.ts +30 -30
  17. package/src/components/DataTable/index.ts +12 -12
  18. package/src/components/DataTable/rows.ts +71 -72
  19. package/src/components/DataTable/types.ts +55 -55
  20. package/src/components/DataTable/useColumnLayout.ts +28 -28
  21. package/src/components/DataTable/useGridNavigation.ts +15 -15
  22. package/src/components/DataTable/useVirtualRows.ts +10 -10
  23. package/src/components/DataTable/viurColumns.ts +69 -69
  24. package/src/forms/ViForm.d.vue.ts +32 -32
  25. package/src/forms/ViForm.vue +17 -16
  26. package/src/forms/ViFormCategory.vue +3 -1
  27. package/src/forms/bones/Bone.vue +125 -108
  28. package/src/forms/bones/BoneActions.vue +21 -21
  29. package/src/forms/bones/BoneLabel.vue +1 -1
  30. package/src/forms/bones/BoneMultipleWrapper.vue +3 -3
  31. package/src/forms/bones/BoneNestedWrapper.vue +3 -3
  32. package/src/forms/bones/BoneSingleEntry.vue +2 -2
  33. package/src/forms/bones/FilterBone.vue +3 -3
  34. package/src/forms/bones/actions/ActionDialog.vue +2 -2
  35. package/src/forms/bones/actions/Debug.vue +6 -6
  36. package/src/forms/bones/actions/Delete.vue +2 -2
  37. package/src/forms/bones/actions/DescribeImage.vue +4 -3
  38. package/src/forms/bones/actions/Download.vue +4 -4
  39. package/src/forms/bones/actions/Placeholder.vue +2 -2
  40. package/src/forms/bones/actions/index.js +72 -74
  41. package/src/forms/bones/bone.d.ts +19 -19
  42. package/src/forms/bones/uploadAdapter.js +3 -3
  43. package/src/forms/bones/utils.js +40 -41
  44. package/src/forms/bones/view/base_item.vue +1 -1
  45. package/src/forms/bones/view/boneLogic.js +1 -1
  46. package/src/forms/bones/widgets/booleanBone.vue +19 -19
  47. package/src/forms/bones/widgets/booleanBoneChoose.vue +2 -2
  48. package/src/forms/bones/widgets/booleanBoneSelect.vue +3 -3
  49. package/src/forms/bones/widgets/codeBone.vue +22 -22
  50. package/src/forms/bones/widgets/colorBone.vue +18 -18
  51. package/src/forms/bones/widgets/dateBone.vue +22 -22
  52. package/src/forms/bones/widgets/emailBone.vue +20 -20
  53. package/src/forms/bones/widgets/fileBone.vue +32 -31
  54. package/src/forms/bones/widgets/keyBone.vue +21 -21
  55. package/src/forms/bones/widgets/numericBone.vue +21 -21
  56. package/src/forms/bones/widgets/passwordBone.vue +34 -31
  57. package/src/forms/bones/widgets/phoneBone.vue +20 -20
  58. package/src/forms/bones/widgets/rawBone.vue +19 -19
  59. package/src/forms/bones/widgets/recordBone.vue +16 -16
  60. package/src/forms/bones/widgets/relationalBone.vue +26 -26
  61. package/src/forms/bones/widgets/selectBone.vue +23 -23
  62. package/src/forms/bones/widgets/selectBoneChoose.vue +2 -2
  63. package/src/forms/bones/widgets/spatialBone.vue +21 -21
  64. package/src/forms/bones/widgets/stringBone.vue +27 -27
  65. package/src/forms/bones/widgets/textBone.vue +28 -26
  66. package/src/forms/install.d.ts +1 -1
  67. package/src/forms/install.js +7 -0
  68. package/src/forms/layouts/LayloutList2Columns.vue +1 -1
  69. package/src/forms/layouts/LayoutCategory.vue +1 -1
  70. package/src/forms/layouts/LayoutList.vue +1 -1
  71. package/src/forms/utils.js +22 -22
  72. package/src/request/configStore.js +4 -4
  73. package/src/request/envelope.js +6 -6
  74. package/src/request/request.js +22 -22
  75. package/src/translations/de.js +31 -0
  76. package/src/translations/en.js +31 -0
  77. package/src/user/LoginScreen.d.vue.ts +24 -24
  78. package/src/user/LoginScreen.vue +6 -7
  79. package/src/user/store.d.ts +16 -16
  80. package/src/vite/safeHtml.js +73 -0
  81. package/src/vite/sanitizeVHtml.d.ts +4 -0
  82. package/src/vite/sanitizeVHtml.js +15 -0
  83. 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-Auswahl-Widget für Bones vom Typ `relational` und `relational.select`.
39
+ * Relational selection widget for bones of type `relational` and `relational.select`.
40
40
  *
41
- * Beim Typ `relational` wird eine `<wa-combobox>` angezeigt, die via `getList`
42
- * Einträge aus dem konfigurierten `module` lädt und filtert. Ist ein Wert gesetzt,
43
- * wird stattdessen ein gesperrtes `<wa-input>` mit dem formatierten Eintrag angezeigt.
44
- * Beim Typ `relational.select` wird ein Dropdown-Widget gerendert.
45
- * Falls die Struktur ein `using`-Objekt enthält, wird zusätzlich ein `Wrapper_nested`
46
- * für die relationalen Zusatz-Felder (`rel`) eingeblendet.
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 - Äußerer Container des Widgets
51
- * @cssClass bone-widget - Basis-Klasse aller Bone-Widgets
52
- * @cssClass bone-widget-relational - Kennzeichnet den Bone-Typ
53
- * @cssClass bone-widget-relational-default - Standard-Variante
54
- * @cssClass bone-widget-relational-{name} - Dynamisch gesetzt auf den Bone-Namen
55
- * @cssClass bone-widget-single-entry - Zeile mit Combobox/Input
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-Name – wird in jedem `change`-Event als erstes Argument übergeben. */
61
+ /** Bone name – passed as the first argument in every `change` event. */
62
62
  name: String,
63
- /** Aktueller Bone-Wert; Objekt mit `dest`- und `rel`-Schlüsseln oder `null`. */
63
+ /** Current bone value; object with `dest` and `rel` keys, or `null`. */
64
64
  value: [Object, String, Number, Boolean, Array],
65
- /** Index im Multiple-Array; `undefined` bei Einzelwert. */
65
+ /** Index in the multiple array; `undefined` for a single value. */
66
66
  index: Number,
67
- /** Sprach-Key bei mehrsprachigen Bones, z.B. `"de"`. */
67
+ /** Language key for multilingual bones, e.g. `"de"`. */
68
68
  lang: String,
69
- /** Bone-Struktur; `using` steuert ob ein Nested-Wrapper angezeigt wird. */
69
+ /** Bone structure; `using` controls whether a nested wrapper is shown. */
70
70
  bone: Object,
71
- /** Aktuell nicht genutzt. */
71
+ /** Currently not used. */
72
72
  autofocus: Boolean,
73
73
  })
74
74
 
75
75
  const emit = defineEmits([
76
76
  /**
77
- * Wird bei Auswahl eines Eintrags, beim Löschen und beim Mount (Initialisierung) gefeuert.
78
- * @arg {string} name - Bone-Name
79
- * @arg {{ dest: object, rel: object|null }|string} value - Ausgewähltes Relational-Objekt oder `""` beim Löschen
80
- * @arg {string|undefined} lang - Sprach-Key
81
- * @arg {number|undefined} index - Index im Multiple-Array
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
- // Halte state.selection synchron mit props.value — wichtig, wenn der Wert
152
- // von außen geleert wird (z.B. via Delete-Action).
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-Auswahlfeld für vordefinierte Werte (Typ `select`).
29
+ * Dropdown select field for predefined values (type `select`).
30
30
  *
31
- * Rendert ein `<wa-select>` mit `<wa-option>`-Einträgen, die aus
32
- * `boneState.bonestructure.values` generiert werden. `values` kann ein Array
33
- * von `[key, label]`-Tupeln oder ein Objekt `{ key: label }` sein.
34
- * Bei aktiviertem `multiple` können mehrere Optionen gleichzeitig gewählt werden.
35
- * Der Bone-Typ `select.choose` wird durch die separate Komponente `SelectBoneChoose`
36
- * abgehandelt und rendert Radio-Buttons bzw. Checkboxen.
37
- * Bei `boneState.label === "placeholder"` wird der Bone-Name als Placeholder angezeigt.
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 - Basis-Klasse aller Bone-Widgets
42
- * @cssClass bone-widget-select - Kennzeichnet den Bone-Typ
43
- * @cssClass bone-widget-select-default - Standard-Variante (Dropdown)
44
- * @cssClass bone-widget-select-{name} - Dynamisch gesetzt auf den Bone-Namen, z.B. `bone-widget-select-status`
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-Name – wird in jedem `change`-Event als erstes Argument übergeben. */
50
+ /** Bone name – passed as the first argument in every `change` event. */
51
51
  name: String,
52
- /** Aktueller Bone-Wert (String, Array bei multiple). */
52
+ /** Current bone value (string, array with multiple). */
53
53
  value: null,
54
- /** Index im Multiple-Array; `undefined` bei Einzelwert. */
54
+ /** Index in the multiple array; `undefined` for a single value. */
55
55
  index: Number,
56
- /** Sprach-Key bei mehrsprachigen Bones, z.B. `"de"`. */
56
+ /** Language key for multilingual bones, e.g. `"de"`. */
57
57
  lang: String,
58
- /** Bone-Struktur (aktuell nicht aktiv genutzt). */
58
+ /** Bone structure (currently not actively used). */
59
59
  bone: Object,
60
- /** Setzt den Fokus auf das Select-Element (aktuell nicht implementiert). */
60
+ /** Focuses the select element (currently not implemented). */
61
61
  autofocus: Boolean,
62
62
  })
63
63
 
64
64
  const emit = defineEmits([
65
65
  /**
66
- * Wird bei jeder Wertänderung sowie beim Mount (Initialisierung) gefeuert.
67
- * @arg {string} name - Bone-Name
68
- * @arg {string|string[]} value - Gewählter Wert oder Array bei multiple
69
- * @arg {string|undefined} lang - Sprach-Key
70
- * @arg {number|undefined} index - Index im Multiple-Array
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 an der Gruppe (siehe booleanBoneChoose): disabled Radios
20
- zeigten keine Auswahl -->
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
- * Koordinaten-Eingabe für geografische Punkte (Breitengrad / Längengrad).
42
+ * Coordinate input for geographic points (latitude / longitude).
43
43
  *
44
- * Rendert zwei `<wa-input type="number">` Felder für Latitude und Longitude.
45
- * Die erlaubten Wertebereiche werden über `boneState.bonestructure.boundslat`
46
- * und `boneState.bonestructure.boundslng` gesteuert. Unterstützt weder
47
- * Mehrsprachigkeit noch Mehrfachwerte.
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 - Basis-Klasse aller Bone-Widgets
52
- * @cssClass bone-widget-spatial - Kennzeichnet den Bone-Typ
53
- * @cssClass bone-widget-spatial-default - Standard-Variante
54
- * @cssClass bone-widget-spatial-{name}-lat - Dynamisch gesetzt für das Breiten­grad-Feld
55
- * @cssClass bone-widget-spatial-{name}-long - Dynamisch gesetzt für das Längen­grad-Feld
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-Name – wird in jedem `change`-Event als erstes Argument übergeben. */
61
+ /** Bone name – passed as the first argument in every `change` event. */
62
62
  name: String,
63
- /** Aktueller Bone-Wert als Array `[lat, lng]` oder Objekt `{ lat, lng }`. */
63
+ /** Current bone value as an array `[lat, lng]` or an object `{ lat, lng }`. */
64
64
  value: [Object, String, Number, Boolean, Array],
65
- /** Index im Multiple-Array; `undefined` bei Einzelwert. */
65
+ /** Index in the multiple array; `undefined` for a single value. */
66
66
  index: Number,
67
- /** Sprach-Key (SpatialBone unterstützt kein multilang). */
67
+ /** Language key (SpatialBone does not support multilang). */
68
68
  lang: String,
69
- /** Bone-Struktur (aktuell nicht aktiv genutzt). */
69
+ /** Bone structure (currently not actively used). */
70
70
  bone: Object,
71
- /** Setzt den Fokus nach dem Mount auf das erste Input-Element. */
71
+ /** Focuses the first input element after mount. */
72
72
  autofocus: Boolean,
73
73
  })
74
74
 
75
75
  const emit = defineEmits([
76
76
  /**
77
- * Wird bei jeder Wertänderung sowie beim Mount (Initialisierung) gefeuert.
78
- * @arg {string} name - Bone-Name
79
- * @arg {[number, number]} value - Koordinaten als `[lat, lng]`
80
- * @arg {string|undefined} lang - Sprach-Key
81
- * @arg {number|undefined} index - Index im Multiple-Array
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
- * Einzeiliges Textfeld für einfache Zeichenketten.
27
+ * Single-line text field for simple strings.
28
28
  *
29
- * Rendert ein `<wa-input>` und delegiert Validierung an das native
30
- * Constraint Validation API. Unterstützt optionale Regex-Validierung
31
- * via `boneState.params.pattern` sowie eine eigene Fehlermeldung via
32
- * `boneState.params.pattern_error`. Bei `boneState.label === "placeholder"`
33
- * wird der Bone-Name als Placeholder angezeigt statt als Label darüber.
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 - Basis-Klasse aller Bone-Widgets
38
- * @cssClass bone-widget-string - Kennzeichnet den Bone-Typ
39
- * @cssClass bone-widget-string-default - Standard-Variante
40
- * @cssClass bone-widget-string-{name} - Dynamisch gesetzt auf den Bone-Namen, z.B. `bone-widget-string-title`
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-Name – wird in jedem `change`-Event als erstes Argument übergeben. */
46
+ /** Bone name – passed as the first argument in every `change` event. */
47
47
  name: String,
48
- /** Aktueller Bone-Wert. */
48
+ /** Current bone value. */
49
49
  value: [Object, String, Number, Boolean, Array],
50
- /** Index im Multiple-Array; `undefined` bei Einzelwert. */
50
+ /** Index in the multiple array; `undefined` for a single value. */
51
51
  index: Number,
52
- /** Sprach-Key bei mehrsprachigen Bones, z.B. `"de"`. */
52
+ /** Language key for multilingual bones, e.g. `"de"`. */
53
53
  lang: String,
54
- /** Bone-Struktur (aktuell nicht aktiv genutzt). */
54
+ /** Bone structure (currently not actively used). */
55
55
  bone: Object,
56
- /** Setzt den Fokus nach 600 ms auf das Input-Element. */
56
+ /** Focuses the input element after 600 ms. */
57
57
  autofocus: Boolean,
58
58
  })
59
59
 
60
60
  const emit = defineEmits([
61
61
  /**
62
- * Wird bei jeder Wertänderung sowie beim Mount (Initialisierung) gefeuert.
63
- * @arg {string} name - Bone-Name
64
- * @arg {string} value - Aktueller Eingabewert
65
- * @arg {string|undefined} lang - Sprach-Key
66
- * @arg {number|undefined} index - Index im Multiple-Array
67
- * @arg {boolean} [valid] - Validierungsstatus; fehlt beim Init-Event
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
- * Verarbeitet `change`- und `keyup`-Events des `<wa-input>`.
108
- * Prüft die native Validität, setzt bei `patternMismatch` eine eigene
109
- * Fehlermeldung und emittiert den `change`-Event mit Validierungsstatus.
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 - Das DOM-Event vom Input-Element
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/dist/translations/de.js"
76
- import "ckeditor5/dist/ckeditor5.css"
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
- * Mehrzeiliges Textfeld für längere Inhalte, wahlweise als Textarea oder Rich-Text-Editor (CKEditor 5).
81
+ * Multi-line text field for longer content, either as a textarea or a rich-text editor (CKEditor 5).
81
82
  *
82
- * Wenn `boneState.bonestructure.valid_html` oder `boneState.bonestructure.validHtml` gesetzt ist,
83
- * wird ein CKEditor 5 (ClassicEditor) gerendert. Die sichtbaren Toolbar-Aktionen werden anhand
84
- * der erlaubten HTML-Tags (`validTags`) gefiltert. Ohne HTML-Konfiguration erscheint ein
85
- * einfaches `<wa-textarea>`. Bei `boneState.label === "placeholder"` wird der Bone-Name als
86
- * Placeholder angezeigt statt als Label.
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 - Basis-Klasse aller Bone-Widgets
91
- * @cssClass bone-widget-text - Kennzeichnet den Bone-Typ
92
- * @cssClass bone-widget-text-default - Standard-Variante (Textarea oder CKEditor)
93
- * @cssClass bone-widget-text-{name} - Dynamisch gesetzt auf den Bone-Namen, z.B. `bone-widget-text-content`
94
- * @cssClass bone-widget-text-{name}-html - Gesetzt wenn der Bone HTML-Inhalt enthält
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-Name – wird in jedem `change`-Event als erstes Argument übergeben. */
101
+ /** Bone name – passed as the first argument in every `change` event. */
101
102
  name: String,
102
- /** Aktueller Bone-Wert als Klartext oder HTML-String. */
103
+ /** Current bone value as plain text or an HTML string. */
103
104
  value: [Object, String, Number, Boolean, Array],
104
- /** Index im Multiple-Array; `undefined` bei Einzelwert. */
105
+ /** Index in the multiple array; `undefined` for a single value. */
105
106
  index: Number,
106
- /** Sprach-Key bei mehrsprachigen Bones, z.B. `"de"`. */
107
+ /** Language key for multilingual bones, e.g. `"de"`. */
107
108
  lang: String,
108
- /** Bone-Struktur (aktuell nicht aktiv genutzt). */
109
+ /** Bone structure (currently not actively used). */
109
110
  bone: Object,
110
- /** Setzt den Fokus auf das Eingabefeld (aktuell nicht implementiert). */
111
+ /** Focuses the input field (currently not implemented). */
111
112
  autofocus: Boolean,
112
113
  })
113
114
 
114
115
  const emit = defineEmits([
115
116
  /**
116
- * Wird bei jeder Wertänderung sowie beim Mount (Initialisierung) gefeuert.
117
- * @arg {string} name - Bone-Name
118
- * @arg {string} value - Aktueller Textwert oder HTML-String
119
- * @arg {string|undefined} lang - Sprach-Key
120
- * @arg {number|undefined} index - Index im Multiple-Array
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: "Link in neuem Fester öffnen",
240
+ label: t("bones.text.openInNewWindow"),
239
241
  attributes: {
240
242
  target: "_blank",
241
243
  rel: "noopener noreferrer",
@@ -1,4 +1,4 @@
1
1
  import type { App } from "vue"
2
2
 
3
- /** Registriert die global per Namen genutzten Formular-Wrapper (`<bone>` usw.). */
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
@@ -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
  }
@@ -36,7 +36,7 @@
36
36
 
37
37
  <script setup>
38
38
  import { inject } from "vue"
39
- import { getBoneWidget } from "../bones"
39
+ import { getBoneWidget } from "../bones/index.js"
40
40
  const formState = inject("formState")
41
41
  const formUpdate = inject("formUpdate")
42
42
  </script>
@@ -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")
@@ -19,7 +19,7 @@
19
19
 
20
20
  <script setup>
21
21
  import { inject } from "vue"
22
- import { getBoneWidget } from "../bones"
22
+ import { getBoneWidget } from "../bones/index.js"
23
23
  const formState = inject("formState")
24
24
  const formUpdate = inject("formUpdate")
25
25
  </script>
@@ -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
- * Tiefe Kopie reiner Daten (Skel-Werte), die Vue-Proxies auf JEDER Ebene
8
- * auflöst. structuredClone allein scheitert daran: ein Record-/using-Formular
9
- * bekommt den reaktiven Wert des Eltern-Bones, und `{ ...proxy }` behält die
10
- * verschachtelten Werte als Proxies. Andere Objekte (Date, File) bleiben geteilt.
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
- // Nur mit Key anhängen: ein SINGLETON hat genau einen Datensatz, sein
37
- // `edit` kennt keinen Key. Ohne diese Prüfung entstand `/edit/undefined`.
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
- // Der `values`-Prop belegt ein frisch GERENDERTES Formular vor. Die
97
- // Antwort auf ein Absenden spiegelt, was gesendet wurde — darüber darf
98
- // er nicht erneut schreiben.
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
- // Neue Struktur = Server-Flags: visibleIf/readonlyIf/requiredIf/evaluate
101
- // gleich wieder anwenden, nicht erst bei der nächsten Eingabe.
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
- // Ein v1-Schritt bringt kein Ziel mit (kein `follow`, kein next_url, kein
151
- // params.action_url) — dort wird der Schritt an DIESELBE URL
152
- // zurückgeschickt, aus der er gerendert wurde. Ohne das stünde postUrl
153
- // nach dem Rendern auf null und der Absenden-Knopf liefe ins Leere.
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
- // Stand festhalten, wie er hereinkam: `state.skel` ist die Arbeitskopie und
566
- // wird beim Tippen verändert. resetForm() stellt daraus wieder her, ohne
567
- // erneut zu laden ("Änderungen verwerfen").
568
- // markRaw: reine Lesedaten, kein reaktiver Proxy.
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
- * Änderungen verwerfen: die Werte des letzten Server-Stands wieder einsetzen,
576
- * OHNE neuen Request (dafür ist reload() da). Struktur und Kategorien bleiben.
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"]` (so rendert viur-core
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
- * Gruppen der Modul-Navigation. viur-core rendert `conf.admin.module_groups`
370
- * als PUNKT-Schlüssel `admin.module.groups` (Singular). Der Plural bleibt als
371
- * Rückfallebene stehen, falls ein Projekt/eine Version ihn so ausliefert.
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"] ?? {}