mirror of
https://github.com/moodle/moodle.git
synced 2025-03-19 23:20:09 +01:00
MDL-79863 qtype_ordering: qtype/ordering allow full HTML editors on answers in order to allow images and pictures
This commit is contained in:
parent
072c95122b
commit
b71ca209ce
@ -36,14 +36,14 @@ defined('MOODLE_INTERNAL') || die();
|
||||
*/
|
||||
class qtype_ordering_edit_form extends question_edit_form {
|
||||
|
||||
const NUM_ANS_ROWS = 2;
|
||||
const NUM_ANS_ROWS = 2;
|
||||
const NUM_ANS_COLS = 60;
|
||||
const NUM_ANS_START = 6;
|
||||
const NUM_ANS_ADD = 2;
|
||||
const NUM_ANS_START = 6;
|
||||
const NUM_ANS_ADD = 3;
|
||||
|
||||
// this functionality is currently disabled
|
||||
// because it is not fully functional
|
||||
protected $use_editor_for_answers = false;
|
||||
protected $use_editor_for_answers = true;
|
||||
|
||||
/**
|
||||
* unique name for this question type
|
||||
@ -112,6 +112,8 @@ class qtype_ordering_edit_form extends question_edit_form {
|
||||
$label = get_string($name, $plugin);
|
||||
if ($this->use_editor_for_answers) {
|
||||
$elements[] = $mform->createElement('editor', $name, $label, $this->get_editor_attributes(), $this->get_editor_options());
|
||||
$elements[] = $mform->createElement('submit', $name.'removeeditor', get_string('removeeditor', $plugin));
|
||||
//$elements[] = $mform->createElement('submit', $name.'removeitem', get_string('removeitem', $plugin));
|
||||
} else {
|
||||
$elements[] = $mform->createElement('textarea', $name, $label, array('rows' => self::NUM_ANS_ROWS, 'cols' => self::NUM_ANS_COLS));
|
||||
}
|
||||
@ -128,6 +130,9 @@ class qtype_ordering_edit_form extends question_edit_form {
|
||||
$buttontext = get_string('addmoreanswers', $plugin, self::NUM_ANS_ADD);
|
||||
$this->repeat_elements($elements, $start, $options, 'countanswers', 'addanswers', self::NUM_ANS_ADD, $buttontext);
|
||||
|
||||
// adjust HTML editor and removal buttons
|
||||
$this->adjust_html_editors($mform, $name);
|
||||
|
||||
// feedback
|
||||
$this->add_ordering_feedback_fields(true);
|
||||
|
||||
@ -156,6 +161,66 @@ class qtype_ordering_edit_form extends question_edit_form {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* adjust_html_editors
|
||||
*/
|
||||
protected function adjust_html_editors($mform, $name) {
|
||||
|
||||
// check whether or not we are using editors
|
||||
if (! $this->use_editor_for_answers) {
|
||||
return;
|
||||
}
|
||||
|
||||
// cache the number of supported formats
|
||||
// for the preferred editor for each format
|
||||
$count = array();
|
||||
|
||||
$ids = array_keys($this->question->options->answers);
|
||||
foreach ($ids as $i => $id) {
|
||||
|
||||
$editor = $name.'['.$i.']';
|
||||
if (! $mform->elementExists($editor)) {
|
||||
continue;
|
||||
}
|
||||
$editor = $mform->getElement($editor);
|
||||
|
||||
// the old/new name of the button to remove the HTML editor
|
||||
// old : the name of the button when added by repeat_elements
|
||||
// new : the simplified name of the button to satisfy
|
||||
// "no_submit_button_pressed()" in lib/formslib.php
|
||||
$oldname = $name.'removeeditor['.$i.']';
|
||||
$newname = $name.'removeeditor_'.$i;
|
||||
|
||||
// remove HTML editor, if necessary
|
||||
if (optional_param($newname, 0, PARAM_RAW)) {
|
||||
$value = $editor->getValue();
|
||||
$value['format'] = FORMAT_MOODLE;
|
||||
$value = $editor->setValue($value);
|
||||
$format = $editor->getFormat();
|
||||
// override incoming format value
|
||||
$_POST['answer'][$i]['format'] = $format;
|
||||
} else {
|
||||
$format = $this->question->options->answers[$id]->answerformat;
|
||||
}
|
||||
|
||||
// check we have a submit button - it should always be there !!
|
||||
if ($mform->elementExists($oldname)) {
|
||||
if (! isset($count[$format])) {
|
||||
$editor = editors_get_preferred_editor($format);
|
||||
$count[$format] = $editor->get_supported_formats();
|
||||
$count[$format] = count($count[$format]);
|
||||
}
|
||||
if ($count[$format] > 1) {
|
||||
$mform->removeElement($oldname);
|
||||
} else {
|
||||
$submit = $mform->getElement($oldname);
|
||||
$submit->setName($newname);
|
||||
}
|
||||
$mform->registerNoSubmitButton($newname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* data_preprocessing
|
||||
*/
|
||||
@ -174,20 +239,14 @@ class qtype_ordering_edit_form extends question_edit_form {
|
||||
if (isset($question->options->answers)) {
|
||||
|
||||
$i = 0;
|
||||
foreach ($question->options->answers as $answer) {
|
||||
foreach ($question->options->answers as $answerid => $answer) {
|
||||
|
||||
if (trim($answer->answer)=='') {
|
||||
continue; // skip empty answers
|
||||
}
|
||||
|
||||
if ($this->use_editor_for_answers) {
|
||||
$draftid = file_get_submitted_draft_itemid("answer[$i]");
|
||||
|
||||
if (isset($answer->id)) {
|
||||
$itemid = $answer->id;
|
||||
} else {
|
||||
$itemid = null;
|
||||
}
|
||||
$itemid = file_get_submitted_draft_itemid("answer[$i]");
|
||||
|
||||
if (isset($answer->answer)) {
|
||||
$text = $answer->answer;
|
||||
@ -201,12 +260,12 @@ class qtype_ordering_edit_form extends question_edit_form {
|
||||
$format = FORMAT_MOODLE;
|
||||
}
|
||||
|
||||
$text = file_prepare_draft_area($draftid, $this->context->id, 'qtype_ordering',
|
||||
'answer', $itemid, $this->editoroptions, $text);
|
||||
$text = file_prepare_draft_area($itemid, $this->context->id, 'question', 'answer',
|
||||
$answerid, $this->editoroptions, $text);
|
||||
|
||||
$question->answer[$i] = array('text' => $text,
|
||||
'format' => $format,
|
||||
'itemid' => $draftid);
|
||||
'itemid' => $itemid);
|
||||
} else {
|
||||
$question->answer[$i]= $answer->answer;
|
||||
}
|
||||
@ -246,7 +305,7 @@ class qtype_ordering_edit_form extends question_edit_form {
|
||||
|
||||
$answercount = 0;
|
||||
foreach ($data['answer'] as $answer){
|
||||
if ($this->use_editor_for_answers) {
|
||||
if (is_array($answer)) {
|
||||
$answer = $answer['text'];
|
||||
}
|
||||
if (trim($answer)=='') {
|
||||
|
@ -25,6 +25,8 @@ $string['layouttype_help'] = 'Choose whether to display the items vertically or
|
||||
$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['removeeditor'] = 'Remove HTML editor';
|
||||
$string['removeitem'] = 'Remove draggable item';
|
||||
$string['selectall'] = 'Select all items';
|
||||
$string['selectcontiguous'] = 'Select a contiguous subset of items';
|
||||
$string['selectcount_help'] = 'The number of items that will be displayed when the question is appears in a quiz.';
|
||||
|
@ -167,6 +167,24 @@ class qtype_ordering_question extends question_graded_automatically {
|
||||
return array($fraction, question_state::graded_state_for_fraction($fraction));
|
||||
}
|
||||
|
||||
public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) {
|
||||
if ($component=='question') {
|
||||
if ($filearea=='answer') {
|
||||
$answerid = reset($args); // "itemid" is answer id
|
||||
return array_key_exists($answerid, $this->answers);
|
||||
|
||||
}
|
||||
if (in_array($filearea, $this->qtype->feedback_fields)) {
|
||||
return $this->check_combined_feedback_file_access($qa, $options, $filearea);
|
||||
|
||||
}
|
||||
if ($filearea=='hint') {
|
||||
return $this->check_hint_file_access($qa, $options, $args);
|
||||
}
|
||||
}
|
||||
return parent::check_file_access($qa, $options, $component, $filearea, $args, $forcedownload);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// custom methods
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -115,6 +115,7 @@ class qtype_ordering extends question_type {
|
||||
|
||||
$result = new stdClass();
|
||||
$context = $question->context;
|
||||
//$context = $this->get_context_by_category_id($question->category);
|
||||
|
||||
// remove empty answers
|
||||
$question->answer = array_filter($question->answer, array($this, 'is_not_blank'));
|
||||
@ -123,6 +124,14 @@ class qtype_ordering extends question_type {
|
||||
// count how many answers we have
|
||||
$countanswers = count($question->answer);
|
||||
|
||||
// search/replace strings to reduce simple <p>...</p> to plain text
|
||||
$p_search = '/^\s*<p>\s*(.*?)(\s*<br\s*\/?>)*\s*<\/p>\s*$/';
|
||||
$p_replace = '$1';
|
||||
|
||||
// search/replace strings to standardize vertical align of <img> tags
|
||||
$img_search = '/(<img[^>]*)\bvertical-align:\s*[a-zA-Z0-9_-]+([^>]*>)/';
|
||||
$img_replace = '$1'.'vertical-align:text-top'.'$2';
|
||||
|
||||
// check at least two answers exist
|
||||
if ($countanswers < 2) {
|
||||
$result->notice = get_string('notenoughanswers', 'qtype_ordering', '2');
|
||||
@ -138,16 +147,40 @@ class qtype_ordering extends question_type {
|
||||
}
|
||||
|
||||
// Insert all the new answers
|
||||
|
||||
foreach ($question->answer as $i => $answer) {
|
||||
|
||||
// extract $answer fields
|
||||
if (is_array($answer)) {
|
||||
// editor
|
||||
$answertext = $answer['text'];
|
||||
$answerformat = $answer['format'];
|
||||
$answeritemid = $answer['itemid'];
|
||||
} else {
|
||||
// textarea
|
||||
$answertext = $answer;
|
||||
$answerformat = FORMAT_MOODLE;
|
||||
$answeritemid = 0; // i.e. no editor
|
||||
}
|
||||
|
||||
// reduce simple <p>...</p> to plain text
|
||||
if (substr_count($answertext, '<p>')==1) {
|
||||
$answertext = preg_replace($p_search, $p_replace, $answertext);
|
||||
}
|
||||
|
||||
// standardize vertical align of img tags
|
||||
$answertext = preg_replace($img_search, $img_replace, $answertext);
|
||||
|
||||
// prepare the $answer object
|
||||
$answer = (object)array(
|
||||
'question' => $question->id,
|
||||
'fraction' => ($i + 1), // start at 1
|
||||
'answer' => (is_array($answer) ? $answer['text'] : $answer),
|
||||
'answerformat' => (is_array($answer) ? $answer['format'] : FORMAT_MOODLE),
|
||||
'answer' => $answertext,
|
||||
'answerformat' => $answerformat,
|
||||
'feedback' => '',
|
||||
'feedbackformat' => FORMAT_MOODLE,
|
||||
);
|
||||
|
||||
// add/insert $answer into the database
|
||||
if ($answer->id = array_shift($answerids)) {
|
||||
if (! $DB->update_record('question_answers', $answer)) {
|
||||
$result->error = get_string('cannotupdaterecord', 'error', 'question_answers (id='.$answer->id.')');
|
||||
@ -160,6 +193,14 @@ class qtype_ordering extends question_type {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
// copy files across from draft files area
|
||||
// Note: we must do this AFTER inserting the answer record
|
||||
// because the answer id is used as the file's "itemid"
|
||||
if ($answeritemid) {
|
||||
$answertext = file_save_draft_area_files($answeritemid, $context->id, 'question', 'answer', $answer->id, $this->fileoptions, $answertext);
|
||||
$DB->set_field('question_answers', 'answer', $answertext, array('id' => $answer->id));
|
||||
}
|
||||
}
|
||||
|
||||
// create $options for this ordering question
|
||||
@ -187,7 +228,11 @@ class qtype_ordering extends question_type {
|
||||
|
||||
// delete old answer records, if any
|
||||
if (count($answerids)) {
|
||||
$DB->delete_records_list('question_answers', 'id', $answerids);
|
||||
$fs = get_file_storage();
|
||||
foreach ($answerids as $answerid) {
|
||||
$fs->delete_area_files($context->id, 'question', 'answer', $answerid);
|
||||
$DB->delete_records('question_answers', array('id' => $answerid));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -136,6 +136,7 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer {
|
||||
// because $answer->fraction holds the correct order number
|
||||
// $id = 'ordering_item_'.$answerid.'_'.intval($question->answers[$answerid]->fraction);
|
||||
$answer = $question->answers[$answerid];
|
||||
$answer->answer = $question->format_text($answer->answer, $answer->answerformat, $qa, 'question', 'answer', $answerid);
|
||||
$params = array('class' => $class, 'id' => $answer->md5key);
|
||||
$result .= html_writer::tag('li', $img.$answer->answer, $params);
|
||||
}
|
||||
|
@ -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-11-15 (30)';
|
||||
$plugin->version = 2015111530;
|
||||
$plugin->release = '2015-11-18 (31)';
|
||||
$plugin->version = 2015111831;
|
||||
$plugin->requires = 2010112400; // Moodle 2.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user