odac 0.9.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 (213) hide show
  1. package/.editorconfig +21 -0
  2. package/.github/workflows/auto-pr-description.yml +49 -0
  3. package/.github/workflows/release.yml +32 -0
  4. package/.github/workflows/test-coverage.yml +58 -0
  5. package/.husky/pre-commit +2 -0
  6. package/.kiro/steering/code-style.md +56 -0
  7. package/.kiro/steering/product.md +20 -0
  8. package/.kiro/steering/structure.md +77 -0
  9. package/.kiro/steering/tech.md +87 -0
  10. package/.prettierrc +10 -0
  11. package/.releaserc.js +134 -0
  12. package/AGENTS.md +84 -0
  13. package/CHANGELOG.md +181 -0
  14. package/CODE_OF_CONDUCT.md +83 -0
  15. package/CONTRIBUTING.md +63 -0
  16. package/LICENSE +661 -0
  17. package/README.md +57 -0
  18. package/SECURITY.md +26 -0
  19. package/bin/candy +10 -0
  20. package/bin/candypack +10 -0
  21. package/cli/index.js +3 -0
  22. package/cli/src/Cli.js +348 -0
  23. package/cli/src/Connector.js +93 -0
  24. package/cli/src/Monitor.js +416 -0
  25. package/core/Candy.js +87 -0
  26. package/core/Commands.js +239 -0
  27. package/core/Config.js +1094 -0
  28. package/core/Lang.js +52 -0
  29. package/core/Log.js +43 -0
  30. package/core/Process.js +26 -0
  31. package/docs/backend/01-overview/01-whats-in-the-candy-box.md +9 -0
  32. package/docs/backend/01-overview/02-super-handy-helper-functions.md +9 -0
  33. package/docs/backend/01-overview/03-development-server.md +79 -0
  34. package/docs/backend/02-structure/01-typical-project-layout.md +39 -0
  35. package/docs/backend/03-config/00-configuration-overview.md +214 -0
  36. package/docs/backend/03-config/01-database-connection.md +60 -0
  37. package/docs/backend/03-config/02-static-route-mapping-optional.md +20 -0
  38. package/docs/backend/03-config/03-request-timeout.md +11 -0
  39. package/docs/backend/03-config/04-environment-variables.md +227 -0
  40. package/docs/backend/03-config/05-early-hints.md +352 -0
  41. package/docs/backend/04-routing/01-basic-page-routes.md +28 -0
  42. package/docs/backend/04-routing/02-controller-less-view-routes.md +43 -0
  43. package/docs/backend/04-routing/03-api-and-data-routes.md +20 -0
  44. package/docs/backend/04-routing/04-authentication-aware-routes.md +48 -0
  45. package/docs/backend/04-routing/05-advanced-routing.md +14 -0
  46. package/docs/backend/04-routing/06-error-pages.md +101 -0
  47. package/docs/backend/04-routing/07-cron-jobs.md +149 -0
  48. package/docs/backend/05-controllers/01-how-to-build-a-controller.md +17 -0
  49. package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +20 -0
  50. package/docs/backend/05-controllers/03-controller-classes.md +93 -0
  51. package/docs/backend/05-forms/01-custom-forms.md +395 -0
  52. package/docs/backend/05-forms/02-automatic-database-insert.md +297 -0
  53. package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +96 -0
  54. package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +40 -0
  55. package/docs/backend/07-views/01-the-view-directory.md +73 -0
  56. package/docs/backend/07-views/02-rendering-a-view.md +179 -0
  57. package/docs/backend/07-views/03-template-syntax.md +181 -0
  58. package/docs/backend/07-views/03-variables.md +328 -0
  59. package/docs/backend/07-views/04-request-data.md +231 -0
  60. package/docs/backend/07-views/05-conditionals.md +290 -0
  61. package/docs/backend/07-views/06-loops.md +353 -0
  62. package/docs/backend/07-views/07-translations.md +358 -0
  63. package/docs/backend/07-views/08-backend-javascript.md +398 -0
  64. package/docs/backend/07-views/09-comments.md +297 -0
  65. package/docs/backend/08-database/01-database-connection.md +99 -0
  66. package/docs/backend/08-database/02-using-mysql.md +322 -0
  67. package/docs/backend/09-validation/01-the-validator-service.md +424 -0
  68. package/docs/backend/10-authentication/01-user-logins-with-authjs.md +53 -0
  69. package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +55 -0
  70. package/docs/backend/10-authentication/03-register.md +134 -0
  71. package/docs/backend/10-authentication/04-candy-register-forms.md +676 -0
  72. package/docs/backend/10-authentication/05-session-management.md +159 -0
  73. package/docs/backend/10-authentication/06-candy-login-forms.md +596 -0
  74. package/docs/backend/11-mail/01-the-mail-service.md +42 -0
  75. package/docs/backend/12-streaming/01-streaming-overview.md +300 -0
  76. package/docs/backend/13-utilities/01-candy-var.md +504 -0
  77. package/docs/frontend/01-overview/01-introduction.md +146 -0
  78. package/docs/frontend/02-ajax-navigation/01-quick-start.md +608 -0
  79. package/docs/frontend/02-ajax-navigation/02-configuration.md +370 -0
  80. package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +519 -0
  81. package/docs/frontend/03-forms/01-form-handling.md +420 -0
  82. package/docs/frontend/04-api-requests/01-get-post.md +443 -0
  83. package/docs/frontend/05-streaming/01-client-streaming.md +163 -0
  84. package/docs/index.json +452 -0
  85. package/docs/server/01-installation/01-quick-install.md +19 -0
  86. package/docs/server/01-installation/02-manual-installation-via-npm.md +9 -0
  87. package/docs/server/02-get-started/01-core-concepts.md +7 -0
  88. package/docs/server/02-get-started/02-basic-commands.md +57 -0
  89. package/docs/server/02-get-started/03-cli-reference.md +276 -0
  90. package/docs/server/02-get-started/04-cli-quick-reference.md +102 -0
  91. package/docs/server/03-service/01-start-a-new-service.md +57 -0
  92. package/docs/server/03-service/02-delete-a-service.md +48 -0
  93. package/docs/server/04-web/01-create-a-website.md +36 -0
  94. package/docs/server/04-web/02-list-websites.md +9 -0
  95. package/docs/server/04-web/03-delete-a-website.md +29 -0
  96. package/docs/server/05-subdomain/01-create-a-subdomain.md +32 -0
  97. package/docs/server/05-subdomain/02-list-subdomains.md +33 -0
  98. package/docs/server/05-subdomain/03-delete-a-subdomain.md +41 -0
  99. package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +34 -0
  100. package/docs/server/07-mail/01-create-a-mail-account.md +23 -0
  101. package/docs/server/07-mail/02-delete-a-mail-account.md +20 -0
  102. package/docs/server/07-mail/03-list-mail-accounts.md +20 -0
  103. package/docs/server/07-mail/04-change-account-password.md +23 -0
  104. package/eslint.config.mjs +120 -0
  105. package/framework/index.js +4 -0
  106. package/framework/src/Auth.js +309 -0
  107. package/framework/src/Candy.js +81 -0
  108. package/framework/src/Config.js +79 -0
  109. package/framework/src/Env.js +60 -0
  110. package/framework/src/Lang.js +57 -0
  111. package/framework/src/Mail.js +83 -0
  112. package/framework/src/Mysql.js +575 -0
  113. package/framework/src/Request.js +301 -0
  114. package/framework/src/Route/Cron.js +128 -0
  115. package/framework/src/Route/Internal.js +439 -0
  116. package/framework/src/Route.js +455 -0
  117. package/framework/src/Server.js +15 -0
  118. package/framework/src/Stream.js +163 -0
  119. package/framework/src/Token.js +37 -0
  120. package/framework/src/Validator.js +271 -0
  121. package/framework/src/Var.js +211 -0
  122. package/framework/src/View/EarlyHints.js +190 -0
  123. package/framework/src/View/Form.js +600 -0
  124. package/framework/src/View.js +513 -0
  125. package/framework/web/candy.js +838 -0
  126. package/jest.config.js +22 -0
  127. package/locale/de-DE.json +80 -0
  128. package/locale/en-US.json +79 -0
  129. package/locale/es-ES.json +80 -0
  130. package/locale/fr-FR.json +80 -0
  131. package/locale/pt-BR.json +80 -0
  132. package/locale/ru-RU.json +80 -0
  133. package/locale/tr-TR.json +85 -0
  134. package/locale/zh-CN.json +80 -0
  135. package/package.json +86 -0
  136. package/server/index.js +5 -0
  137. package/server/src/Api.js +88 -0
  138. package/server/src/DNS.js +940 -0
  139. package/server/src/Hub.js +535 -0
  140. package/server/src/Mail.js +571 -0
  141. package/server/src/SSL.js +180 -0
  142. package/server/src/Server.js +27 -0
  143. package/server/src/Service.js +248 -0
  144. package/server/src/Subdomain.js +64 -0
  145. package/server/src/Web/Firewall.js +170 -0
  146. package/server/src/Web/Proxy.js +134 -0
  147. package/server/src/Web.js +451 -0
  148. package/server/src/mail/imap.js +1091 -0
  149. package/server/src/mail/server.js +32 -0
  150. package/server/src/mail/smtp.js +786 -0
  151. package/test/cli/Cli.test.js +36 -0
  152. package/test/core/Candy.test.js +234 -0
  153. package/test/core/Commands.test.js +538 -0
  154. package/test/core/Config.test.js +1435 -0
  155. package/test/core/Lang.test.js +250 -0
  156. package/test/core/Process.test.js +156 -0
  157. package/test/framework/Route.test.js +239 -0
  158. package/test/framework/View/EarlyHints.test.js +282 -0
  159. package/test/scripts/check-coverage.js +132 -0
  160. package/test/server/Api.test.js +647 -0
  161. package/test/server/Client.test.js +338 -0
  162. package/test/server/DNS.test.js +2050 -0
  163. package/test/server/DNS.test.js.bak +2084 -0
  164. package/test/server/Log.test.js +73 -0
  165. package/test/server/Mail.account.test_.js +460 -0
  166. package/test/server/Mail.init.test_.js +411 -0
  167. package/test/server/Mail.test_.js +1340 -0
  168. package/test/server/SSL.test_.js +1491 -0
  169. package/test/server/Server.test.js +765 -0
  170. package/test/server/Service.test_.js +1127 -0
  171. package/test/server/Subdomain.test.js +440 -0
  172. package/test/server/Web/Firewall.test.js +175 -0
  173. package/test/server/Web.test_.js +1562 -0
  174. package/test/server/__mocks__/acme-client.js +17 -0
  175. package/test/server/__mocks__/bcrypt.js +50 -0
  176. package/test/server/__mocks__/child_process.js +389 -0
  177. package/test/server/__mocks__/crypto.js +432 -0
  178. package/test/server/__mocks__/fs.js +450 -0
  179. package/test/server/__mocks__/globalCandy.js +227 -0
  180. package/test/server/__mocks__/http-proxy.js +105 -0
  181. package/test/server/__mocks__/http.js +575 -0
  182. package/test/server/__mocks__/https.js +272 -0
  183. package/test/server/__mocks__/index.js +249 -0
  184. package/test/server/__mocks__/mail/server.js +100 -0
  185. package/test/server/__mocks__/mail/smtp.js +31 -0
  186. package/test/server/__mocks__/mailparser.js +81 -0
  187. package/test/server/__mocks__/net.js +369 -0
  188. package/test/server/__mocks__/node-forge.js +328 -0
  189. package/test/server/__mocks__/os.js +320 -0
  190. package/test/server/__mocks__/path.js +291 -0
  191. package/test/server/__mocks__/selfsigned.js +8 -0
  192. package/test/server/__mocks__/server/src/mail/server.js +100 -0
  193. package/test/server/__mocks__/server/src/mail/smtp.js +31 -0
  194. package/test/server/__mocks__/smtp-server.js +106 -0
  195. package/test/server/__mocks__/sqlite3.js +394 -0
  196. package/test/server/__mocks__/testFactories.js +299 -0
  197. package/test/server/__mocks__/testHelpers.js +363 -0
  198. package/test/server/__mocks__/tls.js +229 -0
  199. package/watchdog/index.js +3 -0
  200. package/watchdog/src/Watchdog.js +156 -0
  201. package/web/config.json +5 -0
  202. package/web/controller/page/about.js +27 -0
  203. package/web/controller/page/index.js +34 -0
  204. package/web/package.json +18 -0
  205. package/web/public/assets/css/style.css +1835 -0
  206. package/web/public/assets/js/app.js +96 -0
  207. package/web/route/www.js +19 -0
  208. package/web/skeleton/main.html +22 -0
  209. package/web/view/content/about.html +65 -0
  210. package/web/view/content/home.html +205 -0
  211. package/web/view/footer/main.html +11 -0
  212. package/web/view/head/main.html +5 -0
  213. package/web/view/header/main.html +14 -0
