waibu-db 1.1.10 → 1.1.12

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.
@@ -1,5 +1,4 @@
1
- <c:form>
2
- <!-- include waibuDb.partial:/crud/_form.html -->
1
+ <c:wdb-form id="main-form" method="POST" enctype="multipart/form-data">
3
2
  <!-- include waibuDb.partial:/crud/_add-btns.html -->
4
- </c:form>
3
+ </c:wdb-form>
5
4
  <!-- include waibuDb.partial:/crud/_addons.html -->
@@ -1,5 +1,3 @@
1
- <c:div id="main-form">
2
- <!-- include waibuDb.partial:/crud/_form.html -->
3
- </c:div>
1
+ <c:wdb-form tag="div" id="main-form" />
4
2
  <!-- include waibuDb.partial:/crud/_details-btns.html -->
5
3
  <!-- include waibuDb.partial:/crud/_addons.html -->
@@ -1,5 +1,4 @@
1
- <c:form id="main-form">
2
- <!-- include waibuDb.partial:/crud/_form.html -->
1
+ <c:wdb-form id="main-form" method="POST" enctype="multipart/form-data">
3
2
  <!-- include waibuDb.partial:/crud/_edit-btns.html -->
4
- </c:form>
3
+ </c:wdb-form>
5
4
  <!-- include waibuDb.partial:/crud/_addons.html -->
