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