waibu-mpa 1.0.0 → 1.0.2

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.
Files changed (104) hide show
  1. package/README.md +13 -6
  2. package/bajo/.alias +1 -0
  3. package/bajo/config-dev.json +6 -0
  4. package/bajo/config-prod.json +14 -0
  5. package/bajo/config.json +62 -21
  6. package/bajo/hook/dobo.wmpa-session@before-sanitize-schema.js +10 -0
  7. package/bajo/hook/waibu-mpa.theme@after-inject-scripts.js +6 -0
  8. package/bajo/hook/waibu-mpa@pre-parsing.js +28 -5
  9. package/bajo/init.js +7 -0
  10. package/bajo/method/attr-to-array.js +4 -2
  11. package/bajo/method/attr-to-object.js +3 -1
  12. package/bajo/method/attribs/parse.js +28 -0
  13. package/bajo/method/attribs/stringify.js +27 -0
  14. package/bajo/method/base64-json-decode.js +5 -0
  15. package/bajo/method/base64-json-encode.js +5 -0
  16. package/bajo/method/build-url.js +27 -0
  17. package/bajo/method/get-app-title.js +9 -0
  18. package/bajo/method/get-resource.js +12 -0
  19. package/bajo/method/group-attrs.js +45 -0
  20. package/bajo/method/html-tags.js +6 -0
  21. package/bajo/method/iconset-mappings.js +350 -0
  22. package/bajo/method/json-stringify.js +86 -0
  23. package/bajo/method/minify.js +9 -0
  24. package/bajo/method/pagination-layout.js +7 -3
  25. package/bajo/method/render-string.js +4 -2
  26. package/bajo/method/render.js +19 -5
  27. package/bajo/method/resolve-layout.js +15 -0
  28. package/bajo/method/resolve-partial.js +7 -0
  29. package/bajo/method/resolve-template.js +7 -0
  30. package/bajo/method/url-to-breadcrumb.js +35 -0
  31. package/bajoI18N/resource/en-US.json +6 -0
  32. package/bajoI18N/resource/id.json +23 -2
  33. package/dobo/fixture/site-setting.json +5 -0
  34. package/dobo/schema/session.json +9 -0
  35. package/dobo/schema/site-setting.js +28 -0
  36. package/docs/component.md +232 -0
  37. package/docs/configuration.md +34 -0
  38. package/docs/hook.md +118 -0
  39. package/docs/instance.md +23 -0
  40. package/docs/page-building.md +79 -0
  41. package/lib/apply-format.js +6 -11
  42. package/lib/build-locals.js +29 -13
  43. package/lib/build-page/apply-include.js +21 -0
  44. package/lib/build-page/attrs-mutation.js +65 -0
  45. package/lib/build-page/concat-resources.js +69 -0
  46. package/lib/build-page/inject-elements/css.js +16 -0
  47. package/lib/build-page/inject-elements/meta.js +18 -0
  48. package/lib/build-page/inject-elements/script.js +61 -0
  49. package/lib/build-page/inject-elements.js +43 -0
  50. package/lib/build-page/manipulation.js +39 -0
  51. package/lib/build-page/replace-tag.js +48 -0
  52. package/lib/build-page.js +44 -0
  53. package/lib/build-routes.js +76 -28
  54. package/lib/class/component.js +178 -58
  55. package/lib/class/factory/any.js +12 -0
  56. package/lib/class/factory/datalist.js +12 -0
  57. package/lib/class/factory/icon.js +26 -0
  58. package/lib/class/factory/include.js +26 -0
  59. package/lib/class/factory/link.js +19 -0
  60. package/lib/class/factory/page-end.js +58 -0
  61. package/lib/class/factory/page-start.js +19 -0
  62. package/lib/class/factory/script.js +33 -0
  63. package/lib/class/factory/style.js +19 -0
  64. package/lib/class/factory/t.js +15 -0
  65. package/lib/class/factory/template.js +11 -0
  66. package/lib/class/factory/tree.js +36 -0
  67. package/lib/class/factory.js +79 -0
  68. package/lib/class/iconset.js +34 -0
  69. package/lib/class/theme.js +13 -1
  70. package/lib/class/view-engine.js +70 -19
  71. package/lib/collect-iconsets.js +42 -0
  72. package/lib/collect-themes.js +85 -38
  73. package/lib/collect-view-engines.js +12 -7
  74. package/lib/decorate.js +13 -8
  75. package/lib/error.js +16 -3
  76. package/lib/get-cached-result.js +31 -0
  77. package/lib/load-resource.js +27 -0
  78. package/lib/not-found.js +29 -1
  79. package/lib/resolve-resource.js +63 -0
  80. package/lib/session/setup.js +18 -0
  81. package/lib/session/store.js +61 -0
  82. package/lib/sub-app.js +6 -2
  83. package/package.json +4 -3
  84. package/waibu/boot.js +22 -26
  85. package/waibuDb/schema/session.json +3 -0
  86. package/waibuMpa/layout/default.html +5 -0
  87. package/waibuMpa/route/component/render.js +13 -0
  88. package/waibuMpa/route/logo/@id.js +21 -0
  89. package/waibuMpa/route/wmpa.js +30 -0
  90. package/waibuMpa/template/500.html +4 -0
  91. package/waibuMpa/template/_500.html +8 -0
  92. package/waibuMpa/template/wmpa.js +417 -0
  93. package/waibuMpa/view-engine.js +1 -1
  94. package/waibuStatic/virtual.json +2 -2
  95. package/bajo/hook/bajo-i18n@before-init.js +0 -6
  96. package/bajo/method/attrs-to-object.js +0 -14
  97. package/bajo/method/get-tpl-and-theme.js +0 -46
  98. package/bajo/method/object-to-attrs.js +0 -12
  99. package/lib/parse-components.js +0 -83
  100. package/waibuMpa/theme/component/self.js +0 -6
  101. package/waibuMpa/theme/component/tag-three.js +0 -6
  102. package/waibuMpa/theme.js +0 -35
  103. package/waibuMpa/view-engine/template/default/500.html +0 -1
  104. /package/waibuMpa/{view-engine/template/default → template}/404.html +0 -0