@@ -5,7 +5,7 @@ async function addHandler ({ req, reply, model, params = {}, template, addOnsHan
5
5
  const { pick, map, merge, defaultsDeep, omit, isEmpty } = this.lib._
6
6
  const options = {}
7
7
  model = model ?? pascalCase(req.params.model)
8
- const { schema } = await getSchemaExt(model, 'add', options)
8
+ const { schema } = await getSchemaExt(model, 'add', { params })
9
9
  if (schema.disabled.includes('create')) return reply.view(templateDisabled, { action: 'add' })
10
10
  // req.query.attachment = true
11
11
  options.fields = schema.view.fields
@@ -5,7 +5,7 @@ async function deleteHandler ({ req, reply, model, params = {}, templateDisabled
5
5
  const { reduce } = this.lib._
6
6
  const options = {}
7
7
  model = model ?? pascalCase(req.params.model)
8
- const { schema } = await getSchemaExt(model, 'add', options)
8
+ const { schema } = await getSchemaExt(model, 'add', { params })
9
9
  if (schema.disabled.includes('remove')) return reply.view(templateDisabled, { action: 'delete' })
10
10
  options.fields = schema.view.fields
11
11
  const ids = (req.body.ids ?? '').split(',')
@@ -4,7 +4,7 @@ async function detailsHandler ({ req, reply, model, params = {}, template, addOn
4
4
  const { merge } = this.lib._
5
5
  const options = {}
6
6
  model = model ?? pascalCase(req.params.model)
7
- const { schema } = await getSchemaExt(model, 'details', options)
7
+ const { schema } = await getSchemaExt(model, 'details', { params })
8
8
  if (schema.disabled.includes('get')) return reply.view(templateDisabled, { action: 'details' })
9
9
  // req.query.attachment = true
10
10
  options.fields = schema.view.fields
@@ -5,7 +5,7 @@ async function editHandler ({ req, reply, model, params = {}, template, addOnsHa
5
5
  const { merge, defaultsDeep } = this.lib._
6
6
  const options = {}
7
7
  model = model ?? pascalCase(req.params.model)
8
- const { schema } = await getSchemaExt(model, 'edit', options)
8
+ const { schema } = await getSchemaExt(model, 'edit', options, { params })
9
9
  if (schema.disabled.includes('update')) return reply.view(templateDisabled, { action: 'edit' })
10
10
  // req.query.attachment = true
11
11
  options.fields = schema.view.fields
@@ -4,7 +4,7 @@ async function exportHandler ({ req, reply, model, params = {}, templateDisabled
4
4
  const { buildUrl } = this.app.waibuMpa
5
5
  const options = {}
6
6
  model = model ?? pascalCase(req.params.model)
7
- const { schema } = await getSchemaExt(model, 'add', options)
7
+ const { schema } = await getSchemaExt(model, 'add', options, { params })
8
8
  if (schema.disabled.includes('find')) return reply.view(templateDisabled, { action: 'list' })
9
9
  options.fields = schema.view.fields
10
10
  const url = buildUrl({ url: req.url, base: req.body.handler })
@@ -3,9 +3,9 @@ async function listHandler ({ req, reply, model, template, params = {}, addOnsHa
3
3
  const { recordFind, getSchemaExt } = this.app.waibuDb
4
4
  const { get, merge, isArray, upperFirst } = this.lib._
5
5
  const qsKey = this.app.waibu.config.qsKey
6
- const options = { count: true }
6
+ const options = { count: true, rels: '*' }
7
7
  model = model ?? pascalCase(req.params.model)
8
- const { schema } = await getSchemaExt(model, 'list')
8
+ const { schema } = await getSchemaExt(model, 'list', { params })
9
9
  if (schema.disabled.includes('find')) return reply.view(templateDisabled, { action: 'list' })
10
10
  for (const key of ['sort', 'limit', 'fields']) {
11
11
  const sessKey = `wdb${model}${upperFirst(key)}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-db",
3
- "version": "1.1.10",
3
+ "version": "1.1.12",
4
4
  "description": "DB Helper",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -2,24 +2,60 @@ import path from 'path'
2
2
 
3
3
  const defReadonly = ['id', 'createdAt', 'updatedAt']
4
4
 
5
+ const defFormatter = {
6
+ lat: function (val, rec) {
7
+ const format = this.format ?? this.app.bajo.format
8
+ return format(val, 'double', { latitude: true })
9
+ },
10
+ lng: function (val, rec) {
11
+ const format = this.format ?? this.app.bajo.format
12
+ return format(val, 'double', { longitude: true })
13
+ },
14
+ speed: function (val, rec) {
15
+ const format = this.format ?? this.app.bajo.format
16
+ return format(val, 'float', { speed: true, withType: true })
17
+ },
18
+ course: function (val, rec) {
19
+ const format = this.format ?? this.app.bajo.format
20
+ return format(val, 'float', { degree: true })
21
+ },
22
+ heading: function (val, rec) {
23
+ const format = this.format ?? this.app.bajo.format
24
+ return format(val, 'float', { degree: true })
25
+ },
26
+ distance: function (val, rec) {
27
+ const format = this.format ?? this.app.bajo.format
28
+ return format(val, 'float', { distance: true })
29
+ }
30
+ }
31
+
5
32
  function getCommons (action, schema, ext, opts = {}) {
6
- const { map, get, set, without, uniq } = this.lib._
33
+ const { merge, map, get, set, without, uniq } = this.lib._
34
+ const calcFields = get(ext, `view.${action}.calcFields`, get(ext, 'common.calcFields', []))
35
+ const valueFormatter = get(ext, `view.${action}.valueFormatter`, get(ext, 'common.valueFormatter', {}))
36
+ const formatter = get(ext, `view.${action}.formatter`, get(ext, 'common.formatter', {}))
7
37
  const label = get(ext, `view.${action}.label`, get(ext, 'common.label', {}))
8
38
  const card = get(ext, `view.${action}.card`, get(ext, 'common.card', true))
9
39
  const hidden = get(ext, `view.${action}.hidden`, get(ext, 'common.hidden', []))
10
40
  const disabled = get(ext, `view.${action}.disabled`, get(ext, 'common.disabled', []))
41
+ const x = get(ext, `view.${action}.x`, get(ext, 'common.x', {}))
11
42
  const aggregate = get(ext, `view.${action}.stat.aggregate`, get(ext, 'common.stat.aggregate', []))
12
43
  hidden.push(...schema.hidden, ...(opts.hidden ?? []))
13
44
  const allFields = without(map(schema.properties, 'name'), ...hidden)
14
45
  const forFields = get(ext, `view.${action}.fields`, get(ext, 'common.fields', allFields))
46
+ set(schema, 'view.calcFields', calcFields)
47
+ set(schema, 'view.valueFormatter', valueFormatter)
48
+ set(schema, 'view.formatter', merge({}, defFormatter, formatter))
15
49
  set(schema, 'view.stat.aggregate', aggregate)
16
50
  set(schema, 'view.disabled', disabled)
51
+ set(schema, 'view.x', x)
17
52
  if (schema.disabled.length > 0) schema.view.disabled.push(...schema.disabled)
18
53
  let fields = []
19
54
  for (const f of forFields) {
20
- if (allFields.includes(f)) fields.push(f)
55
+ if (allFields.includes(f) || map(calcFields, 'name').includes(f)) fields.push(f)
21
56
  }
22
57
  fields = uniq(without(fields, ...hidden))
58
+
23
59
  if (action !== 'add' && !fields.includes('id')) fields.unshift('id')
24
60
  let noWrap = get(ext, `view.${action}.noWrap`, get(ext, 'common.noWrap', true))
25
61
  if (noWrap === true) noWrap = fields
@@ -59,8 +95,11 @@ function customLayout ({ action, schema, ext, layout, allWidgets, readonly }) {
59
95
  }
60
96
  const widget = find(allWidgets, { name: f.name })
61
97
  if (!widget && !f.component) continue
62
- widget.attr = merge({}, widget.attr, omit(f, ['component']))
63
- if (f.component && !readonly.includes(f.name) && action !== 'details') widget.component = f.component
98
+ widget.attr = merge({}, widget.attr, omit(f, ['component', 'componentOpts']))
99
+ if (f.component && !readonly.includes(f.name) && action !== 'details') {
100
+ widget.component = f.component
101
+ widget.componentOpts = f.componentOpts
102
+ }
64
103
  widgets.push(widget)
65
104
  }
66
105
  if (widgets.length > 0) layout.push({ name: item.name, widgets })
@@ -85,7 +124,7 @@ function applyLayout (action, schema, ext) {
85
124
  } else {
86
125
  if (prop.type === 'boolean') {
87
126
  result.component = 'form-select'
88
- result.attr.options = 'false:No true:Yes'
127
+ result.attr.options = 'false|No true|Yes'
89
128
  }
90
129
  if (prop.values) {
91
130
  result.component = 'form-select'
@@ -112,13 +151,16 @@ const handler = {
112
151
  for (const f of get(schema, 'view.qs.fields', '').split(',')) {
113
152
  if (fields.includes(f)) qsFields.push(f)
114
153
  }
115
- let [col, dir] = get(schema, 'view.qs.sort', '').split(':')
116
- if (!fields.includes(col) || !col) col = 'id'
117
- if (!['1', '-1'].includes(dir)) dir = '1'
154
+ const sort = get(schema, 'view.qs.sort')
155
+ if (sort) {
156
+ let [col, dir] = get(schema, 'view.qs.sort', '').split(':')
157
+ if (!fields.includes(col) || !col) col = 'id'
158
+ if (!['1', '-1'].includes(dir)) dir = '1'
159
+ set(schema, 'view.qs.sort', `${col}:${dir}`)
160
+ }
118
161
  set(schema, 'view.label', label)
119
162
  set(schema, 'view.fields', fields)
120
163
  set(schema, 'view.qs.fields', qsFields.join(','))
121
- set(schema, 'view.qs.sort', `${col}:${dir}`)
122
164
  },
123
165
  details: async function (schema, ext, opts) {
124
166
  applyLayout.call(this, 'details', schema, ext, opts)
@@ -138,8 +180,8 @@ async function getSchemaExt (model, view, opts) {
138
180
 
139
181
  let schema = getSchema(model)
140
182
  const base = path.basename(schema.file, path.extname(schema.file))
141
- let ext = await readConfig(`${schema.ns}:/waibuDb/schema/${base}.*`, { ignoreError: true })
142
- const over = await readConfig(`main:/waibuDb/extend/${schema.ns}/schema/${base}.*`, { ignoreError: true })
183
+ let ext = await readConfig(`${schema.ns}:/waibuDb/schema/${base}.*`, { ignoreError: true, opts })
184
+ const over = await readConfig(`main:/waibuDb/extend/${schema.ns}/schema/${base}.*`, { ignoreError: true, opts })
143
185
  ext = defaultsDeep(over, ext)
144
186
  await handler[view].call(this, schema, ext, opts)
145
187
  schema = pick(schema, ['name', 'properties', 'indexes', 'disabled', 'attachment', 'sortables', 'view'])
@@ -0,0 +1,43 @@
1
+ import wdbBase from '../wdb-base.js'
2
+
3
+ async function form () {
4
+ const WdbBase = await wdbBase.call(this)
5
+
6
+ return class WdbForm extends WdbBase {
7
+ build = async () => {
8
+ const { get, find, filter, forOwn, isEmpty } = this.plugin.lib._
9
+ const { base64JsonEncode } = this.plugin.app.waibuMpa
10
+ const schema = get(this, 'component.locals.schema', {})
11
+ const body = []
12
+ const xModels = get(schema, 'view.x.model', [])
13
+ const xOns = get(schema, 'view.x.on', [])
14
+ for (const l of schema.view.layout) {
15
+ body.push(`<c:fieldset ${schema.view.card === false ? '' : 'card'} ${l.name[0] !== '_' ? ('t:legend="' + l.name + '"') : ''} grid-gutter="2">`)
16
+ for (const w of l.widgets) {
17
+ const prop = find(schema.properties, { name: w.name })
18
+ const attr = [`x-ref="${w.name}"`]
19
+ if (xModels.includes(w.name)) attr.push(`x-model="${w.name}"`)
20
+ forOwn(w.attr, (v, k) => {
21
+ attr.push(`${k}="${v}"`)
22
+ })
23
+ const xon = filter(xOns, { field: w.name })
24
+ for (const o of xon) {
25
+ attr.push(`@${o.bind}="${o.handler}"`)
26
+ }
27
+ if (w.componentOpts) attr.push(`c-opts="${base64JsonEncode(w.componentOpts)}"`)
28
+ body.push(`<c:${w.component} ${w.attr.label ? ('t:label="' + w.attr.label + '"') : ''} data-type="${prop.type}" label-floating name="${w.name}" ${attr.join(' ')} />`)
29
+ }
30
+ body.push('</c:fieldset>')
31
+ }
32
+ const html = await this.component.buildSentence(body, this.component.locals)
33
+ this.params.html = `${html}\n${this.params.html}`
34
+ const xData = get(schema, 'view.x.data', '')
35
+ this.params.attr['x-data'] = isEmpty(xData) ? '' : `{ ${xData} }`
36
+ this.params.attr['x-init'] = get(schema, 'view.x.init', '')
37
+
38
+ this.params.tag = this.params.attr.tag ?? 'form'
39
+ }
40
+ }
41
+ }
42
+
43
+ export default form
@@ -126,39 +126,38 @@ async function table () {
126
126
  let prop = find(schema.properties, { name: f })
127
127
  if (!prop) prop = find(schema.view.calcFields, { name: f })
128
128
  if (!prop) continue
129
+ let dataValue = d[f] ?? ''
130
+ if (['datetime'].includes(prop.type)) dataValue = escape(dataValue.toISOString())
131
+ if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
132
+ if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(d[f]))
129
133
  const opts = {}
130
- if (f === 'lng') opts.longitude = true
131
- else if (f === 'lat') opts.latitude = true
132
134
  let value = req.format(d[f], prop.type, opts)
133
135
  if (prop.type === 'boolean') {
134
136
  value = (await this.component.buildTag({ tag: 'icon', attr: { name: `circle${d[f] ? 'Check' : ''}` } })) +
135
137
  ' ' + (req.t(d[f] ? 'Yes' : 'No'))
136
138
  } else value = escape(value)
137
- let dataValue = d[f] ?? ''
138
- if (['datetime'].includes(prop.type)) dataValue = escape(dataValue.toISOString())
139
- if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
140
- if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(d[f]))
141
139
  const vf = get(schema, `view.valueFormatter.${f}`)
142
140
  if (vf) {
143
- if (isFunction(vf)) dataValue = escape(await vf(d[f], d))
141
+ if (isFunction(vf)) dataValue = escape(await vf.call(req, d[f], d))
144
142
  else dataValue = await callHandler(vf, req, d[f], d)
143
+ value = dataValue
145
144
  }
146
145
  const attr = { dataValue, dataKey: prop.name, dataType: prop.type }
147
146
  if (!disableds.includes('get')) attr.style = { cursor: 'pointer' }
148
147
  const cellFormatter = get(schema, `view.cellFormatter.${f}`)
149
- if (cellFormatter) merge(attr, await cellFormatter(dataValue, d))
148
+ if (cellFormatter) merge(attr, await cellFormatter.call(req, dataValue, d))
150
149
  const noWrap = this.isNoWrap(f, schema, group.body.nowrap) ? 'nowrap' : ''
151
150
  if (this.isRightAligned(f, schema)) attr.text = `align:end ${noWrap}`
152
151
  else attr.text = noWrap
153
152
  const lookup = get(schema, `view.lookup.${f}`)
154
153
  if (lookup) {
155
- const item = find(lookup.values, set({}, lookup.id ?? 'id', value))
154
+ const item = find(lookup.values, set({}, lookup.id ?? 'id', d[f]))
156
155
  if (item) value = req.t(item[lookup.field ?? 'name'])
157
156
  }
158
157
  const formatter = get(schema, `view.formatter.${f}`)
159
158
  if (formatter) {
160
- if (isFunction(formatter)) value = await formatter(dataValue, d)
161
- else value = await callHandler(formatter, req, dataValue, d)
159
+ if (isFunction(formatter)) value = await formatter.call(req, d[f], d)
160
+ else value = await callHandler(formatter, req, d[f], d)
162
161
  value = await this.component.buildSentence(value)
163
162
  }
164
163
  const line = await this.component.buildTag({ tag: 'td', attr, html: value })
@@ -171,7 +170,7 @@ async function table () {
171
170
  }
172
171
  html.push(await this.component.buildTag({ tag: 'tbody', attr: group.body, html: items.join('\n') }))
173
172
  this.params.attr = omit(this.params.attr, ['sortUpIcon', 'sortDownIcon', 'noSort', 'selection', 'headerNowrap'])
174
- const goDetails = `
173
+ let xData = `
175
174
  goDetails (id) {
176
175
  let url = '${this.params.attr.detailsHref ?? this.component.buildUrl({ base: 'details', prettyUrl })}'
177
176
  if (url === '#') return
@@ -180,8 +179,15 @@ async function table () {
180
179
  window.location.href = url
181
180
  }
182
181
  `
182
+ const xDataView = get(schema, 'view.x.data', '')
183
+ if (!isEmpty(xDataView)) xData += `, ${xDataView}`
184
+ let xInit = ''
185
+ const xInitView = get(schema, 'view.x.init', '')
186
+ if (!isEmpty(xInitView)) xInit += `${xInitView}\n`
187
+
183
188
  if (selection === 'multi') {
184
- this.params.attr['x-data'] = `{
189
+ xData = `{
190
+ ${xData},
185
191
  toggleAll: false,
186
192
  selected: [],
187
193
  toggle (id) {
@@ -189,10 +195,10 @@ async function table () {
189
195
  const idx = this.selected.indexOf(id)
190
196
  this.selected.splice(idx, 1)
191
197
  } else this.selected.push(id)
192
- },
193
- ${goDetails}
198
+ }
194
199
  }`
195
- this.params.attr['x-init'] = `
200
+ xInit = `
201
+ ${xInit}
196
202
  $watch('toggleAll', val => {
197
203
  if (val) {
198
204
  const els = document.getElementsByName('_rt')
@@ -203,21 +209,24 @@ async function table () {
203
209
  $watch('selected', val => $dispatch('on-selection', val))
204
210
  `
205
211
  } else if (selection === 'single') {
206
- this.params.attr['x-data'] = `{
212
+ xData = `{
213
+ ${xData},
207
214
  selected: '',
208
215
  toggle (id) {
209
216
  this.selected = id
210
- },
211
- ${goDetails}
217
+ }
212
218
  }`
213
- this.params.attr['x-init'] = `
219
+ xInit = `
220
+ ${xInit}
214
221
  $watch('selected', val => $dispatch('on-selection', [val]))
215
222
  `
216
223
  } else {
217
- this.params.attr['x-data'] = `{
218
- ${goDetails}
224
+ xData = `{
225
+ ${xData}
219
226
  }`
220
227
  }
228
+ this.params.attr['x-data'] = xData
229
+ this.params.attr['x-init'] = xInit
221
230
  this.params.html = await this.component.buildTag({ tag: 'table', attr: this.params.attr, html: html.join('\n') })
222
231
  }
223
232
  }
@@ -1,12 +0,0 @@
1
- <% for (const l of schema.view.layout) { %>
2
- <c:fieldset <%= schema.view.card === false ? '' : 'card' %> <% if (l.name[0] !== '_') print('t:legend="' + l.name + '"') %> grid-gutter="2">
3
- <% for (const w of l.widgets) {
4
- const prop = _.find(schema.properties, { name: w.name })
5
- const attr = []
6
- _.forOwn(w.attr, (v, k) => {
7
- attr.push(`${k}="${v}"`)
8
- })
9
- print(`<c:${w.component} ${w.attr.label ? ('label="' + _t(w.attr.label) + '"') : ''} data-type="${prop.type}" label-floating name="${w.name}" ${attr.join(' ')} />`)
10
- } %>
11
- </c:fieldset>
12
- <% } %>