diff --git a/quiz.admin.inc b/quiz.admin.inc
index bdd5db0..bedb16c 100644
--- a/quiz.admin.inc
+++ b/quiz.admin.inc
@@ -740,11 +740,12 @@ 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);
- }
+ $form = array(
+ '#attributes' => array(
+ 'id' => 'quiz-manage-questions-form',
+ ),
+ '#tree' => TRUE,
+ );
$types = _quiz_get_question_types();
@@ -757,51 +758,235 @@ function quiz_questions_form($form, $form_state, $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);
- // Build up a list of questions
- $questions_to_add = array();
+ if ($quiz->randomization == 2) {
+ $form['question_list']['random'] = array(
+ '#type' => 'value',
+ '#value' => TRUE,
+ );
+ }
+ else {
+ $form['question_list']['random'] = array(
+ '#type' => 'value',
+ '#value' => FALSE,
+ );
+ }
- // 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)
+ $qstns = $form_state['values']['question_list']['questions'];
+ foreach ($qstns as $key => $qstn) {
+ if (preg_match('/\d+-\d+/', $key) != FALSE) {
+ $questions[] = $qstn;
+ }
+ }
}
else {
- // We are coming in fresh and fetches the questions currently on the quiz from the database...
+ // Fetch questions from the database
$include_random = $quiz->randomization == 2;
$questions = quiz_get_questions($quiz->nid, $quiz->vid, TRUE, FALSE, FALSE, $include_random);
+ foreach ($questions as $id => $question) {
+ $questions[$id] = get_object_vars($question);
+ }
}
- 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.') . '
',
+ $question_ids = array();
+ if (!empty($questions)) {
+ foreach ($questions as $question) {
+ $question_ids[] = $question['nid'];
+ $question_id = $question['nid'] . '-' . $question['vid'];
+
+ 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 == 2) {
+ $status = array(
+ '#type' => 'checkbox',
+ '#default_value' => isset($question['question_status']) ? ($question['question_status'] == QUESTION_ALWAYS) ? 1 : 0 : 0,
+ );
+ } else {
+ $status = array(
+ '#type' => 'hidden',
+ '#value' => $question['question_status'],
+ );
+ }
+
+ $qstn = array();
+ $qstn['nid'] = array(
+ '#type' => 'value',
+ '#value' => $question['nid'],
+ );
+ $qstn['vid'] = array(
+ '#type' => 'value',
+ '#value' => $question['vid'],
+ );
+ $qstn['title'] = array(
+ '#type' => 'hidden',
+ '#value' => $question['title'],
+ '#prefix' => $question['title'],
+ );
+ $qstn['type'] = array(
+ '#type' => 'hidden',
+ '#value' => $question['type'],
+ '#prefix' => $types[$question['type']]['name'],
+ );
+ $qstn['latest_vid'] = array(
+ '#type' => 'value',
+ '#value' => $question['latest_vid'],
+ );
+ $qstn['update'] = $update_cell;
+ $qstn['question_status'] = $status;
+
+ $qstn['max_score'] = array(
+ '#type' => 'textfield',
+ '#size' => 3,
+ '#default_value' => $question['max_score'],
+ );
+ $qstn['weight'] = array(
+ '#type' => 'textfield',
+ '#size' => 3,
+ '#default_value' => $question['weight'],
+ );
+ $qstn['remove'] = array(
+ '#type' => 'checkbox',
+ );
+
+ $form['question_list']['questions'][$question_id] = $qstn;
+
+ }
+ }
+ else {
+ $form['additional_questions']['#collapsed'] = FALSE;
+ }
+
+ // 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',
+ ),
+ );
+
+ // 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']) && !empty($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 . '-' . $question->vid] = array(
+ 'add_to_quiz' => array(
+ '#type' => 'checkbox',
+ '#default_value' => 0,
+ ),
+ 'question' => array(
+ '#type' => 'markup',
+ '#markup' => $question->title,
+ ),
+ 'type' => array(
+ '#type' => 'markup',
+ '#markup' => $types[$question->type]['name'],
+ ),
+ 'nid' => array(
+ '#type' => 'hidden',
+ '#value' => $question->nid,
+ ),
+ );
+ }
+
+ $form['question_browser']['questions'] = $question_search;
+ $form['question_browser']['questions'] += array(
+ '#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',
+ ),
);
}
- // 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);
- // We add the questions to the form array
- _quiz_add_questions_to_form($form, $questions, $quiz, $types);
+
+
+
+
+
+
+
// 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++;
+ $question_count = 0;
+ foreach ($form['question_list']['questions'] as $key => $question) {
+ if (preg_match('/\d+-\d+/', $key) != FALSE) {
+ $question_count++;
}
}
- $form['question_list']['#title'] .= ' (' . $always_count . ')';
+ $form['question_list']['#title'] .= ' (' . $question_count . ')';
// Give the user the option to create a new revision of the quiz
_quiz_add_revision_checkbox($form, $quiz);
@@ -817,6 +1002,23 @@ function quiz_questions_form($form, $form_state, $quiz) {
return $form;
}
+
+/**
+ * Handler for quiz_questions_form ajax.
+ *
+ * @param $form
+ * The form variable
+ * @param $form_state
+ * The form state variable
+ * @return
+ * Content for AJAX to use.
+ */
+function quiz_questions_ajax($form, $form_state) {
+ return $form;
+}
+
+
+
/**
* Fields for creating new questions are added to the quiz_questions_form
*
@@ -903,237 +1105,6 @@ function _quiz_add_fields_for_random_quiz(&$form, $quiz) {
/**
- * Returns the questions that was in the question list when the form was submitted using ajax.
- *
- * @param $form_state
- * FAPI form_state(array)
- * @return $questions
- * Array of questions as objects
- */
-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;
- }
- $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.
- *
- * Hidden questions are used to avoid unnecessary ajax calls.
- *
- * @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
- */
-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;
- }
- }
- if (!is_numeric($nid) || !is_numeric($vid) || $continue) {
- continue;
- }
-
- $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];
- }
- }
-}
-
-/**
- * Adds the questions in the $questions array to the form
- *
- * @param $form
- * FAPI form(array)
- * @param $questions
- * The questions to be added to the question list(array)
- * @param $quiz
- * The quiz node(object)
- * @param $question_types
- * array of all available question types
- */
-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'],
- );
-
- $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')),
- )
- ),
- );
- // For js enabled browsers questions are removed by pressing a remove link
- $form[$fieldset]['remove_links'][$id] = array(
- '#markup' => '' . t('Remove') . '',
- );
- // 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.
*
* @param $form
@@ -1167,377 +1138,146 @@ 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], '<');
+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]);
+ }
}
}
- $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' => '',
- );
- return $form;
}
/**
- * adds filter fields to the question browser form
+ * Handler for quiz_questions_form ajax add questions button.
*
- * @param $browser
- * FAPI form(array)
- * @param $question_types
- * Array of question types
+ * Adds questions to the $form_state array.
+ *
+ * @param $form_state
+ * The form state variable
*/
-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'];
+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 $key => $question) {
+ if (preg_match('/\d+-\d+/', $key) != FALSE) {
+ if (isset($question['weight']) && $question['weight'] > $max_weight) {
+ $max_weight = $question['weight'];
+ }
+ }
+ }
+ $nids = array();
+ foreach ($form_state['values']['question_browser']['questions'] as $key => $new_question) {
+ if (preg_match('/\d+-\d+/', $key) != FALSE) {
+ if ($new_question['add_to_quiz'] == 1) {
+ $nids[] = $new_question['nid'];
+ }
+ }
+ }
+ $new_questions = quiz_get_added_questions($nids);
+ foreach($new_questions as $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 . '-' . $question->vid] = 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,
+ );
+ }
}
+}
- // 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
+ * Retrieve list of questions to be added to quiz.
*
- * @see _quiz_questions_browser_form()
+ * Used when on the manage questions page of a quiz.
*
- * @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)
+ * @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_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'];
+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 $filter_sql;
+ return $questions;
}
+
+
+
+
+
/**
* 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'));
- }
- }
-}
+ // Make sure max score is 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;
+ foreach ($form_state['values']['question_list']['questions'] as $key => $question) {
+ if (preg_match('/\d+-\d+/', $key) != FALSE) {
+ 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_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;
+ // Add questions selected for addition
+ _quiz_add_new_questions_to_quiz($form_state);
}
/**
@@ -1546,10 +1286,6 @@ function _quiz_update_items($quiz, $weight_map, $max_scores, $is_new_revision, $
* 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 +1296,56 @@ function quiz_questions_form_submit($form, &$form_state) {
$is_new_revision = (bool) $form_state['values']['new_revision'];
}
- _quiz_question_browser_submit($form, $form_state);
+ $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;
+ $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);
+
+
+
+
+
+ $questions = array();
+ foreach ($form_state['values']['question_list']['questions'] as $key => $question) {
+ if (preg_match('/\d+-\d+/', $key) != FALSE) {
+ $question = new StdClass();
+ $question->nid = $form_state['values']['question_list']['questions'][$key]['nid'];
+ $question->vid = $form_state['values']['question_list']['questions'][$key]['vid'];
+ if (isset($form_state['values']['question_list']['questions'][$key]['question_status'])) {
+ if ($form_state['values']['question_list']['questions'][$key]['question_status'] == 1) {
+ $question->state = QUESTION_ALWAYS;
+ }
+ else {
+ $question->state = QUESTION_RANDOM;
+ $form_state['values']['question_list']['questions'][$key]['max_score'] = $quiz->max_score_for_random;
+ }
+ }
+ else {
+ $question->state = QUESTION_ALWAYS;
+ }
+ $question->weight = $form_state['values']['question_list']['questions'][$key]['weight'];
+ $question->max_score = $form_state['values']['question_list']['questions'][$key]['max_score'];
+ $question->refresh = (isset($form_state['values']['question_list']['questions'][$key]['update']) && $form_state['values']['question_list']['questions'][$id]['update'] == 1);
+
+ // Add item as an object in the questions array.
+ $questions[] = $question;
+ }
+ }
+ // Save questions.
+ quiz_set_questions($quiz, $questions, $is_new_revision);
+
+ $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;
+
+
- $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']['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);
// If using random questions and no term ID is specified, make sure we have enough.
if (empty($term_id)) {
@@ -1806,45 +1575,6 @@ function theme_quiz_admin_summary($variables) {
return $output;
}
-/**
- * Theme a question selection table, adding drag and drop support.
- */
-function theme_question_selection_table($variables) {
- $form = $variables['form'];
- drupal_add_tabledrag('question-list', 'order', 'sibling', 'question-list-weight', NULL, NULL, TRUE);
-
- // Building headers
- $headers = array(t('Question'), t('Type'), t('Actions'), t('Update'), t('Max score'));
- if (isset($form['compulsories'])) {
- $headers[] = t('Compulsory');
- }
- $headers[] = t('Weight');
-
- // Building table body
- $rows = array();
- if (!empty($form['titles'])) {
- foreach (element_children($form['titles']) as $id) {
- $form['weights'][$id]['#attributes']['class'] = array('question-list-weight');
-
- $rows[] = _quiz_get_question_row($form, $id);
- }
- // Make sure the same fields aren't rendered twice
- unset($form['types'], $form['view_links'], $form['remove_links'], $form['stayers']);
- unset($form['max_scores'], $form['revision'], $form['weights'], $form['titles'], $form['compulsories']);
- }
- $html_attr = array('id' => 'question-list');
-
- // We hide the table if no questions have been added so that jQuery can show it the moment the first question is beeing added.
- if (isset($form['no_questions'])) {
- $html_attr['style'] = "display:none;";
- }
-
- $table = theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => $html_attr));
-
- return drupal_render($form['random_settings'])
- . $table
- . drupal_render_children($form);
-}
// RESULT MANAGEMENT
@@ -2333,47 +2063,6 @@ function _quiz_skip_validation(&$elements) {
}
}
-/**
- * Helper function for theme_question_selection_table
- *
- * TODO: DELETE
- *
- * @see quiz_questions_form()
- * @see theme_question_selection_table()
- *
- * @param $sub_form
- * Form definition array for a filtered questions list
- * @param $id
- * Identifier used in $sub_form
- * @return table row
- * Array defining a table row
- */
-function _quiz_get_question_row($sub_form, $id) {
- $question_types = _quiz_get_question_types();
- $type = $sub_form['types'][$id]['#markup'];
-
- // We add the class "hidden-class" to hide questions that haven't been added to the quiz yet.
- $hidden_class = ($sub_form['stayers'][$id]['#default_value'] === 0) ? ' hidden-question' : '';
-
- $data_array = array(
- // The checkbox and the title
- drupal_render($sub_form['stayers'][$id]) . drupal_render($sub_form['titles'][$id]),
-
- $type,
- $sub_form['view_links'][$id]['#markup'] . ' | ' . $sub_form['remove_links'][$id]['#markup'] . '',
- isset($sub_form['revision'][$id]) ? drupal_render($sub_form['revision'][$id]) : t("Up to date"),
- drupal_render($sub_form['max_scores'][$id])
- );
- if (isset($sub_form['compulsories'])) {
- $data_array[] = drupal_render($sub_form['compulsories'][$id]);
- }
- $data_array[] = drupal_render($sub_form['weights'][$id]);
- return array(
- 'class' => array('q-row draggable' . $hidden_class),
- 'id' => 'q-' . $id,
- 'data' => $data_array
- );
-}
/**
* Finds and returns the last table rows(HTML) in a table(HTML)
diff --git a/quiz.module b/quiz.module
index 427502b..15a92df 100644
--- a/quiz.module
+++ b/quiz.module
@@ -568,10 +568,6 @@ function quiz_theme($existing, $type, $theme, $path) {
'file' => 'quiz.pages.inc',
'variables' => array('question_node' => NULL),
),
- 'question_selection_table' => array(
- 'file' => 'quiz.admin.inc',
- 'render element' => 'form',
- ),
'quiz_score_correct' => array(
'file' => 'quiz.pages.inc',
'variables' => array(),
@@ -625,7 +621,17 @@ function quiz_theme($existing, $type, $theme, $path) {
'quiz_my_results_for_quiz' => array(
'variables' => array('rows' => array()),
'file' => 'quiz.admin.inc'
- )
+ ),
+ 'question_selection_table' => array(
+ 'file' => 'quiz.theme.inc',
+ 'path' => $path . '/theme',
+ 'render element' => 'form',
+ ),
+ 'quiz_questions_browse' => array(
+ 'file' => 'quiz.theme.inc',
+ 'path' => $path . '/theme',
+ 'render element' => 'form',
+ ),
);
}
diff --git a/theme/quiz.theme.inc b/theme/quiz.theme.inc
new file mode 100644
index 0000000..89ec242
--- /dev/null
+++ b/theme/quiz.theme.inc
@@ -0,0 +1,94 @@
+ $val) {
+ if (preg_match('/\d+-\d+/', $key) != FALSE) {
+ $questions[$key] = $val;
+ }
+ }
+
+ // Building table body
+ $rows = array();
+ foreach ($questions as $question) {
+ $this_row = array();
+ $this_row[] = array('data' => drupal_render($question['title']), 'class' => 'question-list-title');
+ if ($form['random']['#value'] == TRUE) {
+ $this_row[] = array('data' => drupal_render($question['question_status']), 'class' => 'question-list-compulsory');
+ }
+ $this_row[] = array('data' => drupal_render($question['type']), 'class' => 'question-list-type');
+ $this_row[] = array('data' => l('Edit', 'node/' . $question['nid']['#value'] . '/edit', array('query' => drupal_get_destination())), 'class' => 'question-list-edit');
+ $this_row[] = array('data' => drupal_render($question['remove']), 'class' => 'question-list-remove');
+ $this_row[] = array('data' => drupal_render($question['update']), 'class' => 'question-list-update');
+ $this_row[] = array('data' => drupal_render($question['max_score']), 'class' => 'question-list-max-score');
+ $this_row[] = array('data' => drupal_render($question['weight']), 'class' => 'question-list-weight');
+ $rows[] = array('data' => $this_row, 'class' => array('draggable', 'question-' . $question['nid']['#value']));;
+ }
+
+ // Building headers
+ if ($form['random']['#value'] == TRUE) {
+ $headers = array(t('Question'), t('Compulsory'), t('Type'), t('Edit'), t('Remove'), t('Update'), t('Max score'), t('Weight'));
+ }
+ else {
+ $headers = array(t('Question'), t('Type'), t('Edit'), t('Remove'), t('Update'), t('Max score'), t('Weight'));
+ }
+
+
+ if (!empty($questions)) {
+ $table = theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => 'question-list')));
+ drupal_add_tabledrag('question-list', 'order', 'sibling', 'question-list-weight', NULL, NULL, TRUE);
+ $form['questions']['#children'] = $table;
+ $form['questions']['#children'] .= drupal_render($form['questions']['update']);
+ }
+ else {
+ $form['questions']['#children'] = '' . 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.') . '
';
+ }
+
+ return drupal_render_children($form);
+}
+
+
+
+
+/**
+ * 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'];
+}