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
@@ -1,23 +1,23 @@
1
1
  ## 🔗 Request Data (Query Parameters)
2
2
 
3
- The `<candy get>` tag allows you to access URL query parameters directly in your views. This is useful for forms, filters, and pagination.
3
+ The `<odac get>` tag allows you to access URL query parameters directly in your views. This is useful for forms, filters, and pagination.
4
4
 
5
5
  ### Getting Query Parameters
6
6
 
7
- Use `<candy get="key" />` to access URL query parameters:
7
+ Use `<odac get="key" />` to access URL query parameters:
8
8
 
9
- **Important:** `<candy get>` is for **query parameters** (URL parameters), not for data from controllers. For controller data, use `<candy var>` (see [Variables](./03-variables.md)).
9
+ **Important:** `<odac get>` is for **query parameters** (URL parameters), not for data from controllers. For controller data, use `<odac var>` (see [Variables](./03-variables.md)).
10
10
 
11
11
  ```html
12
12
  <!-- URL: /search?q=laptop&page=2 -->
13
13
 
14
- <p>Search query: <candy get="q" /></p>
15
- <p>Current page: <candy get="page" /></p>
14
+ <p>Search query: <odac get="q" /></p>
15
+ <p>Current page: <odac get="page" /></p>
16
16
  ```
17
17
 
18
18
  **How it works:**
19
19
  1. User visits `/search?q=laptop&page=2`
20
- 2. `<candy get="q" />` retrieves the value of `q` parameter
20
+ 2. `<odac get="q" />` retrieves the value of `q` parameter
21
21
  3. If parameter doesn't exist, it returns empty string (no error)
22
22
 
23
23
  ### Undefined Parameters
@@ -27,7 +27,7 @@ If a parameter doesn't exist, it safely returns an empty string:
27
27
  ```html
28
28
  <!-- URL: /products (no query parameters) -->
29
29
 
30
- <candy get="search" />
30
+ <odac get="search" />
31
31
  <!-- Output: (empty string, no error) -->
32
32
  ```
33
33
 
@@ -35,86 +35,86 @@ This prevents errors when parameters are optional.
35
35
 
36
36
  ### Difference: get vs var
37
37
 
38
- **`<candy get>` - Query Parameters (from URL):**
38
+ **`<odac get>` - Query Parameters (from URL):**
39
39
  ```html
40
40
  <!-- URL: /search?q=laptop -->
41
- <candy get="q" />
41
+ <odac get="q" />
42
42
  <!-- Output: laptop -->
43
43
  ```
44
44
 
45
- **`<candy var>` - Controller Data (from Candy.set()):**
45
+ **`<odac var>` - Controller Data (from Odac.set()):**
46
46
  ```javascript
47
47
  // Controller
48
- Candy.set('productName', 'Laptop')
48
+ Odac.set('productName', 'Laptop')
49
49
  ```
50
50
  ```html
51
51
  <!-- View -->
52
- <candy var="productName" />
52
+ <odac var="productName" />
53
53
  <!-- Output: Laptop -->
54
54
  ```
55
55
 
56
56
  ### Processing Request Data in Controllers
57
57
 
58
- While you can access query parameters directly in views with `<candy get>`, it's often better to process them in the controller:
58
+ While you can access query parameters directly in views with `<odac get>`, it's often better to process them in the controller:
59
59
 
60
60
  ```javascript
61
61
  // Controller: controller/search.js
62
- module.exports = async function(Candy) {
62
+ module.exports = async function(Odac) {
63
63
  // Get query parameters
64
- const query = Candy.Request.get('q') || 'all products'
65
- const page = parseInt(Candy.Request.get('page')) || 1
64
+ const query = Odac.Request.get('q') || 'all products'
65
+ const page = parseInt(Odac.Request.get('page')) || 1
66
66
 
67
67
  // Validate and process
68
68
  const validatedQuery = query.trim()
69
69
  const validatedPage = Math.max(1, page)
70
70
 
71
71
  // Fetch results
72
- const results = await Candy.Mysql.table('products')
72
+ const results = await Odac.Mysql.table('products')
73
73
  .where('name', 'like', `%${validatedQuery}%`)
74
74
  .limit(20)
75
75
  .offset((validatedPage - 1) * 20)
76
76
  .get()
77
77
 
78
78
  // Pass processed data to view
79
- Candy.set({
79
+ Odac.set({
80
80
  query: validatedQuery,
81
81
  page: validatedPage,
82
82
  results: results
83
83
  })
84
84
 
85
- Candy.View.skeleton('main').set('content', 'search')
85
+ Odac.View.skeleton('main').set('content', 'search')
86
86
  }
87
87
  ```
