Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Drag-and-drop words into sentences question renderer class.
  19   *
  20   * @package   qtype_ddwtos
  21   * @copyright 2010 The Open University
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  require_once($CFG->dirroot . '/question/type/gapselect/rendererbase.php');
  29  
  30  
  31  /**
  32   * Generates the output for drag-and-drop words into sentences questions.
  33   *
  34   * @copyright  2010 The Open University
  35   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class qtype_ddwtos_renderer extends qtype_elements_embedded_in_question_text_renderer {
  38  
  39      public function formulation_and_controls(question_attempt $qa,
  40              question_display_options $options) {
  41  
  42          $result = parent::formulation_and_controls($qa, $options);
  43  
  44          $this->page->requires->js_call_amd('qtype_ddwtos/ddwtos', 'init',
  45                  [$qa->get_outer_question_div_unique_id(), $options->readonly]);
  46          return $result;
  47      }
  48  
  49      protected function post_qtext_elements(question_attempt $qa,
  50              question_display_options $options) {
  51          $result = '';
  52          $question = $qa->get_question();
  53  
  54          $dragboxs = '';
  55          foreach ($question->choices as $group => $choices) {
  56              $dragboxs .= $this->drag_boxes($qa, $group,
  57                      $question->get_ordered_choices($group), $options);
  58          }
  59  
  60          $classes = array('answercontainer');
  61          if ($options->readonly) {
  62              $classes[] = 'readonly';
  63          }
  64          $result .= html_writer::tag('div', $dragboxs, array('class' => implode(' ', $classes)));
  65  
  66          // We abuse the clear_wrong method to output the hidden form fields we
  67          // want irrespective of whether we are actually clearing the wrong
  68          // bits of the response.
  69          if (!$options->clearwrong) {
  70              $result .= $this->clear_wrong($qa, false);
  71          }
  72          return $result;
  73      }
  74  
  75      protected function embedded_element(question_attempt $qa, $place,
  76              question_display_options $options) {
  77          $question = $qa->get_question();
  78          $group = $question->places[$place];
  79          $label = $options->add_question_identifier_to_label(get_string('blanknumber', 'qtype_ddwtos', $place));
  80          $boxcontents = '&#160;' . html_writer::tag('span', $label, array('class' => 'accesshide'));
  81  
  82          $value = $qa->get_last_qt_var($question->field($place));
  83  
  84          $attributes = array(
  85              'class' => 'place' . $place . ' drop active group' . $group
  86          );
  87  
  88          if ($options->readonly) {
  89              $attributes['class'] .= ' readonly';
  90          } else {
  91              $attributes['tabindex'] = '0';
  92          }
  93  
  94          $feedbackimage = '';
  95          if ($options->correctness) {
  96              $response = $qa->get_last_qt_data();
  97              $fieldname = $question->field($place);
  98              if (array_key_exists($fieldname, $response)) {
  99                  $fraction = (int) ($response[$fieldname] ==
 100                          $question->get_right_choice_for($place));
 101                  $feedbackimage = $this->feedback_image($fraction);
 102              }
 103          }
 104  
 105          return html_writer::tag('span', $boxcontents, $attributes) . ' ' . $feedbackimage;
 106      }
 107  
 108      protected function drag_boxes($qa, $group, $choices, question_display_options $options) {
 109          $boxes = '';
 110          foreach ($choices as $key => $choice) {
 111              // Bug 8632: long text entry causes bug in drag and drop field in IE.
 112              $content = str_replace('-', '&#x2011;', $choice->text);
 113              $content = str_replace(' ', '&#160;', $content);
 114  
 115              $infinite = '';
 116              if ($choice->infinite) {
 117                  $infinite = ' infinite';
 118              }
 119  
 120              $boxes .= html_writer::tag('span', $content, [
 121                      'class' => 'draghome user-select-none choice' . $key . ' group' .
 122                              $choice->draggroup . $infinite]) . ' ';
 123          }
 124  
 125          return html_writer::nonempty_tag('div', $boxes,
 126              ['class' => 'user-select-none draggrouphomes' . $choice->draggroup]);
 127      }
 128  
 129      /**
 130       * Actually, this question type abuses this method to always output the
 131       * hidden fields it needs.
 132       *
 133       * @param question_attempt $qa the question attempt.
 134       * @param bool $reallyclear whether we are really clearing the responses, or just outputting them.
 135       * @return string HTML to output.
 136       */
 137      public function clear_wrong(question_attempt $qa, $reallyclear = true) {
 138          $question = $qa->get_question();
 139          $response = $qa->get_last_qt_data();
 140  
 141          if (!empty($response) && $reallyclear) {
 142              $cleanresponse = $question->clear_wrong_from_response($response);
 143          } else {
 144              $cleanresponse = $response;
 145          }
 146  
 147          $output = '';
 148          foreach ($question->places as $place => $group) {
 149              $fieldname = $question->field($place);
 150              if (array_key_exists($fieldname, $response)) {
 151                  $value = (string) $response[$fieldname];
 152              } else {
 153                  $value = '0';
 154              }
 155              if (array_key_exists($fieldname, $cleanresponse)) {
 156                  $cleanvalue = (string) $cleanresponse[$fieldname];
 157              } else {
 158                  $cleanvalue = '0';
 159              }
 160              if ($cleanvalue === $value) {
 161                  // Normal case: just one hidden input, to store the
 162                  // current value and be the value submitted.
 163                  $output .= html_writer::empty_tag('input', array(
 164                          'type' => 'hidden',
 165                          'id' => $this->box_id($qa, 'p' . $place),
 166                          'class' => 'placeinput place' . $place . ' group' . $group,
 167                          'name' => $qa->get_qt_field_name($fieldname),
 168                          'value' => s($value)));
 169              } else {
 170                  // The case, which only happens when the question is read-only, where
 171                  // we want to show the drag item in a given place (first hidden input),
 172                  // but when submitted, we want it to go to a different place (second input).
 173                  $output .= html_writer::empty_tag('input', array(
 174                          'type' => 'hidden',
 175                          'id' => $this->box_id($qa, 'p' . $place),
 176                          'class' => 'placeinput place' . $place . ' group' . $group,
 177                          'value' => s($value))) .
 178                          html_writer::empty_tag('input', array(
 179                          'type' => 'hidden',
 180                          'name' => $qa->get_qt_field_name($fieldname),
 181                          'value' => s($cleanvalue)));
 182              }
 183          }
 184          return $output;
 185      }
 186  
 187  }