ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilAssQuestionHintsGUI.php
Go to the documentation of this file.
1 <?php
2 
20 
36 {
40  public const CMD_SHOW_LIST = 'showList';
41  public const CMD_SHOW_HINT = 'showHint';
42  public const CMD_CONFIRM_DELETE = 'confirmDelete';
43  public const CMD_PERFORM_DELETE = 'performDelete';
44  public const CMD_SAVE_LIST_ORDER = 'saveListOrder';
45  public const CMD_CUT_TO_ORDERING_CLIPBOARD = 'cutToOrderingClipboard';
46  public const CMD_PASTE_FROM_ORDERING_CLIPBOARD_BEFORE = 'pasteFromOrderingClipboardBefore';
47  public const CMD_PASTE_FROM_ORDERING_CLIPBOARD_AFTER = 'pasteFromOrderingClipboardAfter';
48  public const CMD_RESET_ORDERING_CLIPBOARD = 'resetOrderingClipboard';
49  public const CMD_CONFIRM_SYNC = 'confirmSync';
50 
51  private $hintOrderingClipboard = null;
52  private ilLanguage $lng;
53  private ilCtrl $ctrl;
55 
59  protected $editingEnabled = false;
60  private \ilGlobalTemplateInterface $main_tpl;
61 
69  {
70  global $DIC;
71  $this->main_tpl = $DIC->ui()->mainTemplate();
72  $this->ctrl = $DIC->ctrl();
73  $this->lng = $DIC->language();
74  $this->questioninfo = $DIC->testQuestionPool()->questionInfo();
75  parent::__construct($questionGUI);
76 
77  $this->hintOrderingClipboard = new ilAssQuestionHintsOrderingClipboard($questionGUI->object);
78  }
79 
83  public function isEditingEnabled(): bool
84  {
85  return $this->editingEnabled;
86  }
87 
91  public function setEditingEnabled(bool $editingEnabled): void
92  {
93  $this->editingEnabled = $editingEnabled;
94  }
95 
96  public function executeCommand(): void
97  {
98  global $DIC;
99  $ilCtrl = $DIC['ilCtrl'];
100  $ilTabs = $DIC['ilTabs'];
101  $lng = $DIC['lng'];
102  global $DIC; /* @var \ILIAS\DI\Container $DIC */
103  $ilHelp = $DIC['ilHelp']; /* @var ilHelpGUI $ilHelp */
104  $ilHelp->setScreenIdComponent('qpl');
105 
106  $DIC->ui()->mainTemplate()->setCurrentBlock("ContentStyle");
107  $DIC->ui()->mainTemplate()->setVariable("LOCATION_CONTENT_STYLESHEET", ilObjStyleSheet::getContentStylePath(0));
108  $DIC->ui()->mainTemplate()->parseCurrentBlock();
109 
110  $cmd = $ilCtrl->getCmd(self::CMD_SHOW_LIST);
111  $nextClass = $ilCtrl->getNextClass($this);
112 
113  switch ($nextClass) {
114  case 'ilassquestionhintgui':
115  if (!$this->isEditingEnabled()) {
116  return;
117  }
118 
119  $gui = new ilAssQuestionHintGUI($this->questionGUI);
120  $ilCtrl->forwardCommand($gui);
121  break;
122 
123  case 'ilasshintpagegui':
124  if ($this->isEditingEnabled()) {
126  } else {
128  }
129 
130  $forwarder = new ilAssQuestionHintPageObjectCommandForwarder($this->questionOBJ, $ilCtrl, $ilTabs, $lng);
131  $forwarder->setPresentationMode($presentationMode);
132  $forwarder->forward();
133  break;
134 
135  default:
136  $this->tabs->setTabActive('tst_question_hints_tab');
137  $cmd .= 'Cmd';
138  $this->$cmd();
139  break;
140  }
141  }
142 
149  private function showListCmd(): void
150  {
151  global $DIC;
152  $ilCtrl = $DIC['ilCtrl'];
153  $tpl = $DIC['tpl'];
154  $lng = $DIC['lng'];
155 
157 
158  $toolbar = new ilToolbarGUI();
159 
160  $questionHintList = ilAssQuestionHintList::getListByQuestionId($this->questionOBJ->getId());
161 
162  if ($this->isEditingEnabled()) {
163  if ($this->hintOrderingClipboard->hasStored()) {
164  $questionHintList = $this->getQuestionHintListWithoutHintStoredInOrderingClipboard($questionHintList);
165 
166  $toolbar->addButton(
167  $lng->txt('tst_questions_hints_toolbar_cmd_reset_ordering_clipboard'),
168  $ilCtrl->getLinkTarget($this, self::CMD_RESET_ORDERING_CLIPBOARD)
169  );
170  } else {
171  $toolbar->addButton(
172  $lng->txt('tst_questions_hints_toolbar_cmd_add_hint'),
173  $ilCtrl->getLinkTargetByClass('ilAssQuestionHintGUI', ilAssQuestionHintGUI::CMD_SHOW_FORM)
174  );
175  }
176 
178  } else {
180  }
181 
182  $table = new ilAssQuestionHintsTableGUI(
183  $this->questionOBJ,
184  $questionHintList,
185  $this,
186  self::CMD_SHOW_LIST,
187  $tableMode,
188  $this->hintOrderingClipboard
189  );
190 
191  $tpl->setContent($ilCtrl->getHtml($toolbar) . $ilCtrl->getHtml($table));
192  }
193 
202  private function confirmDeleteCmd(): void
203  {
204  global $DIC;
205  $ilCtrl = $DIC['ilCtrl'];
206  $tpl = $DIC['tpl'];
207  $lng = $DIC['lng'];
208 
209  $hintIds = self::fetchHintIdsParameter();
210 
211  if (!count($hintIds)) {
212  $this->main_tpl->setOnScreenMessage('failure', $lng->txt('tst_question_hints_delete_hints_missing_selection_msg'), true);
213  $ilCtrl->redirect($this);
214  }
215 
216  $confirmation = new ilConfirmationGUI();
217 
218  $confirmation->setHeaderText($lng->txt('tst_question_hints_delete_hints_confirm_header'));
219  $confirmation->setFormAction($ilCtrl->getFormAction($this));
220  $confirmation->setConfirm($lng->txt('tst_question_hints_delete_hints_confirm_cmd'), self::CMD_PERFORM_DELETE);
221  $confirmation->setCancel($lng->txt('cancel'), self::CMD_SHOW_LIST);
222 
223  $questionHintList = ilAssQuestionHintList::getListByQuestionId($this->questionOBJ->getId());
224 
225  foreach ($questionHintList as $questionHint) {
226  /* @var $questionHint ilAssQuestionHint */
227 
228  if (in_array($questionHint->getId(), $hintIds)) {
229  $confirmation->addItem('hint_ids[]', $questionHint->getId(), sprintf(
230  $lng->txt('tst_question_hints_delete_hints_confirm_item'),
231  $questionHint->getIndex(),
232  $questionHint->getText()
233  ));
234  }
235  }
236 
237  $tpl->setContent($ilCtrl->getHtml($confirmation));
238  }
239 
247  private function performDeleteCmd(): void
248  {
249  if (!$this->isEditingEnabled()) {
250  return;
251  }
252 
253  global $DIC;
254  $ilCtrl = $DIC['ilCtrl'];
255  $tpl = $DIC['tpl'];
256  $lng = $DIC['lng'];
257 
258  $hintIds = self::fetchHintIdsParameter();
259 
260  if (!count($hintIds)) {
261  $this->main_tpl->setOnScreenMessage('failure', $lng->txt('tst_question_hints_delete_hints_missing_selection_msg'), true);
262  $ilCtrl->redirect($this);
263  }
264 
265  $questionCompleteHintList = ilAssQuestionHintList::getListByQuestionId($this->questionOBJ->getId());
266 
267  $questionRemainingHintList = new ilAssQuestionHintList();
268 
269  foreach ($questionCompleteHintList as $listKey => $questionHint) {
270  /* @var $questionHint ilAssQuestionHint */
271 
272  if (in_array($questionHint->getId(), $hintIds)) {
273  $questionHint->delete();
274  } else {
275  $questionRemainingHintList->addHint($questionHint);
276  }
277  }
278 
279  $questionRemainingHintList->reIndex();
280 
281  $this->main_tpl->setOnScreenMessage('success', $lng->txt('tst_question_hints_delete_success_msg'), true);
282 
283  $originalexists = $this->questioninfo->questionExistsInPool((int) $this->questionOBJ->getOriginalId());
284 
285  global $DIC;
286  $ilUser = $DIC['ilUser'];
287  if ($this->request->raw("calling_test") && $originalexists && assQuestion::_isWriteable($this->questionOBJ->getOriginalId(), $ilUser->getId())) {
288  $ilCtrl->redirectByClass('ilAssQuestionHintsGUI', ilAssQuestionHintsGUI::CMD_CONFIRM_SYNC);
289  }
290 
291  $ilCtrl->redirect($this);
292  }
293 
302  private function saveListOrderCmd(): void
303  {
304  if (!$this->isEditingEnabled()) {
305  return;
306  }
307 
308  global $DIC;
309  $ilCtrl = $DIC['ilCtrl'];
310  $lng = $DIC['lng'];
311 
312  $hintIndexes = self::orderHintIndexes(
313  self::fetchHintIndexesParameter()
314  );
315 
316  if (!count($hintIndexes)) {
317  $this->main_tpl->setOnScreenMessage('failure', $lng->txt('tst_question_hints_save_order_unkown_failure_msg'), true);
318  $ilCtrl->redirect($this);
319  }
320 
321  $curQuestionHintList = ilAssQuestionHintList::getListByQuestionId($this->questionOBJ->getId());
322 
323  $newQuestionHintList = new ilAssQuestionHintList();
324 
325  foreach ($hintIndexes as $hintId => $hintIndex) {
326  if (!$curQuestionHintList->hintExists($hintId)) {
327  $this->main_tpl->setOnScreenMessage('failure', $lng->txt('tst_question_hints_save_order_unkown_failure_msg'), true);
328  $ilCtrl->redirect($this);
329  }
330 
331  $questionHint = $curQuestionHintList->getHint($hintId);
332 
333  $newQuestionHintList->addHint($questionHint);
334  }
335 
336  $newQuestionHintList->reIndex();
337 
338  $this->main_tpl->setOnScreenMessage('success', $lng->txt('tst_question_hints_save_order_success_msg'), true);
339 
340  $originalexists = $this->questioninfo->questionExistsInPool((int) $this->questionOBJ->getOriginalId());
341 
342  global $DIC;
343  $ilUser = $DIC['ilUser'];
344  if ($this->request->raw("calling_test") && $originalexists && assQuestion::_isWriteable($this->questionOBJ->getOriginalId(), $ilUser->getId())) {
345  $ilCtrl->redirectByClass('ilAssQuestionHintsGUI', ilAssQuestionHintsGUI::CMD_CONFIRM_SYNC);
346  }
347 
348  $ilCtrl->redirect($this);
349  }
350 
357  private function cutToOrderingClipboardCmd(): void
358  {
359  if (!$this->isEditingEnabled()) {
360  return;
361  }
362 
363  global $DIC;
364  $ilCtrl = $DIC['ilCtrl'];
365 
366  $moveHintIds = self::fetchHintIdsParameter();
367  $this->checkForSingleHintIdAndRedirectOnFailure($moveHintIds);
368 
369  $moveHintId = current($moveHintIds);
370 
372 
373  $this->hintOrderingClipboard->setStored($moveHintId);
374 
375  $ilCtrl->redirect($this, self::CMD_SHOW_LIST);
376  }
377 
385  private function pasteFromOrderingClipboardBeforeCmd(): void
386  {
387  if (!$this->isEditingEnabled()) {
388  return;
389  }
390 
391  global $DIC;
392  $ilCtrl = $DIC['ilCtrl'];
393  $lng = $DIC['lng'];
394 
395  $targetHintIds = self::fetchHintIdsParameter();
396  $this->checkForSingleHintIdAndRedirectOnFailure($targetHintIds);
397 
398  $targetHintId = current($targetHintIds);
399 
401 
402  $curQuestionHintList = ilAssQuestionHintList::getListByQuestionId($this->questionOBJ->getId());
403  $newQuestionHintList = new ilAssQuestionHintList($this->questionOBJ->getId());
404 
405  foreach ($curQuestionHintList as $questionHint) {
406  /* @var $questionHint ilAssQuestionHint */
407 
408  if ($questionHint->getId() == $this->hintOrderingClipboard->getStored()) {
409  continue;
410  }
411 
412  if ($questionHint->getId() == $targetHintId) {
413  $targetQuestionHint = $questionHint;
414 
415  $pasteQuestionHint = ilAssQuestionHint::getInstanceById($this->hintOrderingClipboard->getStored());
416 
417  $newQuestionHintList->addHint($pasteQuestionHint);
418  }
419 
420  $newQuestionHintList->addHint($questionHint);
421  }
422 
423  $successMsg = sprintf(
424  $lng->txt('tst_question_hints_paste_before_success_msg'),
425  $pasteQuestionHint->getIndex(),
426  $targetQuestionHint->getIndex()
427  );
428 
429  $newQuestionHintList->reIndex();
430 
431  $this->hintOrderingClipboard->resetStored();
432 
433  $this->main_tpl->setOnScreenMessage('success', $successMsg, true);
434 
435  $ilCtrl->redirect($this, self::CMD_SHOW_LIST);
436  }
437 
445  private function pasteFromOrderingClipboardAfterCmd(): void
446  {
447  if (!$this->isEditingEnabled()) {
448  return;
449  }
450 
451  global $DIC;
452  $ilCtrl = $DIC['ilCtrl'];
453  $lng = $DIC['lng'];
454 
455  $targetHintIds = self::fetchHintIdsParameter();
456  $this->checkForSingleHintIdAndRedirectOnFailure($targetHintIds);
457 
458  $targetHintId = current($targetHintIds);
459 
461 
462  $curQuestionHintList = ilAssQuestionHintList::getListByQuestionId($this->questionOBJ->getId());
463  $newQuestionHintList = new ilAssQuestionHintList($this->questionOBJ->getId());
464 
465  foreach ($curQuestionHintList as $questionHint) {
466  /* @var $questionHint ilAssQuestionHint */
467 
468  if ($questionHint->getId() == $this->hintOrderingClipboard->getStored()) {
469  continue;
470  }
471 
472  $newQuestionHintList->addHint($questionHint);
473 
474  if ($questionHint->getId() == $targetHintId) {
475  $targetQuestionHint = $questionHint;
476 
477  $pasteQuestionHint = ilAssQuestionHint::getInstanceById($this->hintOrderingClipboard->getStored());
478 
479  $newQuestionHintList->addHint($pasteQuestionHint);
480  }
481  }
482 
483  $successMsg = sprintf(
484  $lng->txt('tst_question_hints_paste_after_success_msg'),
485  $pasteQuestionHint->getIndex(),
486  $targetQuestionHint->getIndex()
487  );
488 
489  $newQuestionHintList->reIndex();
490 
491  $this->hintOrderingClipboard->resetStored();
492 
493  $this->main_tpl->setOnScreenMessage('success', $successMsg, true);
494 
495  $ilCtrl->redirect($this, self::CMD_SHOW_LIST);
496  }
497 
505  private function resetOrderingClipboardCmd(): void
506  {
507  global $DIC;
508  $ilCtrl = $DIC['ilCtrl'];
509  $lng = $DIC['lng'];
510 
511  $this->hintOrderingClipboard->resetStored();
512 
513  $this->main_tpl->setOnScreenMessage('info', $lng->txt('tst_question_hints_ordering_clipboard_resetted'), true);
514  $ilCtrl->redirect($this, self::CMD_SHOW_LIST);
515  }
516 
524  private function initHintOrderingClipboardNotification(): void
525  {
526  global $DIC;
527  $lng = $DIC['lng'];
528 
529  if (!$this->hintOrderingClipboard->hasStored()) {
530  return;
531  }
532 
533  $questionHint = ilAssQuestionHint::getInstanceById($this->hintOrderingClipboard->getStored());
534 
535  $this->main_tpl->setOnScreenMessage('info', sprintf(
536  $lng->txt('tst_question_hints_item_stored_in_ordering_clipboard'),
537  $questionHint->getIndex()
538  ));
539  }
540 
549  {
550  $questionHintList = ilAssQuestionHintList::getListByQuestionId($this->questionOBJ->getId());
551 
552  if (!$questionHintList->hintExists($hintId)) {
553  $this->main_tpl->setOnScreenMessage('failure', $this->lng->txt('tst_question_hints_invalid_hint_id'), true);
554  $this->ctrl->redirect($this, self::CMD_SHOW_LIST);
555  }
556  }
557 
567  {
568  $filteredQuestionHintList = new ilAssQuestionHintList();
569 
570  foreach ($questionHintList as $questionHint) {
571  /* @var $questionHint ilAssQuestionHint */
572 
573  if ($questionHint->getId() != $this->hintOrderingClipboard->getStored()) {
574  $filteredQuestionHintList->addHint($questionHint);
575  }
576  }
577 
578  return $filteredQuestionHintList;
579  }
580 
590  private function checkForSingleHintIdAndRedirectOnFailure($hintIds): void
591  {
592  global $DIC;
593  $ilCtrl = $DIC['ilCtrl'];
594  $lng = $DIC['lng'];
595 
596  if (!count($hintIds)) {
597  $this->main_tpl->setOnScreenMessage('failure', $lng->txt('tst_question_hints_cut_hints_missing_selection_msg'), true);
598  $ilCtrl->redirect($this, self::CMD_SHOW_LIST);
599  } elseif (count($hintIds) > 1) {
600  $this->main_tpl->setOnScreenMessage('failure', $lng->txt('tst_question_hints_cut_hints_single_selection_msg'), true);
601  $ilCtrl->redirect($this, self::CMD_SHOW_LIST);
602  }
603  }
604 
613  private static function fetchHintIdsParameter(): array
614  {
615  global $DIC;
616  $request = $DIC->testQuestionPool()->internal()->request();
617  $hintIds = array();
618 
619  if (isset($_POST['hint_ids']) && is_array($_POST['hint_ids'])) {
620  foreach ($_POST['hint_ids'] as $hintId) {
621  if ((int) $hintId) {
622  $hintIds[] = (int) $hintId;
623  }
624  }
625  } elseif ($request->isset('hint_id') && (int) $request->raw('hint_id')) {
626  $hintIds[] = (int) $request->raw('hint_id');
627  }
628 
629  return $hintIds;
630  }
631 
639  private static function fetchHintIndexesParameter(): array
640  {
641  $hintIndexes = array();
642 
643  if (isset($_POST['hint_indexes']) && is_array($_POST['hint_indexes'])) {
644  foreach ($_POST['hint_indexes'] as $hintId => $hintIndex) {
645  if ((int) $hintId) {
646  $hintIndexes[(int) $hintId] = $hintIndex;
647  }
648  }
649  }
650 
651  return $hintIndexes;
652  }
653 
662  private static function orderHintIndexes($hintIndexes): array
663  {
664  asort($hintIndexes);
665 
666  return $hintIndexes;
667  }
668 
669  public function confirmSyncCmd(): void
670  {
671  $this->questionGUI->originalSyncForm('showHints');
672  }
673 
681  public function getHintPresentationLinkTarget($hintId, $xmlStyle = true): string
682  {
683  global $DIC;
684  $ilCtrl = $DIC['ilCtrl'];
685 
686  if ($this->questionOBJ->isAdditionalContentEditingModePageObject()) {
687  $ilCtrl->setParameterByClass('ilasshintpagegui', 'hint_id', $hintId);
688  $linkTarget = $ilCtrl->getLinkTargetByClass('ilAssHintPageGUI', '', '', false, $xmlStyle);
689  } else {
690  $ilCtrl->setParameter($this, 'hintId', $hintId);
691  $linkTarget = $ilCtrl->getLinkTarget($this, self::CMD_SHOW_HINT, '', false, $xmlStyle);
692  }
693 
694  return $linkTarget;
695  }
696 
705  private function showHintCmd(): void
706  {
707  global $DIC;
708  $ilCtrl = $DIC['ilCtrl'];
709  $tpl = $DIC['tpl'];
710  $lng = $DIC['lng'];
711 
712  if (!$this->request->isset('hintId') || !(int) $this->request->raw('hintId')) {
713  throw new ilTestException('no hint id given');
714  }
715 
716  $DIC->tabs()->clearTargets();
717  $DIC->tabs()->clearSubTabs();
718 
719  $DIC->tabs()->setBackTarget(
720  $DIC->language()->txt('tst_question_hints_back_to_hint_list'),
721  $DIC->ctrl()->getLinkTarget($this, self::CMD_SHOW_LIST)
722  );
723 
724  $questionHint = ilAssQuestionHint::getInstanceById((int) $this->request->raw('hintId'));
725 
726  // build form
727 
728  $form = new ilPropertyFormGUI();
729 
730  $form->setFormAction($ilCtrl->getFormAction($this));
731 
732  $form->setTableWidth('100%');
733 
734  $form->setTitle(sprintf(
735  $lng->txt('tst_question_hints_form_header_edit'),
736  $questionHint->getIndex(),
737  $this->questionOBJ->getTitleForHTMLOutput()
738  ));
739 
740  // form input: hint text
741 
742  $nonEditableHintText = new ilNonEditableValueGUI($lng->txt('tst_question_hints_form_label_hint_text'), 'hint_text', true);
743  $nonEditableHintText->setValue(ilLegacyFormElementsUtil::prepareTextareaOutput($questionHint->getText(), true));
744  $form->addItem($nonEditableHintText);
745 
746  // form input: hint points
747 
748  $nonEditableHintPoints = new ilNonEditableValueGUI($lng->txt('tst_question_hints_form_label_hint_points'), 'hint_points');
749  $nonEditableHintPoints->setValue($questionHint->getPoints());
750  $form->addItem($nonEditableHintPoints);
751 
752  $tpl->setContent($form->getHTML());
753  }
754 }
static getListByQuestionId($questionId)
instantiates a question hint list for the passed question id
static orderHintIndexes($hintIndexes)
sorts the array of indexes by index value so keys (hint ids) get into new order submitted by user ...
getHintPresentationLinkTarget($hintId, $xmlStyle=true)
returns the link target for hint request presentation
static getInstanceById($hintId)
creates a hint object instance, loads the persisted hint dataset identified by passed hint id from da...
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
ILIAS TestQuestionPool InternalRequestService $request
showListCmd()
shows a table with existing hints
showHintCmd()
shows an allready requested hint
static fetchHintIdsParameter()
fetches either an array of hint ids from POST or a single hint id from GET and returns an array of (a...
const CMD_SHOW_LIST
command constants
getQuestionHintListWithoutHintStoredInOrderingClipboard(ilAssQuestionHintList $questionHintList)
returns a new quastion hint list that contains all question hints from the passed list except for the...
Base Exception for all Exceptions relating to Modules/Test.
__construct(assQuestionGUI $questionGUI)
Constructor.
global $DIC
Definition: feed.php:28
resetOrderingClipboardCmd()
resets the ordering clipboard
__construct(VocabulariesInterface $vocabularies)
const TBL_MODE_TESTOUTPUT
the available table modes controlling the tables behaviour
cutToOrderingClipboardCmd()
cuts a hint from question hint list and stores it to ordering clipboard
pasteFromOrderingClipboardAfterCmd()
pastes a hint from ordering clipboard after the selected one
Basic GUI class for assessment questions.
static getContentStylePath(int $a_style_id, bool $add_random=true, bool $add_token=true)
get content style path static (to avoid full reading)
confirmDeleteCmd()
shows a confirmation screen with selected hints for deletion
performDeleteCmd()
performs confirmed deletion for selected hints
const CMD_SHOW_FORM
command constants
static fetchHintIndexesParameter()
fetches an array of hint index values from POST
ilGlobalTemplateInterface $main_tpl
pasteFromOrderingClipboardBeforeCmd()
pastes a hint from ordering clipboard before the selected one
addHint(ilAssQuestionHint $questionHint)
saveListOrderCmd()
saves the order based on index values passed from table&#39;s form (the table must not be paginated...
static _isWriteable(int $question_id, int $user_id)
checkForSingleHintIdAndRedirectOnFailure($hintIds)
checks for a hint id in the passed array and redirects with corresponding failure message if not exac...
setEditingEnabled(bool $editingEnabled)
initHintOrderingClipboardNotification()
inits the notification telling the user, that a hint is stored to hint ordering clipboard ...
static prepareTextareaOutput(string $txt_output, bool $prepare_for_latex_output=false, bool $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output where latex code may be in it If the text is HTML-free...
checkForExistingHintRelatingToCurrentQuestionAndRedirectOnFailure($hintId)
checks for an existing hint relating to current question and redirects with corresponding failure mes...