@prosopo/client-bundle-example 2.7.0 → 2.8.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/CHANGELOG.md +10 -0
- package/dist/assets/{ProcaptchaWidget-3gKvjeiH.js → ProcaptchaWidget-DrBDhP6X.js} +7 -7
- package/dist/assets/{ProcaptchaWidget-D6-M7iAv.js → ProcaptchaWidget-rAM-9Rap.js} +4 -4
- package/dist/assets/{asU8a-DCECA0Qe.js → asU8a-CJdNkNEq.js} +1 -1
- package/dist/assets/{bip39-BQoZog_M.js → bip39-Du2cANEV.js} +2 -2
- package/dist/assets/captcha-BhkVCEXM.css +1 -0
- package/dist/assets/{captchaComponentProvider-BW2eXmc3.js → captchaComponentProvider-DmV1WTrT.js} +4 -4
- package/dist/assets/{captchaRenderer-B_MgGzr9.js → captchaRenderer-RIsSZXCC.js} +2 -2
- package/dist/assets/{emotion-element-5486c51c.browser.esm-CCAJ8JId.js → emotion-element-5486c51c.browser.esm-C3u8NMUC.js} +127 -125
- package/dist/assets/frictionless-explicit-Dq_sNGRK.js +1 -0
- package/dist/assets/frictionless-implicit-Dq_sNGRK.js +1 -0
- package/dist/assets/{hash-BR0YLxPF.js → hash-_rWungeW.js} +1 -1
- package/dist/assets/image-explicit-DQvfVB7-.js +4 -0
- package/dist/assets/image-implicit-Bwa9QJO5.js +1 -0
- package/dist/assets/{index-WqEmiYQ_.js → index-BVr9fC_3.js} +4 -4
- package/dist/assets/{index-BYUYvvuq.js → index-Cu5oL_7b.js} +4 -4
- package/dist/assets/index-Dpt_5E72.js +1 -0
- package/dist/assets/{index-BCjHZ8o6.js → index-DxIFpl6U.js} +1 -1
- package/dist/assets/{index-2or4-1WF.js → index-Wgw2GQWq.js} +2 -2
- package/dist/assets/invisible-frictionless-explicit-DugBtRe4.js +4 -0
- package/dist/assets/invisible-frictionless-implicit-DYYos8W9.js +1 -0
- package/dist/assets/invisible-image-explicit-C5Z4gSb1.js +4 -0
- package/dist/assets/invisible-image-implicit-DfNFNlFj.js +1 -0
- package/dist/assets/invisible-pow-explicit-DjqGWFUb.js +4 -0
- package/dist/assets/invisible-pow-implicit-BRXL14FH.js +4 -0
- package/dist/assets/pow-explicit-BexxbnHM.js +4 -0
- package/dist/assets/pow-implicit-Dpt_5E72.js +1 -0
- package/dist/assets/procaptcha.bundle.js +1 -1
- package/dist/assets/{useTranslation-BPbGzrhj.js → useTranslation-CJplXtqb.js} +1 -1
- package/dist/frictionless-explicit.html +881 -0
- package/dist/frictionless-implicit.html +874 -0
- package/dist/image-explicit.html +877 -0
- package/dist/index.html +575 -74
- package/dist/invisible-frictionless-explicit.html +626 -283
- package/dist/invisible-frictionless-implicit.html +631 -173
- package/dist/invisible-image-explicit.html +627 -284
- package/dist/invisible-image-implicit.html +631 -173
- package/dist/invisible-pow-explicit.html +627 -284
- package/dist/invisible-pow-implicit.html +629 -177
- package/dist/plugins/explanation-injector.ts +250 -0
- package/dist/plugins/form-filler-injector.ts +233 -0
- package/dist/plugins/navigation-injector.ts +237 -89
- package/dist/plugins/status-log-injector.ts +199 -0
- package/dist/pow-explicit.html +877 -0
- package/dist/pow-implicit.html +881 -0
- package/package.json +1 -1
- package/vite.config.ts +32 -3
- package/dist/assets/frictionless-ZgzyuneX.js +0 -1
- package/dist/assets/index-BWsu-rGU.js +0 -1
- package/dist/assets/invisible-frictionless-explicit-DgCaJtPg.js +0 -1
- package/dist/assets/invisible-image-explicit-DgCaJtPg.js +0 -1
- package/dist/assets/invisible-pow-explicit-DgCaJtPg.js +0 -1
- package/dist/assets/pow-BW3QYcgP.js +0 -1
- package/dist/frictionless.html +0 -343
- package/dist/pow.html +0 -323
- /package/dist/assets/{modulepreload-polyfill-B5Qt9EMX.js → captcha-ByKnSsbG.js} +0 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// Copyright 2021-2025 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
// Vite plugin to inject explanations into HTML files
|
|
15
|
+
import type { IndexHtmlTransformContext, Plugin } from "vite";
|
|
16
|
+
|
|
17
|
+
// Utility function to escape HTML special characters
|
|
18
|
+
function escapeHtml(text: string): string {
|
|
19
|
+
return text
|
|
20
|
+
.replace(/&/g, "&")
|
|
21
|
+
.replace(/</g, "<")
|
|
22
|
+
.replace(/>/g, ">")
|
|
23
|
+
.replace(/"/g, """)
|
|
24
|
+
.replace(/'/g, "'");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default function explanationInjector(): Plugin {
|
|
28
|
+
return {
|
|
29
|
+
name: "explanation-injector",
|
|
30
|
+
transformIndexHtml: {
|
|
31
|
+
enforce: "post", // Run after other HTML transforms
|
|
32
|
+
transform(html: string, ctx: IndexHtmlTransformContext): string {
|
|
33
|
+
// Skip if no HTML body is found
|
|
34
|
+
if (!html.includes("<body") || !html.includes("</body>")) {
|
|
35
|
+
return html;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Extract the current page name from the context
|
|
39
|
+
const url = ctx.filename || "";
|
|
40
|
+
const pageName = url.split("/").pop()?.split(".")[0] || "";
|
|
41
|
+
|
|
42
|
+
// Determine CAPTCHA type from filename
|
|
43
|
+
const isFrictionless = pageName.includes("frictionless");
|
|
44
|
+
const isImage = pageName.includes("image");
|
|
45
|
+
const isPow = pageName.includes("pow");
|
|
46
|
+
const isInvisible = pageName.includes("invisible");
|
|
47
|
+
const isExplicit = pageName.includes("explicit");
|
|
48
|
+
|
|
49
|
+
// Generate the appropriate explanation based on CAPTCHA type
|
|
50
|
+
let explanationHtml = "";
|
|
51
|
+
|
|
52
|
+
if (isFrictionless) {
|
|
53
|
+
explanationHtml = generateFrictionlessExplanation(
|
|
54
|
+
isExplicit,
|
|
55
|
+
isInvisible,
|
|
56
|
+
);
|
|
57
|
+
} else if (isImage) {
|
|
58
|
+
explanationHtml = generateImageExplanation(isExplicit, isInvisible);
|
|
59
|
+
} else if (isPow) {
|
|
60
|
+
explanationHtml = generatePowExplanation(isExplicit, isInvisible);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// No explanation needed or couldn't determine type
|
|
64
|
+
if (!explanationHtml) {
|
|
65
|
+
return html;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Look for an existing explanation div to replace
|
|
69
|
+
if (html.includes('<div class="explanation">')) {
|
|
70
|
+
// Replace the existing explanation
|
|
71
|
+
const explRegex =
|
|
72
|
+
/<div class="explanation">[\s\S]*?<\/div>\s*<\/div>/;
|
|
73
|
+
return html.replace(explRegex, explanationHtml);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Otherwise insert before the closing body tag
|
|
77
|
+
return html.replace("</body>", `${explanationHtml}</body>`);
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Helper functions to generate explanations for different CAPTCHA types
|
|
84
|
+
function generateFrictionlessExplanation(
|
|
85
|
+
isExplicit: boolean,
|
|
86
|
+
isInvisible: boolean,
|
|
87
|
+
): string {
|
|
88
|
+
const renderType = isExplicit ? "Explicit" : "Implicit";
|
|
89
|
+
const modeDesc = isInvisible ? "invisible" : "normal";
|
|
90
|
+
|
|
91
|
+
// Create code example with proper HTML escaping
|
|
92
|
+
const codeExample = isExplicit
|
|
93
|
+
? escapeHtml(`// Import the render function
|
|
94
|
+
import { render } from "%VITE_BUNDLE_URL%"
|
|
95
|
+
import { CaptchaType } from "@prosopo/types";
|
|
96
|
+
|
|
97
|
+
// Render CAPTCHA
|
|
98
|
+
const widgetId = render(document.getElementById('procaptcha-container'), {
|
|
99
|
+
siteKey: import.meta.env.PROSOPO_SITE_KEY_FRICTIONLESS,
|
|
100
|
+
captchaType: CaptchaType.frictionless,
|
|
101
|
+
callback: handleCaptchaResponse,
|
|
102
|
+
"failed-callback": handleCaptchaFailed${isInvisible ? ',\n size: "invisible"' : ""}
|
|
103
|
+
});`)
|
|
104
|
+
: escapeHtml(`<div
|
|
105
|
+
class="procaptcha"
|
|
106
|
+
data-theme="light"
|
|
107
|
+
data-sitekey="%PROSOPO_SITE_KEY_FRICTIONLESS%"
|
|
108
|
+
data-failed-callback="onCaptchaFailed"
|
|
109
|
+
data-callback="onCaptchaVerified"
|
|
110
|
+
data-captcha-type="frictionless"${isInvisible ? '\n data-size="invisible"' : ""}
|
|
111
|
+
></div>`);
|
|
112
|
+
|
|
113
|
+
return `
|
|
114
|
+
<div class="explanation">
|
|
115
|
+
<h2>How ${isInvisible ? "Invisible " : ""}Frictionless CAPTCHA Works (${renderType} Rendering)</h2>
|
|
116
|
+
|
|
117
|
+
<h3>Implementation Details</h3>
|
|
118
|
+
<p>This example demonstrates how to use Procaptcha in frictionless mode with ${renderType.toLowerCase()} rendering:</p>
|
|
119
|
+
<ol>
|
|
120
|
+
<li>Import the Procaptcha ${isExplicit ? "render function" : "script"}</li>
|
|
121
|
+
<li>${escapeHtml(isExplicit ? "Create a container for the CAPTCHA" : "Add a div with the procaptcha class")}</li>
|
|
122
|
+
<li>${escapeHtml(isExplicit ? "Render the CAPTCHA explicitly" : "Set data-* attributes to configure the CAPTCHA")}</li>
|
|
123
|
+
<li>Handle the verification result in the callback function</li>
|
|
124
|
+
</ol>
|
|
125
|
+
|
|
126
|
+
<h3>Key Code Example</h3>
|
|
127
|
+
<pre>${codeExample}</pre>
|
|
128
|
+
|
|
129
|
+
<h3>Execution Flow</h3>
|
|
130
|
+
<ol>
|
|
131
|
+
<li>On page load, ${escapeHtml(isExplicit ? "the render function is called to initialize" : "Procaptcha scans for elements with the procaptcha class")}</li>
|
|
132
|
+
<li>The CAPTCHA verification happens ${isInvisible ? "invisibly in the background" : "when the user interacts with it"}</li>
|
|
133
|
+
<li>When verification is complete, the callback function is called with the token</li>
|
|
134
|
+
<li>On successful verification, the form can be submitted with the token</li>
|
|
135
|
+
</ol>
|
|
136
|
+
</div>
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function generateImageExplanation(
|
|
141
|
+
isExplicit: boolean,
|
|
142
|
+
isInvisible: boolean,
|
|
143
|
+
): string {
|
|
144
|
+
const renderType = isExplicit ? "Explicit" : "Implicit";
|
|
145
|
+
const modeDesc = isInvisible ? "invisible" : "visible";
|
|
146
|
+
|
|
147
|
+
// Create code example with proper HTML escaping
|
|
148
|
+
const codeExample = isExplicit
|
|
149
|
+
? escapeHtml(`// Import the render function
|
|
150
|
+
import { render } from "%VITE_BUNDLE_URL%"
|
|
151
|
+
import { CaptchaType } from "@prosopo/types";
|
|
152
|
+
|
|
153
|
+
// Render CAPTCHA
|
|
154
|
+
const widgetId = render(document.getElementById('procaptcha-container'), {
|
|
155
|
+
siteKey: import.meta.env.PROSOPO_SITE_KEY_IMAGE,
|
|
156
|
+
captchaType: CaptchaType.image,
|
|
157
|
+
callback: handleCaptchaResponse,
|
|
158
|
+
"failed-callback": handleCaptchaFailed${isInvisible ? ',\n size: "invisible"' : ""}
|
|
159
|
+
});`)
|
|
160
|
+
: escapeHtml(`<div
|
|
161
|
+
class="procaptcha"
|
|
162
|
+
data-theme="light"
|
|
163
|
+
data-sitekey="%PROSOPO_SITE_KEY_IMAGE%"
|
|
164
|
+
data-failed-callback="onCaptchaFailed"
|
|
165
|
+
data-callback="onCaptchaVerified"
|
|
166
|
+
data-captcha-type="image"${isInvisible ? '\n data-size="invisible"' : ""}
|
|
167
|
+
></div>`);
|
|
168
|
+
|
|
169
|
+
return `
|
|
170
|
+
<div class="explanation">
|
|
171
|
+
<h2>How ${isInvisible ? "Invisible " : ""}Image CAPTCHA Works (${renderType} Rendering)</h2>
|
|
172
|
+
|
|
173
|
+
<h3>Implementation Details</h3>
|
|
174
|
+
<p>This example demonstrates how to use Procaptcha in image mode with ${renderType.toLowerCase()} rendering:</p>
|
|
175
|
+
<ol>
|
|
176
|
+
<li>Import the Procaptcha ${isExplicit ? "render function" : "script"}</li>
|
|
177
|
+
<li>${escapeHtml(isExplicit ? "Create a container for the CAPTCHA" : "Add a div with the procaptcha class")}</li>
|
|
178
|
+
<li>${escapeHtml(isExplicit ? "Render the CAPTCHA explicitly" : "Set data-* attributes to configure the CAPTCHA")}</li>
|
|
179
|
+
<li>Handle the verification result in the callback function</li>
|
|
180
|
+
</ol>
|
|
181
|
+
|
|
182
|
+
<h3>Key Code Example</h3>
|
|
183
|
+
<pre>${codeExample}</pre>
|
|
184
|
+
|
|
185
|
+
<h3>Execution Flow</h3>
|
|
186
|
+
<ol>
|
|
187
|
+
<li>On page load, ${escapeHtml(isExplicit ? "the render function is called to initialize" : "Procaptcha scans for elements with the procaptcha class")}</li>
|
|
188
|
+
<li>The CAPTCHA challenge is rendered ${isInvisible ? "only when needed" : "in the specified container"}</li>
|
|
189
|
+
<li>When the user completes the challenge, the callback function is called</li>
|
|
190
|
+
<li>On successful verification, the form can be submitted with the token</li>
|
|
191
|
+
</ol>
|
|
192
|
+
</div>
|
|
193
|
+
`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function generatePowExplanation(
|
|
197
|
+
isExplicit: boolean,
|
|
198
|
+
isInvisible: boolean,
|
|
199
|
+
): string {
|
|
200
|
+
const renderType = isExplicit ? "Explicit" : "Implicit";
|
|
201
|
+
const modeDesc = isInvisible ? "invisible" : "visible";
|
|
202
|
+
|
|
203
|
+
// Create code example with proper HTML escaping
|
|
204
|
+
const codeExample = isExplicit
|
|
205
|
+
? escapeHtml(`// Import the render function
|
|
206
|
+
import { render } from "%VITE_BUNDLE_URL%"
|
|
207
|
+
import { CaptchaType } from "@prosopo/types";
|
|
208
|
+
|
|
209
|
+
// Render CAPTCHA
|
|
210
|
+
const widgetId = render(document.getElementById('procaptcha-container'), {
|
|
211
|
+
siteKey: import.meta.env.PROSOPO_SITE_KEY_POW,
|
|
212
|
+
captchaType: CaptchaType.pow,
|
|
213
|
+
callback: handleCaptchaResponse,
|
|
214
|
+
"failed-callback": handleCaptchaFailed${isInvisible ? ',\n size: "invisible"' : ""}
|
|
215
|
+
});`)
|
|
216
|
+
: escapeHtml(`<div
|
|
217
|
+
class="procaptcha"
|
|
218
|
+
data-theme="light"
|
|
219
|
+
data-sitekey="%PROSOPO_SITE_KEY_POW%"
|
|
220
|
+
data-failed-callback="onCaptchaFailed"
|
|
221
|
+
data-callback="onCaptchaVerified"
|
|
222
|
+
data-captcha-type="pow"${isInvisible ? '\n data-size="invisible"' : ""}
|
|
223
|
+
></div>`);
|
|
224
|
+
|
|
225
|
+
return `
|
|
226
|
+
<div class="explanation">
|
|
227
|
+
<h2>How ${isInvisible ? "Invisible " : ""}Proof of Work CAPTCHA Works (${renderType} Rendering)</h2>
|
|
228
|
+
|
|
229
|
+
<h3>Implementation Details</h3>
|
|
230
|
+
<p>This example demonstrates how to use Procaptcha in Proof of Work mode with ${renderType.toLowerCase()} rendering:</p>
|
|
231
|
+
<ol>
|
|
232
|
+
<li>Import the Procaptcha ${isExplicit ? "render function" : "script"}</li>
|
|
233
|
+
<li>${escapeHtml(isExplicit ? "Create a container for the CAPTCHA" : "Add a div with the procaptcha class")}</li>
|
|
234
|
+
<li>${escapeHtml(isExplicit ? "Render the CAPTCHA explicitly" : "Set data-* attributes to configure the CAPTCHA")}</li>
|
|
235
|
+
<li>Handle the verification result in the callback function</li>
|
|
236
|
+
</ol>
|
|
237
|
+
|
|
238
|
+
<h3>Key Code Example</h3>
|
|
239
|
+
<pre>${codeExample}</pre>
|
|
240
|
+
|
|
241
|
+
<h3>Execution Flow</h3>
|
|
242
|
+
<ol>
|
|
243
|
+
<li>On page load, ${escapeHtml(isExplicit ? "the render function is called to initialize" : "Procaptcha scans for elements with the procaptcha class")}</li>
|
|
244
|
+
<li>The Proof of Work computation happens in the browser</li>
|
|
245
|
+
<li>When the computation is complete, the callback function is called</li>
|
|
246
|
+
<li>On successful verification, the form can be submitted with the token</li>
|
|
247
|
+
</ol>
|
|
248
|
+
</div>
|
|
249
|
+
`;
|
|
250
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// Copyright 2021-2025 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
// Vite plugin to inject a form filler button into HTML files
|
|
15
|
+
import type { IndexHtmlTransformContext, Plugin } from "vite";
|
|
16
|
+
|
|
17
|
+
export default function formFillerInjector(): Plugin {
|
|
18
|
+
// Style for the form filler button
|
|
19
|
+
const buttonStyle = `
|
|
20
|
+
<style>
|
|
21
|
+
.form-filler-button {
|
|
22
|
+
position: fixed;
|
|
23
|
+
bottom: 20px;
|
|
24
|
+
right: 20px;
|
|
25
|
+
background-color: #2196F3;
|
|
26
|
+
color: white;
|
|
27
|
+
border: none;
|
|
28
|
+
border-radius: 30px;
|
|
29
|
+
padding: 12px 20px;
|
|
30
|
+
font-size: 14px;
|
|
31
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
|
32
|
+
cursor: pointer;
|
|
33
|
+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
|
|
34
|
+
z-index: 9999;
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
gap: 8px;
|
|
38
|
+
transition: all 0.2s ease;
|
|
39
|
+
outline: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.form-filler-button:hover {
|
|
43
|
+
background-color: #1976D2;
|
|
44
|
+
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.25);
|
|
45
|
+
transform: translateY(-2px);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.form-filler-button:active {
|
|
49
|
+
transform: translateY(1px);
|
|
50
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.form-filler-button svg {
|
|
54
|
+
width: 18px;
|
|
55
|
+
height: 18px;
|
|
56
|
+
fill: white;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.form-filler-button span {
|
|
60
|
+
font-weight: 500;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@media (max-width: 768px) {
|
|
64
|
+
.form-filler-button {
|
|
65
|
+
bottom: 15px;
|
|
66
|
+
right: 15px;
|
|
67
|
+
padding: 10px 15px;
|
|
68
|
+
font-size: 12px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.form-filler-button svg {
|
|
72
|
+
width: 14px;
|
|
73
|
+
height: 14px;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
// HTML for the form filler button
|
|
80
|
+
const buttonHtml = `
|
|
81
|
+
<button id="form-filler-button" class="form-filler-button" title="Fill all form fields with default values">
|
|
82
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
83
|
+
<path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/>
|
|
84
|
+
</svg>
|
|
85
|
+
<span>Fill Form</span>
|
|
86
|
+
</button>
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
// JavaScript for form filling functionality
|
|
90
|
+
const fillerScript = `
|
|
91
|
+
<script>
|
|
92
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
93
|
+
// Create a function to fill the form with sensible default values
|
|
94
|
+
function fillFormWithDefaults() {
|
|
95
|
+
// Get all input elements
|
|
96
|
+
const inputs = document.querySelectorAll('input, select, textarea');
|
|
97
|
+
|
|
98
|
+
// Record which elements were filled for status feedback
|
|
99
|
+
const filledElements = [];
|
|
100
|
+
|
|
101
|
+
// Process each input
|
|
102
|
+
inputs.forEach(input => {
|
|
103
|
+
let filled = true;
|
|
104
|
+
|
|
105
|
+
// Skip hidden inputs and those with existing values
|
|
106
|
+
if (input.type === 'hidden' || (input.value && input.value.trim() !== '')) {
|
|
107
|
+
filled = false;
|
|
108
|
+
}
|
|
109
|
+
// Handle different input types
|
|
110
|
+
else if (input.type === 'text') {
|
|
111
|
+
if (input.id.toLowerCase().includes('name') || input.name.toLowerCase().includes('name')) {
|
|
112
|
+
input.value = 'John Doe';
|
|
113
|
+
} else {
|
|
114
|
+
input.value = 'Default Text';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (input.type === 'email') {
|
|
118
|
+
input.value = 'test@example.com';
|
|
119
|
+
}
|
|
120
|
+
else if (input.type === 'password') {
|
|
121
|
+
input.value = 'Password123!';
|
|
122
|
+
}
|
|
123
|
+
else if (input.type === 'tel') {
|
|
124
|
+
input.value = '+1234567890';
|
|
125
|
+
}
|
|
126
|
+
else if (input.type === 'number') {
|
|
127
|
+
input.value = '42';
|
|
128
|
+
}
|
|
129
|
+
else if (input.type === 'url') {
|
|
130
|
+
input.value = 'https://example.com';
|
|
131
|
+
}
|
|
132
|
+
else if (input.type === 'date') {
|
|
133
|
+
const today = new Date();
|
|
134
|
+
const yyyy = today.getFullYear();
|
|
135
|
+
const mm = String(today.getMonth() + 1).padStart(2, '0');
|
|
136
|
+
const dd = String(today.getDate()).padStart(2, '0');
|
|
137
|
+
input.value = \`\${yyyy}-\${mm}-\${dd}\`;
|
|
138
|
+
}
|
|
139
|
+
else if (input.type === 'time') {
|
|
140
|
+
input.value = '12:00';
|
|
141
|
+
}
|
|
142
|
+
else if (input.type === 'checkbox' || input.type === 'radio') {
|
|
143
|
+
input.checked = true;
|
|
144
|
+
}
|
|
145
|
+
else if (input.tagName === 'SELECT') {
|
|
146
|
+
if (input.options.length > 0) {
|
|
147
|
+
input.selectedIndex = 1 >= input.options.length ? 0 : 1; // Select second option if available, first otherwise
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if (input.tagName === 'TEXTAREA') {
|
|
151
|
+
input.value = 'This is a sample text for the textarea field.';
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// For any other input types
|
|
155
|
+
input.value = 'Default Value';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Add to filled elements if we actually filled it
|
|
159
|
+
if (filled) {
|
|
160
|
+
filledElements.push(input);
|
|
161
|
+
|
|
162
|
+
// Dispatch input event to trigger any listeners
|
|
163
|
+
const event = new Event('input', { bubbles: true });
|
|
164
|
+
input.dispatchEvent(event);
|
|
165
|
+
|
|
166
|
+
// For select elements, also dispatch change event
|
|
167
|
+
if (input.tagName === 'SELECT') {
|
|
168
|
+
const changeEvent = new Event('change', { bubbles: true });
|
|
169
|
+
input.dispatchEvent(changeEvent);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Show a notification about what was filled
|
|
175
|
+
if (filledElements.length > 0) {
|
|
176
|
+
// If an updateCaptchaStatus function exists (from our other demos), use it
|
|
177
|
+
if (typeof window.updateCaptchaStatus === 'function') {
|
|
178
|
+
window.updateCaptchaStatus(\`Filled \${filledElements.length} form fields with default values\`, 'info');
|
|
179
|
+
} else {
|
|
180
|
+
console.log(\`Filled \${filledElements.length} form fields with default values\`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Highlight the filled fields briefly
|
|
184
|
+
filledElements.forEach(el => {
|
|
185
|
+
const originalBackground = el.style.backgroundColor;
|
|
186
|
+
const originalTransition = el.style.transition;
|
|
187
|
+
|
|
188
|
+
el.style.transition = 'background-color 1.5s ease';
|
|
189
|
+
el.style.backgroundColor = '#e3f2fd';
|
|
190
|
+
|
|
191
|
+
setTimeout(() => {
|
|
192
|
+
el.style.backgroundColor = originalBackground;
|
|
193
|
+
setTimeout(() => {
|
|
194
|
+
el.style.transition = originalTransition;
|
|
195
|
+
}, 1500);
|
|
196
|
+
}, 500);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Add the click event listener to the form filler button
|
|
202
|
+
const formFillerButton = document.getElementById('form-filler-button');
|
|
203
|
+
if (formFillerButton) {
|
|
204
|
+
formFillerButton.addEventListener('click', fillFormWithDefaults);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
</script>
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
name: "form-filler-injector",
|
|
212
|
+
transformIndexHtml: {
|
|
213
|
+
enforce: "post", // Run after other HTML transforms
|
|
214
|
+
transform(html: string, ctx: IndexHtmlTransformContext): string {
|
|
215
|
+
// Skip if no HTML body is found
|
|
216
|
+
if (!html.includes("<body") || !html.includes("</body>")) {
|
|
217
|
+
return html;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Inject style into the head
|
|
221
|
+
let updatedHtml = html.replace("</head>", `${buttonStyle}</head>`);
|
|
222
|
+
|
|
223
|
+
// Inject button and script before closing body tag
|
|
224
|
+
updatedHtml = updatedHtml.replace(
|
|
225
|
+
"</body>",
|
|
226
|
+
`${buttonHtml}${fillerScript}</body>`,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
return updatedHtml;
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|