PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.4
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.4
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 4.2.1 All 138 releases
learnpress / assets / src / js / utils.js

utils.js in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.4, at assets/src/js/utils.js

358 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Utils functions
3 *
4 * @param url
5 * @param data
6 * @param functions
7 * @since 4.2.5.1
8 * @version 1.0.6
9 */
10 export const lpClassName = {
11 hidden: 'lp-hidden',
12 loading: 'loading',
13 elCollapse: 'lp-collapse',
14 elSectionToggle: '.lp-section-toggle',
15 elTriggerToggle: '.lp-trigger-toggle',
16 };
17
18 export const lpFetchAPI = ( url, data = {}, functions = {} ) => {
19 if ( 'function' === typeof functions.before ) {
20 functions.before();
21 }
22
23 fetch( url, { method: 'GET', ...data } )
24 .then( ( response ) => response.json() )
25 .then( ( response ) => {
26 if ( 'function' === typeof functions.success ) {
27 functions.success( response );
28 }
29 } )
30 .catch( ( err ) => {
31 if ( 'function' === typeof functions.error ) {
32 functions.error( err );
33 }
34 } )
35 .finally( () => {
36 if ( 'function' === typeof functions.completed ) {
37 functions.completed();
38 }
39 } );
40 };
41
42 /**
43 * Get current URL without params.
44 *
45 * @since 4.2.5.1
46 */
47 export const lpGetCurrentURLNoParam = () => {
48 let currentUrl = window.location.href;
49 const hasParams = currentUrl.includes( '?' );
50 if ( hasParams ) {
51 currentUrl = currentUrl.split( '?' )[ 0 ];
52 }
53
54 return currentUrl;
55 };
56
57 export const lpAddQueryArgs = ( endpoint, args ) => {
58 const url = new URL( endpoint );
59
60 Object.keys( args ).forEach( ( arg ) => {
61 url.searchParams.set( arg, args[ arg ] );
62 } );
63
64 return url;
65 };
66
67 /**
68 * Listen element viewed.
69 *
70 * @param el
71 * @param callback
72 * @since 4.2.5.8
73 */
74 export const listenElementViewed = ( el, callback ) => {
75 const observerSeeItem = new IntersectionObserver( function( entries ) {
76 for ( const entry of entries ) {
77 if ( entry.isIntersecting ) {
78 callback( entry );
79 }
80 }
81 } );
82
83 observerSeeItem.observe( el );
84 };
85
86 /**
87 * Listen element created.
88 *
89 * @param callback
90 * @since 4.2.5.8
91 */
92 export const listenElementCreated = ( callback ) => {
93 const observerCreateItem = new MutationObserver( function( mutations ) {
94 mutations.forEach( function( mutation ) {
95 if ( mutation.addedNodes ) {
96 mutation.addedNodes.forEach( function( node ) {
97 if ( node.nodeType === 1 ) {
98 callback( node );
99 }
100 } );
101 }
102 } );
103 } );
104
105 observerCreateItem.observe( document, { childList: true, subtree: true } );
106 // End.
107 };
108
109 /**
110 * Listen element created.
111 *
112 * @param selector
113 * @param callback
114 * @since 4.2.7.1
115 */
116 export const lpOnElementReady = ( selector, callback ) => {
117 const element = document.querySelector( selector );
118 if ( element ) {
119 callback( element );
120 return;
121 }
122
123 const observer = new MutationObserver( ( mutations, obs ) => {
124 const element = document.querySelector( selector );
125 if ( element ) {
126 obs.disconnect();
127 callback( element );
128 }
129 } );
130
131 observer.observe( document.documentElement, {
132 childList: true,
133 subtree: true,
134 } );
135 };
136
137 // Parse JSON from string with content include LP_AJAX_START.
138 export const lpAjaxParseJsonOld = ( data ) => {
139 if ( typeof data !== 'string' ) {
140 return data;
141 }
142
143 const m = String.raw( { raw: data } ).match(
144 /<-- LP_AJAX_START -->(.*)<-- LP_AJAX_END -->/s
145 );
146
147 try {
148 if ( m ) {
149 data = JSON.parse( m[ 1 ].replace( /(?:\r\n|\r|\n)/g, '' ) );
150 } else {
151 data = JSON.parse( data );
152 }
153 } catch ( e ) {
154 data = {};
155 }
156
157 return data;
158 };
159
160 // status 0: hide, 1: show
161 export const lpShowHideEl = ( el, status = 0 ) => {
162 if ( ! el ) {
163 return;
164 }
165
166 if ( ! status ) {
167 el.classList.add( lpClassName.hidden );
168 } else {
169 el.classList.remove( lpClassName.hidden );
170 }
171 };
172
173 // status 0: hide, 1: show
174 export const lpSetLoadingEl = ( el, status ) => {
175 if ( ! el ) {
176 return;
177 }
178
179 if ( ! status ) {
180 el.classList.remove( lpClassName.loading );
181 } else {
182 el.classList.add( lpClassName.loading );
183 }
184 };
185
186 // Toggle collapse section
187 export const toggleCollapse = (
188 e,
189 target,
190 elTriggerClassName = '',
191 elsExclude = [],
192 callback
193 ) => {
194 if ( ! elTriggerClassName ) {
195 elTriggerClassName = lpClassName.elTriggerToggle;
196 }
197
198 // Exclude elements, which should not trigger the collapse toggle
199 if ( elsExclude && elsExclude.length > 0 ) {
200 for ( const elExclude of elsExclude ) {
201 if ( target.closest( elExclude ) ) {
202 return;
203 }
204 }
205 }
206
207 const elTrigger = target.closest( elTriggerClassName );
208 if ( ! elTrigger ) {
209 return;
210 }
211
212 //console.log( 'elTrigger', elTrigger );
213
214 const elSectionToggle = elTrigger.closest(
215 `${ lpClassName.elSectionToggle }`
216 );
217 if ( ! elSectionToggle ) {
218 return;
219 }
220
221 elSectionToggle.classList.toggle( `${ lpClassName.elCollapse }` );
222
223 if ( 'function' === typeof callback ) {
224 callback( elSectionToggle );
225 }
226 };
227
228 // Get data of form
229 export const getDataOfForm = ( form ) => {
230 const dataSend = {};
231 const formData = new FormData( form );
232 for ( const pair of formData.entries() ) {
233 const key = pair[ 0 ];
234 const value = formData.getAll( key );
235 if ( ! dataSend.hasOwnProperty( key ) ) {
236 // Convert value array to string.
237 dataSend[ key ] = value.join( ',' );
238 }
239 }
240
241 return dataSend;
242 };
243
244 // Get field keys of form
245 export const getFieldKeysOfForm = ( form ) => {
246 const keys = [];
247 const elements = form.elements;
248 for ( let i = 0; i < elements.length; i++ ) {
249 const name = elements[ i ].name;
250 if ( name && ! keys.includes( name ) ) {
251 keys.push( name );
252 }
253 }
254 return keys;
255 };
256
257 // Merge data handle with data form.
258 export const mergeDataWithDatForm = ( elForm, dataHandle ) => {
259 const dataForm = getDataOfForm( elForm );
260 const keys = getFieldKeysOfForm( elForm );
261 keys.forEach( ( key ) => {
262 if ( ! dataForm.hasOwnProperty( key ) ) {
263 delete dataHandle[ key ];
264 } else if ( dataForm[ key ][ 0 ] === '' ) {
265 delete dataForm[ key ];
266 delete dataHandle[ key ];
267 }
268 } );
269
270 dataHandle = { ...dataHandle, ...dataForm };
271
272 return dataHandle;
273 };
274
275 /**
276 * Event trigger
277 * For each list of event handlers, listen event on document.
278 *
279 * eventName: 'click', 'change', ...
280 * eventHandlers = [ { selector: '.lp-button', callBack: function(){}, class: object } ]
281 *
282 * @param eventName
283 * @param eventHandlers
284 */
285 export const eventHandlers = ( eventName, eventHandlers ) => {
286 document.addEventListener( eventName, ( e ) => {
287 const target = e.target;
288 let args = {
289 e,
290 target,
291 };
292
293 eventHandlers.forEach( ( eventHandler ) => {
294 args = { ...args, ...eventHandler };
295
296 //console.log( args );
297
298 // Check condition before call back
299 if ( eventHandler.conditionBeforeCallBack ) {
300 if ( eventHandler.conditionBeforeCallBack( args ) !== true ) {
301 return;
302 }
303 }
304
305 // Special check for keydown event with checkIsEventEnter = true
306 if ( eventName === 'keydown' && eventHandler.checkIsEventEnter ) {
307 if ( e.key !== 'Enter' ) {
308 return;
309 }
310 }
311
312 if ( target.closest( eventHandler.selector ) ) {
313 if ( eventHandler.class ) {
314 // Call method of class, function callBack will understand exactly {this} is class object.
315 eventHandler.class[ eventHandler.callBack ]( args );
316 } else {
317 // For send args is objected, {this} is eventHandler object, not class object.
318 eventHandler.callBack( args );
319 }
320 }
321 } );
322 } );
323 };
324
325 /**
326 * Debounce - delays function execution until after `wait` ms of inactivity.
327 *
328 * Each call resets the timer. Only the last call in a burst executes.
329 *
330 * USE CASES:
331 * - Search inputs, form validation, window resize
332 * - Multiple elements need independent timers
333 * - When you need to call with different arguments
334 *
335 * EXAMPLES:
336 * const debouncedSearch = debounce( (query) => fetchResults(query), 300 );
337 * searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value));
338 *
339 * const debouncedResize = debounce( recalculateLayout, 250 );
340 * window.addEventListener('resize', debouncedResize);
341 *
342 * ⚠️ Create ONCE outside event handlers, not inside.
343 *
344 * @param {Function} func - Function to debounce (can be anonymous)
345 * @param {number} wait - Milliseconds to wait (default: 500)
346 * @return {Function} Debounced wrapper function
347 * @since 4.3.7
348 * @version 1.0.0
349 */
350 export const debounce = ( func, wait = 500 ) => {
351 let timer;
352
353 return ( args ) => {
354 clearTimeout( timer );
355 timer = setTimeout( () => func( args ), wait );
356 };
357 };
358