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
← All changes | assets/src/js/utils.js +522 -357 4.3.94.4.8 View file →
@@ -1,357 +1,522 @@
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 -};
1 +/**
2 + * Utils functions
3 + *
4 + * @param url
5 + * @param data
6 + * @param functions
7 + * @since 4.2.5.1
8 + * @version 1.0.7
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 + elBtnFullScreen: '.lp-btn-full-screen-view',
17 + elFullScreen: 'lp-full-screen-view',
18 + elBtnFullScreenClose: 'lp-full-screen-view__close',
19 +};
20 +
21 +export const lpFetchAPI = ( url, data = {}, functions = {} ) => {
22 + if ( 'function' === typeof functions.before ) {
23 + functions.before();
24 + }
25 +
26 + fetch( url, { method: 'GET', ...data } )
27 + .then( ( response ) => response.json() )
28 + .then( ( response ) => {
29 + if ( 'function' === typeof functions.success ) {
30 + functions.success( response );
31 + }
32 + } )
33 + .catch( ( err ) => {
34 + if ( 'function' === typeof functions.error ) {
35 + functions.error( err );
36 + }
37 + } )
38 + .finally( () => {
39 + if ( 'function' === typeof functions.completed ) {
40 + functions.completed();
41 + }
42 + } );
43 +};
44 +
45 +/**
46 + * Get current URL without params.
47 + *
48 + * @since 4.2.5.1
49 + */
50 +export const lpGetCurrentURLNoParam = () => {
51 + let currentUrl = window.location.href;
52 + const hasParams = currentUrl.includes( '?' );
53 + if ( hasParams ) {
54 + currentUrl = currentUrl.split( '?' )[ 0 ];
55 + }
56 +
57 + return currentUrl;
58 +};
59 +
60 +export const lpAddQueryArgs = ( endpoint, args ) => {
61 + const url = new URL( endpoint );
62 +
63 + Object.keys( args ).forEach( ( arg ) => {
64 + url.searchParams.set( arg, args[ arg ] );
65 + } );
66 +
67 + return url;
68 +};
69 +
70 +/**
71 + * Listen element viewed.
72 + *
73 + * @param el
74 + * @param callback
75 + * @since 4.2.5.8
76 + */
77 +export const listenElementViewed = ( el, callback ) => {
78 + const observerSeeItem = new IntersectionObserver( function ( entries ) {
79 + for ( const entry of entries ) {
80 + if ( entry.isIntersecting ) {
81 + callback( entry );
82 + }
83 + }
84 + } );
85 +
86 + observerSeeItem.observe( el );
87 +};
88 +
89 +/**
90 + * Listen element created.
91 + *
92 + * @param callback
93 + * @since 4.2.5.8
94 + */
95 +export const listenElementCreated = ( callback ) => {
96 + const observerCreateItem = new MutationObserver( function ( mutations ) {
97 + mutations.forEach( function ( mutation ) {
98 + if ( mutation.addedNodes ) {
99 + mutation.addedNodes.forEach( function ( node ) {
100 + if ( node.nodeType === 1 ) {
101 + callback( node );
102 + }
103 + } );
104 + }
105 + } );
106 + } );
107 +
108 + observerCreateItem.observe( document, { childList: true, subtree: true } );
109 + // End.
110 +};
111 +
112 +/**
113 + * Listen element created.
114 + *
115 + * @param selector
116 + * @param callback
117 + * @since 4.2.7.1
118 + */
119 +export const lpOnElementReady = ( selector, callback ) => {
120 + const element = document.querySelector( selector );
121 + if ( element ) {
122 + callback( element );
123 + return;
124 + }
125 +
126 + const observer = new MutationObserver( ( mutations, obs ) => {
127 + const element = document.querySelector( selector );
128 + if ( element ) {
129 + obs.disconnect();
130 + callback( element );
131 + }
132 + } );
133 +
134 + observer.observe( document.documentElement, {
135 + childList: true,
136 + subtree: true,
137 + } );
138 +};
139 +
140 +// Parse JSON from string with content include LP_AJAX_START.
141 +export const lpAjaxParseJsonOld = ( data ) => {
142 + if ( typeof data !== 'string' ) {
143 + return data;
144 + }
145 +
146 + const m = String.raw( { raw: data } ).match(
147 + /<-- LP_AJAX_START -->(.*)<-- LP_AJAX_END -->/s
148 + );
149 +
150 + try {
151 + if ( m ) {
152 + data = JSON.parse( m[ 1 ].replace( /(?:\r\n|\r|\n)/g, '' ) );
153 + } else {
154 + data = JSON.parse( data );
155 + }
156 + } catch ( e ) {
157 + data = {};
158 + }
159 +
160 + return data;
161 +};
162 +
163 +// status 0: hide, 1: show
164 +export const lpShowHideEl = ( el, status = 0 ) => {
165 + if ( ! el ) {
166 + return;
167 + }
168 +
169 + if ( ! status ) {
170 + el.classList.add( lpClassName.hidden );
171 + } else {
172 + el.classList.remove( lpClassName.hidden );
173 + }
174 +};
175 +
176 +// status 0: hide, 1: show
177 +export const lpSetLoadingEl = ( el, status ) => {
178 + if ( ! el ) {
179 + return;
180 + }
181 +
182 + if ( ! status ) {
183 + el.classList.remove( lpClassName.loading );
184 + } else {
185 + el.classList.add( lpClassName.loading );
186 + }
187 +};
188 +
189 +// Toggle collapse section
190 +export const toggleCollapse = (
191 + e,
192 + target,
193 + elTriggerClassName = '',
194 + elsExclude = [],
195 + callback
196 +) => {
197 + if ( ! elTriggerClassName ) {
198 + elTriggerClassName = lpClassName.elTriggerToggle;
199 + }
200 +
201 + // Exclude elements, which should not trigger the collapse toggle
202 + if ( elsExclude && elsExclude.length > 0 ) {
203 + for ( const elExclude of elsExclude ) {
204 + if ( target.closest( elExclude ) ) {
205 + return;
206 + }
207 + }
208 + }
209 +
210 + const elTrigger = target.closest( elTriggerClassName );
211 + if ( ! elTrigger ) {
212 + return;
213 + }
214 +
215 + //console.log( 'elTrigger', elTrigger );
216 +
217 + const elSectionToggle = elTrigger.closest(
218 + `${ lpClassName.elSectionToggle }`
219 + );
220 + if ( ! elSectionToggle ) {
221 + return;
222 + }
223 +
224 + elSectionToggle.classList.toggle( `${ lpClassName.elCollapse }` );
225 +
226 + if ( 'function' === typeof callback ) {
227 + callback( elSectionToggle );
228 + }
229 +};
230 +
231 +// Get data of form
232 +export const getDataOfForm = ( form ) => {
233 + const dataSend = {};
234 + const formData = new FormData( form );
235 + for ( const pair of formData.entries() ) {
236 + const key = pair[ 0 ];
237 + const value = formData.getAll( key );
238 + if ( ! dataSend.hasOwnProperty( key ) ) {
239 + // Convert value array to string.
240 + dataSend[ key ] = value.join( ',' );
241 + }
242 + }
243 +
244 + return dataSend;
245 +};
246 +
247 +// Get field keys of form
248 +export const getFieldKeysOfForm = ( form ) => {
249 + const keys = [];
250 + const elements = form.elements;
251 + for ( let i = 0; i < elements.length; i++ ) {
252 + const name = elements[ i ].name;
253 + if ( name && ! keys.includes( name ) ) {
254 + keys.push( name );
255 + }
256 + }
257 + return keys;
258 +};
259 +
260 +// Merge data handle with data form.
261 +export const mergeDataWithDatForm = ( elForm, dataHandle ) => {
262 + const dataForm = getDataOfForm( elForm );
263 + const keys = getFieldKeysOfForm( elForm );
264 + keys.forEach( ( key ) => {
265 + if ( ! dataForm.hasOwnProperty( key ) ) {
266 + delete dataHandle[ key ];
267 + } else if ( dataForm[ key ][ 0 ] === '' ) {
268 + delete dataForm[ key ];
269 + delete dataHandle[ key ];
270 + }
271 + } );
272 +
273 + dataHandle = { ...dataHandle, ...dataForm };
274 +
275 + return dataHandle;
276 +};
277 +
278 +/**
279 + * Event trigger
280 + * For each list of event handlers, listen event on document.
281 + *
282 + * eventName: 'click', 'change', ...
283 + * eventHandlers = [ { selector: '.lp-button', callBack: function(){}, class: object } ]
284 + *
285 + * @param eventName
286 + * @param eventHandlers
287 + */
288 +export const eventHandlers = ( eventName, eventHandlers ) => {
289 + document.addEventListener( eventName, ( e ) => {
290 + const target = e.target;
291 + let args = {
292 + e,
293 + target,
294 + };
295 +
296 + eventHandlers.forEach( ( eventHandler ) => {
297 + args = { ...args, ...eventHandler };
298 +
299 + //console.log( args );
300 +
301 + // Check condition before call back
302 + if ( eventHandler.conditionBeforeCallBack ) {
303 + if ( eventHandler.conditionBeforeCallBack( args ) !== true ) {
304 + return;
305 + }
306 + }
307 +
308 + // Special check for keydown event with checkIsEventEnter = true
309 + if ( eventName === 'keydown' && eventHandler.checkIsEventEnter ) {
310 + if ( e.key !== 'Enter' ) {
311 + return;
312 + }
313 + }
314 +
315 + if ( target.closest( eventHandler.selector ) ) {
316 + if ( eventHandler.class ) {
317 + // Call method of class, function callBack will understand exactly {this} is class object.
318 + eventHandler.class[ eventHandler.callBack ]( args );
319 + } else {
320 + // For send args is objected, {this} is eventHandler object, not class object.
321 + eventHandler.callBack( args );
322 + }
323 + }
324 + } );
325 + } );
326 +};
327 +
328 +/**
329 + * Debounce - delays function execution until after `wait` ms of inactivity.
330 + *
331 + * Each call resets the timer. Only the last call in a burst executes.
332 + *
333 + * USE CASES:
334 + * - Search inputs, form validation, window resize
335 + * - Multiple elements need independent timers
336 + * - When you need to call with different arguments
337 + *
338 + * EXAMPLES:
339 + * const debouncedSearch = debounce( (query) => fetchResults(query), 300 );
340 + * searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value));
341 + *
342 + * const debouncedResize = debounce( recalculateLayout, 250 );
343 + * window.addEventListener('resize', debouncedResize);
344 + *
345 + * ⚠️ Create ONCE outside event handlers, not inside.
346 + *
347 + * @param {Function} func - Function to debounce (can be anonymous)
348 + * @param {number} wait - Milliseconds to wait (default: 500)
349 + * @return {Function} Debounced wrapper function
350 + * @since 4.3.7
351 + * @version 1.0.0
352 + */
353 +export const debounce = ( func, wait = 500 ) => {
354 + let timer;
355 +
356 + return ( args ) => {
357 + clearTimeout( timer );
358 + timer = setTimeout( () => func( args ), wait );
359 + };
360 +};
361 +
362 +/**
363 + * Initialize lp-toggle-enable components.
364 + *
365 + * Finds all `.lp-toggle-enable` elements and wires up toggle behavior.
366 + * Reads initial state from `data-enabled` attribute ("true"/"false").
367 + * Calls `data-on-toggle` callback (if provided via options) on state change.
368 + *
369 + * HTML structure:
370 + * <label class="lp-toggle-enable" data-enabled="true">
371 + * <input type="checkbox" class="lp-toggle-enable__input" />
372 + * <span class="lp-toggle-enable__track"></span>
373 + * </label>
374 + *
375 + * @param {string} selector CSS selector for toggle elements (default: '.lp-toggle-enable')
376 + * @param {Function} onToggle Optional callback( el, isEnabled ) called on state change
377 + * @since 4.4.5
378 + * @version 1.0.0
379 + */
380 +window.lpToggleEnableInit = 0;
381 +export const toggleEnable = ( onToggle = null ) => {
382 + if ( window.lpToggleEnableInit ) {
383 + return;
384 + }
385 + window.lpToggleEnableInit = 1;
386 +
387 + const selector = '.lp-toggle-enable';
388 +
389 + const updateUI = ( toggle, isEnabled ) => {
390 + toggle.classList.toggle( 'is-enabled', isEnabled );
391 + const input = toggle.querySelector( '.lp-toggle-enable__input' );
392 + if ( input ) {
393 + input.checked = isEnabled;
394 + input.value = isEnabled ? '1' : '0';
395 + }
396 + };
397 +
398 + // Delegate click handling via eventHandlers.
399 + eventHandlers( 'click', [
400 + {
401 + selector,
402 + callBack: ( args ) => {
403 + const { e, target } = args;
404 + const toggle = target.closest( selector );
405 +
406 + if ( ! toggle || toggle.classList.contains( 'is-disabled' ) ) {
407 + return;
408 + }
409 +
410 + e.preventDefault();
411 +
412 + const isEnabled = ! toggle.classList.contains( 'is-enabled' );
413 + updateUI( toggle, isEnabled );
414 +
415 + if ( 'function' === typeof onToggle ) {
416 + onToggle( toggle, isEnabled );
417 + }
418 + },
419 + },
420 + ] );
421 +};
422 +
423 +/**
424 + * Initialize custom fullscreen view buttons.
425 + *
426 + * Delegates clicks on `.lp-btn-full-screen-view` buttons to
427 + * `lpToggleFullscreenView`. Reads the `data-target` attribute to find the
428 + * target element. Falls back to the button's parent element when
429 + * `data-target` is not provided.
430 + *
431 + * @since 4.4.5
432 + * @version 1.0.0
433 + */
434 +window.lpFullScreenViewInit = 0;
435 +export const fullScreenView = () => {
436 + if ( window.lpFullScreenViewInit ) {
437 + return;
438 + }
439 + window.lpFullScreenViewInit = 1;
440 +
441 + let lastScrollY = 0;
442 +
443 + const lpToggleFullscreenView = ( elTarget, elBtnFullScreen = null ) => {
444 + const isFullscreen = elTarget.classList.contains(
445 + lpClassName.elFullScreen
446 + );
447 +
448 + if ( isFullscreen ) {
449 + elTarget.classList.remove( lpClassName.elFullScreen );
450 + document.documentElement.classList.remove(
451 + 'lp-full-screen-active'
452 + );
453 + window.scrollTo( 0, lastScrollY );
454 + } else {
455 + lastScrollY = window.scrollY;
456 + elTarget.classList.add( lpClassName.elFullScreen );
457 + document.documentElement.classList.add( 'lp-full-screen-active' );
458 + }
459 +
460 + if ( ! isFullscreen ) {
461 + if (
462 + ! elTarget.querySelector(
463 + `.${ lpClassName.elBtnFullScreenClose }`
464 + )
465 + ) {
466 + const closeButton = document.createElement( 'button' );
467 + closeButton.type = 'button';
468 + closeButton.className = lpClassName.elBtnFullScreenClose;
469 + closeButton.setAttribute( 'aria-label', 'Close' );
470 + closeButton.innerHTML =
471 + lpData.i18n.closeButtonFullScreen || 'Close &times;';
472 +
473 + closeButton.addEventListener( 'click', ( e ) => {
474 + e.preventDefault();
475 + lpToggleFullscreenView( elTarget );
476 + } );
477 +
478 + elTarget.appendChild( closeButton );
479 + }
480 + } else {
481 + const closeButton = elTarget.querySelector(
482 + `.${ lpClassName.elBtnFullScreenClose }`
483 + );
484 + if ( closeButton ) {
485 + closeButton.remove();
486 + }
487 + }
488 + };
489 +
490 + eventHandlers( 'click', [
491 + {
492 + selector: lpClassName.elBtnFullScreen,
493 + callBack: ( args ) => {
494 + const { e, target } = args;
495 + const elBtnFullScreen = target.closest(
496 + lpClassName.elBtnFullScreen
497 + );
498 +
499 + if ( ! elBtnFullScreen ) {
500 + console.log( 'No full screen button found' );
501 + return;
502 + }
503 +
504 + e.preventDefault();
505 +
506 + let elTarget = null;
507 + const targetSelector = elBtnFullScreen.dataset.targetFullscreen;
508 + console.log( targetSelector );
509 + if ( targetSelector ) {
510 + elTarget = document.querySelector( targetSelector );
511 + }
512 +
513 + if ( ! elTarget ) {
514 + console.log( 'No target element found' );
515 + return;
516 + }
517 +
518 + lpToggleFullscreenView( elTarget, elBtnFullScreen );
519 + },
520 + },
521 + ] );
522 +};