@ditojs/admin 0.265.0 → 0.269.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/LICENSE +1 -1
- package/dist/dito-admin.common.js +1193 -968
- package/dist/dito-admin.common.js.map +1 -1
- package/dist/dito-admin.umd.js +1193 -968
- package/dist/dito-admin.umd.js.map +1 -1
- package/dist/dito-admin.umd.min.js +3 -3
- package/dist/dito-admin.umd.min.js.map +1 -1
- package/package.json +13 -13
- package/src/DitoAdmin.js +3 -2
- package/src/components/DitoAccount.vue +4 -3
- package/src/components/DitoButtons.vue +4 -6
- package/src/components/DitoClipboard.vue +20 -9
- package/src/components/{DitoComponentContainer.vue → DitoContainer.vue} +4 -8
- package/src/components/DitoForm.vue +30 -16
- package/src/components/DitoLabel.vue +2 -2
- package/src/components/{DitoComponents.vue → DitoPane.vue} +18 -28
- package/src/components/DitoPanel.vue +10 -5
- package/src/components/DitoPanels.vue +4 -2
- package/src/components/DitoSchema.vue +59 -51
- package/src/components/DitoSchemaInlined.vue +1 -1
- package/src/components/index.js +5 -6
- package/src/mixins/DitoMixin.js +13 -4
- package/src/mixins/ResourceMixin.js +6 -1
- package/src/mixins/RouteMixin.js +1 -1
- package/src/mixins/SchemaParentMixin.js +6 -0
- package/src/mixins/SourceMixin.js +63 -33
- package/src/mixins/TypeMixin.js +32 -17
- package/src/mixins/ValidatorMixin.js +0 -4
- package/src/styles/_button.sass +1 -1
- package/src/types/TypeButton.vue +12 -11
- package/src/types/TypeCode.vue +1 -1
- package/src/types/TypeMarkup.vue +1 -1
- package/src/types/TypeMultiselect.vue +11 -10
- package/src/types/TypeSection.vue +1 -1
- package/src/types/TypeTreeList.vue +1 -3
- package/src/types/TypeUpload.vue +1 -1
- package/src/utils/accessor.js +2 -0
- package/src/utils/schema.js +17 -7
- package/src/components/DitoButtonContainer.vue +0 -22
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
:dataPath="dataPath"
|
|
30
30
|
:data="data"
|
|
31
31
|
)
|
|
32
|
-
dito-
|
|
32
|
+
dito-pane.dito-pane-tab(
|
|
33
33
|
v-if="hasTabs"
|
|
34
34
|
v-for="(schema, tab) in tabs"
|
|
35
35
|
ref="tabs"
|
|
@@ -41,16 +41,15 @@
|
|
|
41
41
|
:data="data"
|
|
42
42
|
:meta="meta"
|
|
43
43
|
:store="store"
|
|
44
|
-
:single="!inlined && !
|
|
44
|
+
:single="!inlined && !hasMainPane"
|
|
45
45
|
:disabled="disabled"
|
|
46
46
|
:generateLabels="generateLabels"
|
|
47
47
|
)
|
|
48
48
|
transition-height(
|
|
49
49
|
:enabled="inlined"
|
|
50
50
|
)
|
|
51
|
-
dito-
|
|
52
|
-
v-if="
|
|
53
|
-
v-show="opened"
|
|
51
|
+
dito-pane.dito-pane-main(
|
|
52
|
+
v-if="hasMainPane && opened"
|
|
54
53
|
ref="components"
|
|
55
54
|
:schema="schema"
|
|
56
55
|
:dataPath="dataPath"
|
|
@@ -70,9 +69,8 @@
|
|
|
70
69
|
v-if="!hasLabel"
|
|
71
70
|
name="edit-buttons"
|
|
72
71
|
)
|
|
73
|
-
template(
|
|
72
|
+
template(v-else-if="isPopulated")
|
|
74
73
|
dito-panels(
|
|
75
|
-
v-if="isPopulated && panelSchemas.length > 0"
|
|
76
74
|
:panels="panelSchemas"
|
|
77
75
|
:data="data"
|
|
78
76
|
:meta="meta"
|
|
@@ -104,7 +102,7 @@
|
|
|
104
102
|
> .dito-panels
|
|
105
103
|
padding: $content-padding $content-padding $content-padding 0
|
|
106
104
|
// Display a ruler between tabbed components and towards the .dito-buttons
|
|
107
|
-
.dito-
|
|
105
|
+
.dito-pane-tab + .dito-pane-main
|
|
108
106
|
&::before
|
|
109
107
|
// Use a pseudo element to display a ruler with proper margins
|
|
110
108
|
display: block
|
|
@@ -204,8 +202,8 @@ export default DitoComponent.component('dito-schema', {
|
|
|
204
202
|
? data.call(this, this.context)
|
|
205
203
|
: data
|
|
206
204
|
),
|
|
207
|
-
containersRegistry: {},
|
|
208
205
|
componentsRegistry: {},
|
|
206
|
+
panesRegistry: {},
|
|
209
207
|
panelsRegistry: {}
|
|
210
208
|
}
|
|
211
209
|
},
|
|
@@ -225,8 +223,8 @@ export default DitoComponent.component('dito-schema', {
|
|
|
225
223
|
|
|
226
224
|
panelSchemas() {
|
|
227
225
|
const panels = getPanelSchemas(this.schema.panels, '')
|
|
228
|
-
for (const
|
|
229
|
-
panels.push(...
|
|
226
|
+
for (const pane of this.panes) {
|
|
227
|
+
panels.push(...pane.panelSchemas)
|
|
230
228
|
}
|
|
231
229
|
return panels
|
|
232
230
|
},
|
|
@@ -341,7 +339,7 @@ export default DitoComponent.component('dito-schema', {
|
|
|
341
339
|
return !this.inlined && !!this.tabs
|
|
342
340
|
},
|
|
343
341
|
|
|
344
|
-
|
|
342
|
+
hasMainPane() {
|
|
345
343
|
const { components } = this.schema
|
|
346
344
|
return !!components && Object.keys(components).length > 0
|
|
347
345
|
},
|
|
@@ -352,14 +350,26 @@ export default DitoComponent.component('dito-schema', {
|
|
|
352
350
|
}
|
|
353
351
|
}),
|
|
354
352
|
|
|
355
|
-
|
|
356
|
-
return
|
|
353
|
+
components() {
|
|
354
|
+
return Object.values(this.componentsRegistry)
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
panes() {
|
|
358
|
+
return Object.values(this.panesRegistry)
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
panels() {
|
|
362
|
+
return Object.values(this.panelsRegistry)
|
|
357
363
|
},
|
|
358
364
|
|
|
359
365
|
componentsByDataPath() {
|
|
360
366
|
return this._listEntriesByDataPath(this.componentsRegistry)
|
|
361
367
|
},
|
|
362
368
|
|
|
369
|
+
panesByDataPath() {
|
|
370
|
+
return this._listEntriesByDataPath(this.panesRegistry)
|
|
371
|
+
},
|
|
372
|
+
|
|
363
373
|
panelsByDataPath() {
|
|
364
374
|
return this._listEntriesByDataPath(this.panelsRegistry)
|
|
365
375
|
}
|
|
@@ -370,7 +380,7 @@ export default DitoComponent.component('dito-schema', {
|
|
|
370
380
|
this.setupSchemaFields()
|
|
371
381
|
// Delegate change events through to parent schema:
|
|
372
382
|
this.delegate('change', this.parentSchemaComponent)
|
|
373
|
-
this.emitEvent('create'
|
|
383
|
+
this.emitEvent('initialize') // Not `'create'`, since that's for data.
|
|
374
384
|
},
|
|
375
385
|
|
|
376
386
|
beforeDestroy() {
|
|
@@ -422,17 +432,11 @@ export default DitoComponent.component('dito-schema', {
|
|
|
422
432
|
},
|
|
423
433
|
|
|
424
434
|
someComponent(callback) {
|
|
425
|
-
return (
|
|
426
|
-
this.isPopulated &&
|
|
427
|
-
Object.values(this.componentsRegistry).some(callback)
|
|
428
|
-
)
|
|
435
|
+
return this.isPopulated && this.components.some(callback)
|
|
429
436
|
},
|
|
430
437
|
|
|
431
438
|
everyComponent(callback) {
|
|
432
|
-
return (
|
|
433
|
-
this.isPopulated &&
|
|
434
|
-
Object.values(this.componentsRegistry).every(callback)
|
|
435
|
-
)
|
|
439
|
+
return this.isPopulated && this.components.every(callback)
|
|
436
440
|
},
|
|
437
441
|
|
|
438
442
|
onExpand(expand) {
|
|
@@ -440,11 +444,16 @@ export default DitoComponent.component('dito-schema', {
|
|
|
440
444
|
// TODO: Actually expose this on DitoContext?
|
|
441
445
|
context: { expand }
|
|
442
446
|
})
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
447
|
+
// Prevent closing the schema with invalid data, since the in-component
|
|
448
|
+
// validation will not be executed once it's closed.
|
|
449
|
+
|
|
450
|
+
// TODO: Move validation out of components, to schema, just like
|
|
451
|
+
// processing, and use `showValidationErrors()` for the resulting errors,
|
|
452
|
+
// then remove this requirement, since we can validate closed forms and
|
|
453
|
+
// schemas then.
|
|
454
|
+
if (!this.opened || expand || this.validateAll()) {
|
|
455
|
+
this.opened = expand
|
|
456
|
+
}
|
|
448
457
|
},
|
|
449
458
|
|
|
450
459
|
onChange() {
|
|
@@ -452,13 +461,13 @@ export default DitoComponent.component('dito-schema', {
|
|
|
452
461
|
},
|
|
453
462
|
|
|
454
463
|
resetValidation() {
|
|
455
|
-
for (const component of
|
|
464
|
+
for (const component of this.components) {
|
|
456
465
|
component.resetValidation()
|
|
457
466
|
}
|
|
458
467
|
},
|
|
459
468
|
|
|
460
469
|
clearErrors() {
|
|
461
|
-
for (const component of
|
|
470
|
+
for (const component of this.components) {
|
|
462
471
|
component.clearErrors()
|
|
463
472
|
}
|
|
464
473
|
},
|
|
@@ -512,7 +521,7 @@ export default DitoComponent.component('dito-schema', {
|
|
|
512
521
|
return this.validateAll(match, false)
|
|
513
522
|
},
|
|
514
523
|
|
|
515
|
-
showValidationErrors(errors, focus) {
|
|
524
|
+
async showValidationErrors(errors, focus) {
|
|
516
525
|
this.clearErrors()
|
|
517
526
|
let first = true
|
|
518
527
|
const unmatched = []
|
|
@@ -531,7 +540,7 @@ export default DitoComponent.component('dito-schema', {
|
|
|
531
540
|
for (const component of components) {
|
|
532
541
|
if (component.showValidationErrors(errs, first && focus)) {
|
|
533
542
|
found = true
|
|
534
|
-
|
|
543
|
+
first = false
|
|
535
544
|
}
|
|
536
545
|
}
|
|
537
546
|
if (!found) {
|
|
@@ -542,22 +551,21 @@ export default DitoComponent.component('dito-schema', {
|
|
|
542
551
|
while (dataPathParts.length > 0) {
|
|
543
552
|
const components = this.getComponentsByDataPath(dataPathParts)
|
|
544
553
|
for (const component of components) {
|
|
545
|
-
if (component.navigateToComponent?.(
|
|
554
|
+
if (await component.navigateToComponent?.(
|
|
546
555
|
fullDataPath,
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
subComponent.showValidationErrors(filteredErrors, true)
|
|
556
|
+
subComponents => {
|
|
557
|
+
let found = false
|
|
558
|
+
for (const component of subComponents) {
|
|
559
|
+
const errs = errors[component.dataPath]
|
|
560
|
+
if (
|
|
561
|
+
errs &&
|
|
562
|
+
component.showValidationErrors(errs, first && focus)
|
|
563
|
+
) {
|
|
564
|
+
found = true
|
|
565
|
+
first = false
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return found
|
|
561
569
|
}
|
|
562
570
|
)) {
|
|
563
571
|
// Found a nested form to display at least parts fo the errors.
|
|
@@ -652,16 +660,16 @@ export default DitoComponent.component('dito-schema', {
|
|
|
652
660
|
this.$schemaParentComponent()?._registerSchemaComponent(this, add)
|
|
653
661
|
},
|
|
654
662
|
|
|
655
|
-
_registerContainer(container, add) {
|
|
656
|
-
this._registerEntry(this.containersRegistry, container, add)
|
|
657
|
-
},
|
|
658
|
-
|
|
659
663
|
_registerComponent(component, add) {
|
|
660
664
|
this._registerEntry(this.componentsRegistry, component, add)
|
|
661
665
|
// Only register with the parent if schema shares data with it.
|
|
662
666
|
this.parentSchemaComponent?._registerComponent(component, add)
|
|
663
667
|
},
|
|
664
668
|
|
|
669
|
+
_registerPane(pane, add) {
|
|
670
|
+
this._registerEntry(this.panesRegistry, pane, add)
|
|
671
|
+
},
|
|
672
|
+
|
|
665
673
|
_registerPanel(panel, add) {
|
|
666
674
|
this._registerEntry(this.panelsRegistry, panel, add)
|
|
667
675
|
},
|
package/src/components/index.js
CHANGED
|
@@ -12,15 +12,14 @@ import './DitoElement'
|
|
|
12
12
|
import './DitoLabel'
|
|
13
13
|
import './DitoSchema'
|
|
14
14
|
import './DitoSchemaInlined'
|
|
15
|
-
import './
|
|
15
|
+
import './DitoPane'
|
|
16
|
+
import './DitoContainer'
|
|
17
|
+
import './DitoTabs'
|
|
18
|
+
import './DitoPanel'
|
|
19
|
+
import './DitoPanels'
|
|
16
20
|
import './DitoButtons'
|
|
17
21
|
import './DitoEditButtons'
|
|
18
|
-
import './DitoComponentContainer'
|
|
19
|
-
import './DitoButtonContainer'
|
|
20
22
|
import './DitoCreateButton'
|
|
21
|
-
import './DitoPanel'
|
|
22
|
-
import './DitoPanels'
|
|
23
|
-
import './DitoTabs'
|
|
24
23
|
import './DitoClipboard'
|
|
25
24
|
import './DitoView'
|
|
26
25
|
import './DitoForm'
|
package/src/mixins/DitoMixin.js
CHANGED
|
@@ -25,7 +25,8 @@ export default {
|
|
|
25
25
|
'$sourceComponent',
|
|
26
26
|
'$resourceComponent',
|
|
27
27
|
'$dialogComponent',
|
|
28
|
-
'$panelComponent'
|
|
28
|
+
'$panelComponent',
|
|
29
|
+
'$tabComponent'
|
|
29
30
|
],
|
|
30
31
|
|
|
31
32
|
provide() {
|
|
@@ -122,6 +123,10 @@ export default {
|
|
|
122
123
|
return this.$panelComponent()
|
|
123
124
|
},
|
|
124
125
|
|
|
126
|
+
tabComponent() {
|
|
127
|
+
return this.$tabComponent()
|
|
128
|
+
},
|
|
129
|
+
|
|
125
130
|
parentSchemaComponent() {
|
|
126
131
|
return this.schemaComponent?.$parent.schemaComponent
|
|
127
132
|
},
|
|
@@ -153,7 +158,7 @@ export default {
|
|
|
153
158
|
// We can't store this in `data`, as this is already the pure data from the
|
|
154
159
|
// API server. That's what the `store` is for: Memory that's available as
|
|
155
160
|
// long as the current editing path is still valid. For type components,
|
|
156
|
-
// this memory is provided by the parent, see RouteMixin and
|
|
161
|
+
// this memory is provided by the parent, see RouteMixin and DitoPane.
|
|
157
162
|
getStore(key) {
|
|
158
163
|
return this.store[key]
|
|
159
164
|
},
|
|
@@ -472,7 +477,7 @@ export default {
|
|
|
472
477
|
|
|
473
478
|
const addEvent = (key, event, callback) => {
|
|
474
479
|
if (isFunction(callback)) {
|
|
475
|
-
this.on(event, callback)
|
|
480
|
+
this.on(hyphenate(event), callback)
|
|
476
481
|
} else {
|
|
477
482
|
console.error(`Invalid event definition: ${key}: ${callback}`)
|
|
478
483
|
}
|
|
@@ -488,7 +493,7 @@ export default {
|
|
|
488
493
|
// doing things. Decide which one to remove.
|
|
489
494
|
for (const [key, value] of Object.entries(this.schema)) {
|
|
490
495
|
if (/^on[A-Z]/.test(key)) {
|
|
491
|
-
addEvent(key,
|
|
496
|
+
addEvent(key, key.slice(2), value)
|
|
492
497
|
}
|
|
493
498
|
}
|
|
494
499
|
},
|
|
@@ -518,6 +523,10 @@ export default {
|
|
|
518
523
|
}
|
|
519
524
|
return res
|
|
520
525
|
}
|
|
526
|
+
},
|
|
527
|
+
|
|
528
|
+
emitSchemaEvent(event, params) {
|
|
529
|
+
return this.schemaComponent.emitEvent(event, params)
|
|
521
530
|
}
|
|
522
531
|
}
|
|
523
532
|
}
|
|
@@ -210,6 +210,7 @@ export default {
|
|
|
210
210
|
}
|
|
211
211
|
} else {
|
|
212
212
|
this.setData(response.data)
|
|
213
|
+
this.emitSchemaEvent('load')
|
|
213
214
|
}
|
|
214
215
|
})
|
|
215
216
|
},
|
|
@@ -288,6 +289,8 @@ export default {
|
|
|
288
289
|
|
|
289
290
|
async submitResource(button, resource, method, data, {
|
|
290
291
|
setData = false,
|
|
292
|
+
onSuccess,
|
|
293
|
+
onError,
|
|
291
294
|
notifySuccess = () => this.notify({
|
|
292
295
|
type: 'success',
|
|
293
296
|
title: 'Request Successful',
|
|
@@ -311,9 +314,10 @@ export default {
|
|
|
311
314
|
// See if we're dealing with a Dito validation error:
|
|
312
315
|
const errors = this.isValidationError(response) && data.errors
|
|
313
316
|
if (errors) {
|
|
314
|
-
this.showValidationErrors(errors, true)
|
|
317
|
+
await this.showValidationErrors(errors, true)
|
|
315
318
|
} else {
|
|
316
319
|
const error = isObject(data) ? data : err
|
|
320
|
+
onError?.(error)
|
|
317
321
|
await this.emitButtonEvent(button, 'error', {
|
|
318
322
|
notify: notifyError,
|
|
319
323
|
error
|
|
@@ -326,6 +330,7 @@ export default {
|
|
|
326
330
|
if (setData && data) {
|
|
327
331
|
this.setData(data)
|
|
328
332
|
}
|
|
333
|
+
onSuccess?.()
|
|
329
334
|
await this.emitButtonEvent(button, 'success', {
|
|
330
335
|
notify: notifySuccess
|
|
331
336
|
})
|
package/src/mixins/RouteMixin.js
CHANGED
|
@@ -24,7 +24,7 @@ export default {
|
|
|
24
24
|
reload: false,
|
|
25
25
|
// Each route-component defines a store that gets passed on to its
|
|
26
26
|
// child components, so they can store values in them that live beyond
|
|
27
|
-
// their life-cycle. See:
|
|
27
|
+
// their life-cycle. See: DitoPane, SourceMixin
|
|
28
28
|
store: {},
|
|
29
29
|
loadCache: {} // See TypeMixin.load()
|
|
30
30
|
}
|
|
@@ -12,6 +12,12 @@ export default {
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
|
|
15
|
+
computed: {
|
|
16
|
+
mainSchemaComponent() {
|
|
17
|
+
return this.schemaComponents[0]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
15
21
|
methods: {
|
|
16
22
|
// This method is called by `DitoSchema.created()/destroyed()` on its
|
|
17
23
|
// $parent, if the parent uses the `SchemaParentMixin`:
|
|
@@ -362,7 +362,6 @@ export default {
|
|
|
362
362
|
// including the nested list data.
|
|
363
363
|
this.viewComponent.setData(data)
|
|
364
364
|
}
|
|
365
|
-
this.schemaComponent.onLoad()
|
|
366
365
|
},
|
|
367
366
|
|
|
368
367
|
unwrapListData(data) {
|
|
@@ -445,54 +444,85 @@ export default {
|
|
|
445
444
|
}
|
|
446
445
|
},
|
|
447
446
|
|
|
448
|
-
|
|
447
|
+
getSchemaComponent(index) {
|
|
449
448
|
const { schemaComponents } = this
|
|
450
449
|
const { length } = schemaComponents
|
|
451
|
-
|
|
452
|
-
|
|
450
|
+
return schemaComponents[((index % length) + length) % length]
|
|
451
|
+
},
|
|
452
|
+
|
|
453
|
+
openSchemaComponent(index) {
|
|
454
|
+
const schemaComponent = this.getSchemaComponent(index)
|
|
453
455
|
if (schemaComponent) {
|
|
454
456
|
schemaComponent.opened = true
|
|
455
457
|
}
|
|
456
458
|
},
|
|
457
459
|
|
|
458
|
-
navigateToComponent(dataPath, onComplete) {
|
|
459
|
-
|
|
460
|
-
|
|
460
|
+
async navigateToComponent(dataPath, onComplete) {
|
|
461
|
+
if (this.collapsible) {
|
|
462
|
+
const index = dataPath.startsWith(this.dataPath)
|
|
463
|
+
? this.isListSource
|
|
464
|
+
? parseDataPath(dataPath.slice(this.dataPath.length + 1))[0] ?? null
|
|
465
|
+
: 0
|
|
466
|
+
: null
|
|
467
|
+
if (index !== null && isNumber(+index)) {
|
|
468
|
+
const schemaComponent = this.getSchemaComponent(+index)
|
|
469
|
+
if (schemaComponent) {
|
|
470
|
+
const { opened } = schemaComponent
|
|
471
|
+
if (!opened) {
|
|
472
|
+
schemaComponent.opened = true
|
|
473
|
+
await this.$nextTick()
|
|
474
|
+
}
|
|
475
|
+
const components = schemaComponent.getComponentsByDataPath(dataPath)
|
|
476
|
+
if (components.length > 0 && (onComplete?.(components) ?? true)) {
|
|
477
|
+
return true
|
|
478
|
+
} else {
|
|
479
|
+
schemaComponent.opened = opened
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return this.navigateToRouteComponent(dataPath, onComplete)
|
|
485
|
+
},
|
|
486
|
+
|
|
487
|
+
navigateToRouteComponent(dataPath, onComplete) {
|
|
488
|
+
return new Promise((resolve, reject) => {
|
|
489
|
+
const callOnComplete = () => {
|
|
461
490
|
// Retrieve the last route component, which will be the component that
|
|
462
491
|
// we just navigated to, and pass it on to `onComplete()`
|
|
463
492
|
const { routeComponents } = this.appState
|
|
464
|
-
|
|
493
|
+
const routeComponent = routeComponents[routeComponents.length - 1]
|
|
494
|
+
resolve(onComplete?.([routeComponent]) ?? true)
|
|
465
495
|
}
|
|
466
|
-
}
|
|
467
496
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
497
|
+
const dataPathParts = parseDataPath(dataPath)
|
|
498
|
+
// See if we can find a route that can serve part of the given dataPath,
|
|
499
|
+
// and take it from there:
|
|
500
|
+
while (dataPathParts.length > 0) {
|
|
501
|
+
const path = this.routeComponent.getChildPath(
|
|
502
|
+
this.api.normalizePath(normalizeDataPath(dataPathParts))
|
|
503
|
+
)
|
|
504
|
+
// See if there actually is a route for this sub-component:
|
|
505
|
+
const { matched } = this.$router.match(path)
|
|
506
|
+
if (matched.length) {
|
|
507
|
+
if (this.$route.path === path) {
|
|
479
508
|
// We're already there, so just call `onComplete()`:
|
|
480
|
-
|
|
481
|
-
|
|
509
|
+
callOnComplete()
|
|
510
|
+
} else {
|
|
482
511
|
// Navigate to the component's path, then call `onComplete()`_:
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
512
|
+
this.$router.push(
|
|
513
|
+
{ path },
|
|
514
|
+
// Wait for the last route component to be mounted in the next
|
|
515
|
+
// tick before calling `onComplete()`
|
|
516
|
+
() => this.$nextTick(callOnComplete),
|
|
517
|
+
reject
|
|
518
|
+
)
|
|
519
|
+
}
|
|
489
520
|
}
|
|
490
|
-
|
|
521
|
+
// Keep removing the last part until we find a match.
|
|
522
|
+
dataPathParts.pop()
|
|
491
523
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
495
|
-
return false
|
|
524
|
+
resolve(false)
|
|
525
|
+
})
|
|
496
526
|
}
|
|
497
527
|
}, // end of `methods`
|
|
498
528
|
|
package/src/mixins/TypeMixin.js
CHANGED
|
@@ -9,10 +9,6 @@ import { isString, asArray } from '@ditojs/utils'
|
|
|
9
9
|
export default {
|
|
10
10
|
mixins: [ValidationMixin],
|
|
11
11
|
|
|
12
|
-
inject: [
|
|
13
|
-
'tabComponent'
|
|
14
|
-
],
|
|
15
|
-
|
|
16
12
|
props: {
|
|
17
13
|
schema: { type: Object, required: true },
|
|
18
14
|
// NOTE: While `dataPath` points to the actual `value`, `data` represents
|
|
@@ -186,12 +182,16 @@ export default {
|
|
|
186
182
|
},
|
|
187
183
|
|
|
188
184
|
listeners() {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
185
|
+
const listeners = this.getListeners()
|
|
186
|
+
const { events = {} } = this.schema
|
|
187
|
+
if (events) {
|
|
188
|
+
// Register callbacks for all provides non-recognized events,
|
|
189
|
+
// assuming they are native events.
|
|
190
|
+
for (const event of Object.keys(events)) {
|
|
191
|
+
listeners[event] ||= () => this.emitEvent(event)
|
|
192
|
+
}
|
|
194
193
|
}
|
|
194
|
+
return listeners
|
|
195
195
|
},
|
|
196
196
|
|
|
197
197
|
validations() {
|
|
@@ -240,28 +240,43 @@ export default {
|
|
|
240
240
|
}
|
|
241
241
|
},
|
|
242
242
|
|
|
243
|
+
// @overridable
|
|
244
|
+
getListeners() {
|
|
245
|
+
return {
|
|
246
|
+
focus: this.onFocus,
|
|
247
|
+
blur: this.onBlur,
|
|
248
|
+
input: this.onInput,
|
|
249
|
+
change: this.onChange
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
|
|
243
253
|
// @overridable
|
|
244
254
|
getValidations() {
|
|
245
255
|
return null
|
|
246
256
|
},
|
|
247
257
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
this.
|
|
251
|
-
|
|
252
|
-
const [focus] = asArray(this.$refs.element)
|
|
253
|
-
if (focus) {
|
|
258
|
+
// @overridable
|
|
259
|
+
focusElement() {
|
|
260
|
+
const [element] = asArray(this.$refs.element)
|
|
261
|
+
if (element) {
|
|
254
262
|
this.$nextTick(() => {
|
|
255
|
-
|
|
263
|
+
element.focus()
|
|
256
264
|
// If the element is disabled, `focus()` will likely not have the
|
|
257
265
|
// desired effect. Use `scrollIntoView()` if available:
|
|
258
266
|
if (this.disabled) {
|
|
259
|
-
(
|
|
267
|
+
(element.$el || element).scrollIntoView?.()
|
|
260
268
|
}
|
|
261
269
|
})
|
|
262
270
|
}
|
|
263
271
|
},
|
|
264
272
|
|
|
273
|
+
focus() {
|
|
274
|
+
// Also focus this component's schema and panel in case it's a tab.
|
|
275
|
+
this.schemaComponent.focus()
|
|
276
|
+
this.tabComponent?.focus()
|
|
277
|
+
this.focusElement()
|
|
278
|
+
},
|
|
279
|
+
|
|
265
280
|
clear() {
|
|
266
281
|
this.value = null
|
|
267
282
|
this.onChange()
|
package/src/styles/_button.sass
CHANGED
package/src/types/TypeButton.vue
CHANGED
|
@@ -39,7 +39,15 @@ export default TypeComponent.register([
|
|
|
39
39
|
}
|
|
40
40
|
}),
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
closeForm: getSchemaAccessor('closeForm', {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: false
|
|
45
|
+
})
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
methods: {
|
|
49
|
+
// @override
|
|
50
|
+
getListeners() {
|
|
43
51
|
return {
|
|
44
52
|
focus: this.onFocus,
|
|
45
53
|
blur: this.onBlur,
|
|
@@ -47,13 +55,10 @@ export default TypeComponent.register([
|
|
|
47
55
|
}
|
|
48
56
|
},
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})
|
|
54
|
-
},
|
|
58
|
+
async submit(options) {
|
|
59
|
+
return this.resourceComponent?.submit(this, options)
|
|
60
|
+
},
|
|
55
61
|
|
|
56
|
-
methods: {
|
|
57
62
|
async onClick() {
|
|
58
63
|
const res = await this.emitEvent('click', {
|
|
59
64
|
parent: this.schemaComponent
|
|
@@ -65,10 +70,6 @@ export default TypeComponent.register([
|
|
|
65
70
|
) {
|
|
66
71
|
await this.submit()
|
|
67
72
|
}
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
async submit(options) {
|
|
71
|
-
return this.resourceComponent?.submit(this, options)
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
})
|