1<?php 2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4 5/** 6 * @author Björn Heyser <bheyser@databay.de> 7 * @version $Id$ 8 * 9 * @package Modules/TestQuestionPool 10 */ 11class ilTestQuestionNavigationGUI 12{ 13 const SHOW_DISABLED_COMMANDS = false; 14 15 const CSS_CLASS_SUBMIT_BUTTONS = 'ilc_qsubmit_Submit'; 16 17 /** 18 * @var ilLanguage 19 */ 20 protected $lng; 21 22 /** 23 * @var string 24 */ 25 private $editSolutionCommand = ''; 26 27 /** 28 * @var bool 29 */ 30 private $questionWorkedThrough = false; 31 32 /** 33 * @var string 34 */ 35 private $submitSolutionCommand = ''; 36 37 // fau: testNav - new variable for 'revert changes' link target 38 /** 39 * @var string 40 */ 41 private $revertChangesLinkTarget = ''; 42 // fau. 43 44 /** 45 * @var bool 46 */ 47 private $discardSolutionButtonEnabled = false; 48 49 /** 50 * @var string 51 */ 52 private $skipQuestionLinkTarget = ''; 53 54 /** 55 * @var string 56 */ 57 private $instantFeedbackCommand = ''; 58 59 /** 60 * @var bool 61 */ 62 private $answerFreezingEnabled = false; 63 64 /** 65 * @var bool 66 */ 67 private $forceInstantResponseEnabled = false; 68 69 /** 70 * @var string 71 */ 72 private $requestHintCommand = ''; 73 74 /** 75 * @var string 76 */ 77 private $showHintsCommand = ''; 78 79 /** 80 * @var bool 81 */ 82 private $hintRequestsExist = false; 83 84 // fau: testNav - change question mark command to link target 85 /** 86 * @var string 87 */ 88 private $questionMarkLinkTarget = ''; 89 // fau. 90 91 /** 92 * @var bool 93 */ 94 private $questionMarked = false; 95 96 /** 97 * @var bool 98 */ 99 private $charSelectorEnabled = false; 100 101 /** 102 * @var bool 103 */ 104 private $anythingRendered = false; 105 106 /** 107 * @param ilLanguage $lng 108 */ 109 public function __construct(ilLanguage $lng) 110 { 111 $this->lng = $lng; 112 } 113 114 /** 115 * @return string 116 */ 117 public function getEditSolutionCommand() 118 { 119 return $this->editSolutionCommand; 120 } 121 122 /** 123 * @param string $editSolutionCommand 124 */ 125 public function setEditSolutionCommand($editSolutionCommand) 126 { 127 $this->editSolutionCommand = $editSolutionCommand; 128 } 129 130 /** 131 * @return boolean 132 */ 133 public function isQuestionWorkedThrough() 134 { 135 return $this->questionWorkedThrough; 136 } 137 138 /** 139 * @param boolean $questionWorkedThrough 140 */ 141 public function setQuestionWorkedThrough($questionWorkedThrough) 142 { 143 $this->questionWorkedThrough = $questionWorkedThrough; 144 } 145 146 /** 147 * @return string 148 */ 149 public function getSubmitSolutionCommand() 150 { 151 return $this->submitSolutionCommand; 152 } 153 154 /** 155 * @param string $submitSolutionCommand 156 */ 157 public function setSubmitSolutionCommand($submitSolutionCommand) 158 { 159 $this->submitSolutionCommand = $submitSolutionCommand; 160 } 161 162 // fau: testNav - get/set revertChangesCommand 163 /** 164 * @return string 165 */ 166 public function getRevertChangesLinkTarget() 167 { 168 return $this->revertChangesLinkTarget; 169 } 170 171 /** 172 * @param string 173 */ 174 public function setRevertChangesLinkTarget($revertChangesLinkTarget) 175 { 176 $this->revertChangesLinkTarget = $revertChangesLinkTarget; 177 } 178 // fau. 179 180 /** 181 * @return bool 182 */ 183 public function isDiscardSolutionButtonEnabled() 184 { 185 return $this->discardSolutionButtonEnabled; 186 } 187 188 /** 189 * @param bool $discardSolutionButtonEnabled 190 */ 191 public function setDiscardSolutionButtonEnabled($discardSolutionButtonEnabled) 192 { 193 $this->discardSolutionButtonEnabled = $discardSolutionButtonEnabled; 194 } 195 196 /** 197 * @return string 198 */ 199 public function getSkipQuestionLinkTarget() 200 { 201 return $this->skipQuestionLinkTarget; 202 } 203 204 /** 205 * @param string $skipQuestionLinkTarget 206 */ 207 public function setSkipQuestionLinkTarget($skipQuestionLinkTarget) 208 { 209 $this->skipQuestionLinkTarget = $skipQuestionLinkTarget; 210 } 211 212 /** 213 * @return string 214 */ 215 public function getInstantFeedbackCommand() 216 { 217 return $this->instantFeedbackCommand; 218 } 219 220 /** 221 * @param string $instantFeedbackCommand 222 */ 223 public function setInstantFeedbackCommand($instantFeedbackCommand) 224 { 225 $this->instantFeedbackCommand = $instantFeedbackCommand; 226 } 227 228 /** 229 * @return boolean 230 */ 231 public function isAnswerFreezingEnabled() 232 { 233 return $this->answerFreezingEnabled; 234 } 235 236 /** 237 * @return boolean 238 */ 239 public function isForceInstantResponseEnabled() 240 { 241 return $this->forceInstantResponseEnabled; 242 } 243 244 /** 245 * @param boolean $forceInstantResponseEnabled 246 */ 247 public function setForceInstantResponseEnabled($forceInstantResponseEnabled) 248 { 249 $this->forceInstantResponseEnabled = $forceInstantResponseEnabled; 250 } 251 252 /** 253 * @param boolean $answerFreezingEnabled 254 */ 255 public function setAnswerFreezingEnabled($answerFreezingEnabled) 256 { 257 $this->answerFreezingEnabled = $answerFreezingEnabled; 258 } 259 260 /** 261 * @return string 262 */ 263 public function getRequestHintCommand() 264 { 265 return $this->requestHintCommand; 266 } 267 268 /** 269 * @param string $requestHintCommand 270 */ 271 public function setRequestHintCommand($requestHintCommand) 272 { 273 $this->requestHintCommand = $requestHintCommand; 274 } 275 276 /** 277 * @return string 278 */ 279 public function getShowHintsCommand() 280 { 281 return $this->showHintsCommand; 282 } 283 284 /** 285 * @param string $showHintsCommand 286 */ 287 public function setShowHintsCommand($showHintsCommand) 288 { 289 $this->showHintsCommand = $showHintsCommand; 290 } 291 292 /** 293 * @return boolean 294 */ 295 public function hintRequestsExist() 296 { 297 return $this->hintRequestsExist; 298 } 299 300 /** 301 * @param boolean $hintRequestsExist 302 */ 303 public function setHintRequestsExist($hintRequestsExist) 304 { 305 $this->hintRequestsExist = $hintRequestsExist; 306 } 307 308 // fau: testNav - change setter/getter of question mark command to link target 309 /** 310 * @return string 311 */ 312 public function getQuestionMarkLinkTarget() 313 { 314 return $this->questionMarkLinkTarget; 315 } 316 317 /** 318 * @param string $questionMarkLinkTarget 319 */ 320 public function setQuestionMarkLinkTarget($questionMarkLinkTarget) 321 { 322 $this->questionMarkLinkTarget = $questionMarkLinkTarget; 323 } 324 // fau. 325 326 /** 327 * @return boolean 328 */ 329 public function isQuestionMarked() 330 { 331 return $this->questionMarked; 332 } 333 334 /** 335 * @param boolean $questionMarked 336 */ 337 public function setQuestionMarked($questionMarked) 338 { 339 $this->questionMarked = $questionMarked; 340 } 341 342 /** 343 * @return boolean 344 */ 345 public function isAnythingRendered() 346 { 347 return $this->anythingRendered; 348 } 349 350 /** 351 * @param boolean $buttonRendered 352 */ 353 public function setAnythingRendered() 354 { 355 $this->anythingRendered = true; 356 } 357 358 /** 359 * @return boolean 360 */ 361 public function isCharSelectorEnabled() 362 { 363 return $this->charSelectorEnabled; 364 } 365 366 /** 367 * @param boolean $charSelectorEnabled 368 */ 369 public function setCharSelectorEnabled($charSelectorEnabled) 370 { 371 $this->charSelectorEnabled = $charSelectorEnabled; 372 } 373 374 // fau: testNav - generate question actions menu 375 /** 376 * Get the HTML of an actions menu below the title 377 * @return string 378 */ 379 public function getActionsHTML() 380 { 381 $tpl = $this->getTemplate('actions'); 382 383 include_once("Services/UIComponent/GroupedList/classes/class.ilGroupedListGUI.php"); 384 $actions = new ilGroupedListGUI(); 385 $actions->setAsDropDown(true, true); 386 387 if ($this->getQuestionMarkLinkTarget()) { 388 $actions->addEntry( 389 $this->getQuestionMarkActionLabel(), 390 $this->getQuestionMarkLinkTarget(), 391 '', 392 '', 393 'ilTestQuestionAction', 394 'tst_mark_question_action' 395 ); 396 $actions->addSeparator(); 397 } 398 399 if ($this->getRevertChangesLinkTarget()) { 400 $actions->addEntry( 401 $this->lng->txt('tst_revert_changes'), 402 $this->getRevertChangesLinkTarget(), 403 '', 404 '', 405 'ilTestQuestionAction ilTestRevertChangesAction', 406 'tst_revert_changes_action' 407 ); 408 } else { 409 $actions->addEntry( 410 $this->lng->txt('tst_revert_changes'), 411 '#', 412 '', 413 '', 414 'ilTestQuestionAction ilTestRevertChangesAction disabled', 415 'tst_revert_changes_action' 416 ); 417 } 418 419 if ($this->isDiscardSolutionButtonEnabled()) { 420 $actions->addEntry( 421 $this->lng->txt('discard_answer'), 422 '#', 423 '', 424 '', 425 'ilTestQuestionAction ilTestDiscardSolutionAction', 426 'tst_discard_solution_action' 427 ); 428 } else { 429 $actions->addEntry( 430 $this->lng->txt('discard_answer'), 431 '#', 432 '', 433 '', 434 'ilTestQuestionAction ilTestDiscardSolutionAction disabled', 435 'tst_discard_solution_action' 436 ); 437 } 438 439 if ($this->getSkipQuestionLinkTarget()) { 440 $actions->addEntry( 441 $this->lng->txt('postpone_question'), 442 $this->getSkipQuestionLinkTarget(), 443 '', 444 '', 445 'ilTestQuestionAction', 446 'tst_skip_question_action' 447 ); 448 } elseif (self::SHOW_DISABLED_COMMANDS) { 449 $actions->addEntry( 450 $this->lng->txt('postpone_question'), 451 '#', 452 '', 453 '', 454 'ilTestQuestionAction disabled', 455 'tst_skip_question_action' 456 ); 457 } 458 459 if ($this->isCharSelectorEnabled()) { 460 $actions->addSeparator(); 461 $actions->addEntry( 462 $this->lng->txt('char_selector_btn_label'), 463 '#', 464 '', 465 '', 466 'ilTestQuestionAction ilCharSelectorMenuToggle', 467 'ilCharSelectorMenuToggleLink' 468 ); 469 } 470 471 // render the mark icon 472 if ($this->getQuestionMarkLinkTarget()) { 473 $this->renderActionsIcon( 474 $tpl, 475 $this->getQuestionMarkIconSource(), 476 $this->getQuestionMarkIconLabel(), 477 'ilTestMarkQuestionIcon' 478 ); 479 } 480 481 // render the action menu 482 include_once './Services/UIComponent/AdvancedSelectionList/classes/class.ilAdvancedSelectionListGUI.php'; 483 $list = new ilAdvancedSelectionListGUI(); 484 $list->setSelectionHeaderClass('btn-primary'); 485 $list->setId('QuestionActions'); 486 $list->setListTitle($this->lng->txt("actions")); 487 $list->setStyle(1); 488 $list->setGroupedList($actions); 489 $tpl->setVariable('ACTION_MENU', $list->getHTML()); 490 491 return $tpl->get(); 492 } 493 // fau. 494 495 496 /** 497 * @return string 498 */ 499 public function getHTML() 500 { 501 // fau: testNav - add parameter for toolbar template purpose 502 $tpl = $this->getTemplate('toolbar'); 503 // fau. 504 if ($this->getEditSolutionCommand()) { 505 $this->renderSubmitButton( 506 $tpl, 507 $this->getEditSolutionCommand(), 508 $this->getEditSolutionButtonLabel() 509 ); 510 } 511 512 // fau: testNav - don't show the standard submit button. 513 // fau: testNav - discard answer is moved to the actions menu. 514 // fau: testNav - skip question (postpone) is moved to the actions menu. 515 516 if ($this->getInstantFeedbackCommand()) { 517 $this->renderSubmitButton( 518 $tpl, 519 $this->getInstantFeedbackCommand(), 520 $this->getCheckButtonLabel(), 521 $this->isForceInstantResponseEnabled() 522 ); 523 } 524 525 if ($this->getRequestHintCommand()) { 526 $this->renderSubmitButton( 527 $tpl, 528 $this->getRequestHintCommand(), 529 $this->getRequestHintButtonLabel() 530 ); 531 } 532 533 if ($this->getShowHintsCommand()) { 534 $this->renderSubmitButton( 535 $tpl, 536 $this->getShowHintsCommand(), 537 'button_show_requested_question_hints' 538 ); 539 } 540 541 // fau: testNav - question mark is moved to the actions menu. 542 // fau: testNav - char selector is moved to the actions menu. 543 544 if ($this->isAnythingRendered()) { 545 $this->parseNavigation($tpl); 546 } 547 548 return $tpl->get(); 549 } 550 551 private function getEditSolutionButtonLabel() 552 { 553 if ($this->isQuestionWorkedThrough()) { 554 return 'edit_answer'; 555 } 556 557 return 'answer_question'; 558 } 559 560 private function getSubmitSolutionButtonLabel() 561 { 562 if ($this->isForceInstantResponseEnabled()) { 563 return 'submit_and_check'; 564 } 565 566 // fau: testNav - rename the submit button to simply "Save" 567 return 'save'; 568 // fau. 569 } 570 571 private function getCheckButtonLabel() 572 { 573 if ($this->isAnswerFreezingEnabled()) { 574 return 'submit_and_check'; 575 } 576 577 return 'check'; 578 } 579 580 private function getRequestHintButtonLabel() 581 { 582 if ($this->hintRequestsExist()) { 583 return 'button_request_next_question_hint'; 584 } 585 586 return 'button_request_question_hint'; 587 } 588 589 // fau: testNav - adjust mark icon and action labels 590 private function getQuestionMarkActionLabel() 591 { 592 if ($this->isQuestionMarked()) { 593 return $this->lng->txt('tst_remove_mark'); 594 } 595 596 return $this->lng->txt('tst_question_mark'); 597 } 598 599 600 private function getQuestionMarkIconLabel() 601 { 602 if ($this->isQuestionMarked()) { 603 return $this->lng->txt('tst_question_marked'); 604 } 605 606 return$this->lng->txt('tst_question_not_marked'); 607 } 608 // fau. 609 610 private function getQuestionMarkIconSource() 611 { 612 if ($this->isQuestionMarked()) { 613 return ilUtil::getImagePath('marked.svg'); 614 } 615 616 return ilUtil::getImagePath('marked_.svg'); 617 } 618 619 // fau: testNav - add parameter for template purpose 620 /** 621 * Get the template 622 * @param string $a_purpose ('toolbar' | 'actions') 623 * @return ilTemplate 624 */ 625 private function getTemplate($a_purpose = 'toolbar') 626 { 627 switch ($a_purpose) { 628 case 'toolbar': 629 return new ilTemplate( 630 'tpl.tst_question_navigation.html', 631 true, 632 true, 633 'Modules/Test' 634 ); 635 636 case 'actions': 637 return new ilTemplate( 638 'tpl.tst_question_actions.html', 639 true, 640 true, 641 'Modules/Test' 642 ); 643 } 644 } 645 // fau. 646 647 /** 648 * @param ilTemplate $tpl 649 */ 650 private function parseNavigation(ilTemplate $tpl) 651 { 652 $tpl->setCurrentBlock('question_related_navigation'); 653 $tpl->parseCurrentBlock(); 654 } 655 656 /** 657 * @param ilTemplate $tpl 658 */ 659 private function parseButtonsBlock(ilTemplate $tpl) 660 { 661 $tpl->setCurrentBlock('buttons'); 662 $tpl->parseCurrentBlock(); 663 } 664 665 /** 666 * @param ilTemplate $tpl 667 * @param $button 668 */ 669 private function renderButtonInstance(ilTemplate $tpl, $button) 670 { 671 $tpl->setCurrentBlock("button_instance"); 672 $tpl->setVariable("BUTTON_INSTANCE", $button->render()); 673 $tpl->parseCurrentBlock(); 674 675 $this->parseButtonsBlock($tpl); 676 $this->setAnythingRendered(); 677 } 678 679 /** 680 * @param ilTemplate $tpl 681 * @param $command 682 * @param $label 683 * @param bool|false $primary 684 */ 685 private function renderSubmitButton(ilTemplate $tpl, $command, $label, $primary = false) 686 { 687 $button = ilSubmitButton::getInstance(); 688 $button->setCommand($command); 689 $button->setCaption($label); 690 $button->setPrimary($primary); 691 $button->addCSSClass(self::CSS_CLASS_SUBMIT_BUTTONS); 692 693 $this->renderButtonInstance($tpl, $button); 694 } 695 696 /** 697 * @param ilTemplate $tpl 698 * @param $htmlId 699 * @param $label 700 * @param $cssClass 701 */ 702 private function renderLinkButton(ilTemplate $tpl, $href, $label) 703 { 704 $button = ilLinkButton::getInstance(); 705 $button->setUrl($href); 706 $button->setCaption($label); 707 708 $this->renderButtonInstance($tpl, $button); 709 } 710 711 /** 712 * @param ilTemplate $tpl 713 * @param $htmlId 714 * @param $label 715 * @param $cssClass 716 */ 717 private function renderJsLinkedButton(ilTemplate $tpl, $htmlId, $label, $cssClass) 718 { 719 $button = ilLinkButton::getInstance(); 720 $button->setId($htmlId); 721 $button->addCSSClass($cssClass); 722 $button->setCaption($label); 723 724 $this->renderButtonInstance($tpl, $button); 725 } 726 727 /** 728 * @param ilTemplate $tpl 729 * @param $command 730 * @param $iconSrc 731 * @param $label 732 * @param $cssClass 733 */ 734 private function renderIcon(ilTemplate $tpl, $command, $iconSrc, $label, $cssClass) 735 { 736 $tpl->setCurrentBlock("submit_icon"); 737 $tpl->setVariable("SUBMIT_ICON_CMD", $command); 738 $tpl->setVariable("SUBMIT_ICON_SRC", $iconSrc); 739 $tpl->setVariable("SUBMIT_ICON_TEXT", $label); 740 $tpl->setVariable("SUBMIT_ICON_CLASS", $cssClass); 741 $tpl->parseCurrentBlock(); 742 743 $this->parseButtonsBlock($tpl); 744 $this->setAnythingRendered(); 745 } 746 747 // fau: testNav - render an icon beneath the actions menu 748 private function renderActionsIcon(ilTemplate $tpl, $iconSrc, $label, $cssClass) 749 { 750 $tpl->setCurrentBlock("actions_icon"); 751 $tpl->setVariable("ICON_SRC", $iconSrc); 752 $tpl->setVariable("ICON_TEXT", $label); 753 $tpl->setVariable("ICON_CLASS", $cssClass); 754 $tpl->parseCurrentBlock(); 755 } 756 // fau. 757} 758