PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.10
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.10
4.4.10 4.4.9.1 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 All 142 releases
← All changes | assets/src/js/frontend/course-builder/builder-lesson/builder-tab-lesson.js +561 -557 4.3.9 → 4.4.10 View file →
@@ -1,557 +1,561 @@
1 -import * as lpUtils from 'lpAssetsJsPath/utils.js';
2 -import * as lpToastify from 'lpAssetsJsPath/lpToastify.js';
3 -import SweetAlert from 'sweetalert2';
4 -import { SWAL_ICON_DELETE, SWAL_ICON_DUPLICATE, SWAL_ICON_TRASH_DRAFT } from '../swal-icons.js';
5 -
6 -export class BuilderTabLesson {
7 - constructor() {
8 - this.init();
9 - }
10 -
11 - static selectors = {
12 - elLessonItem: '.lesson-item',
13 - elLessonExpandedItems: '.lesson-action-expanded__items',
14 - elLessonDuplicate: '.lesson-action-expanded__duplicate',
15 - elLessonTrash: '.lesson-action-expanded__trash',
16 - elLessonRestore: '.lesson-action-expanded__restore',
17 - elLessonPublish: '.lesson-action-expanded__publish',
18 - elLessonDelete: '.lesson-action-expanded__delete',
19 - elLessonActionExpanded: '.lesson-action-expanded',
20 - elLessonStatus: '.lesson-status',
21 - elLessonPreview: '.lesson__preview.lp-btn-set-preview-item',
22 - };
23 -
24 - init() {
25 - this.events();
26 - }
27 -
28 - events() {
29 - if ( BuilderTabLesson._loadedEvents ) {
30 - return;
31 - }
32 - BuilderTabLesson._loadedEvents = true;
33 -
34 - lpUtils.eventHandlers( 'click', [
35 - {
36 - selector: BuilderTabLesson.selectors.elLessonDuplicate,
37 - class: this,
38 - callBack: this.duplicateLesson.name,
39 - },
40 - {
41 - selector: BuilderTabLesson.selectors.elLessonTrash,
42 - class: this,
43 - callBack: this.trashLesson.name,
44 - },
45 - {
46 - selector: BuilderTabLesson.selectors.elLessonPublish,
47 - class: this,
48 - callBack: this.publishLesson.name,
49 - },
50 - {
51 - selector: BuilderTabLesson.selectors.elLessonRestore,
52 - class: this,
53 - callBack: this.restoreLesson.name,
54 - },
55 - {
56 - selector: BuilderTabLesson.selectors.elLessonDelete,
57 - class: this,
58 - callBack: this.deleteLesson.name,
59 - },
60 - {
61 - selector: BuilderTabLesson.selectors.elLessonActionExpanded,
62 - class: this,
63 - callBack: this.toggleExpandedAction.name,
64 - },
65 - {
66 - selector: BuilderTabLesson.selectors.elLessonPreview,
67 - class: this,
68 - callBack: this.toggleLessonPreview.name,
69 - },
70 - ] );
71 -
72 - document.addEventListener( 'click', ( e ) => {
73 - if ( ! e.target.closest( BuilderTabLesson.selectors.elLessonActionExpanded ) ) {
74 - this.closeAllExpanded();
75 - }
76 - } );
77 -
78 - document.addEventListener( 'lp-builder-popup-saved', ( e ) => {
79 - const { type, id, data } = e.detail;
80 - if ( type !== 'lesson' || ! data?.list_item_html ) return;
81 - const elItem = document.querySelector( `.lesson-item[data-lesson-id="${ id }"]` );
82 - if ( elItem ) {
83 - this.replaceItemHtml( elItem.closest( '.lesson' ), data.list_item_html );
84 - }
85 - } );
86 -
87 - document.addEventListener( 'lp-builder-popup-trashed', ( e ) => {
88 - const { type, id, data } = e.detail;
89 - if ( type !== 'lesson' || ! data?.html ) return;
90 - const elItem = document.querySelector( `.lesson-item[data-lesson-id="${ id }"]` );
91 - if ( elItem ) {
92 - this.replaceItemHtml( elItem.closest( '.lesson' ), data.html );
93 - }
94 - } );
95 - }
96 -
97 - duplicateLesson( args ) {
98 - const { target } = args;
99 - const elLessonDuplicate = target.closest( BuilderTabLesson.selectors.elLessonDuplicate );
100 - const elLessonItem = elLessonDuplicate.closest( BuilderTabLesson.selectors.elLessonItem );
101 -
102 - if ( ! elLessonItem ) {
103 - return;
104 - }
105 -
106 - const elActionExpanded = elLessonItem.querySelector(
107 - BuilderTabLesson.selectors.elLessonActionExpanded
108 - );
109 - const lessonId = elLessonItem.dataset.lessonId || '';
110 -
111 - SweetAlert.fire( {
112 - title: elLessonDuplicate.dataset.title || 'Duplicate Lesson',
113 - text: elLessonDuplicate.dataset.content || 'Are you sure you want to duplicate this lesson?',
114 - iconHtml: SWAL_ICON_DUPLICATE,
115 - customClass: { icon: 'lp-cb-swal-icon-html' },
116 - showCloseButton: true,
117 - showCancelButton: true,
118 - cancelButtonText: lpData.i18n.cancel,
119 - confirmButtonText: lpData.i18n.yes,
120 - reverseButtons: true,
121 - } ).then( ( result ) => {
122 - if ( result.isConfirmed ) {
123 - lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
124 -
125 - const dataSend = {
126 - action: 'duplicate_lesson',
127 - args: {
128 - id_url: 'duplicate-lesson',
129 - },
130 - lesson_id: lessonId,
131 - };
132 -
133 - const callBack = {
134 - success: ( response ) => {
135 - const { status, message, data } = response;
136 - lpToastify.show( message || 'Duplicated successfully!', status );
137 -
138 - if ( data?.html ) {
139 - const elLesson = elLessonDuplicate.closest( '.lesson' );
140 - const elLessonList = elLesson.closest( '.lessons-list' ) || elLesson.parentElement;
141 -
142 - if ( elLessonList ) {
143 - elLessonList.insertAdjacentHTML( 'afterbegin', data.html );
144 - const newLesson = elLessonList.firstElementChild;
145 -
146 - if ( newLesson ) {
147 - newLesson.scrollIntoView( {
148 - behavior: 'smooth',
149 - block: 'nearest',
150 - } );
151 - newLesson.classList.add( 'highlight-new-lesson' );
152 - setTimeout( () => {
153 - newLesson.classList.remove( 'highlight-new-lesson' );
154 - }, 1500 );
155 - }
156 - }
157 - }
158 - },
159 - error: ( error ) => {
160 - lpToastify.show( error.message || error, 'error' );
161 - },
162 - completed: () => {
163 - lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
164 - },
165 - };
166 -
167 - window.lpAJAXG.fetchAJAX( dataSend, callBack );
168 - }
169 - } );
170 - }
171 -
172 - trashLesson( args ) {
173 - const { target } = args;
174 - const elLessonTrash = target.closest( BuilderTabLesson.selectors.elLessonTrash );
175 - const elLessonItem = elLessonTrash.closest( BuilderTabLesson.selectors.elLessonItem );
176 -
177 - if ( ! elLessonItem ) {
178 - return;
179 - }
180 -
181 - const elActionExpanded = elLessonItem.querySelector(
182 - BuilderTabLesson.selectors.elLessonActionExpanded
183 - );
184 - const lessonId = elLessonItem.dataset.lessonId || '';
185 -
186 - SweetAlert.fire( {
187 - title: elLessonTrash.dataset.title || 'Trash Lesson',
188 - text:
189 - elLessonTrash.dataset.content ||
190 - 'Are you sure? Moving it to the trash will cause this item to be removed from the course.',
191 - iconHtml: SWAL_ICON_TRASH_DRAFT,
192 - customClass: { icon: 'lp-cb-swal-icon-html' },
193 - showCloseButton: true,
194 - showCancelButton: true,
195 - cancelButtonText: lpData.i18n.cancel,
196 - confirmButtonText: lpData.i18n.yes,
197 - reverseButtons: true,
198 - } ).then( ( result ) => {
199 - if ( result.isConfirmed ) {
200 - lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
201 -
202 - const dataSend = {
203 - action: 'move_trash_lesson',
204 - args: {
205 - id_url: 'move-trash-lesson',
206 - },
207 - lesson_id: lessonId,
208 - };
209 -
210 - const callBack = {
211 - success: ( response ) => {
212 - const { status, message, data } = response;
213 - lpToastify.show( message, status );
214 -
215 - if ( data?.html ) {
216 - this.replaceItemHtml( elLessonTrash.closest( '.lesson' ), data.html );
217 - }
218 - },
219 - error: ( error ) => {
220 - lpToastify.show( error.message || error, 'error' );
221 - },
222 - completed: () => {
223 - lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
224 - },
225 - };
226 -
227 - window.lpAJAXG.fetchAJAX( dataSend, callBack );
228 - }
229 - } );
230 - }
231 -
232 - publishLesson( args ) {
233 - const { target } = args;
234 - const elLessonPublish = target.closest( BuilderTabLesson.selectors.elLessonPublish );
235 - const elLessonItem = elLessonPublish.closest( BuilderTabLesson.selectors.elLessonItem );
236 -
237 - if ( ! elLessonItem ) {
238 - return;
239 - }
240 -
241 - const elActionExpanded = elLessonItem.querySelector(
242 - BuilderTabLesson.selectors.elLessonActionExpanded
243 - );
244 - lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
245 -
246 - const lessonId = elLessonItem.dataset.lessonId || '';
247 -
248 - const dataSend = {
249 - action: 'move_trash_lesson',
250 - args: {
251 - id_url: 'move-trash-lesson',
252 - },
253 - lesson_id: lessonId,
254 - status: 'publish',
255 - };
256 -
257 - const callBack = {
258 - success: ( response ) => {
259 - const { status, message, data } = response;
260 - lpToastify.show( message, status );
261 - if ( data?.html ) {
262 - this.replaceItemHtml( elLessonPublish.closest( '.lesson' ), data.html );
263 - }
264 - },
265 - error: ( error ) => {
266 - lpToastify.show( error.message || error, 'error' );
267 - },
268 - completed: () => {
269 - lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
270 - },
271 - };
272 -
273 - window.lpAJAXG.fetchAJAX( dataSend, callBack );
274 - }
275 -
276 - restoreLesson( args ) {
277 - const { target } = args;
278 - const elLessonRestore = target.closest( BuilderTabLesson.selectors.elLessonRestore );
279 - const elLessonItem = elLessonRestore.closest( BuilderTabLesson.selectors.elLessonItem );
280 -
281 - if ( ! elLessonItem ) {
282 - return;
283 - }
284 -
285 - const elActionExpanded = elLessonItem.querySelector(
286 - BuilderTabLesson.selectors.elLessonActionExpanded
287 - );
288 - lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
289 -
290 - const lessonId = elLessonItem.dataset.lessonId || '';
291 -
292 - const dataSend = {
293 - action: 'move_trash_lesson',
294 - args: {
295 - id_url: 'move-trash-lesson',
296 - },
297 - lesson_id: lessonId,
298 - status: 'draft',
299 - };
300 -
301 - const callBack = {
302 - success: ( response ) => {
303 - const { status, message, data } = response;
304 - lpToastify.show( message, status );
305 - if ( data?.html ) {
306 - this.replaceItemHtml( elLessonRestore.closest( '.lesson' ), data.html );
307 - }
308 - },
309 - error: ( error ) => {
310 - lpToastify.show( error.message || error, 'error' );
311 - },
312 - completed: () => {
313 - lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
314 - },
315 - };
316 -
317 - window.lpAJAXG.fetchAJAX( dataSend, callBack );
318 - }
319 -
320 - deleteLesson( args ) {
321 - const { target } = args;
322 - const elLessonDelete = target.closest( BuilderTabLesson.selectors.elLessonDelete );
323 - const elLessonItem = elLessonDelete.closest( BuilderTabLesson.selectors.elLessonItem );
324 -
325 - if ( ! elLessonItem ) {
326 - return;
327 - }
328 -
329 - const elActionExpanded = elLessonItem.querySelector(
330 - BuilderTabLesson.selectors.elLessonActionExpanded
331 - );
332 - const lessonId = elLessonItem.dataset.lessonId || '';
333 -
334 - if ( ! lessonId ) {
335 - return;
336 - }
337 -
338 - SweetAlert.fire( {
339 - title: elLessonDelete.dataset.title || 'Delete Lesson',
340 - text:
341 - elLessonDelete.dataset.content ||
342 - 'Are you sure you want to permanently delete this lesson?',
343 - iconHtml: SWAL_ICON_DELETE,
344 - customClass: { icon: 'lp-cb-swal-icon-html' },
345 - showCloseButton: true,
346 - showCancelButton: true,
347 - cancelButtonText: lpData.i18n.cancel,
348 - confirmButtonText: lpData.i18n.yes,
349 - reverseButtons: true,
350 - } ).then( ( result ) => {
351 - if ( result.isConfirmed ) {
352 - lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
353 -
354 - const dataSend = {
355 - action: 'move_trash_lesson',
356 - args: {
357 - id_url: 'move-trash-lesson',
358 - },
359 - lesson_id: lessonId,
360 - status: 'delete',
361 - };
362 -
363 - const callBack = {
364 - success: ( response ) => {
365 - const { status, message } = response;
366 - lpToastify.show( message, status );
367 -
368 - if ( status === 'success' ) {
369 - const elLesson = elLessonDelete.closest( '.lesson' );
370 - elLesson.style.transition = 'opacity 0.4s ease-out, transform 0.4s ease-out';
371 - elLesson.style.opacity = '0';
372 - elLesson.style.transform = 'translateX(160px)';
373 -
374 - setTimeout( () => {
375 - elLesson.remove();
376 - }, 400 );
377 - }
378 - },
379 - error: ( error ) => {
380 - lpToastify.show( error.message || error, 'error' );
381 - },
382 - completed: () => {
383 - lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
384 - },
385 - };
386 -
387 - window.lpAJAXG.fetchAJAX( dataSend, callBack );
388 - }
389 - } );
390 - }
391 -
392 - toggleExpandedAction( args ) {
393 - const { target } = args;
394 - const elLessonActionExpanded = target.closest(
395 - BuilderTabLesson.selectors.elLessonActionExpanded
396 - );
397 -
398 - if ( ! elLessonActionExpanded ) {
399 - return;
400 - }
401 -
402 - const elLessonItem = elLessonActionExpanded.closest( BuilderTabLesson.selectors.elLessonItem );
403 -
404 - if ( ! elLessonItem ) {
405 - return;
406 - }
407 -
408 - const elExpandedItems = elLessonItem.querySelector(
409 - BuilderTabLesson.selectors.elLessonExpandedItems
410 - );
411 -
412 - if ( ! elExpandedItems ) {
413 - return;
414 - }
415 -
416 - this.closeAllExpanded( elExpandedItems );
417 - const willOpen = ! elExpandedItems.classList.contains( 'active' );
418 -
419 - if ( willOpen ) {
420 - elExpandedItems.classList.add( 'active' );
421 - elLessonActionExpanded.classList.add( 'active' );
422 - this.setExpandedDirection( elExpandedItems );
423 - } else {
424 - elExpandedItems.classList.remove( 'active' );
425 - elExpandedItems.classList.remove( 'is-dropup' );
426 - elLessonActionExpanded.classList.remove( 'active' );
427 - }
428 - }
429 -
430 - closeAllExpanded( excludeElement = null ) {
431 - const allExpandedItems = document.querySelectorAll(
432 - `${ BuilderTabLesson.selectors.elLessonExpandedItems }.active`
433 - );
434 -
435 - allExpandedItems.forEach( ( item ) => {
436 - if ( item === excludeElement ) {
437 - return;
438 - }
439 -
440 - item.classList.remove( 'active' );
441 - item.classList.remove( 'is-dropup' );
442 -
443 - const lessonItem = item.closest( BuilderTabLesson.selectors.elLessonItem );
444 -
445 - if ( ! lessonItem ) {
446 - return;
447 - }
448 -
449 - const expandedBtn = lessonItem.querySelector(
450 - BuilderTabLesson.selectors.elLessonActionExpanded
451 - );
452 - if ( expandedBtn ) {
453 - expandedBtn.classList.remove( 'active' );
454 - }
455 - } );
456 - }
457 -
458 - setExpandedDirection( elExpandedItems ) {
459 - if ( ! elExpandedItems ) {
460 - return;
461 - }
462 -
463 - elExpandedItems.classList.remove( 'is-dropup' );
464 -
465 - const elLesson = elExpandedItems.closest( '.lesson' );
466 - if ( ! elLesson ) {
467 - return;
468 - }
469 -
470 - if ( elLesson.matches( ':last-child' ) ) {
471 - elExpandedItems.classList.add( 'is-dropup' );
472 - }
473 - }
474 -
475 - /* Toggle preview for a lesson in the lesson list */
476 - toggleLessonPreview( args ) {
477 - const { target } = args;
478 - const elPreviewBtn = target.closest( BuilderTabLesson.selectors.elLessonPreview );
479 - if ( ! elPreviewBtn ) {
480 - return;
481 - }
482 - if (
483 - elPreviewBtn.classList.contains( 'loading' ) ||
484 - elPreviewBtn.classList.contains( 'lp-loading' )
485 - ) {
486 - return;
487 - }
488 -
489 - const elLessonItem = elPreviewBtn.closest( BuilderTabLesson.selectors.elLessonItem );
490 - if ( ! elLessonItem ) {
491 - return;
492 - }
493 -
494 - const icon = elPreviewBtn.querySelector( 'a' );
495 - if ( ! icon ) {
496 - return;
497 - }
498 -
499 - const lessonId = elLessonItem.dataset.lessonId || elPreviewBtn.dataset.id || '';
500 - if ( ! lessonId ) {
501 - return;
502 - }
503 -
504 - // Optimistic toggle
505 - icon.classList.toggle( 'lp-icon-eye' );
506 - icon.classList.toggle( 'lp-icon-eye-slash' );
507 -
508 - const enablePreview = icon.classList.contains( 'lp-icon-eye' );
509 -
510 - lpUtils.lpSetLoadingEl( elPreviewBtn, 1 );
511 - elPreviewBtn.classList.add( 'lp-loading' );
512 -
513 - const dataSend = {
514 - action: 'builder_update_lesson',
515 - args: { id_url: 'builder-update-lesson' },
516 - lesson_id: lessonId,
517 - lesson_settings: true,
518 - _lp_preview: enablePreview ? 'yes' : '',
519 - };
520 -
521 - const callBack = {
522 - success: ( response ) => {
523 - const { status, message } = response;
524 - lpToastify.show( message, status );
525 -
526 - if ( status === 'error' ) {
527 - // Revert on error
528 - icon.classList.toggle( 'lp-icon-eye' );
529 - icon.classList.toggle( 'lp-icon-eye-slash' );
530 - }
531 - },
532 - error: ( error ) => {
533 - lpToastify.show( error.message || error, 'error' );
534 - icon.classList.toggle( 'lp-icon-eye' );
535 - icon.classList.toggle( 'lp-icon-eye-slash' );
536 - },
537 - completed: () => {
538 - lpUtils.lpSetLoadingEl( elPreviewBtn, 0 );
539 - elPreviewBtn.classList.remove( 'lp-loading' );
540 - },
541 - };
542 -
543 - window.lpAJAXG.fetchAJAX( dataSend, callBack );
544 - }
545 -
546 - replaceItemHtml( elLesson, html ) {
547 - if ( ! elLesson || ! html ) {
548 - return;
549 - }
550 - const tmp = document.createElement( 'div' );
551 - tmp.innerHTML = html;
552 - const newEl = tmp.firstElementChild;
553 - if ( newEl ) {
554 - elLesson.replaceWith( newEl );
555 - }
556 - }
557 -}
1 +import * as lpUtils from 'lpAssetsJsPath/utils.js';
2 +import * as lpToastify from 'lpAssetsJsPath/lpToastify.js';
3 +import SweetAlert from 'sweetalert2';
4 +import { SWAL_ICON_DELETE, SWAL_ICON_DUPLICATE, SWAL_ICON_TRASH_DRAFT } from '../swal-icons.js';
5 +
6 +export class BuilderTabLesson {
7 + constructor() {
8 + this.init();
9 + }
10 +
11 + static selectors = {
12 + elLessonItem: '.lesson-item',
13 + elLessonExpandedItems: '.lesson-action-expanded__items',
14 + elLessonDuplicate: '.lesson-action-expanded__duplicate',
15 + elLessonTrash: '.lesson-action-expanded__trash',
16 + elLessonRestore: '.lesson-action-expanded__restore',
17 + elLessonPublish: '.lesson-action-expanded__publish',
18 + elLessonDelete: '.lesson-action-expanded__delete',
19 + elLessonActionExpanded: '.lesson-action-expanded',
20 + elLessonStatus: '.lesson-status',
21 + elLessonPreview: '.lesson__preview.lp-btn-set-preview-item',
22 + };
23 +
24 + init() {
25 + this.events();
26 + }
27 +
28 + events() {
29 + if ( BuilderTabLesson._loadedEvents ) {
30 + return;
31 + }
32 + BuilderTabLesson._loadedEvents = true;
33 +
34 + lpUtils.eventHandlers( 'click', [
35 + {
36 + selector: BuilderTabLesson.selectors.elLessonDuplicate,
37 + class: this,
38 + callBack: this.duplicateLesson.name,
39 + },
40 + {
41 + selector: BuilderTabLesson.selectors.elLessonTrash,
42 + class: this,
43 + callBack: this.trashLesson.name,
44 + },
45 + {
46 + selector: BuilderTabLesson.selectors.elLessonPublish,
47 + class: this,
48 + callBack: this.publishLesson.name,
49 + },
50 + {
51 + selector: BuilderTabLesson.selectors.elLessonRestore,
52 + class: this,
53 + callBack: this.restoreLesson.name,
54 + },
55 + {
56 + selector: BuilderTabLesson.selectors.elLessonDelete,
57 + class: this,
58 + callBack: this.deleteLesson.name,
59 + },
60 + {
61 + selector: BuilderTabLesson.selectors.elLessonActionExpanded,
62 + class: this,
63 + callBack: this.toggleExpandedAction.name,
64 + },
65 + {
66 + selector: BuilderTabLesson.selectors.elLessonPreview,
67 + class: this,
68 + callBack: this.toggleLessonPreview.name,
69 + },
70 + ] );
71 +
72 + document.addEventListener( 'click', ( e ) => {
73 + if ( ! e.target.closest( BuilderTabLesson.selectors.elLessonActionExpanded ) ) {
74 + this.closeAllExpanded();
75 + }
76 + } );
77 +
78 + document.addEventListener( 'lp-builder-popup-saved', ( e ) => {
79 + const { type, id, data } = e.detail;
80 + if ( type !== 'lesson' || ! data?.list_item_html ) return;
81 + const elItem = document.querySelector( `.lesson-item[data-lesson-id="${ id }"]` );
82 + if ( elItem ) {
83 + this.replaceItemHtml( elItem.closest( '.lesson' ), data.list_item_html );
84 + }
85 + } );
86 +
87 + document.addEventListener( 'lp-builder-popup-trashed', ( e ) => {
88 + const { type, id, data } = e.detail;
89 + if ( type !== 'lesson' || ! data?.html ) return;
90 + const elItem = document.querySelector( `.lesson-item[data-lesson-id="${ id }"]` );
91 + if ( elItem ) {
92 + this.replaceItemHtml( elItem.closest( '.lesson' ), data.html );
93 + }
94 + } );
95 + }
96 +
97 + duplicateLesson( args ) {
98 + const { target } = args;
99 + const elLessonDuplicate = target.closest( BuilderTabLesson.selectors.elLessonDuplicate );
100 + const elLessonItem = elLessonDuplicate.closest( BuilderTabLesson.selectors.elLessonItem );
101 +
102 + if ( ! elLessonItem ) {
103 + return;
104 + }
105 +
106 + const elActionExpanded = elLessonItem.querySelector(
107 + BuilderTabLesson.selectors.elLessonActionExpanded
108 + );
109 + const lessonId = elLessonItem.dataset.lessonId || '';
110 +
111 + SweetAlert.fire( {
112 + title: elLessonDuplicate.dataset.title || 'Duplicate Lesson',
113 + text: elLessonDuplicate.dataset.content || 'Are you sure you want to duplicate this lesson?',
114 + iconHtml: SWAL_ICON_DUPLICATE,
115 + customClass: { icon: 'lp-cb-swal-icon-html' },
116 + showCloseButton: true,
117 + showCancelButton: true,
118 + cancelButtonText: lpData.i18n.cancel,
119 + confirmButtonText: lpData.i18n.yes,
120 + reverseButtons: true,
121 + } ).then( ( result ) => {
122 + if ( result.isConfirmed ) {
123 + lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
124 +
125 + const dataSend = {
126 + action: 'duplicate_lesson',
127 + args: {
128 + id_url: 'duplicate-lesson',
129 + },
130 + lesson_id: lessonId,
131 + };
132 +
133 + const callBack = {
134 + success: ( response ) => {
135 + const { status, message, data } = response;
136 + lpToastify.show( message || 'Duplicated successfully!', status );
137 +
138 + if ( data?.html ) {
139 + const elLesson = elLessonDuplicate.closest( '.lesson' );
140 + const elLessonList = elLesson.closest( '.lessons-list' ) || elLesson.parentElement;
141 +
142 + if ( elLessonList ) {
143 + elLessonList.insertAdjacentHTML( 'afterbegin', data.html );
144 + const newLesson = elLessonList.firstElementChild;
145 +
146 + if ( newLesson ) {
147 + newLesson.scrollIntoView( {
148 + behavior: 'smooth',
149 + block: 'nearest',
150 + } );
151 + newLesson.classList.add( 'highlight-new-lesson' );
152 + setTimeout( () => {
153 + newLesson.classList.remove( 'highlight-new-lesson' );
154 + }, 1500 );
155 + }
156 + }
157 + }
158 + },
159 + error: ( error ) => {
160 + lpToastify.show( error.message || error, 'error' );
161 + },
162 + completed: () => {
163 + lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
164 + },
165 + };
166 +
167 + window.lpAJAXG.fetchAJAX( dataSend, callBack );
168 + }
169 + } );
170 + }
171 +
172 + trashLesson( args ) {
173 + const { target } = args;
174 + const elLessonTrash = target.closest( BuilderTabLesson.selectors.elLessonTrash );
175 + const elLessonItem = elLessonTrash.closest( BuilderTabLesson.selectors.elLessonItem );
176 +
177 + if ( ! elLessonItem ) {
178 + return;
179 + }
180 +
181 + const elActionExpanded = elLessonItem.querySelector(
182 + BuilderTabLesson.selectors.elLessonActionExpanded
183 + );
184 + const lessonId = elLessonItem.dataset.lessonId || '';
185 +
186 + SweetAlert.fire( {
187 + title: elLessonTrash.dataset.title || 'Trash Lesson',
188 + text:
189 + elLessonTrash.dataset.content ||
190 + 'Are you sure? Moving it to the trash will cause this item to be removed from the course.',
191 + iconHtml: SWAL_ICON_TRASH_DRAFT,
192 + customClass: { icon: 'lp-cb-swal-icon-html' },
193 + showCloseButton: true,
194 + showCancelButton: true,
195 + cancelButtonText: lpData.i18n.cancel,
196 + confirmButtonText: lpData.i18n.yes,
197 + reverseButtons: true,
198 + } ).then( ( result ) => {
199 + if ( result.isConfirmed ) {
200 + lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
201 +
202 + const dataSend = {
203 + action: 'move_trash_lesson',
204 + args: {
205 + id_url: 'move-trash-lesson',
206 + },
207 + lesson_id: lessonId,
208 + };
209 +
210 + const callBack = {
211 + success: ( response ) => {
212 + const { status, message, data } = response;
213 + lpToastify.show( message, status );
214 +
215 + if ( data?.html ) {
216 + this.replaceItemHtml( elLessonTrash.closest( '.lesson' ), data.html );
217 + }
218 + },
219 + error: ( error ) => {
220 + lpToastify.show( error.message || error, 'error' );
221 + },
222 + completed: () => {
223 + lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
224 + },
225 + };
226 +
227 + window.lpAJAXG.fetchAJAX( dataSend, callBack );
228 + }
229 + } );
230 + }
231 +
232 + publishLesson( args ) {
233 + const { target } = args;
234 + const elLessonPublish = target.closest( BuilderTabLesson.selectors.elLessonPublish );
235 + const elLessonItem = elLessonPublish.closest( BuilderTabLesson.selectors.elLessonItem );
236 +
237 + if ( ! elLessonItem ) {
238 + return;
239 + }
240 +
241 + const elActionExpanded = elLessonItem.querySelector(
242 + BuilderTabLesson.selectors.elLessonActionExpanded
243 + );
244 + lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
245 +
246 + const lessonId = elLessonItem.dataset.lessonId || '';
247 +
248 + const dataSend = {
249 + action: 'move_trash_lesson',
250 + args: {
251 + id_url: 'move-trash-lesson',
252 + },
253 + lesson_id: lessonId,
254 + status: 'publish',
255 + };
256 +
257 + const callBack = {
258 + success: ( response ) => {
259 + const { status, message, data } = response;
260 + lpToastify.show( message, status );
261 + if ( data?.html ) {
262 + this.replaceItemHtml( elLessonPublish.closest( '.lesson' ), data.html );
263 + }
264 + },
265 + error: ( error ) => {
266 + lpToastify.show( error.message || error, 'error' );
267 + },
268 + completed: () => {
269 + lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
270 + },
271 + };
272 +
273 + window.lpAJAXG.fetchAJAX( dataSend, callBack );
274 + }
275 +
276 + restoreLesson( args ) {
277 + const { target } = args;
278 + const elLessonRestore = target.closest( BuilderTabLesson.selectors.elLessonRestore );
279 + const elLessonItem = elLessonRestore.closest( BuilderTabLesson.selectors.elLessonItem );
280 +
281 + if ( ! elLessonItem ) {
282 + return;
283 + }
284 +
285 + const elActionExpanded = elLessonItem.querySelector(
286 + BuilderTabLesson.selectors.elLessonActionExpanded
287 + );
288 + lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
289 +
290 + const lessonId = elLessonItem.dataset.lessonId || '';
291 +
292 + const dataSend = {
293 + action: 'move_trash_lesson',
294 + args: {
295 + id_url: 'move-trash-lesson',
296 + },
297 + lesson_id: lessonId,
298 + status: 'draft',
299 + };
300 +
301 + const callBack = {
302 + success: ( response ) => {
303 + const { status, message, data } = response;
304 + lpToastify.show( message, status );
305 + if ( data?.html ) {
306 + this.replaceItemHtml( elLessonRestore.closest( '.lesson' ), data.html );
307 + }
308 + },
309 + error: ( error ) => {
310 + lpToastify.show( error.message || error, 'error' );
311 + },
312 + completed: () => {
313 + lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
314 + },
315 + };
316 +
317 + window.lpAJAXG.fetchAJAX( dataSend, callBack );
318 + }
319 +
320 + deleteLesson( args ) {
321 + const { target } = args;
322 + const elLessonDelete = target.closest( BuilderTabLesson.selectors.elLessonDelete );
323 + const elLessonItem = elLessonDelete.closest( BuilderTabLesson.selectors.elLessonItem );
324 +
325 + if ( ! elLessonItem ) {
326 + return;
327 + }
328 +
329 + const elActionExpanded = elLessonItem.querySelector(
330 + BuilderTabLesson.selectors.elLessonActionExpanded
331 + );
332 + const lessonId = elLessonItem.dataset.lessonId || '';
333 +
334 + if ( ! lessonId ) {
335 + return;
336 + }
337 +
338 + SweetAlert.fire( {
339 + title: elLessonDelete.dataset.title || 'Delete Lesson',
340 + text:
341 + elLessonDelete.dataset.content ||
342 + 'Are you sure you want to permanently delete this lesson?',
343 + iconHtml: SWAL_ICON_DELETE,
344 + customClass: { icon: 'lp-cb-swal-icon-html' },
345 + showCloseButton: true,
346 + showCancelButton: true,
347 + cancelButtonText: lpData.i18n.cancel,
348 + confirmButtonText: lpData.i18n.yes,
349 + reverseButtons: true,
350 + } ).then( ( result ) => {
351 + if ( result.isConfirmed ) {
352 + lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
353 +
354 + const dataSend = {
355 + action: 'move_trash_lesson',
356 + args: {
357 + id_url: 'move-trash-lesson',
358 + },
359 + lesson_id: lessonId,
360 + status: 'delete',
361 + };
362 +
363 + const callBack = {
364 + success: ( response ) => {
365 + const { status, message } = response;
366 + lpToastify.show( message, status );
367 +
368 + if ( status === 'success' ) {
369 + const elLesson = elLessonDelete.closest( '.lesson' );
370 + elLesson.style.transition = 'opacity 0.4s ease-out, transform 0.4s ease-out';
371 + elLesson.style.opacity = '0';
372 + elLesson.style.transform = 'translateX(160px)';
373 +
374 + setTimeout( () => {
375 + elLesson.remove();
376 + }, 400 );
377 + }
378 + },
379 + error: ( error ) => {
380 + lpToastify.show( error.message || error, 'error' );
381 + },
382 + completed: () => {
383 + lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
384 + },
385 + };
386 +
387 + window.lpAJAXG.fetchAJAX( dataSend, callBack );
388 + }
389 + } );
390 + }
391 +
392 + toggleExpandedAction( args ) {
393 + const { target } = args;
394 + const elLessonActionExpanded = target.closest(
395 + BuilderTabLesson.selectors.elLessonActionExpanded
396 + );
397 +
398 + if ( ! elLessonActionExpanded ) {
399 + return;
400 + }
401 +
402 + const elLessonItem = elLessonActionExpanded.closest( BuilderTabLesson.selectors.elLessonItem );
403 +
404 + if ( ! elLessonItem ) {
405 + return;
406 + }
407 +
408 + const elExpandedItems = elLessonItem.querySelector(
409 + BuilderTabLesson.selectors.elLessonExpandedItems
410 + );
411 +
412 + if ( ! elExpandedItems ) {
413 + return;
414 + }
415 +
416 + this.closeAllExpanded( elExpandedItems );
417 + const willOpen = ! elExpandedItems.classList.contains( 'active' );
418 +
419 + if ( willOpen ) {
420 + elExpandedItems.classList.add( 'active' );
421 + elLessonActionExpanded.classList.add( 'active' );
422 + this.setExpandedDirection( elExpandedItems );
423 + } else {
424 + elExpandedItems.classList.remove( 'active' );
425 + elExpandedItems.classList.remove( 'is-dropup' );
426 + elLessonActionExpanded.classList.remove( 'active' );
427 + }
428 + }
429 +
430 + closeAllExpanded( excludeElement = null ) {
431 + const allExpandedItems = document.querySelectorAll(
432 + `${ BuilderTabLesson.selectors.elLessonExpandedItems }.active`
433 + );
434 +
435 + allExpandedItems.forEach( ( item ) => {
436 + if ( item === excludeElement ) {
437 + return;
438 + }
439 +
440 + item.classList.remove( 'active' );
441 + item.classList.remove( 'is-dropup' );
442 +
443 + const lessonItem = item.closest( BuilderTabLesson.selectors.elLessonItem );
444 +
445 + if ( ! lessonItem ) {
446 + return;
447 + }
448 +
449 + const expandedBtn = lessonItem.querySelector(
450 + BuilderTabLesson.selectors.elLessonActionExpanded
451 + );
452 + if ( expandedBtn ) {
453 + expandedBtn.classList.remove( 'active' );
454 + }
455 + } );
456 + }
457 +
458 + setExpandedDirection( elExpandedItems ) {
459 + if ( ! elExpandedItems ) {
460 + return;
461 + }
462 +
463 + elExpandedItems.classList.remove( 'is-dropup' );
464 +
465 + const elLesson = elExpandedItems.closest( '.lesson' );
466 + if ( ! elLesson ) {
467 + return;
468 + }
469 +
470 + if ( elLesson.matches( ':last-child' ) ) {
471 + elExpandedItems.classList.add( 'is-dropup' );
472 + }
473 + }
474 +
475 + /* Toggle preview for a lesson in the lesson list */
476 + toggleLessonPreview( args ) {
477 + const { target } = args;
478 + const elPreviewBtn = target.closest( BuilderTabLesson.selectors.elLessonPreview );
479 + if ( ! elPreviewBtn ) {
480 + return;
481 + }
482 + if (
483 + elPreviewBtn.classList.contains( 'loading' ) ||
484 + elPreviewBtn.classList.contains( 'lp-loading' )
485 + ) {
486 + return;
487 + }
488 +
489 + const elLessonItem = elPreviewBtn.closest( BuilderTabLesson.selectors.elLessonItem );
490 + if ( ! elLessonItem ) {
491 + return;
492 + }
493 +
494 + const icon = elPreviewBtn.querySelector( 'a' );
495 + if ( ! icon ) {
496 + return;
497 + }
498 +
499 + const lessonId = elLessonItem.dataset.lessonId || elPreviewBtn.dataset.id || '';
500 + if ( ! lessonId ) {
501 + return;
502 + }
503 +
504 + // Optimistic toggle
505 + icon.classList.toggle( 'lp-icon-eye' );
506 + icon.classList.toggle( 'lp-icon-eye-slash' );
507 +
508 + const enablePreview = icon.classList.contains( 'lp-icon-eye' );
509 +
510 + lpUtils.lpSetLoadingEl( elPreviewBtn, 1 );
511 + elPreviewBtn.classList.add( 'lp-loading' );
512 +
513 + const dataSend = {
514 + action: 'builder_update_lesson',
515 + args: { id_url: 'builder-update-lesson' },
516 + lesson_id: lessonId,
517 + lesson_settings: true,
518 + _lp_preview: enablePreview ? 'yes' : '',
519 + return_html: 'yes',
520 + };
521 +
522 + const callBack = {
523 + success: ( response ) => {
524 + const { status, message, data } = response;
525 + lpToastify.show( message, status );
526 +
527 + if ( status === 'error' ) {
528 + // Revert on error
529 + icon.classList.toggle( 'lp-icon-eye' );
530 + icon.classList.toggle( 'lp-icon-eye-slash' );
531 + } else if ( data?.list_item_html ) {
532 + this.replaceItemHtml( elLessonItem, data.list_item_html );
533 + }
534 + },
535 + error: ( error ) => {
536 + lpToastify.show( error.message || error, 'error' );
537 + icon.classList.toggle( 'lp-icon-eye' );
538 + icon.classList.toggle( 'lp-icon-eye-slash' );
539 + },
540 + completed: () => {
541 + lpUtils.lpSetLoadingEl( elPreviewBtn, 0 );
542 + elPreviewBtn.classList.remove( 'lp-loading' );
543 + },
544 + };
545 +
546 + window.lpAJAXG.fetchAJAX( dataSend, callBack );
547 + }
548 +
549 + replaceItemHtml( elLesson, html ) {
550 + if ( ! elLesson || ! html ) {
551 + return;
552 + }
553 +
554 + const nextLesson = elLesson.nextElementSibling;
555 + elLesson.insertAdjacentHTML( 'afterend', html.trim() );
556 + const newLesson = elLesson.nextElementSibling;
557 + if ( newLesson && newLesson !== nextLesson ) {
558 + elLesson.remove();
559 + }
560 + }
561 +}