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