88
88
 
89
89
  ```html
90
90
  <!-- View: view/content/search.html -->
91
- <h1>Search Results for "<candy var="query" />"</h1>
92
- <p>Page <candy var="page" /></p>
91
+ <h1>Search Results for "<odac var="query" />"</h1>
92
+ <p>Page <odac var="page" /></p>
93
93
 
94
- <candy:for in="results" value="product">
94
+ <odac:for in="results" value="product">
95
95
  <div class="product">
96
- <h3><candy var="product.name" /></h3>
97
- <p><candy var="product.price" /></p>
96
+ <h3><odac var="product.name" /></h3>
97
+ <p><odac var="product.price" /></p>
98
98
  </div>
99
- </candy:for>
99
+ </odac:for>
100
100
  ```
101
101
 
102
102
  ### Accessing Request Object
103
103
 
104
- You can access the full Request object through the Candy object:
104
+ You can access the full Request object through the Odac object:
105
105
 
106
106
  ```html
107
107
  <!-- Request method -->
108
- <p>Method: <candy var="Candy.Request.method" /></p>
108
+ <p>Method: <odac var="Odac.Request.method" /></p>
109
109
 
110
110
  <!-- Current URL -->
111
- <p>URL: <candy var="Candy.Request.url" /></p>
111
+ <p>URL: <odac var="Odac.Request.url" /></p>
112
112
 
113
113
  <!-- Client IP -->
114
- <p>IP: <candy var="Candy.Request.ip" /></p>
114
+ <p>IP: <odac var="Odac.Request.ip" /></p>
115
115
 
116
116
  <!-- User agent -->
117
- <p>Browser: <candy var="Candy.Request.headers['user-agent']" /></p>
117
+ <p>Browser: <odac var="Odac.Request.headers['user-agent']" /></p>
118
118
  ```
119
119
 
120
120
  ### Practical Examples
@@ -127,36 +127,36 @@ You can access the full Request object through the Candy object:
127
127
  <input
128
128
  type="text"
129
129
  name="q"
130
- value="<candy get="q" />"
130
+ value="<odac get="q" />"
131
131
  placeholder="Search products..."
132
132
  >
133
133
  <button type="submit">Search</button>
134
134
  </form>
135
135
 
136
136
  <!-- Display search query if exists -->
137
- <candy:if condition="Candy.Request.get('q')">
138
- <p>Showing results for: "<candy get="q" />"</p>
139
- </candy:if>
137
+ <odac:if condition="Odac.Request.get('q')">
138
+ <p>Showing results for: "<odac get="q" />"</p>
139
+ </odac:if>
140
140
  ```
141
141
 
142
142
  #### Pagination
143
143
 
144
144
  ```html
145
- <script:candy>
146
- const currentPage = parseInt(Candy.Request.get('page')) || 1
145
+ <script:odac>
146
+ const currentPage = parseInt(Odac.Request.get('page')) || 1
147
147
  const totalPages = 10
148
- </script:candy>
148
+ </script:odac>
149
149
 
150
150
  <div class="pagination">
151
- <candy:if condition="currentPage > 1">
152
- <a href="?page=<candy var="currentPage - 1" />">Previous</a>
153
- </candy:if>
151
+ <odac:if condition="currentPage > 1">
152
+ <a href="?page=<odac var="currentPage - 1" />">Previous</a>
153
+ </odac:if>
154
154
 
155
- <span>Page <candy var="currentPage" /> of <candy var="totalPages" /></span>
155
+ <span>Page <odac var="currentPage" /> of <odac var="totalPages" /></span>
156
156
 
157
- <candy:if condition="currentPage < totalPages">
158
- <a href="?page=<candy var="currentPage + 1" />">Next</a>
159
- </candy:if>
157
+ <odac:if condition="currentPage < totalPages">
158
+ <a href="?page=<odac var="currentPage + 1" />">Next</a>
159
+ </odac:if>
160
160
  </div>
