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">×</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.