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.
- package/.github/workflows/auto-pr-description.yml +0 -2
- package/.github/workflows/codeql.yml +46 -0
- package/.github/workflows/release.yml +13 -6
- package/.github/workflows/test-coverage.yml +10 -9
- package/.releaserc.js +9 -6
- package/CHANGELOG.md +62 -150
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTING.md +8 -8
- package/LICENSE +21 -661
- package/README.md +12 -12
- package/SECURITY.md +4 -4
- package/bin/odac.js +101 -0
- package/{framework/web/candy.js → client/odac.js} +310 -44
- package/docs/backend/01-overview/{01-whats-in-the-candy-box.md → 01-whats-in-the-odac-box.md} +4 -2
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +29 -1
- package/docs/backend/01-overview/03-development-server.md +11 -11
- package/docs/backend/02-structure/01-typical-project-layout.md +4 -4
- package/docs/backend/03-config/00-configuration-overview.md +6 -6
- package/docs/backend/03-config/01-database-connection.md +1 -1
- package/docs/backend/03-config/02-static-route-mapping-optional.md +4 -4
- package/docs/backend/03-config/04-environment-variables.md +20 -20
- package/docs/backend/03-config/05-early-hints.md +4 -4
- package/docs/backend/04-routing/01-basic-page-routes.md +4 -4
- package/docs/backend/04-routing/02-controller-less-view-routes.md +5 -5
- package/docs/backend/04-routing/03-api-and-data-routes.md +3 -3
- package/docs/backend/04-routing/04-authentication-aware-routes.md +5 -5
- package/docs/backend/04-routing/05-advanced-routing.md +3 -3
- package/docs/backend/04-routing/06-error-pages.md +17 -17
- package/docs/backend/04-routing/07-cron-jobs.md +13 -13
- package/docs/backend/04-routing/08-middleware.md +214 -0
- package/docs/backend/04-routing/09-websocket-auth-middleware.md +292 -0
- package/docs/backend/04-routing/09-websocket-examples.md +381 -0
- package/docs/backend/04-routing/09-websocket-quick-reference.md +211 -0
- package/docs/backend/04-routing/09-websocket.md +298 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +3 -3
- package/docs/backend/05-controllers/02-your-trusty-odac-assistant.md +41 -0
- package/docs/backend/05-controllers/03-controller-classes.md +19 -19
- package/docs/backend/05-forms/01-custom-forms.md +114 -114
- package/docs/backend/05-forms/02-automatic-database-insert.md +82 -82
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +26 -26
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +10 -10
- package/docs/backend/07-views/01-the-view-directory.md +1 -1
- package/docs/backend/07-views/02-rendering-a-view.md +22 -22
- package/docs/backend/07-views/03-template-syntax.md +52 -52
- package/docs/backend/07-views/03-variables.md +84 -84
- package/docs/backend/07-views/04-request-data.md +57 -57
- package/docs/backend/07-views/05-conditionals.md +78 -78
- package/docs/backend/07-views/06-loops.md +114 -114
- package/docs/backend/07-views/07-translations.md +66 -66
- package/docs/backend/07-views/08-backend-javascript.md +103 -103
- package/docs/backend/07-views/09-comments.md +71 -71
- package/docs/backend/08-database/01-database-connection.md +8 -8
- package/docs/backend/08-database/02-using-mysql.md +49 -49
- package/docs/backend/09-validation/01-the-validator-service.md +38 -38
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +15 -15
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +10 -10
- package/docs/backend/10-authentication/03-register.md +12 -12
- package/docs/backend/10-authentication/{04-candy-register-forms.md → 04-odac-register-forms.md} +141 -141
- package/docs/backend/10-authentication/05-session-management.md +10 -10
- package/docs/backend/10-authentication/{06-candy-login-forms.md → 06-odac-login-forms.md} +125 -125
- package/docs/backend/11-mail/01-the-mail-service.md +5 -5
- package/docs/backend/12-streaming/01-streaming-overview.md +96 -54
- package/docs/backend/13-utilities/{01-candy-var.md → 01-odac-var.md} +109 -109
- package/docs/frontend/01-overview/01-introduction.md +30 -30
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +45 -45
- package/docs/frontend/02-ajax-navigation/02-configuration.md +14 -14
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +36 -36
- package/docs/frontend/03-forms/01-form-handling.md +32 -32
- package/docs/frontend/04-api-requests/01-get-post.md +33 -33
- package/docs/frontend/05-streaming/01-client-streaming.md +15 -15
- package/docs/frontend/06-websocket/00-overview.md +76 -0
- package/docs/frontend/06-websocket/01-websocket-client.md +139 -0
- package/docs/frontend/06-websocket/02-shared-websocket.md +149 -0
- package/docs/index.json +49 -11
- package/eslint.config.mjs +6 -6
- package/{framework/index.js → index.js} +1 -1
- package/package.json +14 -39
- package/{framework/src → src}/Auth.js +59 -59
- package/{framework/src → src}/Config.js +3 -3
- package/{framework/src → src}/Lang.js +7 -7
- package/{framework/src → src}/Mail.js +5 -5
- package/{framework/src → src}/Mysql.js +42 -42
- package/src/Odac.js +112 -0
- package/{framework/src → src}/Request.js +38 -36
- package/{framework/src → src}/Route/Internal.js +116 -116
- package/src/Route/Middleware.js +75 -0
- package/src/Route.js +621 -0
- package/src/Server.js +22 -0
- package/{framework/src → src}/Stream.js +11 -3
- package/{framework/src → src}/Validator.js +21 -21
- package/{framework/src → src}/Var.js +5 -5
- package/{framework/src → src}/View/EarlyHints.js +1 -1
- package/{framework/src → src}/View/Form.js +69 -69
- package/{framework/src → src}/View.js +78 -81
- package/src/WebSocket.js +403 -0
- package/template/config.json +5 -0
- package/{web → template}/controller/page/about.js +6 -6
- package/{web → template}/controller/page/index.js +9 -9
- package/{web → template}/package.json +4 -5
- package/{web → template}/public/assets/css/style.css +4 -4
- package/{web → template}/public/assets/js/app.js +6 -6
- package/{web → template}/route/www.js +6 -6
- package/{web → template}/skeleton/main.html +1 -1
- package/{web → template}/view/content/about.html +5 -5
- package/{web → template}/view/content/home.html +12 -12
- package/template/view/footer/main.html +11 -0
- package/{web → template}/view/head/main.html +1 -1
- package/{web → template}/view/header/main.html +2 -2
- package/test/core/Candy.test.js +58 -58
- package/test/core/Commands.test.js +7 -7
- package/test/core/Config.test.js +82 -85
- package/test/core/Lang.test.js +2 -2
- package/test/core/Process.test.js +6 -6
- package/test/framework/Route.test.js +56 -37
- package/test/framework/View/EarlyHints.test.js +2 -2
- package/test/framework/WebSocket.test.js +100 -0
- package/test/framework/middleware.test.js +85 -0
- package/test/server/Api.test.js +31 -31
- package/test/server/DNS.test.js +11 -11
- package/test/server/Hub.test.js +497 -0
- package/test/server/Mail.account.test_.js +3 -3
- package/test/server/Mail.init.test_.js +10 -10
- package/test/server/Mail.test_.js +20 -20
- package/test/server/SSL.test_.js +54 -54
- package/test/server/Server.test.js +39 -39
- package/test/server/Service.test_.js +7 -7
- package/test/server/Subdomain.test.js +7 -7
- package/test/server/Web/Firewall.test.js +87 -87
- package/test/server/Web/Proxy.test.js +397 -0
- package/test/server/{Web.test_.js → Web.test.js} +137 -205
- package/test/server/__mocks__/fs.js +2 -2
- package/test/server/__mocks__/{globalCandy.js → globalOdac.js} +5 -5
- package/test/server/__mocks__/index.js +6 -6
- package/test/server/__mocks__/testFactories.js +1 -1
- package/test/server/__mocks__/testHelpers.js +7 -7
- package/.husky/pre-commit +0 -2
- package/.kiro/steering/code-style.md +0 -56
- package/.kiro/steering/product.md +0 -20
- package/.kiro/steering/structure.md +0 -77
- package/.kiro/steering/tech.md +0 -87
- package/AGENTS.md +0 -84
- package/bin/candy +0 -10
- package/bin/candypack +0 -10
- package/cli/index.js +0 -3
- package/cli/src/Cli.js +0 -348
- package/cli/src/Connector.js +0 -93
- package/cli/src/Monitor.js +0 -416
- package/core/Candy.js +0 -87
- package/core/Commands.js +0 -239
- package/core/Config.js +0 -1094
- package/core/Lang.js +0 -52
- package/core/Log.js +0 -43
- package/core/Process.js +0 -26
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +0 -20
- package/docs/server/01-installation/01-quick-install.md +0 -19
- package/docs/server/01-installation/02-manual-installation-via-npm.md +0 -9
- package/docs/server/02-get-started/01-core-concepts.md +0 -7
- package/docs/server/02-get-started/02-basic-commands.md +0 -57
- package/docs/server/02-get-started/03-cli-reference.md +0 -276
- package/docs/server/02-get-started/04-cli-quick-reference.md +0 -102
- package/docs/server/03-service/01-start-a-new-service.md +0 -57
- package/docs/server/03-service/02-delete-a-service.md +0 -48
- package/docs/server/04-web/01-create-a-website.md +0 -36
- package/docs/server/04-web/02-list-websites.md +0 -9
- package/docs/server/04-web/03-delete-a-website.md +0 -29
- package/docs/server/05-subdomain/01-create-a-subdomain.md +0 -32
- package/docs/server/05-subdomain/02-list-subdomains.md +0 -33
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +0 -41
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +0 -34
- package/docs/server/07-mail/01-create-a-mail-account.md +0 -23
- package/docs/server/07-mail/02-delete-a-mail-account.md +0 -20
- package/docs/server/07-mail/03-list-mail-accounts.md +0 -20
- package/docs/server/07-mail/04-change-account-password.md +0 -23
- package/framework/src/Candy.js +0 -81
- package/framework/src/Route.js +0 -455
- package/framework/src/Server.js +0 -15
- package/locale/de-DE.json +0 -80
- package/locale/en-US.json +0 -79
- package/locale/es-ES.json +0 -80
- package/locale/fr-FR.json +0 -80
- package/locale/pt-BR.json +0 -80
- package/locale/ru-RU.json +0 -80
- package/locale/tr-TR.json +0 -85
- package/locale/zh-CN.json +0 -80
- package/server/index.js +0 -5
- package/server/src/Api.js +0 -88
- package/server/src/DNS.js +0 -940
- package/server/src/Hub.js +0 -535
- package/server/src/Mail.js +0 -571
- package/server/src/SSL.js +0 -180
- package/server/src/Server.js +0 -27
- package/server/src/Service.js +0 -248
- package/server/src/Subdomain.js +0 -64
- package/server/src/Web/Firewall.js +0 -170
- package/server/src/Web/Proxy.js +0 -134
- package/server/src/Web.js +0 -451
- package/server/src/mail/imap.js +0 -1091
- package/server/src/mail/server.js +0 -32
- package/server/src/mail/smtp.js +0 -786
- package/test/server/Client.test.js +0 -338
- package/test/server/__mocks__/http-proxy.js +0 -105
- package/watchdog/index.js +0 -3
- package/watchdog/src/Watchdog.js +0 -156
- package/web/config.json +0 -5
- package/web/view/footer/main.html +0 -11
- /package/{framework/src → src}/Env.js +0 -0
- /package/{framework/src → src}/Route/Cron.js +0 -0
- /package/{framework/src → src}/Token.js +0 -0
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
## 🔗 Request Data (Query Parameters)
|
|
2
2
|
|
|
3
|
-
The `<
|
|
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 `<
|
|
7
|
+
Use `<odac get="key" />` to access URL query parameters:
|
|
8
8
|
|
|
9
|
-
**Important:** `<
|
|
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: <
|
|
15
|
-
<p>Current page: <
|
|
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. `<
|
|
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
|
-
<
|
|
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
|
-
**`<
|
|
38
|
+
**`<odac get>` - Query Parameters (from URL):**
|
|
39
39
|
```html
|
|
40
40
|
<!-- URL: /search?q=laptop -->
|
|
41
|
-
<
|
|
41
|
+
<odac get="q" />
|
|
42
42
|
<!-- Output: laptop -->
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
**`<
|
|
45
|
+
**`<odac var>` - Controller Data (from Odac.set()):**
|
|
46
46
|
```javascript
|
|
47
47
|
// Controller
|
|
48
|
-
|
|
48
|
+
Odac.set('productName', 'Laptop')
|
|
49
49
|
```
|
|
50
50
|
```html
|
|
51
51
|
<!-- View -->
|
|
52
|
-
<
|
|
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 `<
|
|
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(
|
|
62
|
+
module.exports = async function(Odac) {
|
|
63
63
|
// Get query parameters
|
|
64
|
-
const query =
|
|
65
|
-
const page = parseInt(
|
|
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
|
|
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
|
-
|
|
79
|
+
Odac.set({
|
|
80
80
|
query: validatedQuery,
|
|
81
81
|
page: validatedPage,
|
|
82
82
|
results: results
|
|
83
83
|
})
|
|
84
84
|
|
|
85
|
-
|
|
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 "<
|
|
92
|
-
<p>Page <
|
|
91
|
+
<h1>Search Results for "<odac var="query" />"</h1>
|
|
92
|
+
<p>Page <odac var="page" /></p>
|
|
93
93
|
|
|
94
|
-
<
|
|
94
|
+
<odac:for in="results" value="product">
|
|
95
95
|
<div class="product">
|
|
96
|
-
<h3><
|
|
97
|
-
<p><
|
|
96
|
+
<h3><odac var="product.name" /></h3>
|
|
97
|
+
<p><odac var="product.price" /></p>
|
|
98
98
|
</div>
|
|
99
|
-
</
|
|
99
|
+
</odac:for>
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
### Accessing Request Object
|
|
103
103
|
|
|
104
|
-
You can access the full Request object through the
|
|
104
|
+
You can access the full Request object through the Odac object:
|
|
105
105
|
|
|
106
106
|
```html
|
|
107
107
|
<!-- Request method -->
|
|
108
|
-
<p>Method: <
|
|
108
|
+
<p>Method: <odac var="Odac.Request.method" /></p>
|
|
109
109
|
|
|
110
110
|
<!-- Current URL -->
|
|
111
|
-
<p>URL: <
|
|
111
|
+
<p>URL: <odac var="Odac.Request.url" /></p>
|
|
112
112
|
|
|
113
113
|
<!-- Client IP -->
|
|
114
|
-
<p>IP: <
|
|
114
|
+
<p>IP: <odac var="Odac.Request.ip" /></p>
|
|
115
115
|
|
|
116
116
|
<!-- User agent -->
|
|
117
|
-
<p>Browser: <
|
|
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="<
|
|
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
|
-
<
|
|
138
|
-
<p>Showing results for: "<
|
|
139
|
-
</
|
|
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:
|
|
146
|
-
const currentPage = parseInt(
|
|
145
|
+
<script:odac>
|
|
146
|
+
const currentPage = parseInt(Odac.Request.get('page')) || 1
|
|
147
147
|
const totalPages = 10
|
|
148
|
-
</script:
|
|
148
|
+
</script:odac>
|
|
149
149
|
|
|
150
150
|
<div class="pagination">
|
|
151
|
-
<
|
|
152
|
-
<a href="?page=<
|
|
153
|
-
</
|
|
151
|
+
<odac:if condition="currentPage > 1">
|
|
152
|
+
<a href="?page=<odac var="currentPage - 1" />">Previous</a>
|
|
153
|
+
</odac:if>
|
|
154
154
|
|
|
155
|
-
<span>Page <
|
|
155
|
+
<span>Page <odac var="currentPage" /> of <odac var="totalPages" /></span>
|
|
156
156
|
|
|
157
|
-
<
|
|
158
|
-
<a href="?page=<
|
|
159
|
-
</
|
|
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" <
|
|
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" <
|
|
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" <
|
|
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" <
|
|
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="<
|
|
196
|
+
<a href="/" class="<odac:if condition="Odac.Request.url === '/'">active</odac:if>">
|
|
197
197
|
Home
|
|
198
198
|
</a>
|
|
199
|
-
<a href="/products" class="<
|
|
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="<
|
|
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(
|
|
219
|
-
const limit = Math.min(100, parseInt(
|
|
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
|
-
|
|
222
|
-
|
|
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
|
-
<
|
|
228
|
+
<odac:if condition="parseInt(Odac.Request.get('page')) > 0 && parseInt(Odac.Request.get('page')) < 100">
|
|
229
229
|
...
|
|
230
|
-
</
|
|
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
|
-
<
|
|
8
|
+
<odac:if condition="user.isAdmin">
|
|
9
9
|
<p>Welcome to the admin panel!</p>
|
|
10
|
-
</
|
|
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
|
-
<
|
|
19
|
-
<p>Welcome back, <
|
|
20
|
-
<
|
|
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
|
-
</
|
|
22
|
+
</odac:if>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
### If-ElseIf-Else Structure
|
|
26
26
|
|
|
27
27
|
```html
|
|
28
|
-
<
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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
|
-
<
|
|
40
|
+
<odac:else>
|
|
41
41
|
<div class="user-panel">
|
|
42
42
|
<p>You have regular user privileges</p>
|
|
43
43
|
</div>
|
|
44
|
-
</
|
|
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
|
-
<
|
|
53
|
+
<odac:if condition="status === 'active'">Active</odac:if>
|
|
54
54
|
|
|
55
55
|
<!-- Comparison -->
|
|
56
|
-
<
|
|
57
|
-
<
|
|
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
|
-
<
|
|
60
|
+
<odac:if condition="user.isVerified && user.isPremium">
|
|
61
61
|
Premium Verified User
|
|
62
|
-
</
|
|
62
|
+
</odac:if>
|
|
63
63
|
|
|
64
|
-
<
|
|
64
|
+
<odac:if condition="role === 'admin' || role === 'moderator'">
|
|
65
65
|
Staff Member
|
|
66
|
-
</
|
|
66
|
+
</odac:if>
|
|
67
67
|
|
|
68
68
|
<!-- Negation -->
|
|
69
|
-
<
|
|
69
|
+
<odac:if condition="!user.isBanned">
|
|
70
70
|
Welcome!
|
|
71
|
-
</
|
|
71
|
+
</odac:if>
|
|
72
72
|
|
|
73
73
|
<!-- Existence check -->
|
|
74
|
-
<
|
|
74
|
+
<odac:if condition="user">
|
|
75
75
|
User exists
|
|
76
|
-
</
|
|
76
|
+
</odac:if>
|
|
77
77
|
|
|
78
78
|
<!-- Array/String length -->
|
|
79
|
-
<
|
|
79
|
+
<odac:if condition="items.length > 0">
|
|
80
80
|
You have items
|
|
81
|
-
</
|
|
81
|
+
</odac:if>
|
|
82
82
|
|
|
83
83
|
<!-- Method calls -->
|
|
84
|
-
<
|
|
84
|
+
<odac:if condition="Odac.Auth.check()">
|
|
85
85
|
Logged in
|
|
86
|
-
</
|
|
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
|
-
<
|
|
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
|
-
<
|
|
99
|
+
<odac:else>
|
|
100
100
|
<a href="/login">Login</a>
|
|
101
101
|
<a href="/register">Register</a>
|
|
102
|
-
</
|
|
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><
|
|
111
|
-
<p class="price">$<
|
|
110
|
+
<h3><odac var="product.name" /></h3>
|
|
111
|
+
<p class="price">$<odac var="product.price" /></p>
|
|
112
112
|
|
|
113
|
-
<
|
|
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
|
-
<
|
|
117
|
-
<span class="badge low-stock">Only <
|
|
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
|
-
<
|
|
119
|
+
<odac:else>
|
|
120
120
|
<span class="badge out-of-stock">Out of Stock</span>
|
|
121
121
|
<button disabled>Notify Me</button>
|
|
122
|
-
</
|
|
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
|
-
<
|
|
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
|
-
</
|
|
139
|
+
</odac:if>
|
|
140
140
|
|
|
141
|
-
<
|
|
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
|
-
</
|
|
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="<
|
|
163
|
+
<input type="email" name="email" value="<odac var="email" />">
|
|
164
164
|
|
|
165
|
-
<
|
|
166
|
-
<span class="error"><
|
|
167
|
-
</
|
|
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
|
-
<
|
|
175
|
-
<span class="error"><
|
|
176
|
-
</
|
|
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
|
-
<
|
|
179
|
+
<odac:if condition="success">
|
|
180
180
|
<div class="success-message">
|
|
181
|
-
<
|
|
181
|
+
<odac var="success" />
|
|
182
182
|
</div>
|
|
183
|
-
</
|
|
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 <
|
|
193
|
-
<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
|
-
<
|
|
195
|
+
<odac:if condition="user.isPremium">
|
|
196
196
|
<span class="badge">⭐ Premium</span>
|
|
197
|
-
</
|
|
197
|
+
</odac:if>
|
|
198
198
|
|
|
199
|
-
<
|
|
199
|
+
<odac:if condition="user.isVerified">
|
|
200
200
|
<span class="badge">✓ Verified</span>
|
|
201
|
-
</
|
|
201
|
+
</odac:if>
|
|
202
202
|
</div>
|
|
203
203
|
```
|
|
204
204
|
|
|
205
205
|
#### Nested Conditions
|
|
206
206
|
|
|
207
207
|
```html
|
|
208
|
-
<
|
|
209
|
-
<
|
|
210
|
-
<
|
|
211
|
-
<
|
|
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
|
-
<
|
|
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
|
-
</
|
|
222
|
-
<
|
|
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
|
-
</
|
|
228
|
-
<
|
|
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
|
-
</
|
|
233
|
-
<
|
|
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
|
-
</
|
|
238
|
+
</odac:if>
|
|
239
239
|
```
|
|
240
240
|
|
|
241
241
|
#### Conditional Attributes
|
|
242
242
|
|
|
243
243
|
```html
|
|
244
244
|
<!-- Disabled button -->
|
|
245
|
-
<button <
|
|
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" <
|
|
252
|
-
<option value="us" <
|
|
253
|
-
<option value="uk" <
|
|
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
|
-
<
|
|
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
|
-
|
|
274
|
+
Odac.set('canEdit', user.isAdmin || user.id === post.authorId)
|
|
275
275
|
```
|
|
276
276
|
|
|
277
277
|
```html
|
|
278
278
|
<!-- View -->
|
|
279
|
-
<
|
|
279
|
+
<odac:if condition="canEdit">
|
|
280
280
|
<button>Edit</button>
|
|
281
|
-
</
|
|
281
|
+
</odac:if>
|
|
282
282
|
```
|
|
283
283
|
|
|
284
284
|
**Avoid:**
|
|
285
285
|
```html
|
|
286
286
|
<!-- Too complex for a view -->
|
|
287
|
-
<
|
|
287
|
+
<odac:if condition="(user && user.role === 'admin') || (user && post && user.id === post.authorId && !post.isLocked)">
|
|
288
288
|
<button>Edit</button>
|
|
289
|
-
</
|
|
289
|
+
</odac:if>
|
|
290
290
|
```
|