PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.3
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.3
3.4.3 3.4.2 3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.3.1 All 196 releases
convertkit / resources / frontend / js / restrict-content.js

restrict-content.js in Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages 3.4.3, at resources/frontend/js/restrict-content.js

372 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Frontend functionality for Restrict Content functionality.
3 *
4 * @since 2.3.7
5 *
6 * @author ConvertKit
7 */
8
9 /**
10 * Register events
11 */
12 document.addEventListener('DOMContentLoaded', function () {
13 // Open modal.
14 document
15 .querySelectorAll('.convertkit-restrict-content-modal-open')
16 .forEach(function (element) {
17 element.addEventListener('click', function (e) {
18 e.preventDefault();
19 convertKitRestrictContentOpenModal();
20 });
21 });
22
23 // Handle modal form submissions.
24 document.addEventListener('submit', function (e) {
25 // Bail if the submission was not for the Restrict Content form.
26 if (!e.target.matches('form#convertkit-restrict-content-form')) {
27 return;
28 }
29
30 e.preventDefault();
31 convertKitRestrictContentFormSubmit(e);
32 });
33
34 // Close modal.
35 // Check if the element exists on screen; if another JS error occurs, OTP submission might not be async,
36 // resulting in the non-JS OTP code screen loading without a modal (i.e. ?convertkit_login=1).
37 const convertKitRestrictContentCloseElement = document.querySelector(
38 '#convertkit-restrict-content-modal-close'
39 );
40 if (convertKitRestrictContentCloseElement !== null) {
41 convertKitRestrictContentCloseElement.addEventListener(
42 'click',
43 function (e) {
44 e.preventDefault();
45 convertKitRestrictContentCloseModal();
46 }
47 );
48 }
49 });
50
51 /**
52 * Handles Restrict Content form submission.
53 *
54 * @since 2.4.2
55 *
56 * @param {Event} e Form submission event.
57 */
58 function convertKitRestrictContentFormSubmit(e) {
59 // Determine where the response should be displayed; either the embedded login
60 // form, or the modal.
61 const container = convertKitRestrictContentContainer(e.target);
62
63 // Disable inputs.
64 container
65 .querySelectorAll(
66 'input[type="text"], input[type="email"], input[type="submit"]'
67 )
68 .forEach(function (input) {
69 input.setAttribute('disabled', 'disabled');
70 });
71
72 // Show loading overlay.
73 convertKitRestrictContentLoading(true);
74
75 // Determine if this is the email or code submission.
76 const isCodeSubmission =
77 container.querySelector('input#convertkit-subscriber-code') !== null;
78
79 if (isCodeSubmission) {
80 // Code submission.
81 convertKitRestrictContentSubscriberVerification(
82 convertkit_restrict_content.nonce,
83 e.target.querySelector('input[name="subscriber_code"]').value,
84 e.target.querySelector('input[name="token"]').value,
85 e.target.querySelector('input[name="convertkit_post_id"]').value,
86 container
87 );
88
89 return false;
90 }
91
92 // Email submission.
93 convertKitRestrictContentSubscriberAuthenticationSendCode(
94 convertkit_restrict_content.nonce,
95 e.target.querySelector('input[name="convertkit_email"]').value,
96 e.target.querySelector('input[name="convertkit_resource_type"]').value,
97 e.target.querySelector('input[name="convertkit_resource_id"]').value,
98 e.target.querySelector('input[name="convertkit_post_id"]').value,
99 convertKitRestrictContentSpamProtectionResponse(e.target),
100 container
101 );
102 }
103
104 /**
105 * Returns whether the heading should be displayed above the login form, which is
106 * the case when the modal is used.
107 *
108 * @since 3.4.2
109 *
110 * @param {Object} container Container element.
111 * @return {boolean} Display the heading.
112 */
113 function convertKitRestrictContentDisplayHeading(container) {
114 return container.id === 'convertkit-restrict-content-modal-content';
115 }
116
117 /**
118 * Returns the element to display the response in for the given form, which is
119 * either the embedded login form's container, or the modal's content.
120 *
121 * @since 3.4.2
122 *
123 * @param {Object} form Form element.
124 * @return {Object} Container element.
125 */
126 function convertKitRestrictContentContainer(form) {
127 return (
128 form.closest('.convertkit-restrict-content-content') ||
129 document.querySelector('#convertkit-restrict-content-modal-content')
130 );
131 }
132
133 /**
134 * Shows or hides the modal's loading overlay, if the modal is used.
135 *
136 * @since 3.4.2
137 *
138 * @param {boolean} display Display the loading overlay.
139 */
140 function convertKitRestrictContentLoading(display) {
141 const loading = document.querySelector(
142 '#convertkit-restrict-content-modal-loading'
143 );
144
145 if (loading === null) {
146 return;
147 }
148
149 loading.style.display = display ? 'block' : 'none';
150 }
151
152 /**
153 * Returns the spam protection response for the given form, if a spam protection
154 * provider is enabled.
155 *
156 * @since 3.4.2
157 *
158 * @param {Object} form Form element.
159 * @return {string} Spam protection response.
160 */
161 function convertKitRestrictContentSpamProtectionResponse(form) {
162 const field = form.querySelector(
163 '[name="g-recaptcha-response"], [name="cf-turnstile-response"]'
164 );
165
166 return field === null ? '' : field.value;
167 }
168
169 /**
170 * Opens the modal, displaying the content stored within the
171 * #convertkit-restrict-content-modal-content element.
172 *
173 * @since 2.3.8
174 */
175 function convertKitRestrictContentOpenModal() {
176 document.querySelector(
177 '#convertkit-restrict-content-modal-background'
178 ).style.display = 'block';
179 document.querySelector('#convertkit-restrict-content-modal').style.display =
180 'block';
181 }
182
183 /**
184 * Closes the modal.
185 *
186 * @since 2.3.8
187 */
188 function convertKitRestrictContentCloseModal() {
189 document.querySelector(
190 '#convertkit-restrict-content-modal-background'
191 ).style.display = 'none';
192 document.querySelector(
193 '#convertkit-restrict-content-modal-loading'
194 ).style.display = 'none';
195 document.querySelector('#convertkit-restrict-content-modal').style.display =
196 'none';
197 }
198
199 /**
200 * Submits the given email address to the WP REST API kit/v1/restrict-content/subscriber-authentication
201 * endpoint, which will return either:
202 * - the email form view, with an error message e.g. invalid email,
203 * - the code form view, where the user can enter the OTP.
204 *
205 * @since 2.3.8
206 *
207 * @param {string} nonce WordPress nonce.
208 * @param {string} email Email address.
209 * @param {string} resource_type Resource Type (form|tag|product).
210 * @param {string} resource_id Resource ID (Kit Form,Tag or Product ID).
211 * @param {number} post_id WordPress Post ID being viewed / accessed.
212 * @param {string} spam_protection_response Spam protection response.
213 * @param {Object} container Element to display the response in.
214 */
215 function convertKitRestrictContentSubscriberAuthenticationSendCode(
216 nonce,
217 email,
218 resource_type,
219 resource_id,
220 post_id,
221 spam_protection_response,
222 container
223 ) {
224 fetch(convertkit_restrict_content.subscriber_authentication_url, {
225 method: 'POST',
226 headers: {
227 'Content-Type': 'application/json',
228 'X-WP-Nonce': nonce,
229 },
230 body: JSON.stringify({
231 convertkit_email: email,
232 convertkit_resource_type: resource_type,
233 convertkit_resource_id: resource_id,
234 convertkit_post_id: post_id,
235 spam_protection_response,
236 display_heading: convertKitRestrictContentDisplayHeading(container),
237 }),
238 })
239 .then(function (response) {
240 if (convertkit_restrict_content.debug) {
241 console.log(response);
242 }
243
244 return response.json();
245 })
246 .then(function (result) {
247 if (convertkit_restrict_content.debug) {
248 console.log(result);
249 }
250
251 // Output error message if the response contains a code.
252 if (typeof result.code !== 'undefined') {
253 container.innerHTML = result.message;
254 } else {
255 // Output response, which will be either:
256 // - the email form view, with an error message e.g. invalid email,
257 // - the code form view, where the user can enter the OTP.
258 container.innerHTML = result.data;
259 }
260
261 // Hide loading overlay.
262 convertKitRestrictContentLoading(false);
263
264 // Re-bind OTP listener.
265 convertKitRestrictContentOTPField();
266 })
267 .catch(function (error) {
268 if (convertkit_restrict_content.debug) {
269 console.error(error);
270 }
271 });
272 }
273
274 /**
275 * Submits the given email address to the WP REST API kit/v1/restrict-content/subscriber-verification
276 * endpoint, which will return either:
277 * - the code form view, with an error message e.g. invalid code entered,
278 * - the Post's URL, with a `ck-cache-bust` parameter appended, which can then be loaded to show the content.
279 *
280 * @since 2.3.8
281 *
282 * @param {string} nonce WordPress nonce.
283 * @param {string} subscriber_code OTP Subscriber Code.
284 * @param {string} token Subscriber Token.
285 * @param {number} post_id WordPress Post ID being viewed / accessed.
286 * @param {Object} container Element to display the response in.
287 */
288 function convertKitRestrictContentSubscriberVerification(
289 nonce,
290 subscriber_code,
291 token,
292 post_id,
293 container
294 ) {
295 fetch(convertkit_restrict_content.subscriber_verification_url, {
296 method: 'POST',
297 headers: {
298 'Content-Type': 'application/json',
299 'X-WP-Nonce': nonce,
300 },
301 body: JSON.stringify({
302 subscriber_code,
303 token,
304 convertkit_post_id: post_id,
305 }),
306 })
307 .then(function (response) {
308 if (convertkit_restrict_content.debug) {
309 console.log(response);
310 }
311
312 return response.json();
313 })
314 .then(function (result) {
315 if (convertkit_restrict_content.debug) {
316 console.log(result);
317 }
318
319 // If the entered code is invalid, show the response.
320 if (!result.success) {
321 container.innerHTML = result.data;
322
323 // Hide loading overlay.
324 convertKitRestrictContentLoading(false);
325
326 // Re-bind OTP listener.
327 convertKitRestrictContentOTPField();
328 return;
329 }
330
331 // Code entered is valid; load the URL in the response data.
332 window.location = result.url;
333 })
334 .catch(function (error) {
335 if (convertkit_restrict_content.debug) {
336 console.error(error);
337 }
338 });
339 }
340
341 /**
342 * Defines the `--opt-digit` CSS var, so that the background color shifts to the next input
343 * when entering the one time code.
344 *
345 * @since 2.3.8
346 */
347 function convertKitRestrictContentOTPField() {
348 const otpInput = document.querySelector('#convertkit-subscriber-code');
349
350 // Bail if the OTP input isn't displayed on screen.
351 if (otpInput === null) {
352 return;
353 }
354
355 otpInput.addEventListener('input', function () {
356 // Update the --_otp-digit property when the input value changes.
357 otpInput.style.setProperty('--_otp-digit', otpInput.value.length);
358
359 // If all 6 digits have been entered:
360 // - move the caret input to the start,
361 // - blur the input now that all numbers are entered,
362 // - submit the form.
363 if (otpInput.value.length === 6) {
364 otpInput.setSelectionRange(0, 0);
365 otpInput.blur();
366 document
367 .querySelector('#convertkit-restrict-content-form')
368 .requestSubmit();
369 }
370 });
371 }
372