PageSourceSearch

https://digbi.net/wp-content/plugins/learndash-advance-quizzes/assets/js/wpProQuiz_front.js?ver=1790454954

js digbi.net collected 2026-10-05 10:58:14 UTC 314,976 bytes, 7,010 lines download raw bytes

1var gumStream;                      //stream from getUserMedia()
2var recorder;                       //WebAudioRecorder object
3var input;                          //MediaStreamAudioSourceNode  we'll be recording
4var blobAudio;
5var record_timeout;
6
7(function ($) {
8    window.func = window.func || {};
9    window.responseHandler = window.responseHandler || {};
10    window.fetchAnswerDataAll = window.fetchAnswerDataAll || {};
11    window.showQuestionList = window.showQuestionList || {};
12    window.checkCorrectIncorrect = window.checkCorrectIncorrect || {};
13    window.registerSolvedQuestion = window.registerSolvedQuestion || {};
14    window.questionTypeHandlers = window.questionTypeHandlers || {};
15    window.nexrQuestionClickedCalled = window.nexrQuestionClickedCalled || {};
16    /**
17     * @memberOf $
18     */
19    $.wpProQuizFront = function (element, options) {
20
21        var $e = $(element);
22        var config = options;
23        var result_settings = {};
24        var plugin = this;
25        var results = new Object();
26        var catResults = new Object();
27        var startTime = 0;
28        var currentQuestion = null;
29        var quizSolved = [];
30        var is_quiz_resume_in_process = "no";
31        var question_resumed = [];
32        var is_resume_save_event_attached = false;
33        var lastButtonValue = '';
34        var inViewQuestions = false;
35        var currentPage = 1;
36        var timespent = 0;
37        var sending_timer = null;
38
39        var cookie_name = '';
40        var cookieSendTimer = false;
41        var cookie_value = '';
42        var cookieExpireDate = 0;
43        var cookieSending = false;
44        var quiz_resume_data = {};
45
46        var bitOptions = {
47            randomAnswer: 0,
48            randomQuestion: 0,
49            disabledAnswerMark: 0,
50            checkBeforeStart: 0,
51            preview: 0,
52            cors: 0,
53            isAddAutomatic: 0,
54            quizSummeryHide: 0,
55            skipButton: 0,
56            reviewQustion: 0,
57            autoStart: 0,
58            forcingQuestionSolve: 0,
59            hideQuestionPositionOverview: 0,
60            formActivated: 0,
61            maxShowQuestion: 0,
62            sortCategories: 0
63        };
64
65        var quizStatus = {
66            isQuizStart: 0,
67            isLocked: 0,
68            loadLock: 0,
69            isPrerequisite: 0,
70            isUserStartLocked: 0
71        };
72
73        /*
74            var QuizRepeats = {
75                quizRepeats: 0,
76                userAttemptsTaken: 0,
77                userAttemptsLeft: 0,
78            };
79        */
80        var globalNames = {
81            check: 'input[name="check"]',
82            next: 'input[name="next"]',
83            tip: 'input[name="tip"]',
84            questionList: '.wpProQuiz_questionList',
85            skip: 'input[name="skip"]',
86            singlePageLeft: 'input[name="wpProQuiz_pageLeft"]',
87            singlePageRight: 'input[name="wpProQuiz_pageRight"]',
88            save: 'input[name="save"]', //Added by webxity
89            resume: 'input[name="resume"]' //Added by webxity
90        };
91
92        var globalElements = {
93            back: $e.find('input[name="back"]'),
94            next: $e.find(globalNames.next),
95            quiz: $e.find('.wpProQuiz_quiz'),
96            questionList: $e.find('.wpProQuiz_list'),
97            results: $e.find('.wpProQuiz_results'),
98            sending: $e.find('.wpProQuiz_sending'),
99            quizStartPage: $e.find('.wpProQuiz_text'),
100            timelimit: $e.find('.wpProQuiz_time_limit'),
101            toplistShowInButton: $e.find('.wpProQuiz_toplistShowInButton'),
102            listItems: $(),
103            save: $(".ld_advance_quiz_save"), //Added by webxity
104            resume: $(".ld_advance_quiz_resume"), //Added by webxity
105            save_as_next: $("#ld_advanced_save_as_next").val() //Added by webxity
106        };
107
108        var toplistData = {
109            token: '',
110            isUser: 0
111        };
112
113        var formPosConst = {
114            START: 0,
115            END: 1
116        };
117
118        var viewedQuestions = [];
119        var checkedQuestions = [];
120        var resumedQuestions = [];
121        var saveQuizTrigger = 'button'; //Added by Webxity to save state trigger source
122
123        //Added by Webxity - Start
124        var retake_quiz_enabled = LDAdvancedQuizVars.retake_quiz_enabled;
125        var quiz_question_timer_enabled = LDAdvancedQuizVars.quiz_disable_question_time_limit === "0";
126        var is_negative_marking_enabled = LDAdvancedQuizVars.is_negative_marking_enabled;
127        var lastViewedQuestion = 0;
128        //Added by Webxity - End
129
130        /**
131         * @memberOf timelimit
132         */
133        // MAIN TIMER (when time_limit_enabled == 'on') - Updated with resume functionality
134        if (LDAdvancedQuizVars.time_limit_enabled == 'on') {
135            var timelimit = {
136                counter: config.timelimit,
137                intervalId: 0,
138                instance: {},
139                _resumedTime: null, // Add resumed time support
140                _isResuming: false, // Add resume mode support
141                _isStarting: false, // Add starting flag
142                // set cookie for different users and different quizzes
143                timer_cookie: 'ldadv-time-limit-' + config.user_id + '-' + config.quizId,
144
145                stop: function () {
146                    if (this.counter) {
147                        // Don't remove cookie when resuming
148                        if (!this._isResuming && !this._isStarting) {
149                            $.removeCookie(this.timer_cookie);
150                        }
151                        window.clearInterval(this.intervalId);
152                        globalElements.timelimit.hide();
153                        this.intervalId = 0;
154                    }
155                },
156
157                // Add method to set resumed time
158                setResumedTime: function(time) {
159                    this._resumedTime = parseFloat(time);
160                    this._isResuming = true;
161                },
162
163                // Add method to manually set resume mode
164                enableResumeMode: function() {
165                    this._isResuming = true;
166                },
167
168                // Add method to disable resume mode
169                disableResumeMode: function() {
170                    this._isResuming = false;
171                },
172
173                // Add method to check if timer is already running
174                isRunning: function() {
175                    return this.intervalId > 0;
176                },
177
178                start: function () {
179                    // Prevent multiple simultaneous starts
180                    if (this._isStarting) {
181                        return;
182                    }
183                    
184                    // If timer is already running and we're not resuming, don't start again
185                    if (this.intervalId > 0 && !this._isResuming) {
186                        return;
187                    }
188
189                    this._isStarting = true;
190
191                    if (!this.counter) {
192                        this._isStarting = false;
193                        return;
194                    }
195
196                    $.cookie.raw = true;
197
198                    var full = this.counter * 1000;
199
200                    // Choose which cookie to read from based on resume mode
201                    var resume_cookie = "ldadv-time-limit-resume-" + config.user_id + "-" + config.quizId;
202                    var current_cookie = this._isResuming ? resume_cookie : this.timer_cookie;
203                    var tick = $.cookie(current_cookie);
204
205                    // Use resumed time if available, otherwise use cookie, otherwise use counter
206                    var limit;
207                    if (this._resumedTime !== null) {
208                        limit = this._resumedTime;
209
210                        // Set the normal timer cookie with resumed time for future updates
211                        $.cookie(this.timer_cookie, this._resumedTime);
212
213                    } else if (tick) {
214                        limit = parseFloat(tick);
215                        // If we read from resume cookie, also set the normal timer cookie
216                        if (current_cookie === resume_cookie) {
217                            $.cookie(this.timer_cookie, tick);
218                        }
219                    } else {
220                        limit = this.counter;
221                    }
222
223                    // Check if we have resumed data from cookie
224                    if (typeof learndash_prepare_quiz_resume_data == 'function') {
225                        var resume_data = learndash_prepare_quiz_resume_data(config);
226                        if (resume_data !== false) {
227                            if (resume_data[this.timer_cookie]) {
228                                limit = resume_data[this.timer_cookie];
229                            }
230                        }
231                    }
232
233                    var x = limit * 1000;
234
235                    var $timeText = globalElements.timelimit.find('span').text(plugin.methode.parseTime(limit));
236                    var $timeDiv = globalElements.timelimit.find('.wpProQuiz_progress');
237
238                    globalElements.timelimit.show();
239
240                    var beforeTime = +new Date();
241                    var self = this;
242
243                    this.intervalId = window.setInterval(function () {
244                        var diff = (+new Date() - beforeTime);
245                        var remainingTime = x - diff;
246
247                        if (diff >= 500) {
248                            tick = remainingTime / 1000;
249                            $timeText.text(plugin.methode.parseTime(Math.ceil(tick)));
250                            // Always update the normal timer cookie during countdown
251                            $.cookie(self.timer_cookie, tick);
252                        }
253
254                        $timeDiv.css('width', (remainingTime / full * 100) + '%');
255
256                        if (remainingTime <= 0) {
257                            self.stop();
258                            plugin.methode.finishQuiz(true);
259                        }
260                    }, 16);
261
262                    // Clear resume-related flags after timer is successfully started
263                    this._resumedTime = null;
264                    this._isResuming = false;
265                    this._isStarting = false;
266
267                    if (config.quiz_resume_enabled === '1' && !cookieSendTimer) {
268                        plugin.methode.startCookieSendTimer();
269                    }
270                },
271
272                pause: function () {
273                    if (this.counter) {
274                        window.clearInterval(this.intervalId);
275                        globalElements.timelimit.hide();
276                        this.intervalId = 0;
277                    }
278                },
279            };
280        } else {
281            //Added by webxity
282            // QUESTION-SPECIFIC TIMER (your existing implementation is already correct)
283            var timelimit = (function () {
284                var _counter = config.timelimit;
285                var _intervalId = 0;
286                var instance = {};
287                var _resumedTime = null;
288                var _isResuming = false;
289                var _isStarting = false;
290                var _currentQuestionId = null; // ADD THIS
291                
292                // Define base cookie name
293                var base_timer_cookie = "ldadv-time-limit-" + config.user_id + "-" + config.quizId;
294                
295                // Function to get question-specific cookie name
296                var getTimerCookie = function(questionId) {
297                    if (questionId) {
298                        return base_timer_cookie + "-q" + questionId;
299                    }
300                    return base_timer_cookie;
301                };
302                
303                instance.setCurrentQuestion = function(questionId) {
304                    _currentQuestionId = questionId;
305                };
306                //Added by webxity
307                
308                // Define both cookie names
309                var timer_cookie = "ldadv-time-limit-" + config.user_id + "-" + config.quizId;
310                var resume_cookie = "ldadv-time-limit-resume-" + config.user_id + "-" + config.quizId;
311                
312                instance.stop = function () {
313                    if (_counter) {
314                        // Only remove the normal timer cookie when not resuming
315                        if (!_isResuming && !_isStarting) {
316                            $.removeCookie(timer_cookie);
317                        }
318                        window.clearInterval(_intervalId);
319                        globalElements.timelimit.hide();
320                        _intervalId = 0;
321                    }
322                };
323                
324                instance.getInterval = function () {
325                    return _intervalId;
326                };
327                
328                instance.pause = function () {
329                    if (_counter) {
330                        window.clearInterval(_intervalId);
331                        globalElements.timelimit.hide();
332                        _intervalId = 0;
333                    }
334                };
335                
336                // Method to set resumed time and enable resume mode
337                instance.setResumedTime = function(time) {
338                    _resumedTime = parseFloat(time);
339                    _isResuming = true;
340                };
341                
342                // Method to manually set resume mode
343                instance.enableResumeMode = function() {
344                    _isResuming = true;
345                };
346                
347                // Method to disable resume mode
348                instance.disableResumeMode = function() {
349                    _isResuming = false;
350                };
351                
352                // Method to check if timer is already running
353                instance.isRunning = function() {
354                    return _intervalId > 0;
355                };
356
357                //Added by webxity                
358                instance.start = function (questionId) {
359                    // Set current question ID if provided
360                    if (questionId) {
361                        _currentQuestionId = questionId;
362                    }
363                    
364                    if (_isStarting) {
365                        return;
366                    }
367                    
368                    if (_intervalId > 0 && !_isResuming) {
369                        return;
370                    }
371                    
372                    _isStarting = true;
373                    
374                    var differnt_limit = $("#ld_advanced_question_time_limit").val();
375                    
376                    if (differnt_limit == 'yes' && quiz_question_timer_enabled) {
377                        _counter = config.timelimit;
378                    }
379                    if (_counter == 0) {
380                        _counter.NaN;
381                    }
382                    
383                    if (!_counter) {
384                        _isStarting = false;
385                        return;
386                    }
387                    
388                    $.cookie.raw = true;
389                    var full = _counter * 1000;
390                    
391                    // Get question-specific cookie name
392                    var timer_cookie = getTimerCookie(_currentQuestionId);
393                    var resume_cookie = getTimerCookie(_currentQuestionId) + "-resume";
394                    
395                    var current_cookie = _isResuming ? resume_cookie : timer_cookie;
396                    var tick = $.cookie(current_cookie);
397                    
398                    var limit;
399                    if (_resumedTime !== null) {
400                        limit = _resumedTime;
401                        $.cookie(timer_cookie, _resumedTime);
402                    } else if (tick) {
403                        limit = parseFloat(tick);
404                        if (current_cookie === resume_cookie) {
405                            $.cookie(timer_cookie, tick);
406                        }
407                    } else {
408                        limit = _counter;
409                    }
410                    
411                    var x = limit * 1000;
412                    var $timeText = globalElements.timelimit
413                        .find("span")
414                        .text(plugin.methode.parseTime(limit));
415                    var $timeDiv = globalElements.timelimit.find(".wpProQuiz_progress");
416                    globalElements.timelimit.show();
417                    var beforeTime = +new Date();
418                    
419                    _intervalId = window.setInterval(function () {
420                        var diff = +new Date() - beforeTime;
421                        var remainingTime = x - diff;
422                        if (diff >= 500) {
423                            tick = remainingTime / 1000;
424                            $timeText.text(plugin.methode.parseTime(Math.ceil(tick)));
425                            // Save with question-specific cookie name
426                            $.cookie(timer_cookie, tick);
427                        }
428                        $timeDiv.css("width", (remainingTime / full) * 100 + "%");
429                        if (remainingTime <= 0) {
430                            instance.stop();
431                            var differnt_limit = $("#ld_advanced_question_time_limit").val();
432                            if (differnt_limit == "yes" && quiz_question_timer_enabled) 
433                                plugin.methode.nextQuestion();
434                            else {
435                                plugin.methode.finishQuiz(true);
436                            }
437                            $(".wp_pro_quiz_message")
438                                .html("")
439                                .css("display", "none");
440                        }
441                    }, 16);
442                    
443                    _resumedTime = null;
444                    _isResuming = false;
445                    _isStarting = false;
446                };
447                //Added by webxity
448
449                return instance;
450            })();
451        }
452        var current_index = 0;
453        //var mySwipe = null;
454        var mySwipe = [];
455        var not_started_yet = true;
456        function myswipefunction() {
457            mySwipe = [];
458            var swipe_elements = document.getElementsByClassName(
459                "laq_advanced_swipe_questions_slides"
460            );
461            for (var i = 0; i < swipe_elements.length; i++) {
462                var swipe_element = swipe_elements[i];
463                var currid = mySwipe.length;
464                mySwipe[currid] = $.laq_slide(
465                    swipe_element,
466                    $e,
467                    plugin.methode,
468                    config
469                );
470            }
471        }
472
473        /**
474         * @memberOf reviewBox
475         */
476        const reviewBox = new (function () {
477            let $contain = [],
478                $cursor = [],
479                $list = [],
480                $items = [];
481            let x = 0,
482                offset = 0,
483                diff = 0,
484                top = 0,
485                max = 0;
486            const itemsStatus = [];
487
488            this.init = function () {
489                $contain = $e.find('.wpProQuiz_reviewQuestion');
490                $cursor = $contain.find('div');
491                $list = $contain.find('ol');
492                $items = $list.children();
493
494                if (config.mode != 2) {
495                    $(
496                        '.wpProQuiz_reviewLegend li.learndash-quiz-review-legend-item-correct'
497                    ).hide();
498                    $(
499                        '.wpProQuiz_reviewLegend li.learndash-quiz-review-legend-item-incorrect'
500                    ).hide();
501                }
502
503                this.reset();
504
505                const resume_data = learndash_prepare_quiz_resume_data(config);
506                if (config.ld_script_debug == true) {
507                    console.log('resume_data[%o]', resume_data);
508                }
509
510                if (typeof resume_data.reviewBox !== 'undefined') {
511                    jQuery(resume_data.reviewBox).each(function (idx, item) {
512                        if (typeof item === 'object') {
513                            const item_tmp = item;
514                            item = {};
515                            if (typeof item_tmp.solved !== 'undefined') {
516                                item.solved = true;
517                            }
518
519                            if (typeof item_tmp.correct !== 'undefined') {
520                                item.correct = true;
521                            }
522
523                            if (typeof item_tmp.incorrect !== 'undefined') {
524                                item.incorrect = true;
525                            }
526
527                            if (typeof item_tmp.skip !== 'undefined') {
528                                item.skip = true;
529                            }
530
531                            if (typeof item_tmp.review !== 'undefined') {
532                                item.review = true;
533                            }
534                        }
535                        itemsStatus[idx] = item;
536                        setColor(idx);
537                    });
538                }
539
540                $cursor.on('mousedown', function (e) {
541                    e.preventDefault();
542                    e.stopPropagation();
543
544                    offset = e.pageY - $cursor.offset().top + top;
545
546                    $(document).on('mouseup.scrollEvent', endScroll);
547                    $(document).on('mousemove.scrollEvent', moveScroll);
548                });
549
550                $items.on('click', function (e) {
551                    plugin.methode.showQuestion($(this).index());
552
553                    if (LDAdvancedQuizVars.time_limit_enabled != 'on') {
554                        //Add by webxity
555                        if (globalElements.save_as_next == "yes") {
556                            var question_id = $e.find(".wpProQuiz_listItem").eq($(this).index()).data('question-meta').question_pro_id;
557                            saveQuizTrigger = "questionsNavigation";
558                            viewedQuestions.push(question_id);
559                            lastViewedQuestion = $(this).index();
560                            plugin.methode.saveQuestionClicked(true);                    }
561                        //Add by webxity end
562                    }
563                });
564
565                $e.on('questionSolved', function (e) {
566                    // Initialize the object if it doesn't exist
567                    if (!itemsStatus[e.values.index]) {
568                        itemsStatus[e.values.index] = {};
569                    }
570                    itemsStatus[e.values.index].solved = e.values.solved;
571                    setColor(e.values.index);
572                    updateItemsStatus();
573                });
574
575                $e.on('questionSolvedCorrect', function (e) {
576                    // Initialize the object if it doesn't exist
577                    if (!itemsStatus[e.values.index]) {
578                        itemsStatus[e.values.index] = {};
579                    }
580                    itemsStatus[e.values.index].correct = true;
581                    setColor(e.values.index);
582                    updateItemsStatus();
583                });
584
585                $e.on('questionSolvedIncorrect', function (e) {
586                    // Initialize the object if it doesn't exist
587                    if (!itemsStatus[e.values.index]) {
588                        itemsStatus[e.values.index] = {};
589                    }
590                    itemsStatus[e.values.index].incorrect = true;
591                    setColor(e.values.index);
592                    updateItemsStatus();
593                });
594
595                $e.on('changeQuestion', function (e) {
596                    // On Matrix sort questions we need to set the sort capture UL to full height.
597                    if (e.values.item[0] != 'undefined') {
598                        const questionItem = e.values.item[0];
599                        plugin.methode.setupMatrixSortHeights();
600                    }
601
602                    $items.removeClass('wpProQuiz_reviewQuestionTarget');
603                    //$items.removeClass('wpProQuiz_reviewQuestionSolved');
604                    //$items.removeClass('wpProQuiz_reviewQuestionReview');
605
606                    $items
607                        .eq(e.values.index)
608                        .addClass('wpProQuiz_reviewQuestionTarget');
609                    //updateItemsStatus();
610
611                    scroll(e.values.index);
612                });
613
614                $e.on('skipQuestion', function (e) {
615                    itemsStatus[e.values.index].skip =
616                        !itemsStatus[e.values.index].skip;
617                    setColor(e.values.index);
618                    updateItemsStatus();
619                });
620
621                $e.on('reviewQuestion', function (e) {
622                    itemsStatus[e.values.index].review =
623                        !itemsStatus[e.values.index].review;
624                    setColor(e.values.index);
625                    updateItemsStatus();
626                });
627
628                /*
629                $contain.on('mousewheel DOMMouseScroll', function(e) {
630                    e.preventDefault();
631
632                    var ev = e.originalEvent;
633                    var w = ev.wheelDelta ? -ev.wheelDelta / 120 : ev.detail / 3;
634                    var plus = 20 * w;
635
636                    var x = top - $list.offset().top  + plus;
637
638                    if(x > max)
639                        x = max;
640
641                    if(x < 0)
642                        x = 0;
643
644                    var o = x / diff;
645
646                    $list.attr('style', 'margin-top: ' + (-x) + 'px !important');
647                    $cursor.css({top: o});
648
649                    return false;
650                });
651                */
652            };
653
654            this.show = function (save) {
655                if (bitOptions.reviewQustion) {
656                    $contain.parent().show();
657                }
658
659                $e.find('.wpProQuiz_reviewDiv .wpProQuiz_button2').show();
660
661                if (save) {
662                    return;
663                }
664
665                $list.attr('style', 'margin-top: 0px !important');
666                $cursor.css({ top: 0 });
667
668                const h = $list.outerHeight();
669                const c = $contain.height();
670                x = c - $cursor.height();
671                offset = 0;
672                max = h - c;
673                diff = max / x;
674
675                //this.reset();
676
677                if (h > 100) {
678                    $cursor.show();
679                }
680
681                top = $cursor.offset().top;
682            };
683
684            this.hide = function () {
685                $contain.parent().hide();
686            };
687
688            this.toggle = function () {
689                if (bitOptions.reviewQustion) {
690                    // The toggle is called after the quiz submit. So we want to hide the 'review' and 'answered' legend items.
691                    $(
692                        '.wpProQuiz_reviewLegend li.learndash-quiz-review-legend-item-current'
693                    ).hide();
694                    $(
695                        '.wpProQuiz_reviewLegend li.learndash-quiz-review-legend-item-review'
696                    ).hide();
697                    $(
698                        '.wpProQuiz_reviewLegend li.learndash-quiz-review-legend-item-answered'
699                    ).hide();
700
701                    // And show the 'correct' and 'incorrect' indicators.
702                    $(
703                        '.wpProQuiz_reviewLegend li.learndash-quiz-review-legend-item-correct'
704                    ).show();
705                    $(
706                        '.wpProQuiz_reviewLegend li.learndash-quiz-review-legend-item-incorrect'
707                    ).show();
708
709                    $contain.parent().toggle();
710                    $items.removeClass('wpProQuiz_reviewQuestionTarget');
711                    $e.find('.wpProQuiz_reviewDiv .wpProQuiz_button2').hide();
712
713                    $list.attr('style', 'margin-top: 0px !important');
714                    $cursor.css({ top: 0 });
715
716                    const h = $list.outerHeight();
717                    const c = $contain.height();
718                    x = c - $cursor.height();
719                    offset = 0;
720                    max = h - c;
721                    diff = max / x;
722
723                    if (h > 100) {
724                        $cursor.show();
725                    }
726
727                    top = $cursor.offset().top;
728                }
729            };
730
731            this.reset = function () {
732                for (let i = 0, c = $items.length; i < c; i++) {
733                    itemsStatus[i] = {};
734                }
735
736                //$items.removeClass('wpProQuiz_reviewQuestionTarget').css('background-color', '');
737                $items.removeClass('wpProQuiz_reviewQuestionTarget');
738                $items.removeClass('wpProQuiz_reviewQuestionSolved');
739                $items.removeClass('wpProQuiz_reviewQuestionReview');
740            };
741
742            function scroll(index) {
743                /*
744                var $item = $items.eq(index);
745                var iTop = $item.offset().top;
746                var cTop = $contain.offset().top;
747                var calc = iTop - cTop;
748
749                if((calc - 4) < 0 || (calc + 32) > 100) {
750                    var x = cTop - $items.eq(0).offset().top - (cTop - $list.offset().top)  + $item.position().top;
751
752                    if(x > max)
753                        x = max;
754
755                    var o = x / diff;
756
757                    $list.attr('style', 'margin-top: ' + (-x) + 'px !important');
758                    $cursor.css({top: o});
759                }
760                */
761            }
762
763            function setColor(index) {
764                const itemStatus = itemsStatus[index];
765
766                $items
767                    .eq(index)
768                    .removeClass(
769                        'wpProQuiz_reviewQuestionSolved wpProQuiz_reviewQuestionReview wpProQuiz_reviewQuestionSkip'
770                    );
771
772                if (0 === Object.keys(itemStatus).length) {
773                    return;
774                }
775
776                let css_class = '';
777
778                if (itemStatus.correct) {
779                    css_class = 'wpProQuiz_reviewQuestionSolvedCorrect';
780                } else if (itemStatus.incorrect) {
781                    css_class = 'wpProQuiz_reviewQuestionSolvedIncorrect';
782                } else if (
783                    itemStatus.solved === true ||
784                    itemStatus.solved === false
785                ) {
786                    css_class = 'wpProQuiz_reviewQuestionSolved';
787                } else if (itemStatus.review) {
788                    css_class = 'wpProQuiz_reviewQuestionReview';
789                } else if (itemStatus.skip) {
790                    css_class = 'wpProQuiz_reviewQuestionSkip';
791                }
792
793                if (css_class != '') {
794                    $items.eq(index).addClass(css_class);
795                }
796            }
797
798            function moveScroll(e) {
799                e.preventDefault();
800
801                let o = e.pageY - offset;
802
803                if (o < 0) {
804                    o = 0;
805                }
806
807                if (o > x) {
808                    o = x;
809                }
810
811                const v = diff * o;
812
813                $list.attr('style', 'margin-top: ' + -v + 'px !important');
814
815                $cursor.css({ top: o });
816            }
817
818            function endScroll(e) {
819                e.preventDefault();
820
821                $(document).unbind('.scrollEvent');
822            }
823
824            function updateItemsStatus() {
825                plugin.methode.saveMetaDataToCookie({ reviewBox: itemsStatus });
826            }
827        })();
828
829        function QuestionTimer() {
830            let questionStartTime = 0;
831            let currentQuestionId = -1;
832            let quizStartTimer = 0;
833            let isQuizStart = false;
834
835            //Added by webxity            
836            this.questionStart = function (questionId) {
837                if (currentQuestionId != -1) {
838                    this.questionStop();
839                }
840                
841                if (LDAdvancedQuizVars.time_limit_enabled != 'on') {
842                    $e.find(".wpProQuiz_questionList").each(function () {
843                        var $this = $(this);
844                        var question_Id = $this.data("question_id");
845                        if (question_Id == questionId) {
846                            var tmLimit = $(this)
847                                .parent(".wpProQuiz_question")
848                                .siblings(".ld_advanced_time_limit")
849                                .val();
850                            config.timelimit = parseInt(tmLimit);
851                        }
852                    });
853                    var differnt_limit = $("#ld_advanced_question_time_limit").val();
854                    if (differnt_limit == "yes" && quiz_question_timer_enabled) {
855                        timelimit.setCurrentQuestion(questionId); // ADD THIS
856                        timelimit.start(questionId); // PASS questionId
857                    }
858                }
859                
860                currentQuestionId = questionId;
861                questionStartTime = +new Date();
862            };
863            //Added by webxity
864
865            this.questionStop = function () {
866                if (currentQuestionId == -1) {
867                    return;
868                }
869                
870                // MISSING CODE FROM SECOND FUNCTION - Advanced time limit stop handling:
871                if (LDAdvancedQuizVars.time_limit_enabled != 'on') {
872                    //Section by webxity
873                    var differnt_limit = $("#ld_advanced_question_time_limit").val();
874                    if (differnt_limit == "yes" && quiz_question_timer_enabled) {
875                        timelimit.stop();
876                    }
877                    //End Section by webxity
878                }
879                
880                results[currentQuestionId].time += Math.round(
881                    (new Date() - questionStartTime) / 1000
882                );
883                currentQuestionId = -1;
884            };
885            
886            this.startQuiz = function () {
887                if (isQuizStart) {
888                    this.stopQuiz();
889                }
890
891                quizStartTimer = +new Date();
892
893                // Use server start time when quiz is resumed.
894                if (
895                    config.quiz_resume_enabled === '1' &&
896                    typeof config.quiz_resume_quiz_started === 'string'
897                ) {
898                    if ('0' !== config.quiz_resume_quiz_started) {
899                        quizStartTimer = parseInt(
900                            config.quiz_resume_quiz_started,
901                            10
902                        );
903                    }
904                }
905
906                isQuizStart = true;
907            };
908            
909            this.getQuizStart = function () {
910                if (!isQuizStart) {
911                    return;
912                }
913                return quizStartTimer;
914            };
915            
916            this.stopQuiz = function () {
917                if (!isQuizStart) {
918                    return;
919                }
920                quizEndTimer = +new Date();
921                results.comp.quizTime += Math.round(
922                    (quizEndTimer - quizStartTimer) / 1000
923                );
924                
925                // MISSING CODE FROM SECOND FUNCTION - Stop timelimit on quiz stop:
926                timelimit.stop();
927                
928                results.comp.quizEndTimestamp = quizEndTimer;
929                results.comp.quizStartTimestamp = quizStartTimer;
930                isQuizStart = false;
931            };
932            
933            this.init = function () {};
934        }
935        
936        const questionTimer = new QuestionTimer();
937
938        var readResponses = function (name, data, $question, $questionList, lockResponse) {
939            //if (config.ld_script_debug == true) {
940            //  console.log('readResponses: name[%o], data[%o], $question[%o], $questionList[%o], lockResponse[%o]', name, data, $question, $questionList, lockResponse);
941            //}
942
943            if (lockResponse == undefined) {
944                lockResponse = true;
945            }
946            // var response = {};
947            Object.assign(window.func, {
948                'singleMulti': function (name, data, $question, $questionList, lockResponse, response = {}) {
949                    var input = $questionList.find('.wpProQuiz_questionInput');
950                    if (lockResponse == true) {
951                        $questionList.find('.wpProQuiz_questionInput').attr('disabled', 'disabled');
952                    }
953                    //$questionList.children().each(function(i) {
954                    // Changed in v2.3 from the above. children() was pickup up some other random HTML elements within the UL like <p></p>.
955                    // Now we are targetting specifically the .wpProQuiz_questionListItem HTML elements.
956                    jQuery('.wpProQuiz_questionListItem', $questionList).each(function (i) {
957                        var $item = $(this);
958                        var index = $item.attr('data-pos');
959                        if (typeof index !== 'undefined') {
960                            response[index] = input.eq(i).is(':checked');
961                        }
962                    });
963                    return response;
964                },
965
966                'sort_answer': function (name, data, $question, $questionList, lockResponse, response = {}) {
967                    var $items = $questionList.children('li.wpProQuiz_questionListItem');
968                    var idx = 0;
969                    $items.each(function (item_idx, item) {
970                        var data_pos = jQuery(item).data('pos');
971                        if (typeof data_pos !== 'undefined') {
972                            response[idx] = data_pos;
973                            idx++;
974                        }
975                    });
976
977                    if (lockResponse == true) {
978                        $questionList.sortable("destroy");
979                    }
980                    return response;
981                },
982
983                'matrix_sort_answer': function (name, data, $question, $questionList, lockResponse, response = {}) {
984                    var $items = $questionList.children();
985                    var matrix = new Array();
986                    statistcAnswerData = { 0: -1 };
987
988                    $items.each(function () {
989                        var $this = $(this);
990                        var id = $this.attr("data-pos");
991                        var $stringUl = $this.find(".wpProQuiz_maxtrixSortCriterion");
992                        var $stringItem = $stringUl.children();
993
994                        if ($stringItem.length)
995                            statistcAnswerData[$stringItem.attr("data-pos")] = id;
996
997                        response = statistcAnswerData;
998                    });
999                    if (lockResponse == true) {
1000                        $question
1001                            .find(
1002                                ".wpProQuiz_sortStringList, .wpProQuiz_maxtrixSortCriterion"
1003                            )
1004                            .sortable("destroy");
1005                    }
1006                    return response;
1007                },
1008
1009                'free_answer': function (name, data, $question, $questionList, lockResponse, response = {}) {
1010                    var $li = $questionList.children();
1011                    var value = $li.find(".wpProQuiz_questionInput").val();
1012                    if (lockResponse == true) {
1013                        $li.find(".wpProQuiz_questionInput").attr("disabled", "disabled");
1014                    }
1015                    response = value;
1016                    return response;
1017                },
1018
1019                'cloze_answer': function (name, data, $question, $questionList, lockResponse, response = {}) {
1020                    response = {};
1021                    $questionList.find(".wpProQuiz_cloze").each(function (i, v) {
1022                        var $this = $(this);
1023                        var cloze = $this.children();
1024                        var input = cloze.eq(0);
1025                        var span = cloze.eq(1);
1026                        var inputText = plugin.methode.cleanupCurlyQuotes(input.val());
1027                        response[i] = inputText;
1028                        if (lockResponse == true) {
1029                            input.attr("disabled", "disabled");
1030                        }
1031                    });
1032                    return response;
1033                },
1034
1035                'assessment_answer': function (name, data, $question, $questionList, lockResponse, response = {}) {
1036                    correct = true;
1037                    var $input = $questionList.find('.wpProQuiz_questionInput');
1038                    if (lockResponse == true) {
1039                        $questionList.find('.wpProQuiz_questionInput').attr('disabled', 'disabled');
1040                    }
1041                    var val = 0;
1042
1043                    $input.filter(":checked").each(function () {
1044                        val += parseInt($(this).val());
1045                    });
1046
1047                    response = val;
1048                    return response;
1049                },
1050
1051                'essay': function (name, data, $question, $questionList, lockResponse, response = {}) {
1052                    var question_id = $question
1053                        .find("ul.wpProQuiz_questionList")
1054                        .data("question_id");
1055                    if (lockResponse == true) {
1056                        $questionList
1057                            .find(".wpProQuiz_questionEssay")
1058                            .attr("disabled", "disabled");
1059                    }
1060
1061                    var essayText = $questionList.find(".wpProQuiz_questionEssay").val();
1062                    var essayFiles = $questionList
1063                        .find("#uploadEssayFile_" + question_id)
1064                        .val();
1065
1066                    if (typeof essayText != "undefined") {
1067                        response = essayText;
1068                    }
1069
1070                    if (typeof essayFiles != "undefined") {
1071                        response = essayFiles;
1072                    }
1073                    return response;
1074                },
1075                'laq_jumbled_sentence': function (name, data, $question, $questionList, lockResponse, response = {}) {
1076                    var question_id = $question
1077                        .find("ul.wpProQuiz_questionList")
1078                        .data("question_id");
1079                    var jumbled = [];
1080                    var is_added_already = [];
1081
1082                    $question.find(".question_options").each(function (i) {
1083                        var $item = $(this);
1084                        var data_id = $item.attr('id');
1085
1086                        if ($item.data('pts_for_each_usage') == 'no') {
1087                            jumbled[jumbled.length] = {
1088                                id: $item.attr("id"),
1089                                name: $item.attr("name"),
1090                                pts_each_usage: $item.data('pts_for_each_usage'),
1091                                option: $item.val(),
1092                                correct: $question
1093                                    .find(".correct_options")
1094                                    .eq(i)
1095                                    .val(),
1096                                pts: $question
1097                                    .find(".correct_points")
1098                                    .eq(i)
1099                                    .val()
1100                            };
1101                        } else {
1102                            if (!in_array(is_added_already, $item.attr('id'))) {
1103                                is_added_already[data_id] = $item.attr('id');
1104                                jumbled[jumbled.length] = {
1105                                    id: $item.attr("id"),
1106                                    name: $item.attr("name"),
1107                                    pts_each_usage: $item.data('pts_for_each_usage'),
1108                                    option: $item.val(),
1109                                    correct: $question
1110                                        .find(".correct_options")
1111                                        .eq(i)
1112                                        .val(),
1113                                    pts: $question
1114                                        .find(".correct_points")
1115                                        .eq(i)
1116                                        .val()
1117                                };
1118                            }
1119                        }
1120                    });
1121                    response = jumbled;
1122
1123                    if (lockResponse == true) {
1124                        $questionList
1125                            .find(".laq_jumbled_sentence_dropdown")
1126                            .attr("disabled", "disabled");
1127                    }
1128                    return response;
1129                },
1130                'laq_jumble_dnd_sentence': function (name, data, $question, $questionList, lockResponse, response = {}) {
1131                    var question_id = $question
1132                        .find("ul.wpProQuiz_questionList")
1133                        .data("question_id");
1134                    var jumbled = [];
1135                    var is_added_already = [];
1136
1137                    $question.find(".ldavq-jumbled-dnd-dropzone").each(function (i) {
1138                        var $item = $(this);
1139                        var data_id = $item.data('id');
1140
1141                        var ld_adv_correct = $question.find('#correct_options' + data_id).val();
1142                        var ld_adv_pts = $question.find('#correct_points' + data_id).val();
1143                        if ($item.data('pts_for_each_usage') == 'no') {
1144                            jumbled[jumbled.length] = {
1145                                id: $item.attr("id"),
1146                                name: $item.attr("name"),
1147                                pts_each_usage: $item.data('pts_for_each_usage'),
1148                                option: $item.val(),
1149                                correct: ld_adv_correct,
1150                                pts: ld_adv_pts
1151                            };
1152                        } else {
1153                            if (!in_array(is_added_already, $item.attr('id'))) {
1154                                is_added_already[data_id] = $item.attr('id');
1155                                jumbled[jumbled.length] = {
1156                                    id: $item.attr("id"),
1157                                    name: $item.attr("name"),
1158                                    pts_each_usage: $item.data('pts_for_each_usage'),
1159                                    option: $item.val(),
1160                                    correct: ld_adv_correct,
1161                                    pts: ld_adv_pts
1162                                };
1163                            }
1164                        }
1165                    });
1166
1167                    response = jumbled;
1168
1169                    if (lockResponse == true) {
1170                        $questionList
1171                            .find(".ldavq-jumbled-dnd-dropzone")
1172                            .attr("disabled", "disabled");
1173                    }
1174                    return response;
1175                },
1176
1177                'laq_swipe_questions': function (name, data, $question, $questionList, lockResponse, response = {}) {
1178                    var question_id = $question
1179                        .find("ul.wpProQuiz_questionList")
1180                        .data("question_id");
1181                    var swipes = [];
1182                    $question.find(".laq_advanced_swipe_selection").each(function (i) {
1183                        var $item = $(this);
1184                        swipes[swipes.length] = {
1185                            id: $item.attr("id"),
1186                            name: $item.attr("name"),
1187                            pts_each_usage: $item.data('pts_for_each_usage'),
1188                            selection: $item.val(),
1189                            attempted: $question
1190                                .find(".laq_advanced_swipe_attempted")
1191                                .eq(i)
1192                                .val(),
1193                            correct: $question
1194                                .find(".laq_advanced_swipe_correct")
1195                                .eq(i)
1196                                .val(),
1197                            pts: $question
1198                                .find(".laq_advanced_swipe_points")
1199                                .eq(i)
1200                                .val()
1201                        };
1202                    });
1203                    response = swipes;
1204                    return response;
1205                },
1206
1207                'laq_calculated_formula': function (name, data, $question, $questionList, lockResponse, response = {}) {
1208                    var question_id = $question
1209                        .find("ul.wpProQuiz_questionList")
1210                        .data("question_id");
1211
1212                    var calculations = [];
1213
1214                    $question
1215                        .find(".laq_advanced_calculated_selection")
1216                        .each(function (i) {
1217                            var $item = $(this);
1218                            var data_id = $item.attr('id');
1219                            calculations[calculations.length] = {
1220                                id: data_id,
1221                                selection: $item.val(),
1222                                correct: $question
1223                                    .find(".laq_advanced_calculated_correct")
1224                                    .eq(i)
1225                                    .val(),
1226                                variables: $question.find('.card_calculation').eq(i).data('formula_values'),
1227                                work: $question
1228                                    .find(".ld-advanced-calculated-work")
1229                                    .eq(i)
1230                                    .val(),
1231                                pts: $question
1232                                    .find(".laq_advanced_calculated_points")
1233                                    .eq(i)
1234                                    .val()
1235                            };
1236                        });
1237
1238
1239                    response = calculations;
1240                    return response;
1241                },
1242                'laq_audio_questions': function (name, data, $question, $questionList, lockResponse, response = {}) {
1243                    var question_id = $question
1244                        .find("ul.wpProQuiz_questionList")
1245                        .data("question_id");
1246                    if (lockResponse == true) {
1247                        $questionList
1248                            .find(".wpProQuiz_questionEssay")
1249                            .attr("disabled", "disabled");
1250                    }
1251                    
1252                    
1253                    var audioFiles = $("#uploadAudioFile_" + question_id).val();
1254                   
1255                    if (typeof audioFiles != "undefined") {
1256                        response = audioFiles;
1257                    }
1258                    return response;
1259                },
1260            });
1261            if (typeof window.func[name] === 'function') {
1262                var responseVal = window.func[name](name, data, $question, $questionList, lockResponse, {});
1263            } else {
1264                console.warn('Handler not found for question type:', name);
1265                var responseVal = {};
1266            }
1267            return { response: responseVal };
1268        };
1269
1270        function in_array(arr, obj) {
1271            for (var i = 0; i < arr.length; i++) {
1272                if (arr[i] == obj) return true;
1273            }
1274        }
1275
1276        // Called from the Cookie handler logic. If the Quiz is loaded and a cookie is present the values of the cookie are used
1277        // to set the Quiz elements here. Once the value is set we call the trigger 'questionSolved' to update the question overview panel.
1278        function setResponse(
1279            question_data,
1280            question_value,
1281            question,
1282            $questionList,
1283            lockQuestion
1284        ) {
1285            var lockQuestion = lockQuestion || false;
1286            if (question_data.type == "single" || question_data.type == "multiple") {
1287                $questionList.children().each(function (i) {
1288                    var $item = $(this);
1289                    var index = $item.attr("data-pos");
1290
1291                    if (question_value[index] != undefined) {
1292                        var index_value = question_value[index];
1293                        if (index_value == true) {
1294                            $(".wpProQuiz_questionInput", $item).prop("checked", "checked");
1295
1296                            $e.trigger({
1297                                type: "questionSolved",
1298                                values: {
1299                                    item: question,
1300                                    index: question.index(),
1301                                    solved: true
1302                                }
1303                            });
1304                        }
1305                    }
1306                });
1307            } else if (question_data.type == "free_answer") {
1308                $questionList.children().each(function (i) {
1309                    var $item = $(this);
1310                    $(".wpProQuiz_questionInput", this).val(question_value);
1311                });
1312                $e.trigger({
1313                    type: "questionSolved",
1314                    values: { item: question, index: question.index(), solved: true }
1315                });
1316            } else if (question_data.type == "sort_answer") {
1317         
1317       jQuery.each(question_value, function (pos, key) {
1318                    var this_li = $('li.wpProQuiz_questionListItem[data-pos="' + key + '"]', $questionList);
1319                    var this_li_inner = $('div.wpProQuiz_sortable', this_li);
1320                    var this_li_inner_value = $(this_li_inner).text();
1321
1322                    jQuery($questionList).append(this_li);
1323
1324                });
1325                $e.trigger({ type: 'questionSolved', values: { item: question, index: question.index(), solved: true } });
1326            } else if (question_data.type == "matrix_sort_answer") {
1327                jQuery.each(question_value, function (pos, key) {
1328                    var question_response_item = $(
1329                        '.wpProQuiz_matrixSortString .wpProQuiz_sortStringList li[data-pos="' +
1330                        pos +
1331                        '"]',
1332                        question
1333                    );
1334                    var question_destination_outer_li = $(
1335                        'li.wpProQuiz_questionListItem[data-pos="' +
1336                        key +
1337                        '"] ul.wpProQuiz_maxtrixSortCriterion',
1338                        $questionList
1339                    );
1340
1341                    jQuery(question_response_item).appendTo(
1342                        question_destination_outer_li
1343                    );
1344                });
1345                $e.trigger({
1346                    type: "questionSolved",
1347                    values: { item: question, index: question.index(), solved: true }
1348                });
1349            } else if (question_data.type == "cloze_answer") {
1350                // Get the input fields within the questionList parent
1351                jQuery('span.wpProQuiz_cloze input[type="text"]', $questionList).each(
1352                    function (index) {
1353                        if (typeof question_value[index] !== "undefined") {
1354                            $(this).val(question_value[index]);
1355                        }
1356                    }
1357                );
1358                $e.trigger({
1359                    type: "questionSolved",
1360                    values: { item: question, index: question.index(), solved: true }
1361                });
1362            } else if (question_data.type == "assessment_answer") {
1363                $('input.wpProQuiz_questionInput[value="' + question_value + '"]', $questionList).attr('checked', 'checked');
1364                // if (lockQuestion) {
1365                    $('.wpProQuiz_questionListItem input[type="radio"][value="' + question_value + '"]').prop('checked', true);
1366                    // navigationElementslockQuestion(question);
1367                // }
1368                $e.trigger({ type: 'questionSolved', values: { item: question, index: question.index(), solved: true } });
1369            } else if (question_data.type == "essay") {
1370                // The 'essay' value is generic. We need to figure out if this is an upload or inline essay.
1371                if (
1372                    $questionList.find('#uploadEssayFile_' + question_data.id)
1373                        .length
1374                ) {
1375                    const question_input = $questionList.find(
1376                        '#uploadEssayFile_' + question_data.id
1377                    );
1378                    $(question_input).val(question_value);
1379                    $('<p>' + basename(question_value) + '</p>').insertAfter(
1380                        question_input
1381                    );
1382                    if (lockQuestion) {
1383                        $questionList
1384                            .find('form[name="uploadEssay"]')
1385                            .css('pointer-events', 'none');
1386                        navigationElementslockQuestion(question);
1387                    }
1388                    $e.trigger({
1389                        type: 'questionSolved',
1390                        values: {
1391                            item: question,
1392                            index: question.index(),
1393                            solved: true,
1394                        },
1395                    });
1396                } else if (
1397                    $questionList.find('.wpProQuiz_questionEssay').length
1398                ) {
1399                    $questionList
1400                        .find('.wpProQuiz_questionEssay')
1401                        .text(learndash_decodeHTML(question_value));
1402                    if (lockQuestion) {
1403                        $questionList
1404                            .find('.wpProQuiz_questionEssay')
1405                            .attr('disabled', 'disabled');
1406                        navigationElementslockQuestion(question);
1407                    }
1408                    $e.trigger({
1409                        type: 'questionSolved',
1410                        values: {
1411                            item: question,
1412                            index: question.index(),
1413                            solved: true,
1414                        },
1415                    });
1416                }
1417                //Added by Webxity
1418            } else if (question_data.type == "laq_jumbled_sentence") {
1419
1420                for (var i = 0; i < question_value.length; i++) {
1421                    var record = question_value[i];
1422                    
1423                    if (record.option != null && record.option != "") {
1424                        // Set value by select name (matches your data: x, y, z)
1425                        $('ul.wpProQuiz_questionList .laq_jumbled_sentence_question select[name="' + record.name + '"]').val(record.option).change();
1426                        
1427                        // Or alternatively, set by select id (since id matches name in your HTML)
1428                        // $('#' + record.id).val(record.option).change();
1429                    }
1430                }
1431
1432                // Trigger the questionSolved event once after all values are set
1433                var hasValidOptions = question_value.some(function(item) {
1434                    return item.option != null && item.option != "";
1435                });
1436
1437                if (hasValidOptions) {
1438                    $e.trigger({
1439                        type: "questionSolved",
1440                        values: { 
1441                            item: question, 
1442                            index: question.index(), 
1443                            solved: true 
1444                        }
1445                    });
1446                }
1447            } else if (question_data.type == "laq_jumble_dnd_sentence") {
1448                // Iterate through each saved value and set the corresponding dropzone
1449                question_value.forEach(function(item, index) {
1450                    var dropzoneId = '#' + item.id;
1451                    $(dropzoneId).val(item.option);
1452                });
1453                $e.trigger({
1454                    type: "questionSolved",
1455                    values: { item: question, index: question.index(), solved: true }
1456                });
1457            } else if (question_data.type == "laq_swipe_questions") {
1458                 if(jQuery('.ld_aq_swipe_controls').length < 1){
1459                    var swipeIndex = 0;
1460                    var swipeControls = `
1461                        <div class="ld_aq_swipe_controls">
1462                            <a href="javascript:void(0);" class="ld_aq_swipe_button ld_aq_swipe_button_restart" data-idx="${swipeIndex}">
1463                                <span class="dashicons dashicons-image-rotate"></span>
1464                            </a>
1465                        </div>
1466                    `;
1467                    $('.ld_aq_swipe_main_wrap').append(swipeControls);
1468                }
1469                
1470                // Get the parent wrapper for this specific question
1471                var $questionParent = question.find('.ld_aq_swipe_main_wrap');
1472                
1473                var cardParents = $questionParent.find('.card_parent').toArray();
1474                cardParents.sort((a, b) => $(b).data('id') - $(a).data('id'));
1475
1476                var totalSlides = question_value.length;
1477                var attemptedCount = 0;
1478
1479                $(cardParents).each(function(index) {
1480                    var match = question_value[index];
1481
1482                    if (match) {
1483                        $questionParent.find('#laq_advanced_swipe_selection' + index).val(match.selection);
1484                        $questionParent.find('#laq_advanced_swipe_attempted' + index).val(match.attempted);
1485
1486                        // Count attempted slides and move them to backup
1487                        if (match.attempted === 'yes') {
1488                            attemptedCount++;
1489                            $questionParent.find('.laq_advanced_swipe_questions_slides_backup').append($(this));
1490                        }
1491                    }
1492                });
1493
1494                // Calculate remaining slides (total - attempted)
1495                var remainingSlides = totalSlides - attemptedCount;
1496                
1497                // Update ONLY the slides count number, not the total
1498                $questionParent.find('.header #laq_slides_count').text(remainingSlides);
1499                
1500                // Trigger solved event only if at least one slide was attempted
1501                if (attemptedCount > 0) {
1502                    $e.trigger({
1503                        type: "questionSolved",
1504                        values: { item: question, index: question.index(), solved: true }
1505                    });
1506                }
1507
1508            } else if (question_data.type == "laq_calculated_formula") {
1509                
1510                // $('.laq_advanced_calculated_selection').each(function(index,value){
1511                //     $(this).val(question_value[index].selection)
1512                // });
1513                // $e.trigger({
1514                //     type: "questionSolved",
1515                //     values: { item: question, index: question.index(), solved: true }
1516                // });
1517            } else if (question_data.type == "laq_audio_questions") {
1518                var $audioSource = $('#audio-source');
1519                var $audioPlayer = $('#ldavq-audio-player');
1520                var $audioDuration = $('#audio-duration');
1521
1522                if(question_value && !$audioSource.attr('src')) { // Check if audio source is already set
1523                    $audioPlayer.show();
1524                    fetch(question_value)
1525                        .then(response => response.blob())
1526                        .then(blob => {
1527                            var blobUrl = URL.createObjectURL(blob);
1528                            $audioSource.attr('src', blobUrl);
1529                            var audioElement = $audioPlayer[0];
1530                            audioElement.load();
1531                            $audioPlayer.on('loadedmetadata', function() {
1532                                var duration = $audioPlayer[0].duration;
1533                                $('#timer_num').text(formatTime(duration));
1534                            });
1535                    });
1536                }
1537
1538                if ($questionList.find("#uploadAudioFile_" + question_data.id).length) {
1539                    var question_input = $questionList.find("#uploadAudioFile_" + question_data.id);
1540                    
1541                    // Check if value is already set to prevent duplicates
1542                    if (!$(question_input).val()) {
1543                        $(question_input).val(question_value);
1544                        $("<p>" + basename(question_value) + "</p>").insertAfter(question_input);
1545                        $e.trigger({
1546                            type: "questionSolved",
1547                            values: { item: question, index: question.index(), solved: true }
1548                        });
1549                    }
1550                }
1551            } else {
1552                //console.log('unsupported type[%o]', question_data.type);
1553                //console.log('setResponse: question_data[%o] question_value[%o] question[%o], $questionList[%o]', question_data, question_value, question, $questionList);
1554            }
1555            // Look up handler dynamically extend for other question types /* added by AR */
1556            const handler = window.responseHandler[question_data.type];
1557            if (handler) {
1558                handler(question_data, question_value, question, $questionList, lockQuestion, $e);
1559            }
1560            function formatTime(seconds) {
1561                const h = Math.floor(seconds / 3600).toString().padStart(2, '0');
1562                const m = Math.floor((seconds % 3600) / 60).toString().padStart(2, '0');
1563                const s = Math.floor(seconds % 60).toString().padStart(2, '0');
1564                return `${h}:${m}:${s}`;
1565            }
1566        }
1567
1568        function basename(path) {
1569            if (path != undefined) {
1570                return path.split("/").reverse()[0];
1571            }
1572            return "";
1573        }
1574
1575        var formClass = {
1576            funcs: {
1577                isEmpty(str) {
1578                    str = str.trim();
1579                    return !str || 0 === str.length;
1580                },
1581            },
1582            typeConst: {
1583                TEXT: 0,
1584                TEXTAREA: 1,
1585                NUMBER: 2,
1586                CHECKBOX: 3,
1587                EMAIL: 4,
1588                YES_NO: 5,
1589                DATE: 6,
1590                SELECT: 7,
1591                RADIO: 8,
1592            },
1593            checkForm() {
1594                let check = true;
1595                const that = this;
1596                $e.find(
1597                    '.wpProQuiz_forms input, .wpProQuiz_forms textarea, .wpProQuiz_forms .wpProQuiz_formFields, .wpProQuiz_forms select'
1598                ).each(function () {
1599                    const $this = $(this);
1600                    const isRequired = $this.data('required') == 1;
1601                    const type = $this.data('type');
1602                    let test = true;
1603                    const value = $this.val().trim();
1604
1605                    switch (type) {
1606                        case that.typeConst.TEXT:
1607                        case that.typeConst.TEXTAREA:
1608                        case that.typeConst.SELECT:
1609                            if (isRequired) {
1610                                test = !that.funcs.isEmpty(value);
1611                            }
1612
1613                            break;
1614                        case that.typeConst.NUMBER:
1615                            if (isRequired || !that.funcs.isEmpty(value)) {
1616                                test =
1617                                    !that.funcs.isEmpty(value) && !isNaN(value);
1618                            }
1619
1620                            break;
1621                        case that.typeConst.EMAIL:
1622                            if (isRequired || !that.funcs.isEmpty(value)) {
1623                                //test = !funcs.isEmpty(value) && new RegExp(/^[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/)
1624                                //      .test(value);
1625
1626                                // Use the same RegEx as the HTML5 email field. Per https://emailregex.com
1627                                test =
1628                                    !that.funcs.isEmpty(value) &&
1629                                    new RegExp(
1630                                        /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
1631                                    ).test(value);
1632                            }
1633
1634                            break;
1635                        case that.typeConst.CHECKBOX:
1636                            if (isRequired) {
1637                                test = $this.is(':checked');
1638                            }
1639
1640                            break;
1641                        case that.typeConst.YES_NO:
1642                        case that.typeConst.RADIO:
1643                            if (isRequired) {
1644                                test =
1645                                    $this
1646                                        .find('input[type="radio"]:checked')
1647                                        .val() !== undefined;
1648                            }
1649
1650                            break;
1651                        case that.typeConst.DATE:
1652                            var num = 0,
1653                                co = 0;
1654
1655                            $this.find('select').each(function () {
1656                                num++;
1657                                co += that.funcs.isEmpty($(this).val()) ? 0 : 1;
1658                            });
1659
1660                            if (isRequired || co > 0) {
1661                                test = num == co;
1662                            }
1663
1664                            break;
1665                    }
1666
1667                    if (test) {
1668                        $this.siblings('.wpProQuiz_invalidate').hide();
1669                    } else {
1670                        check = false;
1671                        $this.siblings('.wpProQuiz_invalidate').show();
1672                    }
1673                });
1674
1675                return check;
1676            },
1677            getFormData() {
1678                const data = {};
1679                const that = this;
1680                $e.find(
1681                    '.wpProQuiz_forms input, .wpProQuiz_forms textarea, .wpProQuiz_forms .wpProQuiz_formFields, .wpProQuiz_forms select'
1682                ).each(function () {
1683                    const $this = $(this);
1684                    const id = $this.data('form_id');
1685                    const type = $this.data('type');
1686
1687                    switch (type) {
1688                        case that.typeConst.TEXT:
1689                        case that.typeConst.TEXTAREA:
1690                        case that.typeConst.SELECT:
1691                        case that.typeConst.NUMBER:
1692                        case that.typeConst.EMAIL:
1693                            data[id] = $this.val();
1694                            break;
1695                        case that.typeConst.CHECKBOX:
1696                            data[id] = $this.is(':checked') ? 1 : 0;
1697                            break;
1698                        case that.typeConst.YES_NO:
1699                        case that.typeConst.RADIO:
1700                            data[id] = $this
1701                                .find('input[type="radio"]:checked')
1702                                .val();
1703                            break;
1704                        case that.typeConst.DATE:
1705                            data[id] = {
1706                                day: $this
1707                                    .find(
1708                                        'select[name="wpProQuiz_field_' +
1709                                            id +
1710                                            '_day"]'
1711                                    )
1712                                    .val(),
1713                                month: $this
1714                                    .find(
1715                                        'select[name="wpProQuiz_field_' +
1716                                            id +
1717                                            '_month"]'
1718                                    )
1719                                    .val(),
1720                                year: $this
1721                                    .find(
1722                                        'select[name="wpProQuiz_field_' +
1723                                            id +
1724                                            '_year"]'
1725                                    )
1726                                    .val(),
1727                            };
1728                            break;
1729                    }
1730                });
1731
1732                return data;
1733            },
1734            saveFormDataToCookie() {
1735                const formData = {};
1736                const that = this;
1737                $e.find(
1738                    '.wpProQuiz_forms input, .wpProQuiz_forms textarea, .wpProQuiz_forms .wpProQuiz_formFields, .wpProQuiz_forms select'
1739                ).each(function () {
1740                    const $this = $(this);
1741                    const id = $this.data('form_id');
1742                    // Don't save duplicated form fields.
1743                    if (typeof id === 'undefined') {
1744                        return;
1745                    }
1746                    const type = $this.data('type');
1747
1748                    formData.id = id;
1749                    switch (type) {
1750                        case that.typeConst.TEXT:
1751                        case that.typeConst.TEXTAREA:
1752                        case that.typeConst.SELECT:
1753                        case that.typeConst.NUMBER:
1754                        case that.typeConst.EMAIL:
1755                            formData.value = $this.val();
1756                            formData.type = type;
1757                            break;
1758                        case that.typeConst.CHECKBOX:
1759                            formData.value = $this.is(':checked') ? 1 : 0;
1760                            formData.type = type;
1761                            break;
1762                        case that.typeConst.YES_NO:
1763                        case that.typeConst.RADIO:
1764                            formData.value = $this
1765                                .find('input[type="radio"]:checked')
1766                                .val();
1767                            formData.type = type;
1768                            break;
1769                        case that.typeConst.DATE:
1770                            formData.value = {
1771                                day: $this
1772                                    .find(
1773                                        'select[name="wpProQuiz_field_' +
1774                                            id +
1775                                            '_day"]'
1776                                    )
1777                                    .val(),
1778                                month: $this
1779                                    .find(
1780                                        'select[name="wpProQuiz_field_' +
1781                                            id +
1782                                            '_month"]'
1783                                    )
1784                                    .val(),
1785                                year: $this
1786                                    .find(
1787                                        'select[name="wpProQuiz_field_' +
1788                                            id +
1789                                            '_year"]'
1790                                    )
1791                                    .val(),
1792                            };
1793                            formData.type = type;
1794                            break;
1795                    }
1796
1797                    plugin.methode.CookieSaveResponse(
1798                        'formData' + formData.id,
1799                        formData.id,
1800                        formData.type,
1801                        formData.value
1802                    );
1803                });
1804            },
1805            setFormDataFromServer() {
1806                if (config.quiz_resume_enabled !== '1') {
1807                    return;
1808                }
1809
1810                if (config.quiz_resume_data == undefined) {
1811                    return;
1812                }
1813
1814                const resume_data = learndash_prepare_quiz_resume_data(config);
1815                if (resume_data === false) {
1816                    return;
1817                }
1818
1819                const that = this;
1820                $e.find(
1821                    '.wpProQuiz_forms input, .wpProQuiz_forms textarea, .wpProQuiz_forms .wpProQuiz_formFields, .wpProQuiz_forms select'
1822                ).each(function () {
1823                    const $this = $(this);
1824                    const id = $this.data('form_id');
1825                    const type = $this.data('type');
1826                    const formId = 'formData' + id;
1827                    if (resume_data[formId]) {
1828                        if (resume_data[formId].type === type) {
1829                            switch (type) {
1830                                case that.typeConst.TEXT:
1831                                case that.typeConst.TEXTAREA:
1832                                case that.typeConst.SELECT:
1833                                case that.typeConst.NUMBER:
1834                                case that.typeConst.EMAIL:
1835                                    var form_value = resume_data[formId].value;
1836                                    form_value =
1837                                        learndash_decodeHTML(form_value);
1838                                    $this.val(form_value);
1839                                    break;
1840                                case that.typeConst.CHECKBOX:
1841                                    if (resume_data[formId].value) {
1842                                        $this.attr('checked', true);
1843                                    }
1844
1845                                    break;
1846                                case that.typeConst.YES_NO:
1847                                case that.typeConst.RADIO:
1848                                    if (resume_data[formId].value) {
1849                                        $this
1850                                            .find(
1851                                                'input[type="radio"][value="' +
1852                                                    resume_data[formId].value +
1853                                                    '"]'
1854                                            )
1855                                            .attr('checked', true);
1856                                    }
1857
1858                                    break;
1859                                case that.typeConst.DATE:
1860                                    $this
1861                                        .find(
1862                                            'select[name="wpProQuiz_field_' +
1863                                                id +
1864                                                '_day"]'
1865                                        )
1866                                        .val(resume_data[formId].value.day);
1867                                    $this
1868                                        .find(
1869                                            'select[name="wpProQuiz_field_' +
1870                                                id +
1871                                                '_month"]'
1872                                        )
1873                                        .val(resume_data[formId].value.month);
1874                                    $this
1875                                        .find(
1876                                            'select[name="wpProQuiz_field_' +
1877                                                id +
1878                                                '_year"]'
1879                                        )
1880                                        .val(resume_data[formId].value.year);
1881
1882                                    break;
1883                            }
1884                        }
1885                    }
1886                });
1887            },
1888        };
1889
1890        var fetchAllAnswerData = function (resultData) {
1891            $e.find(".wpProQuiz_questionList").each(function () {
1892                var $this = $(this);
1893                var questionId = $this.data("question_id");
1894                var type = $this.data("type");
1895                var data = {};
1896                var handler = window.fetchAnswerDataAll[type];
1897                if (type == "single" || type == "multiple") {
1898                    $this.find(".wpProQuiz_questionListItem").each(function () {
1899                        data[$(this).attr("data-pos")] = +$(this)
1900                            .find(".wpProQuiz_questionInput")
1901                            .is(":checked");
1902                    });
1903                } else if (type == "free_answer") {
1904                    data[0] = $this.find(".wpProQuiz_questionInput").val();
1905                } else if (type == "sort_answer") {
1906                    return true;
1907                    //                  $this.find('.wpProQuiz_questionListItem').each(function() {
1908                    //                      data[$(this).index()] = $(this).attr('data-pos');
1909                    //                  });
1910                } else if (type == "matrix_sort_answer") {
1911                    return true;
1912                    //                  $this.find('.wpProQuiz_questionListItem').each(function() {
1913                    //                      data[$(this).attr('data-pos')] = $(this).find('.wpProQuiz_answerCorrect').length;
1914                    //                  });
1915                } else if (type == "cloze_answer") {
1916                    var i = 0;
1917                    $this.find(".wpProQuiz_cloze input").each(function () {
1918                        data[i++] = $(this).val();
1919                    });
1920                } else if (type == "assessment_answer") {
1921                    data[0] = '';
1922
1923                    $this.find('.wpProQuiz_questionInput:checked').each(function () {
1924                        data[$(this).data('index')] = $(this).val();
1925                    });
1926                } else if (type == "essay") {
1927                    return;
1928                } else if (type == "laq_audio_questions") {
1929                    return;
1930                } else if (type == "laq_video_questions") {
1931                    return;
1932                } else if (type == "laq_jumbled_sentence") {
1933                    var i = 0;
1934                    $(this).find('.laq_jumbled_sentence_dropdown').each(function () {
1935
1936                        var option_index = $(this).data('id');
1937
1938                        var ld_adv_q_temp_data = {};
1939
1940                        ld_adv_q_temp_data.id = $(this).attr('id');
1941                        ld_adv_q_temp_data.name = $(this).attr('name');
1942                        ld_adv_q_temp_data.pts_each_usage = $(this).data('pts_for_each_usage');
1943                        ld_adv_q_temp_data.option = $(this).val();
1944                        ld_adv_q_temp_data.correct = $(this).siblings('#correct_options' + option_index).val();
1945                        ld_adv_q_temp_data.pts = $(this).siblings('#correct_options' + option_index).next('#correct_points').val();
1946                        // console.log(ld_adv_q_temp_data);
1947                        data[i++] = ld_adv_q_temp_data;
1948                    });
1949                } else if (type == "laq_jumble_dnd_sentence") {
1950                    var i = 0;
1951                    $(this).find('.ldavq-jumbled-dnd-dropzone').each(function () {
1952
1953                        var option_index = $(this).data('id');
1954
1955                        var ld_adv_q_temp_data = {};
1956                        ld_adv_q_temp_data.id = $(this).attr('id');
1957                        ld_adv_q_temp_data.name = $(this).attr('name');
1958                        ld_adv_q_temp_data.pts_each_usage = $(this).data('pts_for_each_usage');
1959                        ld_adv_q_temp_data.option = $(this).val();
1960                        ld_adv_q_temp_data.correct = $('#laq_jumble_dnd_sentence_' + option_index).find('#correct_options' + option_index).val();
1961                        ld_adv_q_temp_data.pts = $('#laq_jumble_dnd_sentence_' + option_index).find('#correct_points' + option_index).val();
1962
1963                        data[i++] = ld_adv_q_temp_data;
1964                    });
1965                } else if (type == "laq_swipe_questions") {
1966
1967                    var parent_ele = $(this);
1968
1969                    parent_ele.find('.ld_aq_swipe_main_wrap input.laq_advanced_swipe_selection').each(function (index) {
1970                        data[index] = {};
1971
1972                        data[index].selection = $(this).val();
1973                        data[index].attempted = parent_ele.find('.ld_aq_swipe_main_wrap > input.laq_advanced_swipe_attempted:eq("' + index + '")').val();
1974                        data[index].correct = parent_ele.find('.ld_aq_swipe_main_wrap > input.laq_advanced_swipe_correct:eq("' + index + '")').val();
1975                        data[index].pts = parent_ele.find('.ld_aq_swipe_main_wrap > input.laq_advanced_swipe_points:eq("' + index + '")').val();
1976                    });
1977                } else if (type == "laq_calculated_formula") {
1978
1979                    var parent_ele = $this.closest('.wpProQuiz_question');
1980                    
1981                    parent_ele.find('.card_calculation').each(function (index) {
1982                        data[index] = {};
1983                        data[index].id = index;
1984                        data[index].selection = $(this).find('input.laq_advanced_calculated_selection').val();
1985                        data[index].correct = $(this).find('input.laq_advanced_calculated_correct').val();
1986                        data[index].pts = $(this).find('input.laq_advanced_calculated_points').val();
1987                        data[index].variables = $(this).data('formula_values');
1988                        
1989                        const work = $(this).parents('#laq_advanced_calculated_questions_main').find('.ld-advanced-calculated-work').val();
1990                        // Fix: Check if work exists before calling split
1991                        const formattedValues = work ? work.split('\n').map(value => `<br>${value}`).join('') : '';
1992                        data[index].work = formattedValues;
1993                    });
1994
1995                } else if (typeof handler === 'function') {
1996                    const handlerData = handler($this, data);
1997                    data = handlerData !== true ? handlerData : data;
1998                }
1999
2000                res
2000ultData[questionId]["data"] = data;
2001            });
2002        };
2003
2004
2005        plugin.methode = {
2006            /**
2007             * @memberOf plugin.methode
2008             */
2009
2010            parseBitOptions() {
2011                if (config.bo) {
2012                    bitOptions.randomAnswer = config.bo & (1 << 0);
2013                    bitOptions.randomQuestion = config.bo & (1 << 1);
2014                    bitOptions.disabledAnswerMark = config.bo & (1 << 2);
2015                    bitOptions.checkBeforeStart = config.bo & (1 << 3);
2016                    bitOptions.preview = config.bo & (1 << 4);
2017                    bitOptions.isAddAutomatic = config.bo & (1 << 6);
2018                    bitOptions.reviewQustion = config.bo & (1 << 7);
2019                    bitOptions.quizSummeryHide = config.bo & (1 << 8);
2020                    bitOptions.skipButton = config.bo & (1 << 9);
2021                    bitOptions.autoStart = config.bo & (1 << 10);
2022                    bitOptions.forcingQuestionSolve = config.bo & (1 << 11);
2023                    bitOptions.hideQuestionPositionOverview =
2024                        config.bo & (1 << 12);
2025                    bitOptions.formActivated = config.bo & (1 << 13);
2026                    bitOptions.maxShowQuestion = config.bo & (1 << 14);
2027                    bitOptions.sortCategories = config.bo & (1 << 15);
2028
2029                    const cors = config.bo & (1 << 5);
2030
2031                    if (
2032                        cors &&
2033                        jQuery.support != undefined &&
2034                        jQuery.support.cors != undefined &&
2035                        jQuery.support.cors == false
2036                    ) {
2037                        bitOptions.cors = cors;
2038                    }
2039                }
2040            },
2041
2042            setClozeStyle() {
2043                $e.find('.wpProQuiz_cloze input').each(function () {
2044                    const $this = $(this);
2045                    let word = '';
2046                    const wordLen = $this.data('wordlen');
2047
2048                    for (let i = 0; i < wordLen; i++) {
2049                        word += 'w';
2050                    }
2051
2052                    const clone = $(document.createElement('span'))
2053                        .css('visibility', 'hidden')
2054                        .text(word)
2055                        .appendTo($('body'));
2056
2057                    const width = clone.width();
2058
2059                    clone.remove();
2060
2061                    $this.width(width + 5);
2062                });
2063            },
2064
2065            parseTime(sec) {
2066                let seconds = parseInt(sec % 60);
2067                let minutes = parseInt((sec / 60) % 60);
2068                let hours = parseInt((sec / 3600) % 24);
2069
2070                seconds = (seconds > 9 ? '' : '0') + seconds;
2071                minutes = (minutes > 9 ? '' : '0') + minutes;
2072                hours = (hours > 9 ? '' : '0') + hours;
2073
2074                return hours + ':' + minutes + ':' + seconds;
2075            },
2076
2077            cleanupCurlyQuotes(str) {
2078                str = str.replace(/\u2018/, "'");
2079                str = str.replace(/\u2019/, "'");
2080
2081                str = str.replace(/\u201C/, '"');
2082                str = str.replace(/\u201D/, '"');
2083
2084                //return str.trim().toLowerCase();
2085
2086                // Changes in v2.5 to NOT set cloze answers to lowercase
2087                return str.trim();
2088            },
2089
2090            resetMatrix(selector) {
2091                selector.each(function () {
2092                    const $this = $(this);
2093                    const $list = $this.find('.wpProQuiz_sortStringList');
2094
2095                    $this.find('.wpProQuiz_sortStringItem').each(function () {
2096                        $list.append($(this));
2097                    });
2098                });
2099            },
2100
2101            marker(e, correct) {
2102                if (!bitOptions.disabledAnswerMark) {
2103                    if (correct === true) {
2104                        e.addClass('wpProQuiz_answerCorrect');
2105                    } else if (correct === false) {
2106                        e.addClass('wpProQuiz_answerIncorrect');
2107                    } else {
2108                        e.addClass(correct);
2109                    }
2110                }
2111            },
2112            startQuiz(loadData) {
2113                if (config.ld_script_debug == true) {
2114                    console.log('in startQuiz');
2115                }
2116                $('#ld_advance_quiz_resume_start').hide();
2117                if (quizStatus.loadLock) {
2118                    quizStatus.isQuizStart = 1;
2119
2120                    return;
2121                }
2122
2123                quizStatus.isQuizStart = 0;
2124
2125                if (quizStatus.isLocked) {
2126                    globalElements.quizStartPage.hide();
2127                    $e.find('.wpProQuiz_lock').show();
2128
2129                    return;
2130                }
2131
2132                if (quizStatus.isPrerequisite) {
2133                    globalElements.quizStartPage.hide();
2134                    $e.find('.wpProQuiz_prerequisite').show();
2135
2136                    return;
2137                }
2138
2139                if (quizStatus.isUserStartLocked) {
2140                    globalElements.quizStartPage.hide();
2141                    $e.find('.wpProQuiz_startOnlyRegisteredUser').show();
2142
2143                    return;
2144                }
2145
2146                if (bitOptions.maxShowQuestion && !loadData) {
2147                    if (config.formPos == formPosConst.START) {
2148                        if (!formClass.checkForm()) {
2149                            return;
2150                        }
2151                    }
2152
2153                    globalElements.quizStartPage.hide();
2154                    $e.find('.wpProQuiz_loadQuiz').show();
2155
2156                    plugin.methode.loadQuizDataAjax(true);
2157
2158                    return;
2159                }
2160
2161                if (
2162                    bitOptions.formActivated &&
2163                    config.formPos == formPosConst.START
2164                ) {
2165                    if (!formClass.checkForm()) {
2166                        return;
2167                    }
2168                }
2169
2170                plugin.methode.loadQuizData();
2171                quiz_resume_data = learndash_prepare_quiz_resume_data(config);
2172
2173                if (quiz_resume_data === false) {
2174                    quiz_resume_data = {};
2175                }
2176
2177                // Init our Cookies
2178                //if (config.quiz_resume_enabled === "1") {
2179                //  cookie_name = "ld_save_" + config.quizId + "_quiz_responses";
2180                //  plugin.methode.CookieInit();
2181                //} else if (config.timelimitcookie !== 0) {
2182                //  cookie_name = "ld_" + config.quizId + "_quiz_responses";
2183                //  plugin.methode.CookieInit();
2184                //}
2185
2186                questionTimer.startQuiz();
2187
2188                if (
2189                    bitOptions.randomQuestion &&
2190                    jQuery.isEmptyObject(quiz_resume_data) &&
2191                    !quiz_resume_data.randomQuestions
2192                ) {
2193                    plugin.methode.random(
2194                        globalElements.questionList,
2195                        'question'
2196                    );
2197                }
2198
2199                if (bitOptions.randomAnswer) {
2200                    plugin.methode.random($e.find(globalNames.questionList));
2201                }
2202
2203                if (bitOptions.sortCategories) {
2204                    plugin.methode.sortCategories();
2205                }
2206
2207                // randomize the matrix sort question items
2208                plugin.methode.random($e.find('.wpProQuiz_sortStringList'));
2209
2210                // randomize the sort question answers
2211                // MISSING CODE FROM SECOND FUNCTION - ADDING THIS LINE:
2212                plugin.methode.random($e.find('.wpProQuiz_questionList[data-type="sort_answer"]'));
2213
2214                $e.find('.wpProQuiz_listItem').each(function (i, v) {
2215                    const $this = $(this);
2216                    $this
2217                        .find('.wpProQuiz_question_page span:eq(0)')
2218                        .text(i + 1);
2219                    $this.find('> h5 span').text(i + 1);
2220
2221                    $this
2222                        .find('.wpProQuiz_questionListItem')
2223                        .each(function (i, v) {
2224                            $(this)
2225                                .find('> span:not(.wpProQuiz_cloze)')
2226                                .text(i + 1 + '. ');
2227                        });
2228                });
2229
2230                globalElements.next = $e.find(globalNames.next);
2231
2232                switch (config.mode) {
2233                    case 3:
2234                        $e.find('input[name="checkSingle"]').show();
2235                        break;
2236                    case 2:
2237                        $e.find(globalNames.check).show();
2238
2239                        if (
2240                            !bitOptions.skipButton &&
2241                            bitOptions.reviewQustion
2242                        ) {
2243                            $e.find(globalNames.skip).show();
2244                        }
2245
2246                        break;
2247                    case 1:
2248                        $e.find('input[name="back"]').slice(1).show();
2249                    case 0:
2250                        globalElements.next.show();
2251                        break;
2252                }
2253
2254                if (
2255                    bitOptions.hideQuestionPositionOverview ||
2256                    config.mode == 3
2257                ) {
2258                    $e.find('.wpProQuiz_question_page').hide();
2259                }
2260
2261                //Change last name
2262                const $lastButton = globalElements.next.last();
2263                lastButtonValue = $lastButton.val();
2264                $lastButton.val(config.lbn);
2265
2266                const $listItem = globalElements.questionList.children();
2267
2268                globalElements.listItems = $e.find('.wpProQuiz_list > li');
2269
2270                //quiz_resume_data.lastQuestion = parseInt(quiz_resume_data.lastQuestion);
2271
2272                if (
2273                    config.mode === 3 &&
2274                    'number' !== typeof quiz_resume_data.lastQuestion
2275                ) {
2276                    plugin.methode.showSinglePage(0);
2277                }
2278
2279                if ('number' !== typeof quiz_resume_data.lastQuestion) {
2280                    quiz_resume_data.lastQuestion = 0;
2281                }
2282
2283                // Original
2284                /*
2285                if ( config.mode !== 3 ) {
2286                    currentQuestion = $listItem.eq( 0 ).show();
2287                    var questionId = currentQuestion.find( globalNames.questionList ).data( 'question_id' );
2288                    questionTimer.questionStart( questionId );
2289                }
2290                */
2291
2292                if (config.mode !== 3) {
2293                    if (config.ld_script_debug == true) {
2294                        console.log(
2295                            'line 1359: quiz_resume_data.lastQuestion[%o]',
2296                            quiz_resume_data.lastQuestion
2297                        );
2298                    }
2299
2300                    if (quiz_resume_data.lastQuestion > 0) {
2301                        $listItem.each(function (q_idx, q_item) {
2302                            const q_id = $(q_item)
2303                                .find('.wpProQuiz_questionList')
2304                                .data('question_id');
2305
2306                            if (config.ld_script_debug == true) {
2307                                console.log(
2308                                    'q_id[%o] quiz_resume_data.lastQuestion[%o]',
2309                                    q_id,
2310                                    quiz_resume_data.lastQuestion
2311                                );
2312                            }
2313
2314                            if (q_id === quiz_resume_data.lastQuestion) {
2315                                currentQuestion = $listItem.eq(q_idx);
2316                                if (config.ld_script_debug == true) {
2317                                    console.log(
2318                                        'currentQuestion[%o]',
2319                                        currentQuestion
2320                                    );
2321                                    console.log('$listItem[%o]', $listItem);
2322                                }
2323
2324                                //$listItem.eq(q_idx).show();
2325                                return false;
2326                            }
2327                        });
2328                    } else {
2329                        if (config.ld_script_debug == true) {
2330                            console.log(
2331                                'line 1382: ELSE: quiz_resume_data.lastQuestion zero'
2332                            );
2333                            console.log('$listItem[%o]', $listItem);
2334                        }
2335                        currentQuestion = $listItem.eq(0);
2336
2337                        if (config.ld_script_debug == true) {
2338                            console.log('currentQuestion[%o]', currentQuestion);
2339                        }
2340
2341                        $listItem.eq(0).show();
2342                    }
2343                    
2344                    // MISSING CODE FROM SECOND FUNCTION - ADDING questionTimer.questionStart():
2345                    if (LDAdvancedQuizVars.time_limit_enabled != 'on') {
2346                        var questionId = currentQuestion
2347                            .find(globalNames.questionList)
2348                            .data("question_id");
2349                        questionTimer.questionStart(questionId);
2350                    }
2351                } else {
2352                    if (config.ld_script_debug == true) {
2353                        console.log('line 1390: ELSE: condif.mode = 3');
2354                    }
2355                    currentQuestion = $listItem.eq(0);
2356                }
2357                if (config.ld_script_debug == true) {
2358                    console.log('after currentQuestion[%o]', currentQuestion);
2359                }
2360
2361                // MISSING CODE FROM SECOND FUNCTION - SIMPLIFIED SORTABLE HANDLING:
2362                $e.find(".wpProQuiz_sortable")
2363                    .parents("ul")
2364                    .sortable({
2365                        update: function (event, ui) {
2366                            var $p = $(this).parents(".wpProQuiz_listItem");
2367                            $e.trigger({
2368                                type: "questionSolved",
2369                                values: { item: $p, index: $p.index(), solved: true }
2370                            });
2371                        }
2372                    })
2373                    .disableSelection();
2374
2375                // Keep the existing advanced sortable handling from first function:
2376                // Backwards compatibility with templates older than 4.21.3.
2377                $e.find(
2378                    '.wpProQuiz_sortable:not(.ld-sortable__item-handle)'
2379                ).each(function (index, sortableHandle) {
2380                    const $sortable = $(sortableHandle).parents(
2381                        '.wpProQuiz_questionList'
2382                    );
2383
2384                    $sortable
2385                        .sortable({
2386                            scroll: true,
2387                            scrollSensitivity: 10 || config.scrollSensitivity,
2388                            scrollSpeed: 10 || config.scrollSpeed,
2389                            update() {
2390                                const $p = $(this).parents(
2391                                    '.wpProQuiz_listItem'
2392                                );
2393
2394                                $e.trigger({
2395                                    type: 'questionSolved',
2396                                    values: {
2397                                        item: $p,
2398                                        index: $p.index(),
2399                                        solved: true,
2400                                    },
2401                                });
2402                            },
2403                        })
2404                        .disableSelection();
2405                });
2406
2407                $e.find('.ld-sortable--sort_answer').each(function (
2408                    index,
2409                    sortable
2410                ) {
2411                    let instance = sortable?.ldSortable;
2412
2413                    if (!instance) {
2414                        instance =
2415                            learndash.forms.sortable.initSortable(sortable);
2416                    }
2417
2418                    const callback = (container, item) => {
2419                        const $p = $(container).parents('.wpProQuiz_listItem');
2420
2421                        $e.trigger({
2422                            type: 'questionSolved',
2423                            values: {
2424                                item: $p,
2425                                index: $p.index(),
2426                                solved: true,
2427                            },
2428                        });
2429                    };
2430
2431                    instance.on('dropped', callback);
2432                    instance.on('reorder', callback);
2433                });
2434
2435                $e.find(
2436                    '.wpProQuiz_sortStringList, .wpProQuiz_maxtrixSortCriterion'
2437                )
2438                    .sortable({
2439                        connectWith:
2440                            '.wpProQuiz_maxtrixSortCriterion:not(:has(li)), .wpProQuiz_sortStringList',
2441                        placeholder: 'wpProQuiz_placehold',
2442                        scroll: true,
2443                        scrollSensitivity: 10 || config.scrollSensitivity,
2444                        scrollSpeed: 10 || config.scrollSpeed,
2445                        update(event, ui) {
2446                            const $p = $(this).parents('.wpProQuiz_listItem');
2447                            $e.trigger({
2448                                type: 'questionSolved',
2449                                values: {
2450                                    item: $p,
2451                                    index: $p.index(),
2452                                    solved: true,
2453                                },
2454                            });
2455                        },
2456                    })
2457                    .disableSelection();
2458
2459                quizSolved = [];
2460
2461                if (LDAdvancedQuizVars.time_limit_enabled != 'on') {
2462                    //section by webxity;
2463                    var differnt_limit = $("#ld_advanced_question_time_limit").val();
2464
2465                    if (differnt_limit != "yes") {
2466                        timelimit.start();
2467                    } else if (!quiz_question_timer_enabled) {
2468                        timelimit.start();
2469                    }
2470                    //End section by webxity;
2471                } else {
2472                    timelimit.start();
2473                }
2474
2475                startTime = +new Date();
2476
2477                results = {
2478                    comp: { points: 0, correctQuestions: 0, quizTime: 0 },
2479                };
2480
2481                $e.find('.wpProQuiz_questionList').each(function () {
2482                    const questionId = $(this).data('question_id');
2483
2484                    results[questionId] = { time: 0 };
2485                });
2486
2487                catResults = {};
2488
2489                $.each(options.catPoints, function (i, v) {
2490                    catResults[i] = 0;
2491                });
2492
2493                globalElements.quizStartPage.hide();
2494                $e.find('.wpProQuiz_loadQuiz').hide();
2495                globalElements.quiz.show();
2496                reviewBox.show();
2497
2498                // Force restore scroll functionality
2499                setTimeout(function() {
2500                    // Clear any conflicting events
2501                    $(document).off('mousewheel.quiz DOMMouseScroll.quiz wheel.quiz');
2502                    $(window).off('scroll.quiz');
2503                    
2504                    // Reset scroll-blocking CSS
2505                    $('body, html').css({
2506                        'overflow': 'auto',
2507                        'height': 'auto',
2508                        'touch-action': 'auto'
2509                    });
2510                    
2511                    // Clear animation queues that might interfere
2512                    $('html, body').stop(true, true);
2513                    
2514                    // Force cookie save to trigger scroll restoration
2515                    if (config.quiz_resume_enabled === '1' && Ob
2515ject.keys(cookie_value).length > 0) {
2516                        cookieSending = false; // This is what wp_pro_quiz_cookie_save_quiz sets
2517                    }
2518                }, 100);
2519
2520                // UPDATED COOKIE INITIALIZATION - SIMPLIFIED FROM SECOND FUNCTION:
2521                // Init our Cookie
2522                plugin.methode.CookieInit();
2523
2524                // Keep the existing conditional cookie initialization from first function:
2525                if (config.timelimitcookie !== 0) {
2526                    cookie_name = 'ld_' + config.quizId + '_quiz_responses';
2527                    plugin.methode.CookieInit();
2528                }
2529
2530                if (config.quiz_resume_enabled === '1') {
2531                    cookie_name =
2532                        'ld_save_' + config.quizId + '_quiz_responses';
2533                    plugin.methode.CookieInit();
2534                }
2535
2536                //$('li.wpProQuiz_listItem', globalElements.questionList).each( function (idx, questionItem) {
2537                plugin.methode.setupMatrixSortHeights();
2538                //});
2539
2540                if (config.ld_script_debug == true) {
2541                    console.log(
2542                        'currentQuestion.index [%o] currentQuestion[%o]',
2543                        currentQuestion.index(),
2544                        currentQuestion
2545                    );
2546                }
2547                if (config.mode != 3) {
2548                    $e.trigger({
2549                        type: 'changeQuestion',
2550                        values: {
2551                            item: currentQuestion,
2552                            index: currentQuestion.index(),
2553                        },
2554                    });
2555                }
2556                plugin.methode.mark_drag_fill_nav_link();
2557                // $(".laq_advanced_swipe_attempted").val("no");
2558                plugin.methode.load_save_resume();
2559                myswipefunction();
2560            },
2561
2562            // viewUserQuizStatistics: function (button) {
2563            //     //console.log('in viewUserQuizStatistics');
2564
2565            //     var refId = jQuery(button).data("ref_id");
2566            //     //console.log('refId[%o]', refId);
2567            //     var quizId = jQuery(button).data("quiz_id");
2568            //     //console.log('quizId[%o]', quizId);
2569
2570            //     var post_data = {
2571            //         action: "wp_pro_quiz_admin_ajax",
2572            //         func: "statisticLoadUser",
2573            //         data: {
2574            //             quizId: quizId,
2575            //             userId: 0,
2576            //             refId: refId,
2577            //             avg: 0
2578            //         }
2579            //     };
2580
2581            //     jQuery("#wpProQuiz_user_overlay, #wpProQuiz_loadUserData").show();
2582            //     var content = jQuery("#wpProQuiz_user_content").hide();
2583
2584            //     jQuery.ajax({
2585            //         type: "POST",
2586            //         url: WpProQuizGlobal.ajaxurl,
2587            //         dataType: "json",
2588            //         cache: false,
2589            //         data: post_data,
2590            //         error: function (jqXHR, textStatus, errorThrown) { },
2591            //         success: function (reply_data) {
2592            //             if (typeof reply_data.html !== "undefined") {
2593            //                 content.html(reply_data.html);
2594            //                 jQuery("#wpProQuiz_user_content").show();
2595
2596            //                 jQuery("#wpProQuiz_loadUserData").hide();
2597
2598            //                 content.find(".statistic_data").click(function () {
2599            //                     jQuery(this)
2600            //                         .parents("tr")
2601            //                         .next()
2602            //                         .toggle("fast");
2603
2604            //                     return false;
2605            //                 });
2606            //             }
2607            //         }
2608            //     });
2609
2610            //     jQuery("#wpProQuiz_overlay_close").click(function () {
2611            //         jQuery("#wpProQuiz_user_overlay").hide();
2612            //     });
2613            // },
2614
2615            showSingleQuestion(question) {
2616                //console.log('in showSingleQuestion question[%o]', question);
2617
2618                const page = question ? Math.ceil(question / config.qp
2618p) : 1;
2619
2620                if (
2621                    config.mode === 3 &&
2622                    'number' !== typeof quiz_resume_data.lastQuestion
2623                ) {
2624                    this.showSinglePage(page);
2625                } else {
2626                    this.singlePageNavigationQuizResume(question);
2627                }
2628            },
2629            showSinglePage(page) {
2630                $listItem = globalElements.questionList.children().hide();
2631
2632                if (!config.qpp) {
2633                    $listItem.show();
2634
2635                    return;
2636                }
2637
2638                page = page ? +page : 1;
2639
2640                const maxPage = Math.ceil(
2641                    $e.find('.wpProQuiz_list > li').length / config.qpp
2642                );
2643
2644                if (page > maxPage) {
2645                    return;
2646                }
2647
2648                const pl = $e.find(globalNames.singlePageLeft).hide();
2649                const pr = $e.find(globalNames.singlePageRight).hide();
2650                const cs = $e.find('input[name="checkSingle"]').hide();
2651
2652                if (page > 1) {
2653                    pl.val(pl.data('text').replace(/%d/, page - 1)).show();
2654                }
2655
2656                if (page == maxPage) {
2657                    cs.show();
2658                } else {
2659                    pr.val(pr.data('text').replace(/%d/, page + 1)).show();
2660                }
2661
2662                currentPage = page;
2663
2664                const start = config.qpp * (page - 1);
2665
2666                $listItem.slice(start, start + config.qpp).show();
2667                //plugin.methode.scrollTo( globalElements.quizStartPage );
2668
2669                /**
2670                 * LEARNDASH-6591 On Quiz Start the scroll to the top of the page
2671                 * because the quiz element is hidden. So within the scrollTo()
2672                 * function the element position can't determined.
2673                 *
2674                 * Also changed the scroll element to the outer quiz wrapper.
2675                 */
2676                if (globalElements.self !== undefined) {
2677                    if (globalElements.self.is(':hidden')) {
2678                        globalElements.self.show();
2679                    }
2680                    plugin.methode.scrollTo(globalElements.self);
2681                }
2682            },
2683
2684            nextQuestion() {
2685                if (
2686                    config.timelimitcookie !== 0 ||
2687                    config.quiz_resume_enabled === '1'
2688                ) {
2689                    if (
2690                        currentQuestion
2691                            .find(globalNames.next)
2692                            .data('question-lock') === true
2693                    ) {
2694                        plugin.methode.CookieProcessQuestionResponse(
2695                            currentQuestion,
2696                            true
2697                        );
2698                    } else {
2699                        plugin.methode.CookieProcessQuestionResponse(
2700                            currentQuestion
2701                        );
2702                    }
2703                }
2704
2705                if (config.quiz_resume_enabled === '1') {
2706                    // current Question (before pressing Next)
2707                    plugin.methode.saveMetaDataToCookie({
2708                        lastQuestion: jQuery(currentQuestion[0]).data(
2709                            'question-meta'
2710                        ).question_pro_id,
2711                    });
2712
2713                    // next Question
2714                    const nextQuestion = jQuery(currentQuestion.next()[0]);
2715                    if (
2716                        typeof nextQuestion.data('question-meta') !==
2717                        'undefined'
2718                    ) {
2719                        plugin.methode.saveMetaDataToCookie({
2720                            nextQuestion:
2721                                nextQuestion.data('question-meta')
2722                                    .question_pro_id,
2723                        });
2724                    }
2725                }
2726
2727                jQuery('.mejs-pause').trigger('click');
2728                this.showQuestionObject(currentQuestion.next());
2729                if (globalElements.save_as_next == "yes") {
2730                    plugin.methode.saveQuestionClicked(true);
2731                }
2732            },
2733
2734            prevQuestion() {
2735                this.showQuestionObject(currentQuestion.prev());
2736                plugin.methode.mark_drag_fill_nav_link();
2737                plugin.methode.load_save_resume();
2738            },
2739
2740            showQuestion(index) {
2741                const $element = globalElements.listItems.eq(index);
2742
2743                if (config.mode == 3 || inViewQuestions) {
2744                    if (config.qpp) {
2745                        plugin.methode.showSingleQuestion(index + 1);
2746                    }
2747                    plugin.methode.scrollTo($element, 1);
2748                    questionTimer.startQuiz();
2749                    return;
2750                }
2751
2752                this.showQuestionObject($element);
2753            },
2754
2755            showQuestionObject(obj) {
2756                if (config.ld_script_debug == true) {
2757                    //console.trace();
2758                    console.log('showQuestionObject: obj[%o]', obj);
2759                }
2760
2761                // We hide the current question IF it is set.
2762                if (
2763                    typeof currentQuestion !== 'undefined' &&
2764                    currentQuestion.length > 0
2765                ) {
2766                    globalElements.questionList.children().each(function () {
2767                        if (
2768                            $(this).data('question-meta').question_pro_id !==
2769                            currentQuestion.data('question-meta')
2770                                .question_pro_id
2771                        ) {
2772                            $(this).hide();
2773                        }
2774                    });
2775                }
2776
2777                if (
2778                    !obj.length &&
2779                    bitOptions.forcingQuestionSolve &&
2780                    bitOptions.quizSummeryHide &&
2781                    bitOptions.reviewQustion
2782                ) {
2783                    // First get all the questions...
2784                    list = globalElements.questionList.children();
2785
2786                    if (list != null) {
2787                        list.each(function () {
2788                            const $this = $(this);
2789                            const $questionList = $this.find(
2790                                globalNames.questionList
2791                            );
2792                            const question_id =
2793                                $questionList.data('question_id');
2794                            const data =
2795                                config.json[$questionList.data('question_id')];
2796
2797                            // Within the following logic. If the question type is 'sort_answer' there is a chance
2798                            // the sortable answers will be displayed in the correct order. In that case the user will click
2799                            // the next button.
2800                            // The trigger to set the question was answered is normally a function of the sort/drag action
2801                            // by the user. So we need to set the question answered flag in the case the Quiz summary is enabled.
2802                            //if (data.type == 'sort_answer') {
2803                            //  $e.trigger({type: 'questionSolved', values: {item: $this, index: $this.index(), solved: true}});
2804                            //}
2805                        });
2806                    }
2807
2808                    for (
2809                        let i = 0, c = $e.find('.wpProQuiz_listItem').length;
2810                        i < c;
2811                        i++
2812                    ) {
2813                        if (!quizSolved[i]) {
2814                            alert(WpProQuizGlobal.questionsNotSolved);
2815                            return false;
2816                        }
2817                    }
2818                }
2819
2820                //globalElements.questionList.children().hide();
2821                currentQuestion.hide();
2822
2823                currentQuestion = obj.show();
2824
2825                plugin.methode.scrollTo(globalElements.quiz);
2826
2827                $e.trigger({
2828                    type: 'changeQuestion',
2829                    values: {
2830                        item: currentQuestion,
2831                        index: currentQuestion.index(),
2832                    },
2833                });
2834
2835                if (!currentQuestion.length) {
2836                    plugin.methode.showQuizSummary();
2837                } else {
2838                    const questionId = currentQuestion
2839                        .find(globalNames.questionList)
2840                        .data('question_id');
2841                    questionTimer.questionStart(questionId);
2842                }
2843            },
2844
2845            skipQuestion() {
2846                $e.trigger({
2847                    type: 'skipQuestion',
2848                    values: {
2849                        item: currentQuestion,
2850                        index: currentQuestion.index(),
2851                    },
2852                });
2853                plugin.methode.nextQuestion();
2854            },
2855            reviewQuestion() {
2856                $e.trigger({
2857                    type: 'reviewQuestion',
2858                    values: {
2859                        item: currentQuestion,
2860                        index: currentQuestion.index(),
2861                    },
2862                });
2863            },
2864
2865            uploadFile: function (event) {
2866                var question_id = event.currentTarget.id.replace('uploadEssaySubmit_', '');
2867                var file = $('#uploadEssay_' + question_id)[0].files[0];
2868
2869                if (typeof file !== 'undefined') {
2870                    var nonce = $('#_uploadEssay_nonce_' + question_id).val();
2871                    var uploadEssaySubmit = $('#uploadEssaySubmit_' + question_id);
2872
2873                    var uploadEssayMessage = $('#uploadEssayMessage_' + question_id);
2874                    uploadEssayMessage.removeClass('uploadEssayMessage_fail');
2875                    uploadEssayMessage.removeClass('uploadEssayMessage_success');
2876                    uploadEssayMessage.html(config.essayUploading);
2877
2878                    var data = new FormData();
2879                    data.append('action', 'learndash_upload_essay');
2880                    data.append('nonce', nonce);
2881                    data.append('question_id', question_id);
2882                    data.append('course_id', config.course_id);
2883                    data.append('essayUpload', file);
2884
2885                    $.ajax({
2886                        method: 'POST',
2887                        type: 'POST',
2888                        url: WpProQuizGlobal.ajaxurl,
2889                        data: data,
2890                        cache: false,
2891                        contentType: false,
2892                        processData: false,
2893                        success: function (response) {
2894                            // Update the response message. Then later apply the class for the color.
2895                            if (typeof response.data.message !== 'undefined') {
2896                                uploadEssayMessage.html(response.data.message);
2897                            }
2898
2899                            if (response.success == true && typeof response.data.filelink !== 'undefined') {
2900                                uploadEssayMessage.addClass('uploadEssayMessage_success');
2901                                $('#uploadEssayFile_' + question_id).val(response.data.filelink);
2902
2903                                // disable the upload button. Only one file per quiz.
2904                                uploadEssaySubmit.attr('disabled', 'disabled');
2905
2906                                var $item = $('#uploadEssayFile_' + question_id).parents('.wpProQuiz_listItem');
2907                                $e.trigger({ type: 'questionSolved', values: { item: $item, index: $item.index(), solved: true } });
2908                            } else {
2909                                uploadEssayMessage.addClass('uploadEssayMessage_fail');
2910                                uploadEssaySubmit.removeAttr('disabled');
2911                            }
2912                        },
2913                    });
2914                }
2915                event.preventDefault();
2916            },
2917
2918            uploadAudio: function (event) {
2919                
2920                var question_id = event.currentTarget.id.replace('ldavq_submitBtn_', '');
2921                // var question = question.split('_');
2922                // var question_id = question[1];
2923                var nonce = $('#_uploadAudio_nonce_' + question_id).val();
2924                var uploadEssayMessage = $('#uploadAudioMessage_' + question_id);
2925                uploadEssayMessage.removeClass('uploadEssayMessage_fail');
2926                uploadEssayMessage.removeClass('uploadEssayMessage_success');
2927                uploadEssayMessage.html(config.essayUploading);
2928
2929                var form_ = document.getElementById('uploadfile_form');
2930                var data = new FormData(form_);
2931                
2932                data.set("uploadfiles[]", blobAudio, 'recording_audio.mp3');
2933                data.append('action', 'learndash_upload_audio');
2934                data.append('ldavq-audio-player', blobAudio);
2935                data.append('nonce', nonce);
2936                data.append('question_id', question_id);
2937                data.append('course_id', config.course_id);
2938                
2939                $.ajax({
2940                    method: 'POST',
2941                    type: 'POST',
2942                    url: ajax_app.url,
2943                    data: data,
2944                    cache: false,
2945                    contentType: false,
2946                    processData: false,
2947                    success: function (response) {
2948                        
2949                        if (response.success == true && typeof response.data.filelink !== 'undefined') {
2950                            uploadEssayMessage.addClass('uploadEssayMessage_success').html(response.data.message);
2951                            $('#uploadAudioFile_' + question_id).val(response.data.filelink).data('file', response.data);
2952                            var $item = $('#uploadAudioFile_' + question_id).parents('.wpProQuiz_listItem');
2953                            $e.trigger({ type: 'questionSolved', values: { item: $item, index: $item.index(), solved: true } });
2954                        } else {
2955                            uploadEssayMessage.addClass('uploadEssayMessage_fail').html(response.data.message);
2956                        }
2957                    },
2958                    error: function (error) {
2959                        console.error(error);
2960                    }
2961                });
2962                event.preventDefault();
2963            },
2964
2965            showQuizSummary() {
2966                questionTimer.questionStop();
2967                questionTimer.stopQuiz();
2968                cookieSending = true;
2969
2970                if (bitOptions.quizSummeryHide || !bitOptions.reviewQustion) {
2971                    if (
2972                        bitOptions.formActivated &&
2973                        config.formPos == formPosConst.END
2974                    ) {
2975                        reviewBox.hide();
2976                        globalElements.quiz.hide();
2977                        plugin.methode.scrollTo(
2978                            $e.find('.wpProQuiz_infopage').show()
2979                        );
2980                    } else {
2981                        plugin.methode.finishQuiz();
2982                    }
2983
2984                    return;
2985                }
2986
2987                const quizSummary = $e.find('.wpProQuiz_checkPage');
2988
2989                // Clone the Review questions and legand and add to the
2990                //$e.find('.wpProQuiz_checkPage .wpProQuiz_reviewSummary').html('');
2991                $e.find('.wpProQuiz_checkPage .wpProQuiz_reviewSummary').append(
2992                    $e
2993                        .find('.wpProQuiz_reviewDiv .wpProQuiz_reviewQuestion')
2994                        .clone()
2995                );
2996
2997                $e.find('.wpProQuiz_checkPage .wpProQuiz_reviewSummary').append(
2998                    $e
2999                        .find('.wpProQuiz_reviewDiv .wpProQuiz_reviewLegend')
3000                        .clone()
3001                );
3002
3003                $e.find(
3004                    '.wpProQuiz_checkPage .wpProQuiz_reviewSummary .wpProQuiz_reviewQuestion li'
3005                ).removeClass('wpProQuiz_reviewQuestionTarget');
3006
3007                $e.find(
3008                    '.wpProQuiz_checkPage .wpProQuiz_reviewSummary .wpProQuiz_reviewQuestion li'
3009                ).on('click', function (event) {
3010                    $e.find(
3011                        '.wpProQuiz_checkPage .wpProQuiz_reviewSummary'
3012                    ).html('');
3013
3014                    quizSummary.hide();
3015                    globalElements.quiz.show();
3016                    reviewBox.show(true);
3017
3018                    const index = $(this).index();
3019                    plugin.methode.showQuestion(index);
3020                });
3021
3022                let cSolved = 0;
3023
3024                for (let i = 0, c = quizSolved.length; i < c; i++) {
3025                    if (quizSolved[i]) {
3026                        cSolved++;
3027                    }
3028                }
3029
3030                quizSummary.find('span:eq(0)').text(cSolved);
3031
3032                reviewBox.hide();
3033                globalElements.quiz.hide();
3034
3035                quizSummary.show();
3036
3037                plugin.methode.scrollTo(quizSummary);
3038            },
3039
3040
3041            finishQuiz: function (timeover) {
3042                // LEARNDASH-4412 : Disable final buttons on submit.
3043                globalElements.next.last().attr('disabled', 'disabled');
3044                $e.find('input[name="checkSingle"]').attr('disabled', 'disabled');
3045
3046                questionTimer.questionStop();
3047                questionTimer.stopQuiz();
3048                timelimit.stop();
3049
3050                //Added by webxity
3051                plugin.methode.deleteAllTimerCookies();
3052                //Added by webxity
3053
3054                // Clean up resume cookie when quiz is finished
3055                var resume_cookie = "ldadv-time-limit-resume-" + config.user_id + "-" + config.quizId;
3056                $.removeCookie(resume_cookie);
3057                // console.log('Quiz finished - Resume cookie cleaned up:', resume_cookie);
3058
3059                var time = (+new Date() - startTime) / 1000;
3060                time =
3061                    config.timelimit && time > config.timelimit ? config.timelimit : time;
3062                timespent = time;
3063                $e.find(".wpProQuiz_quiz_time span").text(
3064                    plugin.methode.parseTime(time)
3065                );
3066
3067                if (timeover) {
3068                    globalElements.results.find(".wpProQuiz_time_limit_expired").show();
3069                }
3070
3071                plugin.methode.checkQuestion(
3072                    globalElements.questionList.children(),
3073                    true
3074                );
3075            },
3076
3077            finishQuizEnd: function () {
3078                if (config.mode == "2") {
3079                    results.comp.points = 0;
3080                    results.comp.correctQuestions = 0;
3081                    config.globalPoints = 0;
3082                    $.each(results, function (question_id, result) {
3083                        if (question_id != "comp") {
3084                            results.comp.points =
3085                                results.comp.points + parseInt(result.points);
3086                            if (result.correct == 1 || result.correct == "1") {
3087                                results.comp.correctQuestions += 1;
3088                            }
3089
3090                            config.globalPoints =
3091                                config.globalPoints + parseInt(result.possiblePoints);
3092                        }
3093                    });
3094                }
3095
3096                $e.find(".wpProQuiz_correct_answer").text(
3097                    results.comp.correctQuestions
3098                );
3099
3100                results.comp.result =
3101                    Math.round((results.comp.points / config.globalPoints) * 100 * 100) /
3102                    100;
3103
3104                var hasNotGradedQuestion = false;
3105                $.each(results, function () {
3106                    if (
3107                        typeof this.graded_status !== "undefined" &&
3108                        this.graded_status == "not_graded"
3109                    ) {
3110                        hasNotGradedQuestion = true;
3111                    }
3112                });
3113
3114                if (typeof certificate_details !== 'undefined' && certificate_details.certificateLink != undefined && certificate_details.certificateLink != '') {
3115                    var certificateContainer = $e.find('.wpProQuiz_certificate');
3116                    if (results.comp.result >= certificate_details.certificate_threshold * 100) {
3117                        //if (true == hasNotGradedQuestion && typeof certificate_pending !== 'undefined') {
3118                        //  certificateContainer.append('<br />'+certificate_pending );
3119                        //}
3120                        certificateContainer.show();
3121                    } else if (true == hasNotGradedQuestion && typeof certificate_pending !== 'undefined') {
3122                        certificateContainer.html(certificate_pending);
3123                        certificateContainer.show();
3124                    }
3125                }
3126
3127                var quiz_continue_link = $e.find('.quiz_continue_link');
3128
3129                var show_quiz_continue_buttom_on_fail = false;
3130                if (jQuery(quiz_continue_link).hasClass('show_quiz_continue_buttom_on_fail')) {
3131                    show_quiz_continue_buttom_on_fail = true;
3132                }
3133
3134                if ((typeof options.passingpercentage !== 'undefined') && (parseFloat(options.passingpercentage) >= 0.0)) {
3135                    if ((results.comp.result >= options.passingpercentage) || (show_quiz_continue_buttom_on_fail)) {
3136                        $e.addClass('ld-quiz-result').addClass('ld-quiz-result-passed');
3137                        $e.removeClass('ld-quiz-result-failed');
3138
3139                        $e.trigger({ type: 'learndash-quiz-finished', values: { status: 'passed', item: $e, results: results } });
3140                        $e.trigger({ type: 'learndash-quiz-finished-passed', values: { status: 'passed', item: $e, results: results } });
3141
3142                        //For now, Just append the HTML to the page
3143                        if (typeof continue_details !== 'undefined') {
3144                            $e.find('.quiz_continue_link').html(continue_details);
3145                            $e.find('.quiz_continue_link').show();
3146                        }
3147                    } else {
3148                        $e.removeClass('ld-quiz-result-passed');
3149                        $e.addClass('ld-quiz-result').addClass('ld-quiz-result-failed');
3150
3151                        $e.trigger({ type: 'learndash-quiz-finished', values: { status: 'failed', item: $e, results: results } });
3152                        $e.trigger({ type: 'learndash-quiz-finished-failed', values: { status: 'failed', item: $e, results: results } });
3153
3154                        $e.find('.quiz_continue_link').hide();
3155                    }
3156                } else if (typeof continue_details !== 'undefined') {
3157                    $e.find('.quiz_continue_link').html(continue_details);
3158                    $e.find('.quiz_continue_link').show();
3159                }
3160
3161                $pointFields = $e.find(".wpProQuiz_points span");
3162                $gradedPointsFields = $e.find(".wpProQuiz_graded_points span");
3163
3164                $pointFields.eq(0).text(results.comp.points);
3165                $pointFields.eq(1).text(config.globalPoints);
3166                $pointFields.eq(2).text(results.comp.result + "%");
3167
3168                $gradedQuestionCount = 0;
3169                $gradedQuestionPoints = 0;
3170
3171                $.each(results, function (question_id, result) {
3172                    if ($.isNumeric(question_id) && result.graded_id) {
3173                        var possible = result.possiblePoints - result.points;
3174                        if (possible > 0) {
3175                            $gradedQuestionPoints += possible;
3176                            $gradedQuestionCount++;
3177                        }
3178                    }
3179                });
3180
3181                if ($gradedQuestionCount > 0) {
3182                    $(".wpProQuiz_points").hide();
3183                    $(".wpProQuiz_graded_points").show();
3184                    $gradedPointsFields.eq(0).text(results.comp.points);
3185                    $gradedPointsFields.eq(1).text(config.globalPoints);
3186                    $gradedPointsFields.eq(2).text(results.comp.result + "%");
3187                    $gradedPointsFields.eq(3).text($gradedQuestionCount);
3188                    $gradedPointsFields.eq(4).text($gradedQuestionPoints);
3189                }
3190
3191                $e.find(".wpProQuiz_resultsList > li")
3192                    .eq(plugin.methode.findResultIndex(results.comp.result))
3193                    .show();
3194
3195                plugin.methode.setAverageResult(results.comp.result, false);
3196
3197                this.setCategoryOverview();
3198
3199                plugin.methode.sendCompletedQuiz();
3200
3201                if (bitOptions.isAddAutomatic && toplistData.isUser) {
3202                    plugin.methode.addToplist();
3203                }
3204
3205                reviewBox.hide();
3206
3207                $e.find(".wpProQuiz_checkPage, .wpProQuiz_infopage").hide();
3208                globalElements.quiz.hide();
3209            },
3210
3211            sending: function (start, end, step_size) {
3212                globalElements.sending.show();
3213                var sending_progress_bar = globalElements.sending.find(
3214                    ".sending_progress_bar"
3215                );
3216                var i;
3217                if (typeof start == undefined || start == null) {
3218                    i =
3219                        parseInt(
3220                            (sending_progress_bar.width() * 100) /
3221                            sending_progress_bar.offsetParent().width()
3222                        ) + 156;
3223                } else i = start;
3224
3225                if (end == undefined) var end = 80;
3226
3227                if (step_size == undefined) step_size = 1;
3228
3229                if (sending_timer != null && typeof sending_timer != undefined) {
3230                    clearInterval(sending_timer);
3231                }
3232                sending_timer = setInterval(function () {
3233                    var currentWidth = parseInt(sending_progress_bar.width() * 100 / sending_progress_bar.offsetParent().width());
3234                    if (currentWidth >= end) {
3235                        clearInterval(sending_timer);
3236                        if (currentWidth >= 100) {
3237                            setTimeout(plugin.methode.showResults(), 2000);
3238                        }
3239                    }
3240                    sending_progress_bar.css('width', i + '%');
3241                    i = i + step_size;
3242                }, 300);
3243            },
3244
3245            showResults: function () {
3246                globalElements.sending.hide();
3247                globalElements.results.show();
3248                $('.audio-container').hide();
3249                plugin.methode.scrollTo(globalElements.results);
3250            },
3251
3252            setCategoryOverview: function () {
3253                results.comp.cats = {};
3254                $e.find(".wpProQuiz_catOverview li").each(function () {
3255                    var $this = $(this);
3256                    var catId = $this.data("category_id");
3257                    if (config.catPoints[catId] === undefined) {
3258                        $this.hide();
3259                        return true;
3260                    }
3261
3262                    var r =
3263                        Math.round(
3264                            (catResults[catId] / config.catPoints[catId]) * 100 * 100
3265                        ) / 100;
3266
3267                    results.comp.cats[catId] = r;
3268
3269                    $this.find(".wpProQuiz_catPercent").text(r + "%");
3270
3271                    $this.show();
3272                });
3273            },
3274
3275            questionSolved: function (e) {
3276                //if (config.ld_script_debug == true) {
3277                //  console.log('questionSolved: e.values[%o]', e.values);
3278                //}
3279                if (typeof e.values.item.data('question-meta') != 'undefined') {
3280                    var question_id = e.values.item.data('question-meta').question_pro_id;
3281
3282                    viewedQuestions.push(question_id);
3283                }
3284                lastViewedQuestion = e.values.index;
3285                saveQuizTrigger = 'button';
3286                quizSolved[e.values.index] = e.values.solved;
3287            },
3288            sendCompletedQuiz: function () {
3289                if (bitOptions.preview) return;
3290                fetchAllAnswerData(results);
3291                var formData = formClass.getFormData();
3292                $.each(results, function (question_id, result) {
3293                    if (results[question_id].data == null) {
3294                        results[question_id].data = [];
3295                    }
3296                });
3297                
3298                jQuery.ajax({
3299                    type: 'POST',
3300                    url: WpProQuizGlobal.ajaxurl,
3301                    dataType: "json",
3302                    cache: false,
3303                    data: { 
3304                        action: "wp_pro_quiz_completed_quiz",
3305                        course_id: config.course_id,
3306                        lesson_id: config.lesson_id,
3307                        topic_id: config.topic_id,
3308                        quiz: config.quiz,
3309                        quizId: config.quizId,
3310                        results: JSON.stringify(results),
3311                        res2: JSON.stringify(results),
3312                        timespent: timespent,
3313                        forms: formData,
3314                        quiz_nonce: config.quiz_nonce
3315                    },
3316                    success: function (json) {
3317                        if (json != null) {
3318                            if (typeof config['quizId'] !== 'undefined') {
3319                                var quiz_pro_id = parseInt(config['quizId']);
3320                                if ((typeof json[quiz_pro_id] !== 'undefined') && (typeof json[quiz_pro_id]['quiz_result_settings'] !== 'undefined')) {
3321                                    result_settings = json[quiz_pro_id]['quiz_result_settings'];
3322                                    plugin.methode.afterSendUpdateIU(result_settings);
3323                                }
3324                            }
3325                        }
3326                        plugin.methode.sending(null, 100, 15); //Complete the remaining progress bar faster and show results
3327
3328                        //code by webxity
3329                        // console.log('hello');console.log(json);
3330                        if (
3331                            typeof json.total_quiz_correct !== "undefined" &&
3332                            typeof json.total_quiz_questions !== "undefined"
3333                        ) {
3334                            $e.find(".wpProQuiz_correct_answer").text(
3335                                json.total_quiz_correct
3336                            );
3337                            $e.find(".wpProQuiz_correct_answer")
3338                                .next("span")
3339                                .text(json.total_quiz_questions);
3340
3341                            $pointFields = $e.find(".wpProQuiz_points span");
3342
3343                            $pointFields.eq(0).text(json.points);
3344                            $pointFields.eq(1).text(json.globalPoints);
3345                            $pointFields.eq(2).text(json.result + "%");
3346                        }
3347
3348                        if (retake_quiz_enabled === '1') {
3349                            plugin.methode.setRetakeResult(results, timespent, formData);
3350                        }
3351                        //code by webxity end
3352
3353                        // Clear Cookie on restart
3354                        plugin.methode.CookieDelete();
3355
3356                        //Added by webxity
3357                        plugin.methode.deleteAllTimerCookies();
3358                        //Added by webxity
3359
3360                    }
3361                });
3362            },
3363
3364            setRetakeResult: function (results, timespent, formData) {
3365                jQuery.ajax({
3366                    type: 'POST',
3367                    url: WpProQuizGlobal.ajaxurl,
3368                    dataType: "json",
3369                    cache: false,
3370                    data: {
3371                        action: 'ld_rq_set_retake_result',
3372                        course_id: config.course_id,
3373                        lesson_id: config.lesson_id,
3374                        topic_id: config.topic_id,
3375                        quiz: config.quiz,
3376                        quizId: config.quizId,
3377                        results: JSON.stringify(results),
3378                        timespent: timespent,
3379                        forms: formData,
3380                        quiz_nonce: config.quiz_nonce,
3381                    },
3382                    success: function (json) {
3383                        if ((typeof json.total_quiz_correct !== 'undefined') && (typeof json.total_quiz_questions !== 'undefined')) {
3384
3385                            $e.find('.wpProQuiz_correct_answer').text(json.total_quiz_correct);
3386                            $e.find('.wpProQuiz_correct_answer').next('span').text(json.total_quiz_questions);
3387
3388                            $pointFields = $e.find('.wpProQuiz_points span');
3389
3390                            $pointFields.eq(0).text(json.points);
3391                            $pointFields.eq(1).text(json.globalPoints);
3392                            $pointFields.eq(2).text(json.result + '%');
3393                        }
3394                    }
3395                });
3396            },
3397
3398            afterSendUpdateIU: function (quiz_result_settings) {
3399
3400                if (typeof quiz_result_settings["showAverageResult"] !== "undefined") {
3401                    if (!quiz_result_settings["showAverageResult"]) {
3402                        $e.find(".wpProQuiz_resultTable").remove();
3403                    }
3404                }
3405
3406                if (typeof quiz_result_settings["showCategoryScore"] !== "undefined") {
3407                    if (!quiz_result_settings["showCategoryScore"]) {
3408                        $e.find(".wpProQuiz_catOverview").remove();
3409                    }
3410                }
3411
3412                if (
3413                    typeof quiz_result_settings["showRestartQuizButton"] !== "undefined"
3414                ) {
3415                    if (!quiz_result_settings["showRestartQuizButton"]) {
3416                        $e.find('input[name="restartQuiz"]').remove();
3417                    }
3418                }
3419
3420                if (typeof quiz_result_settings["showResultPoints"] !== "undefined") {
3421                    if (!quiz_result_settings["showResultPoints"]) {
3422                        $e.find(".wpProQuiz_points").remove();
3423                    }
3424                }
3425
3426                if (typeof quiz_result_settings["showResultQuizTime"] !== "undefined") {
3427                    if (!quiz_result_settings["showResultQuizTime"]) {
3428                        $e.find(".wpProQuiz_quiz_time").remove();
3429                    }
3430                }
3431
3432                if (
3433                    typeof quiz_result_settings["showViewQuestionButton"] !== "undefined"
3434                ) {
3435                    if (!quiz_result_settings["showViewQuestionButton"]) {
3436                        $e.find('input[name="reShowQuestion"]').remove();
3437                    }
3438                }
3439
3440                if (typeof quiz_result_settings["showContinueButton"] !== "undefined") {
3441                    if (!quiz_result_settings["showContinueButton"]) {
3442                        $e.find(".quiz_continue_link").remove();
3443                    }
3444                }
3445            },
3446            findResultIndex: function (p) {
3447                var r = config.resultsGrade;
3448                var index = -1;
3449                var diff = 999999;
3450
3451                for (var i = 0; i < r.length; i++) {
3452                    var v = r[i];
3453
3454                    if (p >= v && p - v < diff) {
3455                        diff = p - v;
3456                        index = i;
3457                    }
3458                }
3459
3460                return index;
3461            },
3462
3463            showQustionList: function () {
3464                inViewQuestions = !inViewQuestions;
3465                globalElements.toplistShowInButton.hide();
3466                globalElements.quiz.toggle();
3467                $e.find('.wpProQuiz_QuestionButton').hide();
3468                globalElements.questionList.children().show();
3469                reviewBox.toggle();
3470
3471                //Added by Webxity
3472                $e.find(".ld_advance_quiz_resume").hide();
3473                $e.find(".ld_advance_quiz_save").hide();
3474                $(".laq_advanced_swipe_questions_slides_wrapper").css(
3475                    "display",
3476                    "none"
3477                );
3478                $(".laq_total_slides_wrap").css("display", "none");
3479                $(".laq_swipe_buttons_wrap").css("display", "none");
3480
3481                $(".swipe_question_note").css("display", "none");
3482                $(".laq_advanced_swipe_questions_slides_backup").css(
3483                    "display",
3484                    "block"
3485                );
3486                if (!bitOptions.disabledAnswerMark) {
3487                    $(".laq_advanced_swipe_questions_slides_backup .card_parent").each(function (index) {
3488                        var parent_node = $(this).parent().parent();
3489                        var idex = $(this).data("id");
3490                        idex = parseInt(idex) - 1;
3491                        var correct = parent_node.find("#laq_advanced_swipe_correct" + idex).val();
3492                        var selection = parent_node.find("#laq_advanced_swipe_selection" + idex).val();
3493                        var attempted = parent_node.find("#laq_advanced_swipe_attempted" + idex).val();
3494                        if (attempted == "yes") {
3495                            if (correct == selection) {
3496                                $(this).addClass("wpProQuiz_answerCorrect").css("margin", "5px");
3497                            } else {
3498                                $(this).addClass("wpProQuiz_answerIncorrect").css("margin", "5px");
3499                            }
3500                        }
3501                    });
3502                    
3503                    $(".card_calculation").each(function (index) {
3504                        var correct = $(this).find("#laq_advanced_calculated_correct").val();
3505                        var selection = $(this).find("#laq_advanced_calculated_selection").val();
3506                        
3507                        // Normalize both values by removing commas for comparison
3508                        var normalizedCorrect = correct ? correct.replace(/,/g, '') : '';
3509                        var normalizedSelection = selection ? selection.replace(/,/g, '') : '';
3510                        
3511                        if (normalizedCorrect == normalizedSelection) {
3512                            $(this).addClass("wpProQuiz_answerCorrect").css("margin", "5px");
3513                        } else {
3514                            $(this).addClass("wpProQuiz_answerIncorrect").css("margin", "5px");
3515                        }
3516                    });
3517
3518                    
3519                    $(".laq_jumbled_sentence_question select").each(function (index) {
3520                        var parent_node = $(this).parents(".laq_jumbled_sentence_question");
3521                        var idx = $(this).data("id");
3522                        var correct = parent_node.find("#correct_options" + idx).val();
3523                        var selection = $(this).val().trim();
3524                        var correct_array = correct.trim().split('|');
3525                        if ($.inArray(selection, correct_array) >= 0) {
3526                            $(this).addClass("wpProQuiz_answerCorrect").css("margin", "5px");
3527                        } else {
3528                            $(this).addClass("wpProQuiz_answerIncorrect").css("margin", "5px");
3529                        }
3530                    });
3531                    
3532                    $(".ldavq-jumbled-dnd-dropzone").each(function (index) {
3533                        var parent_node = $(this).parents(".laq_jumble_dnd_sentence_question");
3534                        var idx = $(this).data("id");
3535                        var correct = parent_node.find("#correct_options" + idx).val();
3536                        var selection = $(this).val();
3537                        if (correct.replace(/[^a-zA-Z0-9]/g, '') == selection.replace(/[^a-zA-Z0-9]/g, '')) {
3538                            $(this).addClass("wpProQuiz_answerCorrect").css("margin", "5px");
3539                        } else {
3540                            $(this).addClass("wpProQuiz_answerIncorrect").css("margin", "5px");
3541                        }
3542                    });
3543                    if(Object.keys(window.showQuestionList).length > 0){
3544                        Object.keys(window.showQuestionList).forEach(function (key) {
3545                            let fn = window.showQuestionList[key];
3546                            if (typeof fn === 'function') {
3547                                fn($e); // run it
3548                            }
3549                        });
3550                    }
3551                }
3552                //End Added by Webxity
3553
3554                $e.find(".wpProQuiz_question_page").hide();
3555            },
3556
3557            random: function (group) {
3558                group.each(function () {
3559                    var e = $(this)
3560                        .children()
3561                        .get()
3562                        .sort(function () {
3563                            return Math.round(Math.random()) - 0.5;
3564                        });
3565                    if (e) {
3566                        if (e[0]) {
3567                            $(e).appendTo(e[0].parentNode);
3568                        }
3569                    }
3570                });
3571            },
3572
3573            sortCategories: function () {
3574                var e = $(".wpProQuiz_list")
3575                    .children()
3576                    .get()
3577                    .sort(function (a, b) {
3578                        var aQuestionId = $(a)
3579                            .find(".wpProQuiz_questionList")
3580                            .data("question_id");
3581                        var bQuestionId = $(b)
3582                            .find(".wpProQuiz_questionList")
3583                            .data("question_id");
3584
3585                        return (
3586                            config.json[aQuestionId].catId - config.json[bQuestionId].catId
3587                        );
3588                    });
3589
3590                if (e) {
3591                    if (e[0]) {
3592                        $(e).appendTo(e[0].parentNode);
3593                    }
3594                }
3595            },
3596
3597            restartQuiz: function () {
3598                globalElements.results.hide();
3599                //globalElements.quizStartPage.show();
3600                globalElements.questionList.children().hide();
3601                globalElements.toplistShowInButton.hide();
3602                reviewBox.hide();
3603
3604                $e.find('.wpProQuiz_questionInput, .wpProQuiz_cloze input').removeAttr('disabled').removeAttr('checked')
3605                    .css('background-color', '');
3606
3607                // Reset all the question types to empty values. This really should be moved into a reset function to be called at other times like at Quiz Init.
3608                //              $e.find('.wpProQuiz_cloze input').val('');
3609                $e.find('.wpProQuiz_questionListItem input[type="text"]').val('');
3610
3611                $e.find('.wpProQuiz_answerCorrect, .wpProQuiz_answerIncorrect').removeClass('wpProQuiz_answerCorrect wpProQuiz_answerIncorrect');
3612
3613                $e.find('.wpProQuiz_listItem').data('check', false);
3614                $e.find('textarea.wpProQuiz_questionEssay').val('');
3615                $e.find('input.uploadEssayFile').val('');
3616                $e.find('input.uploadAudioFile').val('');
3617                $e.find('input.wpProQuiz_upload_essay').val('');
3618
3619                $e.find('.wpProQuiz_response').hide().children().hide();
3620
3621                plugin.methode.resetMatrix($e.find('.wpProQuiz_listItem'));
3622
3623                $e.find('.wpProQuiz_sortStringItem, .wpProQuiz_sortable').removeAttr('style');
3624
3625                $e.find('.wpProQuiz_clozeCorrect, .wpProQuiz_QuestionButton, .wpProQuiz_resultsList > li').hide();
3626
3627                $e.find('.wpProQuiz_question_page, input[name="tip"]').show();
3628
3629                $e.find('.wpProQuiz_certificate').attr('style', 'display: none !important');
3630
3631                globalElements.results.find('.wpProQuiz_time_limit_expired').hide();
3632
3633                globalElements.next.last().val(lastButtonValue);
3634
3635                inViewQuestions = false;
3636
3637                // Clear Cookie on restart
3638                //plugin.methode.CookieDelete();
3639
3640                //Added by webxity
3641                plugin.methode.deleteAllTimerCookies();
3642                //Added by webxity
3643
3644                plugin.methode.load_save_resume();
3645            },
3646            showSpinner: function () {
3647                $e.find(".wpProQuiz_spinner").show();
3648            },
3649            hideSpinner: function () {
3650                $e.find(".wpProQuiz_spinner").hide();
3651            },
3652            checkQuestion: function (list, endCheck) {
3653                var finishQuiz = list == undefined ? false : true;
3654                var responses = {};
3655                var r = {};
3656
3657                if (list == undefined && config.mode == 2 && is_quiz_resume_in_process == 'yes') {
3658                    return;
3659                }
3660
3661                list = list == undefined ? currentQuestion : list;
3662
3663                list.each(function () {
3664                    var $this = $(this);
3665                    var question_index = $this.index();
3666                    var $questionList = $this.find(globalNames.questionList);
3667                    var question_id = $questionList.data("question_id");
3668                    var data = config.json[$questionList.data("question_id")];
3669                    var name = data.type;
3670                    var resumedQuestion = resumedQuestions[question_id];
3671
3672                    if (config.mode == 2 && is_quiz_resume_in_process == 'yes') {
3673
3674                        if (!checkedQuestions.includes(question_id)) {
3675                            return true;
3676                        } else if (data.type == 'laq_swipe_questions') {
3677                            let is_attempted = false;
3678
3679                            $.each(resumedQuestion.response, function (index, response) {
3680                                if (response.attempted == 'yes') {
3681                                    is_attempted = true;
3682                                    return;
3683                                }
3684                            });
3685
3686                            if (!is_attempted) {
3687                                return true;
3688                            }
3689                        } else if (data.type == 'laq_calculated_formula') {
3690                            return true;
3691                        }
3692                    }
3693
3694                    questionTimer.questionStop();
3695
3696                    if ($this.data("check")) {
3697                        return true;
3698                    }
3699
3700                    if (data.type == "single" || data.type == "multiple") {
3701                        name = "singleMulti";
3702                    }
3703                    //if (config.ld_script_debug == true) {
3704                    //  console.log('checkQuestion: calling readResponses');
3705                    //}
3706
3707                    responses[question_id] = readResponses(
3708                        name,
3709                        data,
3710                        $this,
3711                        $questionList,
3712                        true
3713                    );
3714                    // console.log(responses);
3715                    responses[question_id]["question_pro_id"] = data["id"];
3716                    responses[question_id]["question_post_id"] = data["question_post_id"];
3717
3718                    plugin.methode.CookieSaveResponse(
3719                        question_id,
3720                        question_index,
3721                        data.type,
3722                        responses[question_id]
3723                    );
3724                });
3725
3726                var data = {
3727                    action: "wp_pro_quiz_admin_ajax",
3728                    func: "saveQuizProgress",
3729                    data: {
3730                        quizId: config.quizId,
3731                        responses: responses,
3732                        timespent: timespent,
3733                        quiz: config.quiz,
3734                    },
3735                };
3736                // quizId: config.quizId,
3737                // quiz: config.quiz,
3738                // quiz_nonce: config.quiz_nonce
3739                $.post(WpProQuizGlobal.ajaxurl, data, function (json) {
3740                    if (json.toplist) {
3741                        $e.find(".wpProQuiz_toplist").show().html(json.toplist);
3742                    }
3743
3744                    if (json.averageResult) {
3745                        $e.find(".wpProQuiz_resultTable .wpProQuiz_points")
3746                            .children()
3747                            .eq(1)
3748                            .text(json.averageResult + "%");
3749                    }
3750
3751                    if (callback && typeof callback === 'function') {
3752                        callback();
3753                    }
3754                }, "json");
3755
3756                config.checkAnswers = {
3757                    list: list,
3758                    responses: responses,
3759                    endCheck: endCheck,
3760                    finishQuiz: finishQuiz
3761                };
3762
3763                if (config.mode == 2 && is_quiz_resume_in_process == 'yes') {
3764                    finishQuiz = false;
3765                }
3766
3767                if (finishQuiz) {
3768                    plugin.methode.sending(1, 80, 3);
3769                } else {
3770                    plugin.methode.showSpinner();
3771                }
3772
3773                plugin.methode.ajax(
3774                    {
3775                        action: "ld_advance_adv_quiz_pro_ajax", //changed for advance addon
3776                        func: "checkAnswers",
3777                        data: {
3778                            quizId: config.quizId,
3779                            quiz: config.quiz,
3780                            course_id: config.course_id,
3781                            quiz_nonce: config.quiz_nonce,
3782                            responses: JSON.stringify(responses)
3783                        }
3784                    },
3785                    function (json) {
3786                        plugin.methode.hideSpinner();
3787                        var list = config.checkAnswers.list;
3788
3789                        var responses = config.checkAnswers.responses;
3790                        var r = config.checkAnswers.r;
3791                        var endCheck = config.checkAnswers.endCheck;
3792                        var finishQuiz = config.checkAnswers.finishQuiz;
3793
3794                        if (config.mode == 2 && is_quiz_resume_in_process == 'yes') {
3795                            finishQuiz = false;
3796                        }
3797
3798                        list.each(function () {
3799                            var $this = $(this);
3800                            var $questionList = $this.find(globalNames.questionList);
3801                            var question_id = $questionList.data("question_id");
3802                            //var data = {id: question_id};
3803
3804                            if (config.mode == 2) {
3805                                if (is_quiz_resume_in_process == 'yes') {
3806                                    if (!checkedQuestions.includes(question_id)) {
3807                                        return true;
3808                                    }
3809                                } else {
3810                                    if (!checkedQuestions.includes(question_id)) {
3811                                        checkedQuestions.push(question_id);
3812                                    }
3813                                }
3814                            }
3815
3816                            if ($this.data("check")) {
3817                                return true;
3818                            }
3819
3820                            if (typeof json[question_id] !== "undefined") {
3821                                var result = json[question_id];
3822
3823                                data = config.json[$questionList.data("question_id")];
3824
3825                                $this.find(".wpProQuiz_response").show();
3826                                $this.find(globalNames.check).hide();
3827                                $this.find(globalNames.skip).hide();
3828                                $this.find(globalNames.next).show();
3829
3830                                results[data.id].points = result.p;
3831                                if (typeof result.p_nonce !== "undefined")
3832                                    results[data.id].p_nonce = result.p_nonce;
3833                                else results[data.id].p_nonce = "";
3834
3835                                results[data.id].correct = Number(result.c);
3836                                results[data.id].data = result.s;
3837                                if (typeof result.a_nonce !== "undefined")
3838                                    results[data.id].a_nonce = result.a_nonce;
3839                                else results[data.id].a_nonce = "";
3840                                results[data.id].possiblePoints = result.e.possiblePoints;
3841
3842                                // If the sort_answer or matrix_sort_answer question type is not 100% correct then the returned
3843                                // result.s object will be empty. So in order to pass the user's answers to the server for the
3844                                // sendCompletedQuiz AJAX call we need to grab the result.e.r object and store into results.
3845                                if (jQuery.isEmptyObject(results[data.id].data)) {
3846                                    if (
3847                                        result.e.type != undefined &&
3848                                        (result.e.type == "sort_answer" ||
3849                                            result.e.type == "matrix_sort_answer")
3850                                    ) {
3851                                        results[data.id].data = result.e.r;
3852                                    }
3853                                }
3854
3855                                if (
3856                                    typeof result.e.graded_id !== "undefined" &&
3857                                    result.e.graded_id > 0
3858                                ) {
3859                                    results[data.id].graded_id = result.e.graded_id;
3860                                }
3861
3862                                if (typeof result.e.graded_status !== "undefined") {
3863                                    results[data.id].graded_status = result.e.graded_status;
3864                                }
3865
3866                                results["comp"].points += result.p;
3867
3868                                $this.find(".wpProQuiz_response").show();
3869                                $this.find(globalNames.check).hide();
3870                                $this.find(globalNames.skip).hide();
3871                                $this.find(globalNames.next).show();
3872
3873                                //results[data.id].points = result.p;
3874                                //results[data.id].correct = Number(result.c);
3875                                //results[data.id].data = result.s;
3876
3877                                // If the sort_answer or matrix_sort_answer question type is not 100% correct then the returned
3878                                // result.s object will be empty. So in order to pass the user's answers to the server for the
3879                                // sendCompletedQuiz AJAX call we need to grab the result.e.r object and store into results.
3880                                if (jQuery.isEmptyObject(results[data.id].data)) {
3881                                    if (typeof result.e.type !== "undefined") {
3882                                        if (
3883                                            result.e.type == "sort_answer" ||
3884                                            result.e.type == "matrix_sort_answer"
3885                                        ) {
3886                                            if (typeof result.e.r !== "undefined") {
3887                                                results[data.id].data = result.e.r;
3888                                            }
3889                                        }
3890
3891                                        if (result.e.type == 'essay') {
3892                                            if (typeof result.e.graded_id !== 'undefined') {
3893                                                results[data.id].data = { graded_id: result.e.graded_id };
3894                                            }
3895                                        }
3896
3897                                        if (result.e.type == 'laq_audio_questions') {
3898                                            if (typeof result.e.graded_id !== 'undefined') {
3899                                                results[data.id].data = { graded_id: result.e.graded_id };
3900                                            }
3901                                        }
3902
3903
3904                                    }
3905                                }
3906
3907                                catResults[data.catId] += result.p;
3908
3909                                //Marker
3910                                plugin.methode.markCorrectIncorrect(result, $this, $questionList);
3911
3912                                if (result.c) {
3913                                    if (typeof result.e.AnswerMessage !== "undefined") {
3914                                        $this
3915                                            .find(".wpProQuiz_correct")
3916                                            .find(".wpProQuiz_AnswerMessage")
3917                                            .html(result.e.AnswerMessage);
3918                                        $this
3919                                            .find(".wpProQuiz_correct")
3920                                            .trigger("learndash-quiz-answer-response-contentchanged");
3921                                    }
3922                                    $e.trigger({ type: 'questionSolvedCorrect', values: { item: $this, index: $this.index(), solved: true, result: result } });
3923
3924                                    $this.find(".wpProQuiz_correct").show();
3925                                    results["comp"].correctQuestions += 1;
3926                                } else {
3927                                    if (typeof result.e.AnswerMessage !== "undefined") {
3928                                        $this.find('.wpProQuiz_incorrect').find('.wpProQuiz_AnswerMessage').html(result.e.AnswerMessage);
3929                                        $this.find('.wpProQuiz_incorrect').trigger('learndash-quiz-answer-response-contentchanged');
3930                                    }
3931                                    $e.trigger({ type: 'questionSolvedIncorrect', values: { item: $this, index: $this.index(), solved: true, result: result } });
3932
3933                                    $this.find('.wpProQuiz_incorrect').show();
3934                                }
3935
3936                                $this.find(".wpProQuiz_responsePoints").text(result.p);
3937
3938                                $this.data("check", true);
3939
3940                                if (!endCheck)
3941                                    $e.trigger({
3942                                        type: "questionSolved",
3943                                        values: { item: $this, index: $this.index(), solved: true }
3944                                    });
3945                            }
3946                        });
3947
3948                        //Added by abbas
3949                        results["comp"].points = 0;
3950                        results["comp"].result = 0;
3951                        results["comp"].correctQuestions = 0;
3952                        //config.globalPoints = json.globalPoints;possiblePoints
3953                        $possiblePoints = 0;
3954                        $.each(json, function (question_id, result) {
3955
3956                            if (checkedQuestions.includes(question_id) && config.mode == 2 && is_quiz_resume_in_process == 'yes') {
3957                                return true;
3958                            }
3959
3960                            if (results[question_id] == null) {
3961                                results[question_id] = {};
3962                            }
3963                            if (results["comp"] == null) {
3964                                results["comp"] = {};
3965                            }
3966
3967                            results[question_id].points = result.p;
3968                            if (typeof result.p_nonce !== "undefined")
3969                                results[question_id].p_nonce = result.p_nonce;
3970                            else results[question_id].p_nonce = "";
3971
3972                            results[question_id].correct = Number(result.c);
3973                            results[question_id].data = result.s;
3974                            if (typeof result.a_nonce !== "undefined")
3975                                results[question_id].a_nonce = result.a_nonce;
3976                            else results[question_id].a_nonce = "";
3977                            results[question_id].possiblePoints = result.e.possiblePoints;
3978                            $possiblePoints += result.e.possiblePoints;
3979
3980                            if (jQuery.isEmptyObject(results[question_id].data)) {
3981                                if (
3982                                    result.e.type != undefined &&
3983                                    (result.e.type == "sort_answer" ||
3984                                        result.e.type == "matrix_sort_answer")
3985                                ) {
3986                                    results[question_id].data = result.e.r;
3987                                }
3988                            }
3989
3990                            if (
3991                                typeof result.e.graded_id !== "undefined" &&
3992                                result.e.graded_id > 0
3993                            ) {
3994                                results[question_id].graded_id = result.e.graded_id;
3995                            }
3996
3997                            if (typeof result.e.graded_status !== "undefined") {
3998                                results[question_id].graded_status = result.e.graded_status;
3999                            }
4000
4001                            if (result.c || result.apa || is_negative_marking_enabled) {
4002                                results["comp"].points += result.p;
4003                            }
4004
4005                            if (result.c && result.o == "no") {
4006                                results["comp"].correctQuestions += 1;
4007                            }
4008
4009                            if (jQuery.isEmptyObject(results[question_id].data)) {
4010                                if (typeof result.e.type !== "undefined") {
4011                                    if (
4012                                        result.e.type == "sort_answer" ||
4013                                        result.e.type == "matrix_sort_answer"
4014                                    ) {
4015                                        if (typeof result.e.r !== "undefined") {
4016                                            results[question_id].data = result.e.r;
4017                                        }
4018                                    }
4019
4020                                    if (result.e.type == "essay") {
4021                                        if (typeof result.e.graded_id !== "undefined") {
4022                                            results[question_id].data = {
4023                                                graded_id: result.e.graded_id
4024                                            };
4025                                        }
4026                                    }
4027
4028                                    if (result.e.type == "laq_audio_questions") {
4029                                        if (typeof result.e.graded_id !== "undefined") {
4030                                            results[question_id].data = {
4031                                                graded_id: result.e.graded_id
4032                                            };
4033                                        }
4034                                    }
4035
4036                                    if (result.e.type == "laq_swipe_questions") {
4037                                        if (typeof result.e.r !== "undefined") {
4038                                            // results[question_id] = {
4039
4040                                            // }
4041                                        }
4042                                    }
4043                                }
4044                            }
4045                        });
4046
4047                        if (config.mode != 2) {
4048                            config.globalPoints = $possiblePoints;
4049                        }
4050                        //Added by abbas
4051                        // Set a default just in case.
4052                        //results.comp.p_nonce = '';
4053
4054                        //if ( typeof json['comp'] !== 'undefined' ) {
4055                        //  if ( ( typeof json['comp']['p'] !== 'undefined' ) && ( typeof json['comp']['p_nonce'] !== 'undefined' ) ) {
4056                        //      results.comp.points = json['comp']['p'];
4057                        //      results.comp.p_nonce = json['comp']['p_nonce'];
4058                        //  }
4059                        //}
4060
4061                        if (config.mode == 2 && is_quiz_resume_in_process == 'yes') {
4062                            is_quiz_resume_in_process = "no";
4063                        }
4064
4065                        if (finishQuiz) plugin.methode.finishQuizEnd();
4066
4067                    }
4068                );
4069            },
4070
4071            markCorrectIncorrect: function (result, $question, $questionList) {
4072                if (typeof result.e.c == "undefined") return;
4073
4074                switch (result.e.type) {
4075                    case "single":
4076                    case "multiple":
4077                        $questionList.children().each(function (i) {
4078                            var $item = $(this);
4079                            var index = $item.attr("data-pos");
4080                            //                  var checked = input.eq(i).is(':checked');
4081
4082                            if (result.e.c[index]) {
4083                                var checked = $("input.wpProQuiz_questionInput", $item).is(
4084                                    ":checked"
4085                                );
4086                                if (checked) {
4087                                    plugin.methode.marker($item, true);
4088                                } else {
4089                                    plugin.methode.marker(
4090                                        $item,
4091                                        "wpProQuiz_answerCorrectIncomplete"
4092                                    );
4093                                }
4094                            } else {
4095                                if (!result.c && result.e.r[index])
4096                                    plugin.methode.marker($item, false);
4097                            }
4098                        });
4099                        break;
4100                    case "free_answer":
4101                        var $li = $questionList.children();
4102                        if (result.c) plugin.methode.marker($li, true);
4103                        else plugin.methode.marker($li, false);
4104                        break;
4105
4106                    case "cloze_answer":
4107                        $questionList.find(".wpProQuiz_cloze").each(function (i, v) {
4108                            var $this = $(this);
4109                            var cloze = $this.children();
4110                            var input = cloze.eq(0);
4111                            var span = cloze.eq(1);
4112                            var inputText = plugin.methode.cleanupCurlyQuotes(input.val());
4113
4114                            if (result.s[i]) {
4115                                //input.css('background-color', '#B0DAB0');
4116                                input.addClass('wpProQuiz_answerCorrect');
4117                            } else {
4118                                input.addClass('wpProQuiz_answerIncorrect');
4119                                //input.css('background-color', '#FFBABA');
4120
4121                                if (typeof result.e.c[i] != "undefined") {
4122                                    span.html("(" + result.e.c[i].join() + ")");
4123                                    span.show();
4124                                }
4125                            }
4126                            input.attr("disabled", "disabled");
4127                        });
4128                        break;
4129                    case 'sort_answer':
4130                        var $items = $questionList.children('li.wpProQuiz_questionListItem');
4131
4132                        $items.each(function (i, v) {
4133                            var $this = $(this);
4134
4135                            if (result.e.c[i] == $this.attr("data-pos")) {
4136                                plugin.methode.marker($this, true);
4137                            } else {
4138                                plugin.methode.marker($this, false);
4139                            }
4140                        });
4141
4142                        $items.children().css({ "box-shadow": "0 0", cursor: "auto" });
4143
4144                        //                      $questionList.sortable("destroy");
4145
4146                        var index = new Array();
4147                        jQuery.each(result.e.c, function (i, v) {
4148                            index[v] = i;
4149                        });
4150                        $items.sort(function (a, b) {
4151                            return index[$(a).attr("data-pos")] > index[$(b).attr("data-pos")]
4152                                ? 1
4153                                : -1;
4154                        });
4155
4156                        $questionList.append($items);
4157                        break;
4158                    case "laq_jumbled_sentence":
4159                        $questionList
4160                            .find(".laq_jumbled_sentence_dropdown")
4161                            .each(function (index) {
4162                                var correct = $questionList
4163                                    .find(".laq_jumbled_sentence_correct")
4164                                    .eq(index)
4165                                    .val().trim();
4166                                var curr_val = ($(this).val() || '').trim();
4167                                var correct_array = correct.trim().split('|').map(function(item) {
4168                                    return item.trim();
4169                                });
4170                                
4171                                // Only show correct answers that are actually correct, not all options
4172                                var correct_display = correct_array.join(', ');
4173                                
4174                                var is_correct = $.inArray(curr_val.trim(), correct_array) >= 0;
4175                                
4176                                // Only show correct answers if user got it wrong or didn't answer
4177                                if (!curr_val || !is_correct) {
4178                                    $questionList
4179                                        .find(".laq_jumbled_sentence_correct_ans")
4180                                        .eq(index)
4181                                        .html(
4182                                            ' <span class="wpProQuiz_clozeCorrect" style="color:green">(' +
4183                                            correct_display +
4184                                            ")</span>"
4185                                        );
4186                                } else {
4187                                    // Hide correct answer display if user got it right
4188                                    $questionList
4189                                        .find(".laq_jumbled_sentence_correct_ans")
4190                                        .eq(index)
4191                                        .html("");
4192                                }
4193                                
4194                                if (is_correct) {
4195                                    $(this).addClass("wpProQuiz_answerCorrect");
4196                                } else {
4197                                    $(this).addClass("wpProQuiz_answerIncorrect");
4198                                }
4199                            });
4200                        break;
4201                    case "laq_jumble_dnd_sentence":
4202                        $questionList
4203                            .find(".ldavq-jumbled-dnd-dropzone")
4204                            .each(function (index) {
4205                                var data_id = $(this).data('id');
4206                                var correct = $questionList.find("#correct_options" + data_id).val().trim();
4207
4208                                var curr_val = $(this).val().trim();
4209                                $questionList
4210                                    .find("#laq_jumble_dnd_sentence_correct_ans" + data_id)
4211                                    .html(
4212                                        "<span " +
4213                                        (correct == curr_val ? 'style="display: none;"' : "") +
4214                                        ' class="wpProQuiz_clozeCorrect" style="color:green">(' +
4215                                        correct +
4216                                        ")</span>"
4217                                    );
4218                                if (correct.replace(/[^a-zA-Z0-9]/g, '') == curr_val.replace(/[^a-zA-Z0-9]/g, '')) {
4219                                    $(this).addClass("wpProQuiz_answerCorrect");
4220                                } else {
4221                                    $(this).addClass("wpProQuiz_answerIncorrect");
4222                                }
4223                            });
4224
4225                        break;
4226                    case "laq_swipe_questions":
4227                        $questionList
4228                            .find(".laq_advanced_swipe_questions_slides_wrapper")
4229                            .css("display", "none");
4230
4231                        $questionList.find(".swipe_question_note").css("display", "none");
4232
4233                        $questionList
4234                            .find(".laq_advanced_swipe_questions_slides_backup")
4235                            .css("display", "block");
4236
4237                        $questionList
4238                            .find(".laq_advanced_swipe_questions_slides_backup .card_parent")
4239                            .each(function (index) {
4240
4241                                var parent_node = $(this).parent().parent();
4242
4243                                var id = parseInt($(this).data("id")) - 1;
4244
4245                                var correct = parent_node.find("#laq_advanced_swipe_correct" + id).val();
4246                                var selection = parent_node.find("#laq_advanced_swipe_selection" + id).val();
4247                                var attempted = parent_node.find("#laq_advanced_swipe_attempted" + id).val();
4248
4249                                if (attempted == "yes" && !bitOptions.disabledAnswerMark) {
4250                                    if (correct == selection) {
4251                                        $(this)
4252                                            .addClass("wpProQuiz_answerCorrect")
4253                                            .css("margin", "5px");
4254                                    } else {
4255                                        $(this)
4256                                            .addClass("wpProQuiz_answerIncorrect")
4257                                            .css("margin", "5px");
4258                                    }
4259                                }
4260                            });
4261
4262                        $('.laq_advanced_swipe_questions_slides_backup').parent().show();
4263                        $('.ld_aq_swipe_main_wrap > div.header').hide();
4264                        $('.ld_aq_swipe_controls').hide();
4265
4266                        break;
4267                    case "laq_calculated_formula":
4268                        $questionList.find(".card_calculation").each(function (index) {
4269                            var correct = $(this)
4270                                .find("#laq_advanced_calculated_correct")
4271                                .val();
4272                            var selection = $(this)
4273                                .find("#laq_advanced_calculated_selection")
4274                                .val();
4275
4276                            // Normalize both values by removing commas for c
4276omparison
4277                            var normalizedCorrect = correct ? correct.replace(/,/g, '') : '';
4278                            var normalizedSelection = selection ? selection.replace(/,/g, '') : '';
4279
4280                            if (normalizedCorrect == normalizedSelection) {
4281
4282                                $(this)
4283                                    .find("#laq_advanced_calculated_selection")
4284                                    .addClass("wpProQuiz_answerCorrect");
4285                                $(this).parent().parent()
4286                                    .find(".ld-advance-calculated-right-col")
4287                                    .addClass("wpProQuiz_answerCorrect");
4288
4289                            } else {
4290                                $(this)
4291                                    .find("#laq_advanced_calculated_selection")
4292                                    .addClass("wpProQuiz_answerIncorrect");
4293                                $(this).parent().parent()
4294                                    .find(".ld-advance-calculated-right-col")
4295                                    .addClass("wpProQuiz_answerIncorrect").attr('disabled', 'disabled');
4296                            }
4297                            $(this)
4298                                .find("#laq_advanced_calculated_selection")
4299                                .parent()
4300                                .append(
4301                                    '<span class="wpProQuiz_clozeCorrect" style="color:green">(' +
4302                                    correct +
4303                                    ")</span>"
4304                                );
4305                            $(this)
4306                                .find("#laq_advanced_calculated_selection").attr('disabled', 'disabled');
4307                            $(this).parent().parent().find(".ld-advanced-calculated-work").attr('disabled', 'disabled');
4308                        });
4309                        break;
4310                    case "matrix_sort_answer":
4311                        var $items = $questionList.children();
4312                        var matrix = new Array();
4313                        statistcAnswerData = { 0: -1 };
4314
4315                        $items.each(function () {
4316                            var $this = $(this);
4317                            var id = $this.attr("data-pos");
4318                            var $stringUl = $this.find(".wpProQuiz_maxtrixSortCriterion");
4319                            var $stringItem = $stringUl.children();
4320                            var i = $stringItem.attr("data-pos");
4321
4322                            if (
4323                                $stringItem.length &&
4324                                result.e.c[i] == $this.attr("data-pos")
4325                            ) {
4326                                plugin.methode.marker($this, true);
4327                            } else {
4328                                plugin.methode.marker($this, false);
4329                            }
4330
4331                            matrix[i] = $stringUl;
4332                        });
4333
4334                        plugin.methode.resetMatrix($question);
4335
4336                        $question
4337                            .find(".wpProQuiz_sortStringItem")
4338                            .each(function () {
4339                                var x = matrix[$(this).attr("data-pos")];
4340                                if (x != undefined) x.append(this);
4341                            })
4342                            .css({ "box-shadow": "0 0", cursor: "auto" });
4343
4344                        //  $question.find('.wpProQuiz_sortStringList, .wpProQuiz_maxtrixSortCriterion').sortable("destroy");
4345                        break;
4346                }
4347                if (window.checkCorrectIncorrect[result.e.type]) {
4348                    window.checkCorrectIncorrect[result.e.type](result, $question, $questionList, plugin);
4349                }
4350            },
4351
4352            setCheckedStatusFromData: function (data, question, list) {
4353                var dataObjects = [quiz_resume_data, cookie_value];
4354                jQuery(dataObjects).each(function (index, dataObject) {
4355                    if (dataObject.hasOwnProperty('checked' + data.id)) {
4356                        for (var element in dataObject) {
4357                            if (element.startsWith('checked')) {
4358                                var elementId = element.replace('checked', '');
4359                                if (elementId == data.id) {
4360                                    questionResult = dataObject[element];
4361                                    plugin.methode.markCorrectIncorrect(questionResult, question, list);
4362
4363                                    if (questionResult.c) {
4364                                        if (typeof questionResult.e.AnswerMessage !== 'undefined') {
4365                                            question.find('.wpProQuiz_correct').find('.wpProQuiz_AnswerMessage').html(questionResult.e.AnswerMessage);
4366                                            question.find('.wpProQuiz_correct').trigger('learndash-quiz-answer-response-contentchanged');
4367                                        }
4368
4369                                        question.find('.wpProQuiz_response').show();
4370                                        question.find('.wpProQuiz_correct').show();
4371                                    } else {
4372                                        if (typeof questionResult.e.AnswerMessage !== 'undefined') {
4373                                            question.find('.wpProQuiz_incorrect').find('.wpProQuiz_AnswerMessage').html(questionResult.e.AnswerMessage);
4374                                            question.find('.wpProQuiz_incorrect').trigger('learndash-quiz-answer-response-contentchanged');
4375                                        }
4376
4377                                        question.find('.wpProQuiz_response').show();
4378                                        question.find('.wpProQuiz_incorrect').show();
4379                                    }
4380                                    // question.find( '.wpProQuiz_responsePoints' ).text( questionResult.p );
4381                                }
4382                            }
4383                        }
4384                    }
4385                });
4386            },
4387
4388            showTip: function () {
4389                var $this = $(this);
4390                var id = $this.siblings('.wpProQuiz_question').find(globalNames.questionList).data('question_id');
4391
4392                $this.siblings('.wpProQuiz_tipp').toggle('fast');
4393
4394                results[id].tip = 1;
4395
4396                $(document).bind("mouseup.tipEvent", function (e) {
4397                    var $tip = $e.find(".wpProQuiz_tipp");
4398                    var $btn = $e.find('input[name="tip"]');
4399
4400                    if (
4401                        !$tip.is(e.target) &&
4402                        $tip.has(e.target).length == 0 &&
4403                        !$btn.is(e.target)
4404                    ) {
4405                        $tip.hide("fast");
4406                        $(document).unbind(".tipEvent");
4407                    }
4408                });
4409            },
4410
4411            ajax: function (data, success, dataType) {
4412                dataType = dataType || "json";
4413
4414                if (bitOptions.cors) {
4415                    jQuery.support.cors = true;
4416                }
4417
4418                if (data["quiz"] === undefined) {
4419                    data["quiz"] = config.quiz;
4420                }
4421                if (data["course_id"] === undefined) {
4422                    data["course_id"] = config.course_id;
4423                }
4424                if (data["quiz_nonce"] === undefined) {
4425                    data["quiz_nonce"] = config.quiz_nonce;
4426                }
4427
4428                $.ajax({
4429                    method: "POST",
4430                    type: "POST",
4431                    url: WpProQuizGlobal.ajaxurl,
4432                    data: data,
4433                    success: success,
4434                    dataType: dataType
4435                });
4436
4437                if (bitOptions.cors) {
4438                    jQuery.support.cors = false;
4439                }
4440            },
4441
4442            checkQuizLock: function () {
4443                quizStatus.loadLock = 1;
4444
4445                plugin.methode.ajax(
4446                    {
4447                        action: "wp_pro_quiz_check_lock",
4448                        quizId: config.quizId
4449                    },
4450                    function (json) {
4451                        if (json.lock != undefined) {
4452                            quizStatus.isLocked = json.lock.is;
4453
4454                            /*
4455                                                        if (json.lock.pre) {
4456                                                            $e.find('input[name="restartQuiz"]').hide();
4457                                                        }
4458                            */
4459                        }
4460
4461                        if (json.prerequisite != undefined) {
4462                            quizStatus.isPrerequisite = 1;
4463                            $e.find(".wpProQuiz_prerequisite span").text(json.prerequisite);
4464                        }
4465
4466                        if (json.startUserLock != undefined) {
4467                            quizStatus.isUserStartLocked = json.startUserLock;
4468                        }
4469
4470                        quizStatus.loadLock = 0;
4471
4472                        if (quizStatus.isQuizStart) {
4473                            plugin.methode.startQuiz();
4474                        }
4475                    }
4476                );
4477            },
4478
4479            loadQuizData: function () {
4480                plugin.methode.ajax(
4481                    {
4482                        action: "wp_pro_quiz_load_quiz_data",
4483                        quizId: config.quizId
4484                    },
4485                    function (json) {
4486                        if (json.toplist) {
4487                            plugin.methode.handleToplistData(json.toplist);
4488                        }
4489
4490                        if (json.averageResult != undefined) {
4491                            plugin.methode.setAverageResult(json.averageResult, true);
4492                        }
4493                    }
4494                );
4495            },
4496
4497            setAverageResult: function (p, g) {
4498                var v = $e.find(".wpProQuiz_resultValue:eq(" + (g ? 0 : 1) + ") > * ");
4499
4500                v.eq(1).text(p + "%");
4501                v.eq(0).css("width", (240 * p) / 100 + "px");
4502            },
4503
4504            handleToplistData: function (json) {
4505                var $tp = $e.find(".wpProQuiz_addToplist");
4506                var $addBox = $tp
4507                    .find(".wpProQuiz_addBox")
4508                    .show()
4509                    .children("div");
4510
4511                if (json.canAdd) {
4512                    $tp.show();
4513                    $tp.find(".wpProQuiz_addToplistMessage").hide();
4514                    $tp.find(".wpProQuiz_toplistButton").show();
4515
4516                    toplistData.token = json.token;
4517                    toplistData.isUser = 0;
4518
4519                    if (json.userId) {
4520                        $addBox.hide();
4521                        toplistData.isUser = 1;
4522
4523                        if (bitOptions.isAddAutomatic) {
4524                            $tp.hide();
4525                        }
4526                    } else {
4527                        $addBox.show();
4528
4529                        var $captcha = $addBox.children().eq(1);
4530
4531                        if (json.captcha) {
4532                            $captcha
4533                                .find('input[name="wpProQuiz_captchaPrefix"]')
4534                                .val(json.captcha.code);
4535                            $captcha
4536                                .find(".wpProQuiz_captchaImg")
4537                                .attr("src", json.captcha.img);
4538                            $captcha.find('input[name="wpProQuiz_captcha"]').val("");
4539
4540                            $captcha.show();
4541                        } else {
4542                            $captcha.hide();
4543                        }
4544                    }
4545                } else {
4546                    $tp.hide();
4547                }
4548            },
4549
4550            scrollTo: function (e, h) {
4551                const x = e.offset().top - 100;
4552
4553                if (h || (window.pageYOffset || document.body.scrollTop) > x) {
4554                    $('html,body').clearQueue().animate({ scrollTop: x }, 300);
4555                }
4556            },
4557
4558            addToplist: function () {
4559                if (bitOptions.preview) return;
4560
4561                var $addToplistMessage = $e
4562                    .find(".wpProQuiz_addToplistMessage")
4563                    .text(WpProQuizGlobal.loadData)
4564                    .show();
4565                var $addBox = $e.find(".wpProQuiz_addBox").hide();
4566
4567                plugin.methode.ajax(
4568                    {
4569                        action: "wp_pro_quiz_add_toplist",
4570                        quizId: config.quizId,
4571                        quiz: config.quiz,
4572                        quiz_nonce: config.quiz_nonce,
4573                        token: toplistData.token,
4574                        name: $addBox.find('input[name="wpProQuiz_toplistName"]').val(),
4575                        email: $addBox.find('input[name="wpProQuiz_toplistEmail"]').val(),
4576                        captcha: $addBox.find('input[name="wpProQuiz_captcha"]').val(),
4577                        prefix: $addBox.find('input[name="wpProQuiz_captchaPrefix"]').val(),
4578                        //points: 99, //results.comp.points, // LD v2.4.3 Calculated on server
4579                        results: JSON.stringify(results),
4580                        //p_nonce: results.comp.p_nonce, // LD v2.4.3 Calculated on server
4581                        //totalPoints:config.globalPoints, // LD v2.4.3 Calculated on server
4582                        timespent: timespent
4583                    },
4584                    function (json) {
4585                        $addToplistMessage.text(json.text);
4586
4587                        if (json.clear) {
4588                            $addBox.hide();
4589                            plugin.methode.updateToplist();
4590                        } else {
4591                            $addBox.show();
4592                        }
4593
4594                        if (json.captcha) {
4595                            $addBox
4596                                .find(".wpProQuiz_captchaImg")
4597                                .attr("src", json.captcha.img);
4598                            $addBox
4599                                .find('input[name="wpProQuiz_captchaPrefix"]')
4600                                .val(json.captcha.code);
4601                            $addBox.find('input[name="wpProQuiz_captcha"]').val("");
4602                        }
4603                    }
4604                );
4605            },
4606
4607            updateToplist: function () {
4608                if (typeof wpProQuiz_fetchToplist == "function") {
4609                    wpProQuiz_fetchToplist();
4610                }
4611            },
4612
4613            registerSolved: function () {
4614                // Free Input field
4615                $e.find('.wpProQuiz_questionInput[type="text"]').change(function (e) {
4616                    var $this = $(this);
4617                    var $p = $this.parents(".wpProQuiz_listItem");
4618                    var s = false;
4619
4620                    if ($this.val() != "") {
4621                        s = true;
4622                    }
4623
4624                    $e.trigger({
4625                        type: "questionSolved",
4626                        values: { item: $p, index: $p.index(), solved: s }
4627                    });
4628                });
4629
4630                // Free Input field
4631                $e.find(".ldavq-jumbled-dnd-dropzone").on('drop change input', function (e) {
4632                    var $this = $(this);
4633                    var $p = $this.parents(".wpProQuiz_listItem");
4634                    var s = false;
4635
4636                    // Check ALL dropzones in this question
4637                    $p.find('.ldavq-jumbled-dnd-dropzone').each(function() {
4638                        if ($(this).val() != "") {
4639                            s = true;
4640                            return false;
4641                        }
4642                    });
4643
4644                    // Small delay to ensure value is set
4645                    setTimeout(function() {
4646                        $e.trigger({
4647                            type: "questionSolved",
4648                            values: { item: $p, index: $p.index(), solved: s }
4649                        });
4650                    }, 50);
4651                });
4652
4653                $e.find(".laq_jumbled_sentence_dropdown").change(function (e) {
4654                    var $this = $(this);
4655                    var $p = $this.parents(".wpProQuiz_listItem");
4656                    var s = false;
4657
4658                    if ($this.val() != "") {
4659                        s = true;
4660                    }
4661
4662                    $e.trigger({
4663                        type: "questionSolved",
4664                        values: { item: $p, index: $p.index(), solved: s }
4665                    });
4666                });
4667                // Free Input field
4668                $e.find(
4669                    '.laq_advanced_calculated_selection[type="text"], .laq_advanced_calculated_selection[type="number"]'
4670                ).change(function (e) {
4671                    var $this = $(this);
4672                    var $p = $this.parents(".wpProQuiz_listItem");
4673                    var s = false;
4674
4675                    if ($this.val() != "") {
4676                        s = true;
4677                    }
4678
4679                    $e.trigger({
4680                        type: "questionSolved",
4681                        values: { item: $p, index: $p.index(), solved: s }
4682                    });
4683                });
4684
4685                // Free Input field
4686                $e.find(".laq_advanced_swipe_attempted").change(function (e) {
4687                    var $this = $(this);
4688                    var $p = $this.parents(".wpProQuiz_listItem");
4689                    var s = false;
4690
4691                    if ($this.val() != "") {
4692                        s = true;
4693                    }
4694
4695                    $e.trigger({
4696                        type: "questionSolved",
4697                        values: { item: $p, index: $p.index(), solved: s }
4698                    });
4699                });
4700
4701                // Single Choice field
4702                $e.find(
4703                    '.wpProQuiz_questionList[data-type="single"] .wpProQuiz_questionInput, .wpProQuiz_questionList[data-type="assessment_answer"] .wpProQuiz_questionInput'
4704                ).change(function (e) {
4705                    var $this = $(this);
4706                    var $p = $this.parents(".wpProQuiz_listItem");
4707                    var s = this.checked;
4708
4709                    $e.trigger({
4710                        type: "questionSolved",
4711                        values: { item: $p, index: $p.index(), solved: s }
4712                    });
4713                });
4714
4715                // Cloze field
4716                $e.find(".wpProQuiz_cloze input").change(function () {
4717                    var $this = $(this);
4718                    var $p = $this.parents(".wpProQuiz_listItem");
4719                    var s = true;
4720
4721                    $p.find(".wpProQuiz_cloze input").each(function () {
4722                        if ($(this).val() == "") {
4723                            s = false;
4724                            return false;
4725                        }
4726                    });
4727
4728                    $e.trigger({
4729                        type: "questionSolved",
4730                        values: { item: $p, index: $p.index(), solved: s }
4731                    });
4732                });
4733
4734                // ?? field
4735                $e.find(
4736                    '.wpProQuiz_questionList[data-type="multiple"] .wpProQuiz_questionInput'
4737                ).change(function (e) {
4738                    var $this = $(this);
4739                    var $p = $this.parents(".wpProQuiz_listItem");
4740                    var c = 0;
4741
4742                    $p.find(
4743                        '.wpProQuiz_questionList[data-type="multiple"] .wpProQuiz_questionInput'
4744                    ).each(function (e) {
4745                        if (this.checked) c++;
4746                    });
4747
4748                    $e.trigger({
4749                        type: "questionSolved",
4750                        values: { item: $p, index: $p.index(), solved: c ? true : false }
4751                    });
4752                });
4753
4754                // Essay textarea field. For Essay file uploads look into uploadFile() function
4755                $e.find('.wpProQuiz_questionList[data-type="essay"] textarea.wpProQuiz_questionEssay').on('change', function (e) {
4756                    var $this = $(this);
4757                    var $p = $this.parents('.wpProQuiz_listItem');
4758                    var s = false;
4759
4760                    if ($this.val() != '') {
4761                        s = true;
4762                    }
4763                    $e.trigger({ type: 'questionSolved', values: { item: $p, index: $p.index(), solved: s } });
4764                });
4765
4766                // Audio textarea field. For Audio file uploads look into uploadFile() function
4767                $e.find('.wpProQuiz_questionList[data-type="laq_audio_questions"]').on('change', function (e) {
4768                    var $this = $(this);
4769                    var $p = $this.parents('.wpProQuiz_listItem');
4770                    var s = false;
4771
4772                    if ($this.val() != '') {
4773                        s = true;
4774                    }
4775                    $e.trigger({ type: 'questionSolved', values: { item: $p, index: $p.index(), solved: s } });
4776                });
4777                if(Object.keys(window.registerSolvedQuestion).length > 0){
4778                    Object.keys(window.registerSolvedQuestion).forEac
4778h(function(key) {
4779                        let fn = window.registerSolvedQuestion[key];
4780                        if(typeof fn === "function"){
4781                            fn($e); // run it
4782                        }
4783                    });
4784                }
4785            },
4786
4787            loadQuizDataAjax: function (quizStart) {
4788                //console.log('config[%o]', config.quizId);
4789
4790                plugin.methode.ajax(
4791                    {
4792                        action: "wp_pro_quiz_admin_ajax",
4793                        func: "quizLoadData",
4794                        data: {
4795                            quizId: config.quizId,
4796                            quiz: config.quiz,
4797                            quiz_nonce: config.quiz_nonce
4798                        }
4799                    },
4800                    function (json) {
4801                        config.globalPoints = json.globalPoints;
4802                        config.catPoints = json.catPoints;
4803                        config.json = json.json;
4804
4805                        globalElements.quiz.remove();
4806
4807                        $e.find(".wpProQuiz_quizAnker").after(json.content);
4808
4809                        $(
4810                            "table.wpProQuiz_toplistTable caption span.wpProQuiz_max_points"
4811                        ).html(config.globalPoints);
4812
4813                        //Reinit globalElements
4814                        globalElements = {
4815                            back: $e.find('input[name="back"]'),
4816                            next: $e.find(globalNames.next),
4817                            quiz: $e.find(".wpProQuiz_quiz"),
4818                            questionList: $e.find(".wpProQuiz_list"),
4819                            results: $e.find(".wpProQuiz_results"),
4820                            sending: $e.find(".wpProQuiz_sending"),
4821                            quizStartPage: $e.find(".wpProQuiz_text"),
4822                            timelimit: $e.find(".wpProQuiz_time_limit"),
4823                            toplistShowInButton: $e.find(".wpProQuiz_toplistShowInButton"),
4824                            listItems: $(),
4825                            save: $(".ld_advance_quiz_save"), //Added by webxity
4826                            resume: $(".ld_advance_quiz_resume"), //Added by webxity
4827                            save_as_next: $("#ld_advanced_save_as_next").val() //Added by webxity
4828                        };
4829
4830                        plugin.methode.initQuiz();
4831
4832                        if (quizStart) plugin.methode.startQuiz(true);
4833
4834                        // load script to show player for ajax content
4835                        var data = json.content;
4836                        var audiotag = data.search("wp-audio-shortcode");
4837                        var videotag = data.search("wp-video-shortcode");
4838                        if (audiotag != "-1" || videotag != "-1") {
4839                            $.getScript(
4840                                json.site_url +
4841                                "/wp-includes/js/mediaelement/mediaelement-and-player.min.js"
4842                            );
4843                            $.getScript(
4844                                json.site_url +
4845                                "/wp-includes/js/mediaelement/wp-mediaelement.js"
4846                            );
4847                            $("<link/>", {
4848                                rel: "stylesheet",
4849                                type: "text/css",
4850                                href:
4851                                    json.site_url +
4852                                    "/wp-includes/js/mediaelement/mediaelementplayer.min.css"
4853                            }).appendTo("head");
4854                        }
4855                    }
4856                );
4857            },
4858
4859            saveQuestionClicked: function (skipPopup) {
4860                // If skipPopup is true, directly save without showing popup
4861                if (skipPopup === true) {
4862                    plugin.methode.performQuizSave();
4863                    return;
4864                }
4865                
4866                // Show the popup instead of directly saving
4867                plugin.methode.showSavePopup();
4868            },             showSavePopup: function() {
4869                // Create popup HTML if it doesn't exist
4870                if ($('#ld_advance_quiz_save_popup').length === 0) {
4871                    var isAllAtOnce = (globalElements.next.length === 0 || !globalElements.next.is(':visible'));
4872                    var nextBtnText = isAllAtOnce ? 'Save Data' : 'Next Question';
4873                    var nextBtnIcon = isAllAtOnce ? 'dashicons-cloud-saved' : 'dashicons-arrow-right-alt';
4874                    var nextBtnInfo = isAllAtOnce ? 'Save your progress and continue working on the quiz.' : 'Continue to the next question in the quiz.';
4875
4876                    var popupHtml = `
4877                        <div id="ld_advance_quiz_save_popup" class="ld-advance-quiz-popup-overlay" style="display: none;">
4878                            <div class="ld-advance-quiz-popup-content">
4879                                <div class="ld-advance-quiz-popup-header">
4880                                    <h3>Quiz Progress</h3>
4881                                    <span class="ld-advance-quiz-popup-close">&times;</span>
4882                                </div>
4883                                <div class="ld-advance-quiz-popup-body">
4884                                    <p>Your quiz progress has been saved. What would you like to do next?</p>
4885                                    <div class="ld-advance-quiz-popup-buttons">
4886                                        <button id="ld_advance_quiz_restart_btn" class="ld-advance-quiz-popup-btn ld-advance-quiz-popup-btn-secondary">
4887                                            <span class="dashicons dashicons-update"></span>
4888                                            Start Quiz
4889                                        </button>
4890                                        <button id="ld_advance_quiz_next_btn" class="ld-advance-quiz-popup-btn ld-advance-quiz-popup-btn-primary">
4891                                            <span class="dashicons ${nextBtnIcon}"></span>
4892                                            ${nextBtnText}
4893                                        </button>
4894                                    </div>
4895                                    <div class="ld-advance-quiz-popup-info">
4896                                        <p><strong>Start Quiz Button:</strong> Start the quiz over from the beginning.</p>
4897                                        <p><strong>${nextBtnText} Button:</strong> ${nextBtnInfo}</p>
4898                                    </div>
4899                                </div>
4900                            </div>
4901                        </div>
4902                    `;
4903                    
4904                    // CSS styles are now in ld-advanced-quiz-frontend-style.css
4905                    $('body').append(popupHtml);
4906                    
4907                    // Bind events
4908                    $('#ld_advance_quiz_save_popup').on('click', function(e) {
4909                        if (e.target === this) {
4910                            plugin.methode.hideSavePopup();
4911                        }
4912                    });
4913                    
4914                    $('.ld-advance-quiz-popup-close').on('click', function() {
4915                        plugin.methode.hideSavePopup();
4916                    });
4917                    
4918                    $('#ld_advance_quiz_next_btn').on('click', function() {
4919                        plugin.methode.hideSavePopup();
4920                        plugin.methode.performSaveAndNext();
4921                    });
4922                    
4923                    $('#ld_advance_quiz_restart_btn').on('click', function() {
4924                        plugin.methode.hideSavePopup();
4925                        plugin.methode.performSaveAndRestart();
4926                    });
4927                }
4928                
4929                // Show the popup
4930                $('#ld_advance_quiz_save_popup').fadeIn(300);
4931            },
4932
4933            hideSavePopup: function() {
4934                $('#ld_advance_quiz_save_popup').fadeOut(300);
4935            },
4936
4937            performSaveAndNext: function() {
4938                // First save the quiz
4939                plugin.methode.performQuizSave(function() {
4940                    // If we are in "All questions at once" mode (no next button), just close the popup
4941                    if (globalElements.next.length === 0 || !globalElements.next.is(':visible')) {
4942                        // Success message is already shown by performQuizSave
4943                        return;
4944                    }
4945                    
4946                    // Otherwise go to next question
4947                    plugin.methode.nextQuestion();
4948                });
4949            },
4950
4951            performSaveAndRestart: function() {
4952                // First save the quiz
4953                plugin.methode.performQuizSave(function() {
4954                    // Then reload the entire page to restart
4955                    location.reload();
4956                });
4957            },
4958
4959            performQuizSave: function(callback) {
4960                var quizId = config.quizId;
4961
4962                var quizPostId = config.quiz;
4963                if (globalElements.save_as_next != "yes") {
4964
4965                    // timelimit.pause();
4966                    var time = (+new Date() - startTime) / 1000;
4967                    time =
4968                        config.timelimit && time > config.timelimit
4969                            ? config.timelimit
4970                            : time;
4971                    timespent = time;
4972                    $e.find(".wpProQuiz_quiz_time span").text(
4973                        plugin.methode.parseTime(time)
4974                    );
4975                }
4976
4977                var finishQuiz = list == undefined ? false : true;
4978                var responses = {};
4979                var r = {};
4980                var list = globalElements.questionList.children();
4981                var endCheck = true;
4982                var list = globalElements.questionList.children();
4983                list = list == undefined ? currentQuestion : list;
4984
4985                list.each(function () {
4986                    var $this = $(this);
4987                    var question_index = $this.index();
4988                    var $questionList = $this.find(globalNames.questionList);
4989                    var question_id = $questionList.data("question_id");
4990                    var data = config.json[$questionList.data("question_id")];
4991                    var name = data.type;
4992
4993                    if (data.type == "single" || data.type == "multiple") {
4994                        name = "singleMulti";
4995                    }
4996
4997                    //if (config.ld_script_debug == true) {
4998                    //  console.log('checkQuestion: calling readResponses');
4999                    //}
5000
5001                    responses[question_id] = readResponses(
5002                        name,
5003                        data,
5004                        $this,
5005                        $questionList,
5006                        false
5007                    );
5008
5009
5010                    responses[question_id]["question_pro_id"] = data["id"];
5011                    responses[question_id]["question_post_id"] = data["question_post_id"];
5012
5013                    plugin.methode.CookieSaveResponse(
5014                        question_id,
5015                        question_index,
5016                        data.type,
5017                        responses[question_id]
5018                    );
5019                });
5020
5021                //Added by webxity
5022                // Get current question ID
5023                var currentQuestionId = null;
5024                if (currentQuestion && currentQuestion.find) {
5025                    var $questionList = currentQuestion.find(globalNames.questionList);
5026                    if ($questionList && $questionList.data) {
5027                        currentQuestionId = $questionList.data('question_id');
5028                    }
5029                }
5030
5031                var resume_cookie;
5032                var currentTimerValue = null;
5033
5034                $.cookie.raw = true;
5035
5036                if (LDAdvancedQuizVars.time_limit_enabled == 'on') {
5037                    // Main timer
5038                    var timer_cookie = 'ldadv-time-limit-' + config.user_id + '-' + config.quizId;
5039                    resume_cookie = timer_cookie + "-resume";
5040                    currentTimerValue = $.cookie(timer_cookie);
5041                } else {
5042                    // Question-specific timer - include question ID in cookie name
5043                    var timer_cookie = "ldadv-time-limit-" + config.user_id + "-" + config.quizId;
5044                    if (currentQuestionId) {
5045                        timer_cookie += "-q" + currentQuestionId;
5046                    }
5047                    resume_cookie = timer_cookie + "-resume";
5048                    currentTimerValue = $.cookie(timer_cookie);
5049                }
5050                //Added by webxity
5051                
5052                // Get timer value from multiple possible sources if c
5052ookie is empty
5053                if (!currentTimerValue || currentTimerValue === 'undefined') {
5054                    var displayedTime = globalElements.timelimit.find('span').text();
5055                    
5056                    if (displayedTime && displayedTime.includes(':')) {
5057                        var timeParts = displayedTime.split(':');
5058                        if (timeParts.length === 3) {
5059                            var hours = parseInt(timeParts[0]) || 0;
5060                            var minutes = parseInt(timeParts[1]) || 0;
5061                            var seconds = parseInt(timeParts[2]) || 0;
5062                            currentTimerValue = hours * 3600 + minutes * 60 + seconds;
5063                        }
5064                    }
5065                    
5066                    if (!currentTimerValue) {
5067                        if (typeof timelimit.isRunning === 'function' && timelimit.isRunning()) {
5068                            var elapsed = (+new Date() - startTime) / 1000;
5069                            currentTimerValue = Math.max(0, config.timelimit - elapsed);
5070                        } else {
5071                            currentTimerValue = config.timelimit;
5072                        }
5073                    }
5074                }
5075                
5076                currentTimerValue = parseFloat(currentTimerValue);
5077                
5078                if (currentTimerValue && currentTimerValue > 0) {
5079                    var expireDate = new Date();
5080                    expireDate.setTime(expireDate.getTime() + (24 * 60 * 60 * 1000)); // 24 hours
5081                    
5082                    $.cookie(resume_cookie, currentTimerValue.toString(), { expires: expireDate });
5083                    
5084                    var verifyValue = $.cookie(resume_cookie);
5085                }
5086                // Continue with existing server save logic
5087                var timelimitData = {};
5088                if (LDAdvancedQuizVars.time_limit_enabled == 'on') {
5089                    if (currentTimerValue) {
5090                        timelimitData.main_timer = currentTimerValue;
5091                    }
5092                } else {
5093                    if (currentTimerValue) {
5094                        timelimitData.question_timer = currentTimerValue;
5095                    }
5096                }
5097
5098                plugin.methode.ajax(
5099                    {
5100                        action: "ld_advance_save_quiz_pro", //changed for advance addon
5101                        func: "checkAnswers",
5102                        data: {
5103                            quizId: config.quizId,
5104                            quiz: config.quiz,
5105                            course_id: config.course_id,
5106                            quiz_nonce: config.quiz_nonce,
5107                            responses: JSON.stringify(responses),
5108                            viewedQuestions: viewedQuestions,
5109                            lastViewedQuestion: lastViewedQuestion,
5110                            saveQuizTrigger: saveQuizTrigger,
5111                            checkedQuestions: checkedQuestions,
5112                            timelimitData: JSON.stringify(timelimitData)
5113                        }
5114                    },
5115                    function (json) {
5116                        plugin.methode.hideSpinner();
5117                        jQuery(".ld_advance_quiz_resume").show();
5118                        jQuery("#ld_advance_quiz_resume_start").hide();
5119
5120                        if (globalElements.save_as_next != "yes") {
5121                            $(".wp_pro_quiz_message")
5122                                .html("Quiz state is saved.")
5123                                .css("display", "block");
5124                            // location.reload();
5125                        }
5126                        
5127                        // Execute the callback if provided
5128                        if (typeof callback === 'function') {
5129                            callback();
5130                        }
5131                    }
5132                );
5133            },
5134            
5135            load_save_resume: function () {
5136
5137                if (is_resume_save_event_attached == false) {
5138                    if (globalElements.save)
5139                        globalElements.save.click(plugin.methode.saveQuestionClicked); // added by webxity
5140
5141                    if (globalElements.resume)
5142                        globalElements.resume.click(plugin.methode.resumeQuestionClicked); // added by webxity
5143                    is_resume_save_event_attached = true;
5144                }
5145            },
5146            mark_drag_fill_nav_link: function () {
5147                
5148                $('.ldavq-jumbled-dnd-dropzone').on('drop', function () {
5149                    if (currentQuestion) {
5150                        $e.trigger({ type: 'questionSolved', values: { item: currentQuestion, index: currentQuestion.index(), solved: true } });
5151                    }
5152                })
5153                
5154                $(document).on('touchend', function(e) {
5155                    if (currentQuestion) {
5156                        $e.trigger({ type: 'questionSolved', values: { item: currentQuestion, index: currentQuestion.index(), solved: true } });
5157                    }
5158                }); 
5159                
5160            },
5161
5162            //Added by webxity
5163            deleteAllTimerCookies: function() {
5164                var base_cookie = "ldadv-time-limit-" + config.user_id + "-" + config.quizId;
5165                
5166                // Delete main timer cookie
5167                $.removeCookie(base_cookie);
5168                $.removeCookie(base_cookie + "-resume");
5169                
5170                // Delete all question-specific timer cookies
5171                if (LDAdvancedQuizVars.time_limit_enabled != 'on') {
5172                    // Get all questions and delete their timer cookies
5173                    $e.find(".wpProQuiz_questionList").each(function() {
5174                        var question_id = $(this).data("question_id");
5175                        if (question_id) {
5176                            var question_cookie = base_cookie + "-q" + question_id;
5177                            $.removeCookie(question_cookie);
5178                            $.removeCookie(question_cookie + "-resume");
5179                        }
5180                    });
5181                }
5182            },
5183            //Added by webxity
5184
5185            resumeQuestionClicked: function (e) {
5186                e.preventDefault();
5187                is_quiz_resume_in_process = "yes";
5188                
5189                var post_data = {
5190                    action: "ld_advance_resume_quiz",
5191                    quizId: config.quizId,
5192                    quizPostId: config.quiz
5193                };
5194
5195                jQuery.ajax({
5196                    type: "POST",
5197                    url: WpProQuizGlobal.ajaxurl,
5198                    dataType: "json",
5199                    cache: false,
5200                    data: post_data,
5201                    error: function (jqXHR, textStatus, errorThrown) { },
5202                    success: function (reply_data) {
5203                        if( reply_data.type && reply_data.type == 'limit_reached' ){
5204                            $(".wp_pro_quiz_message")
5205                                .html(reply_data.message)
5206                                .css({
5207                                    "display": "block",
5208                                    "background-color": "red"
5209                                });
5210                            return;
5211                        }
5212                        
5213                        viewedQuestions = Object.values(reply_data.viewedQuestions).map(Number);
5214                        checkedQuestions = Object.values(reply_data.checkedQuestions).map(Number);
5215                        saveQuizTrigger = reply_data.saveQuizTrigger;
5216
5217                        $(".wp_pro_quiz_message")
5218                            .html("")
5219                            .css("display", "none");
5220
5221                        resumedQuestions = reply_data.data.questions;
5222
5223                        // Determine which question to resume on
5224                        var savedLastViewedQuestion;
5225                        if (viewedQuestions.length > 0) {
5226                            savedLastViewedQuestion = viewedQuestions[viewedQuestions.length - 1];
5227                        } else {
5228                            savedLastViewedQuestion = parseInt(reply_data.lastViewedQuestion);
5229                        }
5230
5231                        // Check if quiz needs to be started
5232                        var needsQuizStart = !quizStatus.isQuizStart;
5233                        
5234                        if (needsQuizStart) {
5235                            plugin.methode.startQuiz();
5236                            
5237                            // Reduced timeout - only wait for DOM
5238                            setTimeout(function() {
5239                                loadResumeData();
5240                            }, 50);
5241                        } else {
5242                            loadResumeData();
5243                        }
5244                        
5245                        function loadResumeData() {
5246                            if (mySwipe.length === 0) {
5247                                myswipefunction();
5248                            }
5249
5250                            // Timer setup
5251                            var resume_cookie = "ldadv-time-limit-resume-" + config.user_id + "-" + config.quizId;
5252                            $.cookie.raw = true;
5253                            var resumeTimerValue = $.cookie(resume_cookie);
5254                            var shouldRestoreTimer = false;
5255                            var originalTimerStart = timelimit.start;
5256                            var loadedQuestionId = savedLastViewedQuestion;
5257
5258                            if (LDAdvancedQuizVars.time_limit_enabled != 'on') {
5259                                var timer_cookie = "ldadv-time-limit-" + config.user_id + "-" + config.quizId + "-q" + loadedQuestionId;
5260                                var resume_cookie = timer_cookie + "-resume";
5261                                resumeTimerValue = $.cookie(resume_cookie);
5262                            }
5263                            
5264                            if (resumeTimerValue && resumeTimerValue !== 'undefined' && parseFloat(resumeTimerValue) > 0) {
5265                                shouldRestoreTimer = true;
5266                                timelimit.enableResumeMode();
5267                                timelimit.setResumedTime(resumeTimerValue);
5268                                timelimit.setCurrentQuestion(loadedQuestionId);
5269                            } else {
5270                                timelimit.start = function() { return; };
5271                            }
5272
5273                            var list = globalElements.questionList.children();
5274                            var swipe_element_index = -1;
5275                            var targetQuestionIndex = 0;
5276
5277                            // Load saved answers for each question
5278                            list.each(function (listIndex) {
5279                                var $this = $(this);
5280                                var $questionList = $this.find(globalNames.questionList);
5281                                var question_id = $questionList.data("question_id");
5282                                var data = config.json[question_id];
5283
5284                                // Track which question to show
5285                                if (question_id === savedLastViewedQuestion) {
5286                                    targetQuestionIndex = listIndex;
5287                                }
5288
5289                                if (!viewedQuestions.includes(question_id)) return;
5290
5291                                var question = [];
5292                                if (resumedQuestions && resumedQuestions[question_id] && resumedQuestions[question_id]["response"]) {
5293                                    question = resumedQuestions[question_id]["response"];
5294                                }
5295                                
5296                                if (data.type == "laq_swipe_questions") {
5297                                    swipe_element_index++;
5298                                }
5299
5300                                var main_index = list.index($this);
5301                                switch (data.type) {
5302                                    case "single":
5303
5304                                        jQuery(".wpProQuiz_questionListItem", $questionList).each(
5305                                            function (i) {
5306                                                var $item = $(this);
5307                                                var index = $item.attr("data-pos");
5308
5309                                                if (question[index] == true) {
5310                                                    $item
5311                                                        .find("input[type=radio]")
5312                                                        .prop("checked", true);
5313                                                    $e.trigger({
5314                                                        type: "questionSolved",
5315                                                        values: {
5316                                                            item: $this,
5317                                                            index: main_index,
5318                                                            solved: true
5319                                                        }
5320                                                    });
5321                                                }
5322                                            }
5323                                        );
5324
5325                                        break;
5326                                    case "multiple":
5327
5328                                        jQuery(".wpProQuiz_questionListItem", $questionList).each(
5329                                            function (i) {
5330                                                var $item = $(this);
5331                                                var index = $item.attr("data-pos");
5332
5333                                                if (question[index] == true) {
5334                                                    $item
5335                                                        .find("input[type=checkbox]")
5336                                                        .prop("checked", true);
5337                                                    $e.trigger({
5338                                                        type: "questionSolved",
5339                                                        values: {
5340                                                            item: $this,
5341                                                            index: main_index,
5342                                                            solved: true
5343                                                        }
5344                                                    });
5345                                                }
5346                                            }
5347                                        );
5348                                        break;
5349                                    case "free_answer":
5350
5351                                        var $li = $questionList.children();
5352                                        var value = $li
5353                                            .find(".wpProQuiz_questionInput")
5354                                            .val(question);
5355                                        $li
5356                                            .find(".wpProQuiz_questionInput")
5357                                            .attr("disabled", false);
5358                                        if (question != "") {
5359                                            $e.trigger({
5360                                                type: "questionSolved",
5361                                                values: {
5362                                                    item: $this,
5363                                                    index: main_index,
5364                                                    solved: true
5365                                                }
5366                                            });
5367                                        }
5368                                        break;
5369                                    case "cloze_answer":
5370
5371                                        $questionList
5372                                            .find(".wpProQuiz_cloze")
5373                                            .each(function (i, v) {
5374                                                var $this = $(this);
5375                                                $this.find("input[type=text]").val(question[i]);
5376                                                if (question[i] != "") {
5377                                                    $e.trigger({
5378                                                        type: "questionSolved",
5379                                                        values: {
5380                                                            item: $this,
5381                                                            index: main_index,
5382                                                            solved: true
5383                                                        }
5384                                                    });
5385                                                }
5386                                            });
5387                                        break;
5388
5389                                    case "sort_answer":
5390                                        var $items = $questionList.children();
5391                                        
5392                                        // Build array of items in correct order
5393                                        var sortedElements = [];
5394                                        
5395                                        for (var i = 0; i < question.length; i++) {
5396                                            var curr_id = question[i];
5397                                            
5398                                            // Find matching item
5399                                            var matchedItem = $items.filter('[data-pos="' + curr_id + '"]').first();
5400                                            if (matchedItem.length) {
5401                                                sortedElements.push(matchedItem[0]);
5402                                            }
5403                                        }
5404                                        
5405                                        // Reorder by appending in sequence
5406                                        for (var i = 0; i < sortedElements.length; i++) {
5407                                            $questionList.append(sortedElements[i]);
5408                                        }
5409                                        
5410                                        // Trigger solved event
5411                                        $e.trigger({
5412                                            type: "questionSolved",
5413                                            values: {
5414                                                item: $this,
5415                                                index: main_index,
5416                                                solved: true
5417                                            }
5418                                        });
5419                                        break;
5420                                    case "matrix_sort_answer":
5421
5422                                        $sortable_items = $questionList
5423                                            .parent()
5424                                            .find(".wpProQuiz_sortStringList");
5425                                        for (var j = 0; j < question.length; j++) {
5426                                            var curr_id = question[j];
5427                                            jQuery(
5428                                                ".wpProQuiz_questionListItem",
5429                                                $questionList
5430                                            ).each(function (i) {
5431                                                var $item = $(this);
5432                                                var index = $item.attr("data-pos");
5433                                                if (curr_id == index) {
5434                                                    $sortable_items.find("li").each(function () {
5435                                                        var $inner_item = $(this);
5436                                                        var inner_index = $inner_item.attr("data-pos");
5437                                                        if (inner_index == j) {
5438                                                            var element = $inner_item.detach();
5439                                                            $item
5440                                                                .find(".wpProQuiz_maxtrixSortCriterion")
5441                                                                .append(element);
5442                                                        }
5443                                                    });
5444                                                    $e.trigger({
5445                                                        type: "questionSolved",
5446                                                        values: {
5447                                                            item: $this,
5448                                                            index: main_index,
5449                                                            solved: true
5450                                                        }
5451                                                    });
5452                                                }
5453                                            });
5454                                        }
5455                                        break;
5456                                    case "assessment_answer":
5457                                        jQuery(
5458                                            ".wpProQuiz_questionListItem input",
5459                                            $questionList
5460                                        ).each(function (i) {
5461                                            var $item = $(this);
5462                                            var index = $item.attr("data-pos");
5463                                            if (parseInt(question) == parseInt($item.val())) {
5464                                                $item.prop("checked", true);
5465                                                $e.trigger({
5466                                                    type: "questionSolved",
5467                                                    values: {
5468                                                        item: $this,
5469                                                        index: main_index,
5470                                                        solved: true
5471                                                    }
5472                                                });
5473                                            }
5474                                        });
5475                                        break;
5476                                    case "essay":
5477                                        var $li = $questionList.children();
5478                                        $li.find("textarea").val(question);
5479                                        
5480                                        if (question != "") {
5481                                            // Extract path after wp-content/ and replace slashes with backslashes
5482                                            let finalEssayURL = question;
5483                                            
5484                                            // Remove everything up to and including "wp-content/"
5485                                            if (finalEssayURL.includes('wp-content/')) {
5486                                                finalEssayURL = finalEssayURL.split('wp-content/')[1];
5487                                            }
5488                                            
5489                                            // Replace forward slashes with backslashes
5490                                            finalEssayURL = finalEssayURL.replace(/\//g, '\\');
5491                                            
5492                                            var uploadEssaySubmit = $("#uploadEssaySubmit_" + question_id);
5493                                            const question_input = $questionList.find('#uploadEssayFile_' + question_id);
5494                                            
5495                                            $(question_input).val(question);
5496                                            $('<p>' + basename(finalEssayURL) + '</p>').insertAfter(question_input);
5497                                            
5498                                            uploadEssaySubmit.val(config.essaySuccess);
5499                                            
5500                                            $e.trigger({
5501                                                type: "questionSolved",
5502                                                values: {
5503                                                    item: $this,
5504                                                    index: main_index,
5505                                                    solved: true
5506                                                }
5507                                            });
5508                                        }
5509                                        break;
5510                                    case "laq_audio_questions":
5511
5512                                        // let audio = top_parent.find(".ldavq-audio-player");
5513                                        // let source = top_parent.find(".audio-source");
5514                                        // var downloadButton  = top_parent.find('.ldavq_downloadLink');
5515                                        // source.src = url;
5516                                        // audio.load(); 
5516//call this to just preload the audio without playing
5517
5518                                        var $li = $questionList.children();
5519                                        $li.find("textarea").val($li);
5520                                        if (question != "") {
5521                                            
5522                                            let audios = document.getElementsByClassName("ldavq-audio-player-"+question_id);
5523                                            if( audios.length > 0 ) {
5524                                                let audio = audios[0];
5525                                                audio.style.display = 'block';
5526                                                let sources = document.getElementsByClassName("ldavq-audio-source-player-"+question_id);
5527                                                if( sources.length > 0 ) {
5528                                                    let source = sources[0];
5529                                                    source.src = question;
5530                                                }
5531                                                audio.load();
5532                                            }
5533
5534                                            //Essay Upload Start
5535                                            var uploadaudioSubmit = $("#ldavq_submitBtn_" + question_id);
5536                                            $("#uploadAudioFile_" + question_id).val(
5537                                                question
5538                                            );
5539
5540                                            // uploadaudioSubmit.attr("disabled", "disabled");
5541                                            uploadaudioSubmit.val(config.essaySuccess);
5542                                            //Essay Upload End
5543
5544                                            $e.trigger({
5545                                                type: "questionSolved",
5546                                                values: {
5547                                                    item: $this,
5548                                                    index: main_index,
5549                                                    solved: true
5550                                                }
5551                                            });
5552                                        }
5553                                        break;
5554                                    case "laq_jumbled_sentence":
5555                                        for (var i = 0; i < question.length; i++) {
5556                                            var record = question[i];
5557                                            jQuery(
5558                                                "select[name=" + record.name + "]",
5559                                                $questionList
5560                                            ).val(record.option);
5561                                            if (record.option != "") {
5562                                                $e.trigger({
5563                                                    type: "questionSolved",
5564                                                    values: {
5565                                                        item: $this,
5566                                                        index: main_index,
5567                                                        solved: true
5568                                                    }
5569                                                });
5570                                            }
5571                                        }
5572                                        break;
5573                                    case "laq_jumble_dnd_sentence":
5574
5575                                        for (var i = 0; i < question.length; i++) {
5576                                            var record = question[i];
5577
5578                                            $this.find('#' + record.id).val(record.option)
5579
5580                                            if (record.option != "") {
5581                                                $e.trigger({
5582                                                    type: "questionSolved",
5583                                                    values: {
5584                                                        item: $this,
5585                                                        index: main_index,
5586                                                        solved: true
5587                                                    }
5588                                                });
5589                                            }
5590                                        }
5591                                        break;
5592                                    case "laq_swipe_questions":
5593                                        for (var i = 0; i < question.length; i++) {
5594                                            var record = question[i];
5595                                            
5596                                            // Set the attempted value from record data
5597                                            var attemptedValue = record.attempted || "no";
5598                                            $this.find("#laq_advanced_swipe_attempted" + i).val(attemptedValue);
5599                                            
5600                                            if (record.attempted == "yes") {
5601                                                $e.trigger({
5602                                                    type: "questionSolved",
5603                                                    values: {
5604                                                        item: $this,
5605                                                        index: main_index,
5606                                                        solved: true
5607                                                    }
5608                                                });
5609                                                
5610                                                if (mySwipe[swipe_element_index] && 
5611                                                    typeof mySwipe[swipe_element_index].shiftSlide === 'function') {
5612                                                    if (parseInt(record.selection) == 0) {
5613                                                        mySwipe[swipe_element_index].shiftSlide(
5614                                                            -1,
5615                                                            "drag",
5616                                                            "outside"
5617                                                        );
5618                                                    } else {
5619                                                        mySwipe[swipe_element_index].shiftSlide(
5620                                                            1,
5621                                                            "drag",
5622                                                            "outside"
5623                                                        );
5624                                                    }
5625                                                }
5626                                            }
5627                                        }
5628                                        break;
5629                                    case "laq_calculated_formula":
5630
5631                                        //if(config.mode==2) {
5632                                        break; //Keep this question type unsolved on resume, as it has a variable answer so user must attempt it after clicking quiz resume
5633                                        //}
5634                                        for (var i = 0; i < question.length; i++) {
5635                                            var record = question[i];
5636                                            $itm = jQuery(".card_calculation", $questionList).eq(i);
5637                                            $itm
5638                                                .find(".laq_advanced_calculated_selection")
5639                                                .val(record.selection);
5640                                            if (record.selection != "") {
5641                                                $e.trigger({
5642                                                    type: "questionSolved",
5643                                                    values: {
5644                                                        item: $this,
5645                                                        index: main_index,
5646                                                        solved: true
5647                                                    }
5648                                                });
5649                                            }
5650                                        }
5651                                        break;
5652                                }
5653                                /* Added by AR */
5654                                const handler = window.questionTypeHandlers[data.type];
5655                                if (handler) handler($questionList, question, $e, $this, main_index, question_id, config);
5656                            // }
5657                        });
5658
5659                            jQuery(".ld_advance_quiz_resume").hide();
5660                            
5661                            if (config.mode == 2) {
5662                                plugin.methode.checkQuestion(list);
5663                            } else {
5664                                is_quiz_resume_in_process = "no";
5665                            }
5666
5667                            // Navigate immediately - no setTimeout
5668                            plugin.methode.showQuestion(targetQuestionIndex);
5669                            
5670                            // Restore timer functionality immediately
5671                            timelimit.start = originalTimerStart;
5672
5673                            // Only delay timer start slightly
5674                            if (shouldRestoreTimer) {
5675                                setTimeout(function() {
5676                                    if (!timelimit.isRunning()) {
5677                                        timelimit.start();
5678                                    }
5679                                }, 50);
5680                            } else {
5681                                if (LDAdvancedQuizVars.time_limit_enabled != 'on') {
5682                                    setTimeout(function() {
5683                                        if (timelimit.getInterval() == 0) {
5684                                            timelimit.start();
5685                                        }
5686                                    }, 50);
5687                                }
5688                            }
5689                        }
5690                    }
5691                });
5692            },
5693            nextQuestionClicked() {
5694                if (currentQuestion.data('type').trim() == 'laq_jumbled_sentence') {
5695                    var empty_count = 0;
5696                    // currentQuestion.find('.laq_jumbled_sentence_dropdown').each(function () {
5697                    //     var $this = $(this);
5698                    //     if ($(this).val().trim() == '') {
5699                    //         $(this).addClass('ldavq_jumbled_sentence_empty_error');
5700                    //         empty_count += 1;
5701                    //     } else {
5702                    //         $(this).removeClass('ldavq_jumbled_sentence_empty_error');
5703                    //     }
5704
5705                    // });
5706
5707                    if (empty_count > 0)
5708                        return;
5709                }
5710
5711                if(Object.keys(window.nexrQuestionClickedCalled).length > 0){
5712                    Object.keys(window.nexrQuestionClickedCalled).forEac
5712h(function(key) {
5713                        let fn = window.nexrQuestionClickedCalled[key];
5714                        if(typeof fn === "function"){
5715                            fn($e, currentQuestion); // run it
5716                        }
5717                    });
5718                }
5719
5720                const $questionList = currentQuestion.find(
5721                    globalNames.questionList
5722                );
5723                const data = config.json[$questionList.data('question_id')];
5724
5725                // Within the following logic. If the question type is 'sort_answer' there is a chance
5726                // the sortable answers will be displayed in the correct order. In that case the user will click
5727                // the next button.
5728                // The trigger to set the question was answered is normally a function of the sort/drag action
5729                // by the user. So we need to set the question answered flag in the case the Quiz summary is enabled.
5730                //if (data.type == 'sort_answer') {
5731                //  var question_index = currentQuestion.index();
5732                //  if ( typeof quizSolved[question_index] === 'undefined') {
5733                //      $e.trigger({type: 'questionSolved', values: {item: currentQuestion, index: question_index, solved: true}});
5734                //  }
5735                //}
5736
5737                if (
5738                    bitOptions.forcingQuestionSolve &&
5739                    !quizSolved[currentQuestion.index()] &&
5740                    (bitOptions.quizSummeryHide || !bitOptions.reviewQustion)
5741                ) {
5742                    // Would really like to do something more stylized instead of a simple alert popup. yuk!
5743                    alert(WpProQuizGlobal.questionNotSolved);
5744                    return false;
5745                }
5746
5747                plugin.methode.nextQuestion();
5748            },
5749            initQuiz() {
5750                //if (config.ld_script_debug == true) {
5751                //  console.log('in initQuiz');
5752                //}
5753
5754                //plugin.methode.setClozeStyle();
5755                plugin.methode.registerSolved();
5756
5757                globalElements.next.on(
5758                    'click',
5759                    plugin.methode.nextQuestionClicked
5760                );
5761
5762                globalElements.back.on('click', function (e) {
5763                    //console.log('back button clicked [%o]', e);
5764                    plugin.methode.prevQuestion();
5765                });
5766                plugin.methode.load_save_resume();
5767                plugin.methode.mark_drag_fill_nav_link();
5768                $e.find(globalNames.check).on('click', function () {
5769                    if (
5770                        bitOptions.forcingQuestionSolve &&
5771                        !quizSolved[currentQuestion.index()]
5772                    ) {
5773                        alert(WpProQuizGlobal.questionNotSolved);
5774                        return false;
5775                    }
5776                    plugin.methode.checkQuestion();
5777                });
5778
5779                $e.find('input[name="checkSingle"]').on('click', function () {
5780                    // First get all the questions...
5781                    const list = globalElements.questionList.children();
5782                    if (list != null) {
5783                        list.each(function () {
5784                            const $this = $(this);
5785                            const $questionList = $this.find(
5786                                globalNames.questionList
5787                            );
5788                            const question_id =
5789                                $questionList.data('question_id');
5790                            const data =
5791                                config.json[$questionList.data('question_id')];
5792
5793                            // Within the following logic. If the question type is 'sort_answer' there is a chance
5794                            // the sortable answers will be displayed in the correct order. In that case the user will click
5795                            // the next button.
5796                            // The trigger to set the question was answered is normally a function of the sort/drag action
5797                            // by the user. So we need to set the question answered flag in the case the Quiz summary is enabled.
5798                            //if (data.type == 'sort_answer') {
5799                            //  //var question_index = $this.index();
5800                            //  //if ( typeof quizSolved[question_index] === 'undefined') {
5801                            //      $e.trigger({type: 'questionSolved', values: {item: $this, index: $this.index(), solved: true}});
5802                            //  //}
5803                            //}
5804                        });
5805                    }
5806
5807                    if (
5808                        bitOptions.forcingQuestionSolve &&
5809                        (bitOptions.quizSummeryHide ||
5810                            !bitOptions.reviewQustion)
5811                    ) {
5812                        for (
5813                            let i = 0,
5814                                c = $e.find('.wpProQuiz_listItem').length;
5815                            i < c;
5816                            i++
5817                        ) {
5818                            if (!quizSolved[i]) {
5819                                alert(WpProQuizGlobal.questionsNotSolved);
5820                                return false;
5821                            }
5822                        }
5823                    }
5824
5825                    plugin.methode.showQuizSummary();
5826                });
5827
5828                $e.find('input[name="tip"]').on(
5829                    'click',
5830                    plugin.methode.showTip
5831                );
5832                $e.find('input[name="skip"]').on(
5833                    'click',
5834                    plugin.methode.skipQuestion
5835                );
5836
5837                $e.find('input[name="wpProQuiz_pageLeft"]').on(
5838                    'click',
5839                    function () {
5840                        plugin.methode.showSinglePage(currentPage - 1);
5841                        plugin.methode.setupMatrixSortHeights();
5842                    }
5843                );
5844
5845                $e.find('input[name="wpProQuiz_pageRight"]').on(
5846                    'click',
5847                    function () {
5848                        plugin.methode.showSinglePage(currentPage + 1);
5849
5850                        plugin.methode.setupMatrixSortHeights();
5851                        //Add by webxity
5852                        if (globalElements.save_as_next == "yes") {
5853                            plugin.methode.saveQuestionClicked(true);
5854                        }
5855                        //Add by webxity end
5856                    }
5857                );
5858
5859                $e.find('input[id^="uploadEssaySubmit"]').on(
5860                    'click',
5861                    plugin.methode.uploadFile
5862                );
5863                $e.find('.ldavq_submitBtn_audio').each(function(index, element) {
5864
5865                    $('.uploadAudioFile').val('');
5866                    $(this).on( "click", plugin.methode.uploadAudio );
5867
5868                });
5869                // Added in LD v2.4 to allow external notification when quiz init happens.
5870                $e.trigger('learndash-quiz-init');
5871            },
5872            // Setup the Cookie specific to the Quiz ID.
5873            CookieInit() {
5874                // Comment out to force clear cookie on init.
5875                // jQuery.cookie(cookie_name, '');
5876
5877                if (config.ld_script_debug == true) {
5878                    console.log('in CookieInit');
5879                }
5880
5881                // Temporarily disable raw mode for this operation
5882                var originalRawSetting = $.cookie.raw;
5883                $.cookie.raw = false;
5884                
5885                cookie_value = jQuery.cookie(cookie_name);
5886                // console.log('hereeeeee',cookie_value);
5887                
5888                // Restore original raw setting
5889                $.cookie.raw = originalRawSetting;
5890                
5891                if (
5892                    !cookie_value ||
5893                    cookie_value == undefined ||
5894                    cookie_value === '%7B%7D'
5895                ) {
5896                    cookie_value = {};
5897                } else {
5898                    // Additional check to ensure we have a string before parsing
5899                    if (typeof cookie_value === 'string') {
5900                        try {
5901                            cookie_value = JSON.parse(cookie_value);
5902                            //console.log("cookie_value[%o]", cookie_value );
5903                        } catch (exception) {
5904                            console.log('JSON.parse error [%o]', exception);
5905                            cookie_value = {};
5906                        }
5907                    } else {
5908                        // console.log('Cookie value is not a string, resetting to empty object');
5909                        cookie_value = {};
5910                    }
5911                }
5912
5913                if (config.ld_script_debug == true) {
5914                    console.log('after parse: cookie_value[%o]', cookie_value);
5915                }
5916
5917                // If we have form entries at the start, save them to cookie.
5918                if (
5919                    bitOptions.formActivated &&
5920                    config.formPos === formPosConst.START &&
5921                    formClass.checkForm()
5922                ) {
5923                    formClass.saveFormDataToCookie();
5924                }
5925
5926                plugin.methode.CookieSetResponses();
5927                plugin.methode.CookieResponseTimer();
5928            },
5929            CookieDelete() {
5930                //if (config.ld_script_debug == true) {
5931                //  console.log('CookieDelete: config.timelimitcookie[%o]', config.timelimitcookie);
5932                //}
5933                //if (config.ld_script_debug == true) {
5934                //  console.log('CookieDelete: cookie_name[%o]', cookie_name);
5935                //}
5936                jQuery.cookie(cookie_name, '');
5937            },
5938            CookieProcessQuestionResponse(list, lockQuestion) {
5939                var lockQuestion = lockQuestion || false;
5940                if (list != null) {
5941                    list.each(function () {
5942                        const $this = $(this);
5943
5944                        const question_index = $this.index();
5945                        const $questionList = $this.find(
5946                            globalNames.questionList
5947                        );
5948                        const question_id = $questionList.data('question_id');
5949                        const data =
5950                            config.json[$questionList.data('question_id')];
5951                        
5952                        // Add safety check to prevent TypeError
5953                        if (!data || !data.type) {
5954                            console.warn('Question data not found for question ID:', question_id);
5955                            return; // Skip this question and continue with the next one
5956                        }
5957                        
5958                        let name = data.type;
5959                        if (data.type == 'single' || data.type == 'multiple') {
5960                            name = 'singleMulti';
5961                        }
5962
5963                        const question_response = readResponses(
5964                            name,
5965                            data,
5966                            $this,
5967                            $questionList,
5968                            false
5969                        );
5970                        
5971                        plugin.methode.saveMetaDataToCookie({
5972                            lastQuestion: question_id,
5973                        });
5974                        plugin.methode.CookieSaveResponse(
5975                            question_id,
5976                            question_index,
5977                            data.type,
5978                            question_response,
5979                            lockQuestion
5980                        );
5981                    });
5982                }
5983            },
5984            // Save the answer(response) to the cookie. This is called from 'checkQuestion' and cookie timer functions.
5985            CookieSaveResponse(
5986                question_id,
5987                question_index,
5988                question_type,
5989                question_response,
5990                lockQuestion
5991            ) {
5992                var lockQuestion = lockQuestion || false;
5993                // set the value
5994                if (question_id === 'formData' + question_index) {
5995                    cookie_value[question_id] = {
5996                        index: question_index,
5997                        value: question_response,
5998                        type: question_type,
5999                    };
6000                } else {
6001                    cookie_value[question_id] = {
6002                        index: question_index,
6003                        value: question_response.response,
6004                        type: question_type,
6005                        lockQuestion,
6006                    };
6007                }
6008                // console.log('CookieSaveResponse',cookie_value);
6009                // Calculate the cookie date to expire
6010                plugin.methode.calculateCookieExpiry();
6011
6012                // store the values.
6013                jQuery.cookie(cookie_name, JSON.stringify(cookie_value), {
6014                    expires: cookieExpireDate,
6015                });
6016
6017                if (config.quiz_resume_enabled === '1') {
6018                    plugin.methode.startCookieSendTimer();
6019                }
6020            },
6021            calculateCookieExpiry() {
6022                cookieExpireDate = new Date();
6023                if (
6024                    config.timelimitcookie &&
6025                    !config.quiz_resume_cookie_expiration
6026                ) {
6027                    cookieExpireDate.setTime(
6028                        cookieExpireDate.getTime() +
6029                            config.timelimitcookie * 1000
6030                    );
6031                }
6032
6033                if (
6034                    config.quiz_resume_cookie_expiration &&
6035                    !config.timelimitcookie
6036                ) {
6037                    cookieExpireDate.setTime(
6038                        cookieExpireDate.getTime() +
6039                            config.quiz_resume_cookie_expiration * 1000
6040                    );
6041                }
6042            },
6043            saveMetaDataToCookie(id, metadata) {
6044                var metadata = metadata || false;
6045                // Calculate the cookie date to expire.
6046                plugin.methode.calculateCookieExpiry();
6047
6048                if (!cookie_value || cookie_value == undefined) {
6049                    cookie_value = {};
6050                }
6051
6052                if (typeof id === 'string' && typeof metadata === 'object') {
6053                    cookie_value[id] = {};
6054                    for (var element in metadata) {
6055                        // @todo Test in IE11
6056                        const obj = { [element]: metadata[element] };
6057                        Object.assign(cookie_value[id], obj);
6058                    }
6059                } else if (typeof id === 'string' && !metadata) {
6060                    cookie_value[id] = true;
6061                } else if (typeof id === 'object') {
6062                    for (var element in id) {
6063                        cookie_value[element] = id[element];
6064                    }
6065                }
6066
6067                // store the values.
6068                jQuery.cookie(cookie_name, JSON.stringify(cookie_value), {
6069                    expires: cookieExpireDate,
6070                });
6071
6072                if (config.quiz_resume_enabled === '1' && !cookieSendTimer) {
6073                    plugin.methode.startCookieSendTimer();
6074                }
6075            },
6076            // The cookie timer loops every 5 seconds to save the last response from the user.
6077            // This only effect Essay questions as there is some current logic where once
6078            // 'readResponses' is called the question is locked.
6079            CookieResponseTimer() {
6080                // Hook into the 'questionSolved' triggered event. This is much better than
6081                // a timer to grab the answer values. With the event trigger we only process the
6082                // single question when the user makes a change.
6083                $e.on('questionSolved', function (e) {
6084                    //if (config.ld_script_debug == true) {
6085                    //  console.log('CookieResponseTimer: e.values[%o]', e.values);
6086                    //}
6087                    if (
6088                        config.timelimitcookie !== 0 ||
6089                        config.quiz_resume_enabled === '1'
6090                    ) {
6091                        plugin.methode.CookieProcessQuestionResponse(
6092                            e.values.item
6093                        );
6094                    }
6095                });
6096            },
6097            // Load the Cookie (if present) and sets the values of the Quiz questions to the cookie saved value
6098            CookieSetResponses() {
6099                if (config.ld_script_debug == true) {
6100                    console.log('In CookieSetResponses');
6101                }
6102
6103                if (
6104                    (cookie_value == undefined ||
6105                        !Object.keys(cookie_value).length) &&
6106                    !config.quiz_resume_id
6107                ) {
6108                    // console.log( 'returning' );
6109                    return;
6110                }
6111
6112                const list = globalElements.questionList.children();
6113                list.each(function () {
6114                    const $this = $(this);
6115
6116                    const $questionList = $this.find(globalNames.questionList);
6117                    const form_question_id = $questionList.data('question_id');
6118
6119                    // Handle server-side data
6120                    if (quiz_resume_data[form_question_id] != undefined) {
6121                        const quiz_resume_question_data =
6122                            quiz_resume_data[form_question_id];
6123                        var form_question_data =
6124                            config.json[$questionList.data('question_id')];
6125
6126                        if (
6127                            form_question_data.type ===
6128                            quiz_resume_question_data.type
6129                        ) {
6130                            setResponse(
6131                                form_question_data,
6132                                quiz_resume_question_data.value,
6133                                $this,
6134                                $questionList,
6135                                quiz_resume_question_data.lockQuestion
6136                            );
6137                        }
6138                    }
6139                    // Handle cookie data
6140                    if (cookie_value[form_question_id] != undefined) {
6141                        const cookie_question_data =
6142                            cookie_value[form_question_id];
6143
6144                        var form_question_data =
6145                            config.json[$questionList.data('question_id')];
6146                        if (
6147                            form_question_data.type ===
6148                            cookie_question_data.type
6149                        ) {
6150                            setResponse(
6151                                form_question_data,
6152                                cookie_question_data.value,
6153                                $this,
6154                                $questionList,
6155                                cookie_question_data.lockQuestion
6156                            );
6157                        }
6158                    }
6159
6160                    // Move to next unanswered question
6161                    if (
6162                        typeof quiz_resume_data !== 'undefined' &&
6163                        typeof cookie_value !== 'undefined'
6164                    ) {
6165                        if (config.ld_script_debug == true) {
6166                            console.log(
6167                                "CookieSet: cookie_value['nextQuestion'][%o]",
6168                                cookie_value.nextQuestion
6169                            );
6170                            console.log(
6171                                'CookieSet: quiz_resume_data[%o]',
6172                                quiz_resume_data
6173                            );
6174                        }
6175                        if (
6176                            typeof cookie_value.nextQuestion !== 'undefined' &&
6177                            cookie_value.nextQuestion
6178                        ) {
6179                            //console.log('cookie_value[%o]', cookie_value);
6180                            plugin.methode.moveToNextUnansweredQuestion(
6181                                cookie_value
6182                            );
6183                        } else {
6184                            //console.log('quiz_resume_data[%o]', quiz_resume_data);
6185                            plugin.methode.moveToNextUnansweredQuestion(
6186                                quiz_resume_data
6187                            );
6188                        }
6189                    }
6190                });
6191            },
6192            startCookieSendTimer() {
6193                // Immediately send the first cookie entry to the server
6194                // to trigger the Continue Quiz logic when no server-side
6195                // data exists.
6196
6197                // If timer is already running, don't start another one.
6198                if (cookieSendTimer) {
6199                    return;
6200                }
6201
6202                // Set flag before starting timer.
6203                cookieSendTimer = true;
6204
6205                if (
6206                    undefined === quiz_resume_data ||
6207                    quiz_resume_data.length === 0
6208                ) {
6209                    plugin.methode.prepareSendCookieData();
6210                }
6211
6212                // Start the Timer
6213                setInterval(function () {
6214                    if (!cookieSending) {
6215                        plugin.methode.prepareSendCookieData();
6216                    }
6217                }, config.quiz_resume_cookie_send_timer * 1000);
6218            },
6219            prepareSendCookieData() {
6220                // Get Timelimit cookie data.
6221                if (config.timelimit) {
6222                    plugin.methode.addTimelimitCookieData();
6223                }
6224
6225                const cookieLength =
6226                    plugin.methode.getObjectLength(cookie_value);
6227                if (cookieLength > 0) {
6228                    const cookieKeys =
6229                        plugin.methode.getObjectKeys(cookie_value);
6230
6231                    // Flag we are sending an ajax request.
6232                    cookieSending = true;
6233                    plugin.methode.sendCookieData(cookieKeys);
6234                }
6235            },
6236            getObjectLength(object) {
6237                return Object.keys(object).length;
6238            },
6239            getObjectKeys(object) {
6240                return Object.keys(object);
6241            },
6242            excludeKeysFromCount(object, exclude) {
6243                const allKeys = plugin.methode.getObjectKeys(object);
6244                let count = 0;
6245                allKeys.forEach(function (key) {
6246                    if (!key.startsWith(exclude)) {
6247                        count++;
6248                    }
6249                });
6250                return count;
6251            },
6252            addTimelimitCookieData() {
6253                const quizTimelimitCookie = jQuery.cookie(
6254                    timelimit.timer_cookie
6255                );
6256                if ('undefined' !== typeof quizTimelimitCookie) {
6257                    plugin.methode.saveMetaDataToCookie({
6258                        [timelimit.timer_cookie]:
6259                            JSON.parse(quizTimelimitCookie),
6260                    });
6261                }
6262            },
6263            moveToNextUnansweredQuestion(data) {
6264                if (config.ld_script_debug == true) {
6265                    console.log('moveToNextUnansweredQuestion: data[%o]', data);
6266                }
6267
6268                if (typeof data !== 'undefined') {
6269                    let nextQuestion =
6270                        typeof data.nextQuestion === 'number'
6271                            ? data.nextQuestion
6272                            : 0;
6273                    const lastQuestion =
6274                        typeof data.lastQuestion === 'number'
6275                            ? data.lastQuestion
6276                            : 0;
6277
6278                    if (config.ld_script_debug == true) {
6279                        console.log(
6280                            'moveToNextUnansweredQuestion: nextQuestion[%o]',
6281                            nextQuestion
6282                        );
6283                        console.log(
6284                            'moveToNextUnansweredQuestion: lastQuestion[%o]',
6285                            lastQuestion
6286                        );
6287                        console.log(
6288                            'moveToNextUnansweredQuestion: config.mode[%o]',
6289                            config.mode
6290                        );
6291                    }
6292
6293                    if (config.mode === 3) {
6294                        if (!config.qpp) {
6295                            jQuery(globalElements.questionList)
6296                                .children()
6297                                .show();
6298                            jQuery(globalElements.listItems).each(function (
6299                                index,
6300                                listItem
6301                            ) {
6302                                if (
6303                                    $(listItem).data('question-meta')
6304                                        .question_pro_id === lastQuestion
6305                                ) {
6306                                    plugin.methode.scrollTo(
6307                                        globalElements.listItems.eq(index),
6308                                        1
6309                                    );
6310                                }
6311                            });
6312                        } else {
6313                            jQuery(globalElements.listItems).each(function (
6314                                index,
6315                                listItem
6316                            ) {
6317                                if (
6318                                    $(listItem).data('question-meta')
6319                                        .question_pro_id === lastQuestion
6320                                ) {
6321                                    plugin.methode.singlePageNavigationQuizResume(
6322                                        index
6323                                    );
6324                                }
6325                            });
6326                        }
6327                    } else {
6328                        if (config.mode == 1 && nextQuestion > 0) {
6329                            nextQuestion = lastQuestion;
6330                        } else if (nextQuestion == 0 && lastQuestion > 0) {
6331                            nextQuestion = lastQuestion;
6332                        }
6333                        jQuery(globalElements.listItems).each(function (
6334                            index,
6335                            listItem
6336                        ) {
6337                            if (
6338                                $(listItem).data('question-meta')
6339                                    .question_pro_id === nextQuestion
6340                            ) {
6341                                if (config.ld_script_debug == true) {
6342                                    console.log(
6343                                        'moveToNextUnansweredQuestion: match: listItem[%o]',
6344                                        listItem
6345                                    );
6346                                }
6347
6348                                currentQuestion =
6349                                    globalElements.listItems.eq(index);
6350
6351                                const questionId = currentQuestion
6352                                    .find(globalNames.questionList)
6353                                    .data('question_id');
6354
6355                                questionTimer.questionStart(questionId);
6356                                plugin.methode.showQuestionObject(
6357                                    currentQuestion
6358                                );
6359
6360                                return false; // break out of the loop.
6361                            }
6362                            // if (config.ld_script_debug == true) {
6363                            //  console.log("moveToNextUnansweredQuestion: not match: listItem[%o]", listItem);
6364                            // }
6365                        });
6366                    }
6367                }
6368            },
6369            // Variation of showSinglePage()
6370            singlePageNavigationQuizResume(index) {
6371                const answeredQuestions = config.qpp >= 1 ? index : index + 1;
6372                const maxPage = Math.ceil(
6373                    $e.find('.wpProQuiz_list > li').length / config.qpp
6374                );
6375                const activePage = Math.ceil(answeredQuestions / config.qpp);
6376
6377                if (activePage <= maxPage) {
6378                    const $listItem = globalElements.questionList
6379                        .children()
6380                        .hide();
6381                    const pl = $e.find(globalNames.singlePageLeft).hide();
6382                    const pr = $e.find(globalNames.singlePageRight).hide();
6383                    const cs = $e.find('input[name="checkSingle"]').hide();
6384
6385                    if (activePage > 1) {
6386                        pl.val(
6387                            pl.data('text').replace(/%d/, activePage - 1)
6388                        ).show();
6389                    }
6390
6391                    if (activePage === maxPage) {
6392                        cs.show();
6393                    } else {
6394                        pr.val(
6395                            pr.data('text').replace(/%d/, activePage 
6395+ 1)
6396                        ).show();
6397                    }
6398
6399                    currentPage = activePage;
6400
6401                    const start = config.qpp * (activePage - 1);
6402
6403                    $listItem.slice(start, start + config.qpp).show();
6404                    if (globalElements.listItems.length === index) {
6405                        index = index - 1;
6406                    }
6407                    plugin.methode.scrollTo(
6408                        globalElements.listItems.eq(index),
6409                        0
6410                    );
6411                }
6412            },
6413            sendCookieData(keys) {
6414                jQuery.ajax({
6415                    type: 'POST',
6416                    url: WpProQuizGlobal.ajaxurl,
6417                    dataType: 'json',
6418                    cache: false,
6419                    data: {
6420                        action: 'wp_pro_quiz_cookie_save_quiz',
6421                        course_id: config.course_id,
6422                        quiz: config.quiz,
6423                        quizId: config.quizId,
6424                        quiz_started: questionTimer.getQuizStart(),
6425                        results: JSON.stringify(cookie_value),
6426                        quiz_nonce: config.quiz_nonce,
6427                    },
6428                    success(response) {
6429                        if (response.success) {
6430                            if (
6431                                plugin.methode.compareObjectKeys(
6432                                    response.data,
6433                                    cookie_value
6434                                )
6435                            ) {
6436                                plugin.methode.deleteCookieKeys(keys);
6437                            }
6438                            cookieSending = false;
6439                        }
6440                    },
6441                    error(xhr) {
6442                        console.log('xhr[%o]', xhr);
6443                        const response = JSON.parse(xhr.responseText);
6444                        console.log(response.data.message);
6445                        cookieSending = false;
6446                    },
6447                });
6448            },
6449            compareObjectKeys(a, b) {
6450                const keysObjectA = Object.keys(a).sort();
6451                const keysObjectB = Object.keys(b).sort();
6452                return (
6453                    JSON.stringify(keysObjectA) === JSON.stringify(keysObjectB)
6454                );
6455            },
6456            deleteCookieKeys(keys) {
6457                // Remove saved keys from cookie object
6458                keys.forEach(function (key) {
6459                    delete cookie_value[key];
6460                });
6461
6462                // Write changed cookie object to cookie
6463                jQuery.cookie(cookie_name, JSON.stringify(cookie_value), {
6464                    expires: cookieExpireDate,
6465                });
6466            },
6467            setupMatrixSortHeights() {
6468                /**
6469                 * Here we have to do all the questions because the current logic when using X questions
6470                 * per page doesn't allow that information.
6471                 */
6472                $('li.wpProQuiz_listItem', globalElements.questionList).each(
6473                    function (idx, questionItem) {
6474                        const question_type = $(questionItem).data('type');
6475                        if ('matrix_sort_answer' === question_type) {
6476                            // On the draggable items get the items max height and set the parent ul to that.
6477                            let sortitems_height = 0;
6478                            $(
6479                                'ul.wpProQuiz_sortStringList li',
6480                                questionItem
6481                            ).each(function (idx, el) {
6482                                const el_height = $(el).outerHeight();
6483                                if (el_height > sortitems_height) {
6484                                    sortitems_height = el_height;
6485                                }
6486                            });
6487                            if (sortitems_height > 0) {
6488                                $(
6489                                    'ul.wpProQuiz_sortStringList',
6490                                    questionItem
6491                                ).css('min-height', sortitems_height);
6492                            }
6493
6494                            $(
6495                                'ul.wpProQuiz_maxtrixSortCriterion',
6496                                questionItem
6497                            ).each(function (idx, el) {
6498                                const parent_td = $(el).parent('td');
6499                                if (typeof parent_td !== 'undefined') {
6500                                    const parent_td_height =
6501                                        $(parent_td).height();
6502                                    if (parent_td_height) {
6503                                        $(el).css('height', parent_td_height);
6504                                        $(el).css(
6505                                            'min-height',
6506                                            parent_td_height
6507                                        );
6508                                    }
6509                                }
6510                            });
6511                        }
6512                    }
6513                );
6514            },
6515        };
6516
6517        /**
6518         * @memberOf plugin
6519         */
6520        plugin.preInit = function () {
6521            plugin.methode.parseBitOptions();
6522            reviewBox.init();
6523
6524            $e.find('input[name="startQuiz"]').on('click', function () {
6525                plugin.methode.startQuiz();
6526                return false;
6527            });
6528
6529            if (bitOptions.checkBeforeStart && !bitOptions.preview) {
6530                plugin.methode.checkQuizLock();
6531            }
6532
6533            $e.find('input[name="reShowQuestion"]').on('click', function () {
6534                plugin.methode.showQustionList();
6535            });
6536
6537            $e.find('input[name="restartQuiz"]').on('click', function () {
6538                plugin.methode.restartQuiz();
6539            });
6540
6541            $e.find('input[name="review"]').on(
6542                'click',
6543                plugin.methode.reviewQuestion
6544            );
6545
6546            $e.find('input[name="wpProQuiz_toplistAdd"]').on(
6547                'click',
6548                plugin.methode.addToplist
6549            );
6550
6551            $e.find('input[name="quizSummary"]').on(
6552                'click',
6553                plugin.methode.showQuizSummary
6554            );
6555
6556            $e.find('input[name="endQuizSummary"]').on('click', function () {
6557                if (bitOptions.forcingQuestionSolve) {
6558                    // First get all the questions...
6559                    list = globalElements.questionList.children();
6560                    if (list != null) {
6561                        list.each(function () {
6562                            const $this = $(this);
6563                            const $questionList = $this.find(
6564                                globalNames.questionList
6565                            );
6566                            const question_id =
6567                                $questionList.data('question_id');
6568                            const data =
6569                                config.json[$questionList.data('question_id')];
6570
6571                            // Within the following logic. If the question type is 'sort_answer' there is a chance
6572                            // the sortable answers will be displayed in the correct order. In that case the user will click
6573                            // the next button.
6574                            // The trigger to set the question was answered is normally a function of the sort/drag action
6575                            // by the user. So we need to set the question answered flag in the case the Quiz summary is enabled.
6576                            //if (data.type == 'sort_answer') {
6577                            //  var question_index = $this.index();
6578                            //  if ( typeof quizSolved[question_index] === 'undefined') {
6579                            //      $e.trigger({type: 'questionSolved', values: {item: $this, index: question_index, solved: true}});
6580                            //  }
6581                            //}
6582                        });
6583                    }
6584
6585                    for (
6586                        let i = 0, c = $e.find('.wpProQuiz_listItem').length;
6587                        i < c;
6588                        i++
6589                    ) {
6590                        if (!quizSolved[i]) {
6591                            alert(WpProQuizGlobal.questionsNotSolved);
6592                            return false;
6593                        }
6594                    }
6595                }
6596
6597                if (
6598                    bitOptions.formActivated &&
6599                    config.formPos == formPosConst.END &&
6600                    !formClass.checkForm()
6601                ) {
6602                    return;
6603                }
6604
6605                plugin.methode.finishQuiz();
6606            });
6607
6608            $e.find('input[name="endInfopage"]').on('click', function () {
6609                if (formClass.checkForm()) {
6610                    plugin.methode.finishQuiz();
6611                }
6612            });
6613
6614            $e.find('input[name="showToplist"]').on('click', function () {
6615                globalElements.quiz.hide();
6616                globalElements.toplistShowInButton.toggle();
6617            });
6618
6619            $e.on('questionSolved', plugin.methode.questionSolved);
6620
6621            if (!bitOptions.maxShowQuestion) {
6622                plugin.methode.initQuiz();
6623            }
6624
6625            if (bitOptions.autoStart) {
6626                plugin.methode.startQuiz();
6627            }
6628
6629            // If the form is shown before the quiz, we need to check if we have saved data.
6630            if (
6631                bitOptions.formActivated &&
6632                config.formPos === formPosConst.START
6633            ) {
6634                formClass.setFormDataFromServer();
6635            }
6636        };
6637
6638        plugin.preInit();
6639    };
6640
6641    $.fn.wpProQuizFront = function (options) {
6642        return this.each(function () {
6643            if (undefined == $(this).data('wpProQuizFront')) {
6644                $(this).data(
6645                    'wpProQuizFront',
6646                    new $.wpProQuizFront(this, options)
6647                );
6648            }
6649        });
6650    };
6651
6652    /**
6653     * Autosize the input field.
6654     * 
6655     * @since 4.21.4
6656     * 
6657     * @param {jQuery} $input       - The input field to autosize.
6658     * @param {number} [$padding=0] - The padding to add to the input field.
6659     */
6660    function autosizeInput($input, $padding = 0) {
6661        const $sizer = $('<span>').css({
6662            position: 'absolute',
6663            visibility: 'hidden',
6664            whiteSpace: 'pre',
6665            font: $input.css('font'),
6666        }).appendTo('body');
6667        
6668        function update() {
6669            $sizer.text($input.val() || $input.attr('placeholder') || '');
6670            $input.width($sizer.width() + 6 + $padding);
6671        }
6672        
6673        $input.on('input', update);
6674        update();
6675    }
6676
6677    // Easy Time instance
6678    var timer = new easytimer.Timer();
6679
6680    // Load Dom Content
6681    $(document).ready(function () {
6682    //window.addEventListener('DOMContentLoaded', function () {
6683        //webkitURL is deprecated but nevertheless
6684        URL = window.URL || window.webkitURL;
6685
6686        // Shim for AudioContext when it's not avb. 
6687        var AudioContext = window.AudioContext || window.webkitAudioContext;
6688        var audioContext; //new audio context to help us record
6689
6690        $('.ldavq_recordBtn').each(function(index, element) {
6691            $(this).on( "click", startRecording )
6692        });
6693        $('.ldavq_stopBtn').each(function(index, element) {
6694            $(this).on( "click", stopRecording );
6695        });
6696        $('.ldavq_pauseBtn').each(function(index, element) {
6697            $(this).on( "click", pauseRecording )
6698        });
6699
6700        // recordButton.addEventListener("click", startRecording);
6701        // stopButton.addEventListener("click", stopRecording);
6702        // // submitButton.addEventListener("click", submitRecording);  
6703        // pauseButton.addEventListener("click", pauseRecording);
6704
6705        // var recordButton = document.getElementById("ldavq_recordBtn");
6706        // var stopButton = document.getElementById("ldavq_stopBtn");
6707        // var downloadButton = document.getElementById("ldavq_downloadBtn");
6708        // var pauseButton = document.getElementById("ldavq_pauseBtn");
6709
6710        var duration;
6711        var question_id;
6712        var top_parent;
6713        // question_id = recordButton.getAttribute('data-questionId');
6714        // duration = recordButton.getAttribute('data-timer');
6715        // question_id = stopButton.getAttribute('data-questionId');
6716        // duration = stopButton.getAttribute('data-timer');
6717        // question_id = pauseButton.getAttribute('data-questionId');
6718        // duration = pauseButton.getAttribute('data-timer');
6719
6720        //var submitButton = document.getElementById("ldavq_submitBtn_" + question_id);
6721
6722        var data = [];
6723
6724        var countdown;
6725        var counter;
6726
6727        // duration = 1;
6728
6729        // Not create event listners if DOM element is not present / missing
6730        // if (recordButton !== null) {
6731        //     recordButton.addEventListener("click", startRecording);
6732        //     stopButton.addEventListener("click", stopRecording);
6733        //     // submitButton.addEventListener("click", submitRecording);  
6734        //     pauseButton.addEventListener("click", pauseRecording);
6735        // }
6736
6737        $('.audio-items .values').each(function(index, element) {
6738            var value = $(this);
6739            timer.addEventListener('secondsUpdated', function (e) {
6740                document.querySelector('.ldavq-audio-items-'+question_id+' .values').innerHTML = timer.getTimeValues().toString();
6741            });
6742    
6743            timer.addEventListener('started', function (e) {
6744                document.querySelector('.ldavq-audio-items-'+question_id+' .values').innerHTML = timer.getTimeValues().toString();
6745            });
6746    
6747            timer.addEventListener('reset', function (e) {
6748                document.querySelector('.ldavq-audio-items-'+question_id+' .values').innerHTML = timer.getTimeValues().toString();
6749            });
6750        });
6751        // Update timer according to functions
6752        
6753
6754
6755        // Start recording
6756        function startRecording() {
6757            var recordButton    = $(this);
6758            question_id         = recordButton.data('questionid');
6759            top_parent          = $(this).parents('.audio-container');
6760            var pauseButton     = top_parent.find('.ldavq_pauseBtn');
6761            var stopButton      = top_parent.find('.ldavq_stopBtn');
6762            var submitButton    = top_parent.find('.ldavq_submitBtn_audio');
6763            var downloadButton  = top_parent.find('.ldavq_downloadLink'); 
6764            duration = recordButton.data('timer');
6765            
6766
6767            var constraints = { audio: true, video: false }
6768            
6769            // We're using the standard promise based getUserMedia() 
6770            // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
6771            navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
6772                audioContext = new AudioContext();
6773
6774                //assign to gumStream for later use
6775                gumStream = stream;
6776
6777                //use the stream
6778                input = audioContext.createMediaStreamSource(stream);
6779
6780                /* Create the Recorder object and configure to record mono sound (1 channel) Recording 2 channels will double the file size */
6781                recorder = new Recorder(input, {
6782                    numChannels: 1
6783                })
6784
6785                top_parent.find('#timer_num').css('display', 'block');
6786                top_parent.find('#duration_text').css('display', 'block');
6787                
6788                // Start the recording process 
6789                recorder.record()
6790
6791                // Start timer
6792                timer.start();
6793
6794                // Stop recording once duration is completed
6795                window.record_start_time = Date.now();
6796                record_timeout = setTimeout(function(){ stopButton.click(); }, duration);
6797            }).catch(function (err) {
6798                //enable the record button if getUSerMedia() fails
6799                recordButton.parent().parent().css('display', 'block');
6800                stopButton.parent().parent().css('display', 'none');
6801                pauseButton.parent().parent().css('display', 'none');
6802
6803            });
6804            recordButton.parent().parent().css('display', 'none');
6805            stopButton.parent().parent().css('display', 'block');
6806            pauseButton.parent().parent().css('display', 'block');
6807            submitButton.parent().parent().css('display', 'none');
6808            downloadButton.parent().parent().parent().css('display', 'none');
6809            downloadButton.addClass("disabled");
6810            top_parent.find('#ldavq-audio-player').css('display', 'none');
6811        }
6812
6813        // Stop Recording function
6814        function stopRecording() {
6815
6816            var stopButton    = $(this);
6817            var top_parent      = $(this).parents('.audio-container');
6818            var pauseButton     = top_parent.find('.ldavq_pauseBtn');
6819            var recordButton    = top_parent.find('.ldavq_recordBtn');
6820            var submitButton    = top_parent.find('.ldavq_submitBtn_audio');
6821            var downloadButton  = top_parent.find('.ldavq_downloadLink'); 
6822
6823            // stop microphone access
6824            clearTimeout(record_timeout);
6825            if (recorder && recorder.recording) {
6826                recorder.stop();
6827            }
6828            if (gumStream && gumStream.getAudioTracks().length > 0) {
6829                gumStream.getAudioTracks()[0].stop();
6830            }
6831            timer.stop();
6832
6833            top_parent.find('#ldavq-audio-player').css('display', 'block');
6834            top_parent.find('#timer_num').css('display', 'none');
6835            top_parent.find('#duration_text').css('display', 'none');
6836
6837            pauseButton.innerHTML = '<span><i class="fas fa-pause"></i> Pause Recording</span>';
6838            submitButton.parent().parent().css('display', 'block');
6839            //submitButton.disabled = false;
6840            // recordButton.disabled = false;
6841            if (ajax_app.download == true) {
6842                downloadButton.removeClass("disabled").css('display', 'block');
6843            }
6844            recorder.exportWAV(createDownloadLink);
6845            
6846            // recordButton.disabled = false;
6847            // stopButton.disabled = true;
6848            // pauseButton.disabled = true;
6849            downloadButton.removeClass("disabled");
6850            recordButton.parent().parent().css('display', 'block');
6851            stopButton.parent().parent().css('display', 'none');
6852            pauseButton.parent().parent().css('display', 'none');
6853            downloadButton.parent().parent().parent().css('display', 'block');
6854        }
6855
6856        // Pause recording function
6857        function pauseRecording() {
6858            
6859            var pauseButton    = $(this);
6860            var top_parent      = $(this).parents('.audio-container');
6861            var stopButton      = top_parent.find('.ldavq_stopBtn');
6862            var recordButton    = top_parent.find('.ldavq_recordBtn');
6863            var submitButton    = top_parent.find('.ldavq_submitBtn_audio');
6864            var downloadButton  = top_parent.find('.ldavq_downloadLink'); 
6865
6866            if (recorder && recorder.recording) {
6867                recorder.stop();
6868                timer.pause();
6869                clearTimeout(record_timeout);
6870                var elapsed = Date.now() - window.record_start_time;
6871                duration = duration - elapsed;
6872                // recordButton.disabled = true;
6873                // stopButton.disabled = false;
6874                recordButton.parent().parent().css('display', 'none');
6875                stopButton.parent().parent().css('display', 'block');
6876                pauseButton.parent().parent().css('display', 'block');
6877
6878                pauseButton.innerHTML = '<span><i class="fas fa-play"></i> Resume Recording</span>';
6879            } else {
6880                recorder.record();
6881                timer.start();
6882                window.record_start_time = Date.now();
6883                record_timeout = setTimeout(function(){ stopButton.click(); }, Math.max(0, duration));
6884                recordButton.parent().parent().css('display', 'none');
6885                stopButton.parent().parent().css('display', 'block');
6886                pauseButton.parent().parent().css('display', 'block');
6887                pauseButton.innerHTML = '<span><i class="fas fa-pause"></i> Pause Recording</span>';
6888            }
6889        }
6890
6891        // Audio download link
6892        function createDownloadLink(blob) {
6893            blobAudio = blob;
6894            let url = URL.createObjectURL(blob);
6895            
6896            let audios = document.getElementsByClassName("ldavq-audio-player-"+question_id);
6897            if( audios.length > 0 ) {
6898                let audio = audios[0];
6899                audio.style.display = 'block';
6900                let sources = document.getElementsByClassName("ldavq-audio-source-player-"+question_id);
6901                if( sources.length > 0 ) {
6902                    let source = sources[0];
6903                    source.src = url;
6904                }
6905                audio.load();
6906            }
6907            //let source = document.getElementById("audio-source");
6908            var downloadButton  = top_parent.find('.ldavq_downloadLink');
6909            //source.src = url;
6910            //audio.load(); //call this to just preload the audio without playing
6911            //audio.play(); //call this to play the song right away
6912            let tagA = downloadButton;
6913            tagA.href = url;
6914            
6915            tagA.download = new Date().toISOString() + '.wav';
6916            
6917            downloadButton.attr('href', url );
6918            downloadButton.attr('target','_blank');
6919            document.getElementById('uploadAudioFile_' + question_id).value = url;
6920            var blobfile = document.getElementById('uploadAudioFileData_' + question_id);
6921            // const keysArr = JSON.parse(blobfile.dataset.blob);
6922            // keysArr.push(blobAudio);
6923            // set array to dataset again
6924            // blobfile.dataset.blob = JSON.stringify(blobAudio);
6925            ajax_app.uploadBlob = blobAudio;
6926        }
6927
6928        // Submit recording and create audio submission 
6929        function submitRecording() {
6930            var form_ = document.getElementById('uploadfile_form');
6931            const formData = new FormData(form_);
6932
6933            formData.set("uploadfiles[]", blobAudio, 'recording_audio.mp3');
6934            formData.append("action", ajax_app.action);
6935            formData.append("nonce", ajax_app.nonce);
6936
6937            jQuery.ajax({
6938                type: 'post',
6939                url: ajax_app.url,
6940                data: formData,
6941                enctype: 'multipart/form-data',
6942                processData: false,
6943                contentType: false,
6944                success: function( result ){ 
6945                    // location.reload()
6946                    $('#uploadEssayFile_' + question_id).val(response.data.filelink);
6947
6948                    // disable the upload button. Only one file per quiz.
6949                    // uploadEssaySubmit.attr('disabled', 'disabled');
6950
6951                    var $item = $('#uploadAudioFile_' + question_id).parents('.wpProQuiz_listItem');
6952                    $e.trigger({ type: 'questionSolved', values: { item: $item, index: $item.index(), solved: true } });
6953                },
6954                error: function( result ){ console.log( result ); }
6955            });  
6956        }
6957    });
6958    // Allow only numbers and arithmetic operators
6959    document.querySelectorAll('.laq_advanced_calculated_selection').forEach(function(input) {
6960        input.addEventListener('input', function() {
6961            this.value = this.value.replace(/[^0-9+.,-]/g, '');
6962        });
6963    });
6964
6965})(jQuery);
6966
6967var learndash_prepare_quiz_resume_data = function (config) {
6968    if (config.quiz_resume_enabled === 'undefined') {
6969        return false;
6970    }
6971    if (config.quiz_resume_enabled !== '1') {
6972        return false;
6973    }
6974
6975    if (config.quiz_resume_data === 'undefined') {
6976        return false;
6977    }
6978
6979    let resume_data = {};
6980    if (config.ld_script_debug == true) {
6981        console.log(
6982            'config.quiz_resume_data (raw)[%o]',
6983            config.quiz_resume_data
6984        );
6985    }
6986    try {
6987        resume_data = JSON.parse(config.quiz_resume_data);
6988        if (config.ld_script_debug == true) {
6989            console.log('resume_data (parsed)[%o]', resume_data);
6990        }
6991    } catch (exception) {
6992        console.log('JSON.parse error [%o]', exception);
6993    }
6994
6995    return resume_data;
6996};
6997
6998var learndash_decodeHTML = function (html) {
6999    html = html || '';
7000
7001    if (html.length > 0 && typeof html === 'string') {
7002        const txt = document.createElement('textarea');
7003        txt.innerHTML = html;
7004
7005        html = txt.value;
7006    }
7007
7008    return html;
7009};
7010

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.