161
161
  ```
162
162
 
@@ -168,19 +168,19 @@ You can access the full Request object through the Candy object:
168
168
  <form action="/products" method="GET">
169
169
  <select name="category">
170
170
  <option value="">All Categories</option>
171
- <option value="electronics" <candy:if condition="Candy.Request.get('category') === 'electronics'">selected</candy:if>>
171
+ <option value="electronics" <odac:if condition="Odac.Request.get('category') === 'electronics'">selected</odac:if>>
172
172
  Electronics
173
173
  </option>
174
- <option value="clothing" <candy:if condition="Candy.Request.get('category') === 'clothing'">selected</candy:if>>
174
+ <option value="clothing" <odac:if condition="Odac.Request.get('category') === 'clothing'">selected</odac:if>>
175
175
  Clothing
176
176
  </option>
177
177
  </select>
178
178
 
179
179
  <select name="sort">
180
- <option value="name" <candy:if condition="Candy.Request.get('sort') === 'name'">selected</candy:if>>
180
+ <option value="name" <odac:if condition="Odac.Request.get('sort') === 'name'">selected</odac:if>>
181
181
  Name
182
182
  </option>
183
- <option value="price" <candy:if condition="Candy.Request.get('sort') === 'price'">selected</candy:if>>
183
+ <option value="price" <odac:if condition="Odac.Request.get('sort') === 'price'">selected</odac:if>>
184
184
  Price
185
185
  </option>
186
186
  </select>
@@ -193,13 +193,13 @@ You can access the full Request object through the Candy object:
193
193
 
194
194
  ```html
195
195
  <nav>
196
- <a href="/" class="<candy:if condition="Candy.Request.url === '/'">active</candy:if>">
196
+ <a href="/" class="<odac:if condition="Odac.Request.url === '/'">active</odac:if>">
197
197
  Home
198
198
  </a>
199
- <a href="/products" class="<candy:if condition="Candy.Request.url.startsWith('/products')">active</candy:if>">
199
+ <a href="/products" class="<odac:if condition="Odac.Request.url.startsWith('/products')">active</odac:if>">
200
200
  Products
201
201
  </a>
202
- <a href="/about" class="<candy:if condition="Candy.Request.url === '/about'">active</candy:if>">
202
+ <a href="/about" class="<odac:if condition="Odac.Request.url === '/about'">active</odac:if>">
203
203
  About
204
204
  </a>
205
205
  </nav>
@@ -215,17 +215,17 @@ You can access the full Request object through the Candy object:
215
215
  **Good:**
216
216
  ```javascript
217
217
  // Controller
218
- const page = Math.max(1, parseInt(Candy.Request.get('page')) || 1)
219
- const limit = Math.min(100, parseInt(Candy.Request.get('limit')) || 20)
218
+ const page = Math.max(1, parseInt(Odac.Request.get('page')) || 1)
219
+ const limit = Math.min(100, parseInt(Odac.Request.get('limit')) || 20)
220
220
 
221
- Candy.set('page', page)
222
- Candy.set('limit', limit)
221
+ Odac.set('page', page)
222
+ Odac.set('limit', limit)
223
223
  ```
224
224
 
225
225
  **Avoid:**
226
226
  ```html
227
227
  <!-- Don't do complex logic in views -->
228
- <candy:if condition="parseInt(Candy.Request.get('page')) > 0 && parseInt(Candy.Request.get('page')) < 100">
228
+ <odac:if condition="parseInt(Odac.Request.get('page')) > 0 && parseInt(Odac.Request.get('page')) < 100">
229
229
  ...
230
- </candy:if>
230
+ </odac:if>
231
231
  ```
@@ -5,9 +5,9 @@ Conditionals allow you to show or hide content based on conditions. This is esse
5
5
  ### Basic If Statement
6
6
 
7
7
  ```html
8
- <candy:if condition="user.isAdmin">
8
+ <odac:if condition="user.isAdmin">
9
9
  <p>Welcome to the admin panel!</p>
10
- </candy:if>
10
+ </odac:if>
11
11
  ```
12
12
 
13
13
  The content inside the tag is only rendered if the condition is true.
@@ -15,33 +15,33 @@ The content inside the tag is only rendered if the condition is true.
15
15
  ### If-Else Structure
16
16
 
17
17
  ```html
18
- <candy:if condition="user.isLoggedIn">
19
- <p>Welcome back, <candy var="user.name" />!</p>
20
- <candy:else>
18
+ <odac:if condition="user.isLoggedIn">
19
+ <p>Welcome back, <odac var="user.name" />!</p>
20
+ <odac:else>
21
21
  <p>Please log in to continue.</p>
22
- </candy:if>
22
+ </odac:if>
23
23
  ```
