diff --git a/quiz.install b/quiz.install index 7a18a5d..e750bdd 100644 --- a/quiz.install +++ b/quiz.install @@ -7,6 +7,17 @@ */ /** + * Implementation of hook_update_N() + * + * Adding a field to turn on/off showing all question on one page + */ +function quiz_update_6421() { + $result = array(); + db_add_field($result, 'quiz_node_properties', 'single_page', array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0)); + return $result; +} + +/** * Implementation of hook_update_N * * Makes sure max_score is correct in the quiz_node_properties @@ -981,6 +992,12 @@ function quiz_schema() { 'not null' => TRUE, 'default' => 0, ), + 'single_page' => array( + 'type' => 'int', + 'size' => 'small', + 'not null' => TRUE, + 'default' => 0, + ), ), 'primary key' => array('vid'), // 'unique keys' => array('vid'), diff --git a/quiz.module b/quiz.module index ca39254..92e2f2d 100644 --- a/quiz.module +++ b/quiz.module @@ -508,6 +508,10 @@ function quiz_theme() { 'file' => 'quiz.pages.inc', 'arguments' => array('question_node' => NULL), ), + 'quiz_multi_question_node' => array( + 'file' => 'quiz.pages.inc', + 'arguments' => array('question_node' => NULL), + ), 'question_selection_table' => array( 'file' => 'quiz.admin.inc', 'arguments' => array('form' => array()), @@ -610,12 +614,12 @@ function quiz_insert($node) { backwards_navigation, repeat_until_correct, quiz_open, quiz_close, takes, show_attempt_stats, keep_results, time_limit, pass_rate, summary_pass, summary_default, quiz_always, feedback_time, display_feedback, tid, - has_userpoints, allow_skipping, allow_resume, allow_jumping) + has_userpoints, allow_skipping, allow_resume, allow_jumping, single_page) VALUES(%d, %d, '%s', %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, '%s', '%s', %d, %d, %d, %d, - %d, %d, %d, %d)"; + %d, %d, %d, %d, %d)"; // If the quiz is saved as not randomized we have to make sure that questions belonging to the quiz are saved as not random _quiz_check_num_random($node); @@ -625,7 +629,7 @@ function quiz_insert($node) { $node->backwards_navigation, $node->repeat_until_correct, $node->quiz_open, $node->quiz_close, $node->takes, $node->show_attempt_stats, $node->keep_results, $node->time_limit, $node->pass_rate, $node->summary_pass, $node->summary_default, $node->quiz_always, $node->feedback_time, $node->display_feedback, $tid, - isset($node->has_userpoints) ? $node->has_userpoints : 0, $node->allow_skipping, $node->allow_resume, $node->allow_jumping); + isset($node->has_userpoints) ? $node->has_userpoints : 0, $node->allow_skipping, $node->allow_resume, $node->allow_jumping, $node->single_page); _quiz_insert_resultoptions($node); @@ -688,6 +692,7 @@ function quiz_update($node) { has_userpoints = %d, allow_skipping = %d, allow_resume = %d, + single_page = %d, allow_jumping = %d WHERE vid = %d AND nid = %d"; @@ -695,6 +700,7 @@ function quiz_update($node) { $node->takes, $node->show_attempt_stats, $node->keep_results, $node->time_limit, $node->pass_rate, $node->summary_pass, $node->summary_default, $node->quiz_always, $node->feedback_time, $node->display_feedback, $node->number_of_random_questions, isset($node->has_userpoints) ? $node->has_userpoints : 0, $node->allow_skipping, $node->allow_resume, $node->allow_jumping, + $node->single_page, $node->vid, $node->nid); _quiz_update_resultoptions($node); } @@ -807,6 +813,7 @@ function _quiz_get_node_defaults() { 'allow_skipping' => 1, 'allow_resume' => 1, 'allow_jumping' => 0, + 'single_page' => 0, ); } @@ -976,6 +983,12 @@ function quiz_form(&$node) { '#collapsible' => TRUE, '#attributes' => array('id' => 'taking-fieldset'), ); + $form['taking']['single_page'] = array( + '#type' => 'checkbox', + '#title' => t('Show all questions on a single page'), + '#default_value' => $node->single_page, + '#description' => t('Whether to show all questions on a single page in the @quiz', array('@quiz' => QUIZ_NAME)), + ); $form['taking']['allow_resume'] = array( '#type' => 'checkbox', '#title' => t('Allow Resume'), @@ -1667,6 +1680,9 @@ function quiz_update_quiz_question_relationship($old_quiz_vid, $new_quiz_vid, $q function quiz_take_quiz($quiz) { global $user; $allow_skipping = $quiz->allow_skipping; + if ($quiz->single_page) { + $_POST['tries'] == '1'; + } if (!isset($quiz)) { drupal_not_found(); @@ -1686,7 +1702,7 @@ function quiz_take_quiz($quiz) { } // If the session has no data for this quiz. - if (!isset($_SESSION['quiz_'. $quiz->nid]['quiz_questions'])) { + if ($quiz->single_page || !isset($_SESSION['quiz_'. $quiz->nid]['quiz_questions'])) { // We delete questions in progress from old revisions. _quiz_delete_old_in_progress($quiz, $user->uid); @@ -1695,7 +1711,8 @@ function quiz_take_quiz($quiz) { $rid = $user->uid > 0 ? _quiz_active_result_id($user->uid, $quiz->nid, $quiz->vid) : 0; // Are we resuming an in-progress quiz? - if ($quiz->allow_resume && $rid > 0) { + // We can't resume single page quizzes. + if ($quiz->allow_resume && !$quiz->single_page && $rid > 0) { _quiz_resume_existing_quiz($quiz, $user->uid, $rid); } @@ -1723,6 +1740,7 @@ function quiz_take_quiz($quiz) { $_SESSION['quiz_'. $quiz->nid]['question_start_time'] = time(); $_SESSION['quiz_'. $quiz->nid]['question_duration'] = $quiz->time_limit; $_SESSION['quiz_'. $quiz->nid]['quiz_vid'] = $quiz->vid; + $_SESSION['current_quiz_id'] = $quiz->nid; } else { @@ -1739,7 +1757,7 @@ function quiz_take_quiz($quiz) { if (!isset($_POST['op'])) { // @todo Starting new quiz... Do we need to show instructions here? } - elseif ($_POST['question_nid'] != $_SESSION['quiz_'. $quiz->nid]['quiz_questions'][0]['nid']) { + elseif (!$quiz->single_page && $_POST['question_nid'] != $_SESSION['quiz_'. $quiz->nid]['quiz_questions'][0]['nid']) { // The user has pressed the navigation buttons multiple times... } // We maintain two lists: previous questions and upcomming questions. @@ -1758,7 +1776,8 @@ function quiz_take_quiz($quiz) { $former_question_array = array_shift($_SESSION['quiz_'. $quiz->nid]['quiz_questions']); $former_question = node_load($former_question_array['nid'], $former_question_array['vid']); - // Call hook_evaluate_question(). + if (!$quiz->single_page) { + // Call hook_evaluate_question() as usual. $types = _quiz_get_question_types(); $module = $types[$former_question->type]['module']; $result = module_invoke($module, 'evaluate_question', $former_question, $_SESSION['quiz_'. $quiz->nid]['result_id']); @@ -1772,6 +1791,26 @@ function quiz_take_quiz($quiz) { $allow_skipping = TRUE; $jumping = TRUE; } + } + else { + foreach ($questions as $question) { + $former_question = node_load($question['nid'], $question['vid']); + $_POST['tries'] = $_POST['tries_' . $question['nid']]; + // Call hook_evaluate_question() for each question. + $types = _quiz_get_question_types(); + $module = $types[$former_question->type]['module']; + $result = module_invoke($module, 'evaluate_question', $former_question, $_SESSION['quiz_'. $quiz->nid]['result_id']); + $q_passed_validation = $result->is_valid; + if ($q_passed_validation != 1) { + /** Very basic validation. TODO: save form values. */ + drupal_set_message('Please check your submission for errors.','error'); + quiz_delete_results(array($_SESSION['quiz_'. $quiz->nid]['result_id'])); + drupal_goto("node/{$quiz->nid}/take"); + } + quiz_store_question_result($quiz, $result, array('set_msg' => TRUE, 'question_data' => $former_question_array)); + } + $quiz_end = TRUE; + } // Stash feedback in the session, since the $_POST gets cleared. if ($quiz->feedback_time == QUIZ_FEEDBACK_QUESTION && $_POST['op'] != t('Back') && $q_passed_validation === TRUE) { @@ -1843,6 +1882,12 @@ function quiz_take_quiz($quiz) { $_SESSION['quiz_'. $quiz->nid]['quiz_questions'][0]['nid'], $_SESSION['quiz_'. $quiz->nid]['quiz_questions'][0]['vid'] ); + if ($quiz->single_page) { + $question_node_multi = array(); + foreach($questions as $question) { + array_push($question_node_multi,node_load($question['nid'], $question['vid'])); + } + } if (isset($_SESSION['quiz_'. $quiz->nid]['quiz_questions'][0]['rid'])) $question_node->rid = $_SESSION['quiz_'. $quiz->nid]['quiz_questions'][0]['rid']; // We got an error message when trying to validate the previous answer @@ -1864,7 +1909,7 @@ function quiz_take_quiz($quiz) { $number_of_questions = quiz_get_number_of_questions($quiz->vid); $question_number = $number_of_questions - count($_SESSION['quiz_'. $quiz->nid]['quiz_questions']); $question_node->question_number = $question_number; - $content['progress']['#value'] = theme('quiz_progress', $question_number, $number_of_questions, $quiz->allow_jumping, $quiz->time_limit); + $content['progress']['#value'] = theme('quiz_progress', $question_number, $number_of_questions, $quiz->allow_jumping, $quiz->time_limit, $quiz->single_page); $content['progress']['#weight'] = -50; if (count($_SESSION['quiz_'. $quiz->nid]['quiz_questions']) + count($_SESSION['quiz_'. $quiz->nid]['previous_quiz_questions']) > $number_of_questions) { drupal_set_message(t('At least one question have been deleted from the quiz after you started taking it. You will have to start over.'), 'warning', FALSE); @@ -1922,7 +1967,12 @@ function quiz_take_quiz($quiz) { } // If we're not yet at the end. if (empty($quiz_end)) { + if (!$quiz->single_page) { $content['body']['question']['#value'] = quiz_take_question_view($question_node, $quiz); + } + else { + $content['body']['question']['#value'] = quiz_node_view_multi($question_node_multi, TRUE, FALSE); + } $content['body']['question']['#weight'] = 0; // If we had feedback from the last question. if (isset($_SESSION['quiz_'. $quiz->nid]['feedback']) && $quiz->feedback_time == QUIZ_FEEDBACK_QUESTION) { @@ -2009,6 +2059,25 @@ function quiz_take_question_view($question_node, $quiz_node) { } /** + * Create the view for a multi-question the user is about to take. + * + * @param $question_nodes + * The question nodes that should be rendered. + * @param $quiz_node + * The quiz node. + * @return + * A string containing the body of the node. + */ +function quiz_node_view_multi($question_nodes = array(), $quiz_node) { + foreach($question_nodes as &$question_node) { + $question_node = node_build_content($question_node, FALSE, TRUE); + node_invoke_nodeapi($question_node, 'alter', FALSE, TRUE); + $question_node->body = drupal_render($question_node->content); + } + return theme('quiz_multi_question_node', $question_nodes); +} + +/** * Store a quiz question result. * * @param $quiz diff --git a/quiz.pages.inc b/quiz.pages.inc index a385fe5..614f5de 100644 --- a/quiz.pages.inc +++ b/quiz.pages.inc @@ -412,7 +412,7 @@ function theme_quiz_score_incorrect() { * * @ingroup themeable */ -function theme_quiz_progress($question_number, $num_of_question, $jumper = FALSE, $time_limit = FALSE) { +function theme_quiz_progress($question_number, $num_of_question, $jumper = FALSE, $time_limit = FALSE, $single_page = FALSE) { // Determine the percentage finished (not used, but left here for other implementations). //$progress = ($question_number*100)/$num_of_question; @@ -425,7 +425,12 @@ function theme_quiz_progress($question_number, $num_of_question, $jumper = FALSE $output = ''; $output .= '