diff --git a/question_types/quiz_question/quiz_question.core.inc b/question_types/quiz_question/quiz_question.core.inc index 6957a04..f396612 100644 --- a/question_types/quiz_question/quiz_question.core.inc +++ b/question_types/quiz_question/quiz_question.core.inc @@ -615,9 +615,9 @@ abstract class QuizQuestion { $may_view_answers = in_array(TRUE, $results); return $may_view_answers; } - + /** - * Utility function that returns the format of the node body + * Utility function that returns the format of the node body */ protected function getFormat() { $body = field_get_items('node', $this->question, 'body'); @@ -642,7 +642,6 @@ abstract class QuizQuestionResponse { protected $answer = NULL; protected $score; public $is_skipped; - public $is_doubtful; /** * Create a new user response. @@ -659,12 +658,8 @@ abstract class QuizQuestionResponse { $this->rid = $result_id; $this->question = $question_node; $this->answer = $answer; - $result = db_query('SELECT is_skipped, is_doubtful FROM {quiz_node_results_answers} - WHERE result_id = :result_id AND question_nid = :question_nid AND question_vid = :question_vid', array(':result_id' => $result_id, ':question_nid' => $question_node->nid, ':question_vid' => $question_node->vid))->fetch(); - if (is_object($result)) { - $this->is_doubtful = $result->is_doubtful; - $this->is_skipped = $result->is_skipped; - } + $this->is_skipped = db_query('SELECT is_skipped FROM {quiz_node_results_answers} + WHERE result_id = :result_id AND question_nid = :question_nid AND question_vid = :question_vid', array(':result_id' => $result_id, ':question_nid' => $question_node->nid, ':question_vid' => $question_node->vid))->fetchField(); } /** @@ -753,7 +748,6 @@ abstract class QuizQuestionResponse { $obj->is_correct = (int) $this->isCorrect(); $obj->is_evaluated = $this->isEvaluated(); $obj->is_skipped = 0; - $obj->is_doubtful = isset($_POST['is_doubtful']) ? $_POST['is_doubtful'] : 0; $obj->is_valid = $this->isValid(); return $obj; } @@ -935,9 +929,9 @@ abstract class QuizQuestionResponse { $this->is_skipped = FALSE; $this->save(); } - + /** - * Utility function that returns the format of the node body + * Utility function that returns the format of the node body */ protected function getFormat() { $body = field_get_items('node', $this->question, 'body'); diff --git a/question_types/quiz_question/quiz_question.module b/question_types/quiz_question/quiz_question.module index 650e0a3..4a20e44 100644 --- a/question_types/quiz_question/quiz_question.module +++ b/question_types/quiz_question/quiz_question.module @@ -183,23 +183,6 @@ function quiz_question_answering_form($form, $form_state, $node, $include_nid_in $is_last = _quiz_is_last_question(); $form['navigation']['#theme'] = 'quiz_question_navigation_form'; - if ($quiz->mark_doubtful) { - $form['is_doubtful'] = array( - '#type' => 'checkbox', - '#title' => t('doubtful'), - '#weight' => 1, - '#prefix' => '
', - '#suffix' => '
', - '#default_value' => 0, - '#attached' => array( - 'js' => array(drupal_get_path('module', 'quiz') . '/theme/quiz_take.js'), - ), - ); - if (isset($node->rid)) { - $form['is_doubtful']['#default_value'] = db_query('SELECT is_doubtful FROM {quiz_node_results_answers} WHERE result_id = :result_id AND question_nid = :question_nid AND question_vid = :question_vid', array(':result_id' => $node->rid, ':question_nid' => $node->nid, ':question_vid' => $node->vid))->fetchField(); - } - } - if (!empty($quiz->backwards_navigation) && !empty($node->question_number)) { $form['navigation']['back'] = array( '#type' => 'submit', @@ -297,12 +280,7 @@ function quiz_question_skip_question($question, $result_id) { $response->vid = $question->vid; $response->rid = $result_id; $response->is_skipped = TRUE; - if (isset($_POST['is_doubtful'])) { - $response->is_doubtful = $_POST['is_doubtful']; - } - else { - $response->is_doubtful = db_query('SELECT is_doubtful FROM {quiz_node_results_answers} WHERE result_id = :result_id AND question_nid = :question_nid AND question_vid = :question_vid', array(':result_id' => $result_id, ':question_nid' => $question->nid, ':question_vid' => $question->vid))->fetchField(); - } + return $response; } diff --git a/quiz.admin.inc b/quiz.admin.inc index bdd5db0..0ef6948 100644 --- a/quiz.admin.inc +++ b/quiz.admin.inc @@ -535,7 +535,7 @@ function _quiz_categorized_new_term_form(&$form, $form_state, $quiz) { $form['new']['max_score'] = array( '#type' => 'textfield', '#title' => t('Max score for each question'), - '#description' => t('The number of points a user will be awarded for each question he gets correct.'), + '#description' => t('The number of points a user will be awarded for each correct answer.'), '#default_value' => 1, ); } @@ -740,13 +740,13 @@ function _quiz_search_terms($start, $all = FALSE) { * HTML output to create page. */ function quiz_questions_form($form, $form_state, $quiz) { - if ($form_state['rebuild']) { - // Save the active filters in $_SESSION - $filters = $form_state['values']['browser']['table']['header']['filters']; - _quiz_questions_store_filters($filters); - } - $types = _quiz_get_question_types(); + $form = array( + '#attributes' => array( + 'id' => 'quiz-manage-questions-form', + ), + '#tree' => TRUE, + ); _quiz_add_fields_for_creating_questions($form, $types, $quiz); @@ -754,54 +754,300 @@ function quiz_questions_form($form, $form_state, $quiz) { $form['question_list'] = array( '#type' => 'fieldset', '#title' => t('Questions in this quiz'), - '#theme' => 'question_selection_table', '#collapsible' => TRUE, - '#attributes' => array('id' => 'mq-fieldset'), - 'question_status' => array('#tree' => TRUE), ); - $form['#attached']['js'] = array(drupal_get_path('module', 'quiz') .'/theme/quiz_question_browser.js'); - // Add randomization settings if this quiz allows randomized questions - _quiz_add_fields_for_random_quiz($form, $quiz); + if ($quiz->randomization == QUIZ_RANDOM_QUESTIONS) { + $form['question_list']['random_settings'] = array( + '#type' => 'fieldset', + '#title' => t('Randomization settings'), + '#collapsible' => TRUE, + ); + $form['question_list']['random_settings']['num_random_questions'] = array( + '#type' => 'textfield', + '#size' => 3, + '#maxlength' => 3, + '#title' => t('Number of questions'), + '#description' => t('The number of questions to be randomly selected each time someone takes this quiz'), + '#default_value' => isset($quiz->number_of_random_questions) ? $quiz->number_of_random_questions : 10, + ); + $form['question_list']['random_settings']['max_score_for_random'] = array( + '#type' => 'textfield', + '#size' => 3, + '#maxlength' => 3, + '#title' => t('Max score for each random question'), + '#description' => t('This will overwrite the max score in the table below.'), + '#default_value' => isset($quiz->max_score_for_random) ? $quiz->max_score_for_random : 1, + ); + } + + + + + + + + + + + // if ($quiz->randomization == QUIZ_RANDOM_CATEGORIES) { + // $terms = _quiz_taxonomy_select($quiz->tid); + // if (!empty($terms) && function_exists('taxonomy_get_vocabularies')) { + // $form['question_list']['random_settings']['random_term_id'] = array( + // '#type' => 'select', + // '#title' => t('Terms'), + // '#size' => 1, + // '#options' => _quiz_taxonomy_select($quiz->tid), + // '#default_value' => $quiz->tid, + // '#description' => t('Randomly select from questions with this term, or choose from the question pool below'), + // '#weight' => -4, + // ); + // } + // } + + + + + - // Build up a list of questions - $questions_to_add = array(); - // We use $form_state[post] to avoid validation failures when questions are added using AJAX - if (isset($form_state['post']['weights'])) { - $questions = _quiz_get_questions_from_form_state($form_state, $questions_to_add); + + + + + $questions = array(); + if (isset($form_state['values']['question_list']['questions'])) { + // Use $form_state to build list of questions (after AJAX form refresh) + $questions = $form_state['values']['question_list']['questions']; + foreach ($questions as $id => $qstn) { + if (!(intval($id) || $id == '0')) { + unset($questions[$id]); + } + } } else { - // We are coming in fresh and fetches the questions currently on the quiz from the database... - $include_random = $quiz->randomization == 2; - $questions = quiz_get_questions($quiz->nid, $quiz->vid, TRUE, FALSE, FALSE, $include_random); + // We are coming in fresh and need to fetch the questions currently on the quiz from the database... + $include_random = $quiz->randomization == QUIZ_RANDOM_QUESTIONS; + $questions_obj = quiz_get_questions($quiz->nid, $quiz->vid, TRUE, FALSE, FALSE, $include_random); + foreach($questions_obj as $id => $question) { + $questions[] = array( + 'title' => $question->title, + 'type' => $question->type, + 'weight' => $question->weight, + 'max_score' => $question->max_score, + 'nid' => $question->nid, + 'vid' => $question->vid, + 'latest_vid' => $question->latest_vid, + 'status' => $question->question_status, + ); + } } - if (empty($questions)) { - $form['question_list']['no_questions'] = array( - '#markup' => '
' . t('There are currently no questions in this quiz. Assign existing questions by using the question browser below. You can also use the links above to create new questions.') . '
', - ); + foreach ($types as $id => $type) { + $question_names[$id] = $type['name']; + } + + // Add questions to $form + $question_array = array(); + $question_ids = array(); + foreach($questions as $id => $question) { + if (intval($id) || $id == '0') { + if ($question['vid'] == $question['latest_vid']) { + $update_cell = array( + '#type' => 'markup', + '#markup' => t('Up to date'), + ); + } else { + $update_cell = array( + '#type' => 'checkbox', + '#title' => ( + l(t('Latest'), 'node/' . $question['nid'] . '/revisions/' . $question['latest_vid'] . '/view') + . ' of ' . + l(t('revisions'), 'node/' . $question['nid'] . '/revisions') + ), + '#default_value' => 0, + ); + } + if ($quiz->randomization == QUIZ_RANDOM_QUESTIONS) { + $status = array( + '#type' => 'checkbox', + '#default_value' => isset($question['status']) ? ($question['status'] == QUESTION_ALWAYS) ? 1 : 0 : 0, + ); + } else { + $status = array( + '#type' => 'hidden', + '#value' => $question['status'], + ); + } + $new_question = array( + 'title' => array( + '#type' => 'hidden', + '#value' => $question['title'], + ), + 'weight' => array( + '#type' => 'textfield', + '#size' => 5, + '#default_value' => $question['weight'], + ), + 'type' => array( + '#type' => 'hidden', + '#value' => in_array($question['type'], $question_names, TRUE) ? $question['type'] : $question_names[$question['type']], + '#prefix' => in_array($question['type'], $question_names, TRUE) ? $question['type'] : $question_names[$question['type']], + ), + 'edit' => array( + '#type' => 'markup', + '#markup' => l(t('Edit'), 'node/' . $question['nid'] . '/edit', array('query' => drupal_get_destination())), + ), + 'remove' => array( + '#type' => 'checkbox', + '#default_value' => 0, + ), + 'update' => $update_cell, + 'max_score' => array( + '#type' => 'textfield', + '#size' => 3, + '#default_value' => $question['max_score'], + ), + + 'nid' => array( + '#type' => 'hidden', + '#value' => $question['nid'], + ), + 'vid' => array( + '#type' => 'hidden', + '#value' => $question['vid'], + ), + 'latest_vid' => array( + '#type' => 'hidden', + '#value' => $question['latest_vid'], + ), + 'status' => $status, + ); + $question_array[$question['nid']] = $new_question; + $question_ids[] = $question['nid']; + } } - // We add the browser and allows the browser to give us information on what questions are displayed in the browser... - $hidden_questions = array(); - $form['question_list']['browser'] = _quiz_question_browser_form($hidden_questions, $questions_to_add, $form_state, $quiz, $types); - // We add the questions from the browser as hidden question rows in the question list. Doing this we can have - // the question show up in the question list instantly when a question is chosen in the browser(using js). - _quiz_add_hidden_questions($questions, $hidden_questions, $form_state, $quiz); + $form['question_list']['questions'] = $question_array; + $form['question_list']['questions'] += array( + '#prefix' => '
', + '#suffix' => '
', + '#theme' => 'quiz_questions_list', + ); - // We add the questions to the form array - _quiz_add_questions_to_form($form, $questions, $quiz, $types); + // Add remove questions button to $form + $form['question_list']['questions']['update'] = array( + '#type' => 'button', + '#value' => t('Remove questions'), + '#ajax' => array( + 'callback' => 'quiz_questions_ajax', + 'wrapper' => 'quiz-manage-questions-form', + ), + ); // Show the number of questions in the table header. - $always_count = 0; - foreach ($form['question_list']['stayers'] as $stayer) { - if ($stayer['#default_value'] === 1) { - $always_count++; + $count = 0; + foreach ($form['question_list']['questions'] as $id => $question) { + if (intval($id) || $id == '0') { + $count++; + } + } + $form['question_list']['#title'] .= ' (' . $count . ')'; + if ($count === 0) { + $form['create_new_question']['#collapsed'] = FALSE; + if (isset($form['question_list']['random_settings'])) { + $form['question_list']['random_settings']['#collapsed'] = TRUE; + } + } + + // Add question browser for adding new questions to quiz. + $form['question_browser'] = array( + '#type' => 'fieldset', + '#title' => t('Other Questions'), + '#collapsible' => TRUE, + ); + $form['question_browser']['search'] = array( + '#type' => 'container', + '#attributes' => array( + 'class' => array('question-browser-search-wrapper'), + ), + ); + $form['question_browser']['search']['search-query'] = array( + '#type' => 'textfield', + '#title' => t('Search for a question to add to the quiz'), + '#default_value' => isset($form_state['values']['question_browser']['search']['search-query']) ? $form_state['values']['question_browser']['search']['search-query'] : '', + ); + $form['question_browser']['search']['search-button'] = array( + '#type' => 'button', + '#value' => t('Search'), + '#ajax' => array( + 'callback' => 'quiz_questions_ajax', + 'wrapper' => 'quiz-manage-questions-form', + ), + ); + + $form['question_browser']['questions'] = array( + '#type' => 'container', + '#attributes' => array( + 'id' => array('questionbrowser-wrapper'), + ), + ); + + if (isset($form_state['values']['question_browser']['search']['search-query']) && trim($form_state['values']['question_browser']['search']['search-query']) != '') { + unset($form_state['values']['question_browser']['questions']); + unset($form['question_browser']['questions']); + $query = new EntityFieldQuery; + $query->entityCondition('entity_type', 'node') + ->propertyCondition('type', array_keys($types), 'IN') + ->propertyCondition('status', '1', '='); + if (!empty($question_ids)) { + $query->propertyCondition('nid', $question_ids, 'NOT IN'); } + $query->propertyCondition('title', '%' . $form_state['values']['question_browser']['search']['search-query'] . '%', 'LIKE') + ->propertyOrderBy('title', 'ASC'); + $result = $query->execute(); + $question_search_raw = node_load_multiple(array_keys($result['node'])); + $question_search = array(); + foreach ($question_search_raw as $question) { + $question_search[$question->nid] = array( + 'add_to_quiz' => array( + '#type' => 'checkbox', + '#default_value' => 0, + ), + 'question' => array( + '#type' => 'markup', + '#markup' => $question->title, + ), + 'type' => array( + '#type' => 'markup', + '#markup' => $question_names[$question->type], + ), + 'nid' => array( + '#type' => 'hidden', + '#value' => $question->nid, + ), + ); + } + + $form['question_browser']['questions'] = $question_search; + $form['question_browser']['questions'] += array( + '#prefix' => '
', + '#suffix' => '
', + '#theme' => 'quiz_questions_browse', + ); + $form['question_browser']['questions']['update'] = array( + '#type' => 'button', + '#value' => t('Add questions'), + '#ajax' => array( + 'callback' => 'quiz_questions_ajax', + 'wrapper' => 'quiz-manage-questions-form', + ), + ); } - $form['question_list']['#title'] .= ' (' . $always_count . ')'; + + + // Give the user the option to create a new revision of the quiz _quiz_add_revision_checkbox($form, $quiz); @@ -814,325 +1060,132 @@ function quiz_questions_form($form, $form_state, $quiz) { '#value' => t('Submit'), '#submit' => array('quiz_questions_form_submit'), ); - return $form; -} -/** - * Fields for creating new questions are added to the quiz_questions_form - * - * @param $form - * FAPI form(array) - * @param $types - * All the question types(array) - * @param $quiz - * The quiz node - */ -function _quiz_add_fields_for_creating_questions(&$form, &$types, &$quiz) { - // Display links to create other questions. - $form['additional_questions'] = array( - '#type' => 'fieldset', - '#title' => t('Create new question'), - '#collapsible' => TRUE, - '#collapsed' => TRUE, - ); - $url_query = drupal_get_destination(); - $url_query['quiz_nid'] = $quiz->nid; - $url_query['quiz_vid'] = $quiz->vid; - foreach ($types as $type => $info) { - $url_type = str_replace('_', '-', $type); - $options = array( - 'attributes' => array('title' => t('Create @name', array('@name' => $info['name']))), - 'query' => $url_query, - ); - $form['additional_questions'][$type] = array( - '#markup' => '
' . l($info['name'], "node/add/$url_type", $options) . '
', - ); - } + return $form; } + /** - * Add fields for random quiz to the quiz_questions_form + * Handler for quiz_questions_form ajax search for questions. * * @param $form - * FAPI form array - * @param $quiz - * The quiz node(object) + * The form variable + * @param $form_state + * The form state variable + * @return + * Content for AJAX to use. */ -function _quiz_add_fields_for_random_quiz(&$form, $quiz) { - if ($quiz->randomization != 2) { - return; - } - $form['question_list']['random_settings'] = array( - '#type' => 'fieldset', - '#title' => t('Settings for random questions'), - '#collapsible' => TRUE, - ); - $form['question_list']['random_settings']['num_random_questions'] = array( - '#type' => 'textfield', - '#size' => 3, - '#maxlength' => 3, - '#weight' => -5, - '#title' => t('Number of random questions'), - '#description' => t('The number of questions to be randomly selected each time someone takes this quiz'), - '#default_value' => isset($quiz->number_of_random_questions) ? $quiz->number_of_random_questions : 10, - ); - $form['question_list']['random_settings']['max_score_for_random'] = array( - '#type' => 'textfield', - '#size' => 3, - '#maxlength' => 3, - '#weight' => -5, - '#title' => t('Max score for each random question'), - '#default_value' => isset($quiz->max_score_for_random) ? $quiz->max_score_for_random : 1, - ); - if ($quiz->randomization == 3) { - $terms = _quiz_taxonomy_select($quiz->tid); - if (!empty($terms) && function_exists('taxonomy_get_vocabularies')) { - $form['question_list']['random_settings']['random_term_id'] = array( - '#type' => 'select', - '#title' => t('Terms'), - '#size' => 1, - '#options' => _quiz_taxonomy_select($quiz->tid), - '#default_value' => $quiz->tid, - '#description' => t('Randomly select from questions with this term, or choose from the question pool below'), - '#weight' => -4, - ); - } - } +function quiz_questions_ajax($form, $form_state) { + return $form; } /** - * Returns the questions that was in the question list when the form was submitted using ajax. + * Handler for quiz_questions_form ajax remove questions button. + * + * Removes questions from the $form_state array. * * @param $form_state - * FAPI form_state(array) - * @return $questions - * Array of questions as objects + * The form state variable */ -function _quiz_get_questions_from_form_state(&$form_state, &$questions_to_add) { - $questions = array(); - // We first store all data from the post in a temporary array. - // Then we fetch more data for each question from the database. - $cur_questions = array(); - $vids = array(); - foreach ($form_state['post']['weights'] as $id => $value) { - $cur_question = new stdClass(); - - // Find nid and vid - $matches = array(); - preg_match('/([0-9]+)-([0-9]+)/', $id, $matches); - $cur_question->nid = $matches[1]; - if (!is_numeric($matches[2])) { - continue; - } - $vids[] = $cur_question->vid = $matches[2]; - $cur_question->max_score = intval($form_state['post']['max_scores'][$id]); - $cur_question->weight = intval($value); - $cur_question->staying = $form_state['post']['stayers'][$id] === '1'; - $cur_question->question_status = QUESTION_ALWAYS; - if ($cur_question->staying == TRUE) { - $questions_to_add[] = $id; +function _quiz_remove_unwanted_questions_from_quiz(&$form_state) { + if (isset($form_state['values']['question_list']['questions'])) { + foreach ($form_state['values']['question_list']['questions'] as $id => $question) { + if (isset($question['remove']) && $question['remove'] == '1') { + unset($form_state['values']['question_list']['questions'][$id]); + } } - $cur_questions[$cur_question->nid] = $cur_question; - } - - $query = db_select('node_revision', 'r'); - $table_alias = $query->join('node', 'n', 'n.nid = r.nid'); - $res = $query->addField('n', 'nid') - ->addTag('node_access') - ->addField('n', 'type') - ->addField('n', 'vid', 'latest_vid') - ->addField('r', 'title') - ->condition('r.vid', $vids, 'IN') - ->execute(); - // TODO: Don't use db_fetch_object - while ($res_o = $res->fetch()) { - $cur_questions[$res_o->nid]->type = $res_o->type; - $cur_questions[$res_o->nid]->title = $res_o->title; - $cur_questions[$res_o->nid]->latest_vid = $res_o->latest_vid; - $questions[] = $cur_questions[$res_o->nid]; } - return $questions; } + /** - * Adds all information about the hidden questions to the questions array. + * Handler for quiz_questions_form ajax add questions button. * - * Hidden questions are used to avoid unnecessary ajax calls. + * Adds questions to the $form_state array. * - * @see quiz_questions_form - * - * @param $questions - * The questions already added to the question list(array) - * @param $hidden_questions - * The questions added to the browser(array) * @param $form_state - * FAPI form_state(array) - * @param $quiz - * The quiz node + * The form state variable */ -function _quiz_add_hidden_questions(&$questions, &$hidden_questions, &$form_state, &$quiz) { - $cur_questions = array(); - $vids = array(); - foreach ($hidden_questions as $key => $id) { - $cur_question = new stdClass(); - $matches = array(); - - // Find nid and vid - preg_match('/([0-9]+)-([0-9]+)/', $id, $matches); - $nid = $matches[1]; - $vid = $matches[2]; - - // If a question already exists in the $questions array we won't add a new one... - $continue = FALSE; - foreach ($questions as $question) { - if ($question->vid == $vid) { - $continue = TRUE; - break; +function _quiz_add_new_questions_to_quiz(&$form_state) { + if (isset($form_state['values']['question_browser']['questions'])) { + // Use $form_state to add new questions (after AJAX form refresh) + $max_weight = 0; + foreach($form_state['values']['question_list']['questions'] as $id => $question) { + if (intval($id) || $id == '0') { + if (isset($question['weight']) && $question['weight'] > $max_weight) { + $max_weight = $question['weight']; + } } } - if (!is_numeric($nid) || !is_numeric($vid) || $continue) { - continue; + $nids = array(); + foreach ($form_state['values']['question_browser']['questions'] as $id => $new_question) { + if (intval($id) || $id == '0') { + if ($new_question['add_to_quiz'] == 1) { + $nids[] = $new_question['nid']; + } + } } - - $cur_question->nid = $nid; - $vids[] = $cur_question->vid = $vid; - $cur_question->weight = 0; - $cur_question->question_status = ($quiz->randomization == 2) ? QUESTION_RANDOM : QUESTION_ALWAYS; - $cur_question->staying = isset($form_state['values']['stayers'][$id]) ? $form_state['values']['stayers'][$id] === '1' : FALSE; - $cur_questions[$cur_question->nid] = $cur_question; - } - if (count($vids) > 0) { - // We fetch the rest of the information for each question and adds node access security - $res = db_select('node', 'n'); - $res->fields('n', array('nid', 'type')); - $res->fields('r', array('title')); - $res->fields('p', array('max_score')); - $res->addField('n', 'vid', 'latest_vid'); - $res->join('node_revision', 'r', 'n.nid = r.nid'); - $res->join('quiz_question_properties', 'p', 'r.vid = p.vid'); - $res->condition('r.vid', $vids, 'in'); - - // TODO: Don't user db_fetch_object - foreach ($res->execute() as $res_o) { - $cur_questions[$res_o->nid]->type = $res_o->type; - $cur_questions[$res_o->nid]->title = $res_o->title; - $cur_questions[$res_o->nid]->max_score = $res_o->type == 'scale' ? 0 : $res_o->max_score; - $cur_questions[$res_o->nid]->latest_vid = $res_o->latest_vid; - $questions[] = $cur_questions[$res_o->nid]; + $new_questions = quiz_get_added_questions($nids); + foreach($new_questions as $id => $question) { + if (!isset($question->weight) || is_null($question->weight)) { + $max_weight++; + $weight = $max_weight; + } else { + $weight = $question->weight; + } + $form_state['values']['question_list']['questions'][$question->nid] = array( + 'title' => $question->title, + 'weight' => $weight, + 'type' => $question->type, + 'remove' => 0, + 'max_score' => isset($question->max_score) ? $question->max_score : 1, + 'nid' => $question->nid, + 'vid' => $question->vid, + 'latest_vid' => $question->latest_vid, + 'status' => $question->question_status, + ); } } } + /** - * Adds the questions in the $questions array to the form + * Fields for creating new questions are added to the quiz_questions_form * * @param $form * FAPI form(array) - * @param $questions - * The questions to be added to the question list(array) + * @param $types + * All the question types(array) * @param $quiz - * The quiz node(object) - * @param $question_types - * array of all available question types + * The quiz node */ -function _quiz_add_questions_to_form(&$form, &$questions, &$quiz, &$question_types) { - $form['question_list']['weights'] = array('#tree' => TRUE); - $form['question_list']['max_scores'] = array('#tree' => TRUE); - $form['question_list']['stayers'] = array('#tree' => TRUE); - $form['question_list']['revision'] = array('#tree' => TRUE); - if ($quiz->randomization == 2) { - $form['question_list']['compulsories'] = array('#tree' => TRUE); - } - - $my_dest = $_GET['q']; - foreach ($questions as $question) { - $fieldset = 'question_list'; - $id = $question->nid . '-' . $question->vid; - - $form[$fieldset]['weights'][$id] = array( - '#type' => 'textfield', - '#size' => 3, - '#maxlength' => 4, - '#default_value' => isset($question->weight) ? $question->weight : 0, - ); - // Quiz directions don't have scoring... - if ($question->type != 'quiz_directions') { - $form[$fieldset]['max_scores'][$id] = array( - '#type' => 'textfield', - '#size' => 2, - '#maxlength' => 2, - '#default_value' => isset($question->max_score) ? $question->max_score : 0, - ); - } - else { - $form[$fieldset]['max_scores'][$id] = array( - '#type' => 'value', - '#value' => isset($question->max_score) ? $question->max_score : 0, - ); - } - - // Add checkboxes to remove questions in js disabled browsers... - $form[$fieldset]['stayers'][$id] = array( - '#type' => 'checkbox', - '#default_value' => (isset($question->staying) && $question->staying === FALSE) ? 0 : 1, - '#attributes' => array('class' => array('q-staying')), - ); - - //Add checkboxes to mark compulsory questions for randomized quizzes. - if ($quiz->randomization == 2) { - $form[$fieldset]['compulsories'][$id] = array( - '#type' => 'checkbox', - '#default_value' => isset($question->question_status) ? ($question->question_status == QUESTION_ALWAYS) ? 1 : 0 : 0, - '#attributes' => array('class' => array('q-compulsory')), - ); - } - - $link_options = array( - 'attributes' => array('class' => array('handle-changes')), - ); - - $form[$fieldset]['titles'][$id] = array('#markup' => l($question->title, 'node/' . $question->nid, $link_options)); - - - $form[$fieldset]['types'][$id] = array( - '#markup' => $question_types[$question->type]['name'], - ); +function _quiz_add_fields_for_creating_questions(&$form, &$types, &$quiz) { + // Display links to create other questions. + $form['create_new_question'] = array( + '#type' => 'fieldset', + '#title' => t('Create new question'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); - $form[$fieldset]['view_links'][$id] = array( - '#markup' => l( - t('Edit'), - 'node/' . $question->nid . '/edit', - array( - 'query' => array('destination' => $my_dest), - 'attributes' => array('class' => array('handle-changes')), - ) - ), + $url_query = drupal_get_destination(); + $url_query['quiz_nid'] = $quiz->nid; + $url_query['quiz_vid'] = $quiz->vid; + foreach ($types as $type => $info) { + $url_type = str_replace('_', '-', $type); + $options = array( + 'attributes' => array('title' => t('Create @name', array('@name' => $info['name']))), + 'query' => $url_query, ); - // For js enabled browsers questions are removed by pressing a remove link - $form[$fieldset]['remove_links'][$id] = array( - '#markup' => '' . t('Remove') . '', + $form['create_new_question'][$type] = array( + '#markup' => '
' . l($info['name'], "node/add/$url_type", $options) . '
', ); - // Add a checkbox to update to the latest revision of the question - if ($question->vid == $question->latest_vid) { - $update_cell = array( - '#markup' => t('Up to date'), - ); - } - else { - $update_cell = array( - '#type' => 'checkbox', - '#title' => (l(t('Latest'), 'node/' . $question->nid . '/revisions/' .$question->latest_vid . '/view') - . ' of ' . - l(t('revisions'), 'node/' . $question->nid . '/revisions') - ), - ); - } - $form[$fieldset]['revision'][$id] = $update_cell; } } + /** * Adds checkbox for creating new revision. Checks it by default if answers exists. * @@ -1167,389 +1220,48 @@ function _quiz_add_revision_checkbox(&$form, &$quiz) { } } -/** - * Creates the browser part of the quiz_questions_form - * - * @param $hidden_questions - * Array where we add the questions in the browser - * @param $questions - * Questions already added to the question list(array) - * @param $form_state - * FAPI form_state(array) - * @param $quiz - * Quiz node(object) - * @return form - * FAPI form(array) - */ -function _quiz_question_browser_form(&$hidden_questions, $questions, $form_state, $quiz, $question_types) { - if (!is_array($question_types) || count($question_types) == 0) { - return $form['no_questions'] = array( - '#markup' => t('No question types are enabled'), - ); - } - $form = array( - '#type' => 'fieldset', - '#title' => t('Browse for questions to add'), - '#description' => t('Mark all the questions you want to add.') . ' ' - . t('You can filter questions by using the textfields and select boxes.') . ' ' - . t('You can sort by pressing the table headers.'), - '#collapsible' => FALSE, - '#collapsed' => FALSE, - '#tree' => TRUE, - '#prefix' => '
', - '#suffix' => '
', - ); - $form['table'] = array('#theme' => 'quiz_browser'); - $browser = &$form['table']; - - // Ajax use this field to send extra query strings to drupal - $browser['add_to_get'] = array( - '#type' => 'hidden', - '#default_value' => '', - ); - - $browser['header'] = array('#theme' => 'quiz_questions_browser_header'); - $browser['body'] = array('#theme' => 'quiz_questions_browser_body'); - - //Build filter part of form: - _quiz_question_browser_add_filter_fields($browser['header'], $question_types, $quiz); - - // Add querystring recieved via ajax to the $_GET array... - if (isset($form_state['values'])) { - _quiz_add_to_get($form_state['values']['browser']['table']['add_to_get']); - } - - // Browsers table header - $browser['header']['#header'] = array( - NULL, - array('data' => t('Title'), 'field' => 'n.title'), - array('data' => t('Type'), 'field' => 'n.type'), - array('data' => t('Changed'), 'field' => 'n.changed', 'sort' => 'desc'), - array('data' => t('Username'), 'field' => 'u.name'), - ); - - $child_nid = db_query('SELECT child_nid FROM {quiz_node_relationship} - WHERE parent_vid = :parent_vid', - array(':parent_vid' => $quiz->vid) - ) - ->fetchCol(); - - $query = db_select('node', 'n')->extend('PagerDefault')->extend('TableSort'); - $query->fields('n', array('nid', 'type', 'vid', 'title', 'changed')); - $query->fields('u', array('name')); - $query->leftJoin('users', 'u', 'n.uid = u.uid'); - $query->condition('type', array_keys($question_types), 'IN'); - if (count($child_nid)) { - $query->condition('nid', $child_nid, 'NOT IN'); - } - - // Apply filter conditions - // _quiz_question_browser_prepare_filter_sql($query); - $pre = 'quiz_question_browser_'; - $changed_timestamps = _quiz_get_interval_timestamps('changed'); - $filter_sql = ''; - if (isset($_SESSION[$pre . 'title']) && !empty($_SESSION[$pre . 'title'])) { - $query->condition('n.title', '%' . db_like($_SESSION[$pre . 'title']) . '%', 'LIKE'); - } - - if (isset($_SESSION[$pre . 'name']) && !empty($_SESSION[$pre . 'name'])) { - $query->condition('u.name', '%' . db_like($_SESSION[$pre . 'name']) . '%', 'LIKE'); - } - - if (isset($_SESSION[$pre . 'type']) && ($_SESSION[$pre . 'type'] !== '0')) { - $query->condition('type', array($_SESSION[$pre . 'type']), 'IN'); - } - - if (isset($_SESSION[$pre . 'changed'])) { - $changed_timestamps = _quiz_get_interval_timestamps('changed'); - if ($changed_timestamps[$_SESSION[$pre . 'changed']][0]) { - $query->condition('changed', $changed_timestamps[$_SESSION[$pre . 'changed']][0], '>'); - } - if ($changed_timestamps[$_SESSION[$pre . 'changed']][1]) { - $query->condition('changed', $changed_timestamps[$_SESSION[$pre . 'changed']][1], '<'); - } - } - $query->limit(10); - $query->orderByHeader($browser['header']['#header']); - $options = array(); - - foreach ($query->execute() as $res_o) { - $id = $res_o->nid . '-' . $res_o->vid; - // Add $id to hidden_questions, this way quiz_questions_form knows that it has to add a invisible row for this question. - $hidden_questions[] = $id; - - $options[$id] = check_plain($res_o->title); - $browser['body']['changed'][$id]['#value'] = format_date($res_o->changed, 'short'); - $browser['body']['types'][$id]['#value'] = $question_types[$res_o->type]['name']; - $browser['body']['names'][$id]['#value'] = check_plain($res_o->name); - } - - $browser['body']['titles'] = array( - '#title' => t('Titles'), - '#type' => 'checkboxes', - '#options' => $options, - '#attributes' => array('class' => array('quiz-browser-checkbox')), - '#default_value' => $questions, - ); - - $browser['pager'] = array( - '#markup' => '
' . theme('pager', array('tags' => NULL)) . '
', - ); - return $form; -} - - -/** - * adds filter fields to the question browser form - * - * @param $browser - * FAPI form(array) - * @param $question_types - * Array of question types - */ -function _quiz_question_browser_add_filter_fields(&$browser, &$question_types, $quiz) { - // Create options array for the type filter(select field) - $type_options = array(t('No filter')); - foreach (array_keys($question_types) as $type) { - $type_options[$type] = $question_types[$type]['name']; - } - - // Create options array for the changed filter - $changed_options = _quiz_get_time_interval_options(); - - // Create the filter form items - $browser['filters'] = array(); - $filters = &$browser['filters']; - - $filters['all'] = array( - '#type' => 'checkbox', - ); - - $pre = 'quiz_question_browser_'; - - $filters['title'] = array( - '#type' => 'textfield', - '#size' => 20, - '#default_value' => isset($_SESSION[$pre . 'title']) ? $_SESSION[$pre . 'title'] : '', - '#ajax' => array( - 'callback' => 'quiz_questions_browser_body_callback', - 'effect' => 'slide', - 'wrapper' => 'quiz-browser-body', - 'method' => 'replace', - 'event' => 'doneTyping', // custom event - ), - ); - $filters['type'] = array( - '#type' => 'select', - '#options' => $type_options, - '#default_value' => isset($_SESSION[$pre . 'type']) ? $_SESSION[$pre . 'type'] : '', - '#ajax' => array( - 'callback' => 'quiz_questions_browser_body_callback', - 'effect' => 'slide', - 'wrapper' => 'quiz-browser-body', - 'method' => 'replace', - ), - ); - $filters['changed'] = array( - '#type' => 'select', - '#options' => $changed_options, - '#default_value' => isset($_SESSION[$pre . 'changed']) ? $_SESSION[$pre . 'changed'] : '', - '#ajax' => array( - 'callback' => 'quiz_questions_browser_body_callback', - 'effect' => 'slide', - 'wrapper' => 'quiz-browser-body', - 'method' => 'replace', - ), - ); - $filters['name'] = array( - '#type' => 'textfield', - '#size' => 10, - '#default_value' => isset($_SESSION[$pre . 'name']) ? $_SESSION[$pre . 'name'] : '', - '#ajax' => array( - 'callback' => 'quiz_questions_browser_body_callback', - 'effect' => 'slide', - 'wrapper' => 'quiz-browser-body', - 'method' => 'replace', - 'event' => 'doneTyping', // custom event - ), - ); -} - -/** - * Returns sql to be added in where clause in the browsers select statement - * - * @see _quiz_questions_browser_form() - * - * @param $filter_params - * params to be sent as parameter to db_query. (array) - * @return $filter_sql - * sql to be added to where statement in browser(string) - */ -function _quiz_question_browser_prepare_filter_sql(&$filter_params) { - $pre = 'quiz_question_browser_'; - $changed_timestamps = _quiz_get_interval_timestamps('changed'); - $filter_sql = ''; - if (isset($_SESSION[$pre .'title']) && drupal_strlen($_SESSION[$pre .'title']) > 0) { - $filter_sql .= ' AND n.title LIKE \'%s%%\''; - $filter_params[] = $_SESSION[$pre . 'title']; - } - if (isset($_SESSION[$pre .'name']) && drupal_strlen($_SESSION[$pre .'name']) > 0) { - $filter_sql .= ' AND u.name LIKE \'%s%%\''; - $filter_params[] = $_SESSION[$pre . 'name']; - } - if (isset($_SESSION[$pre . 'type']) && ($_SESSION[$pre . 'type'] !== '0')) { - $filter_sql .= ' AND n.type = \'%s\''; - $filter_params[] = $_SESSION[$pre . 'type']; - } - if (isset($_SESSION[$pre . 'changed'])) { - $filter_sql .= $changed_timestamps[$_SESSION[$pre . 'changed']]['sql']; - } - return $filter_sql; -} /** * Validate that the supplied questions are real. */ -function quiz_questions_form_validate($form, $form_state) { - if (_quiz_is_int(arg(1))) { - if (node_last_changed(intval(arg(1))) > $form_state['values']['timestamp']) { - form_set_error('changed', t('This content has been modified by another user, changes cannot be saved.')); - } - } - else { - form_set_error('changed', t('A critical error has occured. Please report error code 28 on the quiz project page.')); - return; +function quiz_questions_form_validate($form, &$form_state) { + if (node_last_changed(intval(arg(1))) > $form_state['values']['timestamp']) { + form_set_error('changed', t('This quiz has been modified by another user, changes cannot be saved.')); } - $already_checked = array(); - $weight_map = $form_state['values']['weights']; - // Make sure the number of random questions is a positive number - if (isset($form_state['values']['num_random_questions']) && !_quiz_is_int($form_state['values']['num_random_questions'], 0)) { - form_set_error('num_random_questions', 'The number of random questions needs to be a positive number'); + if (isset($form_state['values']['question_list']['random_settings']['num_random_questions']) && $form_state['values']['question_list']['random_settings']['num_random_questions'] < 0) { + form_set_error("question_list][random_settings][num_random_questions", 'The number of random questions needs to be greater than or equal to 0'); } // Make sure the max score for random questions is a positive number - if (isset($form_state['values']['max_score_for_random']) && !_quiz_is_int($form_state['values']['max_score_for_random'], 0)) { - form_set_error('max_score_for_random', 'The max score for random questions needs to be a positive number'); - } - - if (empty($weight_map)) { - form_set_error('none', 'No questions were included.'); - return; + if (isset($form_state['values']['question_list']['random_settings']['max_score_for_random']) && $form_state['values']['question_list']['random_settings']['max_score_for_random'] < 0) { + form_set_error("question_list][random_settings][max_score_for_random", 'The max score for random questions needs to be greater than or equal to 0'); } - $question_types = array_keys(_quiz_get_question_types()); - - foreach ($weight_map as $id => $weight) { - if ($form_state['values']['stayers'][$id] == 0) { - continue; - } // The question isn't to be added... - - list($nid, $vid) = explode('-', $id, 2); - - // If a node isn't one of the questionstypes we remove it from the question list - $has_questions = (Boolean) db_select('node', 'n') - ->fields('n', array('nid')) - ->condition('type', $question_types, 'IN') - ->addTag('node_access') - ->condition('n.nid', $nid) - ->execute() - ->fetchField(); - if (!$has_questions) { - form_set_error('none', 'One of the supplied questions was invalid. It has been removed from the quiz.'); - unset($form_state['values']['weights'][$id]); - } - - // We also make sure that we don't have duplicate questions in the quiz. - elseif (in_array($nid, $already_checked)) { - form_set_error('none', 'A duplicate question has been removed. You can only ask a question once per quiz.'); - unset($form_state['values']['weights'][$id]); - } - else { - $already_checked[] = $nid; - } - } + // Remove questions selected for removal + _quiz_remove_unwanted_questions_from_quiz($form_state); // We make sure max score is a positive number - $max_scores = $form_state['values']['max_scores']; - foreach ($max_scores as $id => $max_score) { - if ($form_state['values']['stayers'][$id] == 0) { - continue; - } - if (!_quiz_is_int($max_score, 0)) { - form_set_error("max_scores][$id", t('Max score needs to be a positive number')); - } - } -} - -/** - * Update a quiz set of items with new weights and membership - * @param $quiz - * The quiz node - * @param $weight_map - * Weights for each question(determines the order in which the question will be taken by the quiz taker) - * @param $max_scores - * Array of max scores for each question - * @param $is_new_revision - * Array of boolean values determining if the question is to be updated to the newest revision - * @param $refreshes - * True if we are creating a new revision of the quiz - * @param $stayers - * Questions added to the quiz - * @param $compulsories - * Array of boolean values determining if the question is compulsory or not. - * @return array set of questions after updating - */ -function _quiz_update_items($quiz, $weight_map, $max_scores, $is_new_revision, $refreshes, $stayers, $compulsories = NULL) { - $questions = array(); - foreach ($weight_map as $id => $weight) { - // Do not add hidden questions to $questions - if ($stayers[$id] == 0) { - continue; - } - list($nid, $vid) = explode('-', $id, 2); - $nid = (int) $nid; - $vid = (int) $vid; - $question = new stdClass(); - $question->nid = $nid; - $question->vid = $vid; - if (isset($compulsories)) { - if ($compulsories[$id] == 1) { - $question->state = QUESTION_ALWAYS; - } - else { - $question->state = QUESTION_RANDOM; - $max_scores[$id] = $quiz->max_score_for_random; + foreach ($form_state['values']['question_list']['questions'] as $id => $question) { + if (intval($id) || $id == '0') { + if ($question['max_score'] < 0) { + form_set_error("question_list][questions][$id][max_score", t('Max score needs to be greater than or equal to 0')); } } - else { - $question->state = QUESTION_ALWAYS; - } - $question->weight = $weight; - $question->max_score = $max_scores[$id]; - $question->refresh = (isset($refreshes[$id]) && $refreshes[$id] == 1); - - // Add item as an object in the questions array. - $questions[] = $question; } - // Save questions. - quiz_set_questions($quiz, $questions, $is_new_revision); - - return $questions; + // Add questions selected for addition + _quiz_add_new_questions_to_quiz($form_state); } + /** * Submit function for quiz_questions. * * Updates from the "manage questions" tab. */ function quiz_questions_form_submit($form, &$form_state) { - if (isset($form_state['#from_ahah'])) { - return; - } - // Load the quiz node $quiz = node_load(intval(arg(1))); // Update the refresh latest quizzes table so that we know what the users latest quizzes are @@ -1560,23 +1272,52 @@ function quiz_questions_form_submit($form, &$form_state) { $is_new_revision = (bool) $form_state['values']['new_revision']; } - _quiz_question_browser_submit($form, $form_state); + // $weight_map = $form_state['values']['weights']; + // $max_scores = $form_state['values']['max_scores']; + // $refreshes = isset($form_state['values']['revision']) ? $form_state['values']['revision'] : NULL; + // $stayers = $form_state['values']['stayers']; + // $compulsories = isset($form_state['values']['compulsories']) ? $form_state['values']['compulsories'] : NULL; + + $num_random = isset($form_state['values']['question_list']['random_settings']['num_random_questions']) ? $form_state['values']['question_list']['random_settings']['num_random_questions'] : 0; + + $quiz->max_score_for_random = isset($form_state['values']['question_list']['random_settings']['max_score_for_random']) ? $form_state['values']['question_list']['random_settings']['max_score_for_random'] : 1; + + // Store what questions belong to the quiz + // $questions = _quiz_update_items($quiz, $weight_map, $max_scores, $is_new_revision, $refreshes, $stayers, $compulsories); + $questions = array(); + foreach ($form_state['values']['question_list']['questions'] as $id => $question) { + if (intval($id) || $id == '0') { + $question = new StdClass(); + $question->nid = $form_state['values']['question_list']['questions'][$id]['nid']; + $question->vid = $form_state['values']['question_list']['questions'][$id]['vid']; + if (isset($form_state['values']['question_list']['questions'][$id]['status'])) { + if ($form_state['values']['question_list']['questions'][$id]['status'] == 1) { + $question->state = QUESTION_ALWAYS; + } + else { + $question->state = QUESTION_RANDOM; + $form_state['values']['question_list']['questions'][$id]['max_score'] = $quiz->max_score_for_random; + } + } + else { + $question->state = QUESTION_ALWAYS; + } + $question->weight = $form_state['values']['question_list']['questions'][$id]['weight']; + $question->max_score = $form_state['values']['question_list']['questions'][$id]['max_score']; + $question->refresh = (isset($form_state['values']['question_list']['questions'][$id]['update']) && $form_state['values']['question_list']['questions'][$id]['update'] == 1); - $weight_map = $form_state['values']['weights']; - $max_scores = $form_state['values']['max_scores']; - $refreshes = isset($form_state['values']['revision']) ? $form_state['values']['revision'] : NULL; - $stayers = $form_state['values']['stayers']; - $compulsories = isset($form_state['values']['compulsories']) ? $form_state['values']['compulsories'] : NULL; + // Add item as an object in the questions array. + $questions[] = $question; + } + } + // Save questions. + quiz_set_questions($quiz, $questions, $is_new_revision); - $num_random = isset($form_state['values']['num_random_questions']) ? $form_state['values']['num_random_questions'] : 0; - $quiz->max_score_for_random = isset($form_state['values']['max_score_for_random']) ? $form_state['values']['max_score_for_random'] : 1; - $term_id = isset($form_state['values']['random_term_id']) ? (int) $form_state['values']['random_term_id'] : 0; - // Store what questions belong to the quiz - $questions = _quiz_update_items($quiz, $weight_map, $max_scores, $is_new_revision, $refreshes, $stayers, $compulsories); + $term_id = isset($form_state['values']['question_list']['random_settings']['random_term_id']) ? (int) $form_state['values']['question_list']['random_settings']['random_term_id'] : 0; // If using random questions and no term ID is specified, make sure we have enough. if (empty($term_id)) { @@ -1636,41 +1377,65 @@ function quiz_questions_form_submit($form, &$form_state) { } } + /** - * Takes care of the browser part of the submitted form values. - * - * This function changes the form_state to reflect questions added via the browser. - * (Especially if js is disabled) - * - * - * @param $form - * FAPI form(array) - * @param $form_state - * FAPI form_state(array) + * Update a quiz set of items with new weights and membership + * @param $quiz + * The quiz node + * @param $weight_map + * Weights for each question(determines the order in which the question will be taken by the quiz taker) + * @param $max_scores + * Array of max scores for each question + * @param $is_new_revision + * Array of boolean values determining if the question is to be updated to the newest revision + * @param $refreshes + * True if we are creating a new revision of the quiz + * @param $stayers + * Questions added to the quiz + * @param $compulsories + * Array of boolean values determining if the question is compulsory or not. + * @return array set of questions after updating */ -function _quiz_question_browser_submit($form, &$form_state) { - // Find the biggest weight: - $next_weight = max($form_state['values']['weights']); - - // If a question is chosen in the browser, add it to the question list if it isn't already there - if (isset($form_state['values']['browser']['table']['titles'])) { - foreach ($form_state['values']['browser']['table']['titles'] as $id) { - if ($id !== 0) { - if ($form_state['values']['stayers'][$id] == 1) { - continue; - } - $matches = array(); - preg_match('/([0-9]+)-([0-9]+)/', $id, $matches); - $nid = $matches[1]; - $vid = $matches[2]; - $form_state['values']['weights'][$id] = ++$next_weight; - $form_state['values']['max_scores'][$id] = quiz_question_get_max_score($nid, $vid); - $form_state['values']['stayers'][$id] = 1; +function _quiz_update_items($quiz, $weight_map, $max_scores, $is_new_revision, $refreshes, $stayers, $compulsories = NULL) { + $questions = array(); + foreach ($weight_map as $id => $weight) { + // Do not add hidden questions to $questions + if ($stayers[$id] == 0) { + continue; + } + list($nid, $vid) = explode('-', $id, 2); + $nid = (int) $nid; + $vid = (int) $vid; + $question = new stdClass(); + $question->nid = $nid; + $question->vid = $vid; + if (isset($compulsories)) { + if ($compulsories[$id] == 1) { + $question->state = QUESTION_ALWAYS; + } + else { + $question->state = QUESTION_RANDOM; + $max_scores[$id] = $quiz->max_score_for_random; } } + else { + $question->state = QUESTION_ALWAYS; + } + $question->weight = $weight; + $question->max_score = $max_scores[$id]; + $question->refresh = (isset($refreshes[$id]) && $refreshes[$id] == 1); + + // Add item as an object in the questions array. + $questions[] = $question; } + + // Save questions. + quiz_set_questions($quiz, $questions, $is_new_revision); + + return $questions; } + /** * Store values for each browser filter in $_SESSION * @@ -1687,10 +1452,11 @@ function _quiz_questions_store_filters($filters) { // THEME FUNCTIONS + /** * Theme the admin quizzes table. * - * @param $results + * @param $form * As returned by _quiz_get_quizzes(). * * @ingroup themeable @@ -1811,6 +1577,8 @@ function theme_quiz_admin_summary($variables) { */ function theme_question_selection_table($variables) { $form = $variables['form']; + + drupal_add_tabledrag('question-list', 'order', 'sibling', 'question-list-weight', NULL, NULL, TRUE); // Building headers @@ -1844,6 +1612,11 @@ function theme_question_selection_table($variables) { return drupal_render($form['random_settings']) . $table . drupal_render_children($form); + + + + + } // RESULT MANAGEMENT diff --git a/quiz.css b/quiz.css index fd01491..faf6cec 100644 --- a/quiz.css +++ b/quiz.css @@ -1,3 +1,6 @@ + + + /* * Definitions that apply while viewing questions */ @@ -249,80 +252,23 @@ input.q-skip-button:hover, input#edit-back:hover { max-height: 300px; } -.mark-doubtful .toggle { - margin: auto; - position: relative; - width: 100px; - overflow: hidden; - height: 18px; - line-height: 18px; - font-size: 11px; - text-align: center; - cursor: pointer; - border: 1px solid #ccc; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - -khtml-border-radius: 3px; - border-radius: 3px; - -moz-box-shadow: 0 0 10px rgba(0,0,0,0.50) inset; - -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.50) inset; - box-shadow: 0 0 10px rgba(0,0,0,0.50) inset; -} - -.mark-doubtful .toggle.off { - background-clip: padding-box; - background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, color-stop(50%, red), color-stop(50%, white), color-stop(100%, white)); - background-image: -moz-linear-gradient(left, red 50%, white 50%, white 100%); - background-image: linear-gradient(left, red 50%, white 50%, white 100%); -} - -.mark-doubtful .toggle { - background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, color-stop(50%, white), color-stop(50%, green), color-stop(100%, green)); - background-image: -moz-linear-gradient(left, white 50%, green 50%, green 100%); - background-image: linear-gradient(left, white 50%, green 50%, green 100%); -} - -.mark-doubtful .toggle div { - position: relative; - color: #777; - width: 52px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; - background: white; - text-shadow: 1px 1px 0 white; - background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #FEFEFE), color-stop(100%, #EAEAEA)); - background-image: -moz-linear-gradient(top, #FEFEFE 0%, #EAEAEA 100%); - background-image: linear-gradient(top, #FEFEFE 0%, #EAEAEA 100%); - -webkit-transition: left 0.2s; - -mox-transition: left 0.2s; - -o-transition: left 0.2s; - transition: left 0.2s; -} - - -.mark-doubtful .toggle div:after, -.mark-doubtful .toggle div:before { - color: white; - text-shadow: none; - width: 50px; - position: absolute; - top: 0; - font-size: 9px; - font-weight: bold; -} +/* + * Definitions that apply on the quiz questions page. + */ -.mark-doubtful .toggle div:before { - content: "Doubtful"; - left: -48px; -} + #questionlist-wrapper .form-submit { + margin-right: 0; + margin-left: auto; + display: block !important; + } -.mark-doubtful .toggle div:after { - content: "Clear"; - right: -48px; +.question-browser-search-wrapper { + white-space: nowrap; } -.mark-doubtful .toggle.off div { - left: 48px; + +.question-browser-search-wrapper .form-item-question-browser-search-search-query, +.question-browser-search-wrapper .form-submit { + display: inline-block; } + diff --git a/quiz.info b/quiz.info index d6811b8..de2eb96 100644 --- a/quiz.info +++ b/quiz.info @@ -4,9 +4,6 @@ description = "Create interactive, multipage quizzes. This module must have at l dependencies[] = taxonomy core = 7.x -; Always available CSS -stylesheets[all][] = quiz.css - ; This is (or should be) recommended, but not required. ;dependencies[] = jquery_countdown diff --git a/quiz.install b/quiz.install index 1c44d72..80d708f 100644 --- a/quiz.install +++ b/quiz.install @@ -216,12 +216,6 @@ function quiz_schema() { 'not null' => TRUE, 'default' => 1, ), - 'mark_doubtful' => array( - 'type' => 'int', - 'size' => 'tiny', - 'not null' => TRUE, - 'default' => 0, - ), ), 'primary key' => array('vid'), // 'unique keys' => array('vid'), @@ -372,7 +366,7 @@ function quiz_schema() { 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, - ), + ), 'question_nid' => array( 'type' => 'int', 'unsigned' => TRUE, @@ -420,12 +414,6 @@ function quiz_schema() { 'not null' => TRUE, 'default' => 1, ), - 'is_doubtful' => array( - 'type' => 'int', - 'not null' => TRUE, - 'default'=> 0, - 'size'=> 'tiny' - ), ), 'primary key' => array('result_id', 'question_nid', 'question_vid'), 'indexes' => array( @@ -755,22 +743,6 @@ function quiz_update_7405() { } /** - * Adding columns mark answers as doubtful - */ -function quiz_update_7406(&$sandbox) { - $spec = array( - 'type' => 'int', - 'not null' => TRUE, - 'default'=> 0, - 'size'=> 'tiny' - ); - db_add_field('quiz_node_results_answers','is_doubtful', $spec); - db_add_field('quiz_node_properties', 'mark_doubtful', $spec); - return t('Added new format fields to the tables'); -} - - -/** * Implements hook_uninstall(). */ function quiz_uninstall() { diff --git a/quiz.module b/quiz.module index ceb7497..4596599 100644 --- a/quiz.module +++ b/quiz.module @@ -44,9 +44,9 @@ define('QUIZ_NAME', _quiz_get_quiz_name()); /** * Define feedback statuses. */ -define('QUIZ_FEEDBACK_END', 0); -define('QUIZ_FEEDBACK_QUESTION', 1); -define('QUIZ_FEEDBACK_NEVER', 2); +define('QUIZ_FEEDBACK_END', 0); +define('QUIZ_FEEDBACK_QUESTION', 1); +define('QUIZ_FEEDBACK_NEVER', 2); /** * Define options for keeping results. @@ -56,6 +56,14 @@ define('QUIZ_KEEP_LATEST', 1); define('QUIZ_KEEP_ALL', 2); /** + * Define quiz randomization states. + */ +define('QUIZ_RANDOM_NONE', 0); +define('QUIZ_RANDOM_ORDER', 1); +define('QUIZ_RANDOM_QUESTIONS', 2); +define('QUIZ_RANDOM_CATEGORIES', 3); + +/** * Implements hook_help(). */ function quiz_help($path, $arg) { @@ -316,6 +324,15 @@ function quiz_element_info() { return $types; } */ +/** + * Implements hook_init(). + * + * Add quiz-specific styling. + */ +function quiz_init() { + // @todo Use form api #attached + drupal_add_css(drupal_get_path('module', 'quiz') . '/quiz.css'); +} /* * Implementation of hook_cron(). @@ -625,6 +642,16 @@ function quiz_theme($existing, $type, $theme, $path) { 'quiz_my_results_for_quiz' => array( 'variables' => array('rows' => array()), 'file' => 'quiz.admin.inc' + ), + 'quiz_questions_list' => array( + 'render element' => 'form', + 'path' => $path . '/theme', + 'file' => 'quiz.theme.inc' + ), + 'quiz_questions_browse' => array( + 'render element' => 'form', + 'path' => $path . '/theme', + 'file' => 'quiz.theme.inc' ) ); } @@ -742,8 +769,7 @@ function quiz_insert($node) { 'allow_skipping' => $node->allow_skipping, 'allow_resume' => $node->allow_resume, 'allow_jumping' => $node->allow_jumping, - 'show_passed' => $node->show_passed, - 'mark_doubtful' => $node->mark_doubtful + 'show_passed' => $node->show_passed )) ->execute(); @@ -800,8 +826,7 @@ function quiz_update($node) { 'allow_skipping' => $node->allow_skipping, 'allow_resume' => $node->allow_resume, 'allow_jumping' => $node->allow_jumping, - 'show_passed' => $node->show_passed, - 'mark_doubtful' => $node->mark_doubtful + 'show_passed' => $node->show_passed )) ->condition('vid', $node->vid) ->condition('nid', $node->nid) @@ -935,7 +960,6 @@ function _quiz_get_node_defaults() { 'show_passed' => 1, 'quiz_open' => _quiz_form_prepare_date(), 'quiz_close' => _quiz_form_prepare_date(NULL, variable_get('quiz_default_close', 30)), - 'mark_doubtful' => 0, ); } @@ -1141,12 +1165,7 @@ function quiz_form(&$node, &$form_state) { '#default_value' => $node->repeat_until_correct, '#description' => t('Require the user to re-try the question until they answer it correctly.'), ); - $form['taking']['mark_doubtful'] = array( - '#type' => 'checkbox', - '#title' => t('Mark Doubtful'), - '#default_value' => $node->mark_doubtful, - '#description' => t('Allow user to mention if they are not sure about the answer'), - ); + $form['taking']['show_passed'] = array( '#type' => 'checkbox', '#title' => t('Show passed status'), @@ -1158,10 +1177,10 @@ function quiz_form(&$node, &$form_state) { '#type' => 'radios', '#title' => t('Randomize questions'), '#options' => array( - t('No randomization'), - t('Random order'), - t('Random questions'), - t('Categorized random questions'), + QUIZ_RANDOM_NONE => t('No randomization'), + QUIZ_RANDOM_ORDER => t('Random order'), + QUIZ_RANDOM_QUESTIONS => t('Random questions'), + QUIZ_RANDOM_CATEGORIES => t('Categorized random questions'), ), '#description' => t('The difference between "random order" and "random questions" is that with "random questions" questions are drawn randomly from a pool of questions. With "random order" the quiz will always consist of the same questions. With "Categorized random questions" you can choose several terms questions should be drawn from, and you can also choose how many questions that should be drawn from each, and max score for each term.'), '#default_value' => $node->randomization, @@ -2342,7 +2361,6 @@ function quiz_store_question_result($quiz, $result, $options) { 'points_awarded' => $points, 'answer_timestamp' => REQUEST_TIME, 'is_skipped' => (int) $result->is_skipped, - 'is_doubtful' => (int) $result->is_doubtful, 'tid' => ($quiz->randomization == 3 && $result->tid) ? $result->tid : 0, )); @@ -2354,7 +2372,7 @@ function quiz_store_question_result($quiz, $result, $options) { } else { $insert = db_insert('quiz_node_results_answers') - ->fields(array('question_nid', 'question_vid', 'result_id', 'is_correct', 'points_awarded', 'answer_timestamp', 'is_skipped', 'is_doubtful', 'number', 'tid')) + ->fields(array('question_nid', 'question_vid', 'result_id', 'is_correct', 'points_awarded', 'answer_timestamp', 'is_skipped', 'number', 'tid')) ->values(array( 'question_nid' => $result->nid, 'question_vid' => $result->vid, @@ -2363,7 +2381,6 @@ function quiz_store_question_result($quiz, $result, $options) { 'points_awarded' => $points, 'answer_timestamp' => REQUEST_TIME, 'is_skipped' => (int) $result->is_skipped, - 'is_doubtful' => (int) $result->is_doubtful, 'number' => $options['question_data']['number'], 'tid' => ($quiz->randomization == 3 && $result->tid) ? $result->tid : 0, )) @@ -3629,6 +3646,7 @@ function quiz_get_questions($quiz_nid = NULL, $quiz_vid = NULL, $include_all_typ $results = $query->execute(); + foreach($results as $result) { $node = $result; @@ -3645,7 +3663,44 @@ function quiz_get_questions($quiz_nid = NULL, $quiz_vid = NULL, $include_all_typ //} } } + return $questions; +} +/** + * Retrieve list of questions to be added to quiz. + * + * Used when on the manage questions page of a quiz. + * + * @param $nids + * Array of question nids + * @param $include_question + * Should the question(the node body) be included for the questions in the + * returned array? + * + * @return + * An array of questions. + */ +function quiz_get_added_questions($nids, $include_question = TRUE) { + $questions = array(); + if (empty($nids)) { + return array(); + } + if (!is_array($nids)) { + $nids = array($nids); + } + $query = db_select('node', 'n'); + $query->fields('n', array('nid', 'type')) + ->fields('nr', array('vid', 'title')); + $query->addField('n', 'vid', 'latest_vid'); + $query->join('node_revision', 'nr', 'n.nid = nr.nid'); + $query->condition('n.nid', $nids, 'IN') + ->condition('n.type', array_keys(_quiz_get_question_types()), 'IN') + ->condition('n.status', 1); + $results = $query->execute(); + foreach($results as $result) { + $node = $result; + $questions[] = quiz_node_map($node, $include_question); + } return $questions; } diff --git a/theme/quiz.theme.inc b/theme/quiz.theme.inc new file mode 100644 index 0000000..0869c28 --- /dev/null +++ b/theme/quiz.theme.inc @@ -0,0 +1,103 @@ + $row) { + if (intval($id) || $id == '0') { + $this_row = array(); + $this_row[] = array('data' => l($row['title']['#value'], 'node/' . $row['nid']['#value']), 'class' => 'question-title'); + $this_row[] = array('data' => $row['type']['#value'], 'class' => 'question-type'); + $row['weight']['#attributes']['class'] = array('weight', 'question-weight'); + $this_row[] = array('data' => drupal_render($row['weight']), 'class' => 'question-weight'); + $row['max_score']['#attributes']['class'] = array('max-score', 'question-max-score'); + $this_row[] = array('data' => drupal_render($row['max_score']), 'class' => 'question-max-score'); + if ($row['status']['#type'] == 'checkbox') { + $row['status']['#attributes']['class'] = array('compulsory', 'question-compulsory'); + $this_row[] = array('data' => drupal_render($row['status']), 'class' => 'question-compulsory'); + } + $this_row[] = array('data' => $row['update']['#markup'], 'class' => 'question-update'); + $this_row[] = array('data' => l(t('Edit'), 'node/' . $row['nid']['#value'] . '/edit', array('query' => drupal_get_destination())), 'class' => 'edit-link'); + $row['remove']['#attributes']['class'] = array('remove', 'question-remove'); + $this_row[] = array('data' => drupal_render($row['remove']), 'class' => 'question-remove'); + $table_rows[$row['weight']['#default_value']] = array('data' => $this_row, 'class' => array('draggable')); + } + } + if (empty($table_rows)) { + $no_questions = array( + '#type' => 'html_tag', + '#tag' => 'div', + '#attributes' => array( + 'id' => 'question-list-empty', + ), + '#value' => t('There are no questions in this quiz. Add existing questions using the question search below. Create new questions using the links above.'), + ); + return drupal_render($no_questions); + } + ksort($table_rows); + $temp_rows = $table_rows; + $temp_row = array_pop($temp_rows); + if (count($temp_row['data']) == 8) { + $headers = array(t('Question'), t('Type'), t('Weight'), t('Max Score'), t('Compulsory'), t('Update'), t('Edit'), t('Remove')); + } else { + $headers = array(t('Question'), t('Type'), t('Weight'), t('Max Score'), t('Update'), t('Edit'), t('Remove')); + } + $form['#children'] = theme('table', array('header' => $headers, 'rows' => $table_rows, 'attributes' => array('id'=>'questionlist'))); + $form['#children'] .= drupal_render($form['update']); + drupal_add_tabledrag('questionlist', 'order', 'sibling', 'question-weight'); + return $form['#children']; +} + + +/** + * Theme the quiz question browser question list. + * + * @param $form + * FAPI form array + * + */ +function theme_quiz_questions_browse($variables) { + $form = $variables['form']; + $table_rows = array(); + foreach($form as $id => $row) { + if (intval($id) || $id == '0') { + $this_row = array(); + $this_row[] = array('data' => drupal_render($row['add_to_quiz']), 'class' => 'question-select'); + $this_row[] = array('data' => $row['question']['#markup'], 'class' => 'question-name'); + $this_row[] = array('data' => $row['type']['#markup'], 'class' => 'question-type'); + $table_rows[] = array('data' => $this_row); + } + } + if (empty($table_rows)) { + $no_results = array( + '#type' => 'html_tag', + '#tag' => 'div', + '#attributes' => array( + 'id' => 'question-search-no-results', + ), + '#value' => t('Your search returned no results.'), + ); + return drupal_render($no_results); + } + + $headers = array(t('Add to quiz'), t('Question'), t('Type')); + $form['#children'] = theme('table', array('header' => $headers, 'rows' => $table_rows, 'attributes' => array('id'=>'questionlist'))); + $form['#children'] .= drupal_render($form['update']); + return $form['#children']; +} diff --git a/theme/quiz_question_browser.js b/theme/quiz_question_browser.js deleted file mode 100755 index 362c1ff..0000000 --- a/theme/quiz_question_browser.js +++ /dev/null @@ -1,381 +0,0 @@ -(function ($) { -/** - * Sponsored by: Norwegian Centre for Telemedicine - * Code: falcon - * - * @file - * Javascript functions for the quizQuestionBrowser - */ - -// The quiz object -var Quiz = Quiz || {inputEnabled:true}; - -/** - * Adding behavior. Behaviors are called everytime a page is refreshed fully or through ahah. - */ - -Drupal.behaviors.quizQuestionBrowserBehavior = { - attach: function(context, settings) { - - // Question rows in the browser - $('.quiz-question-browser-row') - .once() - - // Add selected class to already selected questions - .filter(':has(:checkbox:checked)') - .addClass('selected') - .end() - - // When the browser row is clicked toggle the selected class and add the questions to the question list - .click(function(event) { - $(this).toggleClass('selected'); - if (event.target.type !== 'checkbox') { - $(':checkbox', this).attr('checked', function() { - return !this.checked; - }); - } - var idToShow = Quiz.findNidVidString(this.id); - var oldHeight = $(document).height(); - if ($(this).hasClass('selected')) { - // Show the question in the question list - $('#question-list').css('display', 'table'); - $('#no-questions').hide(); - $('#q-' + idToShow).removeClass('hidden-question'); - } else { - // Hide the question in the question list - $('#q-' + idToShow).addClass('hidden-question'); - } - $('#edit-stayers-' + idToShow).attr('checked', ($('#q-' + idToShow).hasClass('hidden-question')) ? false : true); - Quiz.fixColorAndWeight($('#q-' + idToShow)); - var toScroll = $(document).height() - oldHeight; - window.scrollBy(0, toScroll); - }); - - // Filter row in the browser - - // Mark all button - $('#edit-browser-table-header-filters-all') - .once() - .click(function(event) { - var ch = $(this).attr('checked'); - $('.quiz-question-browser-row').each(function() { - if (!ch) { - $(this).filter(':has(:checkbox:checked)').each(function() { - $(this).click(); - }); - } - else { - $(this).filter(':has(:checkbox:not(:checked))').each(function() { - $(this).click(); - }); - } - }); - }); - - // Type and date filters - var selector = '#edit-browser-table-header-filters-type'; - selector += ', #edit-browser-table-header-filters-changed'; - $(selector) - .once() - .change(function(event) { - $('#browser-pager').remove(); - Quiz.setInputEnabled(false); - }); - - //Title and username filters - var quizRefreshId; - selector = '#edit-browser-table-header-filters-title'; - selector += ', #edit-browser-table-header-filters-name'; - $(selector) - .once() - // triggering custom event "doneTyping" one second after the last key up in the text fields... - .keyup(function(event) { - clearInterval(quizRefreshId); - var quizClicked = this; - quizRefreshId = setInterval(function(){ - $('#browser-pager').remove(); - $(quizClicked).trigger('doneTyping'); - clearInterval(quizRefreshId); - Quiz.setInputEnabled(false); - }, 1000); - }); - - // Sorting - - // Making datastructure holding all sortable colums and the events that triggers sorting - var toSort = [ - { - name: 'title', - event: 'doneTyping' - }, - { - name: 'name', - event: 'doneTyping' - }, - { - name: 'type', - event: 'change' - }, - { - name: 'changed', - event: 'change' - } - ]; - - for (i in toSort) { - $('.quiz-browser-header-'+ toSort[i].name +' > a') - .once() - .attr('myName', toSort[i].name) - .attr('myEvent', toSort[i].event) - .click(function(event) { - if (!Quiz.inputEnabled) { - event.preventDefault(); - return; - } - var myUrl = $(this).attr('href'); - myUrl = myUrl.slice(myUrl.indexOf('?') + 1); - // add-to-get is the query string used by drupals tablesort api. - // We need to post the query string to drupal since we are using ajax. - // The querystring will be added to $_REQUEST on the server. - $('#edit-browser-table-add-to-get').val(myUrl); - $('#edit-browser-table-header-filters-'+ $(this).attr('myName')).trigger($(this).attr('myEvent')); - event.preventDefault(); - Quiz.setInputEnabled(false); - }); - } - /* - // Pager - $('.pager-item a'+ notDone +', .pager-first a'+ notDone +', .pager-next a'+ notDone +', .pager-previous a'+ notDone +', .pager-last a'+ notDone) - .addClass(done) - .click(function(event){ - if (!Quiz.inputEnabled) { - event.preventDefault(); - return; - } - var myUrl = $(this).attr('href').substr(2); - Quiz.updatePageInUrl(myUrl); - $('.quiz-question-browser-row').remove(); - $('#edit-browser-table-filters-title').trigger('doneTyping'); - event.preventDefault(); - Quiz.setInputEnabled(false); - }); - */ - // If js is active we don't want to show a checkbox for selecting questions - $('.q-staying').css('display', 'none'); - // If js is active we use a link to remove questions from the question list - $('.q-remove').css('display', 'inline'); - - $('.handle-changes').click(function(event){ - if ($('#mq-fieldset .tabledrag-changed').length) { - var proceed = confirm(Drupal.t('Any unsaved changes will be lost. Are you sure you want to proceed?')); - if (!proceed) - event.preventDefault(); - } - }); - $('.q-compulsory').click(function(event){ - var idToToggle = Quiz.findNidVidString(this.id); - if(this.checked) { - $('#edit-max-scores-' + idToToggle).show(); - } - else { - $('#edit-max-scores-' + idToToggle).hide(); - } - }); - $('.q-compulsory').each(function(){ - var idToToggle = Quiz.findNidVidString(this.id); - if(!this.checked) { - $('#edit-max-scores-' + idToToggle).hide(); - } - }); - } -}; - - -/** - * Adding behavior. Behaviors are called everytime a page is refreshed fully or through ahah. - */ -Drupal.behaviors.attachRemoveAction = { - attach: function (context, settings) { - $('.rem-link:not(.attachRemoveAction-processed)') - .addClass('attachRemoveAction-processed') - .click(function (e) { - var $this = $(this); - var remID = $this.parents('tr').attr('id'); - var matches = remID.match(/[0-9]+-[0-9]+/); - if (!matches || matches.length < 1) { - return false; - } - Quiz.fixColorAndWeight($this.parents('tr')); - - //Hide the question - $this.parents('tr').filter(':first').addClass('hidden-question'); - - // Mark the question as removed - $('#edit-stayers-' + matches[0]).attr('checked', false); - - // Uncheck the question in the browser - $('#browser-'+ matches[0]).click(); - - var table = Drupal.tableDrag['question-list']; - if (!table.changed) { - table.changed = true; - $(Drupal.theme('tableDragChangedWarning')).insertAfter(table.table).hide().fadeIn('slow'); - } - - e.preventDefault(); - return true; - }); - } -}; - - - - -// This is only called once, not on ajax refreshes... -$(document).ready(function () { - - // There are some problems with table headers and ajax. We try to reduce those problems here... - var oldTableHeader = Drupal.behaviors.tableHeader; - Drupal.behaviors.tableHeader = function(context) { - if (!$('table.sticky-enabled', context).size()) { - return; - } - oldTableHeader(context); - }; - - // If a browser row is selected make sure it gets marked. - $('.quiz_question_browser_row:has(:checkbox:checked)').each(function() { - $(this).click(); - }); - - // If validation of the form fails questions added using the browser will become invisible. - // We fix this problem here: - $('.q-row').each(function() { - if ($('.q-staying', $(this)).attr('checked')) $(this).removeClass('hidden-question'); - }); -}); - -/** - * Updates the page part of the query string in the add-to-get hidden field - * - * @param myUrl - * The url in the links in the pager(string) - */ -Quiz.updatePageInUrl = function(myUrl) { - // Finds page from input parameter - var pageQuery = myUrl + ''; - var pattern = new RegExp('page=[0-9]+'); - pageQuery = pattern.exec(pageQuery); - if (pageQuery == null) pageQuery = 'page=0'; - - //Replaces stored query strings page with our page - var currentQuery = jQuery('#edit-browser-table-add-to-get').val() + ''; - currentQuery = currentQuery.replace(pattern, ''); - currentQuery += pageQuery; - jQuery('#edit-browser-table-add-to-get').val(currentQuery); -}; - -/** - * Restripes the question list and adjusts the weight fields - * - * @param newest - * The row that last was added to the question list(jQuery object) - */ -Quiz.fixColorAndWeight = function(newest) { - var nextClass = 'odd'; - var lastClass = 'even'; - var lastWeight = 0; - var lastQuestion = null; - var numQRows = 0; - - - $('.q-row').each(function() { - if (!$(this).hasClass('hidden-question') && $(this).attr('id') != newest.attr('id')) { - // Color: - numQRows++; - if (!$(this).hasClass(nextClass)) $(this).removeClass(lastClass).addClass(nextClass); - var currentClass = nextClass; - nextClass = lastClass; - lastClass = currentClass; - lastQuestion = $(this); - - // Weight: - var myId = Quiz.findNidVidString($(this).attr('id') + ''); - var weightField = $('#edit-weights-' + myId); - weightField.val(lastWeight); - lastWeight++; - } - }); - - - if (numQRows < 2) return; - - if (!newest.hasClass(nextClass)) newest.removeClass(lastClass).addClass(nextClass); - var newestId = Quiz.findNidVidString(newest.attr('id')); - - //We move the newest question to the bottom of the list - newest.insertAfter('#q-'+ Quiz.findNidVidString(lastQuestion.attr('id'))); - $('#edit-weights-' + newestId).val(lastWeight); - var marker = Drupal.theme('tableDragChangedMarker'); - var cell = $('td:first', newest); - if ($('span.tabledrag-changed', cell).length == 0) { - cell.append(marker); - } - var table = Drupal.tableDrag['question-list']; - if (!table.changed) { - table.changed = true; - $(Drupal.theme('tableDragChangedWarning')).insertAfter(table.table).hide().fadeIn('slow'); - } -}; - -/** - * Finds and returns the part of a string holding the nid and vid - * - * @param str - * A string that should have nid and vid inside it on this format: nid-vid, for instance 23-24 - */ -Quiz.findNidVidString = function(str) { - var pattern = new RegExp('[0-9]+-[0-9]+'); - return pattern.exec(str); -}; - - -/** - * Adds question rows to the question list - * - * @param rowHtml - * The question rows to be added(html string) - */ -Quiz.addQuestions = function (rowHtml) { - //Add the new rows: - $('#question-list tr:last').after(rowHtml); - - var table = Drupal.tableDrag['question-list']; - - $('.hidden-question').each(function(){ - // Hide weight column: - $('td:last', this).css('display', 'none'); - - table.makeDraggable(this); - }); - - Drupal.attachBehaviors(table.table); -}; - -/** - * Turn all input elements on or off - * - * @param enabled - * Should the inputs be swithced on or off? - */ -Quiz.setInputEnabled = function(enabled) { - Quiz.inputEnabled = enabled; - if (enabled) { - $('.quizQuestionBrowserBehavior-processed').removeAttr('disabled'); - } - else { - jQuery('.quizQuestionBrowserBehavior-processed').attr('disabled', true); - } -} - -})(jQuery);