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/single-course.js +275 -132 4.3.9 → 4.4.9 View file →
@@ -1,4 +1,4 @@
1 1 /******/ (() => { // webpackBootstrap
2 2 /******/ var __webpack_modules__ = ({
3 3
4 4 /***/ "./assets/src/apps/js/frontend/material.js"
@@ -161,10 +161,10 @@
161 161 !*** ./assets/src/apps/js/frontend/single-course/store/index.js ***!
162 162 \******************************************************************/
163 163 () {
164 164
165 -/**
166 - * Created by tu on 9/19/19.
165 +/**
166 + * Created by tu on 9/19/19.
167 167 */
168 168
169 169 /***/ },
170 170
@@ -292,38 +292,35 @@
292 292 }
293 293 // End editor by tungnx
294 294
295 295 // Code for old curriculum
296 - /*const $curriculum = $( '#learn-press-course-curriculum' );
297 - $curriculum.find( '.section-desc' ).each( ( i, el ) => {
298 - const a = $( '<span class="show-desc"></span>' ).on( 'click', () => {
299 - b.toggleClass( 'c' );
300 - } );
301 - const b = $( el ).siblings( '.section-title' ).append( a );
296 + /*const $curriculum = $( '#learn-press-course-curriculum' );
297 + $curriculum.find( '.section-desc' ).each( ( i, el ) => {
298 + const a = $( '<span class="show-desc"></span>' ).on( 'click', () => {
299 + b.toggleClass( 'c' );
300 + } );
301 + const b = $( el ).siblings( '.section-title' ).append( a );
302 302 } );*/
303 303
304 304 // Code for old curriculum
305 - /*$( '.section' ).each( function() {
306 - const $section = $( this ),
307 - $toggle = $section.find( '.section-left' );
308 -
309 - $toggle.on( 'click', function() {
310 - const isClose = $section.toggleClass( 'closed' ).hasClass( 'closed' );
311 - const sections = LP.Cookies.get( 'closed-section-' + lpGlobalSettings.post_id ) || [];
312 - const sectionId = parseInt( $section.data( 'section-id' ) );
313 - const at = sections.findIndex( ( id ) => {
314 - return id == sectionId;
315 - } );
316 -
317 - if ( isClose ) {
318 - sections.push( parseInt( $section.data( 'section-id' ) ) );
319 - } else {
320 - sections.splice( at, 1 );
321 - }
322 -
323 - LP.Cookies.remove( 'closed-section-(.*)' );
324 - LP.Cookies.set( 'closed-section-' + lpGlobalSettings.post_id, [ ...new Set( sections ) ] );
325 - } );
305 + /*$( '.section' ).each( function() {
306 + const $section = $( this ),
307 + $toggle = $section.find( '.section-left' );
308 + $toggle.on( 'click', function() {
309 + const isClose = $section.toggleClass( 'closed' ).hasClass( 'closed' );
310 + const sections = LP.Cookies.get( 'closed-section-' + lpGlobalSettings.post_id ) || [];
311 + const sectionId = parseInt( $section.data( 'section-id' ) );
312 + const at = sections.findIndex( ( id ) => {
313 + return id == sectionId;
314 + } );
315 + if ( isClose ) {
316 + sections.push( parseInt( $section.data( 'section-id' ) ) );
317 + } else {
318 + sections.splice( at, 1 );
319 + }
320 + LP.Cookies.remove( 'closed-section-(.*)' );
321 + LP.Cookies.set( 'closed-section-' + lpGlobalSettings.post_id, [ ...new Set( sections ) ] );
322 + } );
326 323 } );*/
327 324
328 325 document.addEventListener('click', e => {
329 326 if (e.target.id === 'sidebar-toggle') {
@@ -945,8 +942,9 @@
945 942 __webpack_require__.r(__webpack_exports__);
946 943 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
947 944 /* harmony export */ debounce: () => (/* binding */ debounce),
948 945 /* harmony export */ eventHandlers: () => (/* binding */ eventHandlers),
946 +/* harmony export */ fullScreenView: () => (/* binding */ fullScreenView),
949 947 /* harmony export */ getDataOfForm: () => (/* binding */ getDataOfForm),
950 948 /* harmony export */ getFieldKeysOfForm: () => (/* binding */ getFieldKeysOfForm),
951 949 /* harmony export */ listenElementCreated: () => (/* binding */ listenElementCreated),
952 950 /* harmony export */ listenElementViewed: () => (/* binding */ listenElementViewed),
@@ -958,18 +956,19 @@
958 956 /* harmony export */ lpOnElementReady: () => (/* binding */ lpOnElementReady),
959 957 /* harmony export */ lpSetLoadingEl: () => (/* binding */ lpSetLoadingEl),
960 958 /* harmony export */ lpShowHideEl: () => (/* binding */ lpShowHideEl),
961 959 /* harmony export */ mergeDataWithDatForm: () => (/* binding */ mergeDataWithDatForm),
962 -/* harmony export */ toggleCollapse: () => (/* binding */ toggleCollapse)
960 +/* harmony export */ toggleCollapse: () => (/* binding */ toggleCollapse),
961 +/* harmony export */ toggleEnable: () => (/* binding */ toggleEnable)
963 962 /* harmony export */ });
964 -/**
965 - * Utils functions
966 - *
967 - * @param url
968 - * @param data
969 - * @param functions
970 - * @since 4.2.5.1
971 - * @version 1.0.6
963 +/**
964 + * Utils functions
965 + *
966 + * @param url
967 + * @param data
968 + * @param functions
969 + * @since 4.2.5.1
970 + * @version 1.0.7
972 971 */
973 972 const lpClassName = {
974 973 hidden: 'lp-hidden',
975 974 loading: 'loading',
@@ -974,9 +973,12 @@
974 973 hidden: 'lp-hidden',
975 974 loading: 'loading',
976 975 elCollapse: 'lp-collapse',
977 976 elSectionToggle: '.lp-section-toggle',
978 - elTriggerToggle: '.lp-trigger-toggle'
977 + elTriggerToggle: '.lp-trigger-toggle',
978 + elBtnFullScreen: '.lp-btn-full-screen-view',
979 + elFullScreen: 'lp-full-screen-view',
980 + elBtnFullScreenClose: 'lp-full-screen-view__close'
979 981 };
980 982 const lpFetchAPI = (url, data = {}, functions = {}) => {
981 983 if ('function' === typeof functions.before) {
982 984 functions.before();
@@ -998,12 +1000,12 @@
998 1000 }
999 1001 });
1000 1002 };
1001 1003
1002 -/**
1003 - * Get current URL without params.
1004 - *
1005 - * @since 4.2.5.1
1004 +/**
1005 + * Get current URL without params.
1006 + *
1007 + * @since 4.2.5.1
1006 1008 */
1007 1009 const lpGetCurrentURLNoParam = () => {
1008 1010 let currentUrl = window.location.href;
1009 1011 const hasParams = currentUrl.includes('?');
@@ -1019,14 +1021,14 @@
1019 1021 });
1020 1022 return url;
1021 1023 };
1022 1024
1023 -/**
1024 - * Listen element viewed.
1025 - *
1026 - * @param el
1027 - * @param callback
1028 - * @since 4.2.5.8
1025 +/**
1026 + * Listen element viewed.
1027 + *
1028 + * @param el
1029 + * @param callback
1030 + * @since 4.2.5.8
1029 1031 */
1030 1032 const listenElementViewed = (el, callback) => {
1031 1033 const observerSeeItem = new IntersectionObserver(function (entries) {
1032 1034 for (const entry of entries) {
@@ -1037,13 +1039,13 @@
1037 1039 });
1038 1040 observerSeeItem.observe(el);
1039 1041 };
1040 1042
1041 -/**
1042 - * Listen element created.
1043 - *
1044 - * @param callback
1045 - * @since 4.2.5.8
1043 +/**
1044 + * Listen element created.
1045 + *
1046 + * @param callback
1047 + * @since 4.2.5.8
1046 1048 */
1047 1049 const listenElementCreated = callback => {
1048 1050 const observerCreateItem = new MutationObserver(function (mutations) {
1049 1051 mutations.forEach(function (mutation) {
@@ -1062,14 +1064,14 @@
1062 1064 });
1063 1065 // End.
1064 1066 };
1065 1067
1066 -/**
1067 - * Listen element created.
1068 - *
1069 - * @param selector
1070 - * @param callback
1071 - * @since 4.2.7.1
1068 +/**
1069 + * Listen element created.
1070 + *
1071 + * @param selector
1072 + * @param callback
1073 + * @since 4.2.7.1
1072 1074 */
1073 1075 const lpOnElementReady = (selector, callback) => {
1074 1076 const element = document.querySelector(selector);
1075 1077 if (element) {
@@ -1210,17 +1212,17 @@
1210 1212 };
1211 1213 return dataHandle;
1212 1214 };
1213 1215
1214 -/**
1215 - * Event trigger
1216 - * For each list of event handlers, listen event on document.
1217 - *
1218 - * eventName: 'click', 'change', ...
1219 - * eventHandlers = [ { selector: '.lp-button', callBack: function(){}, class: object } ]
1220 - *
1221 - * @param eventName
1222 - * @param eventHandlers
1216 +/**
1217 + * Event trigger
1218 + * For each list of event handlers, listen event on document.
1219 + *
1220 + * eventName: 'click', 'change', ...
1221 + * eventHandlers = [ { selector: '.lp-button', callBack: function(){}, class: object } ]
1222 + *
1223 + * @param eventName
1224 + * @param eventHandlers
1223 1225 */
1224 1226 const eventHandlers = (eventName, eventHandlers) => {
1225 1227 document.addEventListener(eventName, e => {
1226 1228 const target = e.target;
@@ -1261,32 +1263,32 @@
1261 1263 });
1262 1264 });
1263 1265 };
1264 1266
1265 -/**
1266 - * Debounce - delays function execution until after `wait` ms of inactivity.
1267 - *
1268 - * Each call resets the timer. Only the last call in a burst executes.
1269 - *
1270 - * USE CASES:
1271 - * - Search inputs, form validation, window resize
1272 - * - Multiple elements need independent timers
1273 - * - When you need to call with different arguments
1274 - *
1275 - * EXAMPLES:
1276 - * const debouncedSearch = debounce( (query) => fetchResults(query), 300 );
1277 - * searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value));
1278 - *
1279 - * const debouncedResize = debounce( recalculateLayout, 250 );
1280 - * window.addEventListener('resize', debouncedResize);
1281 - *
1282 - * ⚠️ Create ONCE outside event handlers, not inside.
1283 - *
1284 - * @param {Function} func - Function to debounce (can be anonymous)
1285 - * @param {number} wait - Milliseconds to wait (default: 500)
1286 - * @return {Function} Debounced wrapper function
1287 - * @since 4.3.7
1288 - * @version 1.0.0
1267 +/**
1268 + * Debounce - delays function execution until after `wait` ms of inactivity.
1269 + *
1270 + * Each call resets the timer. Only the last call in a burst executes.
1271 + *
1272 + * USE CASES:
1273 + * - Search inputs, form validation, window resize
1274 + * - Multiple elements need independent timers
1275 + * - When you need to call with different arguments
1276 + *
1277 + * EXAMPLES:
1278 + * const debouncedSearch = debounce( (query) => fetchResults(query), 300 );
1279 + * searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value));
1280 + *
1281 + * const debouncedResize = debounce( recalculateLayout, 250 );
1282 + * window.addEventListener('resize', debouncedResize);
1283 + *
1284 + * ⚠️ Create ONCE outside event handlers, not inside.
1285 + *
1286 + * @param {Function} func - Function to debounce (can be anonymous)
1287 + * @param {number} wait - Milliseconds to wait (default: 500)
1288 + * @return {Function} Debounced wrapper function
1289 + * @since 4.3.7
1290 + * @version 1.0.0
1289 1291 */
1290 1292 const debounce = (func, wait = 500) => {
1291 1293 let timer;
1292 1294 return args => {
@@ -1294,8 +1296,141 @@
1294 1296 timer = setTimeout(() => func(args), wait);
1295 1297 };
1296 1298 };
1297 1299
1300 +/**
1301 + * Initialize lp-toggle-enable components.
1302 + *
1303 + * Finds all `.lp-toggle-enable` elements and wires up toggle behavior.
1304 + * Reads initial state from `data-enabled` attribute ("true"/"false").
1305 + * Calls `data-on-toggle` callback (if provided via options) on state change.
1306 + *
1307 + * HTML structure:
1308 + * <label class="lp-toggle-enable" data-enabled="true">
1309 + * <input type="checkbox" class="lp-toggle-enable__input" />
1310 + * <span class="lp-toggle-enable__track"></span>
1311 + * </label>
1312 + *
1313 + * @param {string} selector CSS selector for toggle elements (default: '.lp-toggle-enable')
1314 + * @param {Function} onToggle Optional callback( el, isEnabled ) called on state change
1315 + * @since 4.4.5
1316 + * @version 1.0.0
1317 + */
1318 +window.lpToggleEnableInit = 0;
1319 +const toggleEnable = (onToggle = null) => {
1320 + if (window.lpToggleEnableInit) {
1321 + return;
1322 + }
1323 + window.lpToggleEnableInit = 1;
1324 + const selector = '.lp-toggle-enable';
1325 + const updateUI = (toggle, isEnabled) => {
1326 + toggle.classList.toggle('is-enabled', isEnabled);
1327 + const input = toggle.querySelector('.lp-toggle-enable__input');
1328 + if (input) {
1329 + input.checked = isEnabled;
1330 + input.value = isEnabled ? '1' : '0';
1331 + }
1332 + };
1333 +
1334 + // Delegate click handling via eventHandlers.
1335 + eventHandlers('click', [{
1336 + selector,
1337 + callBack: args => {
1338 + const {
1339 + e,
1340 + target
1341 + } = args;
1342 + const toggle = target.closest(selector);
1343 + if (!toggle || toggle.classList.contains('is-disabled')) {
1344 + return;
1345 + }
1346 + e.preventDefault();
1347 + const isEnabled = !toggle.classList.contains('is-enabled');
1348 + updateUI(toggle, isEnabled);
1349 + if ('function' === typeof onToggle) {
1350 + onToggle(toggle, isEnabled);
1351 + }
1352 + }
1353 + }]);
1354 +};
1355 +
1356 +/**
1357 + * Initialize custom fullscreen view buttons.
1358 + *
1359 + * Delegates clicks on `.lp-btn-full-screen-view` buttons to
1360 + * `lpToggleFullscreenView`. Reads the `data-target` attribute to find the
1361 + * target element. Falls back to the button's parent element when
1362 + * `data-target` is not provided.
1363 + *
1364 + * @since 4.4.5
1365 + * @version 1.0.0
1366 + */
1367 +window.lpFullScreenViewInit = 0;
1368 +const fullScreenView = () => {
1369 + if (window.lpFullScreenViewInit) {
1370 + return;
1371 + }
1372 + window.lpFullScreenViewInit = 1;
1373 + let lastScrollY = 0;
1374 + const lpToggleFullscreenView = (elTarget, elBtnFullScreen = null) => {
1375 + const isFullscreen = elTarget.classList.contains(lpClassName.elFullScreen);
1376 + if (isFullscreen) {
1377 + elTarget.classList.remove(lpClassName.elFullScreen);
1378 + document.documentElement.classList.remove('lp-full-screen-active');
1379 + window.scrollTo(0, lastScrollY);
1380 + } else {
1381 + lastScrollY = window.scrollY;
1382 + elTarget.classList.add(lpClassName.elFullScreen);
1383 + document.documentElement.classList.add('lp-full-screen-active');
1384 + }
1385 + if (!isFullscreen) {
1386 + if (!elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`)) {
1387 + const closeButton = document.createElement('button');
1388 + closeButton.type = 'button';
1389 + closeButton.className = lpClassName.elBtnFullScreenClose;
1390 + closeButton.setAttribute('aria-label', 'Close');
1391 + closeButton.innerHTML = lpData.i18n.closeButtonFullScreen || 'Close &times;';
1392 + closeButton.addEventListener('click', e => {
1393 + e.preventDefault();
1394 + lpToggleFullscreenView(elTarget);
1395 + });
1396 + elTarget.appendChild(closeButton);
1397 + }
1398 + } else {
1399 + const closeButton = elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`);
1400 + if (closeButton) {
1401 + closeButton.remove();
1402 + }
1403 + }
1404 + };
1405 + eventHandlers('click', [{
1406 + selector: lpClassName.elBtnFullScreen,
1407 + callBack: args => {
1408 + const {
1409 + e,
1410 + target
1411 + } = args;
1412 + const elBtnFullScreen = target.closest(lpClassName.elBtnFullScreen);
1413 + if (!elBtnFullScreen) {
1414 + console.log('No full screen button found');
1415 + return;
1416 + }
1417 + e.preventDefault();
1418 + let elTarget = null;
1419 + const targetSelector = elBtnFullScreen.dataset.targetFullscreen;
1420 + console.log(targetSelector);
1421 + if (targetSelector) {
1422 + elTarget = document.querySelector(targetSelector);
1423 + }
1424 + if (!elTarget) {
1425 + console.log('No target element found');
1426 + return;
1427 + }
1428 + lpToggleFullscreenView(elTarget, elBtnFullScreen);
1429 + }
1430 + }]);
1431 +};
1432 +
1298 1433 /***/ },
1299 1434
1300 1435 /***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/toastify-js/src/toastify.css"
1301 1436 /*!*****************************************************************************************!*\
@@ -2741,46 +2876,54 @@
2741 2876 });
2742 2877 };
2743 2878
2744 2879 // Rest API load content course progress - Nhamdv.
2745 -const courseProgress = () => {
2746 - const elements = document.querySelectorAll('.lp-course-progress-wrapper');
2747 - if (!elements.length) {
2748 - return;
2749 - }
2750 - if ('IntersectionObserver' in window) {
2751 - const eleObserver = new IntersectionObserver((entries, observer) => {
2752 - entries.forEach(entry => {
2753 - if (entry.isIntersecting) {
2754 - const ele = entry.target;
2755 - setTimeout(function () {
2756 - getResponse(ele);
2757 - }, 600);
2758 - eleObserver.unobserve(ele);
2759 - }
2760 - });
2761 - });
2762 - [...elements].map(ele => eleObserver.observe(ele));
2763 - }
2764 - const getResponse = async ele => {
2765 - let url = 'lp/v1/lazy-load/course-progress';
2766 - if (lpData.urlParams.hasOwnProperty('lang')) {
2767 - url += '?lang=' + lpData.urlParams.lang;
2768 - }
2769 - const response = await wp.apiFetch({
2770 - path: url,
2771 - method: 'POST',
2772 - data: {
2773 - courseId: lpGlobalSettings.post_id || '',
2774 - userId: lpData.user_id || ''
2775 - }
2776 - });
2777 - const {
2778 - data
2779 - } = response;
2780 - ele.innerHTML = data;
2781 - };
2782 -};
2880 +/*const courseProgress = () => {
2881 + const elements = document.querySelectorAll( '.lp-course-progress-wrapper' );
2882 +
2883 + if ( ! elements.length ) {
2884 + return;
2885 + }
2886 +
2887 + if ( 'IntersectionObserver' in window ) {
2888 + const eleObserver = new IntersectionObserver( ( entries, observer ) => {
2889 + entries.forEach( ( entry ) => {
2890 + if ( entry.isIntersecting ) {
2891 + const ele = entry.target;
2892 +
2893 + setTimeout( function() {
2894 + getResponse( ele );
2895 + }, 600 );
2896 +
2897 + eleObserver.unobserve( ele );
2898 + }
2899 + } );
2900 + } );
2901 +
2902 + [ ...elements ].map( ( ele ) => eleObserver.observe( ele ) );
2903 + }
2904 +
2905 + const getResponse = async ( ele ) => {
2906 + let url = 'lp/v1/lazy-load/course-progress';
2907 + if ( lpData.urlParams.hasOwnProperty( 'lang' ) ) {
2908 + url += '?lang=' + lpData.urlParams.lang;
2909 + }
2910 +
2911 + const response = await wp.apiFetch( {
2912 + path: url,
2913 + method: 'POST',
2914 + data: {
2915 + courseId: lpGlobalSettings.post_id || '',
2916 + userId: lpData.user_id || '',
2917 + },
2918 + } );
2919 +
2920 + const { data } = response;
2921 +
2922 + ele.innerHTML = data;
2923 + };
2924 +};*/
2925 +
2783 2926 const accordionExtraTab = () => {
2784 2927 const elements = document.querySelectorAll('.course-extra-box');
2785 2928 [...elements].map(ele => {
2786 2929 const title = ele.querySelector('.course-extra-box__title');
@@ -2839,9 +2982,9 @@
2839 2982 initCourseSidebar();
2840 2983 enrollCourse();
2841 2984 purchaseCourse();
2842 2985 retakeCourse();
2843 - courseProgress();
2986 + //courseProgress();
2844 2987 courseContinue();
2845 2988 _show_lp_overlay_complete_item__WEBPACK_IMPORTED_MODULE_2__["default"].init();
2846 2989 (0,_material__WEBPACK_IMPORTED_MODULE_5__["default"])();
2847 2990 //courseCurriculumSkeleton();