waibu-mpa 2.1.0 → 2.1.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/index.js +4 -0
- package/lib/build-page/inject-elements.js +1 -1
- package/lib/class/component.js +284 -282
- package/lib/class/iconset.js +39 -35
- package/lib/class/theme.js +23 -19
- package/lib/class/tools.js +9 -0
- package/lib/class/view-engine.js +31 -27
- package/lib/class/widget/any.js +12 -0
- package/lib/class/widget/datalist.js +14 -0
- package/lib/class/widget/icon.js +28 -0
- package/lib/class/widget/link.js +19 -0
- package/lib/class/widget/page-end.js +66 -0
- package/lib/class/widget/page-start.js +25 -0
- package/lib/class/widget/script.js +35 -0
- package/lib/class/widget/style.js +20 -0
- package/lib/class/widget/t.js +16 -0
- package/lib/class/widget/template.js +12 -0
- package/lib/class/widget/tree.js +37 -0
- package/lib/class/widget.js +94 -0
- package/lib/collect-iconsets.js +3 -2
- package/lib/collect-themes.js +8 -20
- package/lib/collect-view-engines.js +3 -2
- package/package.json +1 -1
- package/wiki/CHANGES.md +4 -0
- package/lib/class/base-factory.js +0 -90
- package/lib/class/factory/any.js +0 -10
- package/lib/class/factory/datalist.js +0 -12
- package/lib/class/factory/icon.js +0 -26
- package/lib/class/factory/link.js +0 -19
- package/lib/class/factory/page-end.js +0 -64
- package/lib/class/factory/page-start.js +0 -24
- package/lib/class/factory/script.js +0 -33
- package/lib/class/factory/style.js +0 -19
- package/lib/class/factory/t.js +0 -15
- package/lib/class/factory/template.js +0 -11
- package/lib/class/factory/tree.js +0 -36
package/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { stripHtml } from 'string-strip-html'
|
|
2
2
|
import iconsetMappings from './lib/iconset-mappings.js'
|
|
3
|
+
import toolsFactory from './lib/class/tools.js'
|
|
4
|
+
import widgetFactory from './lib/class/widget.js'
|
|
3
5
|
import path from 'path'
|
|
4
6
|
|
|
5
7
|
// taken from: https://stackoverflow.com/questions/52928550/js-get-list-of-all-available-standard-html-tags
|
|
@@ -130,6 +132,8 @@ async function factory (pkgName) {
|
|
|
130
132
|
init = async () => {
|
|
131
133
|
const { trim } = this.app.lib._
|
|
132
134
|
this.config.waibu.prefix = trim(this.config.waibu.prefix, '/')
|
|
135
|
+
await toolsFactory.call(this)
|
|
136
|
+
await widgetFactory.call(this)
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
arrayToAttr = (array = [], delimiter = ' ') => {
|
|
@@ -11,7 +11,7 @@ async function injectElements (options) {
|
|
|
11
11
|
if (req.darkMode) $('body').attr('data-bs-theme', 'dark')
|
|
12
12
|
const rsc = {}
|
|
13
13
|
for (const tag of reply.ctags ?? []) {
|
|
14
|
-
let Builder = get(cmp, `
|
|
14
|
+
let Builder = get(cmp, `widget.${tag}`)
|
|
15
15
|
if (!isFunction(Builder)) continue
|
|
16
16
|
if (!isClass(Builder)) Builder = await Builder.call(cmp)
|
|
17
17
|
for (const key of ['scripts', 'css']) {
|
package/lib/class/component.js
CHANGED
|
@@ -1,316 +1,318 @@
|
|
|
1
|
-
import baseFactory from './base-factory.js'
|
|
2
1
|
import path from 'path'
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
3
|
+
async function componentFactory () {
|
|
4
|
+
class MpaComponent extends this.app.baseClass.MpaTools {
|
|
5
|
+
constructor ({ plugin, $, theme, iconset, locals, reply, req, scriptBlock, styleBlock } = {}) {
|
|
6
|
+
super(plugin)
|
|
7
|
+
const { get } = plugin.app.lib._
|
|
8
|
+
this.$ = $
|
|
9
|
+
this.theme = theme
|
|
10
|
+
this.iconset = iconset
|
|
11
|
+
this.locals = locals
|
|
12
|
+
this.reply = reply
|
|
13
|
+
this.req = req
|
|
14
|
+
this.cacheMaxAge = get(plugin, 'app.waibuMpa.config.theme.component.cacheMaxAgeDur', 0)
|
|
15
|
+
this.namespace = 'c:'
|
|
16
|
+
this.noTags = []
|
|
17
|
+
this.scriptBlock = scriptBlock
|
|
18
|
+
this.styleBlock = styleBlock
|
|
19
|
+
this.widget = {}
|
|
20
|
+
}
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
addScriptBlock = (type, block) => {
|
|
23
|
+
if (!block) {
|
|
24
|
+
block = type
|
|
25
|
+
type = 'root'
|
|
26
|
+
}
|
|
27
|
+
if (typeof block === 'string') block = [block]
|
|
28
|
+
this.scriptBlock[type] = this.scriptBlock[type] ?? []
|
|
29
|
+
this.scriptBlock[type].push(...block)
|
|
28
30
|
}
|
|
29
|
-
if (typeof block === 'string') block = [block]
|
|
30
|
-
this.scriptBlock[type] = this.scriptBlock[type] ?? []
|
|
31
|
-
this.scriptBlock[type].push(...block)
|
|
32
|
-
}
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
addStyleBlock = (type, block) => {
|
|
33
|
+
if (!block) {
|
|
34
|
+
block = type
|
|
35
|
+
type = 'root'
|
|
36
|
+
}
|
|
37
|
+
if (typeof block === 'string') block = [block]
|
|
38
|
+
this.styleBlock[type] = this.styleBlock[type] ?? []
|
|
39
|
+
this.styleBlock[type].push(...block)
|
|
38
40
|
}
|
|
39
|
-
if (typeof block === 'string') block = [block]
|
|
40
|
-
this.styleBlock[type] = this.styleBlock[type] ?? []
|
|
41
|
-
this.styleBlock[type].push(...block)
|
|
42
|
-
}
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Loads base factories dynamically from the file system.
|
|
44
|
+
* @async
|
|
45
|
+
*/
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
loadBaseWidgets = async () => {
|
|
48
|
+
const { camelCase } = this.app.lib._
|
|
49
|
+
const { importModule } = this.app.bajo
|
|
50
|
+
const { fastGlob } = this.app.lib
|
|
51
|
+
const pattern = `${this.app.waibuMpa.dir.pkg}/lib/class/widget/*.js`
|
|
52
|
+
const files = await fastGlob(pattern)
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
const mod = await importModule(file)
|
|
55
|
+
const name = camelCase(path.basename(file, '.js'))
|
|
56
|
+
this.widget[name] = await mod.call(this.plugin)
|
|
57
|
+
}
|
|
59
58
|
}
|
|
60
|
-
}
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Determines the method to use based on the provided parameters.
|
|
77
|
-
* @param {Object} params - The parameters containing the method information.
|
|
78
|
-
* @returns {string} The determined method name.
|
|
79
|
-
*/
|
|
80
|
-
getMethod = (params) => {
|
|
81
|
-
let method = params.ctag
|
|
82
|
-
if (!this.factory[method]) method = 'any'
|
|
83
|
-
return method
|
|
84
|
-
}
|
|
60
|
+
/**
|
|
61
|
+
* Retrieves a widget builder class or instance for a specific method.
|
|
62
|
+
* @async
|
|
63
|
+
* @param {string} method - The method name to retrieve the builder for.
|
|
64
|
+
* @returns {Promise<Function|Object>} The builder class or instance.
|
|
65
|
+
*/
|
|
66
|
+
getWidget = async (method) => {
|
|
67
|
+
const { isClass } = this.app.lib.aneka
|
|
68
|
+
let Widget = this.widget[method]
|
|
69
|
+
if (!isClass(Widget)) Widget = await Widget.call(this.plugin)
|
|
70
|
+
return Widget
|
|
71
|
+
}
|
|
85
72
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const { compile } = this.app.bajoTemplate
|
|
96
|
-
const { escape } = this.app.waibu
|
|
97
|
-
const { isEmpty, merge, uniq, without } = this.app.lib._
|
|
98
|
-
params.ctag = params.tag
|
|
99
|
-
const method = this.getMethod(params)
|
|
100
|
-
if (opts.attr) params.attr = merge({}, opts.attr, params.attr)
|
|
101
|
-
this.normalizeAttr(params)
|
|
102
|
-
params.attr.content = params.attr.content ?? ''
|
|
103
|
-
let html
|
|
104
|
-
if (params.attr.content.includes('%s')) html = sprintf(params.attr.content, params.html)
|
|
105
|
-
else if (isEmpty(params.html)) html = params.attr.content
|
|
106
|
-
if (!isEmpty(html)) params.html = params.noEscape ? html : escape(html)
|
|
107
|
-
await this.iconAttr(params, method)
|
|
108
|
-
await this.beforeBuildTag(method, params)
|
|
109
|
-
const Builder = await this.getBuilder(method)
|
|
110
|
-
const builder = new Builder({ component: this, params })
|
|
111
|
-
const resp = await builder.build()
|
|
112
|
-
if (resp === false) {
|
|
113
|
-
return false
|
|
73
|
+
/**
|
|
74
|
+
* Determines the method to use based on the provided parameters.
|
|
75
|
+
* @param {Object} params - The parameters containing the method information.
|
|
76
|
+
* @returns {string} The determined method name.
|
|
77
|
+
*/
|
|
78
|
+
getMethod = (params) => {
|
|
79
|
+
let method = params.ctag
|
|
80
|
+
if (!this.widget[method]) method = 'any'
|
|
81
|
+
return method
|
|
114
82
|
}
|
|
115
83
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Builds a tag with the given parameters and options.
|
|
86
|
+
* @async
|
|
87
|
+
* @param {Object} [params={}] - The parameters for the tag.
|
|
88
|
+
* @param {Object} [opts={}] - Additional options for building the tag.
|
|
89
|
+
* @returns {Promise<string|boolean>} The rendered HTML or `false` if the build fails.
|
|
90
|
+
*/
|
|
91
|
+
buildTag = async (params = {}, opts = {}) => {
|
|
92
|
+
const { sprintf } = this.app.lib
|
|
93
|
+
const { compile } = this.app.bajoTemplate
|
|
94
|
+
const { escape } = this.app.waibu
|
|
95
|
+
const { isEmpty, merge, uniq, without } = this.app.lib._
|
|
96
|
+
params.ctag = params.tag
|
|
97
|
+
const method = this.getMethod(params)
|
|
98
|
+
if (opts.attr) params.attr = merge({}, opts.attr, params.attr)
|
|
99
|
+
this.normalizeAttr(params)
|
|
100
|
+
params.attr.content = params.attr.content ?? ''
|
|
101
|
+
let html
|
|
102
|
+
if (params.attr.content.includes('%s')) html = sprintf(params.attr.content, params.html)
|
|
103
|
+
else if (isEmpty(params.html)) html = params.attr.content
|
|
104
|
+
if (!isEmpty(html)) params.html = params.noEscape ? html : escape(html)
|
|
105
|
+
await this.iconAttr(params, method)
|
|
106
|
+
await this.beforeBuildTag(method, params)
|
|
107
|
+
const Widget = await this.getWidget(method)
|
|
108
|
+
const widget = new Widget({ component: this, params })
|
|
109
|
+
const resp = await widget.build()
|
|
110
|
+
if (resp === false) {
|
|
111
|
+
return false
|
|
112
|
+
}
|
|
121
113
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
114
|
+
await this.afterBuildTag(method, params)
|
|
115
|
+
params.attr.class = without(uniq(params.attr.class), undefined, null, '')
|
|
116
|
+
if (isEmpty(params.attr.class)) delete params.attr.class
|
|
117
|
+
if (isEmpty(params.attr.style)) delete params.attr.style
|
|
118
|
+
if (isEmpty(params.html)) return await this.render(params)
|
|
127
119
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
*/
|
|
133
|
-
normalizeAttr = (params = {}, opts = {}) => {
|
|
134
|
-
const { without, keys, isString, isArray } = this.app.lib._
|
|
135
|
-
const { generateId } = this.app.lib.aneka
|
|
136
|
-
params.attr = params.attr ?? {}
|
|
137
|
-
params.attr.class = this.app.waibuMpa.attrToArray(params.attr.class)
|
|
138
|
-
params.attr.style = this.app.waibuMpa.attrToObject(params.attr.style)
|
|
139
|
-
if (isString(opts.cls)) params.attr.class.push(opts.cls)
|
|
140
|
-
else if (isArray(opts.cls)) params.attr.class.push(...opts.cls)
|
|
141
|
-
if (opts.tag) params.tag = opts.tag
|
|
142
|
-
if (opts.autoId) params.attr.id = isString(params.attr.id) ? params.attr.id : generateId('alpha')
|
|
143
|
-
for (const k of without(keys(opts), 'cls', 'tag', 'autoId')) {
|
|
144
|
-
params.attr[k] = opts[k]
|
|
120
|
+
const merged = merge({}, params.locals, { attr: params.attr })
|
|
121
|
+
const result = await compile(params.html, merged, { ttl: this.cacheMaxAge })
|
|
122
|
+
params.html = result
|
|
123
|
+
return await this.render(params)
|
|
145
124
|
}
|
|
146
|
-
params.html = params.html ?? ''
|
|
147
|
-
}
|
|
148
125
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Normalizes the attributes of the given parameters.
|
|
128
|
+
* @param {Object} [params={}] - The parameters containing attributes to normalize.
|
|
129
|
+
* @param {Object} [opts={}] - Additional options for normalization.
|
|
130
|
+
*/
|
|
131
|
+
normalizeAttr = (params = {}, opts = {}) => {
|
|
132
|
+
const { without, keys, isString, isArray } = this.app.lib._
|
|
133
|
+
const { generateId } = this.app.lib.aneka
|
|
134
|
+
params.attr = params.attr ?? {}
|
|
135
|
+
params.attr.class = this.app.waibuMpa.attrToArray(params.attr.class)
|
|
136
|
+
params.attr.style = this.app.waibuMpa.attrToObject(params.attr.style)
|
|
137
|
+
if (isString(opts.cls)) params.attr.class.push(opts.cls)
|
|
138
|
+
else if (isArray(opts.cls)) params.attr.class.push(...opts.cls)
|
|
139
|
+
if (opts.tag) params.tag = opts.tag
|
|
140
|
+
if (opts.autoId) params.attr.id = isString(params.attr.id) ? params.attr.id : generateId('alpha')
|
|
141
|
+
for (const k of without(keys(opts), 'cls', 'tag', 'autoId')) {
|
|
142
|
+
params.attr[k] = opts[k]
|
|
143
|
+
}
|
|
144
|
+
params.html = params.html ?? ''
|
|
145
|
+
}
|
|
159
146
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Renders the final HTML for the given parameters.
|
|
149
|
+
* @async
|
|
150
|
+
* @param {Object} [params={}] - The parameters for rendering.
|
|
151
|
+
* @returns {Promise<string>} The rendered HTML.
|
|
152
|
+
*/
|
|
153
|
+
render = async (params = {}) => {
|
|
154
|
+
const { omit, isEmpty, merge, kebabCase, isArray } = this.app.lib._
|
|
155
|
+
const { stringifyAttribs } = this.app.waibuMpa
|
|
156
|
+
params.attr = params.attr ?? {}
|
|
157
|
+
|
|
158
|
+
params.tag = params.attr.tag ?? ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(params.tag) ? params.tag : kebabCase(params.tag)
|
|
159
|
+
params.attr = omit(params.attr, ['tag', 'content'])
|
|
160
|
+
params.html = params.html ?? ''
|
|
161
|
+
params.attrs = stringifyAttribs(params.attr)
|
|
162
|
+
if (!isEmpty(params.attrs)) params.attrs = ' ' + params.attrs
|
|
163
|
+
let html = isArray(params.html) ? params.html.join('\n') : params.html
|
|
164
|
+
if (!params.noTag) {
|
|
165
|
+
html = params.selfClosing ? `<${params.tag}${params.attrs}/>` : `<${params.tag}${params.attrs}>${params.html}</${params.tag}>`
|
|
166
|
+
const method = this.getMethod(params)
|
|
167
|
+
if (this.widget[method]) { // static method on Widget
|
|
168
|
+
const Widget = await this.getWidget(method)
|
|
169
|
+
if (Widget.after) {
|
|
170
|
+
html = (await Widget.after.call(this, merge({}, params, { result: html }))) ?? html
|
|
171
|
+
}
|
|
173
172
|
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
173
|
+
} else if (!this.noTags.includes(params.attr.octag)) this.noTags.push(params.attr.octag)
|
|
174
|
+
if (params.prepend) html = `${params.prepend}${html}`
|
|
175
|
+
if (params.append) html += params.append
|
|
176
|
+
return html
|
|
177
|
+
}
|
|
180
178
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Processes icon-related attributes and appends them to the HTML.
|
|
181
|
+
* @async
|
|
182
|
+
* @param {Object} [params={}] - The parameters containing icon attributes.
|
|
183
|
+
* @param {string} method - The method name.
|
|
184
|
+
*/
|
|
185
|
+
iconAttr = async (params = {}, method) => {
|
|
186
|
+
if (['modal', 'toast'].includes(method)) return
|
|
187
|
+
const { groupAttrs } = this.app.waibuMpa
|
|
188
|
+
const { merge } = this.app.lib._
|
|
189
|
+
for (const k in params.attr) {
|
|
190
|
+
const v = params.attr[k]
|
|
191
|
+
if (!['icon', 'iconEnd'].includes(k)) continue
|
|
192
|
+
const group = groupAttrs(params.attr, ['icon', 'iconEnd'])
|
|
193
|
+
const _params = { attr: merge(k.endsWith('End') ? group.iconEnd : group.icon, { name: v }) }
|
|
194
|
+
const Widget = this.widget.icon
|
|
195
|
+
const widget = new Widget({ component: this, params: _params })
|
|
196
|
+
await widget.build()
|
|
197
|
+
const icon = await this.render(_params)
|
|
198
|
+
params.html = k.endsWith('End') ? `${params.html} ${icon}` : `${icon} ${params.html}`
|
|
199
|
+
delete params.attr[k]
|
|
200
|
+
}
|
|
202
201
|
}
|
|
203
|
-
}
|
|
204
202
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
203
|
+
/**
|
|
204
|
+
* Builds the `<option>` elements for a `<select>` tag.
|
|
205
|
+
* @param {Object} params - The parameters containing options and values.
|
|
206
|
+
* @returns {string} The generated `<option>` elements.
|
|
207
|
+
*/
|
|
208
|
+
buildOptions = (params) => {
|
|
209
|
+
const { has, omit, find, isPlainObject, isArray } = this.app.lib._
|
|
210
|
+
const { attrToArray } = this.app.waibuMpa
|
|
211
|
+
const items = []
|
|
212
|
+
if (!has(params.attr, 'options')) return
|
|
213
|
+
let values = attrToArray(params.attr.value)
|
|
214
|
+
if (!has(params.attr, 'multiple') && values.length > 0) values = [values[0]]
|
|
215
|
+
const options = isArray(params.attr.options) ? params.attr.options : attrToArray(params.attr.options)
|
|
216
|
+
for (const opt of options) {
|
|
217
|
+
let val
|
|
218
|
+
let text
|
|
219
|
+
if (isPlainObject(opt)) {
|
|
220
|
+
val = opt.value
|
|
221
|
+
text = opt.text
|
|
222
|
+
} else [val, text] = opt.split('|')
|
|
223
|
+
const sel = find(values, v => val === v)
|
|
224
|
+
items.push(`<option value="${val}"${sel ? ' selected' : ''}>${this.req.t(text ?? val)}</option>`)
|
|
225
|
+
}
|
|
226
|
+
params.attr = omit(params.attr, ['options'])
|
|
227
|
+
return items.join('\n')
|
|
227
228
|
}
|
|
228
|
-
params.attr = omit(params.attr, ['options'])
|
|
229
|
-
return items.join('\n')
|
|
230
|
-
}
|
|
231
229
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
230
|
+
/**
|
|
231
|
+
* Builds a URL with the given parameters.
|
|
232
|
+
* @param {Object} options - The options for building the URL.
|
|
233
|
+
* @param {Array<string>} [options.exclude] - Keys to exclude from the URL.
|
|
234
|
+
* @param {string} [options.prefix] - The prefix for the URL.
|
|
235
|
+
* @param {string} [options.base] - The base URL.
|
|
236
|
+
* @param {string} [options.url] - The URL to modify.
|
|
237
|
+
* @param {Object} [options.params={}] - Query parameters to include.
|
|
238
|
+
* @param {boolean} [options.prettyUrl] - Whether to generate a pretty URL.
|
|
239
|
+
* @returns {string} The built URL.
|
|
240
|
+
*/
|
|
241
|
+
buildUrl = ({ exclude, prefix, base, url, params = {}, prettyUrl }) => {
|
|
242
|
+
const { isEmpty } = this.app.lib._
|
|
243
|
+
const { buildUrl } = this.app.waibuMpa
|
|
244
|
+
url = url ?? (isEmpty(this.req.referer) ? this.req.url : this.req.referer)
|
|
245
|
+
return buildUrl({ exclude, prefix, base, url, params, prettyUrl })
|
|
246
|
+
}
|
|
249
247
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
248
|
+
/**
|
|
249
|
+
* Builds a sentence with optional rendering and minification.
|
|
250
|
+
* @async
|
|
251
|
+
* @param {string|string[]} sentence - The sentence or array of sentences to build.
|
|
252
|
+
* @param {Object} [params={}] - Parameters for rendering the sentence.
|
|
253
|
+
* @param {Object} [extra={}] - Extra options such as wrapping or minification.
|
|
254
|
+
* @returns {Promise<string>} The built sentence.
|
|
255
|
+
*/
|
|
256
|
+
buildSentence = async (sentence, params = {}, extra = {}) => {
|
|
257
|
+
if (Array.isArray(sentence)) sentence = sentence.join(' ')
|
|
258
|
+
const { minify, renderString } = this.app.waibuMpa
|
|
259
|
+
if (extra.wrapped) sentence = '<w>' + sentence + '</w>'
|
|
260
|
+
const opts = {
|
|
261
|
+
partial: true,
|
|
262
|
+
ext: params.ext ?? '.html',
|
|
263
|
+
req: this.req,
|
|
264
|
+
reply: this.reply
|
|
265
|
+
}
|
|
266
|
+
let html = await renderString(sentence, params, opts)
|
|
267
|
+
if (extra.wrapped) html = html.slice(3, html.length - 4)
|
|
268
|
+
if (extra.minify) html = await minify(html)
|
|
269
|
+
return html
|
|
267
270
|
}
|
|
268
|
-
let html = await renderString(sentence, params, opts)
|
|
269
|
-
if (extra.wrapped) html = html.slice(3, html.length - 4)
|
|
270
|
-
if (extra.minify) html = await minify(html)
|
|
271
|
-
return html
|
|
272
|
-
}
|
|
273
271
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
272
|
+
/**
|
|
273
|
+
* Hook executed before building a tag.
|
|
274
|
+
* @param {string} tag - The tag name.
|
|
275
|
+
* @param {Object} params - The parameters for the tag.
|
|
276
|
+
*/
|
|
277
|
+
beforeBuildTag = (tag, params) => {}
|
|
280
278
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Hook executed after building a tag.
|
|
281
|
+
* @param {string} tag - The tag name.
|
|
282
|
+
* @param {Object} params - The parameters for the tag.
|
|
283
|
+
*/
|
|
284
|
+
afterBuildTag = (tag, params) => {}
|
|
287
285
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
286
|
+
/**
|
|
287
|
+
* Builds a child tag based on a detector attribute.
|
|
288
|
+
* @async
|
|
289
|
+
* @param {string} detector - The attribute to detect child tags.
|
|
290
|
+
* @param {Object} options - Options for building the child tag.
|
|
291
|
+
* @param {string} [options.tag] - The tag name.
|
|
292
|
+
* @param {Object} options.params - The parameters for the child tag.
|
|
293
|
+
* @param {string} [options.inner] - Inner HTML for the child tag.
|
|
294
|
+
*/
|
|
295
|
+
buildChildTag = async (detector, { tag, params, inner }) => {
|
|
296
|
+
const { has, pickBy, omit, keys } = this.app.lib._
|
|
297
|
+
if (has(params.attr, detector)) {
|
|
298
|
+
const [prefix] = detector.split('-')
|
|
299
|
+
const attr = {}
|
|
300
|
+
const html = tag ? params.attr[detector] : undefined
|
|
301
|
+
tag = tag ?? prefix
|
|
302
|
+
const picked = pickBy(params.attr, (v, k) => k.startsWith(`${prefix}-`))
|
|
303
|
+
for (const k in picked) {
|
|
304
|
+
attr[k.slice(prefix.length + 1)] = picked[k]
|
|
305
|
+
}
|
|
306
|
+
const child = await this.buildTag({ tag, params: { attr, html } })
|
|
307
|
+
params.html += `\n${child}`
|
|
308
|
+
const excluded = [detector, ...keys(picked)]
|
|
309
|
+
params.attr = omit(params.attr, excluded)
|
|
307
310
|
}
|
|
308
|
-
const child = await this.buildTag({ tag, params: { attr, html } })
|
|
309
|
-
params.html += `\n${child}`
|
|
310
|
-
const excluded = [detector, ...keys(picked)]
|
|
311
|
-
params.attr = omit(params.attr, excluded)
|
|
312
311
|
}
|
|
313
312
|
}
|
|
313
|
+
|
|
314
|
+
this.app.baseClass.MpaComponent = MpaComponent
|
|
315
|
+
return MpaComponent
|
|
314
316
|
}
|
|
315
317
|
|
|
316
|
-
export default
|
|
318
|
+
export default componentFactory
|