@prosopo/client-bundle-example 2.5.0 → 2.5.3
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/dist/assets/captchaType-CYBmmAZe.js +1 -0
- package/dist/assets/dummy.txt +0 -0
- package/dist/assets/frictionless-xzpEe3JN.js +1 -0
- package/dist/assets/index-DN-EY_8b.js +1 -0
- package/dist/assets/invisible-frictionless-explicit-DgCaJtPg.js +1 -0
- package/dist/assets/invisible-image-explicit-DgCaJtPg.js +1 -0
- package/dist/assets/invisible-pow-explicit-DgCaJtPg.js +1 -0
- package/dist/assets/modulepreload-polyfill-B5Qt9EMX.js +1 -0
- package/dist/assets/pow-DpBboekQ.js +1 -0
- package/dist/frictionless.html +344 -0
- package/dist/index.html +351 -0
- package/dist/invisible-frictionless-explicit.html +534 -0
- package/dist/invisible-frictionless-implicit.html +426 -0
- package/dist/invisible-image-explicit.html +535 -0
- package/dist/invisible-image-implicit.html +426 -0
- package/dist/invisible-pow-explicit.html +535 -0
- package/dist/invisible-pow-implicit.html +426 -0
- package/dist/plugins/navigation-injector.ts +454 -0
- package/dist/pow.html +324 -0
- package/package.json +3 -3
- package/vite.config.ts +142 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<title>Procaptcha Invisible Image Mode - Explicit Rendering</title>
|
|
5
|
+
<!-- Load the Procaptcha script with explicit rendering -->
|
|
6
|
+
<script type="module" src="https://staging-js.prosopo.io/js/procaptcha.bundle.js?render=explicit" async defer></script>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: Arial, sans-serif;
|
|
10
|
+
margin: 0 auto;
|
|
11
|
+
padding: 20px;
|
|
12
|
+
}
|
|
13
|
+
form {
|
|
14
|
+
border: 1px solid #ddd;
|
|
15
|
+
padding: 20px;
|
|
16
|
+
border-radius: 5px;
|
|
17
|
+
}
|
|
18
|
+
label {
|
|
19
|
+
display: block;
|
|
20
|
+
margin-bottom: 5px;
|
|
21
|
+
}
|
|
22
|
+
input[type="text"],
|
|
23
|
+
input[type="email"] {
|
|
24
|
+
width: 100%;
|
|
25
|
+
padding: 8px;
|
|
26
|
+
margin-bottom: 15px;
|
|
27
|
+
border: 1px solid #ccc;
|
|
28
|
+
border-radius: 4px;
|
|
29
|
+
}
|
|
30
|
+
button {
|
|
31
|
+
background-color: #4CAF50;
|
|
32
|
+
color: white;
|
|
33
|
+
padding: 10px 15px;
|
|
34
|
+
border: none;
|
|
35
|
+
border-radius: 4px;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
button:hover {
|
|
39
|
+
background-color: #45a049;
|
|
40
|
+
}
|
|
41
|
+
#result {
|
|
42
|
+
margin-top: 15px;
|
|
43
|
+
padding: 10px;
|
|
44
|
+
border: 1px solid #ddd;
|
|
45
|
+
border-radius: 4px;
|
|
46
|
+
background-color: #f9f9f9;
|
|
47
|
+
display: none;
|
|
48
|
+
}
|
|
49
|
+
.console-output {
|
|
50
|
+
margin-top: 20px;
|
|
51
|
+
padding: 10px;
|
|
52
|
+
background-color: #f5f5f5;
|
|
53
|
+
border: 1px solid #ddd;
|
|
54
|
+
border-radius: 4px;
|
|
55
|
+
font-family: monospace;
|
|
56
|
+
white-space: pre-wrap;
|
|
57
|
+
max-height: 200px;
|
|
58
|
+
overflow-y: auto;
|
|
59
|
+
}
|
|
60
|
+
.info-box {
|
|
61
|
+
background-color: #e7f3fe;
|
|
62
|
+
border-left: 4px solid #2196F3;
|
|
63
|
+
padding: 15px;
|
|
64
|
+
margin: 20px 0;
|
|
65
|
+
}
|
|
66
|
+
</style>
|
|
67
|
+
<script type="text/javascript">
|
|
68
|
+
function onSubmit(token) {
|
|
69
|
+
console.log('Procaptcha verified, token:', token);
|
|
70
|
+
|
|
71
|
+
const name = document.getElementById('name').value;
|
|
72
|
+
const email = document.getElementById('email').value;
|
|
73
|
+
|
|
74
|
+
const resultElement = document.getElementById('result');
|
|
75
|
+
resultElement.textContent = `Form submitted with:
|
|
76
|
+
- Name: ${name}
|
|
77
|
+
- Email: ${email}
|
|
78
|
+
- Procaptcha verified: Yes`;
|
|
79
|
+
resultElement.style.display = 'block';
|
|
80
|
+
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function validate(event) {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
|
|
87
|
+
// Simple form validation
|
|
88
|
+
if (!document.getElementById('name').value) {
|
|
89
|
+
alert("Please enter your name");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!document.getElementById('email').value) {
|
|
94
|
+
alert("Please enter your email");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
document.getElementById('console-output').innerHTML = '';
|
|
99
|
+
const originalConsoleLog = console.log;
|
|
100
|
+
const consoleOutput = document.getElementById('console-output');
|
|
101
|
+
|
|
102
|
+
console.log = function() {
|
|
103
|
+
originalConsoleLog.apply(console, arguments);
|
|
104
|
+
|
|
105
|
+
// Format and display the arguments in our custom console
|
|
106
|
+
const args = Array.from(arguments).map(arg => {
|
|
107
|
+
if (typeof arg === 'object') {
|
|
108
|
+
try {
|
|
109
|
+
return JSON.stringify(arg, null, 2);
|
|
110
|
+
} catch (e) {
|
|
111
|
+
return "[Object cannot be stringified]";
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return String(arg);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
consoleOutput.innerHTML += args.join(' ') + '<br>';
|
|
118
|
+
consoleOutput.style.display = 'block';
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
console.log('Executing Procaptcha verification...');
|
|
122
|
+
window.procaptcha.execute();
|
|
123
|
+
|
|
124
|
+
setTimeout(() => {
|
|
125
|
+
console.log = originalConsoleLog;
|
|
126
|
+
}, 1000);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function onloadCallback() {
|
|
130
|
+
console.log('Procaptcha script loaded, initializing explicit rendering');
|
|
131
|
+
|
|
132
|
+
// Render the Procaptcha widget
|
|
133
|
+
window.procaptcha.render(document.getElementById('procaptcha-container'), {
|
|
134
|
+
'siteKey': 'undefined',
|
|
135
|
+
'callback': onSubmit,
|
|
136
|
+
'captchaType': 'image',
|
|
137
|
+
'size': 'invisible'
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
document.getElementById('submit-button').addEventListener('click', validate);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
144
|
+
// Set up the onload callback for Procaptcha
|
|
145
|
+
window.onProcaptchaLoad = onloadCallback;
|
|
146
|
+
});
|
|
147
|
+
</script>
|
|
148
|
+
|
|
149
|
+
<style>
|
|
150
|
+
.nav-topbar {
|
|
151
|
+
background-color: #2196F3;
|
|
152
|
+
padding: 0;
|
|
153
|
+
margin-bottom: 20px;
|
|
154
|
+
transition: all 0.3s ease;
|
|
155
|
+
overflow: hidden;
|
|
156
|
+
max-height: 500px; /* Initial state - visible */
|
|
157
|
+
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
|
158
|
+
}
|
|
159
|
+
.nav-topbar.collapsed {
|
|
160
|
+
max-height: 50px; /* Collapsed state - only show toggle button and title */
|
|
161
|
+
}
|
|
162
|
+
.nav-container {
|
|
163
|
+
max-width: 1200px;
|
|
164
|
+
margin: 0 auto;
|
|
165
|
+
padding: 0 15px;
|
|
166
|
+
position: relative;
|
|
167
|
+
}
|
|
168
|
+
.nav-header {
|
|
169
|
+
display: flex;
|
|
170
|
+
justify-content: space-between;
|
|
171
|
+
align-items: center;
|
|
172
|
+
padding: 10px 0;
|
|
173
|
+
position: relative;
|
|
174
|
+
z-index: 20;
|
|
175
|
+
}
|
|
176
|
+
.nav-title {
|
|
177
|
+
color: white;
|
|
178
|
+
font-size: 18px;
|
|
179
|
+
font-weight: bold;
|
|
180
|
+
margin: 0;
|
|
181
|
+
display: flex;
|
|
182
|
+
align-items: center;
|
|
183
|
+
}
|
|
184
|
+
.nav-title-text {
|
|
185
|
+
margin-right: 10px;
|
|
186
|
+
}
|
|
187
|
+
.nav-title-hint {
|
|
188
|
+
font-size: 14px;
|
|
189
|
+
font-weight: normal;
|
|
190
|
+
opacity: 0;
|
|
191
|
+
transition: opacity 0.3s ease;
|
|
192
|
+
}
|
|
193
|
+
.collapsed .nav-title-hint {
|
|
194
|
+
opacity: 0.8;
|
|
195
|
+
}
|
|
196
|
+
.nav-toggle {
|
|
197
|
+
background-color: rgba(0,0,0,0.1);
|
|
198
|
+
color: white;
|
|
199
|
+
border: none;
|
|
200
|
+
padding: 5px 10px;
|
|
201
|
+
cursor: pointer;
|
|
202
|
+
border-radius: 4px;
|
|
203
|
+
z-index: 10;
|
|
204
|
+
display: flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
justify-content: center;
|
|
207
|
+
}
|
|
208
|
+
.nav-toggle:hover {
|
|
209
|
+
background-color: rgba(0,0,0,0.2);
|
|
210
|
+
}
|
|
211
|
+
.nav-toggle-icon {
|
|
212
|
+
width: 24px;
|
|
213
|
+
height: 24px;
|
|
214
|
+
display: inline-block;
|
|
215
|
+
position: relative;
|
|
216
|
+
}
|
|
217
|
+
.nav-toggle-icon svg {
|
|
218
|
+
position: absolute;
|
|
219
|
+
top: 0;
|
|
220
|
+
left: 0;
|
|
221
|
+
transition: opacity 0.3s ease;
|
|
222
|
+
}
|
|
223
|
+
.nav-toggle-icon .icon-collapse {
|
|
224
|
+
opacity: 1;
|
|
225
|
+
}
|
|
226
|
+
.nav-toggle-icon .icon-expand {
|
|
227
|
+
opacity: 0;
|
|
228
|
+
}
|
|
229
|
+
.collapsed .nav-toggle-icon .icon-collapse {
|
|
230
|
+
opacity: 0;
|
|
231
|
+
}
|
|
232
|
+
.collapsed .nav-toggle-icon .icon-expand {
|
|
233
|
+
opacity: 1;
|
|
234
|
+
}
|
|
235
|
+
.nav-content {
|
|
236
|
+
padding: 0 0 15px 0;
|
|
237
|
+
transition: opacity 0.3s ease;
|
|
238
|
+
}
|
|
239
|
+
.collapsed .nav-content {
|
|
240
|
+
opacity: 0;
|
|
241
|
+
}
|
|
242
|
+
.nav-row {
|
|
243
|
+
display: flex;
|
|
244
|
+
flex-wrap: wrap;
|
|
245
|
+
margin-bottom: 15px;
|
|
246
|
+
}
|
|
247
|
+
.nav-group {
|
|
248
|
+
flex: 1;
|
|
249
|
+
min-width: 250px;
|
|
250
|
+
margin-bottom: 10px;
|
|
251
|
+
margin-right: 20px;
|
|
252
|
+
}
|
|
253
|
+
.nav-group-title {
|
|
254
|
+
color: rgba(255,255,255,0.8);
|
|
255
|
+
font-size: 0.9em;
|
|
256
|
+
margin: 0 0 5px 0;
|
|
257
|
+
text-transform: uppercase;
|
|
258
|
+
font-weight: 500;
|
|
259
|
+
}
|
|
260
|
+
.nav-group-links {
|
|
261
|
+
list-style: none;
|
|
262
|
+
margin: 0;
|
|
263
|
+
padding: 0;
|
|
264
|
+
}
|
|
265
|
+
.nav-group-links li {
|
|
266
|
+
margin: 5px 0;
|
|
267
|
+
}
|
|
268
|
+
.nav-group-links a {
|
|
269
|
+
color: white;
|
|
270
|
+
text-decoration: none;
|
|
271
|
+
font-weight: bold;
|
|
272
|
+
padding: 5px 0;
|
|
273
|
+
display: inline-block;
|
|
274
|
+
}
|
|
275
|
+
.nav-group-links a:hover {
|
|
276
|
+
text-decoration: underline;
|
|
277
|
+
}
|
|
278
|
+
.nav-group-links .active {
|
|
279
|
+
border-bottom: 2px solid white;
|
|
280
|
+
}
|
|
281
|
+
.nav-group-links .disabled {
|
|
282
|
+
color: rgba(255,255,255,0.5);
|
|
283
|
+
cursor: not-allowed;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
@media (max-width: 768px) {
|
|
287
|
+
.nav-row {
|
|
288
|
+
flex-direction: column;
|
|
289
|
+
}
|
|
290
|
+
.nav-title-hint {
|
|
291
|
+
display: none;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
</style>
|
|
295
|
+
<script type="module" crossorigin src="/assets/invisible-image-explicit-DgCaJtPg.js"></script>
|
|
296
|
+
<link rel="modulepreload" crossorigin href="/assets/modulepreload-polyfill-B5Qt9EMX.js">
|
|
297
|
+
</head>
|
|
298
|
+
<body>
|
|
299
|
+
|
|
300
|
+
<div id="nav-topbar" class="nav-topbar">
|
|
301
|
+
<div class="nav-container">
|
|
302
|
+
<div id="nav-header" class="nav-header">
|
|
303
|
+
<h1 class="nav-title">
|
|
304
|
+
<span class="nav-title-text">Procaptcha Demo Playground</span>
|
|
305
|
+
<span class="nav-title-hint">(Click anywhere to see more examples)</span>
|
|
306
|
+
</h1>
|
|
307
|
+
<button id="nav-toggle" class="nav-toggle" aria-label="Toggle navigation">
|
|
308
|
+
<span class="nav-toggle-icon">
|
|
309
|
+
<svg class="icon-collapse" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
310
|
+
<polyline points="18 15 12 9 6 15"></polyline>
|
|
311
|
+
</svg>
|
|
312
|
+
<svg class="icon-expand" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
313
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
314
|
+
</svg>
|
|
315
|
+
</span>
|
|
316
|
+
</button>
|
|
317
|
+
</div>
|
|
318
|
+
<div class="nav-content">
|
|
319
|
+
<div class="nav-row">
|
|
320
|
+
|
|
321
|
+
<div class="nav-section">
|
|
322
|
+
<h3 style="color: white; margin: 0 0 10px 0;">Standard Captchas</h3>
|
|
323
|
+
<div class="nav-row">
|
|
324
|
+
|
|
325
|
+
<div class="nav-group">
|
|
326
|
+
<div class="nav-group-title">Image</div>
|
|
327
|
+
<ul class="nav-group-links">
|
|
328
|
+
<li><a href="index.html">Implicit</a></li>
|
|
329
|
+
<li><span class="disabled" title="Coming Soon">Explicit</span></li>
|
|
330
|
+
</ul>
|
|
331
|
+
</div>
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
<div class="nav-group">
|
|
335
|
+
<div class="nav-group-title">Pow</div>
|
|
336
|
+
<ul class="nav-group-links">
|
|
337
|
+
<li><span class="disabled" title="Coming Soon">Implicit</span></li>
|
|
338
|
+
<li><span class="disabled" title="Coming Soon">Explicit</span></li>
|
|
339
|
+
</ul>
|
|
340
|
+
</div>
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
<div class="nav-group">
|
|
344
|
+
<div class="nav-group-title">Frictionless</div>
|
|
345
|
+
<ul class="nav-group-links">
|
|
346
|
+
<li><span class="disabled" title="Coming Soon">Implicit</span></li>
|
|
347
|
+
<li><a href="frictionless-explicit.html">Explicit</a></li>
|
|
348
|
+
</ul>
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
</div>
|
|
352
|
+
</div>
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
<div class="nav-section">
|
|
356
|
+
<h3 style="color: white; margin: 0 0 10px 0;">Invisible Captchas</h3>
|
|
357
|
+
<div class="nav-row">
|
|
358
|
+
|
|
359
|
+
<div class="nav-group">
|
|
360
|
+
<div class="nav-group-title">Image</div>
|
|
361
|
+
<ul class="nav-group-links">
|
|
362
|
+
<li><a href="invisible-image-implicit.html">Implicit</a></li>
|
|
363
|
+
<li><a href="invisible-image-explicit.html" class="active">Explicit</a></li>
|
|
364
|
+
</ul>
|
|
365
|
+
</div>
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
<div class="nav-group">
|
|
369
|
+
<div class="nav-group-title">Pow</div>
|
|
370
|
+
<ul class="nav-group-links">
|
|
371
|
+
<li><a href="invisible-pow-implicit.html">Implicit</a></li>
|
|
372
|
+
<li><a href="invisible-pow-explicit.html">Explicit</a></li>
|
|
373
|
+
</ul>
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
<div class="nav-group">
|
|
378
|
+
<div class="nav-group-title">Frictionless</div>
|
|
379
|
+
<ul class="nav-group-links">
|
|
380
|
+
<li><a href="invisible-frictionless-implicit.html">Implicit</a></li>
|
|
381
|
+
<li><a href="invisible-frictionless-explicit.html">Explicit</a></li>
|
|
382
|
+
</ul>
|
|
383
|
+
</div>
|
|
384
|
+
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
</div>
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
<h1>Procaptcha Invisible Image Mode</h1>
|
|
394
|
+
<p>This example demonstrates how to use Procaptcha in invisible image mode with explicit rendering.</p>
|
|
395
|
+
|
|
396
|
+
<form id="demo-form" action="javascript:void(0);" method="POST">
|
|
397
|
+
<div>
|
|
398
|
+
<label for="name">Name:</label>
|
|
399
|
+
<input type="text" id="name" name="name" placeholder="Your name" required />
|
|
400
|
+
</div>
|
|
401
|
+
|
|
402
|
+
<div>
|
|
403
|
+
<label for="email">Email:</label>
|
|
404
|
+
<input type="email" id="email" name="email" placeholder="Your email" required />
|
|
405
|
+
</div>
|
|
406
|
+
|
|
407
|
+
<!-- Invisible Procaptcha container -->
|
|
408
|
+
<div id="procaptcha-container" data-size="invisible"></div>
|
|
409
|
+
|
|
410
|
+
<!-- Regular submit button (not directly tied to Procaptcha) -->
|
|
411
|
+
<button id="submit-button" type="button">Submit</button>
|
|
412
|
+
</form>
|
|
413
|
+
|
|
414
|
+
<!-- Result display area -->
|
|
415
|
+
<div id="result"></div>
|
|
416
|
+
|
|
417
|
+
<!-- Console output display area -->
|
|
418
|
+
<div id="console-output" class="console-output" style="display: none;"></div>
|
|
419
|
+
|
|
420
|
+
<div style="margin-top: 20px;">
|
|
421
|
+
<h2>How It Works</h2>
|
|
422
|
+
<p>This example demonstrates how to use Procaptcha in invisible image mode with explicit rendering:</p>
|
|
423
|
+
<ol>
|
|
424
|
+
<li>Include the Procaptcha script with <code>?render=explicit</code> parameter</li>
|
|
425
|
+
<li>Create a container div with <code>data-size="invisible"</code></li>
|
|
426
|
+
<li>Define an <code>onloadCallback</code> function that renders the Procaptcha widget</li>
|
|
427
|
+
<li>Add a click handler to your submit button that validates the form and executes Procaptcha</li>
|
|
428
|
+
<li>When Procaptcha verification succeeds, your callback function is called</li>
|
|
429
|
+
</ol>
|
|
430
|
+
<p>The key elements are:</p>
|
|
431
|
+
<pre>
|
|
432
|
+
<script type="module" src="./assets/procaptcha.bundle.js?render=explicit" async defer></script>
|
|
433
|
+
|
|
434
|
+
<div id="procaptcha-container" data-size="invisible"></div>
|
|
435
|
+
|
|
436
|
+
<script>
|
|
437
|
+
// Render the widget
|
|
438
|
+
window.procaptcha.render('procaptcha-container', {
|
|
439
|
+
'siteKey': 'your_site_key',
|
|
440
|
+
'callback': onSubmit,
|
|
441
|
+
'size': 'invisible',
|
|
442
|
+
'captchaType': 'image'
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
// Execute the verification
|
|
446
|
+
window.procaptcha.execute();
|
|
447
|
+
</script>
|
|
448
|
+
</pre>
|
|
449
|
+
|
|
450
|
+
<h3>Console Output</h3>
|
|
451
|
+
<p>When you click the Submit button, the <code>execute()</code> function will:</p>
|
|
452
|
+
<ol>
|
|
453
|
+
<li>Find all Procaptcha containers on the page</li>
|
|
454
|
+
<li>Log each container and its attributes to the console</li>
|
|
455
|
+
<li>Log all child elements of each container</li>
|
|
456
|
+
<li>Dispatch a custom <code>procaptcha:execute</code> event to show the modal</li>
|
|
457
|
+
</ol>
|
|
458
|
+
<p>This helps debug and understand how the invisible Procaptcha is structured in the DOM.</p>
|
|
459
|
+
|
|
460
|
+
<h3>Event-Based Communication System</h3>
|
|
461
|
+
<p>To connect the vanilla JavaScript bundle with the React components, we use a custom event system:</p>
|
|
462
|
+
<ol>
|
|
463
|
+
<li>When <code>window.procaptcha.execute()</code> is called, it dispatches a <code>procaptcha:execute</code> event</li>
|
|
464
|
+
<li>The ProcaptchaWidget React component listens for this event</li>
|
|
465
|
+
<li>When the event is received, the component sets <code>state.showModal = true</code></li>
|
|
466
|
+
<li>This causes the CAPTCHA modal to appear and verification to begin</li>
|
|
467
|
+
</ol>
|
|
468
|
+
<p>This decoupled approach allows the JavaScript bundle to communicate with React components without direct references.</p>
|
|
469
|
+
</div>
|
|
470
|
+
|
|
471
|
+
<!-- Initialize Procaptcha with onload callback -->
|
|
472
|
+
|
|
473
|
+
<script>
|
|
474
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
475
|
+
const toggleBtn = document.getElementById('nav-toggle');
|
|
476
|
+
const navBar = document.getElementById('nav-topbar');
|
|
477
|
+
const navHeader = document.getElementById('nav-header');
|
|
478
|
+
|
|
479
|
+
// Check if navigation was previously collapsed
|
|
480
|
+
const navCollapsed = localStorage.getItem('navCollapsed') === 'true';
|
|
481
|
+
if (navCollapsed) {
|
|
482
|
+
navBar.classList.add('collapsed');
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Function to expand the navigation
|
|
486
|
+
function expandNav() {
|
|
487
|
+
if (navBar.classList.contains('collapsed')) {
|
|
488
|
+
navBar.classList.remove('collapsed');
|
|
489
|
+
localStorage.setItem('navCollapsed', 'false');
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Function to collapse the navigation
|
|
494
|
+
function collapseNav() {
|
|
495
|
+
if (!navBar.classList.contains('collapsed')) {
|
|
496
|
+
navBar.classList.add('collapsed');
|
|
497
|
+
localStorage.setItem('navCollapsed', 'true');
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Function to toggle the navigation
|
|
502
|
+
function toggleNav() {
|
|
503
|
+
navBar.classList.toggle('collapsed');
|
|
504
|
+
localStorage.setItem('navCollapsed', navBar.classList.contains('collapsed'));
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Toggle on button click
|
|
508
|
+
toggleBtn.addEventListener('click', function(e) {
|
|
509
|
+
e.stopPropagation(); // Prevent header click from firing
|
|
510
|
+
toggleNav();
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Expand on toggle button hover when collapsed
|
|
514
|
+
toggleBtn.addEventListener('mouseenter', function() {
|
|
515
|
+
if (navBar.classList.contains('collapsed')) {
|
|
516
|
+
expandNav();
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
// Toggle on header click
|
|
521
|
+
navHeader.addEventListener('click', function(e) {
|
|
522
|
+
// Don't toggle if a link within the header was clicked
|
|
523
|
+
if (e.target.tagName === 'A') {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
toggleNav();
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
// Make the header appear clickable with cursor style
|
|
530
|
+
navHeader.style.cursor = 'pointer';
|
|
531
|
+
});
|
|
532
|
+
</script>
|
|
533
|
+
|
|
534
|
+
</body>
|
|
535
|
+
</html>
|