@radio-garden/ditojs-admin 2.85.2-0.5067ad799
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 +180 -0
- package/dist/dito-admin.css +1 -0
- package/dist/dito-admin.es.js +12106 -0
- package/dist/dito-admin.umd.js +7 -0
- package/package.json +96 -0
- package/src/DitoAdmin.js +293 -0
- package/src/DitoComponent.js +34 -0
- package/src/DitoContext.js +318 -0
- package/src/DitoTypeComponent.js +42 -0
- package/src/DitoUser.js +12 -0
- package/src/appState.js +12 -0
- package/src/components/DitoAccount.vue +60 -0
- package/src/components/DitoAffix.vue +68 -0
- package/src/components/DitoAffixes.vue +200 -0
- package/src/components/DitoButtons.vue +80 -0
- package/src/components/DitoClipboard.vue +186 -0
- package/src/components/DitoContainer.vue +374 -0
- package/src/components/DitoCreateButton.vue +146 -0
- package/src/components/DitoDialog.vue +242 -0
- package/src/components/DitoDraggable.vue +117 -0
- package/src/components/DitoEditButtons.vue +135 -0
- package/src/components/DitoErrors.vue +83 -0
- package/src/components/DitoForm.vue +521 -0
- package/src/components/DitoFormInner.vue +26 -0
- package/src/components/DitoFormNested.vue +17 -0
- package/src/components/DitoHeader.vue +84 -0
- package/src/components/DitoLabel.vue +200 -0
- package/src/components/DitoMenu.vue +186 -0
- package/src/components/DitoNavigation.vue +40 -0
- package/src/components/DitoNotifications.vue +170 -0
- package/src/components/DitoPagination.vue +42 -0
- package/src/components/DitoPane.vue +334 -0
- package/src/components/DitoPanel.vue +256 -0
- package/src/components/DitoPanels.vue +61 -0
- package/src/components/DitoRoot.vue +524 -0
- package/src/components/DitoSchema.vue +846 -0
- package/src/components/DitoSchemaInlined.vue +97 -0
- package/src/components/DitoScopes.vue +76 -0
- package/src/components/DitoSidebar.vue +50 -0
- package/src/components/DitoSpinner.vue +95 -0
- package/src/components/DitoTableCell.vue +64 -0
- package/src/components/DitoTableHead.vue +121 -0
- package/src/components/DitoTabs.vue +103 -0
- package/src/components/DitoTrail.vue +124 -0
- package/src/components/DitoTreeItem.vue +420 -0
- package/src/components/DitoUploadFile.vue +199 -0
- package/src/components/DitoVNode.vue +14 -0
- package/src/components/DitoView.vue +143 -0
- package/src/components/index.js +42 -0
- package/src/directives/resize.js +83 -0
- package/src/index.js +1 -0
- package/src/mixins/ContextMixin.js +68 -0
- package/src/mixins/DataMixin.js +131 -0
- package/src/mixins/DitoMixin.js +591 -0
- package/src/mixins/DomMixin.js +29 -0
- package/src/mixins/EmitterMixin.js +158 -0
- package/src/mixins/ItemMixin.js +144 -0
- package/src/mixins/LoadingMixin.js +23 -0
- package/src/mixins/NumberMixin.js +118 -0
- package/src/mixins/OptionsMixin.js +304 -0
- package/src/mixins/PulldownMixin.js +63 -0
- package/src/mixins/ResourceMixin.js +398 -0
- package/src/mixins/RouteMixin.js +190 -0
- package/src/mixins/SchemaParentMixin.js +33 -0
- package/src/mixins/SortableMixin.js +49 -0
- package/src/mixins/SourceMixin.js +734 -0
- package/src/mixins/TextMixin.js +26 -0
- package/src/mixins/TypeMixin.js +280 -0
- package/src/mixins/ValidationMixin.js +119 -0
- package/src/mixins/ValidatorMixin.js +57 -0
- package/src/mixins/ValueMixin.js +31 -0
- package/src/styles/_base.scss +17 -0
- package/src/styles/_button.scss +191 -0
- package/src/styles/_imports.scss +3 -0
- package/src/styles/_info.scss +19 -0
- package/src/styles/_layout.scss +19 -0
- package/src/styles/_pulldown.scss +38 -0
- package/src/styles/_scroll.scss +13 -0
- package/src/styles/_settings.scss +88 -0
- package/src/styles/_table.scss +223 -0
- package/src/styles/_tippy.scss +45 -0
- package/src/styles/style.scss +9 -0
- package/src/types/DitoTypeButton.vue +143 -0
- package/src/types/DitoTypeCheckbox.vue +27 -0
- package/src/types/DitoTypeCheckboxes.vue +65 -0
- package/src/types/DitoTypeCode.vue +199 -0
- package/src/types/DitoTypeColor.vue +272 -0
- package/src/types/DitoTypeComponent.vue +31 -0
- package/src/types/DitoTypeComputed.vue +50 -0
- package/src/types/DitoTypeDate.vue +99 -0
- package/src/types/DitoTypeLabel.vue +23 -0
- package/src/types/DitoTypeList.vue +364 -0
- package/src/types/DitoTypeMarkup.vue +700 -0
- package/src/types/DitoTypeMultiselect.vue +522 -0
- package/src/types/DitoTypeNumber.vue +66 -0
- package/src/types/DitoTypeObject.vue +136 -0
- package/src/types/DitoTypePanel.vue +18 -0
- package/src/types/DitoTypeProgress.vue +40 -0
- package/src/types/DitoTypeRadio.vue +45 -0
- package/src/types/DitoTypeSection.vue +80 -0
- package/src/types/DitoTypeSelect.vue +133 -0
- package/src/types/DitoTypeSlider.vue +66 -0
- package/src/types/DitoTypeSpacer.vue +11 -0
- package/src/types/DitoTypeSwitch.vue +40 -0
- package/src/types/DitoTypeText.vue +101 -0
- package/src/types/DitoTypeTextarea.vue +48 -0
- package/src/types/DitoTypeTreeList.vue +193 -0
- package/src/types/DitoTypeUpload.vue +503 -0
- package/src/types/index.js +30 -0
- package/src/utils/SchemaGraph.js +147 -0
- package/src/utils/accessor.js +75 -0
- package/src/utils/agent.js +47 -0
- package/src/utils/data.js +92 -0
- package/src/utils/filter.js +266 -0
- package/src/utils/math.js +14 -0
- package/src/utils/options.js +48 -0
- package/src/utils/path.js +5 -0
- package/src/utils/resource.js +44 -0
- package/src/utils/route.js +53 -0
- package/src/utils/schema.js +1121 -0
- package/src/utils/type.js +81 -0
- package/src/utils/uid.js +15 -0
- package/src/utils/units.js +5 -0
- package/src/validators/_creditcard.js +6 -0
- package/src/validators/_decimals.js +11 -0
- package/src/validators/_domain.js +6 -0
- package/src/validators/_email.js +6 -0
- package/src/validators/_hostname.js +6 -0
- package/src/validators/_integer.js +6 -0
- package/src/validators/_max.js +6 -0
- package/src/validators/_min.js +6 -0
- package/src/validators/_password.js +5 -0
- package/src/validators/_range.js +6 -0
- package/src/validators/_required.js +9 -0
- package/src/validators/_url.js +6 -0
- package/src/validators/index.js +12 -0
- package/src/verbs.js +17 -0
- package/types/index.d.ts +3298 -0
- package/types/tests/admin.test-d.ts +27 -0
- package/types/tests/component-buttons.test-d.ts +44 -0
- package/types/tests/component-list.test-d.ts +159 -0
- package/types/tests/component-misc.test-d.ts +137 -0
- package/types/tests/component-object.test-d.ts +69 -0
- package/types/tests/component-section.test-d.ts +174 -0
- package/types/tests/component-select.test-d.ts +107 -0
- package/types/tests/components.test-d.ts +81 -0
- package/types/tests/context.test-d.ts +31 -0
- package/types/tests/fixtures.ts +24 -0
- package/types/tests/form.test-d.ts +109 -0
- package/types/tests/instance.test-d.ts +20 -0
- package/types/tests/schema-features.test-d.ts +402 -0
- package/types/tests/variance.test-d.ts +125 -0
- package/types/tests/view.test-d.ts +146 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { isArray, isPlainObject } from '@ditojs/utils'
|
|
2
|
+
|
|
3
|
+
// @vue/component
|
|
4
|
+
export default {
|
|
5
|
+
data() {
|
|
6
|
+
return {
|
|
7
|
+
listeners: null
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
methods: {
|
|
12
|
+
// Async on() and $off() methods that keep track of the events added /
|
|
13
|
+
// removed, and provide a hasListeners() method that checks if the component
|
|
14
|
+
// has listeners for a given event.
|
|
15
|
+
|
|
16
|
+
// Also adds proper handling of async events, including a async emit() that
|
|
17
|
+
// deals with proper event queueing.
|
|
18
|
+
on(event, callback) {
|
|
19
|
+
if (isArray(event)) {
|
|
20
|
+
for (const ev of event) {
|
|
21
|
+
this.on(ev, callback)
|
|
22
|
+
}
|
|
23
|
+
} else if (isPlainObject(event)) {
|
|
24
|
+
for (const key in event) {
|
|
25
|
+
this.on(key, event[key])
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
const listeners = (this.listeners ||= Object.create(null))
|
|
29
|
+
const { callbacks } = (listeners[event] ||= {
|
|
30
|
+
callbacks: [],
|
|
31
|
+
queue: []
|
|
32
|
+
})
|
|
33
|
+
callbacks.push(callback)
|
|
34
|
+
}
|
|
35
|
+
return this
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
once(event, callback) {
|
|
39
|
+
const on = (...args) => {
|
|
40
|
+
this.off(event, on)
|
|
41
|
+
return callback.apply(this, args)
|
|
42
|
+
}
|
|
43
|
+
on.callback = callback // Needed for `off()`, see below.
|
|
44
|
+
return this.on(event, on)
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
off(event, callback) {
|
|
48
|
+
if (!arguments.length) {
|
|
49
|
+
// Remove all events
|
|
50
|
+
delete this.listeners
|
|
51
|
+
} else if (isArray(event)) {
|
|
52
|
+
for (const ev of event) {
|
|
53
|
+
this.off(ev, callback)
|
|
54
|
+
}
|
|
55
|
+
} else if (isPlainObject(event)) {
|
|
56
|
+
for (const key in event) {
|
|
57
|
+
this.off(key, event[key])
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
// Remove specific event
|
|
61
|
+
const entry = this.listeners?.[event]
|
|
62
|
+
if (entry) {
|
|
63
|
+
if (!callback) {
|
|
64
|
+
// Remove all handlers for this event
|
|
65
|
+
delete this.listeners[event]
|
|
66
|
+
} else {
|
|
67
|
+
// Remove a specific handler: find the index in callbacks
|
|
68
|
+
const { callbacks } = entry
|
|
69
|
+
const index = callbacks.findIndex(
|
|
70
|
+
// Match `cb.callback` also, as used by `once()`, see above:
|
|
71
|
+
cb => cb === callback || cb.callback === callback
|
|
72
|
+
)
|
|
73
|
+
if (index !== -1) {
|
|
74
|
+
callbacks.splice(index, 1)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return this
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
emit(event, ...args) {
|
|
83
|
+
// Only queue event if there actually are listeners for it.
|
|
84
|
+
const entry = this.listeners?.[event]
|
|
85
|
+
if (entry) {
|
|
86
|
+
const { queue, callbacks } = entry
|
|
87
|
+
return new Promise(resolve => {
|
|
88
|
+
const next = async () => {
|
|
89
|
+
// Emit the next event in the queue with its params.
|
|
90
|
+
// Note that it only gets removed once `next()` is called.
|
|
91
|
+
const entry = queue.shift()
|
|
92
|
+
if (entry) {
|
|
93
|
+
let result
|
|
94
|
+
const errors = []
|
|
95
|
+
for (const callback of callbacks) {
|
|
96
|
+
try {
|
|
97
|
+
const res = await callback.apply(this, entry.args)
|
|
98
|
+
if (res !== undefined) {
|
|
99
|
+
result = res
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
errors.push(error)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (errors.length > 0) {
|
|
106
|
+
const error = new AggregateError(
|
|
107
|
+
errors,
|
|
108
|
+
`Errors during event handler for '${event}'`
|
|
109
|
+
)
|
|
110
|
+
entry.resolve(Promise.reject(error))
|
|
111
|
+
} else {
|
|
112
|
+
// Resolve the promise that was added to the queue for the event
|
|
113
|
+
// that was just completed by the wrapper that called `next()`
|
|
114
|
+
entry.resolve(result)
|
|
115
|
+
}
|
|
116
|
+
next()
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
queue.push({ args, resolve })
|
|
120
|
+
// For new queues (= only one entry) emit the first event immediately,
|
|
121
|
+
// to get the queue running.
|
|
122
|
+
if (queue.length === 1) {
|
|
123
|
+
next()
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
// Make sure it's thenable even if there are no listeners.
|
|
128
|
+
return Promise.resolve()
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
// Checks if the component has listeners for a given event type:
|
|
132
|
+
hasListeners(event) {
|
|
133
|
+
if (isArray(event)) {
|
|
134
|
+
for (const ev of event) {
|
|
135
|
+
if (!this.hasListeners(ev)) {
|
|
136
|
+
return false
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return event.length > 0
|
|
140
|
+
} else {
|
|
141
|
+
return !!this.listeners?.[event]
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
delegate(event, target) {
|
|
146
|
+
if (target) {
|
|
147
|
+
if (isArray(event)) {
|
|
148
|
+
for (const ev of event) {
|
|
149
|
+
this.delegate(ev, target)
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
this.on(event, (...args) => target.emit(event, ...args))
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return this
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import DitoContext from '../DitoContext.js'
|
|
2
|
+
import {
|
|
3
|
+
getItemFormSchema,
|
|
4
|
+
getItemId,
|
|
5
|
+
getItemUid,
|
|
6
|
+
isListSource
|
|
7
|
+
} from '../utils/schema.js'
|
|
8
|
+
import { appendDataPath } from '../utils/data.js'
|
|
9
|
+
import { isObject, isString, isFunction } from '@ditojs/utils'
|
|
10
|
+
|
|
11
|
+
// @vue/component
|
|
12
|
+
export default {
|
|
13
|
+
methods: {
|
|
14
|
+
getItemFormSchema,
|
|
15
|
+
|
|
16
|
+
getItemUid,
|
|
17
|
+
|
|
18
|
+
getItemId(sourceSchema, item, index = null) {
|
|
19
|
+
return this.isTransient && index !== null
|
|
20
|
+
? String(index)
|
|
21
|
+
: getItemId(sourceSchema, item)
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
getItemDataPath(sourceSchema, index) {
|
|
25
|
+
let { dataPath } = this
|
|
26
|
+
if (sourceSchema !== this.schema) {
|
|
27
|
+
dataPath = appendDataPath(dataPath, sourceSchema.name)
|
|
28
|
+
}
|
|
29
|
+
if (index != null) {
|
|
30
|
+
dataPath = appendDataPath(dataPath, index)
|
|
31
|
+
}
|
|
32
|
+
return dataPath
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
getItemStore(sourceSchema, item, index) {
|
|
36
|
+
return this.getChildStore(this.getItemUid(sourceSchema, item), index)
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
removeItemStore(sourceSchema, item, index) {
|
|
40
|
+
this.removeChildStore(this.getItemUid(sourceSchema, item), index)
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
findItemIdIndex(sourceSchema, data, itemId) {
|
|
44
|
+
const index = this.isTransient
|
|
45
|
+
? // For transient data, the index is used as the id
|
|
46
|
+
itemId
|
|
47
|
+
: data?.findIndex(
|
|
48
|
+
(item, index) => (
|
|
49
|
+
this.getItemId(sourceSchema, item, index) === itemId
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
return index !== -1 ? index : null
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
getItemLabel(sourceSchema, item, {
|
|
56
|
+
index = null,
|
|
57
|
+
extended = false,
|
|
58
|
+
asObject = false
|
|
59
|
+
} = {}) {
|
|
60
|
+
const { itemLabel } = sourceSchema
|
|
61
|
+
if (!item || !extended && itemLabel === false) {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let dataPath
|
|
66
|
+
const getDataPath = () =>
|
|
67
|
+
(dataPath ??= this.getItemDataPath(sourceSchema, index))
|
|
68
|
+
|
|
69
|
+
let formLabel
|
|
70
|
+
const getFormLabel = () =>
|
|
71
|
+
(formLabel ??= this.getLabel(
|
|
72
|
+
getItemFormSchema(sourceSchema, item, this.context)
|
|
73
|
+
))
|
|
74
|
+
|
|
75
|
+
let text
|
|
76
|
+
let prefix
|
|
77
|
+
let suffix
|
|
78
|
+
if (isFunction(itemLabel)) {
|
|
79
|
+
const label = itemLabel.call(
|
|
80
|
+
this,
|
|
81
|
+
new DitoContext(this, {
|
|
82
|
+
nested: false,
|
|
83
|
+
data: item,
|
|
84
|
+
value: item,
|
|
85
|
+
index,
|
|
86
|
+
|
|
87
|
+
get dataPath() {
|
|
88
|
+
return getDataPath()
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
get formLabel() {
|
|
92
|
+
return getFormLabel()
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
)
|
|
96
|
+
if (isObject(label)) {
|
|
97
|
+
;({ text, prefix, suffix } = label)
|
|
98
|
+
} else {
|
|
99
|
+
text = label
|
|
100
|
+
}
|
|
101
|
+
// It's up to `itemLabel()` entirely to produce the label:
|
|
102
|
+
extended = false
|
|
103
|
+
} else if (isString(itemLabel) && !(itemLabel in item)) {
|
|
104
|
+
// `itemLabel` can be both a key, or simply a label.
|
|
105
|
+
text = itemLabel
|
|
106
|
+
} else {
|
|
107
|
+
// Look up the name on the item, by these rules:
|
|
108
|
+
// 1. If `itemLabel` is a string, use it as the property key
|
|
109
|
+
// 2. Otherwise, if there are columns, use the value of the first
|
|
110
|
+
// 3. Otherwise, see if the item has a property named 'name'
|
|
111
|
+
const { columns } = sourceSchema
|
|
112
|
+
const key = (
|
|
113
|
+
isString(itemLabel) && itemLabel ||
|
|
114
|
+
isListSource(sourceSchema) && columns && Object.keys(columns)[0] ||
|
|
115
|
+
'name'
|
|
116
|
+
)
|
|
117
|
+
text = item[key]
|
|
118
|
+
}
|
|
119
|
+
const hadLabel = !!text
|
|
120
|
+
// If no label was found so far, try to produce one from the index.
|
|
121
|
+
if (text == null) {
|
|
122
|
+
// Always use extended style when auto-generating labels from index/id:
|
|
123
|
+
extended = true
|
|
124
|
+
text =
|
|
125
|
+
isListSource(sourceSchema) && index !== null
|
|
126
|
+
? (text = `${index + 1}`)
|
|
127
|
+
: ''
|
|
128
|
+
}
|
|
129
|
+
if (extended) {
|
|
130
|
+
const formLabel = getFormLabel()
|
|
131
|
+
if (formLabel) {
|
|
132
|
+
// If a label was provided, put in quotes when prefixed with the
|
|
133
|
+
// form label for the extended style:
|
|
134
|
+
text = `${formLabel} ${hadLabel ? `'${text}'` : text}`
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return asObject
|
|
138
|
+
? text || prefix || suffix
|
|
139
|
+
? { text, prefix, suffix }
|
|
140
|
+
: null
|
|
141
|
+
: text
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @vue/component
|
|
2
|
+
export default {
|
|
3
|
+
data() {
|
|
4
|
+
return {
|
|
5
|
+
isLoading: false
|
|
6
|
+
}
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
methods: {
|
|
10
|
+
setLoading(isLoading, { updateRoot = false, updateView = false } = {}) {
|
|
11
|
+
if (!this.isLoading ^ !isLoading) {
|
|
12
|
+
// Boolean xor
|
|
13
|
+
this.isLoading = !!isLoading
|
|
14
|
+
if (updateRoot) {
|
|
15
|
+
this.rootComponent.registerLoading(isLoading)
|
|
16
|
+
}
|
|
17
|
+
if (updateView) {
|
|
18
|
+
this.viewComponent.setLoading(this.isLoading)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
2
|
+
import { isArray } from '@ditojs/utils'
|
|
3
|
+
|
|
4
|
+
// @vue/component
|
|
5
|
+
export default {
|
|
6
|
+
computed: {
|
|
7
|
+
inputValue: {
|
|
8
|
+
get() {
|
|
9
|
+
return this.value !== null ? this.value : ''
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
set(value) {
|
|
13
|
+
this.value =
|
|
14
|
+
value !== ''
|
|
15
|
+
? this.isInteger
|
|
16
|
+
? Number(value)
|
|
17
|
+
: parseFloat(value)
|
|
18
|
+
: null
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
// @overridable
|
|
23
|
+
isInteger() {
|
|
24
|
+
return false
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
stepValue() {
|
|
28
|
+
// Don't show steps if the input is also clearable, since the step buttons
|
|
29
|
+
// would collide with the clear button.
|
|
30
|
+
return this.step == null && !this.isInteger
|
|
31
|
+
? 'any'
|
|
32
|
+
: this.step
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
decimals: getSchemaAccessor('decimals', {
|
|
36
|
+
type: Number
|
|
37
|
+
}),
|
|
38
|
+
|
|
39
|
+
step: getSchemaAccessor('step', {
|
|
40
|
+
type: Number,
|
|
41
|
+
get(step) {
|
|
42
|
+
// For integers, round the steps to the next bigger integer value:
|
|
43
|
+
return this.isInteger && step != null ? Math.ceil(step) : step
|
|
44
|
+
}
|
|
45
|
+
}),
|
|
46
|
+
|
|
47
|
+
min: getSchemaAccessor('min', {
|
|
48
|
+
type: Number,
|
|
49
|
+
get(min) {
|
|
50
|
+
min =
|
|
51
|
+
min === undefined
|
|
52
|
+
? this.getSchemaValue('range', { type: Array })?.[0]
|
|
53
|
+
: min
|
|
54
|
+
return this.isInteger && min != null ? Math.floor(min) : min
|
|
55
|
+
}
|
|
56
|
+
}),
|
|
57
|
+
|
|
58
|
+
max: getSchemaAccessor('max', {
|
|
59
|
+
type: Number,
|
|
60
|
+
get(max) {
|
|
61
|
+
max =
|
|
62
|
+
max === undefined
|
|
63
|
+
? this.getSchemaValue('range', { type: Array })?.[1]
|
|
64
|
+
: max
|
|
65
|
+
return this.isInteger && max != null ? Math.ceil(max) : max
|
|
66
|
+
}
|
|
67
|
+
}),
|
|
68
|
+
|
|
69
|
+
range: getSchemaAccessor('range', {
|
|
70
|
+
type: Array,
|
|
71
|
+
get() {
|
|
72
|
+
// `this.min`, `this.max` already support `schema.range`,
|
|
73
|
+
// so redirect there.
|
|
74
|
+
const { min, max } = this
|
|
75
|
+
return min != null && max != null ? [min, max] : undefined
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
set(range) {
|
|
79
|
+
// Provide a setter that delegates to `[this.min, this.max]`,
|
|
80
|
+
// since those already handle `schema.range`.
|
|
81
|
+
if (isArray(range)) {
|
|
82
|
+
;[this.min, this.max] = range
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
methods: {
|
|
89
|
+
getValidations() {
|
|
90
|
+
const validations = {}
|
|
91
|
+
const { range, min, max, decimals, step } = this
|
|
92
|
+
if (range) {
|
|
93
|
+
validations.range = range
|
|
94
|
+
} else {
|
|
95
|
+
if (min != null) {
|
|
96
|
+
validations.min = min
|
|
97
|
+
}
|
|
98
|
+
if (max != null) {
|
|
99
|
+
validations.max = max
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (decimals != null) {
|
|
103
|
+
validations.decimals = decimals
|
|
104
|
+
} else if (step) {
|
|
105
|
+
const decimals = (`${step}`.split('.')[1] || '').length
|
|
106
|
+
if (decimals > 0) {
|
|
107
|
+
validations.decimals = decimals
|
|
108
|
+
} else {
|
|
109
|
+
validations.integer = true
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (this.isInteger) {
|
|
113
|
+
validations.integer = true
|
|
114
|
+
}
|
|
115
|
+
return validations
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|