package/README.md CHANGED
@@ -1,22 +1,29 @@
1
- # wakatobi-mpa
1
+ # waibu-mpa
2
2
 
3
- Plugin name: **wakatobiMpa**, alias: **wktbmpa**
3
+ Plugin name: **waibuMpa**, alias: **wmpa**
4
4
 
5
- ![GitHub package.json version](https://img.shields.io/github/package-json/v/ardhi/wakatobi-mpa) ![NPM Version](https://img.shields.io/npm/v/wakatobi-mpa)
5
+ ![GitHub package.json version](https://img.shields.io/github/package-json/v/ardhi/waibu-mpa) ![NPM Version](https://img.shields.io/npm/v/waibu-mpa)
6
6
 
7
7
  > <br />**Attention**: I do NOT accept any pull request at the moment, thanks!<br /><br />
8
8
 
9
- Multi Pages App (MPA) for [Wakatobi Framework](https://github.com/ardhi/wakatobi)
9
+ Multi Pages App (MPA) for [Waibu Framework](https://github.com/ardhi/waibu)
10
10
 
11
11
  ## Installation
12
12
 
13
13
  Goto your ```<bajo-base-dir>``` and type:
14
14
 
15
15
  ```bash
16
- $ npm install wakatobi-mpa
16
+ $ npm install waibu-mpa
17
17
  ```
18
18
 
19
- Now open your ```<bajo-data-dir>/config/.plugins``` and put ```wakatobi-mpa``` in it
19
+ Now open your ```<bajo-data-dir>/config/.plugins``` and put ```waibu-mpa``` in it
20
+
21
+ ## Documentation
22
+
23
+ - [Class Instance](docs/instance.md)
24
+ - [Configuration](docs/configuration.md)
25
+ - [App Hook](docs/hook.md)
26
+ - [Component](docs/component.md)
20
27
 
21
28
  ## License
22
29
 
package/bajo/.alias ADDED
@@ -0,0 +1 @@
1
+ wmpa
@@ -0,0 +1,6 @@
1
+ {
2
+ "minifier": false,
3
+ "page": {
4
+ "insertWarning": true
5
+ }
6
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "viewEngine": {
3
+ "cacheMaxAge": 300
4
+ },
5
+ "theme": {
6
+ "component": {
7
+ "unknownTag": "remove",
8
+ "cacheMaxAge": 300
9
+ }
10
+ },
11
+ "prettier": false,
12
+ "compress": {},
13
+ "rateLimit": {}
14
+ }
package/bajo/config.json CHANGED
@@ -1,35 +1,82 @@
1
1
  {
2
- "alias": "wbmpa",
3
2
  "title": "Multi Page Webapp",
4
- "prefix": "",
5
- "mountAppAsRoot": true,
6
- "charset": "utf-8",
3
+ "waibu": {
4
+ "prefix": ""
5
+ },
6
+ "mountMainAsRoot": true,
7
+ "page": {
8
+ "charset": "utf-8",
9
+ "cacheMaxAge": 0,
10
+ "insertWarning": false
11
+ },
7
12
  "darkMode": {
8
- "preset": "light",
9
- "qsKey": "dark"
13
+ "default": false,
14
+ "qsKey": "dark-mode"
10
15
  },
11
16
  "i18n": {
12
17
  "detectors": ["qs"],
13
18
  "defaultNs": ["dobo", "waibuMpa"]
14
19
  },
20
+ "session": {
21
+ "secret": "f703a74b884b539e78c642a5369fe538",
22
+ "cookieName": "sid",
23
+ "cookie": {
24
+ "secure": "auto"
25
+ },
26
+ "saveUninitialized": false
27
+ },
15
28
  "emoji": true,
16
29
  "viewEngine": {
17
- "default": "default",
18
- "cacheMaxAge": 300
30
+ "cacheMaxAge": 0,
31
+ "layout": {
32
+ "default": "waibuMpa:/default.html",
33
+ "fallback": true
34
+ }
19
35
  },
20
36
  "theme": {
21
- "autoInsert": ["css", "meta", "scripts"],
37
+ "default": null,
38
+ "autoInsert": {
39
+ "css": true,
40
+ "meta": true,
41
+ "scripts": true,
42
+ "inlineScript": true,
43
+ "inlineCss": true
44
+ },
22
45
  "component": {
23
- "insertCtag": false,
46
+ "unknownTag": "comment",
24
47
  "defaultTag": "div",
25
- "cacheMaxAge": 300
48
+ "cacheMaxAge": 0
49
+ }
50
+ },
51
+ "iconset": {
52
+ "default": null,
53
+ "autoInsert": {
54
+ "css": true,
55
+ "scripts": true,
56
+ "inlineScript": true,
57
+ "inlineCss": true
58
+ }
59
+ },
60
+ "concatResource": {
61
+ "cacheMaxAge": 0,
62
+ "excluded": [],
63
+ "css": false,
64
+ "scripts": false
65
+ },
66
+ "cheerio": {
67
+ "loadOptions": {
68
+ "xml": {
69
+ "xmlMode": false,
70
+ "decodeEntities": false,
71
+ "recognizeSelfClosing": true
72
+ }
26
73
  }
27
74
  },
28
75
  "prettier": {
29
76
  "parser": "html",
30
- "printWidth": 1000
77
+ "printWidth": 120
31
78
  },
32
- "minify": {
79
+ "minifier": {
33
80
  "removeAttributeQuotes": true,
34
81
  "removeComments": true,
35
82
  "removeCommentsFromCDATA": true,
@@ -46,19 +93,13 @@
46
93
  "tableHeadClass": "",
47
94
  "tableBodyClass": "table-group-divider"
48
95
  },
49
- "home": {
50
- "action": "redirect",
51
- "route": true
52
- },
53
- "multipart": {
54
- },
96
+ "multipart": {},
55
97
  "cors": {},
56
98
  "helmet": {
57
99
  "contentSecurityPolicy": false
58
100
  },
59
101
  "compress": false,
60
102
  "rateLimit": false,
61
- "traceNoTemplate": false,
62
103
  "disabled": [],
63
- "dependencies": ["waibu", "waibu-static"]
104
+ "dependencies": ["waibu", "waibu-static", "bajo-markdown"]
64
105
  }
@@ -0,0 +1,10 @@
1
+ async function doboWmpaSessionBeforeSanitizeSession (schema) {
2
+ const { find } = this.app.bajo.lib._
3
+
4
+ const dobo = this.app.dobo
5
+ let conn = find(dobo.connections, { name: schema.connection })
6
+ if (!conn) conn = find(dobo.connections, { name: 'memory' })
7
+ if (conn) schema.connection = conn.name
8
+ }
9
+
10
+ export default doboWmpaSessionBeforeSanitizeSession
@@ -0,0 +1,6 @@
1
+ async function waibuMpaThemeAfterInjectScripts ({ items }) {
2
+ items.push(`${this.name}.virtual:/json2csv/json2csv.js`)
3
+ items.push(`${this.name}:/wmpa.js`)
4
+ }
5
+
6
+ export default waibuMpaThemeAfterInjectScripts
@@ -1,12 +1,35 @@
1
- const waibuMpaPreHandler = {
1
+ async function checkLang (req, reply) {
2
+ if (!req.session) return
3
+ if (req.langDetector) {
4
+ req.session.lang = req.lang
5
+ await req.i18n.changeLanguage(req.session.lang)
6
+ return
7
+ }
8
+ if (req.session.lang) req.lang = req.session.lang
9
+ await req.i18n.changeLanguage(req.lang)
10
+ }
11
+
12
+ async function checkDark (req, reply) {
13
+ const { isSet } = this.app.bajo
14
+ const key = this.config.darkMode.qsKey
15
+ const value = req.query[key]
16
+ if (isSet(value)) {
17
+ req.darkMode = value
18
+ if (req.session) req.session.darkMode = req.darkMode
19
+ return
20
+ }
21
+ if (isSet(req.session.darkMode)) req.darkMode = req.session.darkMode
22
+ }
23
+
24
+ const waibuMpaPreParsing = {
2
25
  level: 9,
3
- handler: async function (ctx, req, reply) {
26
+ handler: async function (req, reply) {
4
27
  const { importModule } = this.app.bajo
5
28
  const attachI18N = await importModule('waibu:/lib/webapp-scope/attach-i18n.js')
6
29
  await attachI18N.call(this, this.config.i18n.detectors, req, reply)
7
- // darkmode
8
- // if (this.config.darkMode.qsKey) req.dark = req.query[this.config.darkMode.qsKey] ? 'dark' : 'light'
30
+ await checkLang.call(this, req, reply)
31
+ await checkDark.call(this, req, reply)
9
32
  }
10
33
  }
11
34
 
12
- export default waibuMpaPreHandler
35
+ export default waibuMpaPreParsing
package/bajo/init.js ADDED
@@ -0,0 +1,7 @@
1
+ async function init () {
2
+ const { trim } = this.app.bajo.lib._
3
+ this.config.waibu = this.config.waibu ?? {}
4
+ this.config.waibu.prefix = trim(this.config.waibu.prefix, '/')
5
+ }
6
+
7
+ export default init
@@ -1,6 +1,8 @@
1
1
  function attrToArray (text = '', delimiter = ' ') {
2
- const { map, trim, without } = this.app.bajo.lib._
3
- return without(map(text.split(delimiter), i => trim(i)), '')
2
+ const { map, trim, without, isArray } = this.app.bajo.lib._
3
+ if (text === true) text = ''
4
+ if (isArray(text)) text = text.join(delimiter)
5
+ return without(map(text.split(delimiter), i => trim(i)), '', undefined, null)
4
6
  }
5
7
 
6
8
  export default attrToArray
@@ -1,6 +1,8 @@
1
1
  function attrToObject (text = '', delimiter = ';', kvDelimiter = ':') {
2
- const { camelCase } = this.app.bajo.lib._
2
+ const { camelCase, isPlainObject } = this.app.bajo.lib._
3
3
  const result = {}
4
+ if (isPlainObject(text)) text = this.objectToAttr(text)
5
+ if (text.slice(1, 3) === '%=') return text
4
6
  const array = this.attrToArray(text, delimiter)
5
7
  array.forEach(item => {
6
8
  const [key, val] = this.attrToArray(item, kvDelimiter)
@@ -0,0 +1,28 @@
1
+ function attribsParse (text = '', delimiter = ' ', kvDelimiter = '=', camelCasedKey = true) {
2
+ const { trim, camelCase, map, isPlainObject, forOwn } = this.app.bajo.lib._
3
+ let attrs = []
4
+ if (isPlainObject(text)) {
5
+ forOwn(text, (v, k) => {
6
+ attrs.push(`${k}${kvDelimiter}"${v}"`)
7
+ })
8
+ } else attrs = map(text.split(delimiter), t => trim(t))
9
+ const result = {}
10
+ for (const attr of attrs) {
11
+ let [k, ...v] = map(attr.split(kvDelimiter), a => trim(a))
12
+ v = v.join(kvDelimiter)
13
+ v = v.slice(1, v.length - 1)
14
+ if (v === 'undefined') continue
15
+ if (k !== 'content' && v === '') v = true
16
+ // check for retainAttrKey on ALL plugins
17
+ let retain = false
18
+ for (const name of this.app.bajo.pluginNames) {
19
+ const plugin = this.app[name]
20
+ if (plugin && plugin.retainAttrKey && plugin.retainAttrKey(k)) retain = true
21
+ }
22
+ if (!retain && camelCasedKey) k = camelCase(k)
23
+ result[k] = v
24
+ }
25
+ return result
26
+ }
27
+
28
+ export default attribsParse
@@ -0,0 +1,27 @@
1
+ function attribsStringify (obj = {}, kebabCasedKey = true) {
2
+ const { isSet } = this.app.bajo
3
+ const { forOwn, kebabCase, isArray, isPlainObject, isEmpty } = this.app.bajo.lib._
4
+ const attrs = []
5
+ forOwn(obj, (v, k) => {
6
+ let retain = false
7
+ for (const name of this.app.bajo.pluginNames) {
8
+ const plugin = this.app[name]
9
+ if (plugin && plugin.retainAttrKey && plugin.retainAttrKey(k)) retain = true
10
+ }
11
+ if (retain) {
12
+ if (v === true) attrs.push(k)
13
+ else attrs.push(`${k}="${v}"`)
14
+ return undefined
15
+ }
16
+ if (kebabCasedKey) k = kebabCase(k)
17
+ if (!isSet(v)) return undefined
18
+ if (['class', 'style'].includes(k) && isEmpty(v)) return undefined
19
+ if (isArray(v)) v = this.arrayToAttr(v)
20
+ if (isPlainObject(v)) v = this.objectToAttr(v)
21
+ if (k !== 'content' && v === true) attrs.push(k)
22
+ else attrs.push(`${k}="${v}"`)
23
+ })
24
+ return attrs.join(' ')
25
+ }
26
+
27
+ export default attribsStringify
@@ -0,0 +1,5 @@
1
+ function base64JsonDecode (data = 'e30=') {
2
+ return JSON.parse(Buffer.from(data, 'base64'))
3
+ }
4
+
5
+ export default base64JsonDecode
@@ -0,0 +1,5 @@
1
+ function base64JsonEncode (data) {
2
+ return Buffer.from(JSON.stringify(data)).toString('base64')
3
+ }
4
+
5
+ export default base64JsonEncode
@@ -0,0 +1,27 @@
1
+ function buildUrl ({ exclude = [], prefix = '?', base, url = '', params = {} }) {
2
+ const { qs } = this.app.waibu
3
+ const { forOwn, omit, isEmpty } = this.app.bajo.lib._
4
+ const qsKey = this.app.waibu.config.qsKey
5
+ let path
6
+ let hash
7
+ let query
8
+ [path = '', hash = ''] = url.split('#')
9
+ if (hash.includes('?')) [hash, query] = hash.split('?')
10
+ else [path, query] = path.split('?')
11
+ query = qs.parse(query) ?? {}
12
+ forOwn(params, (v, k) => {
13
+ const key = qsKey[k] ?? k
14
+ query[key] = v
15
+ })
16
+ query = prefix + qs.stringify(omit(query, exclude))
17
+ if (!isEmpty(hash)) hash = '#' + hash
18
+ if (!base) return path + query + hash
19
+ const parts = path.split('/')
20
+ if (base) {
21
+ parts.pop()
22
+ parts.push(base)
23
+ }
24
+ return parts.join('/') + query + hash
25
+ }
26
+
27
+ export default buildUrl
@@ -0,0 +1,9 @@
1
+ function getAppTitle (name) {
2
+ const { getPlugin } = this.app.bajo
3
+ const { get } = this.app.bajo.lib._
4
+ const plugin = getPlugin(name, true)
5
+ if (!plugin) return
6
+ return get(plugin, 'config.waibu.title', plugin.title)
7
+ }
8
+
9
+ export default getAppTitle
@@ -0,0 +1,12 @@
1
+ const subNses = ['layout', 'template', 'partial']
2
+
3
+ function getResource (name) {
4
+ const { ns, path, subNs, subSubNs, qs } = this.app.bajo.breakNsPath(name)
5
+ const plugin = this.app.bajo.getPlugin(ns)
6
+ const dir = `${plugin.dir.pkg}/waibuMpa`
7
+ if (!subNses.includes(subNs)) throw this.error('Unknown resource \'%s\'', name)
8
+ const fullPath = subSubNs ? `${dir}/${subSubNs}/${subNs}${path}` : `${dir}/${subNs}${path}`
9
+ return { ns, subNs, subSubNs, path, qs, fullPath }
10
+ }
11
+
12
+ export default getResource
@@ -0,0 +1,45 @@
1
+ function groupAttrs (attribs = {}, keys = [], removeEmpty = true) {
2
+ const { isString, filter, omit, kebabCase, camelCase, isEmpty } = this.app.bajo.lib._
3
+ if (isString(keys)) keys = [keys]
4
+ const attr = { _: {} }
5
+ for (const a in attribs) {
6
+ for (const k of keys) {
7
+ if (a === k) {
8
+ attr._[k] = attribs[a]
9
+ continue
10
+ }
11
+ attr[k] = attr[k] ?? {}
12
+ attr[k].class = attr[k].class ?? []
13
+ attr[k].style = attr[k].style ?? {}
14
+ const _k = kebabCase(k)
15
+ const name = camelCase(kebabCase(a).slice(_k.length + 1))
16
+ if (!kebabCase(a).startsWith(k + '-')) {
17
+ if (!keys.includes(a)) {
18
+ attr._[a] = attribs[a]
19
+ if (a === 'class' && isString(attribs[a])) attr._.class = this.attrToArray(attr._.class)
20
+ if (a === 'style' && isString(attribs[a])) attr._.style = this.attrToObject(attr._.style)
21
+ }
22
+ continue
23
+ }
24
+ attr[k][name] = attribs[a]
25
+ if (name === 'class' && isString(attribs[a])) attr[k].class = this.attrToArray(attr[k].class)
26
+ if (name === 'style' && isString(attribs[a])) attr[k].style = this.attrToObject(attr[k].style)
27
+ }
28
+ }
29
+ const deleted = filter(Object.keys(attr._), m => {
30
+ let match
31
+ m = kebabCase(m)
32
+ for (const k of keys) {
33
+ if (m.startsWith(k + '-')) match = true
34
+ }
35
+ return match
36
+ })
37
+ attr._ = omit(attr._, deleted)
38
+ for (const k of keys) {
39
+ const item = attr[k]
40
+ if (removeEmpty && !attr._[k] && Object.keys(item).length === 2 && isEmpty(item.class) && isEmpty(item.style)) delete attr[k]
41
+ }
42
+ return attr
43
+ }
44
+
45
+ export default groupAttrs
@@ -0,0 +1,6 @@
1
+ // taken from: https://stackoverflow.com/questions/52928550/js-get-list-of-all-available-standard-html-tags
2
+
3
+ const tags = 'a,abbr,address,area,article,aside,audio,b,base,bdi,bdo,blockquote,body,br,button,canvas,caption,cite,code,col,colgroup,data,datalist,dd,del,details,dfn,dialog,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,i,iframe,img,input,ins,kbd,label,legend,li,link,main,map,mark,menu,meta,meter,nav,noscript,object,ol,optgroup,option,output,p,param,picture,pre,progress,q,rp,rt,ruby,s,samp,script,section,select,slot,small,source,span,strong,style,sub,summary,sup,table,tbody,td,template,textarea,tfoot,th,thead,time,title,tr,track,u,ul,var,video,wbr'
4
+ const htmlTags = tags.split(',')
5
+
6
+ export default htmlTags