24
24
 
25
25
  ### If-ElseIf-Else Structure
26
26
 
27
27
  ```html
28
- <candy:if condition="user.role === 'admin'">
28
+ <odac:if condition="user.role === 'admin'">
29
29
  <div class="admin-panel">
30
30
  <p>You have full admin privileges</p>
31
31
  </div>
32
- <candy:elseif condition="user.role === 'moderator'">
32
+ <odac:elseif condition="user.role === 'moderator'">
33
33
  <div class="moderator-panel">
34
34
  <p>You have moderator privileges</p>
35
35
  </div>
36
- <candy:elseif condition="user.role === 'editor'">
36
+ <odac:elseif condition="user.role === 'editor'">
37
37
  <div class="editor-panel">
38
38
  <p>You have editor privileges</p>
39
39
  </div>
40
- <candy:else>
40
+ <odac:else>
41
41
  <div class="user-panel">
42
42
  <p>You have regular user privileges</p>
43
43
  </div>
44
- </candy:if>
44
+ </odac:if>
45
45
  ```
46
46
 
47
47
  ### Condition Syntax
@@ -50,40 +50,40 @@ Conditions use standard JavaScript expressions:
50
50
 
51
51
  ```html
52
52
  <!-- Equality -->
53
- <candy:if condition="status === 'active'">Active</candy:if>
53
+ <odac:if condition="status === 'active'">Active</odac:if>
54
54
 
55
55
  <!-- Comparison -->
56
- <candy:if condition="age >= 18">Adult</candy:if>
57
- <candy:if condition="price < 100">Affordable</candy:if>
56
+ <odac:if condition="age >= 18">Adult</odac:if>
57
+ <odac:if condition="price < 100">Affordable</odac:if>
58
58
 
59
59
  <!-- Logical operators -->
60
- <candy:if condition="user.isVerified && user.isPremium">
60
+ <odac:if condition="user.isVerified && user.isPremium">
61
61
  Premium Verified User
62
- </candy:if>
62
+ </odac:if>
63
63
 
64
- <candy:if condition="role === 'admin' || role === 'moderator'">
64
+ <odac:if condition="role === 'admin' || role === 'moderator'">
65
65
  Staff Member
66
- </candy:if>
66
+ </odac:if>
67
67
 
68
68
  <!-- Negation -->
69
- <candy:if condition="!user.isBanned">
69
+ <odac:if condition="!user.isBanned">
70
70
  Welcome!
71
- </candy:if>
71
+ </odac:if>
72
72
 
73
73
  <!-- Existence check -->
74
- <candy:if condition="user">
74
+ <odac:if condition="user">
75
75
  User exists
76
- </candy:if>
76
+ </odac:if>
77
77
 
78
78
  <!-- Array/String length -->
79
- <candy:if condition="items.length > 0">
79
+ <odac:if condition="items.length > 0">
80
80
  You have items
81
- </candy:if>
81
+ </odac:if>
82
82
 
83
83
  <!-- Method calls -->
84
- <candy:if condition="Candy.Auth.check()">
84
+ <odac:if condition="Odac.Auth.check()">
85
85
  Logged in
86
- </candy:if>
86
+ </odac:if>
87
87
  ```
88
88
 
89
89
  ### Practical Examples
@@ -92,14 +92,14 @@ Conditions use standard JavaScript expressions:
92
92
 
93
93
  ```html
94
94
  <nav>
95
- <candy:if condition="Candy.Auth.check()">
95
+ <odac:if condition="Odac.Auth.check()">
96
96
  <a href="/profile">Profile</a>
97
97
  <a href="/settings">Settings</a>
98
98
  <a href="/logout">Logout</a>
99
- <candy:else>
99
+ <odac:else>
100
100
  <a href="/login">Login</a>
101
101
  <a href="/register">Register</a>
102
- </candy:if>
102
+ </odac:if>
103
103
  </nav>
104
104
  ```
105
105
 
@@ -107,19 +107,19 @@ Conditions use standard JavaScript expressions:
107
107
 
