Completed
Push — master ( 5f1c93...626f54 )
by Julito
31:28
created

FillBlanks::createAnswersForm()   D

Complexity

Conditions 9
Paths 18

Size

Total Lines 318
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 61
nc 18
nop 1
dl 0
loc 318
rs 4.8196
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 *	Class FillBlanks
6
 *
7
 *	@author Eric Marguin
8
 * 	@author Julio Montoya multiple fill in blank option added
9
 *	@package chamilo.exercise
10
 **/
11
class FillBlanks extends Question
12
{
13
    public static $typePicture = 'fill_in_blanks.png';
14
    public static $explanationLangVar = 'FillBlanks';
15
16
    const FILL_THE_BLANK_STANDARD = 0;
17
    const FILL_THE_BLANK_MENU = 1;
18
    const FILL_THE_BLANK_SEVERAL_ANSWER = 2;
19
20
    /**
21
     * Constructor
22
     */
23
    public function __construct()
24
    {
25
        parent::__construct();
26
        $this->type = FILL_IN_BLANKS;
27
        $this->isContent = $this->getIsContent();
28
    }
29
30
    /**
31
     * function which redefines Question::createAnswersForm
32
     * @param FormValidator $form
33
     */
34
    public function createAnswersForm($form)
35
    {
36
        //$fillBlanksAllowedSeparator = self::getAllowedSeparator();
37
        $defaults = array();
38
39
        if (!empty($this->id)) {
40
            $objectAnswer = new Answer($this->id);
41
            $answer = $objectAnswer->selectAnswer(1);
42
            $listAnswersInfo = FillBlanks::getAnswerInfo($answer);
43
            if ($listAnswersInfo['switchable']) {
44
                $defaults['multiple_answer'] = 1;
45
            } else {
46
                $defaults['multiple_answer'] = 0;
47
            }
48
            //take the complete string except after the last '::'
49
            $defaults['answer'] = $listAnswersInfo['text'];
50
            $defaults['select_separator'] = $listAnswersInfo['blankseparatornumber'];
51
            $blankSeparatorNumber = $listAnswersInfo['blankseparatornumber'];
52
        } else {
53
            $defaults['answer'] = get_lang('DefaultTextInBlanks');
54
            $defaults['select_separator'] = 0;
55
            $blankSeparatorNumber = 0;
56
        }
57
58
        $blankSeparatorStart = self::getStartSeparator($blankSeparatorNumber);
59
        $blankSeparatorEnd = self::getEndSeparator($blankSeparatorNumber);
60
61
        $setWeightAndSize = '';
62
        if (isset($listAnswersInfo) && count($listAnswersInfo['tabweighting']) > 0) {
63
            foreach ($listAnswersInfo['tabweighting'] as $i => $weighting) {
64
                $setWeightAndSize .= 'document.getElementById("weighting['.$i.']").value = "'.$weighting.'";';
65
            }
66
            foreach ($listAnswersInfo['tabinputsize'] as $i => $sizeOfInput) {
67
                //var_dump($listAnswersInfo['tabwords']);
68
                $setWeightAndSize .= 'document.getElementById("sizeofinput['.$i.']").value = "'.$sizeOfInput.'";';
69
                $setWeightAndSize .= 'document.getElementById("samplesize['.$i.']").style.width = "'.$sizeOfInput.'px";';
70
            }
71
        }
72
73
        echo '<script>
74
            
75
            var firstTime = true;            
76
            var originalOrder = new Array();   
77
            var blankSeparatorStart = "'.$blankSeparatorStart.'";
78
            var blankSeparatorEnd = "'.$blankSeparatorEnd.'";
79
            var blankSeparatorStartRegexp = getBlankSeparatorRegexp(blankSeparatorStart);
80
            var blankSeparatorEndRegexp = getBlankSeparatorRegexp(blankSeparatorEnd);
81
            var blanksRegexp = "/"+blankSeparatorStartRegexp+"[^"+blankSeparatorStartRegexp+"]*"+blankSeparatorEndRegexp+"/g";
82
            
83
            CKEDITOR.on("instanceCreated", function(e) {
84
                if (e.editor.name === "answer") {                  
85
                    //e.editor.on("change", updateBlanks);
86
                    e.editor.on("change", function(){
87
                        updateBlanks();
88
                    });
89
                }
90
            });                        
91
            
92
            function updateBlanks()
93
            {
94
                
95
                var answer;                
96
                if (firstTime) {
97
                    var field = document.getElementById("answer");
98
                    answer = field.value;
99
                } else {
100
                    answer = CKEDITOR.instances["answer"].getData();
101
                }
102
                                
103
                // disable the save button, if not blanks have been created
104
                $("button").attr("disabled", "disabled");
105
                $("#defineoneblank").show();                
106
                var blanks = answer.match(eval(blanksRegexp));             
107
                var fields = "<div class=\"form-group \">";                
108
                fields += "<label class=\"col-sm-2 control-label\">'.get_lang('Weighting').'</label>";
109
                fields += "<div class=\"col-sm-8\">";
110
                fields += "<table>";
111
                fields += "<tr><th style=\"padding:0 20px\">'.get_lang("WordTofind").'</th><th style=\"padding:0 20px\">'.get_lang("QuestionWeighting").'</th><th style=\"padding:0 20px\">'.get_lang("BlankInputSize").'</th></tr>";
112
113
                if (blanks != null) {
114
                    for (var i=0; i < blanks.length; i++) {
115
                        // remove forbidden characters that causes bugs
116
                        blanks[i] = removeForbiddenChars(blanks[i]);                        
117
                        // trim blanks between brackets
118
                        blanks[i] = trimBlanksBetweenSeparator(blanks[i], blankSeparatorStart, blankSeparatorEnd);
119
                        
120
                        // if the word is empty []
121
                        if (blanks[i] == blankSeparatorStartRegexp+blankSeparatorEndRegexp) {
122
                            break;
123
                        }
124
                        
125
                        // get input size
126
                        var inputSize = 200;                        
127
                        var textValue = blanks[i].substr(1, blanks[i].length - 2);
128
                        var btoaValue = textValue.hashCode();
129
                                                                      
130
                        if (firstTime == false) {
131
                            var element = document.getElementById("samplesize["+i+"]");                                
132
                            if (element) {
133
                                inputSize = document.getElementById("sizeofinput["+i+"]").value;                                
134
                            }
135
                        }                                                                    
136
137
                        if (document.getElementById("weighting["+i+"]")) {
138
                            var value = document.getElementById("weighting["+i+"]").value;
139
                        } else {
140
                            var value = "10";    
141
                        }                                            
142
                        
143
                        fields += "<tr>";
144
                        fields += "<td>"+blanks[i]+"</td>";
145
                        fields += "<td><input style=\"width:35px\" value=\""+value+"\" type=\"text\" id=\"weighting["+i+"]\" name=\"weighting["+i+"]\" /></td>";
146
                        fields += "<td>";
147
                        fields += "<input class=\"btn btn-default\" type=\"button\" value=\"-\" onclick=\"changeInputSize(-1, "+i+")\">&nbsp;";
148
                        fields += "<input class=\"btn btn-default\" type=\"button\" value=\"+\" onclick=\"changeInputSize(1, "+i+")\">&nbsp;";
149
                        fields += "<input class=\"sample\" id=\"samplesize["+i+"]\" data-btoa=\""+btoaValue+"\"   type=\"text\" value=\""+textValue+"\" style=\"width:"+inputSize+"px\" disabled=disabled />";
150
                        fields += "<input id=\"sizeofinput["+i+"]\" type=\"hidden\" value=\""+inputSize+"\" name=\"sizeofinput["+i+"]\"  />";
151
                        fields += "</td>";
152
                        fields += "</tr>";
153
                        
154
                        // enable the save button
155
                        $("button").removeAttr("disabled");
156
                        $("#defineoneblank").hide();
157
                    }
158
                }                         
159
                
160
                document.getElementById("blanks_weighting").innerHTML = fields + "</table></div></div>";                                
161
                $(originalOrder).each(function(i, data) {
162
                     if (firstTime == false) {
163
                        value = data.value;                        
164
                        var d = $("input.sample[data-btoa=\'"+value+"\']");                        
165
                        var id = d.attr("id");   
166
                        if (id) {
167
                            var sizeInputId = id.replace("samplesize", "sizeofinput");                            
168
                            var sizeInputId = sizeInputId.replace("[", "\\\[");
169
                            var sizeInputId = sizeInputId.replace("]", "\\\]");                       
170
                                                         
171
                            $("#"+sizeInputId).val(data.width);                        
172
                            d.outerWidth(data.width+"px");
173
                        }
174
                    }
175
                });
176
                
177
                updateOrder(blanks);               
178
179
                if (firstTime) {
180
                    firstTime = false;
181
                    '.$setWeightAndSize.'
182
                }
183
            }
184
185
            window.onload = updateBlanks;
186
            
187
            String.prototype.hashCode = function() {
188
  var hash = 0, i, chr, len;
189
  if (this.length === 0) return hash;
190
  for (i = 0, len = this.length; i < len; i++) {
191
    chr   = this.charCodeAt(i);
192
    hash  = ((hash << 5) - hash) + chr;
193
    hash |= 0; // Convert to 32bit integer
194
  }
195
  return hash;
196
};
197
            
198
            function updateOrder(blanks) 
199
            {
200
                originalOrder = new Array();                
201
                 if (blanks != null) {
202
                    for (var i=0; i < blanks.length; i++) {
203
                        // remove forbidden characters that causes bugs
204
                        blanks[i] = removeForbiddenChars(blanks[i]);                        
205
                        // trim blanks between brackets
206
                        blanks[i] = trimBlanksBetweenSeparator(blanks[i], blankSeparatorStart, blankSeparatorEnd);
207
                        
208
                        // if the word is empty []
209
                        if (blanks[i] == blankSeparatorStartRegexp+blankSeparatorEndRegexp) {
210
                            break;
211
                        }                        
212
                        var textValue = blanks[i].substr(1, blanks[i].length - 2);
213
                        var btoaValue = textValue.hashCode();
214
                        
215
                        if (firstTime == false) {
216
                            var element = document.getElementById("samplesize["+i+"]");                                
217
                            if (element) {
218
                                inputSize = document.getElementById("sizeofinput["+i+"]").value;
219
                                originalOrder.push({ "width" : inputSize, "value": btoaValue });                                                                               
220
                            }
221
                        }
222
                    }
223
                }
224
            }
225
            
226
            function changeInputSize(coef, inIdNum)
227
            {
228
                if (firstTime) {
229
                    var field = document.getElementById("answer");
230
                    answer = field.value;
231
                } else {
232
                    answer = CKEDITOR.instances["answer"].getData();
233
                }
234
                
235
                var blanks = answer.match(eval(blanksRegexp));
236
                var currentWidth = $("#samplesize\\\["+inIdNum+"\\\]").width();
237
                var newWidth = currentWidth + coef * 20;
238
                newWidth = Math.max(20, newWidth);
239
                newWidth = Math.min(newWidth, 600);
240
                $("#samplesize\\\["+inIdNum+"\\\]").outerWidth(newWidth);
241
                $("#sizeofinput\\\["+inIdNum+"\\\]").attr("value", newWidth);
242
                
243
                updateOrder(blanks); 
244
            }
245
246
            function removeForbiddenChars(inTxt)
247
            {
248
                outTxt = inTxt;
249
                outTxt = outTxt.replace(/&quot;/g, ""); // remove the   char
250
                outTxt = outTxt.replace(/\x22/g, ""); // remove the   char
251
                outTxt = outTxt.replace(/"/g, ""); // remove the   char
252
                outTxt = outTxt.replace(/\\\\/g, ""); // remove the \ char
253
                outTxt = outTxt.replace(/&nbsp;/g, " ");
254
                outTxt = outTxt.replace(/^ +/, "");
255
                outTxt = outTxt.replace(/ +$/, "");
256
                return outTxt;
257
            }
258
259
            function changeBlankSeparator()
260
            {
261
                var separatorNumber = $("#select_separator").val();
262
                var tabSeparator = getSeparatorFromNumber(separatorNumber);
263
                blankSeparatorStart = tabSeparator[0];
264
                blankSeparatorEnd = tabSeparator[1];
265
                blankSeparatorStartRegexp = getBlankSeparatorRegexp(blankSeparatorStart);
266
                blankSeparatorEndRegexp = getBlankSeparatorRegexp(blankSeparatorEnd);
267
                blanksRegexp = "/"+blankSeparatorStartRegexp+"[^"+blankSeparatorStartRegexp+"]*"+blankSeparatorEndRegexp+"/g";
268
                updateBlanks();
269
            }
270
271
            // this function is the same than the PHP one
272
            // if modify it modify the php one escapeForRegexp
273
            function getBlankSeparatorRegexp(inTxt)
274
            {
275
                var tabSpecialChar = new Array(".", "+", "*", "?", "[", "^", "]", "$", "(", ")",
276
                    "{", "}", "=", "!", "<", ">", "|", ":", "-", ")");
277
                for (var i=0; i < tabSpecialChar.length; i++) {
278
                    if (inTxt == tabSpecialChar[i]) {
279
                        return "\\\"+inTxt;
280
                    }
281
                }
282
                return inTxt;
283
            }
284
285
            // this function is the same than the PHP one
286
            // if modify it modify the php one getAllowedSeparator
287
            function getSeparatorFromNumber(innumber)
288
            {
289
                tabSeparator = new Array();
290
                tabSeparator[0] = new Array("[", "]");
291
                tabSeparator[1] = new Array("{", "}");
292
                tabSeparator[2] = new Array("(", ")");
293
                tabSeparator[3] = new Array("*", "*");
294
                tabSeparator[4] = new Array("#", "#");
295
                tabSeparator[5] = new Array("%", "%");
296
                tabSeparator[6] = new Array("$", "$");
297
                return tabSeparator[innumber];
298
            }
299
300
            function trimBlanksBetweenSeparator(inTxt, inSeparatorStart, inSeparatorEnd)
301
            {
302
                var result = inTxt
303
                result = result.replace(inSeparatorStart, "");
304
                result = result.replace(inSeparatorEnd, "");
305
                result = result.trim();
306
                return inSeparatorStart+result+inSeparatorEnd;
307
            }
308
        </script>';
309
310
        // answer
311
        $form->addLabel(
312
            null,
313
            '<br /><br />'.get_lang('TypeTextBelow').', '.get_lang('And').' '.get_lang('UseTagForBlank')
314
        );
315
        $form->addElement(
316
            'html_editor',
317
            'answer',
318
            Display::return_icon('fill_field.png'),
319
            ['id' => 'answer'],
320
            array('ToolbarSet' => 'TestQuestionDescription')
321
        );
322
        $form->addRule('answer', get_lang('GiveText'), 'required');
323
324
        //added multiple answers
325
        $form->addElement('checkbox', 'multiple_answer', '', get_lang('FillInBlankSwitchable'));
326
        $form->addElement(
327
            'select',
328
            'select_separator',
329
            get_lang("SelectFillTheBlankSeparator"),
330
            self::getAllowedSeparatorForSelect(),
331
            ' id="select_separator" style="width:150px" onchange="changeBlankSeparator()" '
332
        );
333
        $form->addLabel(
334
            null,
335
            '<input type="button" onclick="updateBlanks()" value="'.get_lang('RefreshBlanks').'" class="btn btn-default" />'
336
        );
337
        $form->addHtml('<div id="blanks_weighting"></div>');
338
339
        global $text;
340
        // setting the save button here and not in the question class.php
341
        $form->addHtml('<div id="defineoneblank" style="color:#D04A66; margin-left:160px">'.get_lang('DefineBlanks').'</div>');
342
        $form->addButtonSave($text, 'submitQuestion');
343
344
        if (!empty($this->id)) {
345
            $form->setDefaults($defaults);
346
        } else {
347
            if ($this->isContent == 1) {
348
                $form->setDefaults($defaults);
349
            }
350
        }
351
    }
352
353
    /**
354
     * Function which creates the form to create/edit the answers of the question
355
     * @param FormValidator $form
356
     */
357
    public function processAnswersCreation($form)
358
    {
359
        $answer = $form->getSubmitValue('answer');
360
        // Due the ckeditor transform the elements to their HTML value
361
362
        //$answer = api_html_entity_decode($answer, ENT_QUOTES, $charset);
363
        //$answer = htmlentities(api_utf8_encode($answer));
364
365
        // remove the :: eventually written by the user
366
        $answer = str_replace('::', '', $answer);
367
368
        // remove starting and ending space and &nbsp;
369
        $answer = api_preg_replace("/\xc2\xa0/", " ", $answer);
370
371
        // start and end separator
372
        $blankStartSeparator = self::getStartSeparator($form->getSubmitValue('select_separator'));
373
        $blankEndSeparator = self::getEndSeparator($form->getSubmitValue('select_separator'));
374
        $blankStartSeparatorRegexp = self::escapeForRegexp($blankStartSeparator);
375
        $blankEndSeparatorRegexp = self::escapeForRegexp($blankEndSeparator);
376
377
        // remove spaces at the beginning and the end of text in square brackets
378
        $answer = preg_replace_callback(
379
            "/".$blankStartSeparatorRegexp."[^]]+".$blankEndSeparatorRegexp."/",
380
            function ($matches) use ($blankStartSeparator, $blankEndSeparator) {
381
                $matchingResult = $matches[0];
382
                $matchingResult = trim($matchingResult, $blankStartSeparator);
383
                $matchingResult = trim($matchingResult, $blankEndSeparator);
384
                $matchingResult = trim($matchingResult);
385
                // remove forbidden chars
386
                $matchingResult = str_replace("/\\/", "", $matchingResult);
387
                $matchingResult = str_replace('/"/', "", $matchingResult);
388
389
                return $blankStartSeparator.$matchingResult.$blankEndSeparator;
390
            },
391
            $answer
392
        );
393
394
        // get the blanks weightings
395
        $nb = preg_match_all(
396
            '/'.$blankStartSeparatorRegexp.'[^'.$blankStartSeparatorRegexp.']*'.$blankEndSeparatorRegexp.'/',
397
            $answer,
398
            $blanks
399
        );
400
401
        if (isset($_GET['editQuestion'])) {
402
            $this->weighting = 0;
403
        }
404
405
        /* if we have some [tobefound] in the text
406
        build the string to save the following in the answers table
407
        <p>I use a [computer] and a [pen].</p>
408
        becomes
409
        <p>I use a [computer] and a [pen].</p>::100,50:100,50@1
410
            ++++++++-------**
411
            --- -- --- -- -
412
            A B  (C) (D)(E)
413
        +++++++ : required, weighting of each words
414
        ------- : optional, input width to display, 200 if not present
415
        ** : equal @1 if "Allow answers order switches" has been checked, @ otherwise
416
        A : weighting for the word [computer]
417
        B : weighting for the word [pen]
418
        C : input width for the word [computer]
419
        D : input width for the word [pen]
420
        E : equal @1 if "Allow answers order switches" has been checked, @ otherwise
421
        */
422
        if ($nb > 0) {
423
            $answer .= '::';
424
            // weighting
425
            for ($i=0; $i < $nb; ++$i) {
426
                // enter the weighting of word $i
427
                $answer .= $form->getSubmitValue('weighting['.$i.']');
428
                // not the last word, add ","
429
                if ($i != $nb - 1) {
430
                    $answer .= ",";
431
                }
432
                // calculate the global weighting for the question
433
                $this -> weighting += $form->getSubmitValue('weighting['.$i.']');
434
            }
435
436
            // input width
437
            $answer .= ":";
438
            for ($i=0; $i < $nb; ++$i) {
439
                // enter the width of input for word $i
440
                $answer .= $form->getSubmitValue('sizeofinput['.$i.']');
441
                // not the last word, add ","
442
                if ($i != $nb - 1) {
443
                    $answer .= ",";
444
                }
445
            }
446
        }
447
448
        // write the blank separator code number
449
        // see function getAllowedSeparator
450
        /*
451
            0 [...]
452
            1 {...}
453
            2 (...)
454
            3 *...*
455
            4 #...#
456
            5 %...%
457
            6 $...$
458
         */
459
        $answer .= ":".$form->getSubmitValue('select_separator');
460
461
        // Allow answers order switches
462
        $is_multiple = $form -> getSubmitValue('multiple_answer');
463
        $answer.= '@'.$is_multiple;
464
465
        $this->save();
466
        $objAnswer = new Answer($this->id);
467
        $objAnswer->createAnswer($answer, 0, '', 0, 1);
468
        $objAnswer->save();
469
    }
470
471
    /**
472
     * @param null $feedback_type
473
     * @param null $counter
474
     * @param null $score
475
     * @return string
476
     */
477 View Code Duplication
    public function return_header($feedback_type = null, $counter = null, $score = null)
478
    {
479
        $header = parent::return_header($feedback_type, $counter, $score);
480
        $header .= '<table class="'.$this->question_table_class .'">
481
            <tr>
482
                <th>'.get_lang("Answer").'</th>
483
            </tr>';
484
485
        return $header;
486
    }
487
488
    /**
489
     * @param string $separatorStartRegexp
490
     * @param string $separatorEndRegexp
491
     * @param string $correctItemRegexp
492
     * @param integer $questionId
493
     * @param $correctItem
494
     * @param $attributes
495
     * @param string $answer
496
     * @param $listAnswersInfo
497
     * @param boolean $displayForStudent
498
     * @param integer $inBlankNumber
499
     * @return string
500
     */
501
    public static function getFillTheBlankHtml(
502
        $separatorStartRegexp,
503
        $separatorEndRegexp,
504
        $correctItemRegexp,
505
        $questionId,
506
        $correctItem,
507
        $attributes,
508
        $answer,
509
        $listAnswersInfo,
510
        $displayForStudent,
511
        $inBlankNumber
512
    ) {
513
        $result = "";
514
        $inTabTeacherSolution = $listAnswersInfo['tabwords'];
515
        $inTeacherSolution = $inTabTeacherSolution[$inBlankNumber];
516
        switch (self::getFillTheBlankAnswerType($inTeacherSolution)) {
517
            case self::FILL_THE_BLANK_MENU:
518
                $selected = '';
519
                // the blank menu
520
                $optionMenu = '';
521
                // display a menu from answer separated with |
522
                // if display for student, shuffle the correct answer menu
523
                $listMenu = self::getFillTheBlankMenuAnswers($inTeacherSolution, $displayForStudent);
524
                $result .= '<select name="choice['.$questionId.'][]">';
525
                for ($k=0; $k < count($listMenu); $k++) {
526
                    $selected = "";
527
                    if ($correctItem == $listMenu[$k]) {
528
                        $selected = " selected=selected ";
529
                    }
530
                    // if in teacher view, display the first item by default, which is the right answer
531
                    if ($k==0 && !$displayForStudent) {
532
                        $selected = " selected=selected ";
533
                    }
534
                    $optionMenu .= '<option '.$selected.' value="'.$listMenu[$k].'">'.$listMenu[$k].'</option>';
535
                }
536
                if ($selected == "") {
537
                    // no good answer have been found...
538
                    $selected = " selected=selected ";
539
                }
540
                $result .= "<option $selected value=''>--</option>";
541
                $result .= $optionMenu;
542
                $result .= '</select>';
543
                break;
544
            case self::FILL_THE_BLANK_SEVERAL_ANSWER:
545
                //no break
546
            case self::FILL_THE_BLANK_STANDARD:
547
            default:
548
                $result = Display::input('text', "choice[$questionId][]", $correctItem, $attributes);
549
                break;
550
        }
551
552
        return $result;
553
    }
554
555
    /**
556
     * Return an array with the different choices available
557
     * when the answers between bracket show as a menu
558
     * @param string $correctAnswer
559
     * @param bool $displayForStudent true if we want to shuffle the choices of the menu for students
560
     *
561
     * @return array
562
     */
563
    public static function getFillTheBlankMenuAnswers($correctAnswer, $displayForStudent)
564
    {
565
        // if $inDisplayForStudent, then shuffle the result array
566
        $listChoises = api_preg_split("/\|/", $correctAnswer);
567
        if ($displayForStudent) {
568
            shuffle($listChoises);
569
        }
570
571
        return $listChoises;
572
    }
573
574
    /**
575
     * Return the array index of the student answer
576
     * @param string $correctAnswer the menu Choice1|Choice2|Choice3
577
     * @param string $studentAnswer the student answer must be Choice1 or Choice2 or Choice3
578
     *
579
     * @return int  in the example 0 1 or 2 depending of the choice of the student
580
     */
581
    public static function getFillTheBlankMenuAnswerNum($correctAnswer, $studentAnswer)
582
    {
583
        $listChoices = self::getFillTheBlankMenuAnswers($correctAnswer, false);
584
        foreach ($listChoices as $num => $value) {
585
            if ($value == $studentAnswer) {
586
                return $num;
587
            }
588
        }
589
590
        // should not happened, because student choose the answer in a menu of possible answers
591
        return -1;
592
    }
593
594
595
    /**
596
     * Return the possible answer if the answer between brackets is a multiple choice menu
597
     * @param string $correctAnswer
598
     *
599
     * @return array
600
     */
601
    public static function getFillTheBlankSeveralAnswers($correctAnswer)
602
    {
603
        // is answer||Answer||response||Response , mean answer or Answer ...
604
        $listSeveral = api_preg_split("/\|\|/", $correctAnswer);
605
606
        return $listSeveral;
607
    }
608
609
    /**
610
     * Return true if student answer is right according to the correctAnswer
611
     * it is not as simple as equality, because of the type of Fill The Blank question
612
     * eg : studentAnswer = 'Un' and correctAnswer = 'Un||1||un'
613
     * @param string $studentAnswer [studentanswer] of the info array of the answer field
614
     * @param string $correctAnswer [tabwords] of the info array of the answer field
615
     *
616
     * @return bool
617
     */
618
    public static function isGoodStudentAnswer($studentAnswer, $correctAnswer)
619
    {
620
        switch (self::getFillTheBlankAnswerType($correctAnswer)) {
621
            case self::FILL_THE_BLANK_MENU:
622
                $listMenu = self::getFillTheBlankMenuAnswers($correctAnswer, false);
623
                $result = $listMenu[0] == $studentAnswer;
624
                break;
625
            case self::FILL_THE_BLANK_SEVERAL_ANSWER:
626
                // the answer must be one of the choice made
627
                $listSeveral = self::getFillTheBlankSeveralAnswers($correctAnswer);
628
                $result = in_array($studentAnswer, $listSeveral);
629
                break;
630
            case self::FILL_THE_BLANK_STANDARD:
631
            default:
632
                $result = $studentAnswer == $correctAnswer;
633
                break;
634
        }
635
636
        return $result;
637
    }
638
639
    /**
640
     * @param string $correctAnswer
641
     *
642
     * @return int
643
     */
644
    public static function getFillTheBlankAnswerType($correctAnswer)
645
    {
646
        if (api_strpos($correctAnswer, "|") && !api_strpos($correctAnswer, "||")) {
647
            return self::FILL_THE_BLANK_MENU;
648
        } elseif (api_strpos($correctAnswer, "||")) {
649
            return self::FILL_THE_BLANK_SEVERAL_ANSWER;
650
        } else {
651
            return self::FILL_THE_BLANK_STANDARD;
652
        }
653
    }
654
655
    /**
656
     * Return information about the answer
657
     * @param string $userAnswer the text of the answer of the question
658
     * @param bool   $isStudentAnswer true if it's a student answer false the empty question model
659
     *
660
     * @return array of information about the answer
661
     */
662
    public static function getAnswerInfo($userAnswer = "", $isStudentAnswer = false)
663
    {
664
        $listAnswerResults = array();
665
        $listAnswerResults['text'] = '';
666
        $listAnswerResults['wordsCount'] = 0;
667
        $listAnswerResults['tabwordsbracket'] = array();
668
        $listAnswerResults['tabwords'] = array();
669
        $listAnswerResults['tabweighting'] = array();
670
        $listAnswerResults['tabinputsize'] = array();
671
        $listAnswerResults['switchable'] = '';
672
        $listAnswerResults['studentanswer'] = array();
673
        $listAnswerResults['studentscore'] = array();
674
        $listAnswerResults['blankseparatornumber'] = 0;
675
        $listDoubleColon = array();
676
677
        api_preg_match("/(.*)::(.*)$/s", $userAnswer, $listResult);
678
679
        if (count($listResult) < 2) {
680
            $listDoubleColon[] = '';
681
            $listDoubleColon[] = '';
682
        } else {
683
            $listDoubleColon[] = $listResult[1];
684
            $listDoubleColon[] = $listResult[2];
685
        }
686
687
        $listAnswerResults['systemstring'] = $listDoubleColon[1];
688
689
        // make sure we only take the last bit to find special marks
690
        $listArobaseSplit = explode('@', $listDoubleColon[1]);
691
692
        if (count($listArobaseSplit) < 2) {
693
            $listArobaseSplit[1] = '';
694
        }
695
696
        // take the complete string except after the last '::'
697
        $listDetails = explode(":", $listArobaseSplit[0]);
698
699
        // < number of item after the ::[score]:[size]:[separator_id]@ , here there are 3
700
        if (count($listDetails) < 3) {
701
            $listWeightings = explode(',', $listDetails[0]);
702
            $listSizeOfInput = array();
703
            for ($i=0; $i < count($listWeightings); $i++) {
704
                $listSizeOfInput[] = 200;
705
            }
706
            $blankSeparatorNumber = 0;    // 0 is [...]
707
        } else {
708
            $listWeightings = explode(',', $listDetails[0]);
709
            $listSizeOfInput = explode(',', $listDetails[1]);
710
            $blankSeparatorNumber = $listDetails[2];
711
        }
712
713
        $listAnswerResults['text'] = $listDoubleColon[0];
714
        $listAnswerResults['tabweighting'] = $listWeightings;
715
        $listAnswerResults['tabinputsize'] = $listSizeOfInput;
716
        $listAnswerResults['switchable'] = $listArobaseSplit[1];
717
        $listAnswerResults['blankseparatorstart'] = self::getStartSeparator($blankSeparatorNumber);
718
        $listAnswerResults['blankseparatorend'] = self::getEndSeparator($blankSeparatorNumber);
719
        $listAnswerResults['blankseparatornumber'] = $blankSeparatorNumber;
720
721
        $blankCharStart = self::getStartSeparator($blankSeparatorNumber);
722
        $blankCharEnd = self::getEndSeparator($blankSeparatorNumber);
723
        $blankCharStartForRegexp = self::escapeForRegexp($blankCharStart);
724
        $blankCharEndForRegexp = self::escapeForRegexp($blankCharEnd);
725
726
        // get all blanks words
727
        $listAnswerResults['wordsCount'] = api_preg_match_all(
728
            '/'.$blankCharStartForRegexp.'[^'.$blankCharEndForRegexp.']*'.$blankCharEndForRegexp.'/',
729
            $listDoubleColon[0],
730
            $listWords
731
        );
732
733
        if ($listAnswerResults['wordsCount'] > 0) {
734
            $listAnswerResults['tabwordsbracket'] = $listWords[0];
735
            // remove [ and ] in string
736
            array_walk(
737
                $listWords[0],
738
                function (&$value, $key, $tabBlankChar) {
739
                    $trimChars = "";
740
                    for ($i=0; $i < count($tabBlankChar); $i++) {
741
                        $trimChars .= $tabBlankChar[$i];
742
                    }
743
                    $value = trim($value, $trimChars);
744
                },
745
                array($blankCharStart, $blankCharEnd)
746
            );
747
            $listAnswerResults['tabwords'] = $listWords[0];
748
        }
749
750
        // get all common words
751
        $commonWords = api_preg_replace(
752
            '/'.$blankCharStartForRegexp.'[^'.$blankCharEndForRegexp.']*'.$blankCharEndForRegexp.'/',
753
            "::",
754
            $listDoubleColon[0]
755
        );
756
757
        // if student answer, the second [] is the student answer,
758
        // the third is if student scored or not
759
        $listBrackets = array();
760
        $listWords =  array();
761
762
        if ($isStudentAnswer) {
763
            for ($i=0; $i < count($listAnswerResults['tabwords']); $i++) {
764
                $listBrackets[] = $listAnswerResults['tabwordsbracket'][$i];
765
                $listWords[] = $listAnswerResults['tabwords'][$i];
766
                if ($i+1 < count($listAnswerResults['tabwords'])) {
767
                    // should always be
768
                    $i++;
769
                }
770
                $listAnswerResults['studentanswer'][] = $listAnswerResults['tabwords'][$i];
771
                if ($i+1 < count($listAnswerResults['tabwords'])) {
772
                    // should always be
773
                    $i++;
774
                }
775
                $listAnswerResults['studentscore'][] = $listAnswerResults['tabwords'][$i];
776
            }
777
            $listAnswerResults['tabwords'] = $listWords;
778
            $listAnswerResults['tabwordsbracket'] = $listBrackets;
779
780
            // if we are in student view, we've got 3 times :::::: for common words
781
            $commonWords = api_preg_replace("/::::::/", "::", $commonWords);
782
        }
783
784
        $listAnswerResults['commonwords'] = explode("::", $commonWords);
785
786
        return $listAnswerResults;
787
    }
788
789
    /**
790
    * Return an array of student state answers for fill the blank questions
791
    * for each students that answered the question
792
    * -2  : didn't answer
793
    * -1  : student answer is wrong
794
    *  0  : student answer is correct
795
    * >0  : for fill the blank question with choice menu, is the index of the student answer (right answer indice is 0)
796
    *
797
    * @param integer $testId
798
    * @param integer $questionId
799
    * @param $studentsIdList
800
    * @param string $startDate
801
    * @param string $endDate
802
    * @param bool $useLastAnswerredAttempt
803
    * @return array
804
    * (
805
    *     [student_id] => Array
806
    *         (
807
    *             [first fill the blank for question] => -1
808
    *             [second fill the blank for question] => 2
809
    *             [third fill the blank for question] => -1
810
    *         )
811
    * )
812
    */
813
    public static function getFillTheBlankTabResult(
814
        $testId,
815
        $questionId,
816
        $studentsIdList,
817
        $startDate,
818
        $endDate,
819
        $useLastAnswerredAttempt = true
820
    ) {
821
        $tblTrackEAttempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
822
        $tblTrackEExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
823
        $courseId = api_get_course_int_id();
824
        // request to have all the answers of student for this question
825
        // student may have doing it several time
826
        // student may have not answered the bracket id, in this case, is result of the answer is empty
827
        // we got the less recent attempt first
828
        $sql = 'SELECT * FROM '.$tblTrackEAttempt.' tea
829
               LEFT JOIN '.$tblTrackEExercise.' tee
830
               ON tee.exe_id = tea.exe_id
831
               AND tea.c_id = '.$courseId.'
832
               AND exe_exo_id = '.$testId.'    
833
               WHERE 
834
                tee.c_id = '.$courseId.' AND 
835
                question_id = '.$questionId.' AND 
836
                tea.user_id IN ('.implode(',', $studentsIdList).')  AND 
837
                tea.tms >= "'.$startDate.'" AND 
838
                tea.tms <= "'.$endDate.'"
839
               ORDER BY user_id, tea.exe_id;
840
        ';
841
842
        $res = Database::query($sql);
843
        $tabUserResult = array();
844
        $bracketNumber = 0;
845
        // foreach attempts for all students starting with his older attempt
846
        while ($data = Database::fetch_array($res)) {
847
            $tabAnswer = FillBlanks::getAnswerInfo($data['answer'], true);
848
849
            // for each bracket to find in this question
850
            foreach ($tabAnswer['studentanswer'] as $bracketNumber => $studentAnswer) {
851
                if ($tabAnswer['studentanswer'][$bracketNumber] != '') {
852
                    // student has answered this bracket, cool
853
                    switch (FillBlanks::getFillTheBlankAnswerType($tabAnswer['tabwords'][$bracketNumber])) {
854
                        case self::FILL_THE_BLANK_MENU:
855
                            // get the indice of the choosen answer in the menu
856
                            // we know that the right answer is the first entry of the menu, ie 0
857
                            // (remember, menu entries are shuffled when taking the test)
858
                            $tabUserResult[$data['user_id']][$bracketNumber] = FillBlanks::getFillTheBlankMenuAnswerNum(
859
                                $tabAnswer['tabwords'][$bracketNumber],
860
                                $tabAnswer['studentanswer'][$bracketNumber]
861
                            );
862
                            break;
863
                        default:
864
                            if (FillBlanks::isGoodStudentAnswer(
865
                                $tabAnswer['studentanswer'][$bracketNumber],
866
                                $tabAnswer['tabwords'][$bracketNumber]
867
                            )
868
                            ) {
869
                                $tabUserResult[$data['user_id']][$bracketNumber] = 0;   //  right answer
870
                            } else {
871
                                $tabUserResult[$data['user_id']][$bracketNumber] = -1;  // wrong answer
872
                            }
873
                    }
874
                } else {
875
                    // student didn't answer this bracket
876
                    if ($useLastAnswerredAttempt) {
877
                        // if we take into account the last answered attempt
878
                        if (!isset($tabUserResult[$data['user_id']][$bracketNumber])) {
879
                            $tabUserResult[$data['user_id']][$bracketNumber] = -2;      // not answered
880
                        }
881
                    } else {
882
                        // we take the last attempt, even if the student answer the question before
883
                        $tabUserResult[$data['user_id']][$bracketNumber] = -2;      // not answered
884
                    }
885
                }
886
            }
887
        }
888
889
        return $tabUserResult;
890
    }
891
892
    /**
893
     * Return the number of student that give at leat an answer in the fill the blank test
894
     * @param $resultList
895
     * @return int
896
     */
897
    public static function getNbResultFillBlankAll($resultList)
898
    {
899
        $outRes = 0;
900
        // for each student in group
901
        foreach ($resultList as $userId => $tabValue) {
902
            $found = false;
903
            // for each bracket, if student has at least one answer ( choice > -2) then he pass the question
904
            foreach ($tabValue as $i => $choice) {
905
                if ($choice > -2 && !$found) {
906
                    $outRes++;
907
                    $found = true;
908
                }
909
            }
910
        }
911
912
        return $outRes;
913
    }
914
915
    /**
916
     * Replace the occurrence of blank word with [correct answer][student answer][answer is correct]
917
     * @param array $listWithStudentAnswer
918
     *
919
     * @return string
920
     */
921
    public static function getAnswerInStudentAttempt($listWithStudentAnswer)
922
    {
923
        $separatorStart = $listWithStudentAnswer['blankseparatorstart'];
924
        $separatorEnd = $listWithStudentAnswer['blankseparatorend'];
925
        // lets rebuild the sentence with [correct answer][student answer][answer is correct]
926
        $result = "";
927
        for ($i=0; $i < count($listWithStudentAnswer['commonwords']) - 1; $i++) {
928
            $result .= $listWithStudentAnswer['commonwords'][$i];
929
            $result .= $listWithStudentAnswer['tabwordsbracket'][$i];
930
            $result .= $separatorStart.$listWithStudentAnswer['studentanswer'][$i].$separatorEnd;
931
            $result .= $separatorStart.$listWithStudentAnswer['studentscore'][$i].$separatorEnd;
932
        }
933
        $result .= $listWithStudentAnswer['commonwords'][$i];
934
        $result .= "::";
935
        // add the system string
936
        $result .= $listWithStudentAnswer['systemstring'];
937
938
        return $result;
939
    }
940
941
    /**
942
     * This function is the same than the js one above getBlankSeparatorRegexp
943
     * @param string $inChar
944
     *
945
     * @return string
946
     */
947
    public static function escapeForRegexp($inChar)
948
    {
949
        $listChars = [
950
            ".",
951
            "+",
952
            "*",
953
            "?",
954
            "[",
955
            "^",
956
            "]",
957
            "$",
958
            "(",
959
            ")",
960
            "{",
961
            "}",
962
            "=",
963
            "!",
964
            ">",
965
            "|",
966
            ":",
967
            "-",
968
            ")",
969
        ];
970
971
        if (in_array($inChar, $listChars)) {
972
            return "\\".$inChar;
973
        } else {
974
            return $inChar;
975
        }
976
    }
977
978
    /**
979
     * return $text protected for use in regexp
980
     * @param string $text
981
     *
982
     * @return string
983
     */
984
    public static function getRegexpProtected($text)
985
    {
986
        $listRegexpCharacters = [
987
            "/",
988
            ".",
989
            "+",
990
            "*",
991
            "?",
992
            "[",
993
            "^",
994
            "]",
995
            "$",
996
            "(",
997
            ")",
998
            "{",
999
            "}",
1000
            "=",
1001
            "!",
1002
            ">",
1003
            "|",
1004
            ":",
1005
            "-",
1006
            ")",
1007
        ];
1008
        $result = $text;
1009
        for ($i=0; $i < count($listRegexpCharacters); $i++) {
1010
            $result = str_replace($listRegexpCharacters[$i], "\\".$listRegexpCharacters[$i], $result);
1011
        }
1012
1013
        return $result;
1014
    }
1015
1016
1017
    /**
1018
     * This function must be the same than the js one getSeparatorFromNumber above
1019
     * @return array
1020
     */
1021
    public static function getAllowedSeparator()
1022
    {
1023
        $fillBlanksAllowedSeparator = array(
1024
            array('[', ']'),
1025
            array('{', '}'),
1026
            array('(', ')'),
1027
            array('*', '*'),
1028
            array('#', '#'),
1029
            array('%', '%'),
1030
            array('$', '$'),
1031
        );
1032
1033
        return $fillBlanksAllowedSeparator;
1034
    }
1035
1036
    /**
1037
     * return the start separator for answer
1038
     * @param string $number
1039
     *
1040
     * @return string
1041
     */
1042
    public static function getStartSeparator($number)
1043
    {
1044
        $listSeparators = self::getAllowedSeparator();
1045
1046
        return $listSeparators[$number][0];
1047
    }
1048
1049
    /**
1050
     * return the end separator for answer
1051
     * @param string $number
1052
     *
1053
     * @return string
1054
     */
1055
    public static function getEndSeparator($number)
1056
    {
1057
        $listSeparators = self::getAllowedSeparator();
1058
1059
        return $listSeparators[$number][1];
1060
    }
1061
1062
    /**
1063
     * Return as a description text, array of allowed separators for question
1064
     * eg: array("[...]", "(...)")
1065
     * @return array
1066
     */
1067
    public static function getAllowedSeparatorForSelect()
1068
    {
1069
        $listResults = array();
1070
        $fillBlanksAllowedSeparator = self::getAllowedSeparator();
1071
        for ($i=0; $i < count($fillBlanksAllowedSeparator); $i++) {
1072
            $listResults[] = $fillBlanksAllowedSeparator[$i][0]."...".$fillBlanksAllowedSeparator[$i][1];
1073
        }
1074
1075
        return $listResults;
1076
    }
1077
1078
    /**
1079
     * return the code number of the separator for the question
1080
     * @param string $startSeparator
1081
     * @param string $endSeparator
1082
     *
1083
     * @return int
1084
     */
1085
    public function getDefaultSeparatorNumber($startSeparator, $endSeparator)
1086
    {
1087
        $listSeparators = self::getAllowedSeparator();
1088
        $result = 0;
1089
        for ($i=0; $i < count($listSeparators); $i++) {
1090
            if ($listSeparators[$i][0] == $startSeparator &&
1091
                $listSeparators[$i][1] == $endSeparator
1092
            ) {
1093
                $result = $i;
1094
            }
1095
        }
1096
1097
        return $result;
1098
    }
1099
1100
    /**
1101
     * return the HTML display of the answer
1102
     * @param string $answer
1103
     * @param bool   $resultsDisabled
1104
     * @param bool $showTotalScoreAndUserChoices
1105
     *
1106
     * @return string
1107
     */
1108
    public static function getHtmlDisplayForAnswer(
1109
        $answer,
1110
        $resultsDisabled = false,
1111
        $showTotalScoreAndUserChoices = false
1112
    ) {
1113
        $result = '';
1114
        $listStudentAnswerInfo = self::getAnswerInfo($answer, true);
1115
1116 View Code Duplication
        if ($resultsDisabled == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT) {
1117
            if ($showTotalScoreAndUserChoices) {
1118
                $resultsDisabled = false;
1119
            } else {
1120
                $resultsDisabled = true;
1121
            }
1122
        }
1123
1124
        // rebuild the answer with good HTML style
1125
        // this is the student answer, right or wrong
1126
        for ($i=0; $i < count($listStudentAnswerInfo['studentanswer']); $i++) {
1127
            if ($listStudentAnswerInfo['studentscore'][$i] == 1) {
1128
                $listStudentAnswerInfo['studentanswer'][$i] = self::getHtmlRightAnswer(
1129
                    $listStudentAnswerInfo['studentanswer'][$i],
1130
                    $listStudentAnswerInfo['tabwords'][$i],
1131
                    $resultsDisabled
1132
                );
1133
            } else {
1134
                $listStudentAnswerInfo['studentanswer'][$i] = self::getHtmlWrongAnswer(
1135
                    $listStudentAnswerInfo['studentanswer'][$i],
1136
                    $listStudentAnswerInfo['tabwords'][$i],
1137
                    $resultsDisabled
1138
                );
1139
            }
1140
        }
1141
1142
        // rebuild the sentence with student answer inserted
1143
        for ($i=0; $i < count($listStudentAnswerInfo['commonwords']); $i++) {
1144
            $result .= isset($listStudentAnswerInfo['commonwords'][$i]) ? $listStudentAnswerInfo['commonwords'][$i] : '';
1145
            $result .= isset($listStudentAnswerInfo['studentanswer'][$i]) ? $listStudentAnswerInfo['studentanswer'][$i] : '';
1146
        }
1147
1148
        // the last common word (should be </p>)
1149
        $result .= isset($listStudentAnswerInfo['commonwords'][$i]) ? $listStudentAnswerInfo['commonwords'][$i] : '';
1150
1151
        return $result;
1152
    }
1153
1154
    /**
1155
     * return the HTML code of answer for correct and wrong answer
1156
     * @param string $answer
1157
     * @param string $correct
1158
     * @param string $right
1159
     * @param bool   $resultsDisabled
1160
     *
1161
     * @return string
1162
     */
1163
    public static function getHtmlAnswer($answer, $correct, $right, $resultsDisabled = false)
1164
    {
1165
        $style = "color: green";
1166
        if (!$right) {
1167
            $style = "color: red; text-decoration: line-through;";
1168
        }
1169
        $type = FillBlanks::getFillTheBlankAnswerType($correct);
1170
        switch ($type) {
1171
            case self::FILL_THE_BLANK_MENU:
1172
                $correctAnswerHtml = '';
1173
                $listPossibleAnswers = FillBlanks::getFillTheBlankMenuAnswers($correct, false);
1174
                $correctAnswerHtml .= "<span style='color: green'>".$listPossibleAnswers[0]."</span>";
1175
                $correctAnswerHtml .= " <span style='font-weight:normal'>(";
1176
                for ($i=1; $i < count($listPossibleAnswers); $i++) {
1177
                    $correctAnswerHtml .= $listPossibleAnswers[$i];
1178
                    if ($i != count($listPossibleAnswers) - 1) {
1179
                        $correctAnswerHtml .= " | ";
1180
                    }
1181
                }
1182
                $correctAnswerHtml .= ")</span>";
1183
                break;
1184
            case self::FILL_THE_BLANK_SEVERAL_ANSWER:
1185
                $listCorrects = explode("||", $correct);
1186
                $firstCorrect = $correct;
1187
                if (count($listCorrects) > 0) {
1188
                    $firstCorrect = $listCorrects[0];
1189
                }
1190
                $correctAnswerHtml = "<span style='color: green'>".$firstCorrect."</span>";
1191
                break;
1192
            case self::FILL_THE_BLANK_STANDARD:
1193
            default:
1194
                $correctAnswerHtml = "<span style='color: green'>".$correct."</span>";
1195
        }
1196
1197
        if ($resultsDisabled) {
1198
            $correctAnswerHtml = "<span title='".get_lang("ExerciseWithFeedbackWithoutCorrectionComment")."'> - </span>";
1199
        }
1200
1201
        $result = "<span style='border:1px solid black; border-radius:5px; padding:2px; font-weight:bold;'>";
1202
        $result .= "<span style='$style'>".$answer."</span>";
1203
        $result .= "&nbsp;<span style='font-size:120%;'>/</span>&nbsp;";
1204
        $result .= $correctAnswerHtml;
1205
        $result .= "</span>";
1206
1207
        return $result;
1208
    }
1209
1210
    /**
1211
     * return HTML code for correct answer
1212
     * @param string $answer
1213
     * @param string $correct
1214
     * @param bool   $resultsDisabled
1215
     *
1216
     * @return string
1217
     */
1218
    public static function getHtmlRightAnswer($answer, $correct, $resultsDisabled = false)
1219
    {
1220
        return self::getHtmlAnswer($answer, $correct, true, $resultsDisabled);
1221
    }
1222
1223
    /**
1224
     * return HTML code for wrong answer
1225
     * @param string $answer
1226
     * @param string $correct
1227
     * @param bool   $resultsDisabled
1228
     *
1229
     * @return string
1230
     */
1231
    public static function getHtmlWrongAnswer($answer, $correct, $resultsDisabled = false)
1232
    {
1233
        return self::getHtmlAnswer($answer, $correct, false, $resultsDisabled);
1234
    }
1235
1236
    /**
1237
     * Check if a answer is correct by its text
1238
     * @param string $answerText
1239
     * @return bool
1240
     */
1241
    public static function isCorrect($answerText)
1242
    {
1243
        $answerInfo = FillBlanks::getAnswerInfo($answerText, true);
1244
        $correctAnswerList = $answerInfo['tabwords'];
1245
        $studentAnswer = $answerInfo['studentanswer'];
1246
1247
        $isCorrect = true;
1248
1249
        foreach ($correctAnswerList as $i => $correctAnswer) {
1250
            $isGoodStudentAnswer = FillBlanks::isGoodStudentAnswer($studentAnswer[$i], $correctAnswer);
1251
1252
            $isCorrect = $isCorrect && $isGoodStudentAnswer;
1253
        }
1254
1255
        return $isCorrect;
1256
    }
1257
}
1258