Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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

   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 markers question renderer class.
  19   *
  20   * @package   qtype_ddmarker
  21   * @copyright 2012 The Open University
  22   * @author    Jamie Pratt <me@jamiep.org>
  23   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  require_once($CFG->dirroot . '/question/type/rendererbase.php');
  30  require_once($CFG->dirroot . '/question/type/ddimageortext/rendererbase.php');
  31  
  32  
  33  /**
  34   * Generates the output for drag-and-drop markers questions.
  35   *
  36   * @copyright  2010 The Open University
  37   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class qtype_ddmarker_renderer extends qtype_ddtoimage_renderer_base {
  40      public function formulation_and_controls(question_attempt $qa,
  41              question_display_options $options) {
  42  
  43          $question = $qa->get_question();
  44          $response = $qa->get_last_qt_data();
  45          $componentname = $question->qtype->plugin_name();
  46  
  47          $questiontext = $question->format_questiontext($qa);
  48  
  49          $dropareaclass = 'droparea';
  50          $draghomesclass = 'draghomes';
  51          if ($options->readonly) {
  52              $dropareaclass .= ' readonly';
  53              $draghomesclass .= ' readonly';
  54          }
  55  
  56          $output = html_writer::div($questiontext, 'qtext');
  57  
  58          $output .= html_writer::start_div('ddarea');
  59          $output .= html_writer::start_div($dropareaclass);
  60          $output .= html_writer::img(self::get_url_for_image($qa, 'bgimage'), get_string('dropbackground', 'qtype_ddmarker'),
  61                  ['class' => 'dropbackground img-fluid w-100']);
  62  
  63          $output .= html_writer::div('', 'dropzones');
  64          $output .= html_writer::div('', 'markertexts');
  65  
  66          $output .= html_writer::end_div();
  67          $output .= html_writer::start_div($draghomesclass);
  68  
  69          $orderedgroup = $question->get_ordered_choices(1);
  70          $hiddenfields = '';
  71          foreach ($orderedgroup as $choiceno => $drag) {
  72              $classes = ['marker', 'user-select-none', 'choice' . $choiceno];
  73              $attr = [];
  74              if ($drag->infinite) {
  75                  $classes[] = 'infinite';
  76              } else {
  77                  $classes[] = 'dragno' . $drag->noofdrags;
  78              }
  79              if (!$options->readonly) {
  80                  $attr['tabindex'] = 0;
  81              }
  82              $dragoutput = html_writer::start_span(join(' ', $classes), $attr);
  83              $targeticonhtml = $this->output->image_icon('crosshairs', '', $componentname, ['class' => 'target']);
  84              $markertext = html_writer::span($drag->text, 'markertext');
  85              $dragoutput .= $targeticonhtml . $markertext;
  86              $dragoutput .= html_writer::end_span();
  87              $output .= $dragoutput;
  88              $hiddenfields .= $this->hidden_field_choice($qa, $choiceno, $drag->infinite, $drag->noofdrags);
  89          }
  90  
  91          $output .= html_writer::end_div();
  92          $output .= html_writer::end_div();
  93  
  94          if ($question->showmisplaced && $qa->get_state()->is_finished()) {
  95              $visibledropzones = $question->get_drop_zones_without_hit($response);
  96          } else {
  97              $visibledropzones = [];
  98          }
  99  
 100          if ($qa->get_state() == question_state::$invalid) {
 101              $output .= html_writer::div($question->get_validation_error($qa->get_last_qt_data()), 'validationerror');
 102          }
 103  
 104          if ($question->showmisplaced && $qa->get_state()->is_finished()) {
 105              $wrongparts = $question->get_drop_zones_without_hit($response);
 106              if (count($wrongparts) !== 0) {
 107                  $wrongpartsstringspans = [];
 108                  foreach ($wrongparts as $wrongpart) {
 109                      $wrongpartsstringspans[] = html_writer::span($wrongpart->markertext, 'wrongpart');
 110                  }
 111                  $wrongpartsstring = join(', ', $wrongpartsstringspans);
 112                  $output .= html_writer::span(get_string('followingarewrongandhighlighted', 'qtype_ddmarker', $wrongpartsstring),
 113                          'wrongparts');
 114              }
 115          }
 116  
 117          $output .= html_writer::div($hiddenfields, 'ddform');
 118  
 119          $this->page->requires->js_call_amd('qtype_ddmarker/question', 'init',
 120                  [$qa->get_outer_question_div_unique_id(), $options->readonly, $visibledropzones]);
 121  
 122          return $output;
 123      }
 124  
 125      protected function hidden_field_choice(question_attempt $qa, $choiceno, $infinite, $noofdrags, $value = null) {
 126          $varname = 'c'.$choiceno;
 127          $classes = array('choices', 'choice'.$choiceno, 'noofdrags'.$noofdrags);
 128          if ($infinite) {
 129              $classes[] = 'infinite';
 130          }
 131          list(, $html) = $this->hidden_field_for_qt_var($qa, $varname, null, $classes);
 132          return $html;
 133      }
 134  
 135      protected function hint(question_attempt $qa, question_hint $hint) {
 136          $output = '';
 137          $question = $qa->get_question();
 138          $response = $qa->get_last_qt_data();
 139          if ($hint->statewhichincorrect) {
 140              $wrongdrags = $question->get_wrong_drags($response);
 141              $wrongparts = array();
 142              foreach ($wrongdrags as $wrongdrag) {
 143                  $wrongparts[] = html_writer::nonempty_tag('span',
 144                                                  $wrongdrag, array('class' => 'wrongpart'));
 145              }
 146              $output .= html_writer::nonempty_tag('div',
 147                      get_string('followingarewrong', 'qtype_ddmarker', join(', ', $wrongparts)),
 148                      array('class' => 'wrongparts'));
 149          }
 150          $output .= parent::hint($qa, $hint);
 151          return $output;
 152      }
 153  }