108
108
  ```html
109
109
  <div class="product">
110
- <h3><candy var="product.name" /></h3>
111
- <p class="price">$<candy var="product.price" /></p>
110
+ <h3><odac var="product.name" /></h3>
111
+ <p class="price">$<odac var="product.price" /></p>
112
112
 
113
- <candy:if condition="product.stock > 10">
113
+ <odac:if condition="product.stock > 10">
114
114
  <span class="badge in-stock">In Stock</span>
115
115
  <button>Add to Cart</button>
116
- <candy:elseif condition="product.stock > 0">
117
- <span class="badge low-stock">Only <candy var="product.stock" /> left!</span>
116
+ <odac:elseif condition="product.stock > 0">
117
+ <span class="badge low-stock">Only <odac var="product.stock" /> left!</span>
118
118
  <button>Add to Cart</button>
119
- <candy:else>
119
+ <odac:else>
120
120
  <span class="badge out-of-stock">Out of Stock</span>
121
121
  <button disabled>Notify Me</button>
122
- </candy:if>
122
+ </odac:if>
123
123
  </div>
124
124
  ```
125
125
 
@@ -129,22 +129,22 @@ Conditions use standard JavaScript expressions:
129
129
  <div class="dashboard">
130
130
  <h1>Dashboard</h1>
131
131
 
132
- <candy:if condition="user.role === 'admin'">
132
+ <odac:if condition="user.role === 'admin'">
133
133
  <div class="admin-section">
134
134
  <h2>Admin Tools</h2>
135
135
  <a href="/admin/users">Manage Users</a>
136
136
  <a href="/admin/settings">System Settings</a>
137
137
  <a href="/admin/logs">View Logs</a>
138
138
  </div>
139
- </candy:if>
139
+ </odac:if>
140
140
 
141
- <candy:if condition="user.role === 'admin' || user.role === 'moderator'">
141
+ <odac:if condition="user.role === 'admin' || user.role === 'moderator'">
142
142
  <div class="moderation-section">
143
143
  <h2>Moderation</h2>
144
144
  <a href="/moderate/posts">Review Posts</a>
145
145
  <a href="/moderate/reports">Handle Reports</a>
146
146
  </div>
147
- </candy:if>
147
+ </odac:if>
148
148
 
149
149
  <div class="user-section">
150
150
  <h2>Your Content</h2>
@@ -160,27 +160,27 @@ Conditions use standard JavaScript expressions:
160
160
  <form>
161
161
  <div class="form-group">
162
162
  <label>Email</label>
163
- <input type="email" name="email" value="<candy var="email" />">
163
+ <input type="email" name="email" value="<odac var="email" />">
164
164
 
165
- <candy:if condition="errors && errors.email">
166
- <span class="error"><candy var="errors.email" /></span>
167
- </candy:if>
165
+ <odac:if condition="errors && errors.email">
166
+ <span class="error"><odac var="errors.email" /></span>
167
+ </odac:if>
168
168
  </div>
169
169
 
170
170
  <div class="form-group">
171
171
  <label>Password</label>
172
172
  <input type="password" name="password">
173
173
 
174
- <candy:if condition="errors && errors.password">
175
- <span class="error"><candy var="errors.password" /></span>
176
- </candy:if>
174
+ <odac:if condition="errors && errors.password">
175
+ <span class="error"><odac var="errors.password" /></span>
176
+ </odac:if>
177
177
  </div>
178
178
 
179
- <candy:if condition="success">
179
+ <odac:if condition="success">
180
180
  <div class="success-message">
181
- <candy var="success" />
181
+ <odac var="success" />
182
182
  </div>
183
- </candy:if>
183
+ </odac:if>
184
184
 
185
185
  <button type="submit">Submit</button>
186
186
  </form>
@@ -189,75 +189,75 @@ Conditions use standard JavaScript expressions:
189
189
  #### Conditional CSS Classes
190
190
 
191
191
  ```html
192
- <div class="user-card <candy:if condition="user.isPremium">premium</candy:if> <candy:if condition="user.isVerified">verified</candy:if>">
193
- <h3><candy var="user.name" /></h3>
192
+ <div class="user-card <odac:if condition="user.isPremium">premium</odac:if> <odac:if condition="user.isVerified">verified</odac:if>">
193
+ <h3><odac var="user.name" /></h3>
194
194
 
195
- <candy:if condition="user.isPremium">
195
+ <odac:if condition="user.isPremium">
196
196
  <span class="badge">⭐ Premium</span>
197
- </candy:if>
197
+ </odac:if>
198
198
 
199
- <candy:if condition="user.isVerified">
199
+ <odac:if condition="user.isVerified">
200
200
  <span class="badge">✓ Verified</span>
201
- </candy:if>
201
+ </odac:if>
202
202
  </div>
203
203
  ```
