odac 0.9.0 → 1.0.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.
Files changed (208) hide show
  1. package/.github/workflows/auto-pr-description.yml +0 -2
  2. package/.github/workflows/codeql.yml +46 -0
  3. package/.github/workflows/release.yml +13 -6
  4. package/.github/workflows/test-coverage.yml +10 -9
  5. package/.releaserc.js +9 -6
  6. package/CHANGELOG.md +62 -150
  7. package/CODE_OF_CONDUCT.md +1 -1
  8. package/CONTRIBUTING.md +8 -8
  9. package/LICENSE +21 -661
  10. package/README.md +12 -12
  11. package/SECURITY.md +4 -4
  12. package/bin/odac.js +101 -0
  13. package/{framework/web/candy.js → client/odac.js} +310 -44
  14. package/docs/backend/01-overview/{01-whats-in-the-candy-box.md → 01-whats-in-the-odac-box.md} +4 -2
  15. package/docs/backend/01-overview/02-super-handy-helper-functions.md +29 -1
  16. package/docs/backend/01-overview/03-development-server.md +11 -11
  17. package/docs/backend/02-structure/01-typical-project-layout.md +4 -4
  18. package/docs/backend/03-config/00-configuration-overview.md +6 -6
  19. package/docs/backend/03-config/01-database-connection.md +1 -1
  20. package/docs/backend/03-config/02-static-route-mapping-optional.md +4 -4
  21. package/docs/backend/03-config/04-environment-variables.md +20 -20
  22. package/docs/backend/03-config/05-early-hints.md +4 -4
  23. package/docs/backend/04-routing/01-basic-page-routes.md +4 -4
  24. package/docs/backend/04-routing/02-controller-less-view-routes.md +5 -5
  25. package/docs/backend/04-routing/03-api-and-data-routes.md +3 -3
  26. package/docs/backend/04-routing/04-authentication-aware-routes.md +5 -5
  27. package/docs/backend/04-routing/05-advanced-routing.md +3 -3
  28. package/docs/backend/04-routing/06-error-pages.md +17 -17
  29. package/docs/backend/04-routing/07-cron-jobs.md +13 -13
  30. package/docs/backend/04-routing/08-middleware.md +214 -0
  31. package/docs/backend/04-routing/09-websocket-auth-middleware.md +292 -0
  32. package/docs/backend/04-routing/09-websocket-examples.md +381 -0
  33. package/docs/backend/04-routing/09-websocket-quick-reference.md +211 -0
  34. package/docs/backend/04-routing/09-websocket.md +298 -0
  35. package/docs/backend/05-controllers/01-how-to-build-a-controller.md +3 -3
  36. package/docs/backend/05-controllers/02-your-trusty-odac-assistant.md +41 -0
  37. package/docs/backend/05-controllers/03-controller-classes.md +19 -19
  38. package/docs/backend/05-forms/01-custom-forms.md +114 -114
  39. package/docs/backend/05-forms/02-automatic-database-insert.md +82 -82
  40. package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +26 -26
  41. package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +10 -10
  42. package/docs/backend/07-views/01-the-view-directory.md +1 -1
  43. package/docs/backend/07-views/02-rendering-a-view.md +22 -22
  44. package/docs/backend/07-views/03-template-syntax.md +52 -52
  45. package/docs/backend/07-views/03-variables.md +84 -84
  46. package/docs/backend/07-views/04-request-data.md +57 -57
  47. package/docs/backend/07-views/05-conditionals.md +78 -78
  48. package/docs/backend/07-views/06-loops.md +114 -114
  49. package/docs/backend/07-views/07-translations.md +66 -66
  50. package/docs/backend/07-views/08-backend-javascript.md +103 -103
  51. package/docs/backend/07-views/09-comments.md +71 -71
  52. package/docs/backend/08-database/01-database-connection.md +8 -8
  53. package/docs/backend/08-database/02-using-mysql.md +49 -49
  54. package/docs/backend/09-validation/01-the-validator-service.md +38 -38
  55. package/docs/backend/10-authentication/01-user-logins-with-authjs.md +15 -15
  56. package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +10 -10
  57. package/docs/backend/10-authentication/03-register.md +12 -12
  58. package/docs/backend/10-authentication/{04-candy-register-forms.md → 04-odac-register-forms.md} +141 -141
  59. package/docs/backend/10-authentication/05-session-management.md +10 -10
  60. package/docs/backend/10-authentication/{06-candy-login-forms.md → 06-odac-login-forms.md} +125 -125
  61. package/docs/backend/11-mail/01-the-mail-service.md +5 -5
  62. package/docs/backend/12-streaming/01-streaming-overview.md +96 -54
  63. package/docs/backend/13-utilities/{01-candy-var.md → 01-odac-var.md} +109 -109
  64. package/docs/frontend/01-overview/01-introduction.md +30 -30
  65. package/docs/frontend/02-ajax-navigation/01-quick-start.md +45 -45
  66. package/docs/frontend/02-ajax-navigation/02-configuration.md +14 -14
  67. package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +36 -36
  68. package/docs/frontend/03-forms/01-form-handling.md +32 -32
  69. package/docs/frontend/04-api-requests/01-get-post.md +33 -33
  70. package/docs/frontend/05-streaming/01-client-streaming.md +15 -15
  71. package/docs/frontend/06-websocket/00-overview.md +76 -0
  72. package/docs/frontend/06-websocket/01-websocket-client.md +139 -0
  73. package/docs/frontend/06-websocket/02-shared-websocket.md +149 -0
  74. package/docs/index.json +49 -11
  75. package/eslint.config.mjs +6 -6
  76. package/{framework/index.js → index.js} +1 -1
  77. package/package.json +14 -39
  78. package/{framework/src → src}/Auth.js +59 -59
  79. package/{framework/src → src}/Config.js +3 -3
  80. package/{framework/src → src}/Lang.js +7 -7
  81. package/{framework/src → src}/Mail.js +5 -5
  82. package/{framework/src → src}/Mysql.js +42 -42
  83. package/src/Odac.js +112 -0
  84. package/{framework/src → src}/Request.js +38 -36
  85. package/{framework/src → src}/Route/Internal.js +116 -116
  86. package/src/Route/Middleware.js +75 -0
  87. package/src/Route.js +621 -0
  88. package/src/Server.js +22 -0
  89. package/{framework/src → src}/Stream.js +11 -3
  90. package/{framework/src → src}/Validator.js +21 -21
  91. package/{framework/src → src}/Var.js +5 -5
  92. package/{framework/src → src}/View/EarlyHints.js +1 -1
  93. package/{framework/src → src}/View/Form.js +69 -69
  94. package/{framework/src → src}/View.js +78 -81
  95. package/src/WebSocket.js +403 -0
  96. package/template/config.json +5 -0
  97. package/{web → template}/controller/page/about.js +6 -6
  98. package/{web → template}/controller/page/index.js +9 -9
  99. package/{web → template}/package.json +4 -5
  100. package/{web → template}/public/assets/css/style.css +4 -4
  101. package/{web → template}/public/assets/js/app.js +6 -6
  102. package/{web → template}/route/www.js +6 -6
  103. package/{web → template}/skeleton/main.html +1 -1
  104. package/{web → template}/view/content/about.html +5 -5
  105. package/{web → template}/view/content/home.html +12 -12
  106. package/template/view/footer/main.html +11 -0
  107. package/{web → template}/view/head/main.html +1 -1
  108. package/{web → template}/view/header/main.html +2 -2
  109. package/test/core/Candy.test.js +58 -58
  110. package/test/core/Commands.test.js +7 -7
  111. package/test/core/Config.test.js +82 -85
  112. package/test/core/Lang.test.js +2 -2
  113. package/test/core/Process.test.js +6 -6
  114. package/test/framework/Route.test.js +56 -37
  115. package/test/framework/View/EarlyHints.test.js +2 -2
  116. package/test/framework/WebSocket.test.js +100 -0
  117. package/test/framework/middleware.test.js +85 -0
  118. package/test/server/Api.test.js +31 -31
  119. package/test/server/DNS.test.js +11 -11
  120. package/test/server/Hub.test.js +497 -0
  121. package/test/server/Mail.account.test_.js +3 -3
  122. package/test/server/Mail.init.test_.js +10 -10
  123. package/test/server/Mail.test_.js +20 -20
  124. package/test/server/SSL.test_.js +54 -54
  125. package/test/server/Server.test.js +39 -39
  126. package/test/server/Service.test_.js +7 -7
  127. package/test/server/Subdomain.test.js +7 -7
  128. package/test/server/Web/Firewall.test.js +87 -87
  129. package/test/server/Web/Proxy.test.js +397 -0
  130. package/test/server/{Web.test_.js → Web.test.js} +137 -205
  131. package/test/server/__mocks__/fs.js +2 -2
  132. package/test/server/__mocks__/{globalCandy.js → globalOdac.js} +5 -5
  133. package/test/server/__mocks__/index.js +6 -6
  134. package/test/server/__mocks__/testFactories.js +1 -1
  135. package/test/server/__mocks__/testHelpers.js +7 -7
  136. package/.husky/pre-commit +0 -2
  137. package/.kiro/steering/code-style.md +0 -56
  138. package/.kiro/steering/product.md +0 -20
  139. package/.kiro/steering/structure.md +0 -77
  140. package/.kiro/steering/tech.md +0 -87
  141. package/AGENTS.md +0 -84
  142. package/bin/candy +0 -10
  143. package/bin/candypack +0 -10
  144. package/cli/index.js +0 -3
  145. package/cli/src/Cli.js +0 -348
  146. package/cli/src/Connector.js +0 -93
  147. package/cli/src/Monitor.js +0 -416
  148. package/core/Candy.js +0 -87
  149. package/core/Commands.js +0 -239
  150. package/core/Config.js +0 -1094
  151. package/core/Lang.js +0 -52
  152. package/core/Log.js +0 -43
  153. package/core/Process.js +0 -26
  154. package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +0 -20
  155. package/docs/server/01-installation/01-quick-install.md +0 -19
  156. package/docs/server/01-installation/02-manual-installation-via-npm.md +0 -9
  157. package/docs/server/02-get-started/01-core-concepts.md +0 -7
  158. package/docs/server/02-get-started/02-basic-commands.md +0 -57
  159. package/docs/server/02-get-started/03-cli-reference.md +0 -276
  160. package/docs/server/02-get-started/04-cli-quick-reference.md +0 -102
  161. package/docs/server/03-service/01-start-a-new-service.md +0 -57
  162. package/docs/server/03-service/02-delete-a-service.md +0 -48
  163. package/docs/server/04-web/01-create-a-website.md +0 -36
  164. package/docs/server/04-web/02-list-websites.md +0 -9
  165. package/docs/server/04-web/03-delete-a-website.md +0 -29
  166. package/docs/server/05-subdomain/01-create-a-subdomain.md +0 -32
  167. package/docs/server/05-subdomain/02-list-subdomains.md +0 -33
  168. package/docs/server/05-subdomain/03-delete-a-subdomain.md +0 -41
  169. package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +0 -34
  170. package/docs/server/07-mail/01-create-a-mail-account.md +0 -23
  171. package/docs/server/07-mail/02-delete-a-mail-account.md +0 -20
  172. package/docs/server/07-mail/03-list-mail-accounts.md +0 -20
  173. package/docs/server/07-mail/04-change-account-password.md +0 -23
  174. package/framework/src/Candy.js +0 -81
  175. package/framework/src/Route.js +0 -455
  176. package/framework/src/Server.js +0 -15
  177. package/locale/de-DE.json +0 -80
  178. package/locale/en-US.json +0 -79
  179. package/locale/es-ES.json +0 -80
  180. package/locale/fr-FR.json +0 -80
  181. package/locale/pt-BR.json +0 -80
  182. package/locale/ru-RU.json +0 -80
  183. package/locale/tr-TR.json +0 -85
  184. package/locale/zh-CN.json +0 -80
  185. package/server/index.js +0 -5
  186. package/server/src/Api.js +0 -88
  187. package/server/src/DNS.js +0 -940
  188. package/server/src/Hub.js +0 -535
  189. package/server/src/Mail.js +0 -571
  190. package/server/src/SSL.js +0 -180
  191. package/server/src/Server.js +0 -27
  192. package/server/src/Service.js +0 -248
  193. package/server/src/Subdomain.js +0 -64
  194. package/server/src/Web/Firewall.js +0 -170
  195. package/server/src/Web/Proxy.js +0 -134
  196. package/server/src/Web.js +0 -451
  197. package/server/src/mail/imap.js +0 -1091
  198. package/server/src/mail/server.js +0 -32
  199. package/server/src/mail/smtp.js +0 -786
  200. package/test/server/Client.test.js +0 -338
  201. package/test/server/__mocks__/http-proxy.js +0 -105
  202. package/watchdog/index.js +0 -3
  203. package/watchdog/src/Watchdog.js +0 -156
  204. package/web/config.json +0 -5
  205. package/web/view/footer/main.html +0 -11
  206. /package/{framework/src → src}/Env.js +0 -0
  207. /package/{framework/src → src}/Route/Cron.js +0 -0
  208. /package/{framework/src → src}/Token.js +0 -0
