waibu-bootstrap 2.4.0 → 2.6.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/extend/waibuMpa/theme/component/widget/_lib.js +31 -21
- package/extend/waibuMpa/theme/component/widget/app-launcher.js +4 -4
- package/extend/waibuMpa/theme/component/widget/drawer.js +3 -1
- package/extend/waibuMpa/theme/component/widget/form-select-ext.js +2 -4
- package/package.json +1 -1
- package/wiki/CHANGES.md +9 -0
- package/extend/waibuMpa/theme/component/widget/form-select-country.js +0 -26
|
@@ -2,9 +2,10 @@ import { sizes } from '../method/after-build-tag/_lib.js'
|
|
|
2
2
|
|
|
3
3
|
const trueValues = ['true', 'on', 'yes', '1', 1, true]
|
|
4
4
|
|
|
5
|
-
function getInputAttr (group, formControl = true, ro) {
|
|
6
|
-
const { omit, get, set, isPlainObject, isArray, isString, has, forOwn } = this.app.lib._
|
|
5
|
+
async function getInputAttr (group, formControl = true, ro) {
|
|
6
|
+
const { omit, get, set, isPlainObject, isArray, isString, has, forOwn, find, camelCase, isEmpty } = this.app.lib._
|
|
7
7
|
const { escape } = this.app.waibu
|
|
8
|
+
const { req } = this.component
|
|
8
9
|
if (formControl) group._.class.push('form-control')
|
|
9
10
|
const attr = omit(group._, ['hint', 'label', 'wrapper'])
|
|
10
11
|
if (attr.href) {
|
|
@@ -13,7 +14,10 @@ function getInputAttr (group, formControl = true, ro) {
|
|
|
13
14
|
})
|
|
14
15
|
}
|
|
15
16
|
if (has(attr, 'name') && !has(attr, 'value') && this.component.locals.form) {
|
|
16
|
-
|
|
17
|
+
let prop = {}
|
|
18
|
+
const schema = get(this, 'component.locals.schema')
|
|
19
|
+
if (schema) prop = find(schema.properties, { name: attr.name }) ?? {}
|
|
20
|
+
attr.dataType = attr.dataType ?? prop.type ?? 'auto'
|
|
17
21
|
let val = get(this, `component.locals.form.${attr.name}`)
|
|
18
22
|
if (attr.dataType === 'boolean') {
|
|
19
23
|
val = trueValues.includes(val)
|
|
@@ -26,10 +30,16 @@ function getInputAttr (group, formControl = true, ro) {
|
|
|
26
30
|
if (attr.ref) {
|
|
27
31
|
const [ref, fieldName = 'id'] = attr.ref.split(':')
|
|
28
32
|
attr.value = get(this, `component.locals.form._ref.${ref}.${fieldName}`, val)
|
|
29
|
-
} else if (attr.dataType === 'boolean') attr.value =
|
|
30
|
-
else if (has(attr, 'name') === 'lat') attr.value = escape(
|
|
31
|
-
else if (has(attr, 'name') === 'lng') attr.value = escape(
|
|
32
|
-
else
|
|
33
|
+
} else if (attr.dataType === 'boolean') attr.value = req.t(val ? 'true' : 'false')
|
|
34
|
+
else if (has(attr, 'name') === 'lat') attr.value = escape(req.format(val, attr.dataType, { latitude: true }))
|
|
35
|
+
else if (has(attr, 'name') === 'lng') attr.value = escape(req.format(val, attr.dataType, { longitude: true }))
|
|
36
|
+
else if (prop.values) {
|
|
37
|
+
let items = prop.values
|
|
38
|
+
if (typeof prop.values === 'string') items = await this.app.bajo.callHandler(prop.values)
|
|
39
|
+
const item = find(items, { value: val }) ?? {}
|
|
40
|
+
const ttext = camelCase(`${prop.name} ${item.text}`)
|
|
41
|
+
attr.value = escape(req.format(!isEmpty(item) ? (req.te(ttext) ? req.t(ttext) : item.text) : val, attr.dataType))
|
|
42
|
+
} else attr.value = escape(req.format(val, attr.dataType))
|
|
33
43
|
} else attr.value = attr.dataValue
|
|
34
44
|
if (isArray(val)) attr.value = val.join(' ')
|
|
35
45
|
}
|
|
@@ -52,13 +62,13 @@ export async function buildFormLabel (group, tag, cls) {
|
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
export async function buildFormInput (group, params) {
|
|
55
|
-
const attr = getInputAttr.call(this, group)
|
|
65
|
+
const attr = await getInputAttr.call(this, group)
|
|
56
66
|
return await this.component.buildTag({ tag: 'input', attr, selfClosing: true })
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
export async function buildFormCheck (group, params) {
|
|
60
70
|
const { has, get } = this.app.lib._
|
|
61
|
-
const attr = getInputAttr.call(this, group, false)
|
|
71
|
+
const attr = await getInputAttr.call(this, group, false)
|
|
62
72
|
attr.type = 'checkbox'
|
|
63
73
|
attr.class.push('form-check-input')
|
|
64
74
|
if (has(attr, 'name') && !has(attr, 'value')) attr.value = 'true'
|
|
@@ -68,7 +78,7 @@ export async function buildFormCheck (group, params) {
|
|
|
68
78
|
|
|
69
79
|
export async function buildFormSwitch (group, params) {
|
|
70
80
|
const { has } = this.app.lib._
|
|
71
|
-
const attr = getInputAttr.call(this, group, false)
|
|
81
|
+
const attr = await getInputAttr.call(this, group, false)
|
|
72
82
|
attr.type = 'checkbox'
|
|
73
83
|
attr.class.push('form-check-input')
|
|
74
84
|
attr.role = 'switch'
|
|
@@ -78,14 +88,14 @@ export async function buildFormSwitch (group, params) {
|
|
|
78
88
|
}
|
|
79
89
|
|
|
80
90
|
export async function buildFormRadio (group, params) {
|
|
81
|
-
const attr = getInputAttr.call(this, group, false)
|
|
91
|
+
const attr = await getInputAttr.call(this, group, false)
|
|
82
92
|
attr.type = 'radio'
|
|
83
93
|
attr.class.push('form-check-input')
|
|
84
94
|
return await this.component.buildTag({ tag: 'input', attr, selfClosing: true })
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
export async function buildFormCheckToggle (group, params) {
|
|
88
|
-
const attr = getInputAttr.call(this, group, false)
|
|
98
|
+
const attr = await getInputAttr.call(this, group, false)
|
|
89
99
|
attr.type = 'checkbox'
|
|
90
100
|
attr.autocomplete = 'off'
|
|
91
101
|
attr.class.push('btn-check')
|
|
@@ -93,7 +103,7 @@ export async function buildFormCheckToggle (group, params) {
|
|
|
93
103
|
}
|
|
94
104
|
|
|
95
105
|
export async function buildFormRadioToggle (group, params) {
|
|
96
|
-
const attr = getInputAttr.call(this, group, false)
|
|
106
|
+
const attr = await getInputAttr.call(this, group, false)
|
|
97
107
|
attr.type = 'radio'
|
|
98
108
|
attr.autocomplete = 'off'
|
|
99
109
|
attr.class.push('btn-check')
|
|
@@ -101,7 +111,7 @@ export async function buildFormRadioToggle (group, params) {
|
|
|
101
111
|
}
|
|
102
112
|
|
|
103
113
|
export async function buildFormPlaintext (group, params) {
|
|
104
|
-
const attr = getInputAttr.call(this, group, false, true)
|
|
114
|
+
const attr = await getInputAttr.call(this, group, false, true)
|
|
105
115
|
delete attr.dataValue
|
|
106
116
|
attr.class.push('form-control-plaintext')
|
|
107
117
|
attr.readonly = ''
|
|
@@ -110,7 +120,7 @@ export async function buildFormPlaintext (group, params) {
|
|
|
110
120
|
return await this.component.buildTag({ tag: 'textarea', attr, html: attr.value })
|
|
111
121
|
}
|
|
112
122
|
if (attr.href) {
|
|
113
|
-
const content = attr.value ?
|
|
123
|
+
const content = attr.value ? attr.value : attr.href
|
|
114
124
|
const html = await this.component.buildTag({ tag: 'a', attr: { href: attr.href, content } })
|
|
115
125
|
return await this.component.buildTag({ tag: 'div', attr, html })
|
|
116
126
|
}
|
|
@@ -118,7 +128,7 @@ export async function buildFormPlaintext (group, params) {
|
|
|
118
128
|
}
|
|
119
129
|
|
|
120
130
|
export async function buildFormColor (group, params) {
|
|
121
|
-
const attr = getInputAttr.call(this, group)
|
|
131
|
+
const attr = await getInputAttr.call(this, group)
|
|
122
132
|
attr.class.push('form-control-color')
|
|
123
133
|
attr.type = 'color'
|
|
124
134
|
if (!attr.dim) attr.dim = 'width:100'
|
|
@@ -126,13 +136,13 @@ export async function buildFormColor (group, params) {
|
|
|
126
136
|
}
|
|
127
137
|
|
|
128
138
|
export async function buildFormFile (group, params) {
|
|
129
|
-
const attr = getInputAttr.call(this, group)
|
|
139
|
+
const attr = await getInputAttr.call(this, group)
|
|
130
140
|
attr.type = 'file'
|
|
131
141
|
return await this.component.buildTag({ tag: 'input', attr, selfClosing: true })
|
|
132
142
|
}
|
|
133
143
|
|
|
134
144
|
export async function buildFormTextarea (group, params) {
|
|
135
|
-
const attr = getInputAttr.call(this, group)
|
|
145
|
+
const attr = await getInputAttr.call(this, group)
|
|
136
146
|
params.html = attr.value
|
|
137
147
|
attr.style.minHeight = '100px'
|
|
138
148
|
delete attr.value
|
|
@@ -142,12 +152,12 @@ export async function buildFormTextarea (group, params) {
|
|
|
142
152
|
export async function buildFormSelect (group, params) {
|
|
143
153
|
const { omit, trim } = this.app.lib._
|
|
144
154
|
const { $ } = this.component
|
|
145
|
-
let attr = getInputAttr.call(this, group, false)
|
|
155
|
+
let attr = await getInputAttr.call(this, group, false)
|
|
146
156
|
attr.value = attr.value + ''
|
|
147
157
|
attr.class.push('form-select')
|
|
148
158
|
let html = params.html
|
|
149
159
|
if (sizes.includes(attr.size)) attr.class.push(`form-select-${attr.size}`)
|
|
150
|
-
if (attr.options) html = this.component.buildOptions({ attr })
|
|
160
|
+
if (attr.options) html = await this.component.buildOptions({ attr })
|
|
151
161
|
else {
|
|
152
162
|
const items = []
|
|
153
163
|
$(`<div>${trim(html ?? '')}</div>`).find('option').each(function () {
|
|
@@ -160,7 +170,7 @@ export async function buildFormSelect (group, params) {
|
|
|
160
170
|
}
|
|
161
171
|
|
|
162
172
|
export async function buildFormRange (group, params) {
|
|
163
|
-
const attr = getInputAttr.call(this, group, false)
|
|
173
|
+
const attr = await getInputAttr.call(this, group, false)
|
|
164
174
|
attr.type = 'range'
|
|
165
175
|
attr.class.push('form-range')
|
|
166
176
|
return await this.component.buildTag({ tag: 'input', attr, selfClosing: true })
|
|
@@ -9,8 +9,7 @@ async function appLauncher () {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
build = async () => {
|
|
12
|
-
const {
|
|
13
|
-
const { routePath, attrToArray } = this.app.waibu
|
|
12
|
+
const { attrToArray } = this.app.waibu
|
|
14
13
|
const { groupAttrs } = this.app.waibuMpa
|
|
15
14
|
const menu = this.params.attr.menu ?? 'pages'
|
|
16
15
|
const group = groupAttrs(this.params.attr, ['trigger'])
|
|
@@ -21,10 +20,11 @@ async function appLauncher () {
|
|
|
21
20
|
if (menu === 'pages') toolbar.unshift('home')
|
|
22
21
|
launcher += `<c:div padding="x-3 ${menu === 'home' ? 'bottom-3' : ''}">`
|
|
23
22
|
launcher += '<c:navbar padding="y-0"><c:nav tag="ul">\n'
|
|
24
|
-
if (locals._meta.isAdmin) launcher += '<c:nav-item text="color:danger" href="' + routePath('waibuAdmin:/') + '" icon="lock" padding="start-0" />\n'
|
|
25
|
-
launcher += '</c:nav>\n<c:nav tag="ul">\n'
|
|
26
23
|
for (const t of toolbar) {
|
|
27
24
|
if (t === 'home') launcher += '<c:nav-item href="/" icon="house" padding="end-2" />\n'
|
|
25
|
+
}
|
|
26
|
+
launcher += '</c:nav>\n<c:nav tag="ul">\n'
|
|
27
|
+
for (const t of toolbar) {
|
|
28
28
|
if (t === 'user' && this.app.sumba) launcher += '<c:sumba-nav-dropdown-user padding="end-2" />\n'
|
|
29
29
|
if (t === '-') launcher += '<c:nav-divider />\n'
|
|
30
30
|
if (t === 'fullscreen') launcher += '<c:nav-toggle-fullscreen padding="end-2" />\n'
|
|
@@ -12,7 +12,8 @@ async function drawer () {
|
|
|
12
12
|
build = async () => {
|
|
13
13
|
const { isString, omit, trim } = this.app.lib._
|
|
14
14
|
const { groupAttrs } = this.app.waibuMpa
|
|
15
|
-
const {
|
|
15
|
+
const { $, req, locals } = this.component
|
|
16
|
+
const { routePath } = this.app.waibu
|
|
16
17
|
const group = groupAttrs(this.params.attr, ['trigger'])
|
|
17
18
|
this.params.attr.responsive = this.params.attr.responsive ?? true
|
|
18
19
|
this.params.attr.class.push(parseVariant.call(this, { cls, value: this.params.attr.responsive, values: breakpoints }))
|
|
@@ -22,6 +23,7 @@ async function drawer () {
|
|
|
22
23
|
if (this.params.attr.scroll) this.params.attr.dataBsScroll = 'true'
|
|
23
24
|
if (this.params.attr.noDismiss) this.params.attr.dataBsBackdrop = 'static'
|
|
24
25
|
const buttons = []
|
|
26
|
+
if (locals._meta.isAdmin) buttons.push(await this.component.buildTag({ tag: 'btn', attr: { href: routePath('waibuAdmin:/'), icon: 'lock', text: 'color:danger', tooltip: req.t('adminArea') } }))
|
|
25
27
|
const html = []
|
|
26
28
|
$(`<div>${this.params.html}</div>`).children().each(function () {
|
|
27
29
|
if (this.name === 'drawer-toolbar') buttons.push(trim($(this).prop('innerHTML')))
|
|
@@ -36,9 +36,7 @@ async function formSelectExt () {
|
|
|
36
36
|
try {
|
|
37
37
|
options = base64JsonDecode(this.params.attr.options)
|
|
38
38
|
} catch (err) {
|
|
39
|
-
options = this.params.attr.options
|
|
40
|
-
return { value: item, text: item }
|
|
41
|
-
})
|
|
39
|
+
options = this.params.attr.options
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
let opts = { plugins }
|
|
@@ -132,7 +130,7 @@ async function formSelectExt () {
|
|
|
132
130
|
this.params.attr['x-data'] = `{ ${xData.join(',\n')} }`
|
|
133
131
|
// this.params.attr['@load.window'] = 'onLoad()'
|
|
134
132
|
this.params.attr['x-init'] = 'onLoad()'
|
|
135
|
-
this.params.attr.options = options
|
|
133
|
+
if (options.length > 0) this.params.attr.options = options
|
|
136
134
|
this.params.attr = omit(this.params.attr, ['noDropdownInput', 'removeBtn', 'clearBtn', 'c-opts', 'remoteUrl', 'remoteSearchField', 'remoteLabelField', 'remoteValueField'])
|
|
137
135
|
await build.call(this, buildFormSelect, this.params)
|
|
138
136
|
}
|
package/package.json
CHANGED
package/wiki/CHANGES.md
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-02-20
|
|
4
|
+
|
|
5
|
+
- [2.6.0] Change ```getInputAttr()``` to async function
|
|
6
|
+
- [2.6.0] Update to support a function handler as ```prop.values```
|
|
7
|
+
- [2.6.0] Add button to admin area in ```Drawer``` if user is an admin
|
|
8
|
+
|
|
3
9
|
## 2026-02-18
|
|
4
10
|
|
|
5
11
|
- [2.4.0] Update attribute functions from ```waibu```
|
|
6
12
|
- [2.4.0] Bug fix on ```FormSelectExt``` 's static css
|
|
7
13
|
- [2.4.0] Bug fix on ```FormSelectCountry``` 's static css
|
|
14
|
+
- [2.5.0] Remove ```FormSelectCountry``` alltogther
|
|
15
|
+
- [2.5.0] Bug fix on ```FormSelectExt```'s options
|
|
16
|
+
- [2.5.0] In read only mode, auto detect value from model's values
|
|
8
17
|
|
|
9
18
|
## 2026-02-15
|
|
10
19
|
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { css, scripts } from './form-select-ext.js'
|
|
2
|
-
|
|
3
|
-
async function formSelectCountry () {
|
|
4
|
-
return class FormSelectCountry extends this.app.baseClass.MpaWidget {
|
|
5
|
-
static css = [...super.css, ...css]
|
|
6
|
-
static scripts = [...super.scripts, scripts]
|
|
7
|
-
|
|
8
|
-
constructor (options) {
|
|
9
|
-
super(options)
|
|
10
|
-
this.params.noTag = true
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
build = async () => {
|
|
14
|
-
const { readConfig } = this.app.bajo
|
|
15
|
-
const { map } = this.app.lib._
|
|
16
|
-
const { base64JsonEncode } = this.app.waibu
|
|
17
|
-
const countries = await readConfig('bajoCommonDb:/extend/dobo/fixture/country.json', { ignoreError: true, defValue: [] })
|
|
18
|
-
this.params.attr.options = base64JsonEncode(map(countries, c => {
|
|
19
|
-
return { value: c.id, text: c.name.replaceAll('\'', '') }
|
|
20
|
-
}))
|
|
21
|
-
this.params.html = await this.component.buildTag({ tag: 'formSelectExt', attr: this.params.attr, html: '' })
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default formSelectCountry
|