PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.5
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.5
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 / src / js / frontend / course-builder / builder-question / builder-tab-question.js

builder-tab-question.js in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.5, at assets/src/js/frontend/course-builder/builder-question/builder-tab-question.js

468 lines 12.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 BuilderTabQuestion {
7 constructor() {
8 this.init();
9 }
10
11 static selectors = {
12 elQuestionItem: '.question-item',
13 elQuestionExpandedItems: '.question-action-expanded__items',
14 elQuestionDuplicate: '.question-action-expanded__duplicate',
15 elQuestionTrash: '.question-action-expanded__trash',
16 elQuestionRestore: '.question-action-expanded__restore',
17 elQuestionPublish: '.question-action-expanded__publish',
18 elQuestionDelete: '.question-action-expanded__delete',
19 elQuestionActionExpanded: '.question-action-expanded',
20 elQuestionStatus: '.question-status',
21 elBtnEditQuestion: '.btn-edit-question',
22 };
23
24 init() {
25 this.events();
26 }
27
28 events() {
29 if ( BuilderTabQuestion._loadedEvents ) {
30 return;
31 }
32 BuilderTabQuestion._loadedEvents = true;
33
34 lpUtils.eventHandlers( 'click', [
35 {
36 selector: BuilderTabQuestion.selectors.elQuestionDuplicate,
37 class: this,
38 callBack: this.duplicateQuestion.name,
39 },
40 {
41 selector: BuilderTabQuestion.selectors.elQuestionTrash,
42 class: this,
43 callBack: this.trashQuestion.name,
44 },
45 {
46 selector: BuilderTabQuestion.selectors.elQuestionPublish,
47 class: this,
48 callBack: this.publishQuestion.name,
49 },
50 {
51 selector: BuilderTabQuestion.selectors.elQuestionRestore,
52 class: this,
53 callBack: this.restoreQuestion.name,
54 },
55 {
56 selector: BuilderTabQuestion.selectors.elQuestionDelete,
57 class: this,
58 callBack: this.deleteQuestion.name,
59 },
60 {
61 selector: BuilderTabQuestion.selectors.elQuestionActionExpanded,
62 class: this,
63 callBack: this.toggleExpandedAction.name,
64 },
65 {
66 selector: BuilderTabQuestion.selectors.elBtnEditQuestion,
67 class: this,
68 callBack: this.editQuestion.name,
69 },
70 ] );
71
72 document.addEventListener( 'click', ( e ) => {
73 if ( ! e.target.closest( BuilderTabQuestion.selectors.elQuestionActionExpanded ) ) {
74 this.closeAllExpanded();
75 }
76 } );
77 }
78
79 editQuestion( args ) {
80 const { target } = args;
81 const elBtnEditQuestion = target.closest( BuilderTabQuestion.selectors.elBtnEditQuestion );
82
83 if ( ! elBtnEditQuestion ) {
84 return;
85 }
86
87 lpUtils.lpSetLoadingEl( elBtnEditQuestion, 1 );
88 }
89
90 duplicateQuestion( args ) {
91 const { target } = args;
92 const elQuestionDuplicate = target.closest( BuilderTabQuestion.selectors.elQuestionDuplicate );
93 const elQuestionItem = elQuestionDuplicate.closest(
94 BuilderTabQuestion.selectors.elQuestionItem
95 );
96
97 if ( ! elQuestionItem ) {
98 return;
99 }
100
101 const elActionExpanded = elQuestionItem.querySelector(
102 BuilderTabQuestion.selectors.elQuestionActionExpanded
103 );
104 const questionId = elQuestionItem.dataset.questionId || '';
105
106 SweetAlert.fire( {
107 title: elQuestionDuplicate.dataset.title || 'Duplicate Question',
108 text:
109 elQuestionDuplicate.dataset.content || 'Are you sure you want to duplicate this question?',
110 iconHtml: SWAL_ICON_DUPLICATE,
111 customClass: { icon: 'lp-cb-swal-icon-html' },
112 showCloseButton: true,
113 showCancelButton: true,
114 cancelButtonText: lpData.i18n.cancel,
115 confirmButtonText: lpData.i18n.yes,
116 reverseButtons: true,
117 } ).then( ( result ) => {
118 if ( result.isConfirmed ) {
119 lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
120
121 const dataSend = {
122 action: 'duplicate_question',
123 args: {
124 id_url: 'duplicate-question',
125 },
126 question_id: questionId,
127 };
128
129 const callBack = {
130 success: ( response ) => {
131 const { status, message, data } = response;
132 lpToastify.show( message || 'Duplicated successfully!', status );
133
134 if ( status === 'success' && data?.redirect_url ) {
135 window.location.href = data.redirect_url;
136 }
137 },
138 error: ( error ) => {
139 lpToastify.show( error.message || error, 'error' );
140 },
141 completed: () => {
142 lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
143 },
144 };
145
146 window.lpAJAXG.fetchAJAX( dataSend, callBack );
147 }
148 } );
149 }
150
151 trashQuestion( args ) {
152 const { target } = args;
153 const elQuestionTrash = target.closest( BuilderTabQuestion.selectors.elQuestionTrash );
154 const elQuestionItem = elQuestionTrash.closest( BuilderTabQuestion.selectors.elQuestionItem );
155
156 if ( ! elQuestionItem ) {
157 return;
158 }
159
160 const elActionExpanded = elQuestionItem.querySelector(
161 BuilderTabQuestion.selectors.elQuestionActionExpanded
162 );
163 const questionId = elQuestionItem.dataset.questionId || '';
164
165 SweetAlert.fire( {
166 title: elQuestionTrash.dataset.title || 'Trash Question',
167 text:
168 elQuestionTrash.dataset.content || 'Are you sure you want to move this question to trash?',
169 iconHtml: SWAL_ICON_TRASH_DRAFT,
170 customClass: { icon: 'lp-cb-swal-icon-html' },
171 showCloseButton: true,
172 showCancelButton: true,
173 cancelButtonText: lpData.i18n.cancel,
174 confirmButtonText: lpData.i18n.yes,
175 reverseButtons: true,
176 } ).then( ( result ) => {
177 if ( result.isConfirmed ) {
178 lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
179
180 const dataSend = {
181 action: 'move_trash_question',
182 args: {
183 id_url: 'move-trash-question',
184 },
185 question_id: questionId,
186 };
187
188 const callBack = {
189 success: ( response ) => {
190 const { status, message, data } = response;
191 lpToastify.show( message, status );
192
193 if ( data?.html ) {
194 this.replaceItemHtml( elQuestionTrash.closest( '.question' ), data.html );
195 }
196 },
197 error: ( error ) => {
198 lpToastify.show( error.message || error, 'error' );
199 },
200 completed: () => {
201 lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
202 },
203 };
204
205 window.lpAJAXG.fetchAJAX( dataSend, callBack );
206 }
207 } );
208 }
209
210 publishQuestion( args ) {
211 const { target } = args;
212 const elQuestionPublish = target.closest( BuilderTabQuestion.selectors.elQuestionPublish );
213 const elQuestionItem = elQuestionPublish.closest( BuilderTabQuestion.selectors.elQuestionItem );
214
215 if ( ! elQuestionItem ) {
216 return;
217 }
218
219 const elActionExpanded = elQuestionItem.querySelector(
220 BuilderTabQuestion.selectors.elQuestionActionExpanded
221 );
222 lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
223
224 const questionId = elQuestionItem.dataset.questionId || '';
225
226 const dataSend = {
227 action: 'move_trash_question',
228 args: {
229 id_url: 'move-trash-question',
230 },
231 question_id: questionId,
232 status: 'publish',
233 };
234
235 const callBack = {
236 success: ( response ) => {
237 const { status, message, data } = response;
238 lpToastify.show( message, status );
239
240 if ( data?.html ) {
241 this.replaceItemHtml( elQuestionPublish.closest( '.question' ), data.html );
242 }
243 },
244 error: ( error ) => {
245 lpToastify.show( error.message || error, 'error' );
246 },
247 completed: () => {
248 lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
249 },
250 };
251
252 window.lpAJAXG.fetchAJAX( dataSend, callBack );
253 }
254
255 restoreQuestion( args ) {
256 const { target } = args;
257 const elQuestionRestore = target.closest( BuilderTabQuestion.selectors.elQuestionRestore );
258 const elQuestionItem = elQuestionRestore.closest( BuilderTabQuestion.selectors.elQuestionItem );
259
260 if ( ! elQuestionItem ) {
261 return;
262 }
263
264 const elActionExpanded = elQuestionItem.querySelector(
265 BuilderTabQuestion.selectors.elQuestionActionExpanded
266 );
267 lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
268
269 const questionId = elQuestionItem.dataset.questionId || '';
270
271 const dataSend = {
272 action: 'move_trash_question',
273 args: {
274 id_url: 'move-trash-question',
275 },
276 question_id: questionId,
277 status: 'draft',
278 };
279
280 const callBack = {
281 success: ( response ) => {
282 const { status, message, data } = response;
283 lpToastify.show( message, status );
284
285 if ( data?.html ) {
286 this.replaceItemHtml( elQuestionRestore.closest( '.question' ), data.html );
287 }
288 },
289 error: ( error ) => {
290 lpToastify.show( error.message || error, 'error' );
291 },
292 completed: () => {
293 lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
294 },
295 };
296
297 window.lpAJAXG.fetchAJAX( dataSend, callBack );
298 }
299
300 deleteQuestion( args ) {
301 const { target } = args;
302 const elQuestionDelete = target.closest( BuilderTabQuestion.selectors.elQuestionDelete );
303 const elQuestionItem = elQuestionDelete.closest( BuilderTabQuestion.selectors.elQuestionItem );
304
305 if ( ! elQuestionItem ) {
306 return;
307 }
308
309 const elActionExpanded = elQuestionItem.querySelector(
310 BuilderTabQuestion.selectors.elQuestionActionExpanded
311 );
312 const questionId = elQuestionItem.dataset.questionId || '';
313
314 if ( ! questionId ) {
315 return;
316 }
317
318 SweetAlert.fire( {
319 title: elQuestionDelete.dataset.title || 'Delete Question',
320 text:
321 elQuestionDelete.dataset.content ||
322 'Are you sure you want to permanently delete this question?',
323 iconHtml: SWAL_ICON_DELETE,
324 customClass: { icon: 'lp-cb-swal-icon-html' },
325 showCloseButton: true,
326 showCancelButton: true,
327 cancelButtonText: lpData.i18n.cancel,
328 confirmButtonText: lpData.i18n.yes,
329 reverseButtons: true,
330 } ).then( ( result ) => {
331 if ( result.isConfirmed ) {
332 lpUtils.lpSetLoadingEl( elActionExpanded, 1 );
333
334 const dataSend = {
335 action: 'move_trash_question',
336 args: {
337 id_url: 'move-trash-question',
338 },
339 question_id: questionId,
340 status: 'delete',
341 };
342
343 const callBack = {
344 success: ( response ) => {
345 const { status, message } = response;
346 lpToastify.show( message, status );
347
348 if ( status === 'success' ) {
349 const elQuestion = elQuestionDelete.closest( '.question' );
350 elQuestion.style.transition = 'opacity 0.4s ease-out, transform 0.4s ease-out';
351 elQuestion.style.opacity = '0';
352 elQuestion.style.transform = 'translateX(160px)';
353
354 setTimeout( () => {
355 elQuestion.remove();
356 }, 400 );
357 }
358 },
359 error: ( error ) => {
360 lpToastify.show( error.message || error, 'error' );
361 },
362 completed: () => {
363 lpUtils.lpSetLoadingEl( elActionExpanded, 0 );
364 },
365 };
366
367 window.lpAJAXG.fetchAJAX( dataSend, callBack );
368 }
369 } );
370 }
371
372 toggleExpandedAction( args ) {
373 const { target } = args;
374 const elQuestionActionExpanded = target.closest(
375 BuilderTabQuestion.selectors.elQuestionActionExpanded
376 );
377
378 if ( ! elQuestionActionExpanded ) {
379 return;
380 }
381
382 const elQuestionItem = elQuestionActionExpanded.closest(
383 BuilderTabQuestion.selectors.elQuestionItem
384 );
385
386 if ( ! elQuestionItem ) {
387 return;
388 }
389
390 const elExpandedItems = elQuestionItem.querySelector(
391 BuilderTabQuestion.selectors.elQuestionExpandedItems
392 );
393
394 if ( ! elExpandedItems ) {
395 return;
396 }
397
398 this.closeAllExpanded( elExpandedItems );
399 const willOpen = ! elExpandedItems.classList.contains( 'active' );
400
401 if ( willOpen ) {
402 elExpandedItems.classList.add( 'active' );
403 elQuestionActionExpanded.classList.add( 'active' );
404 this.setExpandedDirection( elExpandedItems );
405 } else {
406 elExpandedItems.classList.remove( 'active' );
407 elExpandedItems.classList.remove( 'is-dropup' );
408 elQuestionActionExpanded.classList.remove( 'active' );
409 }
410 }
411
412 closeAllExpanded( excludeElement = null ) {
413 const allExpandedItems = document.querySelectorAll(
414 `${ BuilderTabQuestion.selectors.elQuestionExpandedItems }.active`
415 );
416 allExpandedItems.forEach( ( item ) => {
417 if ( item === excludeElement ) {
418 return;
419 }
420
421 item.classList.remove( 'active' );
422 item.classList.remove( 'is-dropup' );
423
424 const questionItem = item.closest( BuilderTabQuestion.selectors.elQuestionItem );
425
426 if ( ! questionItem ) {
427 return;
428 }
429
430 const expandedBtn = questionItem.querySelector(
431 BuilderTabQuestion.selectors.elQuestionActionExpanded
432 );
433 if ( expandedBtn ) {
434 expandedBtn.classList.remove( 'active' );
435 }
436 } );
437 }
438
439 setExpandedDirection( elExpandedItems ) {
440 if ( ! elExpandedItems ) {
441 return;
442 }
443
444 elExpandedItems.classList.remove( 'is-dropup' );
445
446 const elQuestion = elExpandedItems.closest( '.question' );
447 if ( ! elQuestion ) {
448 return;
449 }
450
451 if ( elQuestion.matches( ':last-child' ) ) {
452 elExpandedItems.classList.add( 'is-dropup' );
453 }
454 }
455
456 replaceItemHtml( elQuestion, html ) {
457 if ( ! elQuestion || ! html ) {
458 return;
459 }
460 const tmp = document.createElement( 'div' );
461 tmp.innerHTML = html;
462 const newEl = tmp.firstElementChild;
463 if ( newEl ) {
464 elQuestion.replaceWith( newEl );
465 }
466 }
467 }
468