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.
- package/.editorconfig +21 -0
- package/.github/workflows/auto-pr-description.yml +49 -0
- package/.github/workflows/release.yml +32 -0
- package/.github/workflows/test-coverage.yml +58 -0
- package/.husky/pre-commit +2 -0
- package/.kiro/steering/code-style.md +56 -0
- package/.kiro/steering/product.md +20 -0
- package/.kiro/steering/structure.md +77 -0
- package/.kiro/steering/tech.md +87 -0
- package/.prettierrc +10 -0
- package/.releaserc.js +134 -0
- package/AGENTS.md +84 -0
- package/CHANGELOG.md +181 -0
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +63 -0
- package/LICENSE +661 -0
- package/README.md +57 -0
- package/SECURITY.md +26 -0
- package/bin/candy +10 -0
- package/bin/candypack +10 -0
- package/cli/index.js +3 -0
- package/cli/src/Cli.js +348 -0
- package/cli/src/Connector.js +93 -0
- package/cli/src/Monitor.js +416 -0
- package/core/Candy.js +87 -0
- package/core/Commands.js +239 -0
- package/core/Config.js +1094 -0
- package/core/Lang.js +52 -0
- package/core/Log.js +43 -0
- package/core/Process.js +26 -0
- package/docs/backend/01-overview/01-whats-in-the-candy-box.md +9 -0
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +9 -0
- package/docs/backend/01-overview/03-development-server.md +79 -0
- package/docs/backend/02-structure/01-typical-project-layout.md +39 -0
- package/docs/backend/03-config/00-configuration-overview.md +214 -0
- package/docs/backend/03-config/01-database-connection.md +60 -0
- package/docs/backend/03-config/02-static-route-mapping-optional.md +20 -0
- package/docs/backend/03-config/03-request-timeout.md +11 -0
- package/docs/backend/03-config/04-environment-variables.md +227 -0
- package/docs/backend/03-config/05-early-hints.md +352 -0
- package/docs/backend/04-routing/01-basic-page-routes.md +28 -0
- package/docs/backend/04-routing/02-controller-less-view-routes.md +43 -0
- package/docs/backend/04-routing/03-api-and-data-routes.md +20 -0
- package/docs/backend/04-routing/04-authentication-aware-routes.md +48 -0
- package/docs/backend/04-routing/05-advanced-routing.md +14 -0
- package/docs/backend/04-routing/06-error-pages.md +101 -0
- package/docs/backend/04-routing/07-cron-jobs.md +149 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +17 -0
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +20 -0
- package/docs/backend/05-controllers/03-controller-classes.md +93 -0
- package/docs/backend/05-forms/01-custom-forms.md +395 -0
- package/docs/backend/05-forms/02-automatic-database-insert.md +297 -0
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +96 -0
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +40 -0
- package/docs/backend/07-views/01-the-view-directory.md +73 -0
- package/docs/backend/07-views/02-rendering-a-view.md +179 -0
- package/docs/backend/07-views/03-template-syntax.md +181 -0
- package/docs/backend/07-views/03-variables.md +328 -0
- package/docs/backend/07-views/04-request-data.md +231 -0
- package/docs/backend/07-views/05-conditionals.md +290 -0
- package/docs/backend/07-views/06-loops.md +353 -0
- package/docs/backend/07-views/07-translations.md +358 -0
- package/docs/backend/07-views/08-backend-javascript.md +398 -0
- package/docs/backend/07-views/09-comments.md +297 -0
- package/docs/backend/08-database/01-database-connection.md +99 -0
- package/docs/backend/08-database/02-using-mysql.md +322 -0
- package/docs/backend/09-validation/01-the-validator-service.md +424 -0
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +53 -0
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +55 -0
- package/docs/backend/10-authentication/03-register.md +134 -0
- package/docs/backend/10-authentication/04-candy-register-forms.md +676 -0
- package/docs/backend/10-authentication/05-session-management.md +159 -0
- package/docs/backend/10-authentication/06-candy-login-forms.md +596 -0
- package/docs/backend/11-mail/01-the-mail-service.md +42 -0
- package/docs/backend/12-streaming/01-streaming-overview.md +300 -0
- package/docs/backend/13-utilities/01-candy-var.md +504 -0
- package/docs/frontend/01-overview/01-introduction.md +146 -0
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +608 -0
- package/docs/frontend/02-ajax-navigation/02-configuration.md +370 -0
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +519 -0
- package/docs/frontend/03-forms/01-form-handling.md +420 -0
- package/docs/frontend/04-api-requests/01-get-post.md +443 -0
- package/docs/frontend/05-streaming/01-client-streaming.md +163 -0
- package/docs/index.json +452 -0
- package/docs/server/01-installation/01-quick-install.md +19 -0
- package/docs/server/01-installation/02-manual-installation-via-npm.md +9 -0
- package/docs/server/02-get-started/01-core-concepts.md +7 -0
- package/docs/server/02-get-started/02-basic-commands.md +57 -0
- package/docs/server/02-get-started/03-cli-reference.md +276 -0
- package/docs/server/02-get-started/04-cli-quick-reference.md +102 -0
- package/docs/server/03-service/01-start-a-new-service.md +57 -0
- package/docs/server/03-service/02-delete-a-service.md +48 -0
- package/docs/server/04-web/01-create-a-website.md +36 -0
- package/docs/server/04-web/02-list-websites.md +9 -0
- package/docs/server/04-web/03-delete-a-website.md +29 -0
- package/docs/server/05-subdomain/01-create-a-subdomain.md +32 -0
- package/docs/server/05-subdomain/02-list-subdomains.md +33 -0
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +41 -0
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +34 -0
- package/docs/server/07-mail/01-create-a-mail-account.md +23 -0
- package/docs/server/07-mail/02-delete-a-mail-account.md +20 -0
- package/docs/server/07-mail/03-list-mail-accounts.md +20 -0
- package/docs/server/07-mail/04-change-account-password.md +23 -0
- package/eslint.config.mjs +120 -0
- package/framework/index.js +4 -0
- package/framework/src/Auth.js +309 -0
- package/framework/src/Candy.js +81 -0
- package/framework/src/Config.js +79 -0
- package/framework/src/Env.js +60 -0
- package/framework/src/Lang.js +57 -0
- package/framework/src/Mail.js +83 -0
- package/framework/src/Mysql.js +575 -0
- package/framework/src/Request.js +301 -0
- package/framework/src/Route/Cron.js +128 -0
- package/framework/src/Route/Internal.js +439 -0
- package/framework/src/Route.js +455 -0
- package/framework/src/Server.js +15 -0
- package/framework/src/Stream.js +163 -0
- package/framework/src/Token.js +37 -0
- package/framework/src/Validator.js +271 -0
- package/framework/src/Var.js +211 -0
- package/framework/src/View/EarlyHints.js +190 -0
- package/framework/src/View/Form.js +600 -0
- package/framework/src/View.js +513 -0
- package/framework/web/candy.js +838 -0
- package/jest.config.js +22 -0
- package/locale/de-DE.json +80 -0
- package/locale/en-US.json +79 -0
- package/locale/es-ES.json +80 -0
- package/locale/fr-FR.json +80 -0
- package/locale/pt-BR.json +80 -0
- package/locale/ru-RU.json +80 -0
- package/locale/tr-TR.json +85 -0
- package/locale/zh-CN.json +80 -0
- package/package.json +86 -0
- package/server/index.js +5 -0
- package/server/src/Api.js +88 -0
- package/server/src/DNS.js +940 -0
- package/server/src/Hub.js +535 -0
- package/server/src/Mail.js +571 -0
- package/server/src/SSL.js +180 -0
- package/server/src/Server.js +27 -0
- package/server/src/Service.js +248 -0
- package/server/src/Subdomain.js +64 -0
- package/server/src/Web/Firewall.js +170 -0
- package/server/src/Web/Proxy.js +134 -0
- package/server/src/Web.js +451 -0
- package/server/src/mail/imap.js +1091 -0
- package/server/src/mail/server.js +32 -0
- package/server/src/mail/smtp.js +786 -0
- package/test/cli/Cli.test.js +36 -0
- package/test/core/Candy.test.js +234 -0
- package/test/core/Commands.test.js +538 -0
- package/test/core/Config.test.js +1435 -0
- package/test/core/Lang.test.js +250 -0
- package/test/core/Process.test.js +156 -0
- package/test/framework/Route.test.js +239 -0
- package/test/framework/View/EarlyHints.test.js +282 -0
- package/test/scripts/check-coverage.js +132 -0
- package/test/server/Api.test.js +647 -0
- package/test/server/Client.test.js +338 -0
- package/test/server/DNS.test.js +2050 -0
- package/test/server/DNS.test.js.bak +2084 -0
- package/test/server/Log.test.js +73 -0
- package/test/server/Mail.account.test_.js +460 -0
- package/test/server/Mail.init.test_.js +411 -0
- package/test/server/Mail.test_.js +1340 -0
- package/test/server/SSL.test_.js +1491 -0
- package/test/server/Server.test.js +765 -0
- package/test/server/Service.test_.js +1127 -0
- package/test/server/Subdomain.test.js +440 -0
- package/test/server/Web/Firewall.test.js +175 -0
- package/test/server/Web.test_.js +1562 -0
- package/test/server/__mocks__/acme-client.js +17 -0
- package/test/server/__mocks__/bcrypt.js +50 -0
- package/test/server/__mocks__/child_process.js +389 -0
- package/test/server/__mocks__/crypto.js +432 -0
- package/test/server/__mocks__/fs.js +450 -0
- package/test/server/__mocks__/globalCandy.js +227 -0
- package/test/server/__mocks__/http-proxy.js +105 -0
- package/test/server/__mocks__/http.js +575 -0
- package/test/server/__mocks__/https.js +272 -0
- package/test/server/__mocks__/index.js +249 -0
- package/test/server/__mocks__/mail/server.js +100 -0
- package/test/server/__mocks__/mail/smtp.js +31 -0
- package/test/server/__mocks__/mailparser.js +81 -0
- package/test/server/__mocks__/net.js +369 -0
- package/test/server/__mocks__/node-forge.js +328 -0
- package/test/server/__mocks__/os.js +320 -0
- package/test/server/__mocks__/path.js +291 -0
- package/test/server/__mocks__/selfsigned.js +8 -0
- package/test/server/__mocks__/server/src/mail/server.js +100 -0
- package/test/server/__mocks__/server/src/mail/smtp.js +31 -0
- package/test/server/__mocks__/smtp-server.js +106 -0
- package/test/server/__mocks__/sqlite3.js +394 -0
- package/test/server/__mocks__/testFactories.js +299 -0
- package/test/server/__mocks__/testHelpers.js +363 -0
- package/test/server/__mocks__/tls.js +229 -0
- package/watchdog/index.js +3 -0
- package/watchdog/src/Watchdog.js +156 -0
- package/web/config.json +5 -0
- package/web/controller/page/about.js +27 -0
- package/web/controller/page/index.js +34 -0
- package/web/package.json +18 -0
- package/web/public/assets/css/style.css +1835 -0
- package/web/public/assets/js/app.js +96 -0
- package/web/route/www.js +19 -0
- package/web/skeleton/main.html +22 -0
- package/web/view/content/about.html +65 -0
- package/web/view/content/home.html +205 -0
- package/web/view/footer/main.html +11 -0
- package/web/view/head/main.html +5 -0
- package/web/view/header/main.html +14 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# AJAX Navigation Configuration
|
|
2
|
+
|
|
3
|
+
Learn how to configure and customize AJAX navigation in your CandyPack application.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Before configuring AJAX navigation, ensure your skeleton template is properly set up. See the [Quick Start guide](01-quick-start.md#skeleton-structure-required) for skeleton setup instructions.
|
|
8
|
+
|
|
9
|
+
**Key requirements:**
|
|
10
|
+
- Skeleton placeholders must be UPPERCASE and wrapped in HTML tags (e.g., `<main>{{ CONTENT }}</main>`)
|
|
11
|
+
- Controller keys are lowercase (e.g., `content: 'home'`)
|
|
12
|
+
- Frontend selectors target the HTML tags (e.g., `content: 'main'` targets `<main>` tag)
|
|
13
|
+
|
|
14
|
+
**Mapping example:**
|
|
15
|
+
- Skeleton: `<main>{{ CONTENT }}</main>`
|
|
16
|
+
- Controller: `content: 'home'`
|
|
17
|
+
- Frontend: `update: { content: 'main' }`
|
|
18
|
+
|
|
19
|
+
## Configuration Options
|
|
20
|
+
|
|
21
|
+
### Basic Configuration
|
|
22
|
+
|
|
23
|
+
The simplest way to enable AJAX navigation:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
Candy.action({
|
|
27
|
+
navigate: 'main' // Update <main> element
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Full Configuration
|
|
32
|
+
|
|
33
|
+
All available options:
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
Candy.action({
|
|
37
|
+
navigate: {
|
|
38
|
+
// Which links to intercept
|
|
39
|
+
links: 'a[href^="/"]', // Default: all internal links
|
|
40
|
+
|
|
41
|
+
// Which elements to update
|
|
42
|
+
update: {
|
|
43
|
+
content: 'main',
|
|
44
|
+
header: 'header',
|
|
45
|
+
sidebar: '#sidebar'
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Callback after navigation
|
|
49
|
+
on: function(page, variables) {
|
|
50
|
+
console.log('Navigated to:', page)
|
|
51
|
+
console.log('Server data:', variables)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Link Selectors
|
|
58
|
+
|
|
59
|
+
### Default Behavior
|
|
60
|
+
|
|
61
|
+
By default, all internal links (starting with `/`) are intercepted:
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
navigate: true // Uses 'a[href^="/"]'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Custom Selectors
|
|
68
|
+
|
|
69
|
+
Target specific links:
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
navigate: {
|
|
73
|
+
links: 'nav a', // Only navigation links
|
|
74
|
+
update: 'main'
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
navigate: {
|
|
80
|
+
links: 'a.ajax-link', // Only links with class
|
|
81
|
+
update: 'main'
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Excluding Links
|
|
86
|
+
|
|
87
|
+
Exclude specific links from AJAX navigation:
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<!-- Using data attribute -->
|
|
91
|
+
<a href="/download.pdf" data-navigate="false">Download</a>
|
|
92
|
+
|
|
93
|
+
<!-- Using CSS class -->
|
|
94
|
+
<a href="/logout" class="no-navigate">Logout</a>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Both methods work automatically - no additional configuration needed!
|
|
98
|
+
|
|
99
|
+
## Element Updates
|
|
100
|
+
|
|
101
|
+
### Single Element
|
|
102
|
+
|
|
103
|
+
Update one element:
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
navigate: 'main' // Shorthand
|
|
107
|
+
// or
|
|
108
|
+
navigate: {
|
|
109
|
+
update: 'main'
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Multiple Elements
|
|
114
|
+
|
|
115
|
+
Update multiple elements simultaneously:
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
navigate: {
|
|
119
|
+
update: {
|
|
120
|
+
content: 'main',
|
|
121
|
+
header: 'header',
|
|
122
|
+
sidebar: '#sidebar',
|
|
123
|
+
breadcrumb: '.breadcrumb'
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The keys (content, header, etc.) must match the view parts defined in your controller:
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
// In controller
|
|
132
|
+
Candy.View.set({
|
|
133
|
+
header: 'main',
|
|
134
|
+
content: 'about',
|
|
135
|
+
sidebar: 'main'
|
|
136
|
+
})
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Callbacks
|
|
140
|
+
|
|
141
|
+
### Navigation Callback
|
|
142
|
+
|
|
143
|
+
Execute code after each navigation:
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
navigate: {
|
|
147
|
+
update: 'main',
|
|
148
|
+
on: function(page, variables) {
|
|
149
|
+
// page: current page name (e.g., 'about')
|
|
150
|
+
// variables: data from server
|
|
151
|
+
|
|
152
|
+
// Update page title
|
|
153
|
+
document.title = variables.title || page
|
|
154
|
+
|
|
155
|
+
// Track analytics
|
|
156
|
+
if (window.gtag) {
|
|
157
|
+
gtag('event', 'page_view', {
|
|
158
|
+
page_path: window.location.pathname
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Update active navigation
|
|
163
|
+
updateActiveNav()
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Page-Specific Actions
|
|
169
|
+
|
|
170
|
+
Run code for specific pages:
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
Candy.action({
|
|
174
|
+
navigate: {
|
|
175
|
+
update: 'main',
|
|
176
|
+
on: (page, vars) => console.log('Navigated to:', page)
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
page: {
|
|
180
|
+
index: function(variables) {
|
|
181
|
+
console.log('Home page loaded')
|
|
182
|
+
},
|
|
183
|
+
about: function(variables) {
|
|
184
|
+
console.log('About page:', variables.title)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Disabling Navigation
|
|
191
|
+
|
|
192
|
+
### Disable Completely
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
Candy.action({
|
|
196
|
+
navigate: false // No AJAX navigation
|
|
197
|
+
})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Disable for Specific Links
|
|
201
|
+
|
|
202
|
+
```html
|
|
203
|
+
<!-- Data attribute -->
|
|
204
|
+
<a href="/download" data-navigate="false">Download</a>
|
|
205
|
+
|
|
206
|
+
<!-- CSS class -->
|
|
207
|
+
<a href="/logout" class="no-navigate">Logout</a>
|
|
208
|
+
|
|
209
|
+
<!-- External links (automatic) -->
|
|
210
|
+
<a href="https://example.com">External</a>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Server-Side Configuration
|
|
214
|
+
|
|
215
|
+
### Sending Variables
|
|
216
|
+
|
|
217
|
+
In your controller, send data to the client:
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
module.exports = function(Candy) {
|
|
221
|
+
// Set variables for AJAX responses
|
|
222
|
+
Candy.set({
|
|
223
|
+
title: 'About Page',
|
|
224
|
+
user: {name: 'John', role: 'admin'},
|
|
225
|
+
stats: {views: 1234}
|
|
226
|
+
}, true) // true = include in AJAX
|
|
227
|
+
|
|
228
|
+
Candy.View.skeleton('main')
|
|
229
|
+
Candy.View.set({
|
|
230
|
+
header: 'main',
|
|
231
|
+
content: 'about',
|
|
232
|
+
footer: 'main'
|
|
233
|
+
})
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Accessing Variables
|
|
238
|
+
|
|
239
|
+
Access server variables in your callback:
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
navigate: {
|
|
243
|
+
update: 'main',
|
|
244
|
+
on: function(page, variables) {
|
|
245
|
+
console.log(variables.title) // 'About Page'
|
|
246
|
+
console.log(variables.user.name) // 'John'
|
|
247
|
+
console.log(variables.stats.views) // 1234
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Advanced Examples
|
|
253
|
+
|
|
254
|
+
### Loading Indicator
|
|
255
|
+
|
|
256
|
+
Show a loading spinner during navigation:
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
Candy.action({
|
|
260
|
+
navigate: {
|
|
261
|
+
update: 'main',
|
|
262
|
+
on: (page, vars) => {
|
|
263
|
+
hideLoadingSpinner()
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
click: {
|
|
268
|
+
'a[href^="/"]': function(e) {
|
|
269
|
+
if (!this.hasAttribute('data-navigate') &&
|
|
270
|
+
!this.classList.contains('no-navigate')) {
|
|
271
|
+
showLoadingSpinner()
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
function showLoadingSpinner() {
|
|
278
|
+
document.getElementById('spinner').style.display = 'block'
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function hideLoadingSpinner() {
|
|
282
|
+
document.getElementById('spinner').style.display = 'none'
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Progress Bar
|
|
287
|
+
|
|
288
|
+
Animated progress bar:
|
|
289
|
+
|
|
290
|
+
```javascript
|
|
291
|
+
let progressBar = document.getElementById('progress')
|
|
292
|
+
|
|
293
|
+
Candy.action({
|
|
294
|
+
navigate: {
|
|
295
|
+
update: 'main',
|
|
296
|
+
on: () => {
|
|
297
|
+
progressBar.style.width = '100%'
|
|
298
|
+
setTimeout(() => {
|
|
299
|
+
progressBar.style.width = '0%'
|
|
300
|
+
}, 300)
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
click: {
|
|
305
|
+
'a[href^="/"]': function() {
|
|
306
|
+
if (!this.hasAttribute('data-navigate')) {
|
|
307
|
+
progressBar.style.width = '30%'
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Conditional Navigation
|
|
315
|
+
|
|
316
|
+
Confirm before navigating:
|
|
317
|
+
|
|
318
|
+
```javascript
|
|
319
|
+
Candy.action({
|
|
320
|
+
navigate: {
|
|
321
|
+
update: 'main'
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
click: {
|
|
325
|
+
'a[href^="/"]': function(e) {
|
|
326
|
+
if (hasUnsavedChanges() &&
|
|
327
|
+
!this.hasAttribute('data-navigate')) {
|
|
328
|
+
if (!confirm('You have unsaved changes. Continue?')) {
|
|
329
|
+
e.preventDefault()
|
|
330
|
+
e.stopPropagation()
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
})
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Best Practices
|
|
339
|
+
|
|
340
|
+
1. **Keep it Simple**: Start with minimal configuration
|
|
341
|
+
2. **Progressive Enhancement**: Ensure links work without JavaScript
|
|
342
|
+
3. **Loading States**: Always show loading indicators
|
|
343
|
+
4. **Error Handling**: Handle failed requests gracefully
|
|
344
|
+
5. **SEO**: Ensure content is accessible to search engines
|
|
345
|
+
6. **Performance**: Only update necessary elements
|
|
346
|
+
|
|
347
|
+
## Troubleshooting
|
|
348
|
+
|
|
349
|
+
### Links Not Working
|
|
350
|
+
|
|
351
|
+
- Check that `navigate` is enabled
|
|
352
|
+
- Verify link selector matches your links
|
|
353
|
+
- Check browser console for errors
|
|
354
|
+
|
|
355
|
+
### Elements Not Updating
|
|
356
|
+
|
|
357
|
+
- Ensure element selectors are correct
|
|
358
|
+
- Verify view parts are defined in controller
|
|
359
|
+
- Check that skeleton has correct placeholders
|
|
360
|
+
|
|
361
|
+
### Variables Not Available
|
|
362
|
+
|
|
363
|
+
- Confirm `Candy.set(data, true)` has `true` parameter
|
|
364
|
+
- Check variables are set before `View.print()`
|
|
365
|
+
|
|
366
|
+
## Next Steps
|
|
367
|
+
|
|
368
|
+
- Learn about [Form Handling](../03-forms/01-form-handling.md)
|
|
369
|
+
- Explore [API Requests](../04-api-requests/01-get-post.md)
|
|
370
|
+
- Check [Advanced Usage](03-advanced-usage.md)
|