From 072c95122b9a83b3d7564ae8166f10da7a361951 Mon Sep 17 00:00:00 2001 From: Gordon Bateson Date: Sun, 15 Nov 2015 10:12:39 +0900 Subject: [PATCH] MDL-79863 qtype_ordering: qtype/ordering increase padding of draggable elements to allow easier dropping in first and last positions --- .../backup_qtype_ordering_plugin.class.php | 2 +- question/type/ordering/db/install.xml | 5 +- question/type/ordering/db/upgrade.php | 17 ++ question/type/ordering/edit_ordering_form.php | 127 +++++++++++++-- .../type/ordering/lang/en/qtype_ordering.php | 4 + question/type/ordering/question.php | 30 ++-- question/type/ordering/questiontype.php | 147 +++++++++++++----- question/type/ordering/renderer.php | 36 +++-- question/type/ordering/styles.css | 38 ++++- question/type/ordering/version.php | 4 +- 10 files changed, 326 insertions(+), 84 deletions(-) diff --git a/question/type/ordering/backup/moodle2/backup_qtype_ordering_plugin.class.php b/question/type/ordering/backup/moodle2/backup_qtype_ordering_plugin.class.php index 2213e9898f4..adb11045694 100644 --- a/question/type/ordering/backup/moodle2/backup_qtype_ordering_plugin.class.php +++ b/question/type/ordering/backup/moodle2/backup_qtype_ordering_plugin.class.php @@ -50,7 +50,7 @@ class backup_qtype_ordering_plugin extends backup_qtype_plugin { $this->add_question_question_answers($pluginwrapper); // Now create the qtype own structures - $fields = array('selecttype', 'selectcount', + $fields = array('layouttype', 'selecttype', 'selectcount', 'correctfeedback', 'correctfeedbackformat', 'incorrectfeedback', 'incorrectfeedbackformat', 'partiallycorrectfeedback', 'partiallycorrectfeedbackformat'); diff --git a/question/type/ordering/db/install.xml b/question/type/ordering/db/install.xml index 13e485b10e8..b1ec87f3384 100644 --- a/question/type/ordering/db/install.xml +++ b/question/type/ordering/db/install.xml @@ -4,8 +4,9 @@ - - + + + diff --git a/question/type/ordering/db/upgrade.php b/question/type/ordering/db/upgrade.php index 017a0801488..cf959cc46c7 100644 --- a/question/type/ordering/db/upgrade.php +++ b/question/type/ordering/db/upgrade.php @@ -149,6 +149,23 @@ function xmldb_qtype_ordering_upgrade($oldversion) { upgrade_plugin_savepoint(true, $newversion, 'qtype', 'ordering'); } + $newversion = 2015110725; + if ($oldversion < $newversion) { + $table = new xmldb_table('qtype_ordering_options'); + $fields = array( + new xmldb_field('layouttype', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, 0, 'questionid'), + new xmldb_field('selecttype', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, 0, 'layouttype') + ); + foreach ($fields as $field) { + if ($dbman->field_exists($table, $field)) { + $dbman->change_field_type($table, $field); + } else { + $dbman->add_field($table, $field); + } + } + upgrade_plugin_savepoint(true, $newversion, 'qtype', 'ordering'); + } + return true; } diff --git a/question/type/ordering/edit_ordering_form.php b/question/type/ordering/edit_ordering_form.php index 93cc5c86793..b0e102abe79 100644 --- a/question/type/ordering/edit_ordering_form.php +++ b/question/type/ordering/edit_ordering_form.php @@ -41,6 +41,13 @@ class qtype_ordering_edit_form extends question_edit_form { const NUM_ANS_START = 6; const NUM_ANS_ADD = 2; + // this functionality is currently disabled + // because it is not fully functional + protected $use_editor_for_answers = false; + + /** + * unique name for this question type + */ public function qtype() { return 'ordering'; } @@ -55,6 +62,17 @@ class qtype_ordering_edit_form extends question_edit_form { // cache this plugins name $plugin = 'qtype_ordering'; + // layouttype + $name = 'layouttype'; + $label = get_string($name, $plugin); + $options = array( + 0 => get_string('vertical', $plugin), + 1 => get_string('horizontal', $plugin) + ); + $mform->addElement('select', $name, $label, $options); + $mform->addHelpButton($name, $name, $plugin); + $mform->setDefault($name, 0); + // selecttype $name = 'selecttype'; $label = get_string($name, $plugin); @@ -80,16 +98,24 @@ class qtype_ordering_edit_form extends question_edit_form { $mform->setDefault($name, 0); // answers (=items) + // get_per_answer_fields() + // add_per_answer_fields() $elements = array(); + $options = array(); $name = 'answerheader'; $label = get_string($name, $plugin); - $elements[] =& $mform->createElement('header', $name, $label); + $elements[] = $mform->createElement('header', $name, $label); + $options[$name] = array('expanded' => true); $name = 'answer'; $label = get_string($name, $plugin); - $options = array('rows' => self::NUM_ANS_ROWS, 'cols' => self::NUM_ANS_COLS); - $elements[] =& $mform->createElement('textarea', $name, $label, $options); + if ($this->use_editor_for_answers) { + $elements[] = $mform->createElement('editor', $name, $label, $this->get_editor_attributes(), $this->get_editor_options()); + } else { + $elements[] = $mform->createElement('textarea', $name, $label, array('rows' => self::NUM_ANS_ROWS, 'cols' => self::NUM_ANS_COLS)); + } + $options[$name] = array('type' => PARAM_RAW); if (empty($this->question->options)){ $start = 0; @@ -99,14 +125,40 @@ class qtype_ordering_edit_form extends question_edit_form { if ($start < self::NUM_ANS_START) { $start = self::NUM_ANS_START; } - $options = array('answerheader' => array('expanded' => true)); $buttontext = get_string('addmoreanswers', $plugin, self::NUM_ANS_ADD); $this->repeat_elements($elements, $start, $options, 'countanswers', 'addanswers', self::NUM_ANS_ADD, $buttontext); // feedback - $this->add_ordering_feedback_fields(); + $this->add_ordering_feedback_fields(true); + + // interactive + $this->add_ordering_interactive_settings(true, true); } + /** + * get_editor_attributes + */ + protected function get_editor_attributes() { + return array( + 'rows' => self::NUM_ANS_ROWS, + 'cols' => self::NUM_ANS_COLS + ); + } + + /** + * get_editor_options + */ + protected function get_editor_options() { + return array( + 'context' => $this->context, + 'maxfiles' => EDITOR_UNLIMITED_FILES, + 'noclean' => true + ); + } + + /** + * data_preprocessing + */ public function data_preprocessing($question) { $question = parent::data_preprocessing($question); @@ -118,17 +170,57 @@ class qtype_ordering_edit_form extends question_edit_form { // answers and fractions $question->answer = array(); $question->fraction = array(); + if (isset($question->options->answers)) { + $i = 0; foreach ($question->options->answers as $answer) { + if (trim($answer->answer)=='') { continue; // skip empty answers } - $question->answer[$i] = $answer->answer; + + if ($this->use_editor_for_answers) { + $draftid = file_get_submitted_draft_itemid("answer[$i]"); + + if (isset($answer->id)) { + $itemid = $answer->id; + } else { + $itemid = null; + } + + if (isset($answer->answer)) { + $text = $answer->answer; + } else { + $text = ''; + } + + if (isset($answer->answerformat)) { + $format = $answer->answerformat; + } else { + $format = FORMAT_MOODLE; + } + + $text = file_prepare_draft_area($draftid, $this->context->id, 'qtype_ordering', + 'answer', $itemid, $this->editoroptions, $text); + + $question->answer[$i] = array('text' => $text, + 'format' => $format, + 'itemid' => $draftid); + } else { + $question->answer[$i]= $answer->answer; + } + $question->fraction[$i] = ($i + 1); $i++; } + } + // layouttype + if (isset($question->options->layouttype)) { + $question->layouttype = $question->options->layouttype; + } else { + $question->layouttype = 0; } // selecttype @@ -154,6 +246,9 @@ class qtype_ordering_edit_form extends question_edit_form { $answercount = 0; foreach ($data['answer'] as $answer){ + if ($this->use_editor_for_answers) { + $answer = $answer['text']; + } if (trim($answer)=='') { continue; // skip empty answer } @@ -168,11 +263,10 @@ class qtype_ordering_edit_form extends question_edit_form { return $errors; } - - protected function add_ordering_feedback_fields($withshownumpartscorrect = false) { + protected function add_ordering_feedback_fields($shownumpartscorrect = false) { if (method_exists($this, 'add_combined_feedback_fields')) { // Moodle >= 2.1 - $this->add_combined_feedback_fields($withshownumpartscorrect); + $this->add_combined_feedback_fields($shownumpartscorrect); } else { // Moodle 2.0 $mform = $this->_form; @@ -185,10 +279,17 @@ class qtype_ordering_edit_form extends question_edit_form { } } - protected function data_preprocessing_ordering_feedback($question, $withshownumcorrect = false) { + protected function add_ordering_interactive_settings($clearwrong=false, $shownumpartscorrect=false) { + if (method_exists($this, 'add_interactive_settings')) { + // Moodle >= 2.1 + $this->add_interactive_settings($clearwrong, $shownumpartscorrect); + } + } + + protected function data_preprocessing_ordering_feedback($question, $shownumcorrect=false) { if (method_exists($this, 'data_preprocessing_combined_feedback')) { // Moodle >= 2.1 - $question = $this->data_preprocessing_combined_feedback($question, $withshownumcorrect); + $question = $this->data_preprocessing_combined_feedback($question, $shownumcorrect); } else { // Moodle 2.0 $names = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'); @@ -208,13 +309,13 @@ class qtype_ordering_edit_form extends question_edit_form { } $text = file_prepare_draft_area($draftid, $this->context->id, 'qtype_ordering', - $name, $itemid, $this->fileoptions, $text); + $name, $itemid, $this->editoroptions, $text); $format = $name.'format'; if (isset($question->options->$format)) { $format = $question->options->$format; } else { - $format = 0; + $format = FORMAT_MOODLE; } $question->$name = array('text' => $text, diff --git a/question/type/ordering/lang/en/qtype_ordering.php b/question/type/ordering/lang/en/qtype_ordering.php index 46f2300a7c4..990b6ae9953 100644 --- a/question/type/ordering/lang/en/qtype_ordering.php +++ b/question/type/ordering/lang/en/qtype_ordering.php @@ -20,6 +20,9 @@ $string['answer'] = 'Item text'; $string['answerheader'] = 'Draggable item {no}'; $string['correctorder'] = 'The correct order for these items is as follows:'; $string['defaultquestionname'] = 'Drag the following items into the correct order.'; +$string['horizontal'] = 'Horizontal'; +$string['layouttype_help'] = 'Choose whether to display the items vertically or horizontally.'; +$string['layouttype'] = 'Layout of items'; $string['noresponsedetails'] = 'Sorry, no details of the response to this question are available.'; $string['notenoughanswers'] = 'Ordering questions must have more than {$a} answers.'; $string['selectall'] = 'Select all items'; @@ -29,6 +32,7 @@ $string['selectcount'] = 'Size of subset'; $string['selectrandom'] = 'Select a random subset of items'; $string['selecttype_help'] = 'Choose whether to display all the items or a subset of the items.'; $string['selecttype'] = 'Item selection type'; +$string['vertical'] = 'Vertical'; // requred strings for Moodle 2.0 $string['ordering'] = 'Ordering'; diff --git a/question/type/ordering/question.php b/question/type/ordering/question.php index 8e76a6afd27..e8628223953 100644 --- a/question/type/ordering/question.php +++ b/question/type/ordering/question.php @@ -54,18 +54,18 @@ class qtype_ordering_question extends question_graded_automatically { public $currentresponse; public function start_attempt(question_attempt_step $step, $variant) { - $this->answers = $this->get_ordering_answers(); - $this->options = $this->get_ordering_options(); + $answers = $this->get_ordering_answers(); + $options = $this->get_ordering_options(); - $countanswers = count($this->answers); + $countanswers = count($answers); // sanitize "selecttype" - $selecttype = $this->options->selecttype; + $selecttype = $options->selecttype; $selecttype = max(0, $selecttype); $selecttype = min(2, $selecttype); // sanitize "selectcount" - $selectcount = $this->options->selectcount; + $selectcount = $options->selectcount; $selectcount = max(3, $selectcount); $selectcount = min($countanswers, $selectcount); @@ -78,15 +78,15 @@ class qtype_ordering_question extends question_graded_automatically { // extract answer ids switch ($selecttype) { case 0: // all - $answerids = array_keys($this->answers); + $answerids = array_keys($answers); break; case 1: // random subset - $answerids = array_rand($this->answers, $selectcount); + $answerids = array_rand($answers, $selectcount); break; case 2: // contiguous subset - $answerids = array_keys($this->answers); + $answerids = array_keys($answers); $offset = mt_rand(0, $countanswers - $selectcount); $answerids = array_slice($answerids, $offset, $selectcount, true); break; @@ -101,8 +101,8 @@ class qtype_ordering_question extends question_graded_automatically { } public function apply_attempt_state(question_attempt_step $step) { - $this->answers = $this->get_ordering_answers(); - $this->options = $this->get_ordering_options(); + $answers = $this->get_ordering_answers(); + $options = $this->get_ordering_options(); $this->currentresponse = array_filter(explode(',', $step->get_qt_var('_currentresponse'))); $this->correctresponse = array_filter(explode(',', $step->get_qt_var('_correctresponse'))); } @@ -198,6 +198,7 @@ class qtype_ordering_question extends question_graded_automatically { if (empty($this->options)) { $this->options = (object)array( 'questionid' => $this->id, + 'layouttype' => 0, // vertical 'selecttype' => 0, // all answers 'selectcount' => 0, 'correctfeedback' => '', @@ -232,4 +233,13 @@ class qtype_ordering_question extends question_graded_automatically { } return $this->answers; } + + public function get_ordering_layoutclass() { + $options = $this->get_ordering_options(); + switch ($options->layouttype) { + case 0: return 'vertical'; + case 1: return 'horizontal'; + default: return ''; // shouldn't happen !! + } + } } diff --git a/question/type/ordering/questiontype.php b/question/type/ordering/questiontype.php index 5ffe07e90de..693390d16fc 100644 --- a/question/type/ordering/questiontype.php +++ b/question/type/ordering/questiontype.php @@ -40,6 +40,9 @@ if (class_exists('question_type')) { */ class qtype_ordering extends question_type { + /** combined feedback fields */ + public $feedback_fields = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'); + /** * Utility method used by {@link qtype_renderer::head_code()} * It looks for any of the files script.js or script.php that @@ -136,16 +139,15 @@ class qtype_ordering extends question_type { // Insert all the new answers - foreach ($question->answer as $i => $text) { + foreach ($question->answer as $i => $answer) { $answer = (object)array( - 'question' => $question->id, - 'fraction' => ($i + 1), // start at 1 - 'answer' => $text, - 'answerformat' => FORMAT_MOODLE, // =0 - 'feedback' => '', - 'feedbackformat' => FORMAT_MOODLE, // =0 + 'question' => $question->id, + 'fraction' => ($i + 1), // start at 1 + 'answer' => (is_array($answer) ? $answer['text'] : $answer), + 'answerformat' => (is_array($answer) ? $answer['format'] : FORMAT_MOODLE), + 'feedback' => '', + 'feedbackformat' => FORMAT_MOODLE, ); - if ($answer->id = array_shift($answerids)) { if (! $DB->update_record('question_answers', $answer)) { $result->error = get_string('cannotupdaterecord', 'error', 'question_answers (id='.$answer->id.')'); @@ -163,6 +165,7 @@ class qtype_ordering extends question_type { // create $options for this ordering question $options = (object)array( 'questionid' => $question->id, + 'layouttype' => $question->layouttype, 'selecttype' => $question->selecttype, 'selectcount' => $question->selectcount ); @@ -196,10 +199,9 @@ class qtype_ordering extends question_type { $options = $this->initialise_combined_feedback($question, $questiondata, $shownumcorrect); } else { // Moodle 2.0 - $names = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'); - foreach ($names as $name) { - $format = $name.'format'; - $question->$name = $questiondata->options->$name; + foreach ($this->feedback_fields as $field) { + $format = $field.'format'; + $question->$field = $questiondata->options->$field; $question->$format = $questiondata->options->$format; } if ($shownumcorrect) { @@ -228,11 +230,10 @@ class qtype_ordering extends question_type { $options = $this->save_combined_feedback_helper($options, $question, $context, $shownumcorrect); } else { // Moodle 2.0 - $names = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'); - foreach ($names as $name) { - $text = $question->$name; - $format = $name.'format'; - $options->$name = $this->import_or_save_files($text, $context, 'qtype_ordering', $name, $question->id); + foreach ($this->feedback_fields as $field) { + $text = $question->$field; + $format = $field.'format'; + $options->$field = $this->import_or_save_files($text, $context, 'qtype_ordering', $field, $question->id); $options->$format = $text['format']; } if ($shownumcorrect) { @@ -243,6 +244,9 @@ class qtype_ordering extends question_type { } public function is_not_blank($value) { + if (is_array($value)) { + $value = $value['text']; + } $value = trim($value); return ($value || $value==='0'); } @@ -281,17 +285,17 @@ class qtype_ordering extends question_type { * @param string $extra (optional, default=null) * @todo Finish documenting this function */ - function import_from_gift($lines, $question, $format, $extra=null) { - + public function import_from_gift($lines, $question, $format, $extra=null) { // convert $lines to a single a string - for preg_match() $lines = implode(PHP_EOL, $lines); // extract question info from GIFT file $lines - $search = '/^([^{]*)\s*\{>\s*(\d+)\s*((?:ALL|EXACT|RANDOM|REL|CONTIGUOUS|CONTIG)?)\s*(.*?)\s*\}\s*$/s'; + $search = '/^([^{]*)\s*\{>\s*(\d+)\s*((?:ALL|EXACT|RANDOM|REL|CONTIGUOUS|CONTIG)?)\s*((?:HORIZONTAL|HORI|H|1|VERTICAL|VERT|V|0)?)\s*(.*?)\s*\}\s*$/s'; // $1 the question name // $2 the number of items to be shown // $3 the extraction type - // $4 the lines of items to be ordered + // $4 the layout type + // $5 the lines of items to be ordered if (empty($extra) || ! preg_match($search, $lines, $matches)) { return false; // format not recognized } @@ -299,7 +303,8 @@ class qtype_ordering extends question_type { $questionname = trim($matches[1]); $selectcount = trim($matches[2]); $selecttype = trim($matches[3]); - $lines = explode(PHP_EOL, $matches[4]); + $layouttype = trim($matches[4]); + $lines = explode(PHP_EOL, $matches[5]); unset($matches); $question->qtype = 'ordering'; @@ -314,7 +319,7 @@ class qtype_ordering extends question_type { } else { $selectcount = min(6, count($lines)); } - $this->set_count_and_type($question, $selectcount, $selecttype); + $this->set_layout_count_type($question, $layouttype, $selectcount, $selecttype); // remove blank items $lines = array_map('trim', $lines); @@ -339,16 +344,40 @@ class qtype_ordering extends question_type { $question->feedbackformat[$i] = FORMAT_MOODLE; // =0 } + // check that the required feedback fields exist + $this->check_ordering_combined_feedback($question); + return $question; } /** - * extract_count_and_type + * check_ordering_combined_feedback * - * @param stdClass $question + * @param stdClass $question (passed by reference) * @todo Finish documenting this function */ - function extract_count_and_type($question) { + protected function check_ordering_combined_feedback(&$question) { + foreach ($this->feedback_fields as $field) { + if (empty($question->$field)) { + $question->$field = array('text' => '', 'format' => 0, 'itemid' => 0, 'files' => null); + } + } + } + + /** + * extract_layout_count_type + * + * @param stdClass $question + * @todo Finish documenting this function + */ + public function extract_layout_count_type($question) { + + switch ($question->options->layouttype) { + case 0: $layout = 'VERTICAL'; break; + case 1: $layout = 'HORIZONTAL'; break; + default: $layout = ''; // shouldn't happen !! + } + switch ($question->options->selecttype) { case 0: $type = 'ALL'; break; // all items case 1: $type = 'RANDOM'; break; // random subset @@ -359,7 +388,7 @@ class qtype_ordering extends question_type { // Note: this used to be (selectcount + 2) $count = $question->options->selectcount; - return array($count, $type); + return array($layout, $count, $type); } /** @@ -370,16 +399,16 @@ class qtype_ordering extends question_type { * @param string $extra (optional, default=null) * @todo Finish documenting this function */ - function export_to_gift($question, $format, $extra=null) { - list($count, $type) = $this->extract_count_and_type($question); - - $expout = $question->questiontext.'{>'.$count.' '.$type.' '."\n"; + public function export_to_gift($question, $format, $extra=null) { + list($layouttype, $selectcount, $selecttype) = $this->extract_layout_count_type($question); + $output = $question->questiontext.'{>'.$selectcount.' '. + $selecttype.' '. + $layouttype."\n"; foreach ($question->options->answers as $answer) { - $expout .= $answer->answer."\n"; + $output .= $answer->answer."\n"; } - $expout .= '}'; - - return $expout; + $output .= '}'; + return $output; } /** @@ -390,13 +419,14 @@ class qtype_ordering extends question_type { * @param string $extra (optional, default=null) * @todo Finish documenting this function */ - function export_to_xml($question, qformat_xml $format, $extra=null) { + public function export_to_xml($question, qformat_xml $format, $extra=null) { - list($count, $type) = $this->extract_count_and_type($question); + list($layouttype, $selectcount, $selecttype) = $this->extract_layout_count_type($question); $output = ''; - $output .= " $type\n"; - $output .= " $count\n"; + $output .= " $layouttype\n"; + $output .= " $selecttype\n"; + $output .= " $selectcount\n"; foreach($question->options->answers as $answer) { $output .= ' format($answer->answerformat).">\n"; @@ -446,9 +476,10 @@ class qtype_ordering extends question_type { $selecttype = 'logical'; $selectcount = 'studentsee'; } + $layouttype = $format->getpath($data, array('#', 'layouttype', 0, '#'), 'VERTICAL'); $selecttype = $format->getpath($data, array('#', $selecttype, 0, '#'), 'RANDOM'); $selectcount = $format->getpath($data, array('#', $selectcount, 0, '#'), 6); - $this->set_count_and_type($newquestion, $selectcount, $selecttype); + $this->set_layout_count_type($newquestion, $layouttype, $selectcount, $selecttype); $newquestion->answer = array(); $newquestion->answerformat = array(); @@ -470,6 +501,9 @@ class qtype_ordering extends question_type { $i++; } + // check that the required feedback fields exist + $this->check_ordering_combined_feedback($newquestion); + return $newquestion; } @@ -499,18 +533,45 @@ class qtype_ordering extends question_type { } /* - * set_count_and_type + * set_layout_count_type * * @param object $question (passed by reference) + * @param integer $layout the layout type * @param integer $count the number of items to display * @param integer $type the extraction type * @param integer $default_type (optional, default=1) */ - function set_count_and_type(&$question, $count, $type, $default_type=1) { + public function set_layout_count_type(&$question, $layout, $count, $type) { + + $default_layout = 0; // horizontal + $default_type = 1; // random + $default_count = 3; + + switch (strtoupper($layout)) { + case 'HORIZONTAL': + case 'HORI': + case 'H': + case '1': + $question->layouttype = 1; + break; + case 'VERTICAL': + case 'VERT': + case 'V': + case '0': + $question->layouttype = 0; + break; + default: + $question->layouttype = $default_layout; + } + // set "selectcount" from $count // this used to be ($count - 2) - $question->selectcount = $count; + if (is_numeric($count)) { + $question->selectcount = intval($count); + } else { + $question->selectcount = $default_count; + } // set "selecttype" from $type switch ($type) { diff --git a/question/type/ordering/renderer.php b/question/type/ordering/renderer.php index 400f1675f95..0a2ac880d52 100644 --- a/question/type/ordering/renderer.php +++ b/question/type/ordering/renderer.php @@ -53,9 +53,16 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { // response_id : id_q27_1_response_319 // sortable_id : id_sortable_q27_1_response_319 $response_fieldname = $question->get_response_fieldname(); - $response_name = $qa->get_qt_field_name($response_fieldname); - $response_id = 'id_'.preg_replace('/[^a-zA-Z0-9]+/', '_', $response_name); - $sortable_id = 'id_sortable_'.$question->id; + $response_name = $qa->get_qt_field_name($response_fieldname); + $response_id = 'id_'.preg_replace('/[^a-zA-Z0-9]+/', '_', $response_name); + $sortable_id = 'id_sortable_'.$question->id; + $ablock_id = 'id_ablock_'.$question->id; + + switch ($question->options->layouttype) { + case 0 : $axis = 'y'; break; // vertical + case 1 : $axis = ''; break; // horizontal + default: $axis = ''; // unknown + } $result = ''; @@ -67,11 +74,13 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { $script .= "if (window.$) {\n"; // $ is an alias for jQuery $script .= " $(function() {\n"; $script .= " $('#$sortable_id').sortable({\n"; + $script .= " axis: '$axis',\n"; + $script .= " containment: '#$ablock_id',\n"; + $script .= " opacity: 0.6,\n"; $script .= " update: function(event, ui) {\n"; $script .= " var ItemsOrder = $(this).sortable('toArray').toString();\n"; $script .= " $('#$response_id').attr('value', ItemsOrder);\n"; - $script .= " },\n"; - $script .= " opacity: 0.6\n"; + $script .= " }\n"; $script .= " });\n"; $script .= " $('#$sortable_id').disableSelection();\n"; $script .= " });\n"; @@ -89,6 +98,9 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { $printeditems = false; if (count($currentresponse)) { + // set layout class + $layoutclass = $question->get_ordering_layoutclass(); + // generate ordering items foreach ($currentresponse as $position => $answerid) { if (! array_key_exists($answerid, $question->answers)) { @@ -100,8 +112,8 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { if ($printeditems==false) { $printeditems = true; - $result .= html_writer::start_tag('div', array('class' => 'ablock')); - $result .= html_writer::start_tag('div', array('class' => 'answer')); + $result .= html_writer::start_tag('div', array('class' => 'ablock', 'id' => $ablock_id)); + $result .= html_writer::start_tag('div', array('class' => 'answer ordering')); $result .= html_writer::start_tag('ul', array('class' => 'sortablelist', 'id' => $sortable_id)); } @@ -118,6 +130,8 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { $class = 'sortableitem'; $img = ''; } + $class = "$class $layoutclass"; + // the original "id" revealed the correct order of the answers // because $answer->fraction holds the correct order number // $id = 'ordering_item_'.$answerid.'_'.intval($question->answers[$answerid]->fraction); @@ -136,7 +150,8 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { 'name' => $response_name, 'id' => $response_id, 'value' => '')); - $result .= html_writer::tag('div', '', array('style' => 'clear:both;')); + // the following DIV is not necessary if we use "overflow: auto;" on the "answer" DIV + //$result .= html_writer::tag('div', '', array('style' => 'clear:both;')); } return $result; @@ -165,12 +180,13 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { } } if ($showcorrect) { + $layoutclass = $question->get_ordering_layoutclass(); $output .= html_writer::tag('p', get_string('correctorder', 'qtype_ordering')); - $output .= html_writer::start_tag('ol'); + $output .= html_writer::start_tag('ol', array('class' => 'correctorder')); $correctresponse = $question->correctresponse; foreach ($correctresponse as $position => $answerid) { $answer = $question->answers[$answerid]; - $output .= html_writer::tag('li', $answer->answer); + $output .= html_writer::tag('li', $answer->answer, array('class' => $layoutclass)); } $output .= html_writer::end_tag('ol'); } diff --git a/question/type/ordering/styles.css b/question/type/ordering/styles.css index 6b2ce54c323..e2631d5e6e5 100644 --- a/question/type/ordering/styles.css +++ b/question/type/ordering/styles.css @@ -1,3 +1,6 @@ +/* ensure container covers the draggable items */ +.que.ordering div.answer.ordering { overflow: auto; } + .que.ordering ul.sortablelist { border : 1px solid #ccc; float : left; @@ -9,23 +12,37 @@ padding : 4px 4px 0 4px; width : 80%; } +.que.ordering ul.sortablelist, +.que.ordering ul.sortablelist li { + -webkit-border-radius: 6px; /* Safari and Chrome */ + -moz-border-radius: 6px; /* Firefox */ + -o-border-radius: 6px; /* Opera */ + border-radius: 6px; /* CSS3 */ +} .que.ordering ul.sortablelist li { background-color : #eeeeee; border : 1px solid #cccccc; border-image : initial; list-style-type : none; - margin-bottom : 1px; - min-height : 20px; - padding : 8px 2px; + margin : 4px; + padding : 6px 12px; } .que.ordering ul.sortablelist li.sortableitem { position : relative; cursor : move; } +.que.ordering ul.sortablelist li.horizontal { + float : left; +} +.que.ordering ul.sortablelist li.vertical { + min-height : 18px; +} .que.ordering ul.sortablelist li.correctposition { + background-color : #dff0d8; /* light green */ border : 4px solid #99ff66; /* gentle green */ } .que.ordering ul.sortablelist li.wrongposition { + background-color : #f2dede; /* light red */ border : 4px solid #ff7373; /* gentle red */ } .que.ordering ul.sortablelist li.correctposition, @@ -33,3 +50,18 @@ margin-bottom : 4px; margin-top : 4px; } + +.que.ordering div.rightanswer ol.correctorder { + overflow: auto; /* cover the floating LI elements */ +} +.que.ordering div.rightanswer ol.correctorder li.horizontal { + float : left; + margin-left : 24px; + margin-right : 24px; +} +.que.ordering div.rightanswer ol.correctorder li.vertical { +} + +/* the width restriction can be limited to editors for draggable items + by inserting "fieldset:nth-child(n+4)" before "div.feditor" */ +#page-question-type-ordering form.mform fieldset:nth-child(n+4) div.feditor { max-width: 480px; } diff --git a/question/type/ordering/version.php b/question/type/ordering/version.php index e3a87558bcf..0019ab305f9 100644 --- a/question/type/ordering/version.php +++ b/question/type/ordering/version.php @@ -30,6 +30,6 @@ defined('MOODLE_INTERNAL') || die(); $plugin->cron = 0; $plugin->component = 'qtype_ordering'; $plugin->maturity = MATURITY_STABLE; // ALPHA=50, BETA=100, RC=150, STABLE=200 -$plugin->release = '2015-07-31 (24)'; -$plugin->version = 2015073124; +$plugin->release = '2015-11-15 (30)'; +$plugin->version = 2015111530; $plugin->requires = 2010112400; // Moodle 2.0