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.
   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   * Test page for dropdown dialog output component.
  19   *
  20   * @copyright 2023 Ferran Recio <ferran@moodle.com>
  21   * @package   core
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  require_once(__DIR__ . '/../../../../config.php');
  26  
  27  defined('BEHAT_SITE_RUNNING') || die();
  28  
  29  global $CFG, $PAGE, $OUTPUT;
  30  $PAGE->set_url('/lib/tests/behat/fixtures/dropdown_dialog_testpage.php');
  31  $PAGE->add_body_class('limitedwidth');
  32  require_login();
  33  $PAGE->set_context(core\context\system::instance());
  34  
  35  echo $OUTPUT->header();
  36  
  37  echo "<h2>Dropdown dialog test page</h2>";
  38  
  39  echo '<div id="regularscenario" class="mb-4">';
  40  echo "<h3>Basic example</h3>";
  41  $dialog = new core\output\local\dropdown\dialog('Open dialog', 'Dialog content');
  42  echo $OUTPUT->render($dialog);
  43  echo '</div>';
  44  
  45  echo '<div id="richcontent" class="mb-4">';
  46  echo "<h3>Rich content example</h3>";
  47  $content = '
  48      <p>Some rich content <b>element</b>.</p>
  49      <ul>
  50          <li>Item 1 <a href="#">Link 1</a></li>
  51          <li>Item 2 <a href="#">Link 2</a></li>
  52      </ul>
  53  ';
  54  $dialog = new core\output\local\dropdown\dialog('Open dialog', $content);
  55  echo $OUTPUT->render($dialog);
  56  echo '</div>';
  57  
  58  echo '<div id="richbutton" class="mb-4">';
  59  echo "<h3>Rich button example</h3>";
  60  $button = $OUTPUT->pix_icon('t/hide', 'Eye icon') . ' Click to <b>open</b></a>';
  61  $dialog = new core\output\local\dropdown\dialog($button, 'Dialog content');
  62  echo $OUTPUT->render($dialog);
  63  echo '</div>';
  64  
  65  echo '<div id="cssoverride" class="mb-4">';
  66  echo "<h3>CSS override example</h3>";
  67  $dialog = new core\output\local\dropdown\dialog(
  68      'Open dialog',
  69      'Dialog content',
  70      [
  71          'buttonclasses' => 'btn btn-primary extraclass',
  72      ]
  73  );
  74  echo $OUTPUT->render($dialog);
  75  echo '</div>';
  76  
  77  echo '<div id="extraattributes" class="mb-4">';
  78  echo "<h3>Extra data attributes example</h3>";
  79  $dialog = new core\output\local\dropdown\dialog('Open dialog', 'Dialog content', [
  80      'extras' => ['data-foo' => 'bar'],
  81  ]);
  82  echo $OUTPUT->render($dialog);
  83  echo '</div>';
  84  
  85  echo '<div id="customid" class="mb-4">';
  86  echo "<h3>Custom element id</h3>";
  87  $dialog = new core\output\local\dropdown\dialog('Open dialog', 'Dialog content', [
  88      'extras' => ['id' => 'CustomDropdownButtonId'],
  89  ]);
  90  echo $OUTPUT->render($dialog);
  91  echo '</div>';
  92  
  93  $inlinejs = "document.querySelector('#CustomDropdownButtonId button').innerHTML = 'Custom ID button found';";
  94  $PAGE->requires->js_amd_inline($inlinejs);
  95  
  96  echo '<div id="position" class="mb-4">';
  97  echo "<h3>Dropdown position example</h3>";
  98  $dialog = new core\output\local\dropdown\dialog('Open dialog', 'Dialog content');
  99  $dialog->set_position(core\output\local\dropdown\dialog::POSITION['end']);
 100  echo $OUTPUT->render($dialog);
 101  echo '</div>';
 102  
 103  echo '<div id="widths" class="mb-4">';
 104  echo "<h3>Dropdown max width values example</h3>";
 105  $content = '
 106      Some long long content. Some long long content. Some long long content. Some long long content.
 107      Some long long content. Some long long content. Some long long content. Some long long content.
 108      Some long long content. Some long long content. Some long long content. Some long long content.
 109  ';
 110  
 111  $dialog = new core\output\local\dropdown\dialog('Default dialog (adaptative)', $content);
 112  $dialog->set_classes('mb-3');
 113  echo $OUTPUT->render($dialog);
 114  
 115  $dialog = new core\output\local\dropdown\dialog('Big dialog', $content);
 116  $dialog->set_dialog_width(core\output\local\dropdown\dialog::WIDTH['big']);
 117  $dialog->set_classes('mb-3');
 118  echo $OUTPUT->render($dialog);
 119  
 120  $dialog = new core\output\local\dropdown\dialog('Small dialog', $content);
 121  $dialog->set_dialog_width(core\output\local\dropdown\dialog::WIDTH['small']);
 122  $dialog->set_classes('mb-3');
 123  echo $OUTPUT->render($dialog);
 124  echo '</div>';
 125  
 126  echo '<div id="dialogjscontrolssection" class="mb-4">';
 127  echo "<h3>Dropdown JS module controls</h3>";
 128  echo '<div class="mb-2">
 129      <button class="btn btn-secondary" id="buttontext">Change button text</button>
 130      <button class="btn btn-secondary" id="opendropdown">Open</button>
 131      <button class="btn btn-secondary" id="closedropdown">Close</button>
 132      <span id="dialogvisibility"></span>
 133  </div>';
 134  $dialog = new core\output\local\dropdown\dialog('Open dialog', 'Dialog content', [
 135      'extras' => ['id' => 'dialogjscontrols'],
 136  ]);
 137  echo $OUTPUT->render($dialog);
 138  echo '</div>';
 139  
 140  $inlinejs = <<<EOF
 141  require(
 142      ['core/local/dropdown/dialog', 'jquery'],
 143      (Module, jQuery) => {
 144          const dialog = Module.getDropdownDialog('#dialogjscontrols');
 145  
 146          document.querySelector('#buttontext').addEventListener('click', () => {
 147              dialog.setButtonContent('New button text');
 148          });
 149  
 150          document.querySelector('#opendropdown').addEventListener('click', (e) => {
 151              e.stopPropagation();
 152              dialog.setVisible(true);
 153          });
 154  
 155          document.querySelector('#closedropdown').addEventListener('click', (e) => {
 156              e.stopPropagation();
 157              dialog.setVisible(false);
 158          });
 159  
 160          const visibility = () => {
 161              const text = 'The dropdown is ' + (dialog.isVisible() ? 'visible' : 'hidden') + '.';
 162              document.querySelector('#dialogvisibility').innerHTML = text;
 163          }
 164          visibility();
 165  
 166  
 167          // Bootstrap 4 events are still jQuery.
 168          jQuery(dialog.getElement()).on('shown.bs.dropdown', (e) => {
 169              visibility();
 170          });
 171          jQuery(dialog.getElement()).on('hidden.bs.dropdown', (e) => {
 172              visibility();
 173          });
 174      }
 175  );
 176  EOF;
 177  $PAGE->requires->js_amd_inline($inlinejs);
 178  
 179  echo "<h2>Dropdown status test page</h2>";
 180  
 181  echo '<div id="statusregularscenario" class="mb-4">';
 182  echo "<h3>Basic example</h3>";
 183  $choice = new core\output\choicelist('Dialog content');
 184  $choice->add_option('option1', 'Option 1', [
 185      'description' => 'Option 1 description'
 186  ]);
 187  $choice->add_option('option2', 'Option 2', [
 188      'description' => 'Option 2 description',
 189      'icon' => new pix_icon('t/hide', 'Eye icon 1')
 190  ]);
 191  $choice->add_option('option3', 'Option 3', [
 192      'icon' => new pix_icon('t/show', 'Eye icon 2')
 193  ]);
 194  $dialog = new core\output\local\dropdown\status('Open dialog', $choice);
 195  echo $OUTPUT->render($dialog);
 196  echo '</div>';
 197  
 198  echo '<div id="statusselectedscenario" class="mb-4">';
 199  echo "<h3>Selected element example</h3>";
 200  $choice = new core\output\choicelist('Dialog content');
 201  $choice->add_option('option1', 'Option 1', [
 202      'description' => 'Option 1 description',
 203      'icon' => new pix_icon('t/show', 'Eye icon 1')
 204  ]);
 205  $choice->add_option('option2', 'Option 2', [
 206      'description' => 'Option 2 description',
 207      'icon' => new pix_icon('t/hide', 'Eye icon 2')
 208  ]);
 209  $choice->add_option('option3', 'Option 3', [
 210      'description' => 'Option 3 description',
 211      'icon' => new pix_icon('t/stealth', 'Eye icon 3')
 212  ]);
 213  $choice->set_selected_value('option2');
 214  $dialog = new core\output\local\dropdown\status('Open dialog', $choice);
 215  echo $OUTPUT->render($dialog);
 216  echo '</div>';
 217  
 218  echo '<div id="statusdisablescenario" class="mb-4">';
 219  echo "<h3>Disable option example</h3>";
 220  $choice = new core\output\choicelist('Dialog content');
 221  $choice->add_option('option1', 'Option 1');
 222  $choice->add_option('option2', 'Option 2', [
 223      'description' => 'Option 2 description',
 224      'icon' => new pix_icon('t/hide', 'Eye icon')
 225  ]);
 226  $choice->add_option('option3', 'Option 3');
 227  $choice->set_option_disabled('option2', true);
 228  $dialog = new core\output\local\dropdown\status('Open dialog', $choice);
 229  echo $OUTPUT->render($dialog);
 230  echo '</div>';
 231  
 232  echo '<div id="statusoptionextrasscenario" class="mb-4">';
 233  echo "<h3>Set option extra attributes example</h3>";
 234  $choice = new core\output\choicelist('Dialog content');
 235  $choice->add_option('option1', 'Option 1');
 236  $choice->add_option('option2', 'Option 2', [
 237      'description' => 'Option 2 description',
 238      'icon' => new pix_icon('t/hide', 'Eye icon')
 239  ]);
 240  $choice->add_option('option3', 'Option 3');
 241  $choice->set_option_extras('option2', ['data-foo' => 'bar']);
 242  $dialog = new core\output\local\dropdown\status('Open dialog', $choice);
 243  echo $OUTPUT->render($dialog);
 244  echo '</div>';
 245  
 246  echo '<div id="statusoptionurl" class="mb-4">';
 247  echo "<h3>Set option url example</h3>";
 248  $choice = new core\output\choicelist('Dialog content');
 249  $choice->add_option('option1', 'Option 1');
 250  $choice->add_option('option2', 'Option 2', [
 251      'url' => new moodle_url('/lib/tests/behat/fixtures/dropdown_output_testpage.php', ['foo' => 'bar']),
 252  ]);
 253  $choice->add_option('option3', 'Option 3');
 254  $choice->set_option_extras('option2', ['data-foo' => 'bar']);
 255  $dialog = new core\output\local\dropdown\status('Open dialog', $choice);
 256  echo $OUTPUT->render($dialog);
 257  $foo = optional_param('foo', 'none', PARAM_TEXT);
 258  echo "<p>Foo param value: $foo</p>";
 259  echo '</div>';
 260  
 261  echo '<div id="statussyncbutton" class="mb-4">';
 262  echo "<h3>Sync button text</h3>";
 263  $choice = new core\output\choicelist('Dialog content');
 264  $choice->add_option('option1', 'Option 1', [
 265      'description' => 'Option 1 description',
 266      'icon' => new pix_icon('t/show', 'Eye icon 1')
 267  ]);
 268  $choice->add_option('option2', 'Option 2', [
 269      'description' => 'Option 2 description',
 270      'icon' => new pix_icon('t/hide', 'Eye icon 2')
 271  ]);
 272  $choice->add_option('option3', 'Option 3', [
 273      'description' => 'Option 3 description',
 274      'icon' => new pix_icon('t/stealth', 'Eye icon 3')
 275  ]);
 276  $choice->set_selected_value('option2');
 277  $dialog = new core\output\local\dropdown\status(
 278      'Open dialog',
 279      $choice,
 280      ['buttonsync' => true, 'updatestatus' => true]
 281  );
 282  echo '<button class="btn">Focus helper</button>';
 283  echo $OUTPUT->render($dialog);
 284  echo '</div>';
 285  
 286  echo '<div id="statusjscontrolsection" class="mb-4">';
 287  echo "<h3>Status JS controls</h3>";
 288  echo '<div class="mb-2">
 289      <button class="btn btn-secondary" id="setselected">Change selected value</button>
 290      <button class="btn btn-secondary" id="syncbutton">Enable sync</button>
 291      <button class="btn btn-secondary" id="updatestatus">Disable update</button>
 292      <span id="statusvalue"></span>
 293  </div>';
 294  $choice = new core\output\choicelist('Dialog content');
 295  $choice->add_option('option1', 'Option 1', [
 296      'description' => 'Option 1 description',
 297      'icon' => new pix_icon('t/show', 'Eye icon 1')
 298  ]);
 299  $choice->add_option('option2', 'Option 2', [
 300      'description' => 'Option 2 description',
 301      'icon' => new pix_icon('t/hide', 'Eye icon 2')
 302  ]);
 303  $choice->add_option('option3', 'Option 3', [
 304      'description' => 'Option 3 description',
 305      'icon' => new pix_icon('t/stealth', 'Eye icon 3')
 306  ]);
 307  $choice->set_selected_value('option2');
 308  $dialog = new core\output\local\dropdown\status(
 309      'Open dialog',
 310      $choice,
 311      [
 312          'extras' => ['id' => 'statusjscontrols'],
 313          'updatestatus' => true
 314      ],
 315  );
 316  echo $OUTPUT->render($dialog);
 317  echo '</div>';
 318  
 319  $inlinejs = <<<EOF
 320  require(
 321      ['core/local/dropdown/status', 'jquery'],
 322      (Module, jQuery) => {
 323          const status = Module.getDropdownStatus('#statusjscontrols');
 324  
 325          const printValue = () => {
 326              const text = 'The status value is ' + status.getSelectedValue() + '.';
 327              document.querySelector('#statusvalue').innerHTML = text;
 328          }
 329          printValue();
 330  
 331          document.querySelector('#setselected').addEventListener('click', () => {
 332              if (status.getSelectedValue() == 'option2') {
 333                  status.setSelectedValue('option3');
 334              } else {
 335                  status.setSelectedValue('option2');
 336              }
 337          });
 338  
 339          document.querySelector('#syncbutton').addEventListener('click', (e) => {
 340              if (status.isButtonSyncEnabled()) {
 341                  status.setButtonSyncEnabled(false);
 342              } else {
 343                  status.setButtonSyncEnabled(true);
 344              }
 345              e.target.innerHTML = (status.isButtonSyncEnabled()) ? 'Disable sync': 'Enable sync';
 346          });
 347  
 348          document.querySelector('#updatestatus').addEventListener('click', (e) => {
 349              if (status.isUpdateStatusEnabled()) {
 350                  status.setUpdateStatusEnabled(false);
 351              } else {
 352                  status.setUpdateStatusEnabled(true);
 353              }
 354              e.target.innerHTML = (status.isUpdateStatusEnabled()) ? 'Disable update': 'Enable update';
 355          });
 356  
 357          status.getElement().addEventListener('change', () => {
 358              printValue();
 359          });
 360  
 361      }
 362  );
 363  EOF;
 364  $PAGE->requires->js_amd_inline($inlinejs);
 365  
 366  echo $OUTPUT->footer();