PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 All 140 releases
← All changes | assets/js/dist/frontend/checkout.js +705 -265 4.1.7 → 4.4.9 View file →
@@ -1,315 +1,755 @@
1 -/******/ (function() { // webpackBootstrap
2 -var __webpack_exports__ = {};
3 -/*!*************************************************!*\
4 - !*** ./assets/src/apps/js/frontend/checkout.js ***!
5 - \*************************************************/
6 -(function ($, settings) {
7 - 'use strict';
1 +/******/ (() => { // webpackBootstrap
2 +/******/ "use strict";
3 +/******/ var __webpack_modules__ = ({
8 4
9 - if (window.LP === undefined) {
10 - window.LP = {};
5 +/***/ "./assets/src/js/utils.js"
6 +/*!********************************!*\
7 + !*** ./assets/src/js/utils.js ***!
8 + \********************************/
9 +(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
10 +
11 +__webpack_require__.r(__webpack_exports__);
12 +/* harmony export */ __webpack_require__.d(__webpack_exports__, {
13 +/* harmony export */ debounce: () => (/* binding */ debounce),
14 +/* harmony export */ eventHandlers: () => (/* binding */ eventHandlers),
15 +/* harmony export */ fullScreenView: () => (/* binding */ fullScreenView),
16 +/* harmony export */ getDataOfForm: () => (/* binding */ getDataOfForm),
17 +/* harmony export */ getFieldKeysOfForm: () => (/* binding */ getFieldKeysOfForm),
18 +/* harmony export */ listenElementCreated: () => (/* binding */ listenElementCreated),
19 +/* harmony export */ listenElementViewed: () => (/* binding */ listenElementViewed),
20 +/* harmony export */ lpAddQueryArgs: () => (/* binding */ lpAddQueryArgs),
21 +/* harmony export */ lpAjaxParseJsonOld: () => (/* binding */ lpAjaxParseJsonOld),
22 +/* harmony export */ lpClassName: () => (/* binding */ lpClassName),
23 +/* harmony export */ lpFetchAPI: () => (/* binding */ lpFetchAPI),
24 +/* harmony export */ lpGetCurrentURLNoParam: () => (/* binding */ lpGetCurrentURLNoParam),
25 +/* harmony export */ lpOnElementReady: () => (/* binding */ lpOnElementReady),
26 +/* harmony export */ lpSetLoadingEl: () => (/* binding */ lpSetLoadingEl),
27 +/* harmony export */ lpShowHideEl: () => (/* binding */ lpShowHideEl),
28 +/* harmony export */ mergeDataWithDatForm: () => (/* binding */ mergeDataWithDatForm),
29 +/* harmony export */ toggleCollapse: () => (/* binding */ toggleCollapse),
30 +/* harmony export */ toggleEnable: () => (/* binding */ toggleEnable)
31 +/* harmony export */ });
32 +/**
33 + * Utils functions
34 + *
35 + * @param url
36 + * @param data
37 + * @param functions
38 + * @since 4.2.5.1
39 + * @version 1.0.7
40 + */
41 +const lpClassName = {
42 + hidden: 'lp-hidden',
43 + loading: 'loading',
44 + elCollapse: 'lp-collapse',
45 + elSectionToggle: '.lp-section-toggle',
46 + elTriggerToggle: '.lp-trigger-toggle',
47 + elBtnFullScreen: '.lp-btn-full-screen-view',
48 + elFullScreen: 'lp-full-screen-view',
49 + elBtnFullScreenClose: 'lp-full-screen-view__close'
50 +};
51 +const lpFetchAPI = (url, data = {}, functions = {}) => {
52 + if ('function' === typeof functions.before) {
53 + functions.before();
11 54 }
12 - /**
13 - * Checkout
14 - *
15 - * @param options
16 - */
55 + fetch(url, {
56 + method: 'GET',
57 + ...data
58 + }).then(response => response.json()).then(response => {
59 + if ('function' === typeof functions.success) {
60 + functions.success(response);
61 + }
62 + }).catch(err => {
63 + if ('function' === typeof functions.error) {
64 + functions.error(err);
65 + }
66 + }).finally(() => {
67 + if ('function' === typeof functions.completed) {
68 + functions.completed();
69 + }
70 + });
71 +};
17 72
73 +/**
74 + * Get current URL without params.
75 + *
76 + * @since 4.2.5.1
77 + */
78 +const lpGetCurrentURLNoParam = () => {
79 + let currentUrl = window.location.href;
80 + const hasParams = currentUrl.includes('?');
81 + if (hasParams) {
82 + currentUrl = currentUrl.split('?')[0];
83 + }
84 + return currentUrl;
85 +};
86 +const lpAddQueryArgs = (endpoint, args) => {
87 + const url = new URL(endpoint);
88 + Object.keys(args).forEach(arg => {
89 + url.searchParams.set(arg, args[arg]);
90 + });
91 + return url;
92 +};
18 93
19 - const Checkout = LP.Checkout = function (options) {
20 - const $formCheckout = $('#learn-press-checkout-form'),
21 - $formLogin = $('#learn-press-checkout-login'),
22 - $formRegister = $('#learn-press-checkout-register'),
23 - $payments = $('.payment-methods'),
24 - $buttonCheckout = $('#learn-press-checkout-place-order'),
25 - $checkoutEmail = $('input[name="guest_email"]');
26 - let selectedMethod = '';
27 -
28 - if (String.prototype.isEmail === undefined) {
29 - String.prototype.isEmail = function () {
30 - return new RegExp('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$').test(this);
31 - };
94 +/**
95 + * Listen element viewed.
96 + *
97 + * @param el
98 + * @param callback
99 + * @since 4.2.5.8
100 + */
101 +const listenElementViewed = (el, callback) => {
102 + const observerSeeItem = new IntersectionObserver(function (entries) {
103 + for (const entry of entries) {
104 + if (entry.isIntersecting) {
105 + callback(entry);
106 + }
32 107 }
108 + });
109 + observerSeeItem.observe(el);
110 +};
33 111
34 - const needPayment = function () {
35 - return $payments.length > 0;
36 - };
112 +/**
113 + * Listen element created.
114 + *
115 + * @param callback
116 + * @since 4.2.5.8
117 + */
118 +const listenElementCreated = callback => {
119 + const observerCreateItem = new MutationObserver(function (mutations) {
120 + mutations.forEach(function (mutation) {
121 + if (mutation.addedNodes) {
122 + mutation.addedNodes.forEach(function (node) {
123 + if (node.nodeType === 1) {
124 + callback(node);
125 + }
126 + });
127 + }
128 + });
129 + });
130 + observerCreateItem.observe(document, {
131 + childList: true,
132 + subtree: true
133 + });
134 + // End.
135 +};
37 136
38 - const selectedPayment = function () {
39 - return $payments.find('input[name="payment_method"]:checked').val();
40 - };
137 +/**
138 + * Listen element created.
139 + *
140 + * @param selector
141 + * @param callback
142 + * @since 4.2.7.1
143 + */
144 +const lpOnElementReady = (selector, callback) => {
145 + const element = document.querySelector(selector);
146 + if (element) {
147 + callback(element);
148 + return;
149 + }
150 + const observer = new MutationObserver((mutations, obs) => {
151 + const element = document.querySelector(selector);
152 + if (element) {
153 + obs.disconnect();
154 + callback(element);
155 + }
156 + });
157 + observer.observe(document.documentElement, {
158 + childList: true,
159 + subtree: true
160 + });
161 +};
41 162
42 - const isLoggedIn = function () {
43 - return $formCheckout.find('input[name="checkout-account-switch-form"]:checked').length = 0;
44 - };
163 +// Parse JSON from string with content include LP_AJAX_START.
164 +const lpAjaxParseJsonOld = data => {
165 + if (typeof data !== 'string') {
166 + return data;
167 + }
168 + const m = String.raw({
169 + raw: data
170 + }).match(/<-- LP_AJAX_START -->(.*)<-- LP_AJAX_END -->/s);
171 + try {
172 + if (m) {
173 + data = JSON.parse(m[1].replace(/(?:\r\n|\r|\n)/g, ''));
174 + } else {
175 + data = JSON.parse(data);
176 + }
177 + } catch (e) {
178 + data = {};
179 + }
180 + return data;
181 +};
45 182
46 - const getActiveFormData = function () {
47 - const formName = $formCheckout.find('input[name="checkout-account-switch-form"]:checked').val();
48 - const $form = $('#checkout-account-' + formName);
49 - return $form.serializeJSON();
50 - };
183 +// status 0: hide, 1: show
184 +const lpShowHideEl = (el, status = 0) => {
185 + if (!el) {
186 + return;
187 + }
188 + if (!status) {
189 + el.classList.add(lpClassName.hidden);
190 + } else {
191 + el.classList.remove(lpClassName.hidden);
192 + }
193 +};
51 194
52 - const getPaymentData = function () {
53 - return $('#checkout-payment').serializeJSON();
54 - };
195 +// status 0: hide, 1: show
196 +const lpSetLoadingEl = (el, status) => {
197 + if (!el) {
198 + return;
199 + }
200 + if (!status) {
201 + el.classList.remove(lpClassName.loading);
202 + } else {
203 + el.classList.add(lpClassName.loading);
204 + }
205 +};
55 206
56 - const getPaymentNote = function () {
57 - return $('.learn-press-checkout-comment').serializeJSON();
58 - };
207 +// Toggle collapse section
208 +const toggleCollapse = (e, target, elTriggerClassName = '', elsExclude = [], callback) => {
209 + if (!elTriggerClassName) {
210 + elTriggerClassName = lpClassName.elTriggerToggle;
211 + }
59 212
60 - const showErrors = function (errors) {
61 - showMessage(errors);
62 - const firstId = Object.keys(errors)[0];
63 - $('input[name="' + firstId + '"]:visible').trigger('focus');
64 - };
65 -
66 - const _formSubmit = function (e) {
67 - e.preventDefault();
68 -
69 - if (needPayment() && !selectedPayment()) {
70 - showMessage('Please select payment method', true);
71 - return false;
213 + // Exclude elements, which should not trigger the collapse toggle
214 + if (elsExclude && elsExclude.length > 0) {
215 + for (const elExclude of elsExclude) {
216 + if (target.closest(elExclude)) {
217 + return;
72 218 }
219 + }
220 + }
221 + const elTrigger = target.closest(elTriggerClassName);
222 + if (!elTrigger) {
223 + return;
224 + }
73 225
74 - let formData = {};
226 + //console.log( 'elTrigger', elTrigger );
75 227
76 - if (!isLoggedIn()) {
77 - formData = $.extend(formData, getActiveFormData(), getPaymentNote());
78 - }
228 + const elSectionToggle = elTrigger.closest(`${lpClassName.elSectionToggle}`);
229 + if (!elSectionToggle) {
230 + return;
231 + }
232 + elSectionToggle.classList.toggle(`${lpClassName.elCollapse}`);
233 + if ('function' === typeof callback) {
234 + callback(elSectionToggle);
235 + }
236 +};
79 237
80 - formData = $.extend(formData, getPaymentData());
81 - removeMessage();
82 - const btnText = $buttonCheckout.text();
83 - const urlHandle = new URL(options.ajaxurl);
84 - urlHandle.searchParams.set('lp-ajax', 'checkout');
85 - $.ajax({
86 - url: urlHandle,
87 - dataType: 'html',
88 - data: formData,
89 - type: 'POST',
238 +// Get data of form
239 +const getDataOfForm = form => {
240 + const dataSend = {};
241 + const formData = new FormData(form);
242 + for (const pair of formData.entries()) {
243 + const key = pair[0];
244 + const value = formData.getAll(key);
245 + if (!dataSend.hasOwnProperty(key)) {
246 + // Convert value array to string.
247 + dataSend[key] = value.join(',');
248 + }
249 + }
250 + return dataSend;
251 +};
90 252
91 - beforeSend() {
92 - $('#learn-press-checkout-place-order').addClass('loading');
93 - $buttonCheckout.html(options.i18n_processing);
94 - },
253 +// Get field keys of form
254 +const getFieldKeysOfForm = form => {
255 + const keys = [];
256 + const elements = form.elements;
257 + for (let i = 0; i < elements.length; i++) {
258 + const name = elements[i].name;
259 + if (name && !keys.includes(name)) {
260 + keys.push(name);
261 + }
262 + }
263 + return keys;
264 +};
95 265
96 - success(response) {
97 - response = LP.parseJSON(response);
266 +// Merge data handle with data form.
267 +const mergeDataWithDatForm = (elForm, dataHandle) => {
268 + const dataForm = getDataOfForm(elForm);
269 + const keys = getFieldKeysOfForm(elForm);
270 + keys.forEach(key => {
271 + if (!dataForm.hasOwnProperty(key)) {
272 + delete dataHandle[key];
273 + } else if (dataForm[key][0] === '') {
274 + delete dataForm[key];
275 + delete dataHandle[key];
276 + }
277 + });
278 + dataHandle = {
279 + ...dataHandle,
280 + ...dataForm
281 + };
282 + return dataHandle;
283 +};
98 284
99 - if (response.messages) {
100 - showErrors(response.messages);
101 - } else if (response.message) {
102 - showMessage('<div class="learn-press-message error">' + response.message + '</div>');
103 - }
285 +/**
286 + * Event trigger
287 + * For each list of event handlers, listen event on document.
288 + *
289 + * eventName: 'click', 'change', ...
290 + * eventHandlers = [ { selector: '.lp-button', callBack: function(){}, class: object } ]
291 + *
292 + * @param eventName
293 + * @param eventHandlers
294 + */
295 +const eventHandlers = (eventName, eventHandlers) => {
296 + document.addEventListener(eventName, e => {
297 + const target = e.target;
298 + let args = {
299 + e,
300 + target
301 + };
302 + eventHandlers.forEach(eventHandler => {
303 + args = {
304 + ...args,
305 + ...eventHandler
306 + };
104 307
105 - $('#learn-press-checkout-place-order').removeClass('loading');
308 + //console.log( args );
106 309
107 - if ('success' === response.result) {
108 - if (response.redirect && response.redirect.match(/https?/)) {
109 - $buttonCheckout.html(options.i18n_redirecting);
110 - window.location = response.redirect;
111 - }
112 - } else {
113 - $buttonCheckout.html(btnText);
114 - }
115 - },
310 + // Check condition before call back
311 + if (eventHandler.conditionBeforeCallBack) {
312 + if (eventHandler.conditionBeforeCallBack(args) !== true) {
313 + return;
314 + }
315 + }
116 316
117 - error(jqXHR, textStatus, errorThrown) {
118 - $('#learn-press-checkout-place-order').removeClass('loading');
119 - showMessage('<div class="learn-press-message error">' + errorThrown + '</div>');
120 - $buttonCheckout.html(btnText);
121 - LP.unblockContent();
317 + // Special check for keydown event with checkIsEventEnter = true
318 + if (eventName === 'keydown' && eventHandler.checkIsEventEnter) {
319 + if (e.key !== 'Enter') {
320 + return;
122 321 }
322 + }
323 + if (target.closest(eventHandler.selector)) {
324 + if (eventHandler.class) {
325 + // Call method of class, function callBack will understand exactly {this} is class object.
326 + eventHandler.class[eventHandler.callBack](args);
327 + } else {
328 + // For send args is objected, {this} is eventHandler object, not class object.
329 + eventHandler.callBack(args);
330 + }
331 + }
332 + });
333 + });
334 +};
123 335
124 - });
125 - return false;
126 - };
336 +/**
337 + * Debounce - delays function execution until after `wait` ms of inactivity.
338 + *
339 + * Each call resets the timer. Only the last call in a burst executes.
340 + *
341 + * USE CASES:
342 + * - Search inputs, form validation, window resize
343 + * - Multiple elements need independent timers
344 + * - When you need to call with different arguments
345 + *
346 + * EXAMPLES:
347 + * const debouncedSearch = debounce( (query) => fetchResults(query), 300 );
348 + * searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value));
349 + *
350 + * const debouncedResize = debounce( recalculateLayout, 250 );
351 + * window.addEventListener('resize', debouncedResize);
352 + *
353 + * ⚠️ Create ONCE outside event handlers, not inside.
354 + *
355 + * @param {Function} func - Function to debounce (can be anonymous)
356 + * @param {number} wait - Milliseconds to wait (default: 500)
357 + * @return {Function} Debounced wrapper function
358 + * @since 4.3.7
359 + * @version 1.0.0
360 + */
361 +const debounce = (func, wait = 500) => {
362 + let timer;
363 + return args => {
364 + clearTimeout(timer);
365 + timer = setTimeout(() => func(args), wait);
366 + };
367 +};
127 368
128 - const _selectPaymentChange = function () {
129 - const id = $(this).val(),
130 - $selected = $payments.children().filter('.selected').removeClass('selected'),
131 - buttonText = $selected.find('#payment_method_' + selectedMethod).data('order_button_text');
132 - $selected.find('.payment-method-form').slideUp();
133 - $selected.end().filter('#learn-press-payment-method-' + id).addClass('selected').find('.payment-method-form').hide().slideDown();
134 - selectedMethod = $selected.find('payment_method').val();
369 +/**
370 + * Initialize lp-toggle-enable components.
371 + *
372 + * Finds all `.lp-toggle-enable` elements and wires up toggle behavior.
373 + * Reads initial state from `data-enabled` attribute ("true"/"false").
374 + * Calls `data-on-toggle` callback (if provided via options) on state change.
375 + *
376 + * HTML structure:
377 + * <label class="lp-toggle-enable" data-enabled="true">
378 + * <input type="checkbox" class="lp-toggle-enable__input" />
379 + * <span class="lp-toggle-enable__track"></span>
380 + * </label>
381 + *
382 + * @param {string} selector CSS selector for toggle elements (default: '.lp-toggle-enable')
383 + * @param {Function} onToggle Optional callback( el, isEnabled ) called on state change
384 + * @since 4.4.5
385 + * @version 1.0.0
386 + */
387 +window.lpToggleEnableInit = 0;
388 +const toggleEnable = (onToggle = null) => {
389 + if (window.lpToggleEnableInit) {
390 + return;
391 + }
392 + window.lpToggleEnableInit = 1;
393 + const selector = '.lp-toggle-enable';
394 + const updateUI = (toggle, isEnabled) => {
395 + toggle.classList.toggle('is-enabled', isEnabled);
396 + const input = toggle.querySelector('.lp-toggle-enable__input');
397 + if (input) {
398 + input.checked = isEnabled;
399 + input.value = isEnabled ? '1' : '0';
400 + }
401 + };
135 402
136 - if (buttonText) {
137 - $buttonCheckout.html(buttonText);
403 + // Delegate click handling via eventHandlers.
404 + eventHandlers('click', [{
405 + selector,
406 + callBack: args => {
407 + const {
408 + e,
409 + target
410 + } = args;
411 + const toggle = target.closest(selector);
412 + if (!toggle || toggle.classList.contains('is-disabled')) {
413 + return;
138 414 }
139 - };
140 - /**
141 - * Button to switch between mode login/register or place order
142 - * in case user is not logged in and guest checkout is enabled.
143 - */
415 + e.preventDefault();
416 + const isEnabled = !toggle.classList.contains('is-enabled');
417 + updateUI(toggle, isEnabled);
418 + if ('function' === typeof onToggle) {
419 + onToggle(toggle, isEnabled);
420 + }
421 + }
422 + }]);
423 +};
144 424
145 -
146 - const _guestCheckoutClick = function () {
147 - const showOrHide = $formCheckout.toggle().is(':visible');
148 - $formLogin.toggle(!showOrHide);
149 - $formRegister.toggle(!showOrHide);
150 - $('#learn-press-button-guest-checkout').toggle(!showOrHide);
151 - };
152 - /**
153 - * Append messages into document.
154 - *
155 - * @param message
156 - * @param wrap
157 - */
158 -
159 -
160 - const showMessage = function (message) {
161 - let wrap = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
162 - removeMessage();
163 -
164 - if ($.isPlainObject(message)) {
165 - Object.keys(message).reverse().forEach(id => {
166 - const m = message[id];
167 - let msg = Array.isArray(m) ? m[0] : m;
168 - const type = Array.isArray(m) ? m[1] : '';
169 - msg = '<div class="learn-press-message ' + (typeof type === 'string' ? type : '') + '">' + msg + '</div>';
170 - $formCheckout.prepend(msg);
425 +/**
426 + * Initialize custom fullscreen view buttons.
427 + *
428 + * Delegates clicks on `.lp-btn-full-screen-view` buttons to
429 + * `lpToggleFullscreenView`. Reads the `data-target` attribute to find the
430 + * target element. Falls back to the button's parent element when
431 + * `data-target` is not provided.
432 + *
433 + * @since 4.4.5
434 + * @version 1.0.0
435 + */
436 +window.lpFullScreenViewInit = 0;
437 +const fullScreenView = () => {
438 + if (window.lpFullScreenViewInit) {
439 + return;
440 + }
441 + window.lpFullScreenViewInit = 1;
442 + let lastScrollY = 0;
443 + const lpToggleFullscreenView = (elTarget, elBtnFullScreen = null) => {
444 + const isFullscreen = elTarget.classList.contains(lpClassName.elFullScreen);
445 + if (isFullscreen) {
446 + elTarget.classList.remove(lpClassName.elFullScreen);
447 + document.documentElement.classList.remove('lp-full-screen-active');
448 + window.scrollTo(0, lastScrollY);
449 + } else {
450 + lastScrollY = window.scrollY;
451 + elTarget.classList.add(lpClassName.elFullScreen);
452 + document.documentElement.classList.add('lp-full-screen-active');
453 + }
454 + if (!isFullscreen) {
455 + if (!elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`)) {
456 + const closeButton = document.createElement('button');
457 + closeButton.type = 'button';
458 + closeButton.className = lpClassName.elBtnFullScreenClose;
459 + closeButton.setAttribute('aria-label', 'Close');
460 + closeButton.innerHTML = lpData.i18n.closeButtonFullScreen || 'Close &times;';
461 + closeButton.addEventListener('click', e => {
462 + e.preventDefault();
463 + lpToggleFullscreenView(elTarget);
171 464 });
465 + elTarget.appendChild(closeButton);
466 + }
467 + } else {
468 + const closeButton = elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`);
469 + if (closeButton) {
470 + closeButton.remove();
471 + }
472 + }
473 + };
474 + eventHandlers('click', [{
475 + selector: lpClassName.elBtnFullScreen,
476 + callBack: args => {
477 + const {
478 + e,
479 + target
480 + } = args;
481 + const elBtnFullScreen = target.closest(lpClassName.elBtnFullScreen);
482 + if (!elBtnFullScreen) {
483 + console.log('No full screen button found');
172 484 return;
173 485 }
174 -
175 - if (wrap) {
176 - message = '<div class="learn-press-message ' + (typeof wrap === 'string' ? wrap : '') + '">' + message + '</div>';
486 + e.preventDefault();
487 + let elTarget = null;
488 + const targetSelector = elBtnFullScreen.dataset.targetFullscreen;
489 + console.log(targetSelector);
490 + if (targetSelector) {
491 + elTarget = document.querySelector(targetSelector);
177 492 }
178 -
179 - if (Array.isArray(message)) {
180 - message.map(msg => $formCheckout.prepend('<div class="learn-press-message error">' + msg + '</div>'));
181 - } else {
182 - $formCheckout.prepend('<div class="learn-press-message error">' + message + '</div>');
183 - }
184 -
185 - $('html, body').animate({
186 - scrollTop: $formCheckout.offset().top - 100
187 - }, 1000);
188 - $(document).trigger('learn-press/checkout-error');
189 - };
190 - /**
191 - * Callback function for guest email.
192 - *
193 - * @private
194 - */
195 -
196 -
197 - const _checkEmail = function () {
198 - if (!this.value.isEmail()) {
493 + if (!elTarget) {
494 + console.log('No target element found');
199 495 return;
200 496 }
497 + lpToggleFullscreenView(elTarget, elBtnFullScreen);
498 + }
499 + }]);
500 +};
201 501
202 - this.timer && clearTimeout(this.timer);
203 - $checkoutEmail.addClass('loading');
204 - this.timer = setTimeout(function () {
205 - $.post({
206 - url: window.location.href,
207 - data: {
208 - 'lp-ajax': 'checkout-user-email-exists',
209 - email: $checkoutEmail.val()
210 - },
502 +/***/ }
211 503
212 - success(response) {
213 - const res = LP.parseJSON(response);
214 - $checkoutEmail.removeClass('loading');
215 - $('.lp-guest-checkout-output').remove();
504 +/******/ });
505 +/************************************************************************/
506 +/******/ // The module cache
507 +/******/ var __webpack_module_cache__ = {};
508 +/******/
509 +/******/ // The require function
510 +/******/ function __webpack_require__(moduleId) {
511 +/******/ // Check if module is in cache
512 +/******/ var cachedModule = __webpack_module_cache__[moduleId];
513 +/******/ if (cachedModule !== undefined) {
514 +/******/ return cachedModule.exports;
515 +/******/ }
516 +/******/ // Create a new module (and put it into the cache)
517 +/******/ var module = __webpack_module_cache__[moduleId] = {
518 +/******/ // no module.id needed
519 +/******/ // no module.loaded needed
520 +/******/ exports: {}
521 +/******/ };
522 +/******/
523 +/******/ // Execute the module function
524 +/******/ if (!(moduleId in __webpack_modules__)) {
525 +/******/ delete __webpack_module_cache__[moduleId];
526 +/******/ var e = new Error("Cannot find module '" + moduleId + "'");
527 +/******/ e.code = 'MODULE_NOT_FOUND';
528 +/******/ throw e;
529 +/******/ }
530 +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
531 +/******/
532 +/******/ // Return the exports of the module
533 +/******/ return module.exports;
534 +/******/ }
535 +/******/
536 +/************************************************************************/
537 +/******/ /* webpack/runtime/define property getters */
538 +/******/ (() => {
539 +/******/ // define getter functions for harmony exports
540 +/******/ __webpack_require__.d = (exports, definition) => {
541 +/******/ for(var key in definition) {
542 +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
543 +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
544 +/******/ }
545 +/******/ }
546 +/******/ };
547 +/******/ })();
548 +/******/
549 +/******/ /* webpack/runtime/hasOwnProperty shorthand */
550 +/******/ (() => {
551 +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
552 +/******/ })();
553 +/******/
554 +/******/ /* webpack/runtime/make namespace object */
555 +/******/ (() => {
556 +/******/ // define __esModule on exports
557 +/******/ __webpack_require__.r = (exports) => {
558 +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
559 +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
560 +/******/ }
561 +/******/ Object.defineProperty(exports, '__esModule', { value: true });
562 +/******/ };
563 +/******/ })();
564 +/******/
565 +/************************************************************************/
566 +var __webpack_exports__ = {};
567 +// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
568 +(() => {
569 +/*!********************************************!*\
570 + !*** ./assets/src/js/frontend/checkout.js ***!
571 + \********************************************/
572 +__webpack_require__.r(__webpack_exports__);
573 +/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils.js */ "./assets/src/js/utils.js");
574 +/**
575 + * File JS handling checkout page.
576 + */
216 577
217 - if (res && res.output) {
218 - $checkoutEmail.after(res.output);
219 - }
220 - }
221 578
222 - });
223 - }, 500);
224 - };
225 - /**
226 - * Remove all messages
227 - */
228 579
229 -
230 - const removeMessage = function () {
231 - $('.learn-press-error, .learn-press-notice, .learn-press-message').remove();
580 +// Events
581 +document.addEventListener('submit', e => {
582 + window.lpCheckout.submit(e);
583 +});
584 +document.addEventListener('change', e => {
585 + window.lpCheckout.paymentSelect(e);
586 +});
587 +document.addEventListener('keyup', e => {
588 + window.lpCheckout.checkEmailGuest(e);
589 +});
590 +window.lpCheckout = {
591 + idFormCheckout: 'learn-press-checkout-form',
592 + idBtnPlaceOrder: 'learn-press-checkout-place-order',
593 + classPaymentMethod: 'lp-payment-method',
594 + classPaymentMethodForm: 'payment-method-form',
595 + timeOutCheckEmail: null,
596 + fetchAPI: (url, params, callBack) => {
597 + const option = {
598 + headers: {}
232 599 };
233 - /**
234 - * Callback function for showing/hiding register form.
235 - *
236 - * @param e
237 - * @param toggle
238 - */
600 + if (0 !== parseInt(lpData.user_id)) {
601 + option.headers['X-WP-Nonce'] = lpData.nonce;
602 + }
603 + const searchParams = new URLSearchParams();
604 + Object.keys(params).forEach(key => {
605 + searchParams.append(key, params[key]);
606 + });
607 + option.method = 'POST';
608 + option.body = searchParams;
609 + fetch(url, option).then(res => res.text()).then(data => {
610 + data = (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpAjaxParseJsonOld)(data);
611 + callBack.success(data);
612 + }).finally(() => {
613 + callBack.completed();
614 + }).catch(err => callBack.error(err));
615 + },
616 + submit: e => {
617 + const formCheckout = e.target;
618 + if (formCheckout.id !== window.lpCheckout.idFormCheckout) {
619 + return;
620 + }
621 + if (formCheckout.classList.contains('processing')) {
622 + return;
623 + }
624 + e.preventDefault();
625 + formCheckout.classList.add('processing');
626 + const btnSubmit = formCheckout.querySelector('button[type="submit"]');
627 + btnSubmit.disabled = true;
628 + window.lpCheckout.removeMessage();
629 + const elBtnPlaceOrder = document.getElementById(window.lpCheckout.idBtnPlaceOrder);
630 + const urlHandle = new URL(lpCheckoutSettings.ajaxurl);
631 + urlHandle.searchParams.set('lp-ajax', 'checkout');
239 632
240 -
241 - const _toggleRegisterForm = function (e, toggle) {
242 - toggle = $formRegister.find('.learn-press-form-register').toggle(toggle).is(':visible');
243 - $formRegister.find('.checkout-form-register-toggle[data-toggle="show"]').toggle(!toggle);
244 - e && (e.preventDefault(), _toggleLoginForm(null, !toggle));
633 + // get values from FormData
634 + const formData = new FormData(formCheckout);
635 + const dataSend = Object.fromEntries(Array.from(formData.keys(), key => {
636 + const val = formData.getAll(key);
637 + return [key, val.length > 1 ? val : val.pop()];
638 + }));
639 + elBtnPlaceOrder.classList.add('loading');
640 + const callBack = {
641 + success: response => {
642 + response = (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpAjaxParseJsonOld)(response);
643 + const {
644 + message,
645 + result
646 + } = response;
647 + if (response.redirect) {
648 + window.location.href = response.redirect;
649 + } else if ('success' !== result) {
650 + window.lpCheckout.showErrors(formCheckout, 'error', message);
651 + }
652 + },
653 + error: error => {
654 + window.lpCheckout.showErrors(formCheckout, 'error', error);
655 + },
656 + completed: () => {
657 + elBtnPlaceOrder.classList.remove('loading');
658 + formCheckout.classList.remove('processing');
659 + btnSubmit.disabled = false;
660 + }
245 661 };
246 - /**
247 - * Callback function for showing/hiding login form.
248 - *
249 - * @param e {Event}
250 - * @param toggle {boolean}
251 - * @private
252 - */
253 -
254 -
255 - const _toggleLoginForm = function (e, toggle) {
256 - toggle = $formLogin.find('.learn-press-form-login').toggle(toggle).is(':visible');
257 - $formLogin.find('.checkout-form-login-toggle[data-toggle="show"]').toggle(!toggle);
258 - e && (e.preventDefault(), _toggleRegisterForm(null, !toggle));
259 - };
260 - /**
261 - * Place order action
262 - */
263 -
264 -
265 - $buttonCheckout.on('click', function (e) {});
266 - $('.lp-button-guest-checkout').on('click', _guestCheckoutClick);
267 - $('#learn-press-button-cancel-guest-checkout').on('click', _guestCheckoutClick);
268 - $checkoutEmail.on('keyup changex', _checkEmail).trigger('changex');
269 - $payments.on('change select', 'input[name="payment_method"]', _selectPaymentChange);
270 - $formCheckout.on('submit', _formSubmit);
271 - $payments.children('.selected').find('input[name="payment_method"]').trigger('select');
272 - $formLogin.on('click', '.checkout-form-login-toggle', _toggleLoginForm);
273 - $formRegister.on('click', '.checkout-form-register-toggle', _toggleRegisterForm);
274 - $formRegister.find('input').each(function () {
275 - if (-1 !== $.inArray($(this).attr('type').toLowerCase(), ['text', 'email', 'number']) && $(this).val()) {
276 - _toggleRegisterForm();
277 -
278 - return false;
662 + window.lpCheckout.fetchAPI(urlHandle, dataSend, callBack);
663 + },
664 + paymentSelect: e => {
665 + const target = e.target;
666 + const elPaymentMethod = target.closest(`.${window.lpCheckout.classPaymentMethod}`);
667 + if (!elPaymentMethod) {
668 + return;
669 + }
670 + const elUlPaymentMethods = elPaymentMethod.closest('.payment-methods');
671 + if (!elUlPaymentMethods) {
672 + return;
673 + }
674 + const elPaymentMethods = elUlPaymentMethods.querySelectorAll(`.${window.lpCheckout.classPaymentMethod}`);
675 + elPaymentMethods.forEach(el => {
676 + el.classList.remove('selected');
677 + const elPaymentMethodForm = el.querySelector(`.${window.lpCheckout.classPaymentMethodForm}`);
678 + if (!elPaymentMethodForm) {
679 + return;
279 680 }
681 + if (elPaymentMethod !== el) {
682 + elPaymentMethodForm.style.display = 'none';
683 + } else {
684 + elPaymentMethodForm.style.display = 'block';
685 + }
280 686 });
281 - $formLogin.find('input:not([type="hidden"])').each(function () {
282 - if (-1 !== $.inArray($(this).attr('type').toLowerCase(), ['text', 'email', 'number']) && $(this).val()) {
283 - _toggleLoginForm();
284 -
285 - return false;
286 - }
287 - }); // Show form if there is only one form Register or Login
288 -
289 - if ($formRegister.length && !$formLogin.length) {
290 - _toggleRegisterForm();
291 - } else if (!$formRegister.length && $formLogin.length) {
292 - _toggleLoginForm();
687 + elPaymentMethod.classList.add('selected');
688 + },
689 + checkEmailGuest: e => {
690 + const target = e.target;
691 + if (target.id !== 'guest_email') {
692 + return;
293 693 }
294 -
295 - $formCheckout.on('change', 'input[name="checkout-account-switch-form"]', function () {
296 - $(this).next().find('input:not([type="hidden"]):visible').first().trigger('focus');
297 - }).on('change', '#guest_email', function () {
298 - $formCheckout.find('#reg_email').val(this.value);
299 - }).on('change', '#reg_email', function () {
300 - $formCheckout.find('#guest_email').val(this.value);
694 + if (!window.lpCheckout.isEmail(target.value)) {
695 + return;
696 + }
697 + target.classList.add('loading');
698 + if (window.lpCheckout.timeOutCheckEmail !== null) {
699 + clearTimeout(window.lpCheckout.timeOutCheckEmail);
700 + }
701 + window.lpCheckout.timeOutCheckEmail = setTimeout(() => {
702 + const callBack = {
703 + success: response => {
704 + const {
705 + message,
706 + data,
707 + status
708 + } = response;
709 + if ('success' === status) {
710 + const content = data.content || '';
711 + const elGuestOutput = document.querySelector('.lp-guest-checkout-output');
712 + if (elGuestOutput) {
713 + elGuestOutput.remove();
714 + }
715 + target.insertAdjacentHTML('afterend', content);
716 + } else {
717 + window.lpCheckout.showErrors(target.closest('form'), status, message);
718 + }
719 + },
720 + error: error => {
721 + window.lpCheckout.showErrors(target.closest('form'), 'error', error);
722 + },
723 + completed: () => {
724 + target.classList.remove('loading');
725 + }
726 + };
727 + window.lpCheckout.fetchAPI(window.location.href, {
728 + 'lp-ajax': 'checkout-user-email-exists',
729 + email: target.value
730 + }, callBack);
731 + }, 500);
732 + },
733 + removeMessage: () => {
734 + const lpMessages = document.querySelectorAll('.learn-press-message');
735 + if (!lpMessages) {
736 + return;
737 + }
738 + lpMessages.forEach(el => {
739 + el.remove();
301 740 });
302 - setTimeout(function () {
303 - $formCheckout.find('input:not([type="hidden"]):visible').first().trigger('focus');
304 - }, 300);
305 - };
741 + },
742 + showErrors: (form, status, message) => {
743 + const mesHtml = `<div class="learn-press-message ${status}">${message}</div>`;
744 + form.insertAdjacentHTML('afterbegin', mesHtml);
745 + form.scrollIntoView();
746 + },
747 + isEmail: email => {
748 + return new RegExp('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$').test(email);
749 + }
750 +};
751 +})();
306 752
307 - $(document).ready(function () {
308 - if (typeof lpCheckoutSettings !== 'undefined') {
309 - LP.$checkout = new Checkout(lpCheckoutSettings);
310 - }
311 - });
312 -})(jQuery);
313 753 /******/ })()
314 754 ;
315 755 //# sourceMappingURL=checkout.js.map