PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
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 4.2.0 All 139 releases
learnpress / assets / js / dist / frontend / courses.js

courses.js in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.8, at assets/js/dist/frontend/courses.js

1,253 lines 40.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (() => { // webpackBootstrap
2 /******/ "use strict";
3 /******/ var __webpack_modules__ = ({
4
5 /***/ "./assets/src/js/api.js"
6 /*!******************************!*\
7 !*** ./assets/src/js/api.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 */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
14 /* harmony export */ });
15 /**
16 * List API on backend
17 *
18 * @since 4.2.6
19 * @version 1.0.2
20 */
21
22 const lplistAPI = {};
23 let lp_rest_url;
24 if ('undefined' !== typeof lpDataAdmin) {
25 lp_rest_url = lpDataAdmin.lp_rest_url;
26 lplistAPI.admin = {
27 apiAdminNotice: lp_rest_url + 'lp/v1/admin/tools/admin-notices',
28 apiAddons: lp_rest_url + 'lp/v1/addon/all',
29 apiAddonAction: lp_rest_url + 'lp/v1/addon/action-n',
30 apiAddonsPurchase: lp_rest_url + 'lp/v1/addon/info-addons-purchase',
31 apiSearchCourses: lp_rest_url + 'lp/v1/admin/tools/search-course',
32 apiSearchUsers: lp_rest_url + 'lp/v1/admin/tools/search-user',
33 apiAssignUserCourse: lp_rest_url + 'lp/v1/admin/tools/assign-user-course',
34 apiUnAssignUserCourse: lp_rest_url + 'lp/v1/admin/tools/unassign-user-course'
35 };
36 }
37 if ('undefined' !== typeof lpData) {
38 lp_rest_url = lpData.lp_rest_url;
39 lplistAPI.frontend = {
40 apiWidgets: lp_rest_url + 'lp/v1/widgets/api',
41 apiCourses: lp_rest_url + 'lp/v1/courses/archive-course',
42 // Deprecated API, don't load from v4.3.7
43 apiAJAX: lp_rest_url + 'lp/v1/load_content_via_ajax/',
44 // Deprecated since 4.3.0
45 apiProfileCoverImage: lp_rest_url + 'lp/v1/profile/cover-image'
46 };
47 }
48 if (lp_rest_url) {
49 lplistAPI.apiCourses = lp_rest_url + 'lp/v1/courses/';
50 lplistAPI.apiEditCoursesArchiveBlock = lp_rest_url + 'lp/v1/courses/edit-archive-block';
51 lplistAPI.apiCoursesSuggest = lp_rest_url + 'lp/v1/courses/courses-suggest';
52 }
53 /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (lplistAPI);
54
55 /***/ },
56
57 /***/ "./assets/src/js/utils.js"
58 /*!********************************!*\
59 !*** ./assets/src/js/utils.js ***!
60 \********************************/
61 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
62
63 __webpack_require__.r(__webpack_exports__);
64 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
65 /* harmony export */ debounce: () => (/* binding */ debounce),
66 /* harmony export */ eventHandlers: () => (/* binding */ eventHandlers),
67 /* harmony export */ fullScreenView: () => (/* binding */ fullScreenView),
68 /* harmony export */ getDataOfForm: () => (/* binding */ getDataOfForm),
69 /* harmony export */ getFieldKeysOfForm: () => (/* binding */ getFieldKeysOfForm),
70 /* harmony export */ listenElementCreated: () => (/* binding */ listenElementCreated),
71 /* harmony export */ listenElementViewed: () => (/* binding */ listenElementViewed),
72 /* harmony export */ lpAddQueryArgs: () => (/* binding */ lpAddQueryArgs),
73 /* harmony export */ lpAjaxParseJsonOld: () => (/* binding */ lpAjaxParseJsonOld),
74 /* harmony export */ lpClassName: () => (/* binding */ lpClassName),
75 /* harmony export */ lpFetchAPI: () => (/* binding */ lpFetchAPI),
76 /* harmony export */ lpGetCurrentURLNoParam: () => (/* binding */ lpGetCurrentURLNoParam),
77 /* harmony export */ lpOnElementReady: () => (/* binding */ lpOnElementReady),
78 /* harmony export */ lpSetLoadingEl: () => (/* binding */ lpSetLoadingEl),
79 /* harmony export */ lpShowHideEl: () => (/* binding */ lpShowHideEl),
80 /* harmony export */ mergeDataWithDatForm: () => (/* binding */ mergeDataWithDatForm),
81 /* harmony export */ toggleCollapse: () => (/* binding */ toggleCollapse),
82 /* harmony export */ toggleEnable: () => (/* binding */ toggleEnable)
83 /* harmony export */ });
84 /**
85 * Utils functions
86 *
87 * @param url
88 * @param data
89 * @param functions
90 * @since 4.2.5.1
91 * @version 1.0.7
92 */
93 const lpClassName = {
94 hidden: 'lp-hidden',
95 loading: 'loading',
96 elCollapse: 'lp-collapse',
97 elSectionToggle: '.lp-section-toggle',
98 elTriggerToggle: '.lp-trigger-toggle',
99 elBtnFullScreen: '.lp-btn-full-screen-view',
100 elFullScreen: 'lp-full-screen-view',
101 elBtnFullScreenClose: 'lp-full-screen-view__close'
102 };
103 const lpFetchAPI = (url, data = {}, functions = {}) => {
104 if ('function' === typeof functions.before) {
105 functions.before();
106 }
107 fetch(url, {
108 method: 'GET',
109 ...data
110 }).then(response => response.json()).then(response => {
111 if ('function' === typeof functions.success) {
112 functions.success(response);
113 }
114 }).catch(err => {
115 if ('function' === typeof functions.error) {
116 functions.error(err);
117 }
118 }).finally(() => {
119 if ('function' === typeof functions.completed) {
120 functions.completed();
121 }
122 });
123 };
124
125 /**
126 * Get current URL without params.
127 *
128 * @since 4.2.5.1
129 */
130 const lpGetCurrentURLNoParam = () => {
131 let currentUrl = window.location.href;
132 const hasParams = currentUrl.includes('?');
133 if (hasParams) {
134 currentUrl = currentUrl.split('?')[0];
135 }
136 return currentUrl;
137 };
138 const lpAddQueryArgs = (endpoint, args) => {
139 const url = new URL(endpoint);
140 Object.keys(args).forEach(arg => {
141 url.searchParams.set(arg, args[arg]);
142 });
143 return url;
144 };
145
146 /**
147 * Listen element viewed.
148 *
149 * @param el
150 * @param callback
151 * @since 4.2.5.8
152 */
153 const listenElementViewed = (el, callback) => {
154 const observerSeeItem = new IntersectionObserver(function (entries) {
155 for (const entry of entries) {
156 if (entry.isIntersecting) {
157 callback(entry);
158 }
159 }
160 });
161 observerSeeItem.observe(el);
162 };
163
164 /**
165 * Listen element created.
166 *
167 * @param callback
168 * @since 4.2.5.8
169 */
170 const listenElementCreated = callback => {
171 const observerCreateItem = new MutationObserver(function (mutations) {
172 mutations.forEach(function (mutation) {
173 if (mutation.addedNodes) {
174 mutation.addedNodes.forEach(function (node) {
175 if (node.nodeType === 1) {
176 callback(node);
177 }
178 });
179 }
180 });
181 });
182 observerCreateItem.observe(document, {
183 childList: true,
184 subtree: true
185 });
186 // End.
187 };
188
189 /**
190 * Listen element created.
191 *
192 * @param selector
193 * @param callback
194 * @since 4.2.7.1
195 */
196 const lpOnElementReady = (selector, callback) => {
197 const element = document.querySelector(selector);
198 if (element) {
199 callback(element);
200 return;
201 }
202 const observer = new MutationObserver((mutations, obs) => {
203 const element = document.querySelector(selector);
204 if (element) {
205 obs.disconnect();
206 callback(element);
207 }
208 });
209 observer.observe(document.documentElement, {
210 childList: true,
211 subtree: true
212 });
213 };
214
215 // Parse JSON from string with content include LP_AJAX_START.
216 const lpAjaxParseJsonOld = data => {
217 if (typeof data !== 'string') {
218 return data;
219 }
220 const m = String.raw({
221 raw: data
222 }).match(/<-- LP_AJAX_START -->(.*)<-- LP_AJAX_END -->/s);
223 try {
224 if (m) {
225 data = JSON.parse(m[1].replace(/(?:\r\n|\r|\n)/g, ''));
226 } else {
227 data = JSON.parse(data);
228 }
229 } catch (e) {
230 data = {};
231 }
232 return data;
233 };
234
235 // status 0: hide, 1: show
236 const lpShowHideEl = (el, status = 0) => {
237 if (!el) {
238 return;
239 }
240 if (!status) {
241 el.classList.add(lpClassName.hidden);
242 } else {
243 el.classList.remove(lpClassName.hidden);
244 }
245 };
246
247 // status 0: hide, 1: show
248 const lpSetLoadingEl = (el, status) => {
249 if (!el) {
250 return;
251 }
252 if (!status) {
253 el.classList.remove(lpClassName.loading);
254 } else {
255 el.classList.add(lpClassName.loading);
256 }
257 };
258
259 // Toggle collapse section
260 const toggleCollapse = (e, target, elTriggerClassName = '', elsExclude = [], callback) => {
261 if (!elTriggerClassName) {
262 elTriggerClassName = lpClassName.elTriggerToggle;
263 }
264
265 // Exclude elements, which should not trigger the collapse toggle
266 if (elsExclude && elsExclude.length > 0) {
267 for (const elExclude of elsExclude) {
268 if (target.closest(elExclude)) {
269 return;
270 }
271 }
272 }
273 const elTrigger = target.closest(elTriggerClassName);
274 if (!elTrigger) {
275 return;
276 }
277
278 //console.log( 'elTrigger', elTrigger );
279
280 const elSectionToggle = elTrigger.closest(`${lpClassName.elSectionToggle}`);
281 if (!elSectionToggle) {
282 return;
283 }
284 elSectionToggle.classList.toggle(`${lpClassName.elCollapse}`);
285 if ('function' === typeof callback) {
286 callback(elSectionToggle);
287 }
288 };
289
290 // Get data of form
291 const getDataOfForm = form => {
292 const dataSend = {};
293 const formData = new FormData(form);
294 for (const pair of formData.entries()) {
295 const key = pair[0];
296 const value = formData.getAll(key);
297 if (!dataSend.hasOwnProperty(key)) {
298 // Convert value array to string.
299 dataSend[key] = value.join(',');
300 }
301 }
302 return dataSend;
303 };
304
305 // Get field keys of form
306 const getFieldKeysOfForm = form => {
307 const keys = [];
308 const elements = form.elements;
309 for (let i = 0; i < elements.length; i++) {
310 const name = elements[i].name;
311 if (name && !keys.includes(name)) {
312 keys.push(name);
313 }
314 }
315 return keys;
316 };
317
318 // Merge data handle with data form.
319 const mergeDataWithDatForm = (elForm, dataHandle) => {
320 const dataForm = getDataOfForm(elForm);
321 const keys = getFieldKeysOfForm(elForm);
322 keys.forEach(key => {
323 if (!dataForm.hasOwnProperty(key)) {
324 delete dataHandle[key];
325 } else if (dataForm[key][0] === '') {
326 delete dataForm[key];
327 delete dataHandle[key];
328 }
329 });
330 dataHandle = {
331 ...dataHandle,
332 ...dataForm
333 };
334 return dataHandle;
335 };
336
337 /**
338 * Event trigger
339 * For each list of event handlers, listen event on document.
340 *
341 * eventName: 'click', 'change', ...
342 * eventHandlers = [ { selector: '.lp-button', callBack: function(){}, class: object } ]
343 *
344 * @param eventName
345 * @param eventHandlers
346 */
347 const eventHandlers = (eventName, eventHandlers) => {
348 document.addEventListener(eventName, e => {
349 const target = e.target;
350 let args = {
351 e,
352 target
353 };
354 eventHandlers.forEach(eventHandler => {
355 args = {
356 ...args,
357 ...eventHandler
358 };
359
360 //console.log( args );
361
362 // Check condition before call back
363 if (eventHandler.conditionBeforeCallBack) {
364 if (eventHandler.conditionBeforeCallBack(args) !== true) {
365 return;
366 }
367 }
368
369 // Special check for keydown event with checkIsEventEnter = true
370 if (eventName === 'keydown' && eventHandler.checkIsEventEnter) {
371 if (e.key !== 'Enter') {
372 return;
373 }
374 }
375 if (target.closest(eventHandler.selector)) {
376 if (eventHandler.class) {
377 // Call method of class, function callBack will understand exactly {this} is class object.
378 eventHandler.class[eventHandler.callBack](args);
379 } else {
380 // For send args is objected, {this} is eventHandler object, not class object.
381 eventHandler.callBack(args);
382 }
383 }
384 });
385 });
386 };
387
388 /**
389 * Debounce - delays function execution until after `wait` ms of inactivity.
390 *
391 * Each call resets the timer. Only the last call in a burst executes.
392 *
393 * USE CASES:
394 * - Search inputs, form validation, window resize
395 * - Multiple elements need independent timers
396 * - When you need to call with different arguments
397 *
398 * EXAMPLES:
399 * const debouncedSearch = debounce( (query) => fetchResults(query), 300 );
400 * searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value));
401 *
402 * const debouncedResize = debounce( recalculateLayout, 250 );
403 * window.addEventListener('resize', debouncedResize);
404 *
405 * ⚠️ Create ONCE outside event handlers, not inside.
406 *
407 * @param {Function} func - Function to debounce (can be anonymous)
408 * @param {number} wait - Milliseconds to wait (default: 500)
409 * @return {Function} Debounced wrapper function
410 * @since 4.3.7
411 * @version 1.0.0
412 */
413 const debounce = (func, wait = 500) => {
414 let timer;
415 return args => {
416 clearTimeout(timer);
417 timer = setTimeout(() => func(args), wait);
418 };
419 };
420
421 /**
422 * Initialize lp-toggle-enable components.
423 *
424 * Finds all `.lp-toggle-enable` elements and wires up toggle behavior.
425 * Reads initial state from `data-enabled` attribute ("true"/"false").
426 * Calls `data-on-toggle` callback (if provided via options) on state change.
427 *
428 * HTML structure:
429 * <label class="lp-toggle-enable" data-enabled="true">
430 * <input type="checkbox" class="lp-toggle-enable__input" />
431 * <span class="lp-toggle-enable__track"></span>
432 * </label>
433 *
434 * @param {string} selector CSS selector for toggle elements (default: '.lp-toggle-enable')
435 * @param {Function} onToggle Optional callback( el, isEnabled ) called on state change
436 * @since 4.4.5
437 * @version 1.0.0
438 */
439 window.lpToggleEnableInit = 0;
440 const toggleEnable = (onToggle = null) => {
441 if (window.lpToggleEnableInit) {
442 return;
443 }
444 window.lpToggleEnableInit = 1;
445 const selector = '.lp-toggle-enable';
446 const updateUI = (toggle, isEnabled) => {
447 toggle.classList.toggle('is-enabled', isEnabled);
448 const input = toggle.querySelector('.lp-toggle-enable__input');
449 if (input) {
450 input.checked = isEnabled;
451 input.value = isEnabled ? '1' : '0';
452 }
453 };
454
455 // Delegate click handling via eventHandlers.
456 eventHandlers('click', [{
457 selector,
458 callBack: args => {
459 const {
460 e,
461 target
462 } = args;
463 const toggle = target.closest(selector);
464 if (!toggle || toggle.classList.contains('is-disabled')) {
465 return;
466 }
467 e.preventDefault();
468 const isEnabled = !toggle.classList.contains('is-enabled');
469 updateUI(toggle, isEnabled);
470 if ('function' === typeof onToggle) {
471 onToggle(toggle, isEnabled);
472 }
473 }
474 }]);
475 };
476
477 /**
478 * Initialize custom fullscreen view buttons.
479 *
480 * Delegates clicks on `.lp-btn-full-screen-view` buttons to
481 * `lpToggleFullscreenView`. Reads the `data-target` attribute to find the
482 * target element. Falls back to the button's parent element when
483 * `data-target` is not provided.
484 *
485 * @since 4.4.5
486 * @version 1.0.0
487 */
488 window.lpFullScreenViewInit = 0;
489 const fullScreenView = () => {
490 if (window.lpFullScreenViewInit) {
491 return;
492 }
493 window.lpFullScreenViewInit = 1;
494 let lastScrollY = 0;
495 const lpToggleFullscreenView = (elTarget, elBtnFullScreen = null) => {
496 const isFullscreen = elTarget.classList.contains(lpClassName.elFullScreen);
497 if (isFullscreen) {
498 elTarget.classList.remove(lpClassName.elFullScreen);
499 document.documentElement.classList.remove('lp-full-screen-active');
500 window.scrollTo(0, lastScrollY);
501 } else {
502 lastScrollY = window.scrollY;
503 elTarget.classList.add(lpClassName.elFullScreen);
504 document.documentElement.classList.add('lp-full-screen-active');
505 }
506 if (!isFullscreen) {
507 if (!elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`)) {
508 const closeButton = document.createElement('button');
509 closeButton.type = 'button';
510 closeButton.className = lpClassName.elBtnFullScreenClose;
511 closeButton.setAttribute('aria-label', 'Close');
512 closeButton.innerHTML = lpData.i18n.closeButtonFullScreen || 'Close &times;';
513 closeButton.addEventListener('click', e => {
514 e.preventDefault();
515 lpToggleFullscreenView(elTarget);
516 });
517 elTarget.appendChild(closeButton);
518 }
519 } else {
520 const closeButton = elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`);
521 if (closeButton) {
522 closeButton.remove();
523 }
524 }
525 };
526 eventHandlers('click', [{
527 selector: lpClassName.elBtnFullScreen,
528 callBack: args => {
529 const {
530 e,
531 target
532 } = args;
533 const elBtnFullScreen = target.closest(lpClassName.elBtnFullScreen);
534 if (!elBtnFullScreen) {
535 console.log('No full screen button found');
536 return;
537 }
538 e.preventDefault();
539 let elTarget = null;
540 const targetSelector = elBtnFullScreen.dataset.targetFullscreen;
541 console.log(targetSelector);
542 if (targetSelector) {
543 elTarget = document.querySelector(targetSelector);
544 }
545 if (!elTarget) {
546 console.log('No target element found');
547 return;
548 }
549 lpToggleFullscreenView(elTarget, elBtnFullScreen);
550 }
551 }]);
552 };
553
554 /***/ },
555
556 /***/ "./assets/src/js/utils/cookies.js"
557 /*!****************************************!*\
558 !*** ./assets/src/js/utils/cookies.js ***!
559 \****************************************/
560 (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
561
562 __webpack_require__.r(__webpack_exports__);
563 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
564 /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
565 /* harmony export */ });
566 const Cookies = {
567 get: (name, def, global) => {
568 let ret;
569 if (global) {
570 ret = wpCookies.get(name);
571 } else {
572 let ck = wpCookies.get('LP');
573 if (ck) {
574 ck = JSON.parse(ck);
575 ret = name ? ck[name] : ck;
576 }
577 }
578 if (!ret && ret !== def) {
579 ret = def;
580 }
581 return ret;
582 },
583 set(name, value, expires, path, domain, secure) {
584 if (arguments.length > 2) {
585 wpCookies.set(name, value, expires, path, domain, secure);
586 } else if (arguments.length == 2) {
587 let ck = wpCookies.get('LP');
588 if (ck) {
589 ck = JSON.parse(ck);
590 } else {
591 ck = {};
592 }
593 ck[name] = value;
594 wpCookies.set('LP', JSON.stringify(ck), '', '/');
595 } else {
596 wpCookies.set('LP', JSON.stringify(name), '', '/');
597 }
598 },
599 remove(name) {
600 const allCookies = Cookies.get();
601 const reg = new RegExp(name, 'g');
602 const newCookies = {};
603 const useRegExp = name.match(/\*/);
604 for (const i in allCookies) {
605 if (useRegExp) {
606 if (!i.match(reg)) {
607 newCookies[i] = allCookies[i];
608 }
609 } else if (name != i) {
610 newCookies[i] = allCookies[i];
611 }
612 }
613 Cookies.set(newCookies);
614 }
615 };
616 /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Cookies);
617
618 /***/ }
619
620 /******/ });
621 /************************************************************************/
622 /******/ // The module cache
623 /******/ const __webpack_module_cache__ = {};
624 /******/
625 /******/ // The require function
626 /******/ function __webpack_require__(moduleId) {
627 /******/ // Check if module is in cache
628 /******/ const cachedModule = __webpack_module_cache__[moduleId];
629 /******/ if (cachedModule !== undefined) {
630 /******/ return cachedModule.exports;
631 /******/ }
632 /******/ // Create a new module (and put it into the cache)
633 /******/ const module = __webpack_module_cache__[moduleId] = {
634 /******/ // no module.id needed
635 /******/ // no module.loaded needed
636 /******/ exports: {}
637 /******/ };
638 /******/
639 /******/ // Execute the module function
640 /******/ if (!(moduleId in __webpack_modules__)) {
641 /******/ delete __webpack_module_cache__[moduleId];
642 /******/ const e = new Error("Cannot find module '" + moduleId + "'");
643 /******/ e.code = 'MODULE_NOT_FOUND';
644 /******/ throw e;
645 /******/ }
646 /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
647 /******/
648 /******/ // Return the exports of the module
649 /******/ return module.exports;
650 /******/ }
651 /******/
652 /************************************************************************/
653 /******/ /* webpack/runtime/define property getters */
654 /******/ (() => {
655 /******/ // define getter/value functions for harmony exports
656 /******/ __webpack_require__.d = (exports, definition) => {
657 /******/ if(Array.isArray(definition)) {
658 /******/ var i = 0;
659 /******/ while(i < definition.length) {
660 /******/ var key = definition[i++];
661 /******/ var binding = definition[i++];
662 /******/ if(!__webpack_require__.o(exports, key)) {
663 /******/ if(binding === 0) {
664 /******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
665 /******/ } else {
666 /******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
667 /******/ }
668 /******/ } else if(binding === 0) { i++; }
669 /******/ }
670 /******/ } else {
671 /******/ for(var key in definition) {
672 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
673 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
674 /******/ }
675 /******/ }
676 /******/ }
677 /******/ };
678 /******/ })();
679 /******/
680 /******/ /* webpack/runtime/hasOwnProperty shorthand */
681 /******/ (() => {
682 /******/ __webpack_require__.o = (obj, prop) => (Object.hasOwn(obj, prop))
683 /******/ })();
684 /******/
685 /******/ /* webpack/runtime/make namespace object */
686 /******/ (() => {
687 /******/ // define __esModule on exports
688 /******/ __webpack_require__.r = (exports) => {
689 /******/ if(Symbol.toStringTag) {
690 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
691 /******/ }
692 /******/ Object.defineProperty(exports, '__esModule', { value: true });
693 /******/ };
694 /******/ })();
695 /******/
696 /************************************************************************/
697 let __webpack_exports__ = {};
698 // This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
699 (() => {
700 /*!*******************************************!*\
701 !*** ./assets/src/js/frontend/courses.js ***!
702 \*******************************************/
703 __webpack_require__.r(__webpack_exports__);
704 /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../api */ "./assets/src/js/api.js");
705 /* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils */ "./assets/src/js/utils.js");
706 /* harmony import */ var _utils_cookies__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils/cookies */ "./assets/src/js/utils/cookies.js");
707 /**
708 * @deprecated 4.2.5.8
709 * But still support for theme has html old, override.
710 * Todo: if want remove file, need to check theme override file archive, can via remove hook override file.
711 */
712
713
714
715
716 const elListCoursesIdNewDefault = '.lp-list-courses-default';
717 if ('undefined' === typeof lpData || 'undefined' === typeof lpSettingCourses) {
718 console.log('lpData || lpSettingCourses is undefined');
719 }
720
721 // Call API load courses.
722 // When LP v4.2.3.3 release a long time, we will remove this function on theme Eduma.
723 // assets/js/thim-course-filter-v2.js
724 window.lpArchiveRequestCourse = args => {
725 window.lpCourseList.updateEventTypeBeforeFetch('filter');
726 window.lpCourseList.triggerFetchAPI(args);
727 };
728
729 // Events
730 document.addEventListener('change', function (e) {
731 const target = e.target;
732 if (window.lpCourseList.checkIsNewListCourses()) {
733 return;
734 }
735 window.lpCourseList.onChangeSortBy(e, target);
736 window.lpCourseList.onChangeTypeLayout(e, target);
737 });
738 document.addEventListener('click', function (e) {
739 const target = e.target;
740 if (window.lpCourseList.checkIsNewListCourses()) {
741 return;
742 }
743 window.lpCourseList.clickLoadMore(e, target);
744 window.lpCourseList.clickNumberPage(e, target);
745 });
746 document.addEventListener('scroll', function (e) {
747 const target = e.target;
748 if (window.lpCourseList.checkIsNewListCourses()) {
749 return;
750 }
751 window.lpCourseList.scrollInfinite(e, target);
752 });
753 document.addEventListener('keyup', function (e) {
754 const target = e.target;
755 if (window.lpCourseList.checkIsNewListCourses()) {
756 return;
757 }
758 window.lpCourseList.searchCourse(e, target);
759 });
760 document.addEventListener('submit', function (e) {
761 const target = e.target;
762 if (window.lpCourseList.checkIsNewListCourses()) {
763 return;
764 }
765 window.lpCourseList.searchCourse(e, target);
766 });
767 window.lpCourseList = (() => {
768 const classArchiveCourse = 'lp-archive-courses';
769 const classListCourse = 'learn-press-courses';
770 const classPaginationCourse = 'learn-press-pagination';
771 const classSkeletonArchiveCourse = 'lp-archive-course-skeleton';
772 const classCoursesPageResult = 'courses-page-result';
773 const lpArchiveLoadAjax = parseInt(lpSettingCourses.lpArchiveLoadAjax || 0);
774 const lpArchiveNoLoadAjaxFirst = parseInt(lpSettingCourses.lpArchiveNoLoadAjaxFirst) === 1;
775 const lpArchiveSkeletonParam = lpData.urlParams || [];
776 const currentUrl = (0,_utils__WEBPACK_IMPORTED_MODULE_1__.lpGetCurrentURLNoParam)();
777 let filterCourses = {};
778 const typePagination = lpSettingCourses.lpArchivePaginationType || 'number';
779 let typeEventBeforeFetch;
780 let timeOutSearch;
781 let isLoadingInfinite = false;
782 const fetchAPI = (args, callBack = {}) => {
783 //console.log( 'Fetch API Courses' );
784 const url = (0,_utils__WEBPACK_IMPORTED_MODULE_1__.lpAddQueryArgs)(_api__WEBPACK_IMPORTED_MODULE_0__["default"].frontend.apiCourses, args);
785 let paramsFetch = {};
786 if (0 !== parseInt(lpData.user_id)) {
787 paramsFetch = {
788 headers: {
789 'X-WP-Nonce': lpData.nonce
790 }
791 };
792 }
793 ;(0,_utils__WEBPACK_IMPORTED_MODULE_1__.lpFetchAPI)(url, paramsFetch, callBack);
794 };
795 return {
796 init: () => {
797 const urlParams = {};
798 const urlQueryString = window.location.search;
799 const urlSearchParams = new URLSearchParams(urlQueryString);
800 for (const [key, val] of urlSearchParams.entries()) {
801 urlParams[key] = val;
802 }
803 filterCourses = {
804 ...lpArchiveSkeletonParam,
805 ...urlParams
806 };
807 filterCourses.paged = parseInt(filterCourses.paged || 1);
808 if (isNaN(filterCourses.paged)) {
809 filterCourses.paged = 1;
810 }
811 if (lpArchiveNoLoadAjaxFirst && typePagination !== 'number') {
812 filterCourses.paged = 1;
813 }
814 window.localStorage.setItem('lp_filter_courses', JSON.stringify(filterCourses));
815 },
816 updateEventTypeBeforeFetch: type => {
817 typeEventBeforeFetch = type;
818 },
819 onChangeSortBy: (e, target) => {
820 if (!target.classList.contains('courses-order-by')) {
821 return;
822 }
823 e.preventDefault();
824 const filterCourses = JSON.parse(window.localStorage.getItem('lp_filter_courses')) || {};
825 filterCourses.order_by = target.value || '';
826 if ('undefined' !== typeof lpSettingCourses && lpData.is_course_archive && lpSettingCourses.lpArchiveLoadAjax) {
827 window.lpCourseList.triggerFetchAPI(filterCourses);
828 } else {
829 window.location.href = (0,_utils__WEBPACK_IMPORTED_MODULE_1__.lpAddQueryArgs)(currentUrl, filterCourses);
830 }
831 },
832 onChangeTypeLayout: (e, target) => {
833 if ('lp-switch-layout-btn' !== target.getAttribute('name')) {
834 return;
835 }
836 const elArchive = target.closest(`.${classArchiveCourse}`);
837 if (!elArchive) {
838 return;
839 }
840 const elListCourse = elArchive.querySelector(`.${classListCourse}`);
841 if (!elListCourse) {
842 return;
843 }
844 e.preventDefault();
845 const layout = target.value;
846 if (layout) {
847 elListCourse.dataset.layout = layout;
848 _utils_cookies__WEBPACK_IMPORTED_MODULE_2__["default"].set('courses-layout', layout);
849 }
850 },
851 clickNumberPage: (e, target) => {
852 if (!lpArchiveLoadAjax || parseInt(lpSettingCourses.noLoadCoursesJs)) {
853 return;
854 }
855 if (target.classList.contains('page-numbers')) {
856 const parentArchive = target.closest(`.${classArchiveCourse}`);
857 if (!parentArchive) {
858 return;
859 }
860 e.preventDefault();
861 const pageCurrent = filterCourses.paged;
862 if (target.classList.contains('prev')) {
863 filterCourses.paged = pageCurrent - 1;
864 } else if (target.classList.contains('next')) {
865 filterCourses.paged = pageCurrent + 1;
866 } else {
867 filterCourses.paged = parseInt(target.textContent);
868 }
869 typeEventBeforeFetch = 'number';
870 window.lpCourseList.triggerFetchAPI(filterCourses);
871 return;
872 }
873 const parent = target.closest('.page-numbers');
874 if (parent) {
875 e.preventDefault();
876 parent.click();
877 }
878 },
879 clickLoadMore: (e, target) => {
880 if (!target.classList.contains('courses-btn-load-more')) {
881 return;
882 }
883 const elArchive = target.closest(`.${classArchiveCourse}`);
884 if (!elArchive) {
885 return;
886 }
887 const elListCourse = elArchive.querySelector(`.${classListCourse}`);
888 if (!elListCourse) {
889 return;
890 }
891 e.preventDefault();
892 ++filterCourses.paged;
893 typeEventBeforeFetch = 'load-more';
894 window.lpCourseList.triggerFetchAPI(filterCourses);
895 },
896 scrollInfinite: (e, target) => {
897 const elArchive = document.querySelector(`.${classArchiveCourse}`);
898 if (!elArchive) {
899 return;
900 }
901 const elInfinite = elArchive.querySelector('.courses-load-infinite');
902 if (!elInfinite) {
903 return;
904 }
905
906 // Create an IntersectionObserver object.
907 const observer = new IntersectionObserver(function (entries) {
908 for (const entry of entries) {
909 // If the entry is intersecting, load the image.
910 if (entry.isIntersecting) {
911 if (isLoadingInfinite) {
912 return;
913 }
914 ++filterCourses.paged;
915 typeEventBeforeFetch = 'infinite';
916 window.lpCourseList.triggerFetchAPI(filterCourses);
917
918 //observer.unobserve( entry.target );
919 }
920 }
921 });
922 observer.observe(elInfinite);
923 },
924 triggerFetchAPI: args => {
925 // For case, click on pagination, filter.
926 const elArchive = document.querySelector(`.${classArchiveCourse}`);
927 if (!elArchive) {
928 return;
929 }
930 const elListCourse = elArchive.querySelector(`.${classListCourse}`);
931 if (!elListCourse) {
932 return;
933 }
934 filterCourses = args;
935 let callBack;
936 switch (typeEventBeforeFetch) {
937 case 'load-more':
938 callBack = window.lpCourseList.callBackPaginationTypeLoadMore(elArchive, elListCourse);
939 break;
940 case 'infinite':
941 callBack = window.lpCourseList.callBackPaginationTypeInfinite(elArchive, elListCourse);
942 break;
943 case 'custom':
944 callBack = args.customCallBack || false;
945 break;
946 case 'filter':
947 default:
948 // number
949 // Change url by params filter courses
950 //callBack = window.lpCourseList.callBackPaginationTypeNumber( elListCourse );
951 callBack = window.lpCourseList.callBackFilter(args, elArchive, elListCourse);
952 break;
953 }
954 if (!callBack) {
955 return;
956 }
957
958 //console.log( 'Args', args );
959
960 fetchAPI(args, callBack);
961 },
962 callBackFilter: (args, elArchive, elListCourse) => {
963 if (!elListCourse) {
964 return;
965 }
966 const skeleton = elListCourse.querySelector(`.${classSkeletonArchiveCourse}`);
967 return {
968 before: () => {
969 window.history.pushState('', '', (0,_utils__WEBPACK_IMPORTED_MODULE_1__.lpAddQueryArgs)(currentUrl, args));
970 window.localStorage.setItem('lp_filter_courses', JSON.stringify(args));
971 if (skeleton) {
972 skeleton.style.display = 'block';
973 }
974 },
975 success: res => {
976 // Remove all items before insert new items.
977 const elLis = elListCourse.querySelectorAll(`:not(.${classSkeletonArchiveCourse})`);
978 elLis.forEach(elLi => {
979 const parent = elLi.closest(`.${classSkeletonArchiveCourse}`);
980 if (parent) {
981 return;
982 }
983 elLi.remove();
984 });
985
986 // Insert new items.
987 elListCourse.insertAdjacentHTML('afterbegin', res.data.content || '');
988
989 // Check if Pagination exists will remove.
990 const elPagination = document.querySelector(`.${classPaginationCourse}`);
991 if (elPagination) {
992 elPagination.remove();
993 }
994
995 // Insert Pagination.
996 const pagination = res.data.pagination || '';
997 elListCourse.insertAdjacentHTML('afterend', pagination);
998
999 // Set showing results page.
1000 const elCoursesPageResult = document.querySelector(`.${classCoursesPageResult}`);
1001 if (elCoursesPageResult) {
1002 elCoursesPageResult.innerHTML = res.data.from_to || '';
1003 }
1004 },
1005 error: error => {
1006 elListCourse.innerHTML += `<div class="lp-ajax-message error" style="display:block">${error.message || 'Error'}</div>`;
1007 },
1008 completed: () => {
1009 if (skeleton) {
1010 skeleton.style.display = 'none';
1011 }
1012 // Scroll to archive element
1013 const optionScroll = {
1014 behavior: 'smooth'
1015 };
1016 elListCourse.closest(`.${classArchiveCourse}`).scrollIntoView(optionScroll);
1017 }
1018 };
1019 },
1020 /*callBackPaginationTypeNumber: ( elListCourse ) => {
1021 if ( ! elListCourse ) {
1022 return;
1023 }
1024 const skeleton = elListCourse.querySelector( `.${ classSkeletonArchiveCourse }` );
1025 return {
1026 before: () => {
1027 const urlPush = lpAddQueryArgs( currentUrl, args );
1028 window.history.pushState( '', '', urlPush );
1029 // Save filter courses to Storage
1030 window.localStorage.setItem( 'lp_filter_courses', JSON.stringify( args ) );
1031 if ( skeleton ) {
1032 skeleton.style.display = 'block';
1033 }
1034 },
1035 success: ( res ) => {
1036 // Remove all items before insert new items.
1037 const elLis = elListCourse.querySelectorAll( `:not(.${ classSkeletonArchiveCourse })` );
1038 elLis.forEach( ( elLi ) => {
1039 const parent = elLi.closest( `.${ classSkeletonArchiveCourse }` );
1040 if ( parent ) {
1041 return;
1042 }
1043 elLi.remove();
1044 } );
1045 // Insert new items.
1046 elListCourse.insertAdjacentHTML( 'afterbegin', res.data.content || '' );
1047 // Check if Pagination exists will remove.
1048 const elPagination = document.querySelector( `.${ classPaginationCourse }` );
1049 if ( elPagination ) {
1050 elPagination.remove();
1051 }
1052 // Insert Pagination.
1053 const pagination = res.data.pagination || '';
1054 elListCourse.insertAdjacentHTML( 'afterend', pagination );
1055 },
1056 error: ( error ) => {
1057 elListCourse.innerHTML += `<div class="lp-ajax-message error" style="display:block">${ error.message || 'Error' }</div>`;
1058 },
1059 completed: () => {
1060 if ( skeleton ) {
1061 skeleton.style.display = 'none';
1062 }
1063 // Scroll to archive element
1064 const optionScroll = { behavior: 'smooth' };
1065 elListCourse.closest( '.lp-archive-courses' ).scrollIntoView( optionScroll );
1066 },
1067 };
1068 },*/
1069 callBackPaginationTypeLoadMore: (elArchive, elListCourse) => {
1070 //console.log( 'callBackPaginationTypeLoadMore' );
1071 if (!elListCourse || !elArchive) {
1072 return false;
1073 }
1074 const btnLoadMore = elArchive.querySelector('.courses-btn-load-more');
1075 let elLoading;
1076 if (btnLoadMore) {
1077 elLoading = btnLoadMore.querySelector('.lp-loading-circle');
1078 }
1079 //const skeleton = document.querySelector( `.${ classSkeletonArchiveCourse }` );
1080
1081 return {
1082 before: () => {
1083 if (btnLoadMore) {
1084 elLoading.classList.remove('hide');
1085 btnLoadMore.setAttribute('disabled', 'disabled');
1086 }
1087
1088 /*if ( skeleton ) {
1089 skeleton.style.display = 'block';
1090 }*/
1091 },
1092 success: res => {
1093 elListCourse.insertAdjacentHTML('beforeend', res.data.content || '');
1094 elListCourse.insertAdjacentHTML('afterend', res.data.pagination || '');
1095
1096 // Set showing results page.
1097 const elCoursesPageResult = document.querySelector(`.${classCoursesPageResult}`);
1098 if (elCoursesPageResult) {
1099 elCoursesPageResult.innerHTML = res.data.from_to || '';
1100 }
1101 },
1102 error: error => {
1103 elListCourse.innerHTML += `<div class="lp-ajax-message error" style="display:block">${error.message || 'Error'}</div>`;
1104 },
1105 completed: () => {
1106 if (btnLoadMore) {
1107 elLoading.classList.add('hide');
1108 btnLoadMore.remove();
1109 }
1110
1111 /*if ( skeleton ) {
1112 skeleton.style.display = 'none';
1113 }*/
1114 }
1115 };
1116 },
1117 callBackPaginationTypeInfinite: (elArchive, elListCourse) => {
1118 //console.log( 'callBackPaginationTypeInfinite' );
1119 if (!elListCourse || !elListCourse) {
1120 return;
1121 }
1122 const elInfinite = elArchive.querySelector('.courses-load-infinite');
1123 if (!elInfinite) {
1124 return;
1125 }
1126 const loading = elInfinite.querySelector('.lp-loading-circle');
1127 isLoadingInfinite = true;
1128 elInfinite.classList.remove('courses-load-infinite');
1129 return {
1130 before: () => {
1131 loading.classList.remove('hide');
1132 },
1133 success: res => {
1134 elListCourse.insertAdjacentHTML('beforeend', res.data.content || '');
1135 if (res.data.pagination) {
1136 elListCourse.insertAdjacentHTML('afterend', res.data.pagination || '');
1137 }
1138
1139 // Set showing results page.
1140 const elCoursesPageResult = document.querySelector(`.${classCoursesPageResult}`);
1141 if (elCoursesPageResult) {
1142 elCoursesPageResult.innerHTML = res.data.from_to || '';
1143 }
1144 },
1145 error: error => {
1146 elListCourse.innerHTML += `<div class="lp-ajax-message error" style="display:block">${error.message || 'Error'}</div>`;
1147 },
1148 completed: () => {
1149 elInfinite.remove();
1150 isLoadingInfinite = false;
1151 }
1152 };
1153 },
1154 searchCourse: (e, target) => {
1155 if ('c_search' === target.name) {
1156 e.preventDefault();
1157 const parentFormSearch = target.closest('form.search-courses');
1158 if (!parentFormSearch) {
1159 return;
1160 }
1161 const btnSearch = parentFormSearch.querySelector('button[type="submit"]');
1162 btnSearch.click();
1163 return;
1164 }
1165 if (!target.classList.contains('search-courses')) {
1166 return;
1167 }
1168 const formSearchCourses = target;
1169 e.preventDefault();
1170 const elArchive = formSearchCourses.closest(`.${classArchiveCourse}`);
1171 if (!elArchive) {
1172 return;
1173 }
1174 const elListCourse = elArchive.querySelector(`.${classListCourse}`);
1175 if (!elListCourse) {
1176 return;
1177 }
1178 const elInputSearch = formSearchCourses.querySelector('input[name=c_search]');
1179 const keyword = elInputSearch.value;
1180 if (!keyword || keyword && keyword.length > 2) {
1181 if (undefined !== timeOutSearch) {
1182 clearTimeout(timeOutSearch);
1183 }
1184 timeOutSearch = setTimeout(function () {
1185 typeEventBeforeFetch = 'filter';
1186 filterCourses.c_search = keyword;
1187 filterCourses.paged = 1;
1188 window.lpCourseList.triggerFetchAPI(filterCourses);
1189 }, 800);
1190 }
1191 },
1192 ajaxEnableLoadPage: () => {
1193 // For case enable AJAX when load page.
1194 let countTime = 0;
1195 if (!lpArchiveNoLoadAjaxFirst) {
1196 let detectedElArchive;
1197 const callBack = {
1198 success: res => {
1199 detectedElArchive = setInterval(function () {
1200 const skeleton = document.querySelector(`.${classSkeletonArchiveCourse}`);
1201 const elArchive = document.querySelector(`.${classArchiveCourse}`);
1202 let elListCourse;
1203 if (elArchive) {
1204 elListCourse = elArchive.querySelector(`.${classListCourse}`);
1205 }
1206 ++countTime;
1207 if (countTime > 5000) {
1208 clearInterval(detectedElArchive);
1209 }
1210 if (elListCourse && skeleton) {
1211 clearInterval(detectedElArchive);
1212 elListCourse.insertAdjacentHTML('afterbegin', res.data.content || '');
1213 skeleton.style.display = 'none';
1214 const pagination = res.data.pagination || '';
1215 elListCourse.insertAdjacentHTML('afterend', pagination);
1216
1217 // Set showing results page.
1218 const elCoursesPageResult = document.querySelector(`.${classCoursesPageResult}`);
1219 if (elCoursesPageResult) {
1220 elCoursesPageResult.innerHTML = res.data.from_to || '';
1221 }
1222 }
1223 }, 1);
1224 }
1225 };
1226 if ('number' !== typePagination) {
1227 filterCourses.paged = 1;
1228 }
1229 fetchAPI(filterCourses, callBack);
1230 }
1231 },
1232 getFilterParams: () => {
1233 return filterCourses;
1234 },
1235 // Check has exists new list courses.
1236 checkIsNewListCourses: () => {
1237 const elListCoursesNew = document.querySelector(elListCoursesIdNewDefault);
1238 return !!elListCoursesNew;
1239 }
1240 };
1241 })();
1242 document.addEventListener('DOMContentLoaded', function () {
1243 if (window.lpCourseList.checkIsNewListCourses()) {
1244 return;
1245 }
1246 window.lpCourseList.init();
1247 window.lpCourseList.ajaxEnableLoadPage();
1248 });
1249 })();
1250
1251 /******/ })()
1252 ;
1253 //# sourceMappingURL=courses.js.map