Merge branch '3.0'
[GitHub/WoltLab/WCF.git] / com.woltlab.wcf / templates / recaptcha.tpl
CommitLineData
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}