Index: quiz.install =================================================================== --- quiz.install (revision 5651) +++ quiz.install (working copy) @@ -8,6 +8,17 @@ */ /** + * Implementation of hook_update_N() + * + * Adding a field to turn on/off showing all question on one page + */ +function quiz_update_6419() { + $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 * * Change the primary key of the quiz_node_properties table to something more useful... @@ -876,6 +887,12 @@ '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'), Index: quiz.pages.inc =================================================================== --- quiz.pages.inc (revision 5651) +++ quiz.pages.inc (working copy) @@ -341,7 +341,7 @@ * * @ingroup themeable */ -function theme_quiz_progress($question_number, $num_of_question) { +function theme_quiz_progress($question_number, $num_of_question, $quiz) { // Determine the percentage finished (not used, but left here for other implementations). //$progress = ($question_number*100)/$num_of_question; @@ -350,7 +350,12 @@ $output = ''; $output .= '
'; - $output .= t('Question %x of %y', array('%x' => $current_question, '%y' => $num_of_question)); + if ($quiz->single_page) { + $output .= format_plural($num_of_question, '1 question', '@count questions'); + } + else { + $output .= t('Question %x of %y', array('%x' => $current_question, '%y' => $num_of_question)); + } $output .= '

'."\n"; // Add div to be used by jQuery countdown $output .= '
'; @@ -463,6 +468,31 @@ } /** + * Theme the multi question node. + * + * @param $nodes + * The question nodes + * @return + * Themed html feedback + */ +function theme_quiz_multi_question_node($nodes = array()) { + $qno = 0; + foreach ($nodes as $node) { + $qno++; + preg_match('|]*?>(.*?)|si', $node->body, $matches); + $form_free_body = preg_replace('/]*?>/','',$matches[1]); + $item_list[] = array( + 'class' => "question-{$node->nid} question-number-$qno", + 'data' => str_replace('name="tries', 'name="tries_' . $node->nid . '', $form_free_body), + ); + } + $output = '
'; + $output .= theme_item_list($item_list, null, 'ol'); + $output .= '
'; + return $output; +} + +/** * Theme the stats on the views page * * @param $node Index: quiz.module =================================================================== --- quiz.module (revision 5651) +++ quiz.module (working copy) @@ -425,7 +425,7 @@ 'file' => 'quiz.pages.inc', ), 'quiz_progress' => array( - 'arguments' => array('question_number' => NULL, 'num_of_question' => NULL), + 'arguments' => array('question_number' => NULL, 'num_of_question' => NULL, 'quiz' => NULL), 'file' => 'quiz.pages.inc', ), 'quiz_no_feedback' => array( @@ -440,6 +440,10 @@ '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()), @@ -535,12 +539,12 @@ 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) + has_userpoints, allow_skipping, 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)"; // 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); @@ -549,7 +553,7 @@ $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); + isset($node->has_userpoints) ? $node->has_userpoints : 0, $node->allow_skipping, $node->single_page); _quiz_insert_resultoptions($node); @@ -610,13 +614,14 @@ display_feedback = %d, number_of_random_questions = %d, has_userpoints = %d, - allow_skipping = %d + allow_skipping = %d, + single_page = %d WHERE vid = %d AND nid = %d"; _quiz_check_num_random($node); $resource = db_query($sql, $node->vid, $node->aid, $node->randomization, $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, $node->number_of_random_questions, isset($node->has_userpoints) ? $node->has_userpoints : 0, $node->allow_skipping, + $node->feedback_time, $node->display_feedback, $node->number_of_random_questions, isset($node->has_userpoints) ? $node->has_userpoints : 0, $node->allow_skipping, $node->single_page, $node->vid, $node->nid); _quiz_update_resultoptions($node); } @@ -689,6 +694,7 @@ 'tid' => 0, 'has_userpoints' => 0, 'allow_skipping' => 1, + 'single_page' => 0, ); } @@ -863,6 +869,12 @@ '#default_value' => $node->allow_skipping, '#description' => t('Whether to allow users to skip questions in the @quiz', array('@quiz' => QUIZ_NAME)), ); + $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']['backwards_navigation'] = array( '#type' => 'checkbox', '#title' => t('Backwards navigation'), @@ -1493,6 +1505,9 @@ 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(); @@ -1512,7 +1527,7 @@ } // 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); @@ -1549,6 +1564,7 @@ $_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 { @@ -1579,15 +1595,37 @@ $_SESSION['quiz_'. $quiz->nid]['quiz_questions'][0]['rid'] = $_SESSION['quiz_' . $quiz->nid]['result_id']; $_SESSION['quiz_'. $quiz->nid]['previous_quiz_questions'][] = $_SESSION['quiz_'. $quiz->nid]['quiz_questions'][0]; $former_question_array = array_shift($_SESSION['quiz_'. $quiz->nid]['quiz_questions']); - $former_question = node_load($former_question_array['nid'], $former_question_array['vid']); + if (!$quiz->single_page) { + $former_question = node_load($former_question_array['nid'], $former_question_array['vid']); - // Call hook_evaluate_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; - quiz_store_question_result($quiz, $result, array('set_msg' => TRUE)); + // Call hook_evaluate_question() for a single 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; + quiz_store_question_result($quiz, $result, array('set_msg' => 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)); + } + $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) { // Invoke hook_get_report(). @@ -1649,6 +1687,12 @@ $_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 @@ -1665,7 +1709,7 @@ $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); + $content['progress']['#value'] = theme('quiz_progress', $question_number, $number_of_questions, $quiz); $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); @@ -1733,7 +1777,12 @@ } // If we're not yet at the end. if (empty($quiz_end)) { - $content['body']['question']['#value'] = quiz_take_question_view($question_node, $quiz); + 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) { @@ -1794,6 +1843,25 @@ } /** + * 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