Commit | Line | Data |
---|---|---|
96714cab MS |
1 | {if $recaptchaLegacyMode|empty} |
2 | {include file='captcha'} | |
3 | {else} | |
ec9e64f0 TD |
4 | {* No explicit keys were set, use legacy V1 API and WoltLab's OEM keys *} |
5 | {if RECAPTCHA_PUBLICKEY === '' || RECAPTCHA_PRIVATEKEY === ''} | |
95961bdf | 6 | <section class="section"> |
d2d216fb MW |
7 | <header class="sectionHeader"> |
8 | <h2 class="sectionTitle">{lang}wcf.recaptcha.title{/lang}</h2> | |
114b5320 | 9 | <p class="sectionDescription">{lang}wcf.recaptcha.description{/lang}</p> |
d2d216fb | 10 | </header> |
376d7839 | 11 | |
96714cab MS |
12 | <dl class="wide reCaptcha{if $errorField|isset && $errorField == 'recaptchaString'} formError{/if}"> |
13 | {if !$ajaxCaptcha|isset || !$ajaxCaptcha} | |
14 | <script data-relocate="true"> | |
96714cab MS |
15 | var RecaptchaOptions = { |
16 | lang: '{@$recaptchaLanguageCode}', | |
17 | theme : 'custom' | |
18 | } | |
96714cab MS |
19 | </script> |
20 | {/if} | |
21 | <dt class="jsOnly"> | |
22 | <label for="recaptcha_response_field">reCAPTCHA</label> | |
23 | </dt> | |
24 | <dd class="jsOnly"> | |
95961bdf | 25 | <div id="recaptcha_image"></div> |
e5f9b56c | 26 | <input type="text" id="recaptcha_response_field" name="recaptcha_response_field" class="medium"> |
96714cab MS |
27 | {if (($errorType|isset && $errorType|is_array && $errorType[recaptchaString]|isset) || ($errorField|isset && $errorField == 'recaptchaString'))} |
28 | {if $errorType|is_array && $errorType[recaptchaString]|isset} | |
29 | {assign var='__errorType' value=$errorType[recaptchaString]} | |
30 | {else} | |
31 | {assign var='__errorType' value=$errorType} | |
32 | {/if} | |
b9f4bd69 | 33 | <small class="innerError"> |
96714cab MS |
34 | {if $__errorType == 'empty'} |
35 | {lang}wcf.global.form.error.empty{/lang} | |
36 | {else} | |
37 | {lang}wcf.recaptcha.error.recaptchaString.{$__errorType}{/lang} | |
38 | {/if} | |
b9f4bd69 MS |
39 | </small> |
40 | {/if} | |
96714cab MS |
41 | </dd> |
42 | ||
43 | {event name='fields'} | |
44 | ||
45 | <dd class="jsOnly"> | |
46 | <ul class="buttonList smallButtons"> | |
ca8bfa53 MS |
47 | <li><a href="javascript:Recaptcha.reload()" class="button small"><span class="icon icon16 fa-repeat"></span> <span>{lang}wcf.recaptcha.reload{/lang}</span></a></li> |
48 | <li class="recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type('audio')" class="button small"><span class="icon icon16 fa-volume-up"></span> <span>{lang}wcf.recaptcha.audio{/lang}</span></a></li> | |
49 | <li class="recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type('image')" class="button small"><span class="icon icon16 fa-eye"></span> <span>{lang}wcf.recaptcha.image{/lang}</span></a></li> | |
50 | <li><a href="javascript:Recaptcha.showhelp()" class="button small"><span class="icon icon16 fa-question"></span> <span>{lang}wcf.recaptcha.help{/lang}</span></a></li> | |
96714cab MS |
51 | {event name='buttons'} |
52 | </ul> | |
53 | </dd> | |
54 | ||
55 | {if !$ajaxCaptcha|isset || !$ajaxCaptcha} | |
2a83aa92 | 56 | <script data-relocate="true" src="//www.google.com/recaptcha/api/challenge?k={$recaptchaPublicKey}"></script> |
96714cab MS |
57 | <noscript> |
58 | <dd> | |
e5f9b56c | 59 | <iframe src="//www.google.com/recaptcha/api/noscript?k={$recaptchaPublicKey}" height="300" width="500" seamless="seamless"></iframe><br> |
96714cab | 60 | <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea> |
e5f9b56c | 61 | <input type="hidden" name="recaptcha_response_field" value="manual_challenge"> |
96714cab MS |
62 | </dd> |
63 | {if (($errorType|isset && $errorType|is_array && $errorType[recaptchaString]|isset) || ($errorField|isset && $errorField == 'recaptchaString'))} | |
64 | {if $errorType|is_array && $errorType[recaptchaString]|isset} | |
65 | {assign var='__errorType' value=$errorType[recaptchaString]} | |
66 | {else} | |
67 | {assign var='__errorType' value=$errorType} | |
68 | {/if} | |
69 | <small class="innerError"> | |
70 | {if $errorType == 'empty'} | |
71 | {lang}wcf.global.form.error.empty{/lang} | |
72 | {else} | |
73 | {lang}wcf.recaptcha.error.recaptchaString.{$__errorType}{/lang} | |
74 | {/if} | |
75 | </small> | |
76 | {/if} | |
77 | </noscript> | |
78 | {else} | |
79 | <script data-relocate="true"> | |
2a83aa92 MS |
80 | $.getScript('//www.google.com/recaptcha/api/js/recaptcha_ajax.js', function() { |
81 | Recaptcha.create("{$recaptchaPublicKey}", "recaptcha_image", { | |
82 | lang: '{@$recaptchaLanguageCode}', | |
83 | theme : 'custom' | |
84 | }); | |
85 | ||
86 | WCF.System.Captcha.addCallback('{$captchaID}', function() { | |
87 | return { | |
88 | recaptcha_challenge_field: Recaptcha.get_challenge(), | |
89 | recaptcha_response_field: Recaptcha.get_response() | |
90 | }; | |
91 | }); | |
96714cab | 92 | }); |
96714cab MS |
93 | </script> |
94 | {/if} | |
95 | </dl> | |
95961bdf | 96 | </section> |
ec9e64f0 | 97 | {else} |
7c4b6e24 | 98 | {if $supportsAsyncCaptcha|isset && $supportsAsyncCaptcha && RECAPTCHA_PUBLICKEY_INVISIBLE && RECAPTCHA_PRIVATEKEY_INVISIBLE} |
6b3d5c38 TD |
99 | <section class="section"> |
100 | <h2 class="sectionTitle">{lang}wcf.recaptcha.title{/lang}</h2> | |
101 | {assign var="recaptchaBucketID" value=true|microtime|sha1} | |
102 | <dl class="{if $errorField|isset && $errorField == 'recaptchaString'}formError{/if}"> | |
103 | <dt></dt> | |
104 | <dd> | |
7cc7a716 | 105 | <input type="hidden" name="recaptcha-type" value="invisible"> |
6b3d5c38 TD |
106 | <div id="recaptchaBucket{$recaptchaBucketID}"></div> |
107 | <noscript> | |
108 | <div style="width: 302px; height: 473px;"> | |
01f0f832 | 109 | <div style="width: 302px; height: 422px; position: relative;"> |
6b3d5c38 | 110 | <div style="width: 302px; height: 422px; position: relative;"> |
7c4b6e24 | 111 | <iframe src="https://www.google.com/recaptcha/api/fallback?k={RECAPTCHA_PUBLICKEY_INVISIBLE|encodeJS}" frameborder="0" scrolling="no" style="width: 302px; height:422px; border-style: none;"></iframe> |
6b3d5c38 TD |
112 | </div> |
113 | <div style="width: 300px; height: 60px; position: relative; border-style: none; bottom: 12px; left: 0; margin: 0px; padding: 0px; right: 25px; background: #f9f9f9; border: 1px solid #c1c1c1; border-radius: 3px;"> | |
114 | <textarea name="g-recaptcha-response" class="g-recaptcha-response" style="width: 290px; height: 50px; border: 1px solid #c1c1c1; margin: 5px; padding: 0px; resize: none;"></textarea> | |
115 | </div> | |
2ca3c9cb TD |
116 | </div> |
117 | </div> | |
6b3d5c38 TD |
118 | </noscript> |
119 | {if (($errorType|isset && $errorType|is_array && $errorType[recaptchaString]|isset) || ($errorField|isset && $errorField == 'recaptchaString'))} | |
120 | {if $errorType|is_array && $errorType[recaptchaString]|isset} | |
121 | {assign var='__errorType' value=$errorType[recaptchaString]} | |
ec9e64f0 | 122 | {else} |
6b3d5c38 | 123 | {assign var='__errorType' value=$errorType} |
ec9e64f0 | 124 | {/if} |
6b3d5c38 TD |
125 | <small class="innerError"> |
126 | {if $__errorType == 'empty'} | |
127 | {lang}wcf.global.form.error.empty{/lang} | |
128 | {else} | |
129 | {lang}wcf.captcha.recaptchaInvisible.error.recaptchaString.{$__errorType}{/lang} | |
130 | {/if} | |
131 | </small> | |
132 | {/if} | |
133 | </dd> | |
134 | </dl> | |
135 | <script data-relocate="true"> | |
136 | if (!WCF.recaptcha) { | |
137 | WCF.recaptcha = { | |
138 | queue: [], | |
139 | callbackCalled: false, | |
140 | mapping: { } | |
141 | }; | |
142 | ||
143 | // this needs to be in global scope | |
144 | function recaptchaCallback() { | |
145 | var bucketId; | |
146 | WCF.recaptcha.callbackCalled = true; | |
147 | ||
148 | // clear queue | |
149 | while (config = WCF.recaptcha.queue.shift()) { | |
150 | (function (config) { | |
151 | var bucketId = config.bucket; | |
152 | ||
153 | require(['Dom/Traverse', 'Dom/Util'], function (DomTraverse, DomUtil) { | |
154 | var bucket = elById(bucketId); | |
155 | ||
156 | var promise = new Promise(function (resolve, reject) { | |
157 | WCF.recaptcha.mapping['recaptchaBucket{$recaptchaBucketID}'] = grecaptcha.render(bucket, { | |
7c4b6e24 | 158 | sitekey: '{RECAPTCHA_PUBLICKEY_INVISIBLE|encodeJS}', |
6b3d5c38 TD |
159 | size: 'invisible', |
160 | badge: 'inline', | |
161 | callback: resolve | |
162 | }); | |
163 | }); | |
164 | ||
165 | if (config.ajaxCaptcha) { | |
166 | WCF.System.Captcha.addCallback(config.ajaxCaptcha, function() { | |
167 | grecaptcha.execute(WCF.recaptcha.mapping['recaptchaBucket{$recaptchaBucketID}']); | |
168 | return promise.then(function (token) { | |
169 | return { | |
7cc7a716 TD |
170 | 'g-recaptcha-response': token, |
171 | 'recaptcha-type': 'invisible' | |
6b3d5c38 TD |
172 | }; |
173 | }); | |
174 | }); | |
175 | } | |
176 | else { | |
177 | var form = DomTraverse.parentByTag(bucket, 'FORM'); | |
178 | ||
179 | var pressed = undefined; | |
180 | elBySelAll('input[type=submit]', form, function (button) { | |
181 | button.addEventListener('click', function (event) { | |
182 | pressed = button; | |
183 | }); | |
184 | }); | |
185 | ||
186 | var listener = function (event) { | |
187 | event.preventDefault(); | |
188 | promise.then(function (token) { | |
189 | form.removeEventListener('submit', listener); | |
190 | pressed.disabled = false; | |
191 | pressed.click(); | |
192 | }); | |
193 | grecaptcha.execute(WCF.recaptcha.mapping['recaptchaBucket{$recaptchaBucketID}']); | |
194 | } | |
195 | form.addEventListener('submit', listener); | |
196 | } | |
197 | ||
198 | }); | |
199 | })(config); | |
200 | } | |
201 | } | |
202 | } | |
203 | ||
204 | // add captcha to queue | |
205 | WCF.recaptcha.queue.push({ | |
206 | bucket: 'recaptchaBucket{$recaptchaBucketID}' | |
207 | {if $ajaxCaptcha|isset && $ajaxCaptcha} | |
208 | , ajaxCaptcha: '{$captchaID}' | |
ec9e64f0 | 209 | {/if} |
6b3d5c38 TD |
210 | }); |
211 | ||
212 | // trigger callback immediately, if API already is available | |
213 | if (WCF.recaptcha.callbackCalled) setTimeout(recaptchaCallback, 1); | |
ec9e64f0 | 214 | |
6b3d5c38 TD |
215 | // ensure recaptcha API is loaded at most once |
216 | if (!window.grecaptcha) $.getScript('https://www.google.com/recaptcha/api.js?render=explicit&onload=recaptchaCallback'); | |
217 | </script> | |
218 | </section> | |
219 | {else} | |
220 | <section class="section"> | |
221 | <h2 class="sectionTitle">{lang}wcf.recaptcha.title{/lang}</h2> | |
222 | {assign var="recaptchaBucketID" value=true|microtime|sha1} | |
223 | <dl class="{if $errorField|isset && $errorField == 'recaptchaString'}formError{/if}"> | |
224 | <dt></dt> | |
225 | <dd> | |
7cc7a716 | 226 | <input type="hidden" name="recaptcha-type" value="v2"> |
6b3d5c38 TD |
227 | <div id="recaptchaBucket{$recaptchaBucketID}"></div> |
228 | <noscript> | |
229 | <div style="width: 302px; height: 473px;"> | |
230 | <div style="width: 302px; height: 422px; position: relative;"> | |
231 | <div style="width: 302px; height: 422px; position: relative;"> | |
232 | <iframe src="https://www.google.com/recaptcha/api/fallback?k={RECAPTCHA_PUBLICKEY|encodeJS}" frameborder="0" scrolling="no" style="width: 302px; height:422px; border-style: none;"></iframe> | |
233 | </div> | |
234 | <div style="width: 300px; height: 60px; position: relative; border-style: none; bottom: 12px; left: 0; margin: 0px; padding: 0px; right: 25px; background: #f9f9f9; border: 1px solid #c1c1c1; border-radius: 3px;"> | |
235 | <textarea name="g-recaptcha-response" class="g-recaptcha-response" style="width: 290px; height: 50px; border: 1px solid #c1c1c1; margin: 5px; padding: 0px; resize: none;"></textarea> | |
236 | </div> | |
237 | </div> | |
238 | </div> | |
239 | </noscript> | |
240 | {if (($errorType|isset && $errorType|is_array && $errorType[recaptchaString]|isset) || ($errorField|isset && $errorField == 'recaptchaString'))} | |
241 | {if $errorType|is_array && $errorType[recaptchaString]|isset} | |
242 | {assign var='__errorType' value=$errorType[recaptchaString]} | |
243 | {else} | |
244 | {assign var='__errorType' value=$errorType} | |
245 | {/if} | |
246 | <small class="innerError"> | |
247 | {if $__errorType == 'empty'} | |
248 | {lang}wcf.global.form.error.empty{/lang} | |
249 | {else} | |
250 | {lang}wcf.captcha.recaptchaV2.error.recaptchaString.{$__errorType}{/lang} | |
251 | {/if} | |
252 | </small> | |
253 | {/if} | |
254 | </dd> | |
255 | </dl> | |
256 | <script data-relocate="true"> | |
257 | if (!WCF.recaptcha) { | |
258 | WCF.recaptcha = { | |
259 | queue: [], | |
260 | callbackCalled: false, | |
261 | mapping: { } | |
262 | }; | |
ec9e64f0 | 263 | |
6b3d5c38 TD |
264 | // this needs to be in global scope |
265 | function recaptchaCallback() { | |
266 | var bucket; | |
267 | WCF.recaptcha.callbackCalled = true; | |
268 | ||
269 | // clear queue | |
270 | while (bucket = WCF.recaptcha.queue.shift()) { | |
271 | WCF.recaptcha.mapping[bucket] = grecaptcha.render(bucket, { | |
272 | 'sitekey' : '{RECAPTCHA_PUBLICKEY|encodeJS}' | |
273 | }); | |
274 | } | |
ec9e64f0 TD |
275 | } |
276 | } | |
6b3d5c38 TD |
277 | |
278 | // add captcha to queue | |
279 | WCF.recaptcha.queue.push('recaptchaBucket{$recaptchaBucketID}'); | |
280 | ||
281 | // trigger callback immediately, if API already is available | |
282 | if (WCF.recaptcha.callbackCalled) setTimeout(recaptchaCallback, 1); | |
283 | ||
284 | {if $ajaxCaptcha|isset && $ajaxCaptcha} | |
285 | WCF.System.Captcha.addCallback('{$captchaID}', function() { | |
286 | return { | |
7cc7a716 TD |
287 | 'g-recaptcha-response': grecaptcha.getResponse(WCF.recaptcha.mapping['recaptchaBucket{$recaptchaBucketID}']), |
288 | 'type': 'v2' | |
6b3d5c38 TD |
289 | }; |
290 | }); | |
291 | {/if} | |
292 | ||
293 | // ensure recaptcha API is loaded at most once | |
294 | if (!window.grecaptcha) $.getScript('https://www.google.com/recaptcha/api.js?render=explicit&onload=recaptchaCallback'); | |
295 | </script> | |
296 | </section> | |
ec9e64f0 | 297 | {/if} |
ec9e64f0 | 298 | {/if} |
96714cab | 299 | {/if} |