1 {if $recaptchaLegacyMode|empty}
2 {include file='captcha'}
4 {* No explicit keys were set, use legacy V1 API and WoltLab's OEM keys *}
5 {if RECAPTCHA_PUBLICKEY === '' || RECAPTCHA_PRIVATEKEY === ''}
6 <section class="section">
7 <header class="sectionHeader">
8 <h2 class="sectionTitle">{lang}wcf.recaptcha.title{/lang}</h2>
9 <p class="sectionDescription">{lang}wcf.recaptcha.description{/lang}</p>
12 <dl class="wide reCaptcha{if $errorField|isset && $errorField == 'recaptchaString'} formError{/if}">
13 {if !$ajaxCaptcha|isset || !$ajaxCaptcha}
14 <script data-relocate="true">
15 var RecaptchaOptions = {
16 lang: '{@$recaptchaLanguageCode}',
22 <label for="recaptcha_response_field">reCAPTCHA</label>
25 <div id="recaptcha_image"></div>
26 <input type="text" id="recaptcha_response_field" name="recaptcha_response_field" class="medium">
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]}
31 {assign var='__errorType' value=$errorType}
33 <small class="innerError">
34 {if $__errorType == 'empty'}
35 {lang}wcf.global.form.error.empty{/lang}
37 {lang}wcf.recaptcha.error.recaptchaString.{$__errorType}{/lang}
46 <ul class="buttonList smallButtons">
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>
51 {event name='buttons'}
55 {if !$ajaxCaptcha|isset || !$ajaxCaptcha}
56 <script data-relocate="true" src="//www.google.com/recaptcha/api/challenge?k={$recaptchaPublicKey}"></script>
59 <iframe src="//www.google.com/recaptcha/api/noscript?k={$recaptchaPublicKey}" height="300" width="500" seamless="seamless"></iframe><br>
60 <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
61 <input type="hidden" name="recaptcha_response_field" value="manual_challenge">
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]}
67 {assign var='__errorType' value=$errorType}
69 <small class="innerError">
70 {if $errorType == 'empty'}
71 {lang}wcf.global.form.error.empty{/lang}
73 {lang}wcf.recaptcha.error.recaptchaString.{$__errorType}{/lang}
79 <script data-relocate="true">
80 $.getScript('//www.google.com/recaptcha/api/js/recaptcha_ajax.js', function() {
81 Recaptcha.create("{$recaptchaPublicKey}", "recaptcha_image", {
82 lang: '{@$recaptchaLanguageCode}',
86 WCF.System.Captcha.addCallback('{$captchaID}', function() {
88 recaptcha_challenge_field: Recaptcha.get_challenge(),
89 recaptcha_response_field: Recaptcha.get_response()
98 {if $supportsAsyncCaptcha|isset && $supportsAsyncCaptcha && RECAPTCHA_PUBLICKEY_INVISIBLE && RECAPTCHA_PRIVATEKEY_INVISIBLE}
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}">
105 <input type="hidden" name="recaptcha-type" value="invisible">
106 <div id="recaptchaBucket{$recaptchaBucketID}"></div>
108 <div style="width: 302px; height: 473px;">
109 <div style="width: 302px; height: 422px; position: relative;">
110 <div style="width: 302px; height: 422px; position: relative;">
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>
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>
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]}
123 {assign var='__errorType' value=$errorType}
125 <small class="innerError">
126 {if $__errorType == 'empty'}
127 {lang}wcf.global.form.error.empty{/lang}
129 {lang}wcf.captcha.recaptchaInvisible.error.recaptchaString.{$__errorType}{/lang}
135 <script data-relocate="true">
136 if (!WCF.recaptcha) {
139 callbackCalled: false,
143 // this needs to be in global scope
144 function recaptchaCallback() {
146 WCF.recaptcha.callbackCalled = true;
149 while (config = WCF.recaptcha.queue.shift()) {
151 var bucketId = config.bucket;
153 require(['Dom/Traverse', 'Dom/Util'], function (DomTraverse, DomUtil) {
154 var bucket = elById(bucketId);
156 var promise = new Promise(function (resolve, reject) {
157 WCF.recaptcha.mapping['recaptchaBucket{$recaptchaBucketID}'] = grecaptcha.render(bucket, {
158 sitekey: '{RECAPTCHA_PUBLICKEY_INVISIBLE|encodeJS}',
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) {
170 'g-recaptcha-response': token,
171 'recaptcha-type': 'invisible'
177 var form = DomTraverse.parentByTag(bucket, 'FORM');
179 var pressed = undefined;
180 elBySelAll('input[type=submit]', form, function (button) {
181 button.addEventListener('click', function (event) {
186 var listener = function (event) {
187 event.preventDefault();
188 promise.then(function (token) {
189 form.removeEventListener('submit', listener);
190 pressed.disabled = false;
193 grecaptcha.execute(WCF.recaptcha.mapping['recaptchaBucket{$recaptchaBucketID}']);
195 form.addEventListener('submit', listener);
204 // add captcha to queue
205 WCF.recaptcha.queue.push({
206 bucket: 'recaptchaBucket{$recaptchaBucketID}'
207 {if $ajaxCaptcha|isset && $ajaxCaptcha}
208 , ajaxCaptcha: '{$captchaID}'
212 // trigger callback immediately, if API already is available
213 if (WCF.recaptcha.callbackCalled) setTimeout(recaptchaCallback, 1);
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');
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}">
226 <input type="hidden" name="recaptcha-type" value="v2">
227 <div id="recaptchaBucket{$recaptchaBucketID}"></div>
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>
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>
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]}
244 {assign var='__errorType' value=$errorType}
246 <small class="innerError">
247 {if $__errorType == 'empty'}
248 {lang}wcf.global.form.error.empty{/lang}
250 {lang}wcf.captcha.recaptchaV2.error.recaptchaString.{$__errorType}{/lang}
256 <script data-relocate="true">
257 if (!WCF.recaptcha) {
260 callbackCalled: false,
264 // this needs to be in global scope
265 function recaptchaCallback() {
267 WCF.recaptcha.callbackCalled = true;
270 while (bucket = WCF.recaptcha.queue.shift()) {
271 WCF.recaptcha.mapping[bucket] = grecaptcha.render(bucket, {
272 'sitekey' : '{RECAPTCHA_PUBLICKEY|encodeJS}'
278 // add captcha to queue
279 WCF.recaptcha.queue.push('recaptchaBucket{$recaptchaBucketID}');
281 // trigger callback immediately, if API already is available
282 if (WCF.recaptcha.callbackCalled) setTimeout(recaptchaCallback, 1);
284 {if $ajaxCaptcha|isset && $ajaxCaptcha}
285 WCF.System.Captcha.addCallback('{$captchaID}', function() {
287 'g-recaptcha-response': grecaptcha.getResponse(WCF.recaptcha.mapping['recaptchaBucket{$recaptchaBucketID}']),
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');