/** * Shows the quiz for the unit, based on the type being shown. * * @param Boolean $showErrorsOnForm If true, show the errors on the form, acts as an override to disable showing errors if they are not wanted. * * @return String The HTML that renders the quiz for answering. */ function render_quizzes_handleQuizRendering($showErrorsOnForm = true) { // Hopefully not needed, but just in case. if (!$this->unitQuizDetails) { return false; } // Reload all raw answers user has created so far (if we have anything so far) if (!empty($this->unitQuizProgress) && 'incomplete' == $this->unitQuizProgress->quiz_paging_status) { $this->fetch_quizzes_loadRawAnswersSoFarForThisQuiz($this->unitQuizProgress->quiz_data); } // Render the wrapper for the quiz using the pending message section // Use the Quiz ID and Unit ID to validate permissions. $html = sprintf('<div class="wpcw_fe_quiz_box_wrap" id="wpcw_fe_quiz_complete_%d_%d">', $this->unitPost->ID, $this->unitQuizDetails->quiz_id); // Are we going to show the answers on a single for as part of the review? if ($this->check_paging_shouldWeShowReviewPage_rightNow()) { // To do, show a message here about reviewing answers... $html .= WPCW_UnitFrontend::message_createMessage_warning(__('You can now review your answers before submitting them.', 'wp_courseware')); } // Use any raw selection data that we have so far to pre-fill answers. $resultsList = $this->unchecked_QuizAnswersToGrade; // enctype="multipart/form-data" for file uploads.. // data-wpcw_expired="false" - this is used by the timer to indicate if the timer has expired or not. $html .= sprintf('<form method="post" enctype="multipart/form-data" id="quiz_complete_%d_%d" data-wpcw_unit="%d" data-wpcw_quiz="%d" data-wpcw_expired="false">', $this->unitPost->ID, $this->unitQuizDetails->quiz_id, $this->unitPost->ID, $this->unitQuizDetails->quiz_id); $html .= '<div class="wpcw_fe_quiz_box wpcw_fe_quiz_box_pending">'; // #### 1 - Quiz Title - constant for all quizzes $html .= sprintf('<div class="wpcw_fe_quiz_title">%s</div>', $this->unitQuizDetails->quiz_title); // #### 2 - Pass mark - just needed for blocking quizes if ('quiz_block' == $this->unitQuizDetails->quiz_type) { $totalQs = count($this->unitQuizDetails->questions); $passQs = ceil($this->unitQuizDetails->quiz_pass_mark / 100 * $totalQs); $html .= '<div class="wpcw_fe_quiz_pass_mark">'; $html .= sprintf(__('You\'ll need to correctly answer at least <b>%d of the %d</b> questions below (<b>at least %d%%</b>) to progress to the next unit.', 'wp_courseware'), $passQs, $totalQs, $this->unitQuizDetails->quiz_pass_mark); $html .= '</div>'; } // #### 3 - The actual question form. if (!empty($this->unitQuizDetails->questions)) { $questionNum = 1; $showQuestions = true; // Timer Mode if ('use_timer' == $this->unitQuizDetails->quiz_timer_mode) { // We've not started the quiz yet, so we show the begin test button. if (empty($this->unitQuizProgress) || 'retake_waiting' == $this->unitQuizProgress->quiz_next_step_type) { $showQuestions = false; $html .= '<div class="wpcw_fe_quiz_q_hdr"></div>'; // Begin Quiz $html .= sprintf(' <div class="wpcw_fe_quiz_begin_quiz"> <div class="wpcw_fe_quiz_begin_quiz_hdr">%s</div> <a href="#" class="fe_btn fe_btn_completion" id="wpcw_fe_quiz_begin_quiz" data-wpcw_quiz="%d" data-wpcw_unit="%d" >%s</a> <div class="wpcw_fe_submit_loader wpcw_loader"> <img src="%simg/ajax_loader.gif" /> </div> </div>', sprintf(__('You have <b>%s</b> to complete this quiz...', 'wp_coursware'), WPCW_time_convertMinutesToHumanLabel($this->unitQuizDetails->quiz_timer_mode_limit)), $this->unitQuizDetails->quiz_id, $this->unitPost->ID, __('Begin Quiz...', 'wp_courseware'), WPCW_plugin_getPluginPath()); } else { // Total time in seconds for this quiz $timerDetails_secondsLeft = $allowedTime = 60 * $this->unitQuizDetails->quiz_timer_mode_limit; // What time do we have left? $timeSoFar = strtotime($this->unitQuizProgress->quiz_started_date); $timeNow = current_time('timestamp'); // We've started the quiz when the time so far is > 0 if ($timeSoFar > 0) { $timerDetails_secondsLeft = $allowedTime - ($timeNow - $timeSoFar); } // Show the timer if we have time left. $html .= sprintf('<div id="wpcw_fe_timer_countdown" data-time_left="%d">%s</div>', $timerDetails_secondsLeft, WPCW_time_convertSecondsToHumanLabel($timerDetails_secondsLeft)); } } if ($showQuestions) { // We're paging, so check what question or questions to show next. if ($this->check_paging_areWePagingQuestions()) { // Stores the index of the next question to show $questionToShowIndex = $this->fetch_paging_getQuestionIndex(); $question = $this->fetch_paging_getQuestion($questionToShowIndex); // Show progress of user through the questions. $html .= sprintf('<div class="wpcw_fe_paging_progress">%s</div>', sprintf(__('Question %d of %d', 'wp_courseware'), $questionToShowIndex + 1, $this->fetch_paging_getQuestionCount())); // Header before questions (but show progress before the header line). $html .= '<div class="wpcw_fe_quiz_q_hdr"></div>'; // Show the answer later button. if ($this->check_paging_shouldWeShowAnswerLaterButton()) { $html .= sprintf('<div class="wpcw_fe_quiz_answer_later"><a href="#" class="fe_btn fe_btn_small fe_btn_navigation" id="wpcw_fe_quiz_answer_later">%s</a></div>', __('Answer Later...', 'wp_courseware')); } // Render just this question $html .= $this->render_quizzes_handleQuizRendering_singleQuestion($question, $resultsList, $showErrorsOnForm, $questionToShowIndex + 1, true, 0); // Work out what caption to show for the submit button. Change this if we're about to // submit the answers for the final question or review our answers. $buttonCaption = __('Save & Next Question »', 'wp_courseware'); // Are we showing the last incomplete question (and we're nearly complete) if ($this->unitQuizProgress && $this->unitQuizProgress->quiz_paging_incomplete <= 1 && $this->check_paging_isThisTheLastIncompleteQuestion($question->question_id)) { // We appear to be on the last question. Are we going to review too? if ($this->check_paging_shouldWeShowReviewPage()) { $buttonCaption = __('Save & Review Answers »', 'wp_courseware'); } else { $buttonCaption = __('Submit Answers', 'wp_courseware'); } } // Previous button - created if required. Using a button rather than a link to ensure the buttons look right when side-by-side. $buttonPreviousClicker = false; if ($this->check_paging_shouldWeShowPreviousButton()) { $buttonPreviousClicker = sprintf('<input type="submit" class="fe_btn fe_btn_completion btn_completion" id="fe_btn_quiz_previous" name="previous_question" value="%s">', __('« Previous Question', 'wp_courseware')); } // #### 4A - The navigation buttons $html .= sprintf('<div class="wpcw_fe_quiz_submit wpcw_fe_quiz_submit_data"> %s <div class="wpcw_fe_submit_loader wpcw_loader"> <img src="%simg/ajax_loader.gif" /> </div> %s <input type="submit" class="fe_btn fe_btn_completion btn_completion" id="fe_btn_quiz_next" name="submit" value="%s"> </div>', WPCW_content_progressBar(0, 'wpcw_fe_upload_progress'), WPCW_plugin_getPluginPath(), $buttonPreviousClicker, $buttonCaption); } else { // Header before questions $html .= '<div class="wpcw_fe_quiz_q_hdr"></div>'; $questionIndex = 0; foreach ($this->unitQuizDetails->questions as $question) { $html .= $this->render_quizzes_handleQuizRendering_singleQuestion($question, $resultsList, $showErrorsOnForm, $questionNum++, false, $questionIndex++); } // #### 4B - The submit answers button. //<a href="#" class="fe_btn fe_btn_completion btn_completion" id="quiz_complete_%d_%d">%s</a> $html .= sprintf('<div class="wpcw_fe_quiz_submit wpcw_fe_quiz_submit_data"> %s <div class="wpcw_fe_submit_loader wpcw_loader"> <img src="%simg/ajax_loader.gif" /> </div> <input type="submit" class="fe_btn fe_btn_completion btn_completion" name="submit" value="%s"> </div>', WPCW_content_progressBar(0, 'wpcw_fe_upload_progress'), WPCW_plugin_getPluginPath(), __('Submit Answers', 'wp_courseware')); } // end of check for paging. } // end of check of showing questions (e.g. timer mode) } // end of question check $html .= '</div>'; // .wpcw_fe_quiz_box $html .= '</form>'; $html .= '</div>'; // .wpcw_fe_quiz_box_wrap return $html; }