@ditojs/admin 2.8.0 → 2.8.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ditojs/admin",
3
- "version": "2.8.0",
3
+ "version": "2.8.1",
4
4
  "type": "module",
5
5
  "description": "Dito.js Admin is a schema based admin interface for Dito.js Server, featuring auto-generated views and forms and built with Vue.js",
6
6
  "repository": "https://github.com/ditojs/dito/tree/master/packages/admin",
@@ -83,7 +83,7 @@
83
83
  "vite": "^4.3.5"
84
84
  },
85
85
  "types": "types",
86
- "gitHead": "6f589b645e8841b1875330d9918a7d952af49b31",
86
+ "gitHead": "26db3d0a7ebbed92b052bd7cffa078e9cdae7497",
87
87
  "scripts": {
88
88
  "build": "vite build",
89
89
  "watch": "yarn build --mode 'development' --watch",
@@ -40,6 +40,15 @@ export default DitoComponent.component('DitoCreateButton', {
40
40
 
41
41
  props: {
42
42
  schema: { type: Object, required: true },
43
+ // The next four props are there for `DitoContext` and the `context()`
44
+ // getter in `DitoMixin`.
45
+ // TODO: Should they be moved to shared mixin that defines them as required
46
+ // and also provides the `context()` getter, perhaps `ContextMixin`?
47
+ // `schema` could be included as well, and `ContextMixin` could be used in
48
+ // `DitoForm`, `DitoView`, `DitoPanel`, `DitoSchema`, `DitoEditButtons`,
49
+ // etc? But the problem with the root components is that they don't have
50
+ // these props. We could add a `contextAttributes()` getter for easy passing
51
+ // on as `v-bind="contextAttributes"`.
43
52
  dataPath: { type: String, required: true },
44
53
  data: { type: [Object, Array], default: null },
45
54
  meta: { type: Object, required: true },
@@ -72,7 +81,14 @@ export default DitoComponent.component('DitoCreateButton', {
72
81
  isFormCreatable(form) {
73
82
  // Forms can be excluded from the list by providing `if: false` or
74
83
  // `creatable: false`.
75
- return form.creatable !== false && this.shouldRenderSchema(form)
84
+ return (
85
+ this.shouldRenderSchema(form) &&
86
+ this.getSchemaValue('creatable', {
87
+ type: Boolean,
88
+ default: true,
89
+ schema: form
90
+ })
91
+ )
76
92
  },
77
93
 
78
94
  createItem(form, type = null) {
@@ -10,18 +10,18 @@ DitoButtons.dito-edit-buttons.dito-buttons-round(
10
10
  )
11
11
  //- Firefox doesn't like <button> here, so use <a> instead:
12
12
  a.dito-button(
13
- v-if="hasDraggable"
14
- :class="{ 'dito-disabled': disabled }"
13
+ v-if="draggable"
14
+ :class="{ 'dito-disabled': isDraggableDisabled }"
15
15
  v-bind="getButtonAttributes(verbs.drag)"
16
16
  )
17
17
  RouterLink.dito-button(
18
- v-if="hasEditable"
19
- :class="{ 'dito-disabled': disabled || !editPath }"
18
+ v-if="editable"
19
+ :class="{ 'dito-disabled': isEditableDisabled }"
20
20
  :to="editPath ? { path: editPath } : {}"
21
21
  v-bind="getButtonAttributes(verbs.edit)"
22
22
  )
23
23
  DitoCreateButton(
24
- v-if="hasCreatable"
24
+ v-if="creatable"
25
25
  :schema="schema"
26
26
  :dataPath="dataPath"
27
27
  :data="data"
@@ -30,12 +30,12 @@ DitoButtons.dito-edit-buttons.dito-buttons-round(
30
30
  :path="createPath"
31
31
  :verb="verbs.create"
32
32
  :text="createButtonText"
33
- :disabled="disabled || !createPath"
33
+ :disabled="isCreatableDisabled"
34
34
  )
35
35
  button.dito-button(
36
- v-if="hasDeletable"
36
+ v-if="deletable"
37
37
  type="button"
38
- :disabled="disabled || !isFormDeletable"
38
+ :disabled="isDeletableDisabled"
39
39
  v-bind="getButtonAttributes(verbs.delete)"
40
40
  @click="$emit('delete')"
41
41
  )
@@ -70,24 +70,28 @@ export default DitoComponent.component('DitoEditButtons', {
70
70
  return this.getLabel(this.schema.form)
71
71
  },
72
72
 
73
- hasDraggable() {
74
- return this.hasOption('draggable')
73
+ isDraggableDisabled() {
74
+ return this.disabled || !this.hasSchemaOption('draggable')
75
75
  },
76
76
 
77
- hasEditable() {
78
- return this.hasOption('editable')
77
+ isDeletableDisabled() {
78
+ return this.disabled || !this.hasSchemaOption('deletable')
79
79
  },
80
80
 
81
- hasCreatable() {
82
- return this.hasOption('creatable')
83
- },
84
-
85
- hasDeletable() {
86
- return this.hasOption('deletable')
81
+ isCreatableDisabled() {
82
+ return (
83
+ this.disabled ||
84
+ !this.createPath ||
85
+ !this.hasSchemaOption('creatable')
86
+ )
87
87
  },
88
88
 
89
- isFormDeletable() {
90
- return this.schema.deletable !== false
89
+ isEditableDisabled() {
90
+ return (
91
+ this.disabled ||
92
+ !this.editPath ||
93
+ !this.hasSchemaOption('editable')
94
+ )
91
95
  },
92
96
 
93
97
  createButtonText() {
@@ -105,11 +109,13 @@ export default DitoComponent.component('DitoEditButtons', {
105
109
  },
106
110
 
107
111
  methods: {
108
- hasOption(name) {
109
- // The options of the outer component are passed to the buttons component
110
- // through properties `this[name]`, but can be disabled on a per-form
111
- // basis by setting `schema[name]` to `false`.
112
- return !!(this[name] && this.schema[name] !== false)
112
+ hasSchemaOption(name) {
113
+ // All options can be disabled on a per-form basis by setting
114
+ // `schema[name]` to `false` or a callback returning `false`.
115
+ return this.getSchemaValue(name, {
116
+ type: Boolean,
117
+ default: true
118
+ })
113
119
  }
114
120
  }
115
121
  })
@@ -26,14 +26,14 @@ export default DitoComponent.component('DitoElement', {
26
26
 
27
27
  classes() {
28
28
  return {
29
- ...this.$attrs.class,
29
+ ...asObject(this.$attrs.class),
30
30
  ...asObject(this.options.class)
31
31
  }
32
32
  },
33
33
 
34
34
  styles() {
35
35
  return {
36
- ...this.$attrs.style,
36
+ ...asObject(this.$attrs.style),
37
37
  ...asObject(this.options.style)
38
38
  }
39
39
  }
@@ -123,8 +123,6 @@ export default DitoComponent.component('DitoLabel', {
123
123
  label {
124
124
  cursor: inherit;
125
125
  font-weight: bold;
126
- white-space: nowrap;
127
- line-height: $input-height;
128
126
  }
129
127
 
130
128
  label,
@@ -132,6 +130,9 @@ export default DitoComponent.component('DitoLabel', {
132
130
  &__suffix {
133
131
  @include user-select(none);
134
132
  @include ellipsis;
133
+
134
+ white-space: nowrap;
135
+ line-height: $input-height;
135
136
  }
136
137
 
137
138
  &__prefix + label,
@@ -219,6 +219,7 @@ export default DitoComponent.component('DitoPane', {
219
219
 
220
220
  .dito-pane {
221
221
  $self: &;
222
+ $root-padding: $content-padding - $form-spacing-half;
222
223
 
223
224
  display: flex;
224
225
  position: relative;
@@ -240,7 +241,7 @@ export default DitoComponent.component('DitoPane', {
240
241
  margin: 0;
241
242
  // Move the negative margin used to remove the padding added by
242
243
  // `.dito-container` inside `.dito-pane` to the padding:
243
- padding: $content-padding - $form-spacing-half;
244
+ padding: $root-padding;
244
245
 
245
246
  &#{$self}--single {
246
247
  padding: $content-padding;
@@ -260,9 +261,9 @@ export default DitoComponent.component('DitoPane', {
260
261
  content: '';
261
262
  width: 100%;
262
263
  border-bottom: $border-style;
263
- // Add removed $form-spacing-half again to the ruler
264
- margin: (-$content-padding + $form-spacing-half) $form-spacing-half
265
- $form-spacing-half;
264
+ // Shift ruler up by $root-padding to exclude removed $form-spacing-half.
265
+ margin: (-$root-padding) $form-spacing-half $root-padding;
266
+ padding: $form-spacing-half;
266
267
  }
267
268
  }
268
269
 
@@ -273,6 +274,9 @@ export default DitoComponent.component('DitoPane', {
273
274
  }
274
275
 
275
276
  .dito-break {
277
+ // `.dito-break` is rendered as <span> so we can use the
278
+ // `.dito-container:first-of-type` selector to match the first container
279
+ // even if it has a break before it.
276
280
  display: block;
277
281
  flex: 100%;
278
282
  height: 0;
@@ -53,22 +53,24 @@ slot(name="before")
53
53
  template(
54
54
  v-if="hasTabs"
55
55
  )
56
- DitoPane.dito-pane__tab(
56
+ template(
57
57
  v-for="(tabSchema, tab) in tabs"
58
- v-show="selectedTab === tab"
59
- ref="tabs"
60
- :key="tab"
61
- :tab="tab"
62
- :schema="tabSchema"
63
- :dataPath="dataPath"
64
- :data="data"
65
- :meta="meta"
66
- :store="store"
67
- :single="!inlined && !hasMainPane"
68
- :disabled="disabled"
69
- :generateLabels="generateLabels"
70
- :accumulatedBasis="accumulatedBasis"
71
58
  )
59
+ DitoPane.dito-pane__tab(
60
+ v-if="selectedTab === tab"
61
+ ref="tabs"
62
+ :key="tab"
63
+ :tab="tab"
64
+ :schema="tabSchema"
65
+ :dataPath="dataPath"
66
+ :data="data"
67
+ :meta="meta"
68
+ :store="store"
69
+ :single="!inlined && !hasMainPane"
70
+ :disabled="disabled"
71
+ :generateLabels="generateLabels"
72
+ :accumulatedBasis="accumulatedBasis"
73
+ )
72
74
  DitoPane.dito-pane__main(
73
75
  v-if="hasMainPane"
74
76
  ref="components"
@@ -28,7 +28,6 @@ export default {
28
28
  data() {
29
29
  return {
30
30
  parsedValue: undefined,
31
- changedValue: undefined,
32
31
  focused: false
33
32
  }
34
33
  },
@@ -48,37 +47,27 @@ export default {
48
47
 
49
48
  value: {
50
49
  get() {
51
- let value = computeValue(
50
+ const value = computeValue(
52
51
  this.schema,
53
52
  this.data,
54
53
  this.name,
55
54
  this.dataPath,
56
55
  { component: this }
57
56
  )
58
- const { formatValue } = this.$options
59
- if (formatValue) {
60
- value = formatValue(this.schema, value, this.dataPath)
61
- }
62
57
  const { format } = this.schema
63
- if (format) {
64
- value = format(new DitoContext(this, { value }))
65
- }
66
- return value
58
+ return format
59
+ ? format(new DitoContext(this, { value }))
60
+ : value
67
61
  },
68
62
 
69
63
  set(value) {
70
- const { parseValue } = this.$options
71
- if (parseValue) {
72
- value = parseValue(this.schema, value, this.dataPath)
73
- }
74
64
  const { parse } = this.schema
75
65
  if (parse) {
76
66
  value = parse(new DitoContext(this, { value }))
77
67
  }
68
+ this.parsedValue = value
78
69
  // eslint-disable-next-line vue/no-mutating-props
79
70
  this.data[this.name] = value
80
- this.parsedValue = value
81
- this.changedValue = undefined
82
71
  }
83
72
  },
84
73
 
@@ -295,7 +284,6 @@ export default {
295
284
 
296
285
  clear() {
297
286
  this.value = null
298
- this.changedValue = undefined
299
287
  this.blur()
300
288
  this.onChange()
301
289
  },
@@ -318,21 +306,12 @@ export default {
318
306
  },
319
307
 
320
308
  onChange() {
321
- const value =
322
- this.parsedValue !== undefined ? this.parsedValue : this.value
323
-
324
- if (this.$options.nativeField) {
325
- // For some odd reason, the native change event now sometimes fires
326
- // twice on Vue3. Filter out second call.
327
- // TODO: Investigate why this happens, and if it's a bug in Vue3.
328
- if (value === this.changedValue) return
329
- this.changedValue = value
330
- }
331
-
332
309
  this.markDirty()
333
310
  this.emitEvent('change', {
334
- // Prevent endless parse recursion:
335
- context: { value },
311
+ context: {
312
+ // Prevent endless parse recursion:
313
+ value: this.parsedValue !== undefined ? this.parsedValue : this.value
314
+ },
336
315
  // Pass `schemaComponent` as parent, so change events can propagate up.
337
316
  parent: this.schemaComponent
338
317
  })
@@ -38,6 +38,7 @@
38
38
  :disabled="disabled"
39
39
  @click="clear"
40
40
  )
41
+ //- Edit button is never disabled, even if the field is disabled.
41
42
  DitoEditButtons(
42
43
  v-if="editable"
43
44
  :schema="schema"
@@ -45,7 +46,7 @@
45
46
  :data="data"
46
47
  :meta="meta"
47
48
  :store="store"
48
- :disabled="disabled"
49
+ :disabled="false"
49
50
  :editable="editable"
50
51
  :editPath="editPath"
51
52
  )
@@ -37,6 +37,7 @@
37
37
  :disabled="disabled"
38
38
  @click="clear"
39
39
  )
40
+ //- Edit button is never disabled, even if the field is disabled.
40
41
  DitoEditButtons(
41
42
  v-if="editable"
42
43
  :schema="schema"
@@ -44,7 +45,7 @@
44
45
  :data="data"
45
46
  :meta="meta"
46
47
  :store="store"
47
- :disabled="disabled"
48
+ :disabled="false"
48
49
  :editable="editable"
49
50
  :editPath="editPath"
50
51
  )