adding some strings
[moodle-linuxchix.git] / mod / hotpot / template / v6 / jquiz6.js_
blobcf1a4f73cfa149c7ecdda0a4c002a7c08a221fda
2 [inclScorm1.2]
3 //JQUIZ-SPECIFIC SCORM-RELATED JAVASCRIPT CODE
5 function SetScormScore(){
6 //Reports the current score and any other information back to the LMS
7         if (API != null){
8                 API.LMSSetValue('cmi.core.score.raw', Score);
9 //Now send detailed reports about each item
10                 for (var i=0; i<State.length; i++){
11                         if (State[i] != null){
12                                 var ItemLabel = 'Item_' + (i+1).toString();
13                                 var ThisItemScore = '';
14                                 var ThisItemStatus = '';
15                                 API.LMSSetValue('cmi.objectives.' + i + '.id', 'obj'+ItemLabel);
16                                 API.LMSSetValue('cmi.interactions.' + i + '.id', 'int'+ItemLabel);
17                                 API.LMSSetValue('cmi.objectives.' + i + '.score.min', '0');
18                                 API.LMSSetValue('cmi.objectives.' + i + '.score.max', '100');
19                                 if (State[i][2] > 0){
20                                         ThisItemScore = Math.floor(State[i][0] * 100) + '';
21                                         ThisItemStatus = 'completed';
22                                 }
23                                 else{
24                                         ThisItemScore = '0';
25                                         ThisItemStatus = 'incomplete';
26                                 }
27                                 API.LMSSetValue('cmi.objectives.' + i + '.score.raw', ThisItemScore);
28                                 API.LMSSetValue('cmi.objectives.' + i + '.status', ThisItemStatus);
29                                 API.LMSSetValue('cmi.interactions.' + i + '.weighting', I[i][0]);
30 //We can only use the performance type, because we're storing multiple responses of various types.
31                                 API.LMSSetValue('cmi.interactions.' + i + '.type', 'performance');
32                                 API.LMSSetValue('cmi.interactions.' + i + '.student_response', State[i][5]);
33                         }
34                 }
35                 
36                 API.LMSCommit('');
37         }
39 [/inclScorm1.2]
41 //JQUIZ CORE JAVASCRIPT CODE
43 var CurrQNum = 0;
44 var CorrectIndicator = '[strCorrectIndicator]';
45 var IncorrectIndicator = '[strIncorrectIndicator]';
46 var YourScoreIs = '[strYourScoreIs]';
47 var ContinuousScoring = [boolContinuousScoring];
48 var CorrectFirstTime = '[strCorrectFirstTime]';
49 var ShowCorrectFirstTime = [boolShowCorrectFirstTime];
50 var ShuffleQs = [boolShuffleQs];
51 var ShuffleAs = [boolShuffleAs];
52 var DefaultRight = '[strDefaultRight]';
53 var DefaultWrong = '[strDefaultWrong]';
54 var QsToShow = [QsToShow];
55 var Score = 0;
56 var Finished = false;
57 var Qs = null;
58 var QArray = new Array();
59 var ShowingAllQuestions = false;
60 var ShowAllQuestionsCaption = '[strShowAllQuestionsCaptionJS]';
61 var ShowOneByOneCaption = '[strShowOneByOneCaptionJS]';
62 var State = new Array();
63 var Feedback = '';
64 var TimeOver = false;
65 var strInstructions = '';
66 var Locked = false;
68 //The following variable can be used to add a message explaining that
69 //the question is finished, so no further marking will take place.
70 var strQuestionFinished = '';
72 function CompleteEmptyFeedback(){
73         var QNum, ANum;
74         for (QNum=0; QNum<I.length; QNum++){
75 //Only do this if not multi-select
76                 if (I[QNum][2] != '3'){
77                 for (ANum = 0; ANum<I[QNum][3].length; ANum++){
78                         if (I[QNum][3][ANum][1].length < 1){
79                                 if (I[QNum][3][ANum][2] > 0){
80                                         I[QNum][3][ANum][1] = DefaultRight;
81                                 }
82                                 else{
83                                         I[QNum][3][ANum][1] = DefaultWrong;
84                                 }
85                         }
86                 }
87                 }
88         }
91 function SetUpQuestions(){
92         var AList = new Array(); 
93         var QList = new Array();
94         var i, j;
95         Qs = document.getElementById('Questions');
96         while (Qs.getElementsByTagName('li').length > 0){
97                 QList.push(Qs.removeChild(Qs.getElementsByTagName('li')[0]));
98         }
99         var DumpItem = 0;
100         if (QsToShow > QList.length){
101                 QsToShow = QList.length;
102         }
103         while (QsToShow < QList.length){
104                 DumpItem = Math.floor(QList.length*Math.random());
105                 for (j=DumpItem; j<(QList.length-1); j++){
106                         QList[j] = QList[j+1];
107                 }
108                 QList.length = QList.length-1;
109         }
110         if (ShuffleQs == true){
111                 QList = Shuffle(QList);
112         }
113         if (ShuffleAs == true){
114                 var As;
115                 for (var i=0; i<QList.length; i++){
116                         As = QList[i].getElementsByTagName('ol')[0];
117                         if (As != null){
118                         AList.length = 0;
119                                 while (As.getElementsByTagName('li').length > 0){
120                                         AList.push(As.removeChild(As.getElementsByTagName('li')[0]));
121                                 }
122                                 AList = Shuffle(AList);
123                                 for (j=0; j<AList.length; j++){
124                                         As.appendChild(AList[j]);
125                                 }
126                         }
127                 }
128         }
129         
130         for (i=0; i<QList.length; i++){
131                 Qs.appendChild(QList[i]);
132                 QArray[QArray.length] = QList[i];
133         }
135 //Show the first item
136         QArray[0].style.display = '';
137         
138 //Now hide all except the first item
139         for (i=1; i<QArray.length; i++){
140                 QArray[i].style.display = 'none';
141         }               
142         SetQNumReadout();
143         
144         SetFocusToTextbox();
147 function SetFocusToTextbox(){
148 //if there's a textbox, set the focus in it
149         if (QArray[CurrQNum].getElementsByTagName('input')[0] != null){
150                 QArray[CurrQNum].getElementsByTagName('input')[0].focus();
151 //and show a keypad if there is one
152                 if (document.getElementById('CharacterKeypad') != null){
153                         document.getElementById('CharacterKeypad').style.display = 'block';
154                 }
155         }
156         else{
157         if (QArray[CurrQNum].getElementsByTagName('textarea')[0] != null){
158                 QArray[CurrQNum].getElementsByTagName('textarea')[0].focus();   
159 //and show a keypad if there is one
160                         if (document.getElementById('CharacterKeypad') != null){
161                                 document.getElementById('CharacterKeypad').style.display = 'block';
162                         }
163                 }
164 //This added for 6.0.4.11: hide accented character buttons if no textbox
165                 else{
166                         if (document.getElementById('CharacterKeypad') != null){
167                                 document.getElementById('CharacterKeypad').style.display = 'none';
168                         }
169                 }
170         }
173 function ChangeQ(ChangeBy){
174 //The following line prevents moving to another question until the current
175 //question is answered correctly. Uncomment it to enable this behaviour. 
176 //      if (State[CurrQNum][0] == -1){return;}
177         if (((CurrQNum + ChangeBy) < 0)||((CurrQNum + ChangeBy) >= QArray.length)){return;}
178         QArray[CurrQNum].style.display = 'none';
179         CurrQNum += ChangeBy;
180         QArray[CurrQNum].style.display = '';
181 //Undocumented function added 10/12/2004
182         ShowSpecialReadingForQuestion();
183         SetQNumReadout();
184         SetFocusToTextbox();
187 var HiddenReadingShown = false;
188 function ShowSpecialReadingForQuestion(){
189 //Undocumented function for showing specific reading text elements which change with each question
190 //Added on 10/12/2004
191         if (document.getElementById('ReadingDiv') != null){
192                 if (HiddenReadingShown == true){
193                         document.getElementById('ReadingDiv').innerHTML = '';
194                 }
195                 if (QArray[CurrQNum] != null){
196 //Fix for 6.0.4.25
197                         var Children = QArray[CurrQNum].getElementsByTagName('div');
198                         for (var i=0; i<Children.length; i++){
199                         if (Children[i].className=="HiddenReading"){
200                                         document.getElementById('ReadingDiv').innerHTML = Children[i].innerHTML;
201                                         HiddenReadingShown = true;
202 //Hide the ShowAllQuestions button to avoid confusion
203                                         if (document.getElementById('ShowMethodButton') != null){
204                                                 document.getElementById('ShowMethodButton').style.display = 'none';
205                                         }
206                                 }
207                         }       
208                 }
209         }
212 function SetQNumReadout(){
213         document.getElementById('QNumReadout').innerHTML = (CurrQNum+1) + ' / ' + QArray.length;
214         if ((CurrQNum+1) >= QArray.length){
215                 if (document.getElementById('NextQButton') != null){
216                         document.getElementById('NextQButton').style.visibility = 'hidden';
217                 }
218         }
219         else{
220                 if (document.getElementById('NextQButton') != null){
221                         document.getElementById('NextQButton').style.visibility = 'visible';
222                 }
223         }
224         if (CurrQNum <= 0){
225                 if (document.getElementById('PrevQButton') != null){
226                         document.getElementById('PrevQButton').style.visibility = 'hidden';
227                 }
228         }
229         else{
230                 if (document.getElementById('PrevQButton') != null){
231                         document.getElementById('PrevQButton').style.visibility = 'visible';
232                 }
233         }
236 [strItemArray]
238 function StartUp(){
239         RemoveBottomNavBarForIE();
241 //If there's only one question, no need for question navigation controls
242         if (QsToShow < 2){
243                 document.getElementById('QNav').style.display = 'none';
244         }
245         
246 //Stash the instructions so they can be redisplayed
247         strInstructions = document.getElementById('InstructionsDiv').innerHTML;
248         
249 [inclScorm1.2]
250         ScormStartUp();
251 [/inclScorm1.2]
252         
253 [inclSendResults]
254         GetUserName();
255 [/inclSendResults]
256         
257 [inclPreloadImages]
258         PreloadImages([PreloadImageList]);
259 [/inclPreloadImages]
260         
261         CompleteEmptyFeedback();
263         SetUpQuestions();
264         ClearTextBoxes();
265         CreateStatusArray();
266         
267 [inclTimer]
268         setTimeout('StartTimer()', 50);
269 [/inclTimer]
270         
271 //Check search string for q parameter
272         if (document.location.search.length > 0){
273                 if (ShuffleQs == false){
274                         var JumpTo = parseInt(document.location.search.substring(1,document.location.search.length))-1;
275                         if (JumpTo <= QsToShow){
276                                 ChangeQ(JumpTo);
277                         }
278                 }
279         }
280 //Undocumented function added 10/12/2004
281         ShowSpecialReadingForQuestion();
284 function ShowHideQuestions(){
285         FuncBtnOut(document.getElementById('ShowMethodButton'));
286         document.getElementById('ShowMethodButton').style.display = 'none';
287         if (ShowingAllQuestions == false){
288                 for (var i=0; i<QArray.length; i++){
289                                 QArray[i].style.display = '';
290                         }
291                 document.getElementById('Questions').style.listStyleType = 'decimal';
292                 document.getElementById('OneByOneReadout').style.display = 'none';
293                 document.getElementById('ShowMethodButton').innerHTML = ShowOneByOneCaption;
294                 ShowingAllQuestions = true;
295         }
296         else{
297                 for (var i=0; i<QArray.length; i++){
298                                 if (i != CurrQNum){
299                                         QArray[i].style.display = 'none';
300                                 }
301                         }
302                 document.getElementById('Questions').style.listStyleType = 'none';
303                 document.getElementById('OneByOneReadout').style.display = '';
304                 document.getElementById('ShowMethodButton').innerHTML = ShowAllQuestionsCaption;
305                 ShowingAllQuestions = false;    
306         }
307         document.getElementById('ShowMethodButton').style.display = 'inline';
310 function CreateStatusArray(){
311         var QNum, ANum;
312 //For each item in the item array
313         for (QNum=0; QNum<I.length; QNum++){
314 //Check if the question still exists (hasn't been nuked by showing a random selection)
315                 if (document.getElementById('Q_' + QNum) != null){
316                         State[QNum] = new Array();
317                         State[QNum][0] = -1; //Score for this q; -1 shows question not done yet
318                         State[QNum][1] = new Array(); //answers
319                         for (ANum = 0; ANum<I[QNum][3].length; ANum++){
320                                 State[QNum][1][ANum] = 0; //answer not chosen yet; when chosen, will store its position in the series of choices
321                         }
322                         State[QNum][2] = 0; //tries at this q so far
323                         State[QNum][3] = 0; //incrementing percent-correct values of selected answers
324                         State[QNum][4] = 0; //penalties incurred for hints
325                         State[QNum][5] = ''; //Sequence of answers chosen by number
326                 }
327                 else{
328                         State[QNum] = null;
329                 }
330         }
333 [inclMultiChoice]
335 function CheckMCAnswer(QNum, ANum, Btn){
336 //if question doesn't exist, bail
337         if (State[QNum].length < 1){return;}
338         
339 //Get the feedback
340         Feedback = I[QNum][3][ANum][1];
341         
342 //Now show feedback and bail if question already complete
343         if (State[QNum][0] > -1){
344 //Add an extra message explaining that the question
345 // is finished if defined by the user
346                 if (strQuestionFinished.length > 0){Feedback += '<br />' + strQuestionFinished;}
347 //Show the feedback
348                 ShowMessage(Feedback);
349                 return;
350         }
351         
352 //Hide the button while processing
353         Btn.style.display = 'none';
355 //Increment the number of tries
356         State[QNum][2]++;
357         
358 //Add the percent-correct value of this answer
359         State[QNum][3] += I[QNum][3][ANum][3];
360         
361 //Store the try number in the answer part of the State array, for tracking purposes
362         State[QNum][1][ANum] = State[QNum][2];
363         if (State[QNum][5].length > 0){State[QNum][5] += ' | ';}
364         State[QNum][5] += String.fromCharCode(65+ANum);
365         
366 //Should this answer be accepted as correct?
367         if (I[QNum][3][ANum][2] < 1){
368 //It's wrong
370 //Mark the answer
371                 Btn.innerHTML = IncorrectIndicator;
372                 
373 //Remove any previous score unless exercise is finished (6.0.3.8+)
374                 if (Finished == false){
375                         WriteToInstructions(strInstructions);
376                 }       
377                 
378 //Check whether this leaves just one MC answer unselected, in which case the Q is terminated
379                 var RemainingAnswer = FinalAnswer(QNum);
380                 if (RemainingAnswer > -1){
381 //Behave as if the last answer had been selected, but give no credit for it
382 //Increment the number of tries
383                         State[QNum][2]++;               
384                 
385 //Calculate the score for this question
386                         CalculateMCQuestionScore(QNum);
388 //Get the overall score and add it to the feedback
389                         CalculateOverallScore();
390                         if ((ContinuousScoring == true)||(Finished == true)){
391                                 Feedback += '<br />' + YourScoreIs + ' ' + Score + '%.';
392                                 WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
393                         }
394                 }
395         }
396         else{
397 //It's right
398 //Mark the answer
399                 Btn.innerHTML = CorrectIndicator;
400                                 
401 //Calculate the score for this question
402                 CalculateMCQuestionScore(QNum);
404 //Get the overall score and add it to the feedback
405                 if (ContinuousScoring == true){
406                         CalculateOverallScore();
407                         if ((ContinuousScoring == true)||(Finished == true)){
408                                 Feedback += '<br />' + YourScoreIs + ' ' + Score + '%.';
409                                 WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
410                         }
411                 }
412         }
413         
414 //Show the button again
415         Btn.style.display = 'inline';
416         
417 //Finally, show the feedback    
418         ShowMessage(Feedback);
419         
420 //Check whether all questions are now done
421         CheckFinished();
424 function CalculateMCQuestionScore(QNum){
425         var Tries = State[QNum][2] + State[QNum][4]; //include tries and hint penalties
426         var PercentCorrect = State[QNum][3];
427         var TotAns = GetTotalMCAnswers(QNum);
428         var HintPenalties = State[QNum][4];
429         
430 //Make sure it's not already complete
432         if (State[QNum][0] < 0){
433 //Allow for Hybrids
434                 if (HintPenalties >= 1){
435                         State[QNum][0] = 0;
436                 }
437                 else{
438 //This line calculates the score for this question
439                         if (TotAns == 1){
440                                 State[QNum][0] = 1;
441                         }
442                         else{
443                                 State[QNum][0] = ((TotAns-((Tries*100)/State[QNum][3]))/(TotAns-1));
444                         }
445                 }
446 //Fix for Safari bug added for version 6.0.3.42 (negative infinity problem)
447                 if ((State[QNum][0] < 0)||(State[QNum][0] == Number.NEGATIVE_INFINITY)){
448                         State[QNum][0] = 0;
449                 }
450         }
453 function GetTotalMCAnswers(QNum){
454         var Result = 0;
455         for (var ANum=0; ANum<I[QNum][3].length; ANum++){
456                 if (I[QNum][3][ANum][4] == 1){ //This is an MC answer
457                         Result++;
458                 }
459         }
460         return Result;
463 function FinalAnswer(QNum){
464         var UnchosenAnswers = 0;
465         var FinalAnswer = -1;
466         for (var ANum=0; ANum<I[QNum][3].length; ANum++){
467                 if (I[QNum][3][ANum][4] == 1){ //This is an MC answer
468                         if (State[QNum][1][ANum] < 1){ //This answer hasn't been chosen yet
469                                 UnchosenAnswers++;
470                                 FinalAnswer = ANum;
471                         }
472                 }
473         }
474         if (UnchosenAnswers == 1){
475                 return FinalAnswer;
476         }
477         else{
478                 return -1;
479         }
482 [/inclMultiChoice]
484 [inclMultiSelect]
486 function CheckMultiSelAnswer(QNum){
487 //bail if question doesn't exist or exercise finished
488         if ((State[QNum].length < 1)||(Finished == true)){return;}
490 //Increment the tries for this question
491         State[QNum][2]++;
492         
493         var ShouldBeChecked;
494         var Matches = 0;
495         if (State[QNum][5].length > 0){State[QNum][5] += ' | ';}
496         
497 //Check if there are any mismatches
498         Feedback = '';
499         var CheckBox = null;
500         for (var ANum=0; ANum<I[QNum][3].length; ANum++){
501                 CheckBox = document.getElementById('Q_' + QNum + '_' + ANum + '_Chk');
502                 if (CheckBox.checked == true){
503                         State[QNum][5] += 'Y';
504                 }
505                 else{
506                         State[QNum][5] += 'N';
507                 }
508                 ShouldBeChecked = (I[QNum][3][ANum][2] == 1);
509                 if (ShouldBeChecked == CheckBox.checked){
510                         Matches++;
511                 }
512                 else{
513                         Feedback = I[QNum][3][ANum][1];
514                 }
515         }
516 //Add the hit readout
517         Feedback = Matches + ' / ' + I[QNum][3].length + '<br />' + Feedback;
518         if (Matches == I[QNum][3].length){
519 //It's right
520                 CalculateMultiSelQuestionScore(QNum);
521                 if (ContinuousScoring == true){
522                         CalculateOverallScore();
523                         if ((ContinuousScoring == true)||(Finished == true)){
524                                 Feedback += '<br />' + YourScoreIs + ' ' + Score + '%.';
525                                 WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
526                         }
527                 }
528         }
529         else{
530 //It's wrong -- Remove any previous score unless exercise is finished (6.0.3.8+)
531                 if (Finished == false){
532                         WriteToInstructions(strInstructions);
533                 }       
534         }
535                 
536 //Show the feedback
537         ShowMessage(Feedback);
538         
539 //Check whether all questions are now done
540         CheckFinished();
543 function CalculateMultiSelQuestionScore(QNum){
544         var Tries = State[QNum][2];
545         var TotAns = State[QNum][1].length;
546         
547 //Make sure it's not already complete
548         if (State[QNum][0] < 0){
549                 State[QNum][0] = (TotAns - (Tries-1)) / TotAns;
550                 if (State[QNum][0] < 0){
551                         State[QNum][0] = 0;
552                 }
553         }
556 [/inclMultiSelect]
558 function CalculateOverallScore(){
559         var TotalWeighting = 0;
560         var TotalScore = 0;
561         
562         for (var QNum=0; QNum<State.length; QNum++){
563                 if (State[QNum] != null){
564                         if (State[QNum][0] > -1){
565                                 TotalWeighting += I[QNum][0];
566                                 TotalScore += (I[QNum][0] * State[QNum][0]);
567                         }
568                 }
569         }
570         if (TotalWeighting > 0){
571                 Score = Math.floor((TotalScore/TotalWeighting)*100);
572         }
573         else{
574 //if TotalWeighting is 0, no questions so far have any value, so 
575 //no penalty should be shown.
576                 Score = 100; 
577         }
580 function CheckFinished(){
581         var FB = '';
582         var AllDone = true;
583         for (var QNum=0; QNum<State.length; QNum++){
584                 if (State[QNum] != null){
585                         if (State[QNum][0] < 0){
586                                 AllDone = false;
587                         }
588                 }
589         }
590         if (AllDone == true){
591         
592 //Report final score and submit if necessary
593                 CalculateOverallScore();
594                 FB = YourScoreIs + ' ' + Score + '%.';
595                 if (ShowCorrectFirstTime == true){
596                         var CFT = 0;
597                         for (QNum=0; QNum<State.length; QNum++){
598                                 if (State[QNum] != null){
599                                         if (State[QNum][0] >= 1){
600                                                 CFT++;
601                                         }
602                                 }
603                         }
604                         FB += '<br />' + CorrectFirstTime + ' ' + CFT + '/' + QsToShow;
605                 }
606                 WriteToInstructions(FB);
607                 
608                 Finished == true;
609 [inclTimer]
610                 window.clearInterval(Interval);
611 [/inclTimer]
613 [inclScorm1.2]
614                 if (TimeOver == true){
615                         SetScormTimedOut();
616                 }
617                 else{
618                         SetScormComplete();
619                 }
620 [/inclScorm1.2]
622                 TimeOver = true;
623                 Locked = true;
624                 
625 [inclSendResults]
626                 setTimeout('SendResults(' + Score + ')', 50);
627 [/inclSendResults]
629                 Finished = true;
630                 Detail = '<?xml version="1.0"?><hpnetresult><fields>';
631                 for (QNum=0; QNum<State.length; QNum++){
632                         if (State[QNum] != null){
633                                 if (State[QNum][5].length > 0){
634                                         Detail += '<field><fieldname>Question #' + (QNum+1) + '</fieldname><fieldtype>question-tracking</fieldtype><fieldlabel>Q ' + (QNum+1) + '</fieldlabel><fieldlabelid>QuestionTrackingField</fieldlabelid><fielddata>' + State[QNum][5] + '</fielddata></field>';
635                                 }
636                         }
637                 }
638                 Detail += '</fields></hpnetresult>';
639                 setTimeout('Finish()', SubmissionTimeout);
640         }
641 [inclScorm1.2]
642         else{
643                 SetScormIncomplete();
644         }
645 [/inclScorm1.2]
648 [inclTimer]
649 function TimesUp(){
650         document.getElementById('Timer').innerHTML = '[strTimesUp]';
651 [inclPreloadImages]
652         RefreshImages();
653 [/inclPreloadImages]
654         TimeOver = true;
655         Finished = true;
656         ShowMessage('[strTimesUp]');
657         
658 //Set all remaining scores to 0
659         for (var QNum=0; QNum<State.length; QNum++){
660                 if (State[QNum] != null){
661                         if (State[QNum][0] < 0){
662                                 State[QNum][0] = 0;
663                         }
664                 }
665         }
666         CheckFinished();
668 [/inclTimer]