204
204
 
205
205
  #### Nested Conditions
206
206
 
207
207
  ```html
208
- <candy:if condition="user">
209
- <candy:if condition="user.isActive">
210
- <candy:if condition="user.subscription">
211
- <candy:if condition="user.subscription.status === 'active'">
208
+ <odac:if condition="user">
209
+ <odac:if condition="user.isActive">
210
+ <odac:if condition="user.subscription">
211
+ <odac:if condition="user.subscription.status === 'active'">
212
212
  <div class="premium-content">
213
213
  <h2>Premium Content</h2>
214
214
  <p>Welcome, premium member!</p>
215
215
  </div>
216
- <candy:elseif condition="user.subscription.status === 'expired'">
216
+ <odac:elseif condition="user.subscription.status === 'expired'">
217
217
  <div class="renewal-notice">
218
218
  <p>Your subscription has expired. Please renew to continue.</p>
219
219
  <a href="/renew">Renew Now</a>
220
220
  </div>
221
- </candy:if>
222
- <candy:else>
221
+ </odac:if>
222
+ <odac:else>
223
223
  <div class="upgrade-notice">
224
224
  <p>Upgrade to premium for exclusive content!</p>
225
225
  <a href="/upgrade">Upgrade Now</a>
226
226
  </div>
227
- </candy:if>
228
- <candy:else>
227
+ </odac:if>
228
+ <odac:else>
229
229
  <div class="inactive-notice">
230
230
  <p>Your account is inactive. Please contact support.</p>
231
231
  </div>
232
- </candy:if>
233
- <candy:else>
232
+ </odac:if>
233
+ <odac:else>
234
234
  <div class="login-notice">
235
235
  <p>Please log in to view this content.</p>
236
236
  <a href="/login">Login</a>
237
237
  </div>
238
- </candy:if>
238
+ </odac:if>
239
239
  ```
240
240
 
241
241
  #### Conditional Attributes
242
242
 
243
243
  ```html
244
244
  <!-- Disabled button -->
245
- <button <candy:if condition="!canSubmit">disabled</candy:if>>
245
+ <button <odac:if condition="!canSubmit">disabled</odac:if>>
246
246
  Submit
247
247
  </button>
248
248
 
249
249
  <!-- Selected option -->
250
250
  <select name="country">
251
- <option value="tr" <candy:if condition="country === 'tr'">selected</candy:if>>Turkey</option>
252
- <option value="us" <candy:if condition="country === 'us'">selected</candy:if>>USA</option>
253
- <option value="uk" <candy:if condition="country === 'uk'">selected</candy:if>>UK</option>
251
+ <option value="tr" <odac:if condition="country === 'tr'">selected</odac:if>>Turkey</option>
252
+ <option value="us" <odac:if condition="country === 'us'">selected</odac:if>>USA</option>
253
+ <option value="uk" <odac:if condition="country === 'uk'">selected</odac:if>>UK</option>
254
254
  </select>
255
255
 
256
256
  <!-- Checked checkbox -->
257
257
  <input
258
258
  type="checkbox"
259
259
  name="terms"
260
- <candy:if condition="termsAccepted">checked</candy:if>
260
+ <odac:if condition="termsAccepted">checked</odac:if>
261
261
  >
262
262
  ```
263
263
 
@@ -271,20 +271,20 @@ Conditions use standard JavaScript expressions:
271
271
  **Good:**
272
272
  ```javascript
273
273
  // Controller
274
- Candy.set('canEdit', user.isAdmin || user.id === post.authorId)
274
+ Odac.set('canEdit', user.isAdmin || user.id === post.authorId)
275
275
  ```
276
276
 
277
277
  ```html
278
278
  <!-- View -->
279
- <candy:if condition="canEdit">
279
+ <odac:if condition="canEdit">
280
280
  <button>Edit</button>
281
- </candy:if>
281
+ </odac:if>
282
282
  ```
283
283
 
284
284
  **Avoid:**
285
285
  ```html
286
286
  <!-- Too complex for a view -->
287
- <candy:if condition="(user && user.role === 'admin') || (user && post && user.id === post.authorId && !post.isLocked)">
287
+ <odac:if condition="(user && user.role === 'admin') || (user && post && user.id === post.authorId && !post.isLocked)">
288
288
  <button>Edit</button>
289
- </candy:if>
289
+ </odac:if>
290
290
  ```