@@ -0,0 +1,398 @@
1
+ ## 💻 Backend JavaScript (Server-Side Execution)
2
+
3
+ Backend JavaScript allows you to execute JavaScript code during template rendering on the server. This code runs **before** the HTML is sent to the browser.
4
+
5
+ ### Basic Usage
6
+
7
+ ```html
8
+ <script:candy>
9
+ // This runs on the SERVER during template rendering
10
+ let total = 0;
11
+ for (let item of cart) {
12
+ total += item.price * item.quantity;
13
+ }
14
+ </script:candy>
15
+
16
+ <p>Total: $<candy var="total" /></p>
17
+ ```
18
+
19
+ ### Key Characteristics
20
+
21
+ - ✅ Runs on the **server** during template rendering
22
+ - ✅ Has access to all backend variables and Candy object
23
+ - ✅ Perfect for calculations, data manipulation, filtering
24
+ - ✅ Full IDE syntax highlighting and autocomplete
25
+ - ❌ Does NOT run in the browser
26
+ - ❌ Cannot access browser APIs (window, document, localStorage, etc.)
27
+
28
+ ### When to Use Backend JavaScript
29
+
30
+ Use backend JavaScript for:
31
+ - **Calculations**: Totals, averages, statistics
32
+ - **Data transformation**: Filtering, sorting, mapping arrays
33
+ - **Complex logic**: Logic that's too complex for inline conditions
34
+ - **Variable preparation**: Creating temporary variables for display
35
+
36
+ ### Accessing Variables
37
+
38
+ You have access to all variables set in the controller:
39
+
40
+ ```javascript
41
+ // Controller
42
+ module.exports = async function(Candy) {
43
+ Candy.set('products', [
44
+ { name: 'Laptop', price: 999, quantity: 2 },
45
+ { name: 'Mouse', price: 29, quantity: 5 }
46
+ ])
47
+
48
+ Candy.View.skeleton('main').set('content', 'cart')
49
+ }
50
+ ```
51
+
52
+ ```html
53
+ <!-- View -->
54
+ <script:candy>
55
+ let total = 0;
56
+ let itemCount = 0;
57
+
58
+ for (let product of products) {
59
+ total += product.price * product.quantity;
60
+ itemCount += product.quantity;
61
+ }
62
+
63
+ const avgPrice = total / itemCount;
64
+ </script:candy>
65
+
66
+ <div class="cart-summary">
67
+ <p>Total Items: <candy var="itemCount" /></p>
68
+ <p>Total Price: $<candy var="total" /></p>
69
+ <p>Average Price: $<candy var="avgPrice.toFixed(2)" /></p>
70
+ </div>
71
+ ```
72
+
73
+ ### Accessing the Candy Object
74
+
75
+ Full access to the Candy object and all its methods:
76
+
77
+ ```html
78
+ <script:candy>
79
+ const isLoggedIn = Candy.Auth.check();
80
+ const currentUser = isLoggedIn ? Candy.Auth.user() : null;
81
+ const requestMethod = Candy.Request.method;
82
+ const currentUrl = Candy.Request.url;
83
+ </script:candy>
84
+
85
+ <candy:if condition="isLoggedIn">
86
+ <p>Welcome, <candy var="currentUser.name" />!</p>
87
+ </candy:if>
88
+ ```
89
+
90
+ ### Practical Examples
91
+
92
+ #### Shopping Cart Calculations
93
+
94
+ ```html
95
+ <script:candy>
96
+ let subtotal = 0;
97
+ let totalItems = 0;
98
+
99
+ for (let item of cart) {
100
+ subtotal += item.price * item.quantity;
101
+ totalItems += item.quantity;
102
+ }
103
+
104
+ const tax = subtotal * 0.18; // 18% tax
105
+ const shipping = subtotal > 100 ? 0 : 10;
106
+ const total = subtotal + tax + shipping;
107
+ </script:candy>
108
+
109
+ <div class="cart-summary">
110
+ <h3>Order Summary</h3>
111
+ <p>Items (<candy var="totalItems" />): $<candy var="subtotal.toFixed(2)" /></p>
112
+ <p>Tax (18%): $<candy var="tax.toFixed(2)" /></p>
113
+ <p>Shipping:
114
+ <candy:if condition="shipping === 0">
115
+ <span class="free">FREE</span>
116
+ <candy:else>
117
+ $<candy var="shipping.toFixed(2)" />
118
+ </candy:if>
119
+ </p>
120
+ <hr>
121
+ <p class="total">Total: $<candy var="total.toFixed(2)" /></p>
122
+ </div>
123
+ ```
124
+
125
+ #### Filtering and Sorting
126
+
127
+ ```html
128
+ <script:candy>
129
+ // Filter active products
130
+ const activeProducts = products.filter(p => p.isActive && p.stock > 0);
131
+
132
+ // Sort by price
133
+ activeProducts.sort((a, b) => a.price - b.price);
134
+
135
+ // Get featured products
136
+ const featured = activeProducts.filter(p => p.featured).slice(0, 3);
137
+
138
+ // Calculate statistics
139
+ const avgPrice = activeProducts.reduce((sum, p) => sum + p.price, 0) / activeProducts.length;
140
+ const maxPrice = Math.max(...activeProducts.map(p => p.price));
141
+ const minPrice = Math.min(...activeProducts.map(p => p.price));
142
+ </script:candy>
143
+
144
+ <div class="products-section">
145
+ <h2>Featured Products</h2>
146
+ <p>Showing <candy var="featured.length" /> of <candy var="activeProducts.length" /> products</p>
147
+ <p>Price range: $<candy var="minPrice" /> - $<candy var="maxPrice" /></p>
148
+
149
+ <candy:for in="featured" value="product">
150
+ <div class="product">
151
+ <h3><candy var="product.name" /></h3>
152
+ <p>$<candy var="product.price" /></p>
153
+
154
+ <candy:if condition="product.price < avgPrice">
155
+ <span class="badge">Great Deal!</span>
156
+ </candy:if>
157
+ </div>
158
+ </candy:for>
159
+ </div>
160
+ ```
161
+
162
+ #### Date and Time Formatting
163
+
164
+ ```html
165
+ <script:candy>
166
+ const now = new Date();
167
+ const postDate = new Date(post.createdAt);
168
+
169
+ // Calculate time difference
170
+ const diffMs = now - postDate;
171
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
172
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
173
+ const diffMinutes = Math.floor(diffMs / (1000 * 60));
174
+
175
+ let timeAgo;
176
+ if (diffDays > 0) {
177
+ timeAgo = diffDays + ' days ago';
178
+ } else if (diffHours > 0) {
179
+ timeAgo = diffHours + ' hours ago';
180
+ } else if (diffMinutes > 0) {
181
+ timeAgo = diffMinutes + ' minutes ago';
182
+ } else {
183
+ timeAgo = 'Just now';
184
+ }
185
+
186
+ const formattedDate = postDate.toLocaleDateString('en-US', {
187
+ year: 'numeric',
188
+ month: 'long',
189
+ day: 'numeric'
190
+ });
191
+ </script:candy>
192
+
193
+ <div class="post">
194
+ <h2><candy var="post.title" /></h2>
195
+ <p class="meta">
196
+ Posted <candy var="timeAgo" /> (<candy var="formattedDate" />)
197
+ </p>
198
+ </div>
199
+ ```
200
+
201
+ #### Grouping Data
202
+
203
+ ```html
204
+ <script:candy>
205
+ // Group products by category
206
+ const grouped = {};
207
+ for (let product of products) {
208
+ if (!grouped[product.category]) {
209
+ grouped[product.category] = [];
210
+ }
211
+ grouped[product.category].push(product);
212
+ }
213
+
214
+ // Sort categories
215
+ const categories = Object.keys(grouped).sort();
216
+ </script:candy>
217
+
218
+ <div class="products-by-category">
219
+ <candy:for in="categories" value="category">
220
+ <div class="category-section">
221
+ <h2><candy var="category" /></h2>
222
+ <p><candy var="grouped[category].length" /> products</p>
223
+
224
+ <candy:for in="grouped[category]" value="product">
225
+ <div class="product">
226
+ <h3><candy var="product.name" /></h3>
227
+ <p>$<candy var="product.price" /></p>
228
+ </div>
229
+ </candy:for>
230
+ </div>
231
+ </candy:for>
232
+ </div>
233
+ ```
234
+
235
+ #### Pagination Logic
236
+
237
+ ```html
238
+ <script:candy>
239
+ const itemsPerPage = 10;
240
+ const currentPage = parseInt(Candy.Request.get('page')) || 1;
241
+ const totalItems = products.length;
242
+ const totalPages = Math.ceil(totalItems / itemsPerPage);
243
+
244
+ const startIndex = (currentPage - 1) * itemsPerPage;
245
+ const endIndex = Math.min(startIndex + itemsPerPage, totalItems);
246
+ const currentItems = products.slice(startIndex, endIndex);
247
+
248
+ const hasPrevious = currentPage > 1;
249
+ const hasNext = currentPage < totalPages;
250
+ </script:candy>
251
+
252
+ <div class="products">
253
+ <candy:for in="currentItems" value="product">
254
+ <div class="product">
255
+ <h3><candy var="product.name" /></h3>
256
+ </div>
257
+ </candy:for>
258
+ </div>
259
+
260
+ <div class="pagination">
261
+ <candy:if condition="hasPrevious">
262
+ <a href="?page=<candy var="currentPage - 1" />">Previous</a>
263
+ </candy:if>
264
+
265
+ <span>Page <candy var="currentPage" /> of <candy var="totalPages" /></span>
266
+
267
+ <candy:if condition="hasNext">
268
+ <a href="?page=<candy var="currentPage + 1" />">Next</a>
269
+ </candy:if>
270
+ </div>
271
+ ```
272
+
273
+ #### Complex Conditional Logic
274
+
275
+ ```html
276
+ <script:candy>
277
+ const user = Candy.Auth.check() ? Candy.Auth.user() : null;
278
+
279
+ const canEdit = user && (
280
+ user.role === 'admin' ||
281
+ user.id === post.authorId
282
+ );
283
+
284
+ const canDelete = user && user.role === 'admin';
285
+
286
+ const canComment = user && !user.isBanned && post.commentsEnabled;
287
+
288
+ const showActions = canEdit || canDelete || canComment;
289
+ </script:candy>
290
+
291
+ <div class="post">
292
+ <h2><candy var="post.title" /></h2>
293
+ <p><candy var="post.content" /></p>
294
+
295
+ <candy:if condition="showActions">
296
+ <div class="actions">
297
+ <candy:if condition="canEdit">
298
+ <a href="/posts/<candy var="post.id" />/edit">Edit</a>
299
+ </candy:if>
300
+
301
+ <candy:if condition="canDelete">
302
+ <a href="/posts/<candy var="post.id" />/delete">Delete</a>
303
+ </candy:if>
304
+
305
+ <candy:if condition="canComment">
306
+ <a href="#comments">Add Comment</a>
307
+ </candy:if>
308
+ </div>
309
+ </candy:if>
310
+ </div>
311
+ ```
312
+
313
+ ### Multiple Script Blocks
314
+
315
+ You can use multiple `<script:candy>` blocks in the same view:
316
+
317
+ ```html
318
+ <script:candy>
319
+ let total = 0;
320
+ </script:candy>
321
+
322
+ <candy:for in="items" value="item">
323
+ <div><candy var="item.name" /></div>
324
+
325
+ <script:candy>
326
+ total += item.price;
327
+ </script:candy>
328
+ </candy:for>
329
+
330
+ <p>Total: $<candy var="total" /></p>
331
+ ```
332
+
333
+ ### Comparison with Client-Side JavaScript
334
+
335
+ **Backend JavaScript (`<script:candy>`):**
336
+ ```html
337
+ <script:candy>
338
+ // Runs on SERVER during rendering
339
+ const total = products.reduce((sum, p) => sum + p.price, 0);
340
+ </script:candy>
341
+ <p>Total: $<candy var="total" /></p>
342
+ ```
343
+
344
+ **Client-Side JavaScript (`<script>`):**
345
+ ```html
346
+ <script>
347
+ // Runs in BROWSER after page loads
348
+ document.addEventListener('DOMContentLoaded', function() {
349
+ console.log('Page loaded');
350
+
351
+ // Can access browser APIs
352
+ localStorage.setItem('visited', 'true');
353
+
354
+ // Can manipulate DOM
355
+ document.querySelector('.button').addEventListener('click', function() {
356
+ alert('Clicked!');
357
+ });
358
+ });
359
+ </script>
360
+ ```
361
+
362
+ ### Best Practices
363
+
364
+ 1. **Keep it simple**: Complex logic should be in controllers
365
+ 2. **Use for calculations**: Perfect for totals, averages, filtering
366
+ 3. **Avoid heavy operations**: Don't do database queries or API calls
367
+ 4. **Use meaningful variable names**: Make code self-documenting
368
+ 5. **Comment when necessary**: Explain complex calculations
369
+
370
+ **Good:**
371
+ ```html
372
+ <script:candy>
373
+ const discountedPrice = product.price * (1 - product.discount / 100);
374
+ const savings = product.price - discountedPrice;
375
+ </script:candy>
376
+ ```
377
+
378
+ **Avoid:**
379
+ ```html
380
+ <script:candy>
381
+ // Don't do this - should be in controller
382
+ const users = await Candy.Mysql.query('SELECT * FROM users');
383
+ const apiData = await fetch('https://api.example.com/data');
384
+ </script:candy>
385
+ ```
386
+
387
+ ### Common Use Cases
388
+
389
+ - ✅ Calculate totals and subtotals
390
+ - ✅ Filter and sort arrays
391
+ - ✅ Format dates and numbers
392
+ - ✅ Group and aggregate data
393
+ - ✅ Create temporary display variables
394
+ - ✅ Simple conditional logic
395
+ - ❌ Database queries (use controller)
396
+ - ❌ API calls (use controller)
397
+ - ❌ File operations (use controller)
398
+ - ❌ Heavy computations (use controller)
@@ -0,0 +1,297 @@
1
+ ## 💬 Comments in Views
2
+
3
+ CandyPack supports two types of comments in view files: backend comments (not rendered) and regular HTML comments (rendered).
4
+
5
+ ### Backend Comments (Not Rendered)
6
+
7
+ Backend comments are removed during template rendering and never appear in the HTML output sent to the browser.
8
+
9
+ #### Single-Line Backend Comments
10
+
11
+ ```html
12
+ <!--candy This is a backend comment -->
13
+ <p>This will be rendered</p>
14
+ ```
15
+
16
+ #### Multi-Line Backend Comments
17
+
18
+ ```html
19
+ <!--candy
20
+ This is a multi-line backend comment
21
+ It can span multiple lines
22
+ None of this will appear in the output
23
+ candy-->
24
+
25
+ <div class="content">
26
+ <p>This will be rendered</p>
27
+ </div>
28
+ ```
29
+
30
+ ### Regular HTML Comments (Rendered)
31
+
32
+ Standard HTML comments are preserved and sent to the browser:
33
+
34
+ ```html
35
+ <!-- This is a regular HTML comment -->
36
+ <!-- It will appear in the browser's HTML source -->
37
+ <p>Content here</p>
38
+ ```
39
+
40
+ ### When to Use Each Type
41
+
42
+ #### Use Backend Comments For:
43
+
44
+ **Development Notes:**
45
+ ```html
46
+ <!--candy TODO: Add pagination here -->
47
+ <!--candy FIXME: This needs optimization -->
48
+ <!--candy NOTE: This section is for admin users only -->
49
+ ```
50
+
51
+ **Sensitive Information:**
52
+ ```html
53
+ <!--candy
54
+ Database query returns: id, name, email, password_hash
55
+ We only display: name, email
56
+ candy-->
57
+
58
+ <candy:for in="users" value="user">
59
+ <p><candy var="user.name" /> - <candy var="user.email" /></p>
60
+ </candy:for>
61
+ ```
62
+
63
+ **Debugging Information:**
64
+ ```html
65
+ <!--candy Debug: user object structure -->
66
+ <!--candy { id: 1, name: "John", role: "admin" } -->
67
+
68
+ <candy:if condition="user.role === 'admin'">
69
+ <div class="admin-panel">Admin content</div>
70
+ </candy:if>
71
+ ```
72
+
73
+ **Temporary Code:**
74
+ ```html
75
+ <!--candy
76
+ Old implementation - keeping for reference
77
+ <div class="old-layout">
78
+ <candy:for in="items" value="item">
79
+ <p><candy var="item.name" /></p>
80
+ </candy:for>
81
+ </div>
82
+ candy-->
83
+
84
+ <div class="new-layout">
85
+ <candy:for in="items" value="item">
86
+ <div class="item-card">
87
+ <h3><candy var="item.name" /></h3>
88
+ </div>
89
+ </candy:for>
90
+ </div>
91
+ ```
92
+
93
+ #### Use HTML Comments For:
94
+
95
+ **Section Markers:**
96
+ ```html
97
+ <!-- Header Section -->
98
+ <header>
99
+ <nav>...</nav>
100
+ </header>
101
+
102
+ <!-- Main Content -->
103
+ <main>
104
+ <article>...</article>
105
+ </main>
106
+
107
+ <!-- Footer Section -->
108
+ <footer>
109
+ <p>Copyright 2024</p>
110
+ </footer>
111
+ ```
112
+
113
+ **Browser-Specific Hacks:**
114
+ ```html
115
+ <!--[if IE]>
116
+ <p>You are using Internet Explorer</p>
117
+ <![endif]-->
118
+ ```
119
+
120
+ **Third-Party Integration Notes:**
121
+ ```html
122
+ <!-- Google Analytics -->
123
+ <script>
124
+ // Analytics code here
125
+ </script>
126
+
127
+ <!-- Facebook Pixel -->
128
+ <script>
129
+ // Pixel code here
130
+ </script>
131
+ ```
132
+
133
+ ### Practical Examples
134
+
135
+ #### Documenting Complex Logic
136
+
137
+ ```html
138
+ <!--candy
139
+ This section displays products based on user role:
140
+ - Admin: sees all products including inactive
141
+ - Regular user: sees only active products
142
+ - Guest: sees only featured products
143
+ candy-->
144
+
145
+ <script:candy>
146
+ let visibleProducts;
147
+
148
+ if (Candy.Auth.check()) {
149
+ const user = Candy.Auth.user();
150
+ if (user.role === 'admin') {
151
+ visibleProducts = products;
152
+ } else {
153
+ visibleProducts = products.filter(p => p.isActive);
154
+ }
155
+ } else {
156
+ visibleProducts = products.filter(p => p.featured);
157
+ }
158
+ </script:candy>
159
+
160
+ <candy:for in="visibleProducts" value="product">
161
+ <div class="product">
162
+ <h3><candy var="product.name" /></h3>
163
+ </div>
164
+ </candy:for>
165
+ ```
166
+
167
+ #### Marking Sections for Developers
168
+
169
+ ```html
170
+ <div class="dashboard">
171
+ <!--candy START: User Statistics Section -->
172
+ <div class="stats">
173
+ <h2>Statistics</h2>
174
+ <p>Total Users: <candy var="stats.totalUsers" /></p>
175
+ <p>Active Users: <candy var="stats.activeUsers" /></p>
176
+ </div>
177
+ <!--candy END: User Statistics Section -->
178
+
179
+ <!--candy START: Recent Activity Section -->
180
+ <div class="activity">
181
+ <h2>Recent Activity</h2>
182
+ <candy:for in="activities" value="activity">
183
+ <p><candy var="activity.description" /></p>
184
+ </candy:for>
185
+ </div>
186
+ <!--candy END: Recent Activity Section -->
187
+ </div>
188
+ ```
189
+
190
+ #### Explaining Template Variables
191
+
192
+ ```html
193
+ <!--candy
194
+ Available variables from controller:
195
+ - user: Current user object { id, name, email, role }
196
+ - posts: Array of post objects
197
+ - categories: Array of category objects
198
+ - settings: Site settings object
199
+ candy-->
200
+
201
+ <div class="profile">
202
+ <h1><candy var="user.name" /></h1>
203
+ <p><candy var="user.email" /></p>
204
+ </div>
205
+ ```
206
+
207
+ #### Temporary Disabling Code
208
+
209
+ ```html
210
+ <div class="products">
211
+ <candy:for in="products" value="product">
212
+ <div class="product-card">
213
+ <h3><candy var="product.name" /></h3>
214
+ <p>$<candy var="product.price" /></p>
215
+
216
+ <!--candy Temporarily disabled - waiting for API
217
+ <div class="reviews">
218
+ <candy var="product.averageRating" /> stars
219
+ </div>
220
+ candy-->
221
+ </div>
222
+ </candy:for>
223
+ </div>
224
+ ```
225
+
226
+ #### Version History
227
+
228
+ ```html
229
+ <!--candy
230
+ Version History:
231
+ v1.0 - Initial implementation
232
+ v1.1 - Added sorting functionality
233
+ v1.2 - Added filtering by category
234
+ v2.0 - Complete redesign with new layout
235
+ candy-->
236
+
237
+ <div class="product-list">
238
+ <!-- Product list implementation -->
239
+ </div>
240
+ ```
241
+
242
+ ### Best Practices
243
+
244
+ 1. **Use backend comments for sensitive info**: Never expose internal logic or data structures in HTML comments
245
+ 2. **Keep comments concise**: Don't over-comment obvious code
246
+ 3. **Update comments**: Remove or update outdated comments
247
+ 4. **Use meaningful descriptions**: Make comments helpful for other developers
248
+ 5. **Don't commit debug comments**: Remove debug comments before committing
249
+
250
+ **Good:**
251
+ ```html
252
+ <!--candy This query is cached for 5 minutes -->
253
+ <candy:for in="products" value="product">
254
+ <div><candy var="product.name" /></div>
255
+ </candy:for>
256
+ ```
257
+
258
+ **Avoid:**
259
+ ```html
260
+ <!--candy Loop through products -->
261
+ <candy:for in="products" value="product">
262
+ <!--candy Display product name -->
263
+ <div><candy var="product.name" /></div>
264
+ </candy:for>
265
+ ```
266
+
267
+ ### Security Considerations
268
+
269
+ **Never expose sensitive information in HTML comments:**
270
+
271
+ ```html
272
+ <!-- BAD: Visible in browser source -->
273
+ <!-- Database password: secret123 -->
274
+ <!-- API key: abc123xyz -->
275
+
276
+ <!--candy GOOD: Not visible in output -->
277
+ <!--candy Database password: secret123 -->
278
+ <!--candy API key: abc123xyz -->
279
+ ```
280
+
281
+ **Be careful with user data:**
282
+
283
+ ```html
284
+ <!-- BAD: Exposes user data -->
285
+ <!-- User ID: 12345, Email: user@example.com -->
286
+
287
+ <!--candy GOOD: Hidden from output -->
288
+ <!--candy User ID: 12345, Email: user@example.com -->
289
+ ```
290
+
291
+ ### Comment Syntax Summary
292
+
293
+ | Type | Syntax | Rendered | Use Case |
294
+ |------|--------|----------|----------|
295
+ | Backend Single-Line | `<!--candy comment -->` | No | Development notes, TODOs |
296
+ | Backend Multi-Line | `<!--candy ... candy-->` | No | Detailed explanations, disabled code |
297
+ | HTML Comment | `<!-- comment -->` | Yes | Section markers, browser hacks |