@@ -53,7 +53,7 @@ class Validator {
53
53
  result.result.message = message ?? ''
54
54
  result.data = data ?? null
55
55
  } else {
56
- result.errors = this.#message['_candy_form'] ? {_candy_form: this.#message['_candy_form']} : this.#message
56
+ result.errors = this.#message['_odac_form'] ? {_odac_form: this.#message['_odac_form']} : this.#message
57
57
  }
58
58
  return result
59
59
  }
@@ -98,37 +98,37 @@ class Validator {
98
98
  error = !value || (value !== 1 && value !== '1' && value !== 'on' && value !== 'yes' && value !== true)
99
99
  break
100
100
  case 'numeric':
101
- error = value && value !== '' && !Candy.Var(value).is('numeric')
101
+ error = value && value !== '' && !Odac.Var(value).is('numeric')
102
102
  break
103
103
  case 'alpha':
104
- error = value && value !== '' && !Candy.Var(value).is('alpha')
104
+ error = value && value !== '' && !Odac.Var(value).is('alpha')
105
105
  break
106
106
  case 'alphaspace':
107
- error = value && value !== '' && !Candy.Var(value).is('alphaspace')
107
+ error = value && value !== '' && !Odac.Var(value).is('alphaspace')
108
108
  break
109
109
  case 'alphanumeric':
110
- error = value && value !== '' && !Candy.Var(value).is('alphanumeric')
110
+ error = value && value !== '' && !Odac.Var(value).is('alphanumeric')
111
111
  break
112
112
  case 'alphanumericspace':
113
- error = value && value !== '' && !Candy.Var(value).is('alphanumericspace')
113
+ error = value && value !== '' && !Odac.Var(value).is('alphanumericspace')
114
114
  break
115
115
  case 'email':
116
- error = value && value !== '' && !Candy.Var(value).is('email')
116
+ error = value && value !== '' && !Odac.Var(value).is('email')
117
117
  break
118
118
  case 'ip':
119
- error = value && value !== '' && !Candy.Var(value).is('ip')
119
+ error = value && value !== '' && !Odac.Var(value).is('ip')
120
120
  break
121
121
  case 'float':
122
- error = value && value !== '' && !Candy.Var(value).is('float')
122
+ error = value && value !== '' && !Odac.Var(value).is('float')
123
123
  break
124
124
  case 'mac':
125
- error = value && value !== '' && !Candy.Var(value).is('mac')
125
+ error = value && value !== '' && !Odac.Var(value).is('mac')
126
126
  break
127
127
  case 'domain':
128
- error = value && value !== '' && !Candy.Var(value).is('domain')
128
+ error = value && value !== '' && !Odac.Var(value).is('domain')
129
129
  break
130
130
  case 'url':
131
- error = value && value !== '' && !Candy.Var(value).is('url')
131
+ error = value && value !== '' && !Odac.Var(value).is('url')
132
132
  break
133
133
  case 'username':
134
134
  error = value && value !== '' && !/^[a-zA-Z0-9]+$/.test(value)
@@ -137,7 +137,7 @@ class Validator {
137
137
  error = value && value !== '' && /<[^>]*>/g.test(value)
138
138
  break
139
139
  case 'usercheck':
140
- error = !(await Candy.Auth.check())
140
+ error = !(await Odac.Auth.check())
141
141
  break
142
142
  case 'array':
143
143
  error = value && !Array.isArray(value)
@@ -192,12 +192,12 @@ class Validator {
192
192
  error = value && value !== '' && vars[1] && !new RegExp(vars[1]).test(value)
193
193
  break
194
194
  case 'user': {
195
- if (!(await Candy.Auth.check())) {
195
+ if (!(await Odac.Auth.check())) {
196
196
  error = true
197
197
  } else {
198
- const userData = Candy.Auth.user(vars[1])
199
- if (Candy.Var(userData).is('bcrypt')) {
200
- error = !Candy.Var(userData).hashCheck(value)
198
+ const userData = Odac.Auth.user(vars[1])
199
+ if (Odac.Var(userData).is('bcrypt')) {
200
+ error = !Odac.Var(userData).hashCheck(value)
201
201
  } else {
202
202
  error = value !== userData
203
203
  }
@@ -243,10 +243,10 @@ class Validator {
243
243
  const ip = this.#request.ip()
244
244
  const now = new Date().toISOString().slice(0, 13).replace(/[-:T]/g, '')
245
245
  const page = this.#request.path()
246
- const storage = Candy.storage('sys')
246
+ const storage = Odac.storage('sys')
247
247
  const validation = storage.get('validation') || {}
248
248
 
249
- this.#name = '_candy_form'
249
+ this.#name = '_odac_form'
250
250
 
251
251
  if (Object.keys(this.#message).length > 0) {
252
252
  if (!validation.brute) validation.brute = {}
@@ -257,8 +257,8 @@ class Validator {
257
257
  validation.brute[now][page][ip]++
258
258
 
259
259
  if (validation.brute[now][page][ip] >= maxAttempts) {
260
- this.#message['_candy_form'] = Candy.Lang
261
- ? Candy.Lang.get('Too many failed attempts. Please try again later.')
260
+ this.#message['_odac_form'] = Odac.Lang
261
+ ? Odac.Lang.get('Too many failed attempts. Please try again later.')
262
262
  : 'Too many failed attempts. Please try again later.'
263
263
  }
264
264
  }
@@ -44,7 +44,7 @@ class Var {
44
44
  let hour = date.getHours()
45
45
  let minute = date.getMinutes()
46
46
  let second = date.getSeconds()
47
- return Candy.Var(format).replace({
47
+ return Odac.Var(format).replace({
48
48
  Y: year,
49
49
  m: month < 10 ? `0${month}` : month,
50
50
  d: day < 10 ? `0${day}` : day,
@@ -56,7 +56,7 @@ class Var {
56
56
  }
57
57
 
58
58
  decrypt(key) {
59
- if (!key) key = Candy.Config.encrypt.key
59
+ if (!key) key = Odac.Config.encrypt.key
60
60
  const iv = '2dea8a25e5e8f004'
61
61
  try {
62
62
  const encryptedText = Buffer.from(this.#value, 'base64')
@@ -71,7 +71,7 @@ class Var {
71
71
  }
72
72
 
73
73
  encrypt(key) {
74
- if (!key) key = Candy.Config.encrypt.key
74
+ if (!key) key = Odac.Config.encrypt.key
75
75
  const iv = '2dea8a25e5e8f004'
76
76
  const cipher = nodeCrypto.createCipheriv('aes-256-cbc', key, iv)
77
77
  let encrypted = cipher.update(this.#value)
@@ -97,7 +97,7 @@ class Var {
97
97
  let any = this.#any
98
98
  this.#any = false
99
99
  let result = !any
100
- // if(\Candy::config('locale')->get() == 'tr') $this->str = \Candy::var($this->str)->clear('Ç','ç','Ğ','ğ','İ','ı','Ö','ö','Ş','ş','Ü','ü');
100
+ // if(\Odac::config('locale')->get() == 'tr') $this->str = \Odac::var($this->str)->clear('Ç','ç','Ğ','ğ','İ','ı','Ö','ö','Ş','ş','Ü','ü');
101
101
  if (args.includes('alpha')) result = (result || any) && ((any && result) || /^[A-Za-z]+$/.test(this.#value))
102
102
  if (args.includes('alphaspace')) result = (result || any) && ((any && result) || /^[A-Za-z\s]+$/.test(this.#value))
103
103
  if (args.includes('alphanumeric')) result = (result || any) && ((any && result) || /^[A-Za-z0-9]+$/.test(this.#value))
@@ -160,7 +160,7 @@ class Var {
160
160
  if (args.length == 1) args = args[0]
161
161
  if (['array', 'object'].includes(typeof this.#value)) {
162
162
  let new_value = {}
163
- for (const key of Object.keys(this.#value)) new_value[key] = Candy.Var(this.#value[key]).replace(args)
163
+ for (const key of Object.keys(this.#value)) new_value[key] = Odac.Var(this.#value[key]).replace(args)
164
164
  return new_value
165
165
  }
166
166
  for (const arg of Object.keys(args)) this.#value = this.#value.replace(arg, args[arg])
@@ -178,7 +178,7 @@ class EarlyHints {
178
178
  res.writeEarlyHints({link: links})
179
179
  }
180
180
 
181
- res.setHeader('X-Candy-Early-Hints', JSON.stringify(links))
181
+ res.setHeader('X-Odac-Early-Hints', JSON.stringify(links))
182
182
 
183
183
  return true
184
184
  } catch {
@@ -3,15 +3,15 @@ const nodeCrypto = require('crypto')
3
3
  class Form {
4
4
  static FORM_TYPES = ['register', 'login', 'form']
5
5
 
6
- static parse(content, Candy) {
6
+ static parse(content, Odac) {
7
7
  for (const type of this.FORM_TYPES) {
8
- content = this.parseFormType(content, Candy, type)
8
+ content = this.parseFormType(content, Odac, type)
9
9
  }
10
10
  return content
11
11
  }
12
12
 
13
- static parseFormType(content, Candy, type) {
14
- const regex = new RegExp(`<candy:${type}[\\s\\S]*?<\\/candy:${type}>`, 'g')
13
+ static parseFormType(content, Odac, type) {
14
+ const regex = new RegExp(`<odac:${type}[\\s\\S]*?<\\/odac:${type}>`, 'g')
15
15
  const matches = content.match(regex)
16
16
  if (!matches) return content
17
17
 
@@ -19,7 +19,7 @@ class Form {
19
19
  const formToken = nodeCrypto.randomBytes(32).toString('hex')
20
20
  const formConfig = this.extractConfig(match, formToken, type)
21
21
 
22
- this.storeConfig(formToken, formConfig, Candy, type)
22
+ this.storeConfig(formToken, formConfig, Odac, type)
23
23
 
24
24
  const generatedForm = this.generateForm(match, formConfig, formToken, type)
25
25
  content = content.replace(match, generatedForm)
@@ -38,13 +38,13 @@ class Form {
38
38
  }
39
39
  }
40
40
 
41
- static storeConfig(token, config, Candy, type) {
41
+ static storeConfig(token, config, Odac, type) {
42
42
  if (type === 'register') {
43
- this.storeRegisterConfig(token, config, Candy)
43
+ this.storeRegisterConfig(token, config, Odac)
44
44
  } else if (type === 'login') {
45
- this.storeLoginConfig(token, config, Candy)
45
+ this.storeLoginConfig(token, config, Odac)
46
46
  } else if (type === 'form') {
47
- this.storeFormConfig(token, config, Candy)
47
+ this.storeFormConfig(token, config, Odac)
48
48
  }
49
49
  }
50
50
 
@@ -69,7 +69,7 @@ class Form {
69
69
  sets: []
70
70
  }
71
71
 
72
- const registerMatch = html.match(/<candy:register([^>]*)>/)
72
+ const registerMatch = html.match(/<odac:register([^>]*)>/)
73
73
  if (!registerMatch) return config
74
74
 
75
75
  const registerTag = registerMatch[0]
@@ -79,7 +79,7 @@ class Form {
79
79
  if (redirectMatch) config.redirect = redirectMatch[1]
80
80
  if (autologinMatch) config.autologin = autologinMatch[1] !== 'false'
81
81
 
82
- const submitMatch = html.match(/<candy:submit([^>/]*)(?:\/?>|>(.*?)<\/candy:submit>)/)
82
+ const submitMatch = html.match(/<odac:submit([^>/]*)(?:\/?>|>(.*?)<\/odac:submit>)/)
83
83
  if (submitMatch) {
84
84
  const submitTag = submitMatch[1]
85
85
  const textMatch = submitTag.match(/text=["']([^"']+)["']/)
@@ -97,7 +97,7 @@ class Form {
97
97
  if (idMatch) config.submitId = idMatch[1]
98
98
  }
99
99
 
100
- const fieldMatches = html.match(/<candy:field[\s\S]*?<\/candy:field>/g)
100
+ const fieldMatches = html.match(/<odac:field[\s\S]*?<\/odac:field>/g)
101
101
  if (fieldMatches) {
102
102
  for (const fieldHtml of fieldMatches) {
103
103
  const field = this.parseField(fieldHtml)
@@ -105,7 +105,7 @@ class Form {
105
105
  }
106
106
  }
107
107
 
108
- const setMatches = html.match(/<candy:set[^>]*\/?>/g)
108
+ const setMatches = html.match(/<odac:set[^>]*\/?>/g)
109
109
  if (setMatches) {
110
110
  for (const setTag of setMatches) {
111
111
  const set = this.parseSet(setTag)
@@ -117,7 +117,7 @@ class Form {
117
117
  }
118
118
 
119
119
  static parseField(html) {
120
- const fieldTagMatch = html.match(/<candy:field([^>]*?)(?:\/>|>)/)
120
+ const fieldTagMatch = html.match(/<odac:field([^>]*?)(?:\/>|>)/)
121
121
  if (!fieldTagMatch) return null
122
122
 
123
123
  const fieldTag = fieldTagMatch[0]
@@ -152,7 +152,7 @@ class Form {
152
152
  if (uniqueMatch) field.unique = uniqueMatch[1] !== 'false'
153
153
  if (skipMatch) field.skip = skipMatch[1] !== 'false'
154
154
 
155
- const validateMatches = html.match(/<candy:validate[^>]*>/g)
155
+ const validateMatches = html.match(/<odac:validate[^>]*>/g)
156
156
  if (validateMatches) {
157
157
  for (const validateTag of validateMatches) {
158
158
  const ruleMatch = validateTag.match(/rule=["']([^"']+)["']/)
@@ -195,36 +195,36 @@ class Form {
195
195
  return set
196
196
  }
197
197
 
198
- static storeRegisterConfig(token, config, Candy) {
199
- if (!Candy.View) Candy.View = {}
200
- if (!Candy.View.registerForms) Candy.View.registerForms = {}
198
+ static storeRegisterConfig(token, config, Odac) {
199
+ if (!Odac.View) Odac.View = {}
200
+ if (!Odac.View.registerForms) Odac.View.registerForms = {}
201
201
 
202
202
  const formData = {
203
203
  config: config,
204
204
  created: Date.now(),
205
205
  expires: Date.now() + 30 * 60 * 1000,
206
- sessionId: Candy.Request.session('_client'),
207
- userAgent: Candy.Request.header('user-agent'),
208
- ip: Candy.Request.ip
206
+ sessionId: Odac.Request.session('_client'),
207
+ userAgent: Odac.Request.header('user-agent'),
208
+ ip: Odac.Request.ip
209
209
  }
210
210
 
211
- Candy.View.registerForms[token] = formData
212
- Candy.Request.session(`_register_form_${token}`, formData)
211
+ Odac.View.registerForms[token] = formData
212
+ Odac.Request.session(`_register_form_${token}`, formData)
213
213
  }
214
214
 
215
215
  static generateRegisterForm(originalHtml, config, formToken) {
216
216
  const submitText = config.submitText || 'Register'
217
217
  const submitLoading = config.submitLoading || 'Processing...'
218
218
 
219
- let innerContent = originalHtml.replace(/<candy:register[^>]*>/, '').replace(/<\/candy:register>/, '')
219
+ let innerContent = originalHtml.replace(/<odac:register[^>]*>/, '').replace(/<\/odac:register>/, '')
220
220
 
221
- innerContent = innerContent.replace(/<candy:field[\s\S]*?<\/candy:field>/g, fieldMatch => {
221
+ innerContent = innerContent.replace(/<odac:field[\s\S]*?<\/odac:field>/g, fieldMatch => {
222
222
  const field = this.parseField(fieldMatch)
223
223
  if (!field) return fieldMatch
224
224
  return this.generateFieldHtml(field)
225
225
  })
226
226
 
227
- const submitMatch = innerContent.match(/<candy:submit[\s\S]*?(?:<\/candy:submit>|\/?>)/)
227
+ const submitMatch = innerContent.match(/<odac:submit[\s\S]*?(?:<\/odac:submit>|\/?>)/)
228
228
  if (submitMatch) {
229
229
  let submitAttrs = `type="submit" data-submit-text="${submitText}" data-loading-text="${submitLoading}"`
230
230
  if (config.submitClass) submitAttrs += ` class="${config.submitClass}"`
@@ -234,12 +234,12 @@ class Form {
234
234
  innerContent = innerContent.replace(submitMatch[0], submitButton)
235
235
  }
236
236
 
237
- innerContent = innerContent.replace(/<candy:set[^>]*\/?>/g, '')
237
+ innerContent = innerContent.replace(/<odac:set[^>]*\/?>/g, '')
238
238
 
239
- let html = `<form class="candy-register-form" data-candy-register="${formToken}" method="POST" action="/_candy/register" novalidate>\n`
240
- html += ` <input type="hidden" name="_candy_register_token" value="${formToken}">\n`
239
+ let html = `<form class="odac-register-form" data-odac-register="${formToken}" method="POST" action="/_odac/register" novalidate>\n`
240
+ html += ` <input type="hidden" name="_odac_register_token" value="${formToken}">\n`
241
241
  html += innerContent
242
- html += `\n <span class="candy-form-success" style="display:none;"></span>\n`
242
+ html += `\n <span class="odac-form-success" style="display:none;"></span>\n`
243
243
  html += `</form>`
244
244
 
245
245
  return html
@@ -249,12 +249,12 @@ class Form {
249
249
  let html = ''
250
250
 
251
251
  if (field.label && field.type !== 'checkbox') {
252
- const fieldId = field.id || `candy-${field.name}`
252
+ const fieldId = field.id || `odac-${field.name}`
253
253
  html += `<label for="${fieldId}">${field.label}</label>\n`
254
254
  }
255
255
 
256
256
  const classAttr = field.class ? ` class="${field.class}"` : ''
257
- const idAttr = field.id ? ` id="${field.id}"` : ` id="candy-${field.name}"`
257
+ const idAttr = field.id ? ` id="${field.id}"` : ` id="odac-${field.name}"`
258
258
 
259
259
  if (field.type === 'checkbox') {
260
260
  const attrs = this.buildHtml5Attributes(field)
@@ -375,7 +375,7 @@ class Form {
375
375
  fields: []
376
376
  }
377
377
 
378
- const loginMatch = html.match(/<candy:login([^>]*)>/)
378
+ const loginMatch = html.match(/<odac:login([^>]*)>/)
379
379
  if (!loginMatch) return config
380
380
 
381
381
  const loginTag = loginMatch[0]
@@ -383,7 +383,7 @@ class Form {
383
383
 
384
384
  if (redirectMatch) config.redirect = redirectMatch[1]
385
385
 
386
- const submitMatch = html.match(/<candy:submit([^>/]*)(?:\/?>|>(.*?)<\/candy:submit>)/)
386
+ const submitMatch = html.match(/<odac:submit([^>/]*)(?:\/?>|>(.*?)<\/odac:submit>)/)
387
387
  if (submitMatch) {
388
388
  const submitTag = submitMatch[1]
389
389
  const textMatch = submitTag.match(/text=["']([^"']+)["']/)
@@ -401,7 +401,7 @@ class Form {
401
401
  if (idMatch) config.submitId = idMatch[1]
402
402
  }
403
403
 
404
- const fieldMatches = html.match(/<candy:field[\s\S]*?<\/candy:field>/g)
404
+ const fieldMatches = html.match(/<odac:field[\s\S]*?<\/odac:field>/g)
405
405
  if (fieldMatches) {
406
406
  for (const fieldHtml of fieldMatches) {
407
407
  const field = this.parseField(fieldHtml)
@@ -412,36 +412,36 @@ class Form {
412
412
  return config
413
413
  }
414
414
 
415
- static storeLoginConfig(token, config, Candy) {
416
- if (!Candy.View) Candy.View = {}
417
- if (!Candy.View.loginForms) Candy.View.loginForms = {}
415
+ static storeLoginConfig(token, config, Odac) {
416
+ if (!Odac.View) Odac.View = {}
417
+ if (!Odac.View.loginForms) Odac.View.loginForms = {}
418
418
 
419
419
  const formData = {
420
420
  config: config,
421
421
  created: Date.now(),
422
422
  expires: Date.now() + 30 * 60 * 1000,
423
- sessionId: Candy.Request.session('_client'),
424
- userAgent: Candy.Request.header('user-agent'),
425
- ip: Candy.Request.ip
423
+ sessionId: Odac.Request.session('_client'),
424
+ userAgent: Odac.Request.header('user-agent'),
425
+ ip: Odac.Request.ip
426
426
  }
427
427
 
428
- Candy.View.loginForms[token] = formData
429
- Candy.Request.session(`_login_form_${token}`, formData)
428
+ Odac.View.loginForms[token] = formData
429
+ Odac.Request.session(`_login_form_${token}`, formData)
430
430
  }
431
431
 
432
432
  static generateLoginForm(originalHtml, config, formToken) {
433
433
  const submitText = config.submitText || 'Login'
434
434
  const submitLoading = config.submitLoading || 'Logging in...'
435
435
 
436
- let innerContent = originalHtml.replace(/<candy:login[^>]*>/, '').replace(/<\/candy:login>/, '')
436
+ let innerContent = originalHtml.replace(/<odac:login[^>]*>/, '').replace(/<\/odac:login>/, '')
437
437
 
438
- innerContent = innerContent.replace(/<candy:field[\s\S]*?<\/candy:field>/g, fieldMatch => {
438
+ innerContent = innerContent.replace(/<odac:field[\s\S]*?<\/odac:field>/g, fieldMatch => {
439
439
  const field = this.parseField(fieldMatch)
440
440
  if (!field) return fieldMatch
441
441
  return this.generateFieldHtml(field)
442
442
  })
443
443
 
444
- const submitMatch = innerContent.match(/<candy:submit[\s\S]*?(?:<\/candy:submit>|\/?>)/)
444
+ const submitMatch = innerContent.match(/<odac:submit[\s\S]*?(?:<\/odac:submit>|\/?>)/)
445
445
  if (submitMatch) {
446
446
  let submitAttrs = `type="submit" data-submit-text="${submitText}" data-loading-text="${submitLoading}"`
447
447
  if (config.submitClass) submitAttrs += ` class="${config.submitClass}"`
@@ -451,10 +451,10 @@ class Form {
451
451
  innerContent = innerContent.replace(submitMatch[0], submitButton)
452
452
  }
453
453
 
454
- let html = `<form class="candy-login-form" data-candy-login="${formToken}" method="POST" action="/_candy/login" novalidate>\n`
455
- html += ` <input type="hidden" name="_candy_login_token" value="${formToken}">\n`
454
+ let html = `<form class="odac-login-form" data-odac-login="${formToken}" method="POST" action="/_odac/login" novalidate>\n`
455
+ html += ` <input type="hidden" name="_odac_login_token" value="${formToken}">\n`
456
456
  html += innerContent
457
- html += `\n <span class="candy-form-success" style="display:none;"></span>\n`
457
+ html += `\n <span class="odac-form-success" style="display:none;"></span>\n`
458
458
  html += `</form>`
459
459
 
460
460
  return html
@@ -476,7 +476,7 @@ class Form {
476
476
  successMessage: null
477
477
  }
478
478
 
479
- const formMatch = html.match(/<candy:form([^>]*)>/)
479
+ const formMatch = html.match(/<odac:form([^>]*)>/)
480
480
  if (!formMatch) return config
481
481
 
482
482
  const formTag = formMatch[0]
@@ -501,7 +501,7 @@ class Form {
501
501
  if (redirectMatch) config.redirect = redirectMatch
502
502
  if (successMatch) config.successMessage = successMatch
503
503
 
504
- const submitMatch = html.match(/<candy:submit([^>/]*)(?:\/?>|>(.*?)<\/candy:submit>)/)
504
+ const submitMatch = html.match(/<odac:submit([^>/]*)(?:\/?>|>(.*?)<\/odac:submit>)/)
505
505
  if (submitMatch) {
506
506
  const submitTag = submitMatch[1]
507
507
  const textMatch = submitTag.match(/text=["']([^"']+)["']/)
@@ -519,7 +519,7 @@ class Form {
519
519
  if (idMatch) config.submitId = idMatch[1]
520
520
  }
521
521
 
522
- const fieldMatches = html.match(/<candy:field[\s\S]*?<\/candy:field>/g)
522
+ const fieldMatches = html.match(/<odac:field[\s\S]*?<\/odac:field>/g)
523
523
  if (fieldMatches) {
524
524
  for (const fieldHtml of fieldMatches) {
525
525
  const field = this.parseField(fieldHtml)
@@ -527,7 +527,7 @@ class Form {
527
527
  }
528
528
  }
529
529
 
530
- const setMatches = html.match(/<candy:set[^>]*\/?>/g)
530
+ const setMatches = html.match(/<odac:set[^>]*\/?>/g)
531
531
  if (setMatches) {
532
532
  for (const setTag of setMatches) {
533
533
  const set = this.parseSet(setTag)
@@ -538,32 +538,32 @@ class Form {
538
538
  return config
539
539
  }
540
540
 
541
- static storeFormConfig(token, config, Candy) {
542
- if (!Candy.View) Candy.View = {}
543
- if (!Candy.View.customForms) Candy.View.customForms = {}
541
+ static storeFormConfig(token, config, Odac) {
542
+ if (!Odac.View) Odac.View = {}
543
+ if (!Odac.View.customForms) Odac.View.customForms = {}
544
544
 
545
545
  const formData = {
546
546
  config: config,
547
547
  created: Date.now(),
548
548
  expires: Date.now() + 30 * 60 * 1000,
549
- sessionId: Candy.Request.session('_client'),
550
- userAgent: Candy.Request.header('user-agent'),
551
- ip: Candy.Request.ip
549
+ sessionId: Odac.Request.session('_client'),
550
+ userAgent: Odac.Request.header('user-agent'),
551
+ ip: Odac.Request.ip
552
552
  }
553
553
 
554
- Candy.View.customForms[token] = formData
555
- Candy.Request.session(`_custom_form_${token}`, formData)
554
+ Odac.View.customForms[token] = formData
555
+ Odac.Request.session(`_custom_form_${token}`, formData)
556
556
  }
557
557
 
558
558
  static generateCustomForm(originalHtml, config, formToken) {
559
559
  const submitText = config.submitText || 'Submit'
560
560
  const submitLoading = config.submitLoading || 'Processing...'
561
- const action = config.action || '/_candy/form'
561
+ const action = config.action || '/_odac/form'
562
562
  const method = config.method || 'POST'
563
563
 
564
- let innerContent = originalHtml.replace(/<candy:form[^>]*>/, '').replace(/<\/candy:form>/, '')
564
+ let innerContent = originalHtml.replace(/<odac:form[^>]*>/, '').replace(/<\/odac:form>/, '')
565
565
 
566
- innerContent = innerContent.replace(/<candy:field[\s\S]*?<\/candy:field>/g, fieldMatch => {
566
+ innerContent = innerContent.replace(/<odac:field[\s\S]*?<\/odac:field>/g, fieldMatch => {
567
567
  const field = this.parseField(fieldMatch)
568
568
  if (!field) return fieldMatch
569
569
  return this.generateFieldHtml(field)
@@ -572,7 +572,7 @@ class Form {
572
572
  const escapeHtml = str =>
573
573
  String(str).replace(/[&<>"']/g, m => ({'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'})[m])
574
574
 
575
- const submitMatch = innerContent.match(/<candy:submit[\s\S]*?(?:<\/candy:submit>|\/?>)/)
575
+ const submitMatch = innerContent.match(/<odac:submit[\s\S]*?(?:<\/odac:submit>|\/?>)/)
576
576
  if (submitMatch) {
577
577
  let submitAttrs = `type="submit" data-submit-text="${escapeHtml(submitText)}" data-loading-text="${escapeHtml(submitLoading)}"`
578
578
  if (config.submitClass) submitAttrs += ` class="${escapeHtml(config.submitClass)}"`
@@ -582,15 +582,15 @@ class Form {
582
582
  innerContent = innerContent.replace(submitMatch[0], submitButton)
583
583
  }
584
584
 
585
- innerContent = innerContent.replace(/<candy:set[^>]*\/?>/g, '')
585
+ innerContent = innerContent.replace(/<odac:set[^>]*\/?>/g, '')
586
586
 
587
- let formAttrs = `class="candy-custom-form${config.class ? ' ' + escapeHtml(config.class) : ''}" data-candy-form="${escapeHtml(formToken)}" method="${escapeHtml(method)}" action="${escapeHtml(action)}" novalidate`
587
+ let formAttrs = `class="odac-custom-form${config.class ? ' ' + escapeHtml(config.class) : ''}" data-odac-form="${escapeHtml(formToken)}" method="${escapeHtml(method)}" action="${escapeHtml(action)}" novalidate`
588
588
  if (config.id) formAttrs += ` id="${escapeHtml(config.id)}"`
589
589
 
590
590
  let html = `<form ${formAttrs}>\n`
591
- html += ` <input type="hidden" name="_candy_form_token" value="${escapeHtml(formToken)}">\n`
591
+ html += ` <input type="hidden" name="_odac_form_token" value="${escapeHtml(formToken)}">\n`
592
592
  html += innerContent
593
- html += `\n <span class="candy-form-success" style="display:none;"></span>\n`
593
+ html += `\n <span class="odac-form-success" style="display:none;"></span>\n`
594
594
  html += `</form>`
595
595
 
596
596
  return html