Differences Between: [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
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 * Renderer outputting the quiz editing UI. 19 * 20 * @package mod_quiz 21 * @copyright 2013 The Open University. 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace mod_quiz\output; 26 defined('MOODLE_INTERNAL') || die(); 27 28 use \mod_quiz\structure; 29 use \html_writer; 30 use renderable; 31 32 /** 33 * Renderer outputting the quiz editing UI. 34 * 35 * @copyright 2013 The Open University. 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 * @since Moodle 2.7 38 */ 39 class edit_renderer extends \plugin_renderer_base { 40 41 /** @var string The toggle group name of the checkboxes for the toggle-all functionality. */ 42 protected $togglegroup = 'quiz-questions'; 43 44 /** 45 * Render the edit page 46 * 47 * @param \quiz $quizobj object containing all the quiz settings information. 48 * @param structure $structure object containing the structure of the quiz. 49 * @param \question_edit_contexts $contexts the relevant question bank contexts. 50 * @param \moodle_url $pageurl the canonical URL of this page. 51 * @param array $pagevars the variables from {@link question_edit_setup()}. 52 * @return string HTML to output. 53 */ 54 public function edit_page(\quiz $quizobj, structure $structure, 55 \question_edit_contexts $contexts, \moodle_url $pageurl, array $pagevars) { 56 $output = ''; 57 58 // Page title. 59 $output .= $this->heading_with_help(get_string('editingquizx', 'quiz', 60 format_string($quizobj->get_quiz_name())), 'editingquiz', 'quiz', '', 61 get_string('basicideasofquiz', 'quiz'), 2); 62 63 // Information at the top. 64 $output .= $this->quiz_state_warnings($structure); 65 66 $output .= html_writer::start_div('mod_quiz-edit-top-controls'); 67 68 $output .= html_writer::start_div('d-flex justify-content-between flex-wrap mb-1'); 69 $output .= html_writer::start_div('d-flex flex-column justify-content-around'); 70 $output .= $this->quiz_information($structure); 71 $output .= html_writer::end_tag('div'); 72 $output .= $this->maximum_grade_input($structure, $pageurl); 73 $output .= html_writer::end_tag('div'); 74 75 $output .= html_writer::start_div('d-flex justify-content-between flex-wrap mb-1'); 76 $output .= html_writer::start_div('mod_quiz-edit-action-buttons btn-group edit-toolbar', ['role' => 'group']); 77 $output .= $this->repaginate_button($structure, $pageurl); 78 $output .= $this->selectmultiple_button($structure); 79 $output .= html_writer::end_tag('div'); 80 81 $output .= html_writer::start_div('d-flex flex-column justify-content-around'); 82 $output .= $this->total_marks($quizobj->get_quiz()); 83 $output .= html_writer::end_tag('div'); 84 $output .= html_writer::end_tag('div'); 85 86 $output .= $this->selectmultiple_controls($structure); 87 $output .= html_writer::end_tag('div'); 88 89 // Show the questions organised into sections and pages. 90 $output .= $this->start_section_list($structure); 91 92 foreach ($structure->get_sections() as $section) { 93 $output .= $this->start_section($structure, $section); 94 $output .= $this->questions_in_section($structure, $section, $contexts, $pagevars, $pageurl); 95 96 if ($structure->is_last_section($section)) { 97 $output .= \html_writer::start_div('last-add-menu'); 98 $output .= html_writer::tag('span', $this->add_menu_actions($structure, 0, 99 $pageurl, $contexts, $pagevars), array('class' => 'add-menu-outer')); 100 $output .= \html_writer::end_div(); 101 } 102 103 $output .= $this->end_section(); 104 } 105 106 $output .= $this->end_section_list(); 107 108 // Initialise the JavaScript. 109 $this->initialise_editing_javascript($structure, $contexts, $pagevars, $pageurl); 110 111 // Include the contents of any other popups required. 112 if ($structure->can_be_edited()) { 113 $thiscontext = $contexts->lowest(); 114 $this->page->requires->js_call_amd('mod_quiz/quizquestionbank', 'init', [ 115 $thiscontext->id 116 ]); 117 118 $this->page->requires->js_call_amd('mod_quiz/add_random_question', 'init', [ 119 $thiscontext->id, 120 $pagevars['cat'], 121 $pageurl->out_as_local_url(true), 122 $pageurl->param('cmid') 123 ]); 124 125 // Include the question chooser. 126 $output .= $this->question_chooser(); 127 } 128 129 return $output; 130 } 131 132 /** 133 * Render any warnings that might be required about the state of the quiz, 134 * e.g. if it has been attempted, or if the shuffle questions option is 135 * turned on. 136 * 137 * @param structure $structure the quiz structure. 138 * @return string HTML to output. 139 */ 140 public function quiz_state_warnings(structure $structure) { 141 $warnings = $structure->get_edit_page_warnings(); 142 143 if (empty($warnings)) { 144 return ''; 145 } 146 147 $output = array(); 148 foreach ($warnings as $warning) { 149 $output[] = \html_writer::tag('p', $warning); 150 } 151 return $this->box(implode("\n", $output), 'statusdisplay'); 152 } 153 154 /** 155 * Render the status bar. 156 * 157 * @param structure $structure the quiz structure. 158 * @return string HTML to output. 159 */ 160 public function quiz_information(structure $structure) { 161 list($currentstatus, $explanation) = $structure->get_dates_summary(); 162 163 $output = html_writer::span( 164 get_string('numquestionsx', 'quiz', $structure->get_question_count()), 165 'numberofquestions') . ' | ' . 166 html_writer::span($currentstatus, 'quizopeningstatus', 167 array('title' => $explanation)); 168 169 return html_writer::div($output, 'statusbar'); 170 } 171 172 /** 173 * Render the form for setting a quiz' overall grade 174 * 175 * @param structure $structure the quiz structure. 176 * @param \moodle_url $pageurl the canonical URL of this page. 177 * @return string HTML to output. 178 */ 179 public function maximum_grade_input($structure, \moodle_url $pageurl) { 180 $output = ''; 181 $output .= html_writer::start_div('maxgrade'); 182 $output .= html_writer::start_tag('form', array('method' => 'post', 'action' => 'edit.php', 183 'class' => 'quizsavegradesform form-inline')); 184 $output .= html_writer::start_tag('fieldset', array('class' => 'invisiblefieldset')); 185 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())); 186 $output .= html_writer::input_hidden_params($pageurl); 187 $output .= html_writer::tag('label', get_string('maximumgrade') . ' ', 188 array('for' => 'inputmaxgrade')); 189 $output .= html_writer::empty_tag('input', array('type' => 'text', 'id' => 'inputmaxgrade', 190 'name' => 'maxgrade', 'size' => ($structure->get_decimal_places_for_grades() + 2), 191 'value' => $structure->formatted_quiz_grade(), 192 'class' => 'form-control')); 193 $output .= html_writer::empty_tag('input', array('type' => 'submit', 'class' => 'btn btn-secondary ml-1', 194 'name' => 'savechanges', 'value' => get_string('save', 'quiz'))); 195 $output .= html_writer::end_tag('fieldset'); 196 $output .= html_writer::end_tag('form'); 197 $output .= html_writer::end_tag('div'); 198 return $output; 199 } 200 201 /** 202 * Return the repaginate button 203 * @param structure $structure the structure of the quiz being edited. 204 * @param \moodle_url $pageurl the canonical URL of this page. 205 * @return string HTML to output. 206 */ 207 protected function repaginate_button(structure $structure, \moodle_url $pageurl) { 208 $header = html_writer::tag('span', get_string('repaginatecommand', 'quiz'), array('class' => 'repaginatecommand')); 209 $form = $this->repaginate_form($structure, $pageurl); 210 211 $buttonoptions = array( 212 'type' => 'submit', 213 'name' => 'repaginate', 214 'id' => 'repaginatecommand', 215 'value' => get_string('repaginatecommand', 'quiz'), 216 'class' => 'btn btn-secondary mr-1', 217 'data-header' => $header, 218 'data-form' => $form, 219 ); 220 if (!$structure->can_be_repaginated()) { 221 $buttonoptions['disabled'] = 'disabled'; 222 } else { 223 $this->page->requires->js_call_amd('mod_quiz/repaginate', 'init'); 224 } 225 226 return html_writer::empty_tag('input', $buttonoptions); 227 } 228 229 /** 230 * Generate the bulk action button. 231 * 232 * @param structure $structure the structure of the quiz being edited. 233 * @return string HTML to output. 234 */ 235 protected function selectmultiple_button(structure $structure) { 236 $buttonoptions = array( 237 'type' => 'button', 238 'name' => 'selectmultiple', 239 'id' => 'selectmultiplecommand', 240 'value' => get_string('selectmultipleitems', 'quiz'), 241 'class' => 'btn btn-secondary' 242 ); 243 if (!$structure->can_be_edited()) { 244 $buttonoptions['disabled'] = 'disabled'; 245 } 246 247 return html_writer::tag('button', get_string('selectmultipleitems', 'quiz'), $buttonoptions); 248 } 249 250 /** 251 * Generate the controls that appear when the bulk action button is pressed. 252 * 253 * @param structure $structure the structure of the quiz being edited. 254 * @return string HTML to output. 255 */ 256 protected function selectmultiple_controls(structure $structure) { 257 $output = ''; 258 259 // Bulk action button delete and bulk action button cancel. 260 $buttondeleteoptions = array( 261 'type' => 'button', 262 'id' => 'selectmultipledeletecommand', 263 'value' => get_string('deleteselected', 'mod_quiz'), 264 'class' => 'btn btn-secondary', 265 'data-action' => 'toggle', 266 'data-togglegroup' => $this->togglegroup, 267 'data-toggle' => 'action', 268 'disabled' => true 269 ); 270 $buttoncanceloptions = array( 271 'type' => 'button', 272 'id' => 'selectmultiplecancelcommand', 273 'value' => get_string('cancel', 'moodle'), 274 'class' => 'btn btn-secondary' 275 ); 276 277 $groupoptions = array( 278 'class' => 'btn-group selectmultiplecommand actions m-1', 279 'role' => 'group' 280 ); 281 282 $output .= html_writer::tag('div', 283 html_writer::tag('button', get_string('deleteselected', 'mod_quiz'), $buttondeleteoptions) . 284 " " . 285 html_writer::tag('button', get_string('cancel', 'moodle'), 286 $buttoncanceloptions), $groupoptions); 287 288 $toolbaroptions = array( 289 'class' => 'btn-toolbar m-1', 290 'role' => 'toolbar', 291 'aria-label' => get_string('selectmultipletoolbar', 'quiz'), 292 ); 293 294 // Select all/deselect all questions. 295 $selectallid = 'questionselectall'; 296 $selectalltext = get_string('selectall', 'moodle'); 297 $deselectalltext = get_string('deselectall', 'moodle'); 298 $mastercheckbox = new \core\output\checkbox_toggleall($this->togglegroup, true, [ 299 'id' => $selectallid, 300 'name' => $selectallid, 301 'value' => 1, 302 'label' => $selectalltext, 303 'selectall' => $selectalltext, 304 'deselectall' => $deselectalltext, 305 ], true); 306 307 $selectdeselect = html_writer::div($this->render($mastercheckbox), 'selectmultiplecommandbuttons'); 308 $output .= html_writer::tag('div', $selectdeselect, $toolbaroptions); 309 return $output; 310 } 311 312 /** 313 * Return the repaginate form 314 * @param structure $structure the structure of the quiz being edited. 315 * @param \moodle_url $pageurl the canonical URL of this page. 316 * @return string HTML to output. 317 */ 318 protected function repaginate_form(structure $structure, \moodle_url $pageurl) { 319 $perpage = array(); 320 $perpage[0] = get_string('allinone', 'quiz'); 321 for ($i = 1; $i <= 50; ++$i) { 322 $perpage[$i] = $i; 323 } 324 325 $hiddenurl = clone($pageurl); 326 $hiddenurl->param('sesskey', sesskey()); 327 328 $select = html_writer::select($perpage, 'questionsperpage', 329 $structure->get_questions_per_page(), false, array('class' => 'custom-select')); 330 331 $buttonattributes = array( 332 'type' => 'submit', 333 'name' => 'repaginate', 334 'value' => get_string('go'), 335 'class' => 'btn btn-secondary ml-1' 336 ); 337 338 $formcontent = html_writer::tag('form', html_writer::div( 339 html_writer::input_hidden_params($hiddenurl) . 340 get_string('repaginate', 'quiz', $select) . 341 html_writer::empty_tag('input', $buttonattributes) 342 ), array('action' => 'edit.php', 'method' => 'post')); 343 344 return html_writer::div($formcontent, '', array('id' => 'repaginatedialog')); 345 } 346 347 /** 348 * Render the total marks available for the quiz. 349 * 350 * @param \stdClass $quiz the quiz settings from the database. 351 * @return string HTML to output. 352 */ 353 public function total_marks($quiz) { 354 $totalmark = html_writer::span(quiz_format_grade($quiz, $quiz->sumgrades), 'mod_quiz_summarks'); 355 return html_writer::tag('span', 356 get_string('totalmarksx', 'quiz', $totalmark), 357 array('class' => 'totalpoints')); 358 } 359 360 /** 361 * Generate the starting container html for the start of a list of sections 362 * @param structure $structure the structure of the quiz being edited. 363 * @return string HTML to output. 364 */ 365 protected function start_section_list(structure $structure) { 366 $class = 'slots'; 367 if ($structure->get_section_count() == 1) { 368 $class .= ' only-one-section'; 369 } 370 return html_writer::start_tag('ul', array('class' => $class)); 371 } 372 373 /** 374 * Generate the closing container html for the end of a list of sections 375 * @return string HTML to output. 376 */ 377 protected function end_section_list() { 378 return html_writer::end_tag('ul'); 379 } 380 381 /** 382 * Display the start of a section, before the questions. 383 * 384 * @param structure $structure the structure of the quiz being edited. 385 * @param \stdClass $section The quiz_section entry from DB 386 * @return string HTML to output. 387 */ 388 protected function start_section($structure, $section) { 389 390 $output = ''; 391 392 $sectionstyle = ''; 393 if ($structure->is_only_one_slot_in_section($section)) { 394 $sectionstyle = ' only-has-one-slot'; 395 } 396 397 $output .= html_writer::start_tag('li', array('id' => 'section-'.$section->id, 398 'class' => 'section main clearfix'.$sectionstyle, 'role' => 'region', 399 'aria-label' => $section->heading)); 400 401 $output .= html_writer::start_div('content'); 402 403 $output .= html_writer::start_div('section-heading'); 404 405 $headingtext = $this->heading(html_writer::span( 406 html_writer::span($section->heading, 'instancesection'), 'sectioninstance'), 3); 407 408 if (!$structure->can_be_edited()) { 409 $editsectionheadingicon = ''; 410 } else { 411 $editsectionheadingicon = html_writer::link(new \moodle_url('#'), 412 $this->pix_icon('t/editstring', get_string('sectionheadingedit', 'quiz', $section->heading), 413 'moodle', array('class' => 'editicon visibleifjs')), 414 array('class' => 'editing_section', 'data-action' => 'edit_section_title')); 415 } 416 $output .= html_writer::div($headingtext . $editsectionheadingicon, 'instancesectioncontainer'); 417 418 if (!$structure->is_first_section($section) && $structure->can_be_edited()) { 419 $output .= $this->section_remove_icon($section); 420 } 421 $output .= $this->section_shuffle_questions($structure, $section); 422 423 $output .= html_writer::end_div($output, 'section-heading'); 424 425 return $output; 426 } 427 428 /** 429 * Display a checkbox for shuffling question within a section. 430 * 431 * @param structure $structure object containing the structure of the quiz. 432 * @param \stdClass $section data from the quiz_section table. 433 * @return string HTML to output. 434 */ 435 public function section_shuffle_questions(structure $structure, $section) { 436 $checkboxattributes = array( 437 'type' => 'checkbox', 438 'id' => 'shuffle-' . $section->id, 439 'value' => 1, 440 'data-action' => 'shuffle_questions', 441 'class' => 'cm-edit-action', 442 ); 443 444 if (!$structure->can_be_edited()) { 445 $checkboxattributes['disabled'] = 'disabled'; 446 } 447 if ($section->shufflequestions) { 448 $checkboxattributes['checked'] = 'checked'; 449 } 450 451 if ($structure->is_first_section($section)) { 452 $help = $this->help_icon('shufflequestions', 'quiz'); 453 } else { 454 $help = ''; 455 } 456 457 $helpspan = html_writer::span($help, 'shuffle-help-tip'); 458 $progressspan = html_writer::span('', 'shuffle-progress'); 459 $checkbox = html_writer::empty_tag('input', $checkboxattributes); 460 $label = html_writer::label(get_string('shufflequestions', 'quiz'), 461 $checkboxattributes['id'], false); 462 return html_writer::span($progressspan . $checkbox . $label. ' ' . $helpspan, 463 'instanceshufflequestions', array('data-action' => 'shuffle_questions')); 464 } 465 466 /** 467 * Display the end of a section, after the questions. 468 * 469 * @return string HTML to output. 470 */ 471 protected function end_section() { 472 $output = html_writer::end_tag('div'); 473 $output .= html_writer::end_tag('li'); 474 475 return $output; 476 } 477 478 /** 479 * Render an icon to remove a section from the quiz. 480 * 481 * @param object $section the section to be removed. 482 * @return string HTML to output. 483 */ 484 public function section_remove_icon($section) { 485 $title = get_string('sectionheadingremove', 'quiz', $section->heading); 486 $url = new \moodle_url('/mod/quiz/edit.php', 487 array('sesskey' => sesskey(), 'removesection' => '1', 'sectionid' => $section->id)); 488 $image = $this->pix_icon('t/delete', $title); 489 return $this->action_link($url, $image, null, array( 490 'class' => 'cm-edit-action editing_delete', 'data-action' => 'deletesection')); 491 } 492 493 /** 494 * Renders HTML to display the questions in a section of the quiz. 495 * 496 * This function calls {@link core_course_renderer::quiz_section_question()} 497 * 498 * @param structure $structure object containing the structure of the quiz. 499 * @param \stdClass $section information about the section. 500 * @param \question_edit_contexts $contexts the relevant question bank contexts. 501 * @param array $pagevars the variables from {@link \question_edit_setup()}. 502 * @param \moodle_url $pageurl the canonical URL of this page. 503 * @return string HTML to output. 504 */ 505 public function questions_in_section(structure $structure, $section, 506 $contexts, $pagevars, $pageurl) { 507 508 $output = ''; 509 foreach ($structure->get_slots_in_section($section->id) as $slot) { 510 $output .= $this->question_row($structure, $slot, $contexts, $pagevars, $pageurl); 511 } 512 return html_writer::tag('ul', $output, array('class' => 'section img-text')); 513 } 514 515 /** 516 * Displays one question with the surrounding controls. 517 * 518 * @param structure $structure object containing the structure of the quiz. 519 * @param int $slot which slot we are outputting. 520 * @param \question_edit_contexts $contexts the relevant question bank contexts. 521 * @param array $pagevars the variables from {@link \question_edit_setup()}. 522 * @param \moodle_url $pageurl the canonical URL of this page. 523 * @return string HTML to output. 524 */ 525 public function question_row(structure $structure, $slot, $contexts, $pagevars, $pageurl) { 526 $output = ''; 527 528 $output .= $this->page_row($structure, $slot, $contexts, $pagevars, $pageurl); 529 530 // Page split/join icon. 531 $joinhtml = ''; 532 if ($structure->can_be_edited() && !$structure->is_last_slot_in_quiz($slot) && 533 !$structure->is_last_slot_in_section($slot)) { 534 $joinhtml = $this->page_split_join_button($structure, $slot); 535 } 536 // Question HTML. 537 $questionhtml = $this->question($structure, $slot, $pageurl); 538 $qtype = $structure->get_question_type_for_slot($slot); 539 $questionclasses = 'activity ' . $qtype . ' qtype_' . $qtype . ' slot'; 540 541 $output .= html_writer::tag('li', $questionhtml . $joinhtml, 542 array('class' => $questionclasses, 'id' => 'slot-' . $structure->get_slot_id_for_slot($slot), 543 'data-canfinish' => $structure->can_finish_during_the_attempt($slot))); 544 545 return $output; 546 } 547 548 /** 549 * Displays one question with the surrounding controls. 550 * 551 * @param structure $structure object containing the structure of the quiz. 552 * @param int $slot the first slot on the page we are outputting. 553 * @param \question_edit_contexts $contexts the relevant question bank contexts. 554 * @param array $pagevars the variables from {@link \question_edit_setup()}. 555 * @param \moodle_url $pageurl the canonical URL of this page. 556 * @return string HTML to output. 557 */ 558 public function page_row(structure $structure, $slot, $contexts, $pagevars, $pageurl) { 559 $output = ''; 560 561 $pagenumber = $structure->get_page_number_for_slot($slot); 562 563 // Put page in a heading for accessibility and styling. 564 $page = $this->heading(get_string('page') . ' ' . $pagenumber, 4); 565 566 if ($structure->is_first_slot_on_page($slot)) { 567 // Add the add-menu at the page level. 568 $addmenu = html_writer::tag('span', $this->add_menu_actions($structure, 569 $pagenumber, $pageurl, $contexts, $pagevars), 570 array('class' => 'add-menu-outer')); 571 572 $addquestionform = $this->add_question_form($structure, 573 $pagenumber, $pageurl, $pagevars); 574 575 $output .= html_writer::tag('li', $page . $addmenu . $addquestionform, 576 array('class' => 'pagenumber activity yui3-dd-drop page', 'id' => 'page-' . $pagenumber)); 577 } 578 579 return $output; 580 } 581 582 /** 583 * Returns the add menu that is output once per page. 584 * @param structure $structure object containing the structure of the quiz. 585 * @param int $page the page number that this menu will add to. 586 * @param \moodle_url $pageurl the canonical URL of this page. 587 * @param \question_edit_contexts $contexts the relevant question bank contexts. 588 * @param array $pagevars the variables from {@link \question_edit_setup()}. 589 * @return string HTML to output. 590 */ 591 public function add_menu_actions(structure $structure, $page, \moodle_url $pageurl, 592 \question_edit_contexts $contexts, array $pagevars) { 593 594 $actions = $this->edit_menu_actions($structure, $page, $pageurl, $pagevars); 595 if (empty($actions)) { 596 return ''; 597 } 598 $menu = new \action_menu(); 599 $menu->set_alignment(\action_menu::TR, \action_menu::TR); 600 $menu->set_constraint('.mod-quiz-edit-content'); 601 $trigger = html_writer::tag('span', get_string('add', 'quiz'), array('class' => 'add-menu')); 602 $menu->set_menu_trigger($trigger); 603 // The menu appears within an absolutely positioned element causing width problems. 604 // Make sure no-wrap is set so that we don't get a squashed menu. 605 $menu->set_nowrap_on_items(true); 606 607 // Disable the link if quiz has attempts. 608 if (!$structure->can_be_edited()) { 609 return $this->render($menu); 610 } 611 612 foreach ($actions as $action) { 613 if ($action instanceof \action_menu_link) { 614 $action->add_class('add-menu'); 615 } 616 $menu->add($action); 617 } 618 $menu->attributes['class'] .= ' page-add-actions commands'; 619 620 // Prioritise the menu ahead of all other actions. 621 $menu->prioritise = true; 622 623 return $this->render($menu); 624 } 625 626 /** 627 * Returns the list of actions to go in the add menu. 628 * @param structure $structure object containing the structure of the quiz. 629 * @param int $page the page number that this menu will add to. 630 * @param \moodle_url $pageurl the canonical URL of this page. 631 * @param array $pagevars the variables from {@link \question_edit_setup()}. 632 * @return array the actions. 633 */ 634 public function edit_menu_actions(structure $structure, $page, 635 \moodle_url $pageurl, array $pagevars) { 636 $questioncategoryid = question_get_category_id_from_pagevars($pagevars); 637 static $str; 638 if (!isset($str)) { 639 $str = get_strings(array('addasection', 'addaquestion', 'addarandomquestion', 640 'addarandomselectedquestion', 'questionbank'), 'quiz'); 641 } 642 643 // Get section, page, slotnumber and maxmark. 644 $actions = array(); 645 646 // Add a new question to the quiz. 647 $returnurl = new \moodle_url($pageurl, array('addonpage' => $page)); 648 $params = array('returnurl' => $returnurl->out_as_local_url(false), 649 'cmid' => $structure->get_cmid(), 'category' => $questioncategoryid, 650 'addonpage' => $page, 'appendqnumstring' => 'addquestion'); 651 652 $actions['addaquestion'] = new \action_menu_link_secondary( 653 new \moodle_url('/question/addquestion.php', $params), 654 new \pix_icon('t/add', $str->addaquestion, 'moodle', array('class' => 'iconsmall', 'title' => '')), 655 $str->addaquestion, array('class' => 'cm-edit-action addquestion', 'data-action' => 'addquestion') 656 ); 657 658 // Call question bank. 659 $icon = new \pix_icon('t/add', $str->questionbank, 'moodle', array('class' => 'iconsmall', 'title' => '')); 660 if ($page) { 661 $title = get_string('addquestionfrombanktopage', 'quiz', $page); 662 } else { 663 $title = get_string('addquestionfrombankatend', 'quiz'); 664 } 665 $attributes = array('class' => 'cm-edit-action questionbank', 666 'data-header' => $title, 'data-action' => 'questionbank', 'data-addonpage' => $page); 667 $actions['questionbank'] = new \action_menu_link_secondary($pageurl, $icon, $str->questionbank, $attributes); 668 669 // Add a random question. 670 if ($structure->can_add_random_questions()) { 671 $returnurl = new \moodle_url('/mod/quiz/edit.php', array('cmid' => $structure->get_cmid(), 'data-addonpage' => $page)); 672 $params = ['returnurl' => $returnurl, 'cmid' => $structure->get_cmid(), 'appendqnumstring' => 'addarandomquestion']; 673 $url = new \moodle_url('/mod/quiz/addrandom.php', $params); 674 $icon = new \pix_icon('t/add', $str->addarandomquestion, 'moodle', array('class' => 'iconsmall', 'title' => '')); 675 $attributes = array('class' => 'cm-edit-action addarandomquestion', 'data-action' => 'addarandomquestion'); 676 if ($page) { 677 $title = get_string('addrandomquestiontopage', 'quiz', $page); 678 } else { 679 $title = get_string('addrandomquestionatend', 'quiz'); 680 } 681 $attributes = array_merge(array('data-header' => $title, 'data-addonpage' => $page), $attributes); 682 $actions['addarandomquestion'] = new \action_menu_link_secondary($url, $icon, $str->addarandomquestion, $attributes); 683 } 684 685 // Add a new section to the add_menu if possible. This is always added to the HTML 686 // then hidden with CSS when no needed, so that as things are re-ordered, etc. with 687 // Ajax it can be relevaled again when necessary. 688 $params = array('cmid' => $structure->get_cmid(), 'addsectionatpage' => $page); 689 690 $actions['addasection'] = new \action_menu_link_secondary( 691 new \moodle_url($pageurl, $params), 692 new \pix_icon('t/add', $str->addasection, 'moodle', array('class' => 'iconsmall', 'title' => '')), 693 $str->addasection, array('class' => 'cm-edit-action addasection', 'data-action' => 'addasection') 694 ); 695 696 return $actions; 697 } 698 699 /** 700 * Render the form that contains the data for adding a new question to the quiz. 701 * 702 * @param structure $structure object containing the structure of the quiz. 703 * @param int $page the page number that this menu will add to. 704 * @param \moodle_url $pageurl the canonical URL of this page. 705 * @param array $pagevars the variables from {@link \question_edit_setup()}. 706 * @return string HTML to output. 707 */ 708 protected function add_question_form(structure $structure, $page, \moodle_url $pageurl, array $pagevars) { 709 710 $questioncategoryid = question_get_category_id_from_pagevars($pagevars); 711 712 $output = html_writer::tag('input', null, 713 array('type' => 'hidden', 'name' => 'returnurl', 714 'value' => $pageurl->out_as_local_url(false, array('addonpage' => $page)))); 715 $output .= html_writer::tag('input', null, 716 array('type' => 'hidden', 'name' => 'cmid', 'value' => $structure->get_cmid())); 717 $output .= html_writer::tag('input', null, 718 array('type' => 'hidden', 'name' => 'appendqnumstring', 'value' => 'addquestion')); 719 $output .= html_writer::tag('input', null, 720 array('type' => 'hidden', 'name' => 'category', 'value' => $questioncategoryid)); 721 722 return html_writer::tag('form', html_writer::div($output), 723 array('class' => 'addnewquestion', 'method' => 'post', 724 'action' => new \moodle_url('/question/addquestion.php'))); 725 } 726 727 /** 728 * Display a question. 729 * 730 * @param structure $structure object containing the structure of the quiz. 731 * @param int $slot the first slot on the page we are outputting. 732 * @param \moodle_url $pageurl the canonical URL of this page. 733 * @return string HTML to output. 734 */ 735 public function question(structure $structure, $slot, \moodle_url $pageurl) { 736 $output = ''; 737 $output .= html_writer::start_tag('div'); 738 739 if ($structure->can_be_edited()) { 740 $output .= $this->question_move_icon($structure, $slot); 741 } 742 743 $output .= html_writer::start_div('mod-indent-outer'); 744 $checkbox = new \core\output\checkbox_toggleall($this->togglegroup, false, [ 745 'id' => 'selectquestion-' . $structure->get_displayed_number_for_slot($slot), 746 'name' => 'selectquestion[]', 747 'value' => $structure->get_displayed_number_for_slot($slot), 748 'classes' => 'select-multiple-checkbox', 749 ]); 750 $output .= $this->render($checkbox); 751 $output .= $this->question_number($structure->get_displayed_number_for_slot($slot)); 752 753 // This div is used to indent the content. 754 $output .= html_writer::div('', 'mod-indent'); 755 756 // Display the link to the question (or do nothing if question has no url). 757 if ($structure->get_question_type_for_slot($slot) == 'random') { 758 $questionname = $this->random_question($structure, $slot, $pageurl); 759 } else { 760 $questionname = $this->question_name($structure, $slot, $pageurl); 761 } 762 763 // Start the div for the activity title, excluding the edit icons. 764 $output .= html_writer::start_div('activityinstance'); 765 $output .= $questionname; 766 767 // Closing the tag which contains everything but edit icons. Content part of the module should not be part of this. 768 $output .= html_writer::end_tag('div'); // .activityinstance. 769 770 // Action icons. 771 $questionicons = ''; 772 $questionicons .= $this->question_preview_icon($structure->get_quiz(), $structure->get_question_in_slot($slot)); 773 if ($structure->can_be_edited()) { 774 $questionicons .= $this->question_remove_icon($structure, $slot, $pageurl); 775 } 776 $questionicons .= $this->marked_out_of_field($structure, $slot); 777 $output .= html_writer::span($questionicons, 'actions'); // Required to add js spinner icon. 778 if ($structure->can_be_edited()) { 779 $output .= $this->question_dependency_icon($structure, $slot); 780 } 781 782 // End of indentation div. 783 $output .= html_writer::end_tag('div'); 784 $output .= html_writer::end_tag('div'); 785 786 return $output; 787 } 788 789 /** 790 * Render the move icon. 791 * 792 * @param structure $structure object containing the structure of the quiz. 793 * @param int $slot the first slot on the page we are outputting. 794 * @return string The markup for the move action. 795 */ 796 public function question_move_icon(structure $structure, $slot) { 797 return html_writer::link(new \moodle_url('#'), 798 $this->pix_icon('i/dragdrop', get_string('move'), 'moodle', array('class' => 'iconsmall', 'title' => '')), 799 array('class' => 'editing_move', 'data-action' => 'move') 800 ); 801 } 802 803 /** 804 * Output the question number. 805 * @param string $number The number, or 'i'. 806 * @return string HTML to output. 807 */ 808 public function question_number($number) { 809 if (is_numeric($number)) { 810 $number = html_writer::span(get_string('question'), 'accesshide') . ' ' . $number; 811 } 812 return html_writer::tag('span', $number, array('class' => 'slotnumber')); 813 } 814 815 /** 816 * Render the preview icon. 817 * 818 * @param \stdClass $quiz the quiz settings from the database. 819 * @param \stdClass $question data from the question and quiz_slots tables. 820 * @param bool $label if true, show the preview question label after the icon 821 * @param int $variant which question variant to preview (optional). 822 * @return string HTML to output. 823 */ 824 public function question_preview_icon($quiz, $question, $label = null, $variant = null) { 825 $url = quiz_question_preview_url($quiz, $question, $variant); 826 827 // Do we want a label? 828 $strpreviewlabel = ''; 829 if ($label) { 830 $strpreviewlabel = ' ' . get_string('preview', 'quiz'); 831 } 832 833 // Build the icon. 834 $strpreviewquestion = get_string('previewquestion', 'quiz'); 835 $image = $this->pix_icon('t/preview', $strpreviewquestion); 836 837 $action = new \popup_action('click', $url, 'questionpreview', 838 question_preview_popup_params()); 839 840 return $this->action_link($url, $image . $strpreviewlabel, $action, 841 array('title' => $strpreviewquestion, 'class' => 'preview')); 842 } 843 844 /** 845 * Render an icon to remove a question from the quiz. 846 * 847 * @param structure $structure object containing the structure of the quiz. 848 * @param int $slot the first slot on the page we are outputting. 849 * @param \moodle_url $pageurl the canonical URL of the edit page. 850 * @return string HTML to output. 851 */ 852 public function question_remove_icon(structure $structure, $slot, $pageurl) { 853 $url = new \moodle_url($pageurl, array('sesskey' => sesskey(), 'remove' => $slot)); 854 $strdelete = get_string('delete'); 855 856 $image = $this->pix_icon('t/delete', $strdelete); 857 858 return $this->action_link($url, $image, null, array('title' => $strdelete, 859 'class' => 'cm-edit-action editing_delete', 'data-action' => 'delete')); 860 } 861 862 /** 863 * Display an icon to split or join two pages of the quiz. 864 * 865 * @param structure $structure object containing the structure of the quiz. 866 * @param int $slot the first slot on the page we are outputting. 867 * @return string HTML to output. 868 */ 869 public function page_split_join_button($structure, $slot) { 870 $insertpagebreak = !$structure->is_last_slot_on_page($slot); 871 $url = new \moodle_url('repaginate.php', array('quizid' => $structure->get_quizid(), 872 'slot' => $slot, 'repag' => $insertpagebreak ? 2 : 1, 'sesskey' => sesskey())); 873 874 if ($insertpagebreak) { 875 $title = get_string('addpagebreak', 'quiz'); 876 $image = $this->image_icon('e/insert_page_break', $title); 877 $action = 'addpagebreak'; 878 } else { 879 $title = get_string('removepagebreak', 'quiz'); 880 $image = $this->image_icon('e/remove_page_break', $title); 881 $action = 'removepagebreak'; 882 } 883 884 // Disable the link if quiz has attempts. 885 $disabled = null; 886 if (!$structure->can_be_edited()) { 887 $disabled = 'disabled'; 888 } 889 return html_writer::span($this->action_link($url, $image, null, array('title' => $title, 890 'class' => 'page_split_join cm-edit-action', 'disabled' => $disabled, 'data-action' => $action)), 891 'page_split_join_wrapper'); 892 } 893 894 /** 895 * Display the icon for whether this question can only be seen if the previous 896 * one has been answered. 897 * 898 * @param structure $structure object containing the structure of the quiz. 899 * @param int $slot the first slot on the page we are outputting. 900 * @return string HTML to output. 901 */ 902 public function question_dependency_icon($structure, $slot) { 903 $a = array( 904 'thisq' => $structure->get_displayed_number_for_slot($slot), 905 'previousq' => $structure->get_displayed_number_for_slot(max($slot - 1, 1)), 906 ); 907 if ($structure->is_question_dependent_on_previous_slot($slot)) { 908 $title = get_string('questiondependencyremove', 'quiz', $a); 909 $image = $this->pix_icon('t/locked', get_string('questiondependsonprevious', 'quiz'), 910 'moodle', array('title' => '')); 911 $action = 'removedependency'; 912 } else { 913 $title = get_string('questiondependencyadd', 'quiz', $a); 914 $image = $this->pix_icon('t/unlocked', get_string('questiondependencyfree', 'quiz'), 915 'moodle', array('title' => '')); 916 $action = 'adddependency'; 917 } 918 919 // Disable the link if quiz has attempts. 920 $disabled = null; 921 if (!$structure->can_be_edited()) { 922 $disabled = 'disabled'; 923 } 924 $extraclass = ''; 925 if (!$structure->can_question_depend_on_previous_slot($slot)) { 926 $extraclass = ' question_dependency_cannot_depend'; 927 } 928 return html_writer::span($this->action_link('#', $image, null, array('title' => $title, 929 'class' => 'cm-edit-action', 'disabled' => $disabled, 'data-action' => $action)), 930 'question_dependency_wrapper' . $extraclass); 931 } 932 933 /** 934 * Renders html to display a name with the link to the question on a quiz edit page 935 * 936 * If the user does not have permission to edi the question, it is rendered 937 * without a link 938 * 939 * @param structure $structure object containing the structure of the quiz. 940 * @param int $slot which slot we are outputting. 941 * @param \moodle_url $pageurl the canonical URL of this page. 942 * @return string HTML to output. 943 */ 944 public function question_name(structure $structure, $slot, $pageurl) { 945 $output = ''; 946 947 $question = $structure->get_question_in_slot($slot); 948 $editurl = new \moodle_url('/question/question.php', array( 949 'returnurl' => $pageurl->out_as_local_url(), 950 'cmid' => $structure->get_cmid(), 'id' => $question->id)); 951 952 $instancename = quiz_question_tostring($question); 953 954 $qtype = \question_bank::get_qtype($question->qtype, false); 955 $namestr = $qtype->local_name(); 956 957 $icon = $this->pix_icon('icon', $namestr, $qtype->plugin_name(), array('title' => $namestr, 958 'class' => 'activityicon', 'alt' => ' ', 'role' => 'presentation')); 959 960 $editicon = $this->pix_icon('t/edit', '', 'moodle', array('title' => '')); 961 962 // Need plain question name without html tags for link title. 963 $title = shorten_text(format_string($question->name), 100); 964 965 // Display the link itself. 966 $activitylink = $icon . html_writer::tag('span', $editicon . $instancename, array('class' => 'instancename')); 967 $output .= html_writer::link($editurl, $activitylink, 968 array('title' => get_string('editquestion', 'quiz').' '.$title)); 969 970 return $output; 971 } 972 973 /** 974 * Renders html to display a random question the link to edit the configuration 975 * and also to see that category in the question bank. 976 * 977 * @param structure $structure object containing the structure of the quiz. 978 * @param int $slotnumber which slot we are outputting. 979 * @param \moodle_url $pageurl the canonical URL of this page. 980 * @return string HTML to output. 981 */ 982 public function random_question(structure $structure, $slotnumber, $pageurl) { 983 984 $question = $structure->get_question_in_slot($slotnumber); 985 $slot = $structure->get_slot_by_number($slotnumber); 986 $slottags = $structure->get_slot_tags_for_slot_id($slot->id); 987 $editurl = new \moodle_url('/mod/quiz/editrandom.php', 988 array('returnurl' => $pageurl->out_as_local_url(), 'slotid' => $slot->id)); 989 990 $temp = clone($question); 991 $temp->questiontext = ''; 992 $instancename = quiz_question_tostring($temp); 993 994 $configuretitle = get_string('configurerandomquestion', 'quiz'); 995 $qtype = \question_bank::get_qtype($question->qtype, false); 996 $namestr = $qtype->local_name(); 997 $icon = $this->pix_icon('icon', $namestr, $qtype->plugin_name(), array('title' => $namestr, 998 'class' => 'icon activityicon', 'alt' => ' ', 'role' => 'presentation')); 999 1000 $editicon = $this->pix_icon('t/edit', $configuretitle, 'moodle', array('title' => '')); 1001 $qbankurlparams = array( 1002 'cmid' => $structure->get_cmid(), 1003 'cat' => $question->category . ',' . $question->contextid, 1004 'recurse' => !empty($question->questiontext) 1005 ); 1006 1007 foreach ($slottags as $index => $slottag) { 1008 $qbankurlparams["qtagids[{$index}]"] = $slottag->tagid; 1009 } 1010 1011 // If this is a random question, display a link to show the questions 1012 // selected from in the question bank. 1013 $qbankurl = new \moodle_url('/question/edit.php', $qbankurlparams); 1014 $qbanklink = ' ' . \html_writer::link($qbankurl, 1015 get_string('seequestions', 'quiz'), array('class' => 'mod_quiz_random_qbank_link')); 1016 1017 return html_writer::link($editurl, $icon . $editicon, array('title' => $configuretitle)) . 1018 ' ' . $instancename . ' ' . $qbanklink; 1019 } 1020 1021 /** 1022 * Display the 'marked out of' information for a question. 1023 * Along with the regrade action. 1024 * @param structure $structure object containing the structure of the quiz. 1025 * @param int $slot which slot we are outputting. 1026 * @return string HTML to output. 1027 */ 1028 public function marked_out_of_field(structure $structure, $slot) { 1029 if (!$structure->is_real_question($slot)) { 1030 $output = html_writer::span('', 1031 'instancemaxmark decimalplaces_' . $structure->get_decimal_places_for_question_marks()); 1032 1033 $output .= html_writer::span( 1034 $this->pix_icon('spacer', '', 'moodle', array('class' => 'editicon visibleifjs', 'title' => '')), 1035 'editing_maxmark'); 1036 return html_writer::span($output, 'instancemaxmarkcontainer infoitem'); 1037 } 1038 1039 $output = html_writer::span($structure->formatted_question_grade($slot), 1040 'instancemaxmark decimalplaces_' . $structure->get_decimal_places_for_question_marks(), 1041 array('title' => get_string('maxmark', 'quiz'))); 1042 1043 $output .= html_writer::span( 1044 html_writer::link( 1045 new \moodle_url('#'), 1046 $this->pix_icon('t/editstring', '', 'moodle', array('class' => 'editicon visibleifjs', 'title' => '')), 1047 array( 1048 'class' => 'editing_maxmark', 1049 'data-action' => 'editmaxmark', 1050 'title' => get_string('editmaxmark', 'quiz'), 1051 ) 1052 ) 1053 ); 1054 return html_writer::span($output, 'instancemaxmarkcontainer'); 1055 } 1056 1057 /** 1058 * Renders the question chooser. 1059 * 1060 * @param renderable 1061 * @return string 1062 */ 1063 public function render_question_chooser(renderable $chooser) { 1064 return $this->render_from_template('mod_quiz/question_chooser', $chooser->export_for_template($this)); 1065 } 1066 1067 /** 1068 * Render the question type chooser dialogue. 1069 * @return string HTML to output. 1070 */ 1071 public function question_chooser() { 1072 $chooser = \mod_quiz\output\question_chooser::get($this->page->course, [], null); 1073 $container = html_writer::div($this->render($chooser), '', array('id' => 'qtypechoicecontainer')); 1074 return html_writer::div($container, 'createnewquestion'); 1075 } 1076 1077 /** 1078 * Render the contents of the question bank pop-up in its initial state, 1079 * when it just contains a loading progress indicator. 1080 * @return string HTML to output. 1081 */ 1082 public function question_bank_loading() { 1083 return html_writer::div($this->pix_icon('i/loading', get_string('loading')), 'questionbankloading'); 1084 } 1085 1086 /** 1087 * Initialise the JavaScript for the general editing. (JavaScript for popups 1088 * is handled with the specific code for those.) 1089 * 1090 * @param structure $structure object containing the structure of the quiz. 1091 * @param \question_edit_contexts $contexts the relevant question bank contexts. 1092 * @param array $pagevars the variables from {@link \question_edit_setup()}. 1093 * @param \moodle_url $pageurl the canonical URL of this page. 1094 * @return bool Always returns true 1095 */ 1096 protected function initialise_editing_javascript(structure $structure, 1097 \question_edit_contexts $contexts, array $pagevars, \moodle_url $pageurl) { 1098 1099 $config = new \stdClass(); 1100 $config->resourceurl = '/mod/quiz/edit_rest.php'; 1101 $config->sectionurl = '/mod/quiz/edit_rest.php'; 1102 $config->pageparams = array(); 1103 $config->questiondecimalpoints = $structure->get_decimal_places_for_question_marks(); 1104 $config->pagehtml = $this->new_page_template($structure, $contexts, $pagevars, $pageurl); 1105 $config->addpageiconhtml = $this->add_page_icon_template($structure); 1106 1107 $this->page->requires->yui_module('moodle-mod_quiz-toolboxes', 1108 'M.mod_quiz.init_resource_toolbox', 1109 array(array( 1110 'courseid' => $structure->get_courseid(), 1111 'quizid' => $structure->get_quizid(), 1112 'ajaxurl' => $config->resourceurl, 1113 'config' => $config, 1114 )) 1115 ); 1116 unset($config->pagehtml); 1117 unset($config->addpageiconhtml); 1118 1119 $this->page->requires->strings_for_js(array('areyousureremoveselected'), 'quiz'); 1120 $this->page->requires->yui_module('moodle-mod_quiz-toolboxes', 1121 'M.mod_quiz.init_section_toolbox', 1122 array(array( 1123 'courseid' => $structure, 1124 'quizid' => $structure->get_quizid(), 1125 'ajaxurl' => $config->sectionurl, 1126 'config' => $config, 1127 )) 1128 ); 1129 1130 $this->page->requires->yui_module('moodle-mod_quiz-dragdrop', 'M.mod_quiz.init_section_dragdrop', 1131 array(array( 1132 'courseid' => $structure, 1133 'quizid' => $structure->get_quizid(), 1134 'ajaxurl' => $config->sectionurl, 1135 'config' => $config, 1136 )), null, true); 1137 1138 $this->page->requires->yui_module('moodle-mod_quiz-dragdrop', 'M.mod_quiz.init_resource_dragdrop', 1139 array(array( 1140 'courseid' => $structure, 1141 'quizid' => $structure->get_quizid(), 1142 'ajaxurl' => $config->resourceurl, 1143 'config' => $config, 1144 )), null, true); 1145 1146 // Require various strings for the command toolbox. 1147 $this->page->requires->strings_for_js(array( 1148 'clicktohideshow', 1149 'deletechecktype', 1150 'deletechecktypename', 1151 'edittitle', 1152 'edittitleinstructions', 1153 'emptydragdropregion', 1154 'hide', 1155 'markedthistopic', 1156 'markthistopic', 1157 'move', 1158 'movecontent', 1159 'moveleft', 1160 'movesection', 1161 'page', 1162 'question', 1163 'selectall', 1164 'show', 1165 'tocontent', 1166 ), 'moodle'); 1167 1168 $this->page->requires->strings_for_js(array( 1169 'addpagebreak', 1170 'cannotremoveallsectionslots', 1171 'cannotremoveslots', 1172 'confirmremovesectionheading', 1173 'confirmremovequestion', 1174 'dragtoafter', 1175 'dragtostart', 1176 'numquestionsx', 1177 'sectionheadingedit', 1178 'sectionheadingremove', 1179 'removepagebreak', 1180 'questiondependencyadd', 1181 'questiondependencyfree', 1182 'questiondependencyremove', 1183 'questiondependsonprevious', 1184 ), 'quiz'); 1185 1186 foreach (\question_bank::get_all_qtypes() as $qtype => $notused) { 1187 $this->page->requires->string_for_js('pluginname', 'qtype_' . $qtype); 1188 } 1189 1190 return true; 1191 } 1192 1193 /** 1194 * HTML for a page, with ids stripped, so it can be used as a javascript template. 1195 * 1196 * @param structure $structure object containing the structure of the quiz. 1197 * @param \question_edit_contexts $contexts the relevant question bank contexts. 1198 * @param array $pagevars the variables from {@link \question_edit_setup()}. 1199 * @param \moodle_url $pageurl the canonical URL of this page. 1200 * @return string HTML for a new page. 1201 */ 1202 protected function new_page_template(structure $structure, 1203 \question_edit_contexts $contexts, array $pagevars, \moodle_url $pageurl) { 1204 if (!$structure->has_questions()) { 1205 return ''; 1206 } 1207 1208 $pagehtml = $this->page_row($structure, 1, $contexts, $pagevars, $pageurl); 1209 1210 // Normalise the page number. 1211 $pagenumber = $structure->get_page_number_for_slot(1); 1212 $strcontexts = array(); 1213 $strcontexts[] = 'page-'; 1214 $strcontexts[] = get_string('page') . ' '; 1215 $strcontexts[] = 'addonpage%3D'; 1216 $strcontexts[] = 'addonpage='; 1217 $strcontexts[] = 'addonpage="'; 1218 $strcontexts[] = get_string('addquestionfrombanktopage', 'quiz', ''); 1219 $strcontexts[] = 'data-addonpage%3D'; 1220 $strcontexts[] = 'action-menu-'; 1221 1222 foreach ($strcontexts as $strcontext) { 1223 $pagehtml = str_replace($strcontext . $pagenumber, $strcontext . '%%PAGENUMBER%%', $pagehtml); 1224 } 1225 1226 return $pagehtml; 1227 } 1228 1229 /** 1230 * HTML for a page, with ids stripped, so it can be used as a javascript template. 1231 * 1232 * @param structure $structure object containing the structure of the quiz. 1233 * @return string HTML for a new icon 1234 */ 1235 protected function add_page_icon_template(structure $structure) { 1236 1237 if (!$structure->has_questions()) { 1238 return ''; 1239 } 1240 1241 $html = $this->page_split_join_button($structure, 1); 1242 return str_replace('&slot=1&', '&slot=%%SLOT%%&', $html); 1243 } 1244 1245 /** 1246 * Return the contents of the question bank, to be displayed in the question-bank pop-up. 1247 * 1248 * @param \mod_quiz\question\bank\custom_view $questionbank the question bank view object. 1249 * @param array $pagevars the variables from {@link \question_edit_setup()}. 1250 * @return string HTML to output / send back in response to an AJAX request. 1251 */ 1252 public function question_bank_contents(\mod_quiz\question\bank\custom_view $questionbank, array $pagevars) { 1253 1254 $qbank = $questionbank->render('editq', $pagevars['qpage'], $pagevars['qperpage'], 1255 $pagevars['cat'], $pagevars['recurse'], $pagevars['showhidden'], $pagevars['qbshowtext'], 1256 $pagevars['qtagids']); 1257 return html_writer::div(html_writer::div($qbank, 'bd'), 'questionbankformforpopup'); 1258 } 1259 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body