| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <!-- 2 // PLEASE NOTE that this version is more recent than the incorrectly 3 // numbered v6.1, dated 2003.11.17. From now on, version numbers will 4 // follow those of Hot Potatoes. 5 /* hot-potatoes.js (v6.0.4.0 - 2005.02.18) 6 * ======================================= 7 * by Gordon Bateson, February 2003 8 * Copyright (c) 2003 Gordon Bateson. All Rights Reserved. 9 * 10 * You are hereby granted a royalty free license to use or modify this 11 * software provided that this copyright notice appears on all copies. 12 * 13 * This software is provided "AS IS" without a warranty of any kind. 14 * 15 * Documentation and downloads may be available from: 16 * http://www.kanazawa-gu.ac.jp/~gordon/research/hot-potatoes/ 17 */ 18 // This JavaScript library modifies the SendResults and StartUp functions 19 // used by hotpot v5 and v6, so that more (or less!) details about the 20 // student can be input, and more details of a quiz's questions and answers 21 // can be submitted to the server when the quiz is finished 22 // If the arrays below (Login, DB, JBC, ...) are set BEFORE calling this 23 // script, they will NOT be overwritten. Any array that is not set, will 24 // use the defaults below. This is useful if you want to use different 25 // settings for different quizzes. 26 // ************ 27 // Login Screen 28 // ************ 29 if (window.Login==null) { 30 Login = new Array(); 31 Login[0] = true; // Show prompt for user name 32 // This can also be a string of user names ... 33 // Login[0] = "Guest,Peter,Paul,Mary,Webmaster"; 34 // or an array of user names (and on-screen texts) (and passwords) ... 35 // Login[0] = new Array("Guest", "001,Peter,xxxx", "002,Paul,yyyy", "003,Mary,zzzz", "Webmaster"); 36 // and can also be written as ... 37 // Login[0] = new Array( 38 // new Array("Guest"), 39 // new Array("001", "Peter", "xxxx"), 40 // new Array("002", "Paul", "yyyy"), 41 // new Array("003", "Mary", "zzzz"), 42 // new Array("Webmaster") 43 // ); 44 Login[1] = true; // Show prompt for student's UserID 45 // If there is no password prompt (i.e. Logon[3] is false), this value 46 // will be checked against the password information, if any, in Login[0] 47 Login[2] = false; // Show prompt for student's email 48 Login[3] = false; // Show prompt for quiz password, and check this value against 49 // the password information, if any, in Login[0] 50 // This can also be a string required to start the quiz ... 51 // Login[3] = "password"; 52 Login[4] = true; // Show prompt for the cookie expiry date 53 // If false, cookies expire at the end of the current session 54 Login[5] = "guest,webmaster" 55 // guest user names (case insensitive) ... 56 // Login[5] = "guest,webmaster"; 57 // These users do NOT need to fill in other login fields 58 // and their quiz results are NOT added to the database 59 // the Login prompts and error messages 60 // are defined in the MSG array (see below) 61 } 62 // ********* 63 // Database (for use with BFormMail) 64 // ********* 65 if (window.DB==null) { 66 DB = new Array(); 67 DB[0] = true; // append form fields to database on server 68 // If you are NOT using BFormMail's database feature, 69 // set DB[0]=false, and you can then safely ignore DB[1 to 5] 70 DB[1] = "/home/gordon/public_html/cgi/hot-potatoes-data"; 71 // append_db folder path (no trailing slash) 72 // Can be either an absolute path e.g. "/home/gordon/public_html/cgi/hot-potatoes-data" 73 // or a relative (to CGI bin) path e.g. "hot-potatoes-data" 74 DB[2] = "hot-potatoes"; 75 // append_db file name (no extension) 76 // If left blank, the quiz file name, without extension, will be used 77 // i.e. each quiz will have its results stored in a different file. 78 // If filled in, this file will store the results for ALL quizzes. 79 // Database files and folders must be set up BEFORE running the quiz 80 // must have appropriate access privileges (on Unix, use "chmod 666"). 81 DB[3] = ""; // append_db extension (if left blank, ".txt" will be used) 82 DB[4] = ""; // db_fields (if left blank, ALL quiz fields will be sent) 83 DB[5] = ""; // db_delimiter (if left blank, tab will be used) 84 DB[6] = "REMOTE_ADDR,HTTP_USER_AGENT"; 85 // env_report ('REMOTE_ADDR','HTTP_USER_AGENT' and a few others) 86 // for a complete description of these fields are, see ... 87 // http://www.infosheet.com/stuff/BFormMail.readme 88 // Switches DB[7] and DB[8] force the settings in the ResultForm 89 // In v5 and v6 quizzes, these settings wil be override those in the original quiz 90 // If the quiz results are to be sent to an LMS (via the "store" form) 91 // then switches DB[7] and DB[8] are not used 92 DB[7] = ''; // URL of form processing script 93 // e.g. http://www.kanazawa-gu.ac.jp/~gordon/cgi/bformmail.cgi 94 DB[8] = ''; // email address to which results should be sent 95 // e.g. gordon@kanazawa-gu.ac.jp 96 } 97 // By default the quiz's question's scores will be returned. 98 // If you want more detailed information, set the flags below: 99 // ******** 100 // JBC 101 // ******** 102 if (window.JBC==null) { 103 JBC = new Array(); 104 JBC[0] = true; // show separator line between answers on email 105 JBC[1] = true; // show number of attempts to answer question 106 JBC[2] = true; // show question texts 107 JBC[3] = true; // show right answer(s) 108 JBC[4] = true; // show wrong answer(s) 109 JBC[5] = true; // show ignored answer(s) 110 JBC[6] = false; // show answer as text (false) or number (true) 111 } 112 // JBC quizzes use the global variables 'I' and 'Status' 113 // I : an array of JBC_QUESTIONs (one for each question) 114 // JBC_QUESTION : 115 // [0] : question text 116 // [1] : array of JBC_ANSWERs (one for each answer) 117 // [2] : single/multi flag 118 // 0 : single answer (using 'button') 119 // 1 : multiple answers (using 'checkbox') 120 // JBC_ANSWER : 121 // [0] : answer text 122 // [1] : answer feedback 123 // [2] : correct answer flag 124 // 0 : this is NOT the correct answer 125 // 1 : this is the correct answer 126 // Status : an array of JBC_QUESTION_STATUSes 127 // JBC_QUESTION_STATUS: 128 // [0] : correctly answered yet flag 129 // 0 : this question has NOT been correctly answered 130 // 1 : this question has been correctly answered 131 // [1] : array of JBC_ANSWER_STATUSes (one for each answer) 132 // '0' : initial value 133 // 'R' : single answer question was answered 'R'ight 134 // 'W' : single answer question was answered 'W'rong 135 // 'C' : multiple answer question's checkbox was 'C'hecked 136 // 'U' : multiple answer question's checkbox was 'U'nchecked 137 // [2] : number of times this question has been wrongly answered 138 // [3] : score (out of 1) for this question (maybe undefined on HP<5.5) 139 // 0 : not correct yet 140 // 0<[3]<1 : correct but only after [2] wrong attempts 141 // 1 : correct first time (bravo!) 142 // N.B. score = (numberOfAnswers - numberofWrongTries) / numberOfAnswers 143 // ******** 144 // JCloze 145 // ******** 146 if (window.JCloze==null) { 147 JCloze = new Array(); 148 JCloze[0] = true; // show separator line between answers on email 149 JCloze[1] = true; // show student's correct answer 150 JCloze[2] = true; // show other correct answer(s), if any 151 JCloze[3] = true; // show wrong answer(s), if any (NOT available for v5) 152 JCloze[4] = false; // show number of hints + checks (legacy field, replaced by [7]+[9]) 153 JCloze[5] = false; // show if clue was asked for or not (legacy field, replaced by [8]) 154 JCloze[6] = true; // show clue 155 JCloze[7] = true; // show number of hints (=next letter requests) 156 JCloze[8] = true; // show number of clues 157 JCloze[9] = true; // show number of checks 158 } 159 // JCloze quizzes use the global variables 'I' and 'State' 160 // I : array of JCLOZE_ANSWERs 161 // JCLOZE_ANSWER : 162 // [0] : (unused) 163 // [1] : array of JCLOZE_ANSWER_TEXTs 164 // [2] : clue for this answer 165 // JCLOZE_ANSWER_TEXT : 166 // [0] : array (seems unnecessary, just the text would be enough?) 167 // [0] : text of possible answer 168 // State : array of JCLOZE_ANSWER_STATEs 169 // JCLOZE_ANSWER_STATE (v5) : 170 // [0] : clue asked for or not 171 // [1] : number of hints (show next letter) and penalties ('check' an incorrect answer) 172 // [2] : length of answer matched 173 // [3] : score for this item 174 // [4] : already answered correctly 175 // [5] : answer entered in text box (right or not) 176 // JCLOZE_ANSWER_STATE (v6) 177 // this.ClueGiven = false; 178 // this.HintsAndChecks = 0; 179 // this.MatchedAnswerLength = 0; 180 // this.ItemScore = 0; 181 // this.AnsweredCorrectly = false; 182 // this.Guesses = new Array(); last guess is correct answer 183 // ******** 184 // JCross 185 // ******** 186 if (window.JCross==null) { 187 JCross = new Array(); 188 JCross[0] = true; // show separator line between answers on email 189 JCross[1] = true; // show number of penalties (hints or checks before complete) 190 JCross[2] = true; // show number of letters 191 JCross[3] = true; // show correct answers 192 JCross[4] = true; // show clues 193 JCross[5] = true; // show wrong answers 194 JCross[6] = true; // show if clue was asked for or not 195 JCross[7] = true; // show number of hints (=next letter requests) 196 JCross[8] = true; // show number of checks 197 // there are no "ignored" answers for JCross quizzes 198 } 199 // JCross quizzes use the following global variables: 200 // L : letters (of correct answers) 201 // C : clue numbers (CL in v6) 202 // G : guesses 203 // 'L', 'C' ('CL') and 'G' are all 2-dimensional arrays (rows x cols) 204 // 205 // v5 quizzes additionally use the following single-dimension arrays 206 // A : clues for across (horizontal) words 207 // D : clues for down (vertical) words 208 // N.B. form is only sent when all answers are correct so 209 // you can't find out what 'wrong' answers were entered 210 // ******** 211 // JMatch 212 // ******** 213 if (window.JMatch==null) { 214 JMatch = new Array(); 215 JMatch[0] = true; // show separator line between answers on email 216 JMatch[1] = false; // show number of penalties (= total number of checks) 217 JMatch[2] = true; // show LHS texts (the question) 218 JMatch[3] = true; // show correct answers 219 JMatch[4] = true; // show wrong answers 220 JMatch[5] = true; // show checks (per match) [empty or unchanged RHS are not counted] 221 // JMatch has no "clue" or "hint" buttons 222 // there cannot be any "ignored" answers 223 } 224 // v5 JMatch quizzes use the global variables 'I' and 'Status' (and 'RItems') 225 // v6 JMatch quizzes use only 'Status' 226 // v6+ JMatch quizzes use 'F' and 'D' (see below) 227 // I : an array of JMATCH_PAIRs (one for each pair) 228 // JMATCH_PAIR : 229 // [0] : LHS text 230 // [1] : RHS text 231 // [2] : fixed (=not jumbled) flag 232 // 0 : not fixed 233 // 1 : fixed 234 // [3] : index in drop down list selection 235 // Status : an array of JMATCH_PAIR_STATUSes 236 // JMATCH_PAIR_STATUS: 237 // [0] : correctly matched yet flag 238 // 0 : this pair has NOT been correctly matched 239 // 1 : this pair has been correctly matched 240 // [1] : number of times this item has been wrongly matched 241 // v6 quizzes only 242 // [2] : id of original SELECT element containing possible matches 243 // Note that after matching, this SELECT is removed, so don't try looking for it :-) 244 // v6+ JMatch quizzes use the global variables 'F' and 'D' 245 // F : array of JMATCH_FIXED_ITEMs 246 // JMATCH_FIXED_ITEM: 247 // [0] : text 248 // [1] : tag 249 // D : array of JMATCH_DRAGGABLE_ITEMs 250 // JMATCH_DRAGGABLE_ITEM 251 // [0] : text 252 // [1] : tag of the F item to which it SHOULD be dragged 253 // [2] : tag of the F item to which it was dragged (initally 0) 254 // N.B. form is only sent when all answers are correct so 255 // you can't find out what 'wrong' answers were entered 256 // ******** 257 // JMix 258 // ******** 259 if (window.JMix==null) { 260 JMix = new Array(); 261 JMix[0] = true; // show separator line between answers on email 262 JMix[1] = false; // show number of wrong guesses (replaced by JMix[5]) 263 JMix[2] = true; // show right answer 264 JMix[3] = true; // show wrong answer, if any 265 JMix[4] = false; // show answer as text (false) or number (true) 266 JMix[5] = true; // show number of checks 267 JMix[6] = true; // show number of hints (=show next word) 268 } 269 // JMix quizzes use the global variables 270 // 'Segments', 'GuessSequence' and 'Penalties' 271 // Segments : array of JMix_QUESTIONs 272 // JMix_QUESTION: 273 // [0] : text 274 // [1] : order in sequence 275 // [2] : used flag 276 // GuessSequence : array of 'order in sequence' numbers 277 // Penalties : number of incorrect guesses 278 // ******** 279 // JQuiz 280 // ******** 281 if (window.JQuiz==null) { 282 JQuiz = new Array(); 283 JQuiz[0] = true; // show separator line between answers on email 284 JQuiz[1] = true; // show question text 285 JQuiz[2] = true; // show student's correct answer(s) 286 JQuiz[3] = false; // show wrong and ignored answer(s) (legacy field superceded by [8] & [9]) 287 JQuiz[4] = true; // show number of hints requested 288 JQuiz[5] = false; // show number of checks of incorrect answers (legacy field superceded by [12]) 289 // HP6 v6 quizzes only 290 JQuiz[6] = false; // show answer value (false) or A,B,C... index (true) 291 JQuiz[7] = false; // show all students answers 292 JQuiz[8] = true; // show student's wrong answers 293 JQuiz[9] = true; // show ignored answers (not relevant for multi-select questions) 294 JQuiz[10] = true; // show score weightings 295 JQuiz[11] = true; // show question type 296 JQuiz[12] = true; // show number of checks (if true, then JQuiz[5] of will be ignored) 297 JQuiz[13] = true; // show number of times ShowAnswer button was pressed (usually 0 or 1) 298 } 299 // v5 JQuiz quizzes use the global variables 'I' and 'Status' 300 // I : array of JQUIZ_ANSWERs 301 // JQUIZ_ANSWER : 302 // [0] : question text 303 // [1] : array of JQUIZ_ANSWER_TEXTs (one for each answer) 304 // JQUIZ_ANSWER_TEXT : 305 // [0] : array (seems unnecessary, just the text would be enough?) 306 // [0] : text of possible answer 307 // Status : array of JQUIZ_ANSWER_STATEs 308 // JQUIZ_ANSWER_STATE : 309 // [0] : question done or not 310 // [1] : number of wrong checks 311 // [2] : number of hints asked for 312 // [3] : student's answer 313 // [4] : score for this question 314 // v6 JQuiz quizzes use the global variables 'I' and 'State' 315 // I : array of JQUIZ_QUESTIONs 316 // JQUIZ_QUESTION : 317 // [0] : weighting 318 // [1] : ?? (always set to '') 319 // [2] : question type 320 // '0'=multiple-choice, '1'=short-answer, '2'=hybrid, '3'=multi-select 321 // [3] : array of JQUIZ_ANSWERSs (one for each possible answer) 322 // JQUIZ_ANSWER : 323 // [0] : answer value 324 // [1] : feedback text 325 // [2] : correct answer flag (1=a correct answer, 0=a wrong answer) 326 // [3] : weighted score (as percentage) if correct 327 // [4] : flag (usually set to 1, but for hybrid answers that are not 328 // to be included in multiple choice options, it is set to 0) 329 // State : array of JQUIZ_QUESTION_STATEs 330 // JQUIZ_QUESTION_STATE : 331 // [0] : score (-1 shows not done yet) 332 // [1] : array showing on which number try each JQUIZ_ANSWER was selected 333 // [2] : number of attempts at this question 334 // [3] : total of weighted scores of correct answers that were selected 335 // i.e. each time a correct answer is selected, 336 // its JQUIZ_ANSWER[3] weighting is added to this total 337 // so when all the correct answers have been selected, this will be 100 338 // [4] : penalties incurred for hints (score is set to zero if >= 1) 339 // [5] : - for multiple choice, short-answer and hybrid questions, this is a 340 // comma-delimited list showing order in which answers were chosen 341 // - for multi-select fields, this is bar-delimted ('|') list of settings 342 // showing whether each checkbox was selected ('Y') on not ('N') when the 343 // 'Check' button was clicked. The final item in the list will be the 344 // settings for the correct answer. 345 // N.B. JBC, JMatch(v5) and JQuiz(v5) all use global variables 'I' and 'Status' 346 // JBC : I[0].length==3 && !window.RItems 347 // JQuiz(v5) : I[0].length==2 348 // JMatch(v5) : I[0].length==4 && window.RItems 349 // N.B. JCloze(v5+6) and JQuiz(v6) both use global variables 'I' and 'State' 350 // JCloze (v5) : I[0].length==3 && State[0].Guesses==null 351 // JCloze (v6) : I[0].length==3 && State[0].Guesses!=null 352 // JQuiz (v6) : I[0].length==4 353 // ********** 354 // Rhubarb 355 // ********** 356 if (window.Rhubarb==null) { 357 Rhubarb = new Array(); 358 Rhubarb[0] = true; // show correct words (so far) 359 Rhubarb[1] = true; // show correct words as count (true) or list (false) 360 Rhubarb[2] = true; // show wrong words 361 Rhubarb[3] = false; // show wrong words as count (true) or list (false) 362 Rhubarb[4] = false; // show ignored words (not implemented yet) 363 Rhubarb[5] = true; // show hints 364 } 365 // ********** 366 // Sequitur 367 // ********** 368 if (window.Sequitur==null) { 369 Sequitur = new Array(); 370 Sequitur[0] = true; // show count of correct button clicks 371 Sequitur[1] = true; // show count of wrong button clicks 372 } 373 // ********** 374 // Messages 375 // ********** 376 if (window.MSG==null) { 377 MSG = new Array(); 378 // Login prompts 379 MSG[0] = 'Name'; 380 MSG[1] = 'ID'; 381 MSG[2] = 'Email'; 382 MSG[3] = 'Password'; 383 MSG[4] = 'Cookies'; 384 // Login buttons 385 MSG[5] = 'Start the Quiz'; 386 MSG[6] = 'Cancel'; 387 // Cookie menu options (only used if Login[4] is true) 388 MSG[7] = 'keep for this session only'; 389 MSG[8] = 'keep for one day'; 390 MSG[9] = 'keep for one month'; 391 MSG[10] = 'do NOT keep cookies'; 392 // Login error messages 393 MSG[11] = 'Sorry, you were unable to login. Please try again later.'; 394 MSG[12] = 'Please fill in all the information.'; 395 MSG[13] = 'Incorrect Password. Please try again.'; 396 MSG[14] = 'Incorrect ID. Please try again.'; 397 MSG[15] = 'Email address does not appear to be valid.'; 398 // day and month names (used in Start_Time and End_Time) 399 MSG[16] = new Array('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); 400 MSG[17] = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); 401 // enable popups 402 MSG[18] = 'Please enable pop-up windows on your browser.'; 403 // browser specific instuctions on how to enable popup windows 404 var n = navigator; 405 var s = n.userAgent.toLowerCase(); 406 if (n.appName=='Netscape' && s.indexOf('gecko')>=0) { 407 // Netscape 6 and 7 408 MSG[18] += '\n\n' + 'Edit->Preferences, ' + (s.indexOf('mac')>=0 ? 'Advanced->Scripts & Plugins' : 'Privacy & Security->Popup Window Controls'); 409 } else if (s.indexOf('safari')>=0) { 410 // Safari 411 MSG[18] += '\n\n' + 'on Safari menu, uncheck "Block Pop-Up Windows"'; 412 } else if (s.indexOf('firebird')>=0) { 413 // Firebird 414 MSG[18] += '\n\n' + 'Preferences->Web Features, uncheck "Block Pop-Up Windows"'; 415 } else if (s.indexOf('msie 6')>=0) { 416 // IE 6 (WinXP.SP2) 417 MSG[18] += '\n\n' + 'Tools->Pop-up Blocker->Turn Off Pop-up Blocker'; 418 } 419 } 420 //if (window.FEEDBACK==null) { 421 // FEEDBACK = new Array(); 422 // FEEDBACK[0] = ''; // url of feedback page/script 423 // FEEDBACK[1] = ''; // array of array('teachername', 'value'); 424 // FEEDBACK[2] = ''; // 'student name' [formmail only] 425 // FEEDBACK[3] = ''; // 'email@somewhere.com>' [formmail only] 426 // FEEDBACK[4] = ''; // window width 427 // FEEDBACK[5] = ''; // window height 428 // FEEDBACK[6] = ''; // 'Send a message to teacher' [prompt/button text] 429 // FEEDBACK[7] = ''; // 'Title' 430 // FEEDBACK[8] = ''; // 'Teacher' 431 // FEEDBACK[8] = ''; // 'Message' 432 // FEEDBACK[10] = ''; // 'Close this window' [formmail only] 433 //} 434 // ********** 435 // HP array 436 // ********** 437 HP = new Array(); 438 for (var i=0; i<=8; i++) { 439 HP[i] = new Array(); 440 } 441 // indexes for the HP array (makes the code further down easier to read) 442 _score = 0; 443 _weight = 1; 444 _correct = 2; 445 _wrong = 3; 446 _unused = 4; 447 _hints = 5; 448 _clues = 6; 449 _checks = 7; 450 _guesses = 8; 451 // ************* 452 // Server Fields 453 // ************* 454 if (window.ServerFields==null) { 455 ServerFields = new Array(); 456 // these fields will be added to the ResultForm and submitted to the CGI script on the server. 457 // 'Sort', 'return_link_title', 'return_link_url' and 'print_blank_fields' are useful for formmail 458 // override the HP setting of sort fields (forces ALL fields to be displayed) 459 ServerFields[0] = new Array('sort', ''); 460 // add link to close pop-up results window 461 ServerFields[1] = new Array('return_link_title', 'Close this window'); 462 ServerFields[2] = new Array('return_link_url', 'javascript:self.close()'); 463 // make sure zero values are printed 464 ServerFields[3] = new Array('print_blank_fields', 'yes'); 465 // you can also set other fields for your customized CGI script 466 // e.g. adding a server defined start time (instead of a client defined start time) 467 // ServerFields[4] = new Array('serverStartTime', '<?php echo date("Y-m-d H:i:s") ?>'); 468 } 469 // ********************* 470 // Login screen 471 // (not required by LMS) 472 // ********************* 473 function QuizLogin(LoginPrompt) { 474 if (!is_LMS() && (Login[0] || Login[1] || Login[2] || Login[3])) { 475 var html = '' 476 + '<html>' 477 + '<head></head>' 478 + '<body bgColor="#cccccc" onLoad="opener.setFocus(self)">' 479 + '<form onSubmit="' 480 + 'self.ok=true;' 481 + 'self.expiry=null;' 482 ; 483 if (Login[4]) { // cookie expiry 484 html += "opener.checkOK(self,'CookieExpiry');"; 485 } 486 if (Login[0]) { // user name 487 html += "opener.checkOK(self,'UserName');"; 488 } 489 if (Login[1]) { // user ID 490 html += "opener.checkOK(self,'UserID');"; 491 } 492 if (Login[2]) { // user email 493 html += "opener.checkOK(self,'UserEmail');"; 494 } 495 if (Login[3]) { // quiz password 496 html += "opener.checkOK(self,'Password');"; 497 } 498 html += 'if(ok){' 499 + 'opener.StartQuiz();' 500 + 'self.close();' 501 + '}else{' 502 + 'if(isNaN(self.tries))self.tries=0;' 503 + 'self.tries++;' 504 + 'if(self.tries<3){' 505 + 'opener.setFocus(self);' 506 + '}else{' 507 + "alert(opener.MSG[11]);" 508 + 'opener.goBack();' 509 + 'self.close();' 510 + '}' 511 + '}' 512 + 'return false;' 513 + '">' 514 ; 515 html += '<table>' 516 + '<caption>' + LoginPrompt + '</caption>'; 517 ; 518 if (Login[0]) { // user name 519 var v = getCookie(self, 'UserName'); 520 html += '<tr>' 521 + '<th align=right nowrap>' + MSG[0] + ' :</th>' 522 + '<td>' 523 ; 524 if (typeof(Login[0])=='boolean') { // text box 525 html += '<input type=text name=UserName value="' + v + '">'; 526 } else { // drop down menu of names 527 // pattern to match commas and white space 528 var comma = (window.RegExp) ? new RegExp('\\s*,\\s*') : ','; 529 // convert list of names to array, if necessary 530 if (typeof(Login[0])=='string') { 531 Login[0] = Login[0].split(comma); 532 } 533 html += '<select name=UserName size=1>' 534 + '<option value=""></option>' 535 ; 536 for(var i=0; i<Login[0].length; i++) { 537 // convert name details to array if nececount_cary 538 if (typeof(Login[0][i])=='string') { 539 Login[0][i] = Login[0][i].split(comma); 540 } 541 html += makeOption(Login[0][i][0], v, Login[0][i][1]); 542 } 543 html += '</select>'; 544 } 545 html += '</td>' 546 + '</tr>' 547 ; 548 } 549 if (Login[1]) { // user ID 550 var v = getCookie(self, 'UserID'); 551 html += '<tr><th align=right nowrap>' + MSG[1] + ' :</th><td><input type=text name=UserID value="' + v + '"></td></tr>'; 552 } 553 if (Login[2]) { // user email 554 var v = getCookie(self, 'UserEmail'); 555 html += '<tr><th align=right nowrap>' + MSG[2] +' :</th><td><input type=text name=UserEmail value="' + v + '"></td></tr>'; 556 } 557 if (Login[3]) { // quiz password 558 var v = getCookie(self, 'Password'); 559 html += '<tr><th align=right nowrap>' + MSG[3] + ' :</th><td><input type=password name=Password value="' + v + '"></td></tr>'; 560 } 561 if (Login[4]) { // cookie lifespan 562 var v = getCookie(self, 'CookieExpiry'); 563 html += '<tr>' 564 + '<th align=right nowrap>' + MSG[4] + ' :</th>' 565 + '<td>' 566 + '<select name="CookieExpiry" size=1>' 567 + makeOption('session', v, MSG[7]) 568 + makeOption('day', v, MSG[8]) 569 + makeOption('month', v, MSG[9]) 570 + makeOption('never', v, MSG[10]) 571 + '</select>' 572 + '</td>' 573 + '</tr>' 574 ; 575 } 576 html += '<tr>' 577 + '<th> </th>' 578 + '<td nowrap>' 579 + '<input type=submit value="' + MSG[5] + '"> ' 580 + '<input type=button value="' + MSG[6] + '" onClick="opener.goBack();self.close();">' 581 + '</td>' 582 + '</tr>' 583 + '</table></form></body></html>' 584 ; 585 // set height of Login Window 586 var m = navigator.userAgent.indexOf('Mac')>=0; 587 var h = (m ? 80 : 100); 588 for (var i=0; i<5; i++) h += (Login[i] ? (m ? 20 : 25) : 0); 589 // open up a new window 590 if (!openWindow('', '', (m ? 320 : 300), h, 'RESIZABLE', html)) { 591 alert(MSG[18]); // unable to open popup window 592 } 593 } else { // no Login required 594 window.UserName = window.UserID = window.UserEmail = window.Password = ''; 595 window.StartQuiz(); 596 } 597 return true; 598 } 599 function makeOption(value, v, txt) { 600 return '<option value="' + value + '"' + (value==v ? ' SELECTED' : '') + '>' + (txt ? txt : value) + '</option>'; 601 } 602 function setFocus(w) { 603 w.focus(); // bring window to the front 604 var obj = w.document.forms[0].elements; 605 for(var i=0; i<obj.length; i++) { 606 var v = getValue(w, i); 607 if (v=='' || obj[i].type=='submit') { 608 obj[i].focus(); 609 break; 610 } 611 } 612 } 613 function checkOK(w, n){ 614 var v = getValue(w, n, true); 615 if (v || (n!='UserName' && isGuest())) { 616 if (n=='CookieExpiry') setCookieExpiry(w, v); 617 setCookie(self, n, v, w.expiry); 618 if (n!='CookieExpiry') eval('self.' + n + '=v'); 619 } else { 620 if (w.ok) alert(MSG[12]); 621 w.ok = false; 622 } 623 } 624 function getValue(w, n, flag) { 625 var obj = w.document.forms[0].elements[n]; 626 var TYPE = obj.type.toUpperCase(); // required for ns4 (win) 627 if (obj.options && TYPE.indexOf('SELECT')>=0){ 628 var v = obj.options[obj.selectedIndex].value; 629 } else { 630 var v = obj.value; 631 } 632 if (flag) { 633 var msg = ''; 634 if (n=='Password' || (n=='UserID' && !Login[3])) { 635 var pwd = getPassword(w); 636 if (pwd && v!=pwd) msg = MSG[n=='Password' ? 13 : 14]; 637 } 638 if (n=='UserEmail' && window.RegExp) { 639 var r = '(\\w|-)+'; 640 r = r + '(\\.' + r + ')'; 641 r = new RegExp('^(' + r + '*)@(' + r + '+)$'); 642 if (v.match(r)==null) msg = MSG[15]; 643 } 644 if (msg) { 645 obj.value = v = ''; 646 if (w.ok) alert(msg); 647 w.ok = false; 648 } 649 } 650 return v; 651 } 652 function getPassword(w) { 653 var pwd = ''; 654 if (Login[3] && typeof(Login[3])=='string') { 655 pwd = Login[3]; 656 } else if ((Login[3] || Login[1]) && typeof(Login[0])=='object') { 657 var username = getValue(w, 'UserName'); 658 for(var i=0; i<Login[0].length; i++) { 659 if (username==Login[0][i][0]) { 660 pwd = Login[0][i][2]; 661 break; 662 } 663 } 664 } 665 return pwd; 666 } 667 function setCookieExpiry(w, v) { 668 if (v=='never'){ 669 w.expiry = new Date('Thu, 01-Jan-70 00:00:01 GMT'); 670 } else if (v=='day' || v=='month') { 671 var ms = (v=='month' ? 31 : 1) * 60 * 60 * 24 * 1000; 672 w.expiry = new Date((new Date()).getTime() + ms); 673 } 674 } 675 function setCookie(w, name, value, expires, path, domain, secure) { 676 if (name) w.document.cookie = '' 677 + 'HP_' + name + "=" + escape(value) 678 + (expires ? "; expires=" + expires.toGMTString() : "") 679 + (path ? "; path=" + path : "") 680 + (domain ? "; domain=" + domain : "") 681 + (secure ? "; secure" : "") 682 ; 683 } 684 function getCookie(w, n) { 685 var c = w.document.cookie; 686 var i = c.indexOf('HP_' + n + '='); 687 var j = (i<0) ? -1 : c.indexOf(';', (i += n.length + 4)); 688 return (i<0) ? '' : unescape(c.substring(i, ((j<0) ? c.length : j))); 689 } 690 function goBack(w) { 691 if (w==null) w = self; // default 692 if (w.history.length) w.history.back(); 693 } 694 function openWindow(url, name, width, height, attributes, html) { 695 // set height, width and attributes 696 if (window.screen && width && height) { 697 var W = screen.availWidth; 698 var H = screen.availHeight; 699 width = Math.min(width, W); 700 height = Math.min(height, H); 701 attributes = '' 702 + (attributes ? (attributes+',') : '') 703 + 'WIDTH='+width+',HEIGHT='+height 704 ; 705 } 706 // create global hpWindows object, if necessary 707 if (!window.hpWindows) window.hpWindows = new Array(); 708 // initialize window object 709 var w = null; 710 // has a window with this name been opened before? 711 if (name && hpWindows[name]) { 712 // http://www.webreference.com/js/tutorial1/exist.html 713 if (hpWindows[name].open && !hpWindows[name].closed) { 714 w = hpWindows[name]; 715 w.focus(); 716 } else { 717 hpWindows[name] = null; 718 } 719 } 720 // check window is not already open 721 if (w==null) { 722 // workaround for "Access is denied" errors in IE when offline 723 // based on an idea seen at http://www.devshed.com/Client_Side/JavaScript/Mini_FAQ 724 var ie_offline = (document.all && location.protocol=='file:'); 725 // try and open the new window 726 w = window.open((ie_offline ? '' : url), name, attributes); 727 // check window opened OK (user may have prevented popups) 728 if (w) { 729 // center the window 730 if (window.screen && width && height) { 731 w.moveTo((W-width)/2, (H-height)/2); 732 } 733 // add content, if required 734 if (html) { 735 with (w.document) { 736 clear(); 737 open(); 738 write(html); 739 close(); 740 } 741 } else if (url && ie_offline) { 742 w.location = url; 743 } 744 if (name) hpWindows[name] = w; 745 } 746 } 747 return w; 748 } 749 // ********************* 750 // Send results by email 751 // (not required by LMS) 752 // ********************* 753 function SendAllResults(Score) { 754 // check this quiz is not generated by a LMS 755 if (!is_LMS()) { 756 // add flat file database details to the results form 757 AddDatabaseDetailsToResultForm(); 758 // add student details to the results form 759 AddStudentDetailsToResultForm(); 760 // add question details to the results form 761 AddQuestionDetailsToResultForm(); 762 // add server fields, if any, to results form 763 AddServerFieldsToResultForm(); 764 // change "method" of form, because "get" only allows 512 byts of data 765 ResultForm = replaceLast('method="get"', 'method="post"', ResultForm); 766 // create results window and form 767 var w = openWindow('', '', 500, 400, 'RESIZABLE,SCROLLBARS,LOCATION', ResultForm); 768 // check window opened OK (user may have prevented popups) 769 if (w) { 770 // get shortcut to form object 771 var form = w.document.forms[0]; 772 // update some important field values 773 form.Score.value = Score + '%'; 774 form.realname.value = UserName; 775 form.Start_Time.value = getTime(Start_Time); 776 form.End_Time.value = getTime(); 777 // force email subject and Exercise title 778 form.subject.value = document.title; 779 form. Exercise.value = document.title; 780 // update DB fields, if required 781 if (DB[0] && !isGuest()) set_db_fields(form); 782 if (DB[7]) form.action = DB[7]; 783 if (DB[8]) form.recipient.value = DB[8]; 784 // if this is a Netscape browser, check if the referer will be set OK 785 if (navigator.appName=='Netscape' && (location.protocol=='file:' || navigator.userAgent.indexOf('Netscape6')>=0)) { 786 // ns4 and ns7 set referer to 'file:// ...' when running a quiz offline 787 // ns6.2 (at least) always sets referer to 'about:blank' 788 // Netscape's setting of referer can cause BFormMail 789 // to reject the form, so encode the form data as a URL 790 var url = form.action; 791 var obj = form.elements; 792 for (var i=0; i<obj.length; i++) { 793 var v = escape(obj[i].value); 794 v = v.replace((new RegExp('\\+', 'g')), '%2B'); 795 url += (i==0 ? '?' : '&') + obj[i].name + '=' + v; 796 } 797 w.location.href = url; 798 } else { // browser can POST form ok 799 form.submit(); 800 } 801 } else { // unable to open popup window 802 alert(MSG[18]); 803 } 804 } // end if LMS 805 } 806 function isGuest() { 807 // check username is not a "guest" user 808 var flag = false; 809 var n = getCookie(self, 'UserName').toLowerCase(); 810 if (n) { 811 // convert list of user names to array, if necessary 812 if(typeof(Login[5])=='string') { 813 Login[5] = Login[5].split(','); 814 } 815 for(var i=0; i<Login[5].length; i++) { 816 if (n==Login[5][i].toLowerCase()) { 817 flag = true; 818 break; 819 } 820 } 821 } 822 return flag; 823 } 824 function set_db_fields(form) { 825 // update list of DB fields, if required 826 if (DB[4]=='' && window.RegExp) { 827 // add administration fields 828 var db_fields = '' 829 + 'subject,realname' 830 + (Login[1] ? ',ID' : '') 831 + (Login[2] ? ',email' : '') 832 + (Login[3] ? ',password' : '') 833 + ',Score,Start_Time,End_Time' 834 ; 835 // add answer fields (except separators) 836 var r = new RegExp('^[^_]+_q\\d\\d_\\w+$'); 837 for(var i=0; i<form.elements.length; i++) { 838 var n = form.elements[i].name; 839 if (r.test(n)) db_fields += ',' + n; 840 } 841 form.db_fields.value = db_fields; 842 } 843 // make sure delimiter is set (NS6+ requires this be set here, not any earlier) 844 form.db_delimiter.value = (DB[5] ? DB[5] : '\t'); 845 } 846 function AddStudentDetailsToResultForm() { 847 var sDetails = ''; 848 if (Login[0]) { // user name 849 // use 'realname' instead of a separate 'Name' field 850 // sDetails += hpHiddenField('Name', window.UserName); 851 } 852 if (Login[1]) { // user ID 853 sDetails += hpHiddenField('ID', window.UserID); 854 } 855 if (Login[2]) { // user email 856 sDetails += hpHiddenField('email', window.UserEmail); 857 } 858 if (sDetails && window.RegExp) { 859 // insert sDetails before '<input...Score...></input>' 860 var r = new RegExp('<input[^>]*Score[^>]*><\\/input>', 'i'); 861 var m = r.exec(ResultForm); 862 if (m) { 863 ResultForm = ResultForm.replace(m[0], sDetails + m[0] + makeSeparator('Time_')); 864 sDetails = ''; 865 } 866 } 867 if (Login[3]) { // quiz password 868 sDetails += hpHiddenField('Password', window.Password); 869 ResultForm = replaceLast('</form>', sDetails + '</form>', ResultForm); 870 } 871 } 872 function AddQuestionDetailsToResultForm() { 873 var qDetails = GetQuestionDetails(); 874 if (qDetails) { 875 // insert qDetails before the final </form> tag in the ResultForm 876 ResultForm = replaceLast('</form>', qDetails + '</form>', ResultForm); 877 } 878 } 879 function AddDatabaseDetailsToResultForm() { 880 if (window.DB && DB[0] && !isGuest()) { 881 var dbDetails = ''; 882 var folder = DB[1]; 883 if (folder && folder.charAt(folder.length-1)!='/') folder += '/'; 884 var file = DB[2]; 885 if (file=='') { 886 file = location.href; 887 file= file.substring(file.lastIndexOf('/')+1); 888 var i = file.indexOf('?'); 889 if (i >= 0) file = file.substring(0, i); 890 var i = file.lastIndexOf('.'); 891 if (i >= 0) file = file.substring(0, i); 892 } 893 var ext = (DB[3] ? DB[3] : 'txt'); 894 if (ext.charAt(0)!='.') ext = '.' + ext; 895 dbDetails += hpHiddenField('append_db', folder + file + ext); 896 dbDetails += hpHiddenField('db_fields', DB[4]); 897 dbDetails += hpHiddenField('db_delimiter', ''); // NS6+ requires this be set later 898 if (DB[6]) dbDetails += hpHiddenField('env_report', DB[6]); 899 // insert dbDetails before the final </form> tag in the ResultForm 900 ResultForm = replaceLast('</form>', dbDetails + '</form>', ResultForm); 901 } 902 } 903 function AddServerFieldsToResultForm() { 904 if (window.ServerFields) { 905 var s = ''; // input tags for s(erver fields) 906 for (var i=0; i<ServerFields.length; i++) { 907 if (ServerFields[i][0] && window.RegExp) { 908 // remove previous field value, if any 909 var r = new RegExp('<input[^>]*name\\s*=\\s*["\']\\s*' + ServerFields[i][0] + '[^>]*>(\\s*<\\/input>)?', 'i'); 910 if (r.test(ResultForm)) { 911 ResultForm = ResultForm.replace(r, ''); 912 } 913 } 914 if (ServerFields[i][1]) { 915 s += hpHiddenField(ServerFields[i][0], ServerFields[i][1]); 916 } 917 } // end for 918 if (s) ResultForm = replaceLast('</form>', s + '</form>', ResultForm); 919 } 920 } 921 function replaceLast(a, b, c) { 922 // replace last occurrence of 'a' in 'c' with 'b' 923 var l = a.length; 924 var i = c.lastIndexOf(a); 925 return (i<0 || l==0) ? c : (c.substring(0, i) + b + c.substring(i+l)); 926 } 927 // ************************* 928 // Extract question details 929 // ************************* 930 function GetQuestionDetails() { 931 var hp = hpVersion(); 932 var t = hpQuizType(); 933 var v = hpQuizVersion(); 934 return (t==1) ? GetJbcQuestionDetails(hp, v) : 935 (t==2) ? GetJClozeQuestionDetails(hp, v) : 936 (t==3) ? GetJCrossQuestionDetails(hp, v) : 937 (t==4) ? GetJMatchQuestionDetails(hp, v) : 938 (t==5) ? GetJMixQuestionDetails(hp, v) : 939 (t==6) ? GetJQuizQuestionDetails(hp, v) : 940 (t==7) ? GetRhubarbDetails(hp, v) : 941 (t==8) ? GetSequiturDetails(hp, v) : ''; 942 } 943 function GetJbcQuestionDetails(hp, v) { 944 qDetails = ''; 945 // check the quiz version 946 if (hp==5 || hp==6) { 947 // get question details 948 for(var q=0; q<I.length; q++) { 949 // initialize strings to hold answer details 950 var aDetails = new Array(); 951 aDetails[0] = new Array(); // right 952 aDetails[1] = new Array(); // wrong 953 aDetails[2] = new Array(); // ignored 954 // get answer details 955 for(var a=0; a<I[q][1].length; a++) { 956 var i = (Status[q][1][a]=='R') ? 0 : (Status[q][1][a]=='0') ? 2 : 1; 957 aDetails[i][aDetails[i].length] = (JBC[6] ? a : I[q][1][a][0]); 958 } 959 // format 'Q' (a padded, two-digit version of 'q') 960 var Q = getQ('JBC', q); 961 // add separator, if required 962 if (JBC[0]) qDetails += makeSeparator(Q); 963 if (JBC[1]) { // number of attempts to answer question 964 qDetails += hpHiddenField(Q+'attempts', Status[q][2] + (Status[q][0]==1 ? 1 : 0)); 965 } 966 if (JBC[2]) { // question text 967 qDetails += hpHiddenField(Q+'text', I[q][0]); 968 } 969 if (JBC[3] && (DB[0] || aDetails[0].length>0)) { // right 970 qDetails += hpHiddenField(Q+'right', aDetails[0]); 971 } 972 if (JBC[4] && (DB[0] || aDetails[1].length>0)) { // wrong 973 qDetails += hpHiddenField(Q+'wrong', aDetails[1]); 974 } 975 if (JBC[5] && (DB[0] || aDetails[2].length>0)) { // ignored 976 qDetails += hpHiddenField(Q+'ignored', aDetails[2]); 977 } 978 // calculate score for this question, if required (for HP version < 5.5) 979 if (isNaN(Status[q][3])) { 980 var a1 = Status[q][1].length; // answers 981 var a2 = Status[q][2]; // attempts 982 Status[q][3] = (a1<1 || a1<(a2-1)) ? 0 : ((a1 - (a2-1)) / a1); 983 } 984 // add 'score' for this question 985 qDetails += hpHiddenField(Q+'score', Math.floor(Status[q][3]*100)+'%'); 986 } // end for 987 } 988 return qDetails; 989 } 990 function GetJClozeQuestionDetails(hp, v) { 991 var qDetails = ''; 992 // check the quiz version 993 if (hp==5 || hp==6) { 994 var r = hpRottmeier(); 995 if (parseInt(r)==2) { // Rottmeier Find-It 3a+3b 996 qDetails += hpHiddenField('JCloze_penalties', window.TotWrongChoices); 997 } 998 // get details for each question 999 var q_max = (r==0) ? State.length : GapList.length; // could use I.length for both 1000 for (var q=0; q<q_max; q++) { 1001 // format 'Q' (a padded, two-digit version of 'q') 1002 var Q = getQ('JCloze', q); 1003 // add separator, if required 1004 if (JCloze[0]) qDetails += makeSeparator(Q); 1005 // score (as %) 1006 var x = (hp==5) ? State[q][3] : (r==0) ? State[q].ItemScore : GapList[q][1].Score; 1007 qDetails += hpHiddenField(Q+'score', Math.floor(x*100)+'%'); 1008 var correct = (HP[_correct][q] ? HP[_correct][q] : ''); 1009 if (JCloze[1]) { // student's correct answer 1010 qDetails += hpHiddenField(Q+'correct', correct); 1011 } 1012 if (JCloze[2]) { // ignored answers 1013 var x = new Array(); 1014 if (r!=2.1) { // exclude Find-It 3a 1015 for (var i=0, ii=0; i<I[q][1].length; i++) { 1016 var s = I[q][1][i][0]; 1017 if (typeof(s)=='string' && s!='') { 1018 if (s.toUpperCase() == correct.toUpperCase()) { 1019 var is_ignored = false; 1020 } else { 1021 // DropDown 2.4 1022 var is_ignored = true; 1023 var iii_max = HP[_wrong][q] ? HP[_wrong][q].length : 0; 1024 for (var iii=0; iii<iii_max; iii++) { 1025 if (s.toUpperCase() == HP[_wrong][q][iii].toUpperCase()) { 1026 var is_ignored = false; 1027 } 1028 } 1029 } 1030 if (is_ignored) { 1031 x[ii++] = s; 1032 } 1033 } 1034 } 1035 } 1036 qDetails += hpHiddenField(Q+'ignored', x); 1037 } 1038 if (JCloze[3]) { 1039 var x = (HP[_wrong][q] ? HP[_wrong][q] : ''); 1040 qDetails += hpHiddenField(Q+'wrong', x); 1041 } 1042 if (JCloze[4]) { // number of penalties (Hints + Checks) 1043 var x = (hp==5) ? State[q][1] : (r==0) ? State[q].HintsAndChecks : (r==1) ? GapList[q][1].NumOfTrials : (r==2.2) ? GapList[q][1].HintsAndChecks : 0; 1044 qDetails += hpHiddenField(Q+'penalties', x); 1045 } 1046 if (JCloze[5]) { // clue shown? 1047 var x = (hp==5) ? State[q][0] : (r==0) ? State[q].ClueGiven: (r==1) ? GapList[q][1].ClueAskedFor : false; 1048 qDetails += hpHiddenField(Q+'clue_shown', (x ? 'YES' : 'NO')); 1049 } 1050 if (JCloze[6]) { // clue text 1051 qDetails += hpHiddenField(Q+'clue_text', I[q][2]); 1052 } 1053 if (JCloze[7]) { // number of hints 1054 var x = (HP[_hints][q] ? HP[_hints][q] : 0); 1055 qDetails += hpHiddenField(Q+'hints', x); 1056 } 1057 if (JCloze[8]) { // number of clues 1058 var x = HP[_clues][q] ? HP[_clues][q] : 0; 1059 qDetails += hpHiddenField(Q+'clues', x); 1060 } 1061 if (JCloze[9]) { // number of checks (including the final one for the correct answer) 1062 var x = (HP[_checks][q] ? HP[_checks][q] : 0); 1063 qDetails += hpHiddenField(Q+'checks', x); 1064 } 1065 } // end for 1066 } 1067 return qDetails; 1068 } 1069 function GetJCrossQuestionDetails(hp, v) { 1070 var qDetails = ''; 1071 // check the quiz version 1072 if (hp==5 || hp==6) { 1073 // inialize letter count 1074 var letters = 0; 1075 // get details for each question 1076 for (var row=0; row<L.length; row++) { 1077 for (var col=0; col<L[row].length; col++) { 1078 // increment letter count, if required 1079 if (L[row][col]) letters++; 1080 // show answers and clues, if required 1081 var q = (hp==5) ? C[row][col] : CL[row][col]; 1082 if (q) { 1083 for (var i=0; i<2; i++) { // 0==across, 1==down 1084 var AD = (i==0) ? 'A' : 'D'; 1085 var acrossdown = (i==0) ? 'across' : 'down'; 1086 1087 var clue = (hp==5) ? eval(AD+'['+q+']') : GetJCrossClue('Clue_'+AD+'_'+q); 1088 if (clue) { 1089 // format 'Q' (a padded, two-digit version of 'q') 1090 var Q = getQ('JCross', q) + acrossdown + '_'; // e.g. JCross_01_across_ 1091 1092 if (JCross[0]) { 1093 qDetails += makeSeparator(Q); 1094 } 1095 if (JCross[5]) { 1096 var x = (HP[_correct][AD] && HP[_correct][AD][q]) ? HP[_correct][AD][q] : ''; 1097 qDetails += hpHiddenField(Q+'correct', x); 1098 } 1099 if (JCross[4]) qDetails += hpHiddenField(Q+'clue', clue); 1100 if (JCross[5]) { 1101 var x = (HP[_wrong][AD] && HP[_wrong][AD][q]) ? HP[_wrong][AD][q] : ''; 1102 qDetails += hpHiddenField(Q+'wrong', x); 1103 } 1104 if (JCross[6]) { 1105 var x = HP[_clues][q] ? HP[_clues][q] : 0; 1106 qDetails += hpHiddenField(Q+'clues', x); 1107 } 1108 if (JCross[7]) { 1109 var x = (HP[_hints][AD] && HP[_hints][AD][q]) ? HP[_hints][AD][q] : 0; 1110 qDetails += hpHiddenField(Q+'hints', x); 1111 } 1112 if (JCross[8]) { 1113 var x = (HP[_checks][AD] && HP[_checks][AD][q]) ? HP[_checks][AD][q] : ''; 1114 qDetails += hpHiddenField(Q+'checks', x); 1115 } 1116 } // end for i 1117 } // end if clue 1118 } // end if q 1119 } // end for col 1120 } // end for row 1121 if (JCross[2]) { // show number of letters 1122 qDetails = hpHiddenField('JCross_letters', letters) + qDetails; 1123 } 1124 if (JCross[1]) { // show penalties 1125 var x = (window.Penalties) ? Penalties : 0; 1126 qDetails = hpHiddenField('JCross_penalties', x) + qDetails; 1127 } 1128 } 1129 return qDetails; 1130 } 1131 function GetJCrossClue(id) { 1132 var obj = (document.getElementById) ? document.getElementById(id) : null; 1133 return (obj) ? GetTextFromNodeN(obj, 'Clue') : ''; 1134 } 1135 function GetJCrossWord(a, r, c, goDown) { 1136 // a is a 2-dimensional array of letters, r is a row number, c is a column number 1137 var s = ''; 1138 while (r<a.length && c<a[r].length && a[r][c]) { 1139 s += a[r][c]; 1140 if (goDown) { 1141 r++; 1142 } else { 1143 c++; 1144 } 1145 } 1146 return s; 1147 } 1148 function GetJMatchText(q, className) { 1149 var obj = (document.getElementById) ? document.getElementById('Questions') : null; 1150 return (obj) ? GetTextFromNodeN(obj, className, q) : ''; 1151 } 1152 function GetJMatchRHS(v, q, getCorrect) { 1153 var rhs = ''; 1154 if (v==5.1 || v==6.1) { // Drag-and-drop 1155 var max_i = (window.F && window.D) ? D.length : 0; 1156 for (var i=0; i<max_i; i++) { 1157 if (F[q][1]==D[i][getCorrect ? 1 : 2]) break; 1158 } 1159 if (i<max_i) rhs = D[i][0]; 1160 } else if (v==5 || v==6) { // drop-down list of options 1161 var obj=document.getElementById(Status[q][2]); 1162 if (obj) { // not correct yet 1163 if (getCorrect) { 1164 var k = GetKeyFromSelect(obj); 1165 var i_max = obj.options.length; 1166 for (var i=0; i<i_max; i++) { 1167 if (obj.options[i].value==k) break; 1168 } 1169 if (i>=i_max) i = 0; // shouldn't happen 1170 } else { 1171 // get current guess, if any 1172 var i = obj.selectedIndex; 1173 } 1174 if (i) rhs = obj.options[i].innerHTML; 1175 } else { // correct 1176 rhs = GetJMatchText(q, 'RightItem'); 1177 } 1178 } 1179 return rhs; 1180 } 1181 function GetJMixQuestionDetails(hp, v) { 1182 qDetails = ''; 1183 // check the quiz version 1184 if (hp==5 || hp==6) { 1185 var q = 0; // question number 1186 // format 'Q' (a padded, two-digit version of 'q') 1187 var Q = getQ('JMix', q); 1188 // add separator, if required 1189 if (JMix[0]) qDetails += makeSeparator(Q); 1190 // add 'score' for this question 1191 var score = HP[_correct]==null ? 0 : ((Segments.length-Penalties)/Segments.length); 1192 qDetails += hpHiddenField(Q+'score', Math.floor(score*100)+'%'); 1193 if (JMix[1]) { // number of wrong guesses 1194 qDetails += hpHiddenField(Q+'wrongGuesses', Penalties); 1195 } 1196 if (JMix[2]) { // right answer 1197 var x = (HP[_correct][q]) ? HP[_correct][q] : ''; 1198 qDetails += hpHiddenField(Q+'correct', x); 1199 } 1200 if (JMix[3]) { // wrong answer(s) 1201 var x = (HP[_wrong][q]) ? HP[_wrong][q] : ''; 1202 qDetails += hpHiddenField(Q+'wrong', x); 1203 } 1204 if (JMix[5]) { // checks 1205 var x = (HP[_checks][q]) ? HP[_checks][q] : 0; 1206 qDetails += hpHiddenField(Q+'checks', x); 1207 } 1208 if (JMix[6]) { // hints 1209 var x = (HP[_hints][q]) ? HP[_hints][q] : 0; 1210 qDetails += hpHiddenField(Q+'hints', x); 1211 } 1212 } 1213 return qDetails; 1214 } 1215 function GetJMixSequence(indexes) { 1216 var s = new Array(); 1217 for (var i=0; i<indexes.length; i++) { 1218 s[i] = JMix[4] ? indexes[i] : GetJMixSegmentText(indexes[i]); 1219 } 1220 return s; 1221 } 1222 function GetJMixSegmentText(index){ 1223 var i_max = Segments.length; 1224 for (var i=0; i<i_max; i++) { 1225 if (Segments[i][1] == index) break; 1226 } 1227 return (i<i_max) ? Segments[i][0] : ''; 1228 } 1229 function GetJQuizQuestionDetails(hp, v) { 1230 var qDetails = ''; 1231 // HP5.5 uses "Status" for v5 and v6 JMatch quizzes (HP6 uses "State") 1232 // var hp = (window.Status) ? 5 : (window.State) ? 6 : 0; 1233 // check the quiz version 1234 if (hp==5 || hp==6) { 1235 // get details for each question 1236 var max_q = (hp==5) ? Status.length : State.length; 1237 for (var q=0; q<max_q; q++) { 1238 // skip this question if it was not used (HP6 v6 only) 1239 if (hp==6 && !State[q]) continue; 1240 // format 'Q' (a padded, two-digit version of 'q') 1241 var Q = getQ('JQuiz', q); 1242 // add separator 1243 if (JQuiz[0]) qDetails += makeSeparator(Q); 1244 if (hp==6 && JQuiz[11]) { // question type 1245 var x = parseInt(I[q][2]); 1246 x = (x==0) ? 'multiple-choice' : (x==1) ? 'short-answer' : (x==2) ? 'hybrid' : (x==3) ? 'multi-select' : 'n/a'; 1247 qDetails += hpHiddenField(Q+'type', x); 1248 } 1249 // score (as %) 1250 var x = (hp==5) ? Status[q][4]*10 : I[q][0]*State[q][0]; 1251 if (x<0) x = 0; 1252 qDetails += hpHiddenField(Q+'score', Math.floor(x)+'%'); 1253 if (hp==6 && JQuiz[10]) { // weighting 1254 qDetails += hpHiddenField(Q+'weighting', I[q][0]); 1255 } 1256 if (JQuiz[1]) { // question text 1257 var x = (hp==5) ? I[q][0] : (document.getElementById) ? GetTextFromNodeN(document.getElementById('Q_'+q), 'QuestionText') : ''; 1258 qDetails += hpHiddenField(Q+'question', x); 1259 } 1260 if (JQuiz[2]) { // student's correct answers 1261 var x = (HP[_correct][q]) ? HP[_correct][q] : ''; 1262 qDetails += hpHiddenField(Q+'correct', x); 1263 } 1264 if (JQuiz[3]) { // ignored and wrong answers 1265 var x = (hp==5) ? new Array() : GetJQuizAnswerDetails(q, 1); 1266 if (hp==5) { 1267 for (var i=0; i<I[q][1].length; i++) { 1268 var correct = HP[_correct][q] ? HP[_correct][q] : ''; 1269 if (I[q][1][i][0] && I[q][1][i][0].toUpperCase()!=correct.toUpperCase()) { 1270 x[x.length] = I[q][1][i][0]; 1271 } 1272 } 1273 } 1274 if (DB[0] || x) qDetails += hpHiddenField(Q+'other', x); 1275 } 1276 if (hp==6 && JQuiz[7]) { // all selected answers 1277 var x = GetJQuizAnswerDetails(q, 0); 1278 qDetails += hpHiddenField(Q+'selected', x); 1279 } 1280 if (JQuiz[8]) { // wrong answers 1281 var x = (HP[_wrong][q]) ? HP[_wrong][q] : ''; 1282 qDetails += hpHiddenField(Q+'wrong', x); 1283 } 1284 if (hp==6 && JQuiz[9]) { // ignored answers 1285 var x = GetJQuizAnswerDetails(q, 4); 1286 qDetails += hpHiddenField(Q+'ignored', x); 1287 } 1288 if (JQuiz[4]) { // number of hints 1289 var x = (HP[_hints][q]) ? HP[_hints][q] : 0; 1290 qDetails += hpHiddenField(Q+'hints', x); 1291 } 1292 if (JQuiz[5] || JQuiz[12]) { // number of checks 1293 if (JQuiz[12]) { // strictly checks only 1294 var x = (HP[_checks][q]) ? HP[_checks][q] : 0; 1295 } else { // checks (+ hints in HP6) 1296 var x = (hp==5) ? Status[q][1] : (State[q][2]-1); 1297 } 1298 qDetails += hpHiddenField(Q+'checks', x); 1299 } 1300 if (JQuiz[13]) { // ShowAnswer button 1301 var x = (HP[_clues][q]) ? HP[_clues][q] : 0; 1302 qDetails += hpHiddenField(Q+'clues', x); 1303 } 1304 } // end for 1305 } // end if 1306 return qDetails; 1307 } 1308 function GetTextFromNodeN(obj, className, n) { 1309 // returns the text under the nth node of obj with the target class name 1310 var txt = ''; 1311 if (obj && className) { 1312 if (typeof(n)=='undefined') { 1313 n = 0; 1314 } 1315 var nodes = GetNodesByClassName(obj, className); 1316 if (n<nodes.length) { 1317 txt += GetTextFromNode(nodes[n]); 1318 } 1319 } 1320 return txt; 1321 } 1322 function GetNodesByClassName(obj, className) { 1323 // returns an array of nodes with the target classname 1324 var nodes = new Array(); 1325 if (obj) { 1326 if (className && obj.className==className) { 1327 nodes.push(obj); 1328 } else if (obj.childNodes) { 1329 for (var i=0; i<obj.childNodes.length; i++) { 1330 nodes = nodes.concat(GetNodesByClassName(obj.childNodes[i], className)); 1331 } 1332 } 1333 } 1334 return nodes; 1335 } 1336 function GetTextFromNode(obj) { 1337 // return text in (and under) a single DOM node 1338 var txt = ''; 1339 if (obj) { 1340 if (obj.nodeType==3) { 1341 txt = obj.nodeValue + ' '; 1342 } 1343 if (obj.childNodes) { 1344 for (var i=0; i<obj.childNodes.length; i++) { 1345 txt += GetTextFromNode(obj.childNodes[i]); 1346 } 1347 } 1348 } 1349 return txt; 1350 } 1351 function GetJQuizAnswerDetails(q, flag) { 1352 // flag : the type of information required about the student's answers 1353 // 0 : all student's answers 1354 // 1 : student's wrong and ignored answers 1355 // 2 : student's correct answers 1356 // 3 : student's wrong answers 1357 // 4 : ignored answers 1358 var x = State[q][5]; //Sequence of answers chosen by number 1359 if (I[q][2]=='3') { // multi-select 1360 if (flag==4) { 1361 var x = new Array(); 1362 } else { 1363 // get required part of 'x' and convert to array 1364 if (x.charAt(0)=='|') { 1365 // HP 6.0 and 6.1 (always has leading bar) 1366 var i = x.lastIndexOf('|'); 1367 var x = x.substring((flag==2 ? (i+1) : 1), ((flag==0 || flag==2) ? x.length : i)).split('|'); 1368 } else { 1369 // HP 6.2 (no leading delimiter) 1370 var i = x.lastIndexOf(' | '); 1371 var x = x.substring((flag==2 ? (i+3) : 0), ((flag==0 || flag==2) ? x.length : i)).split(' | '); 1372 } 1373 } 1374 for (var i=0; i<x.length; i++) { 1375 var a = new Array(); 1376 for (var ii=0; ii<x[i].length; ii++) { 1377 if (x[i].charAt(ii)=='Y') { 1378 var s = JQuiz[6] ? String.fromCharCode(97+ii) : I[q][3][ii][0]; 1379 if (s && s.replace && window.RegExp) { 1380 s = s.replace(new RegExp('\\+', 'g'), '+'); 1381 } 1382 a.push(s); 1383 } 1384 } 1385 x[i] = a.join('+'); 1386 } 1387 } else if (x) { // multiple-choice, short-answer and hybrid 1388 if (x.charAt(x.length-1)==',') { 1389 // HP 6.0 and 6.1 (always has trailing comma) 1390 x = x.substring(0, x.length-1).split(','); 1391 } else { 1392 // HP 6.2 (short answer also contains student entered text) 1393 x = x.split(' | '); 1394 } 1395 if (flag) { 1396 var a = new Array(); 1397 if (flag==1 || flag==2 || flag==3) { 1398 for (var i=0; i<x.length; i++) { 1399 var is_correct = false; 1400 if (x[i].length==1) { // single letter 1401 var ii = x[i].charCodeAt(0) - 65; 1402 if (I[q][3] && I[q][3][ii] && I[q][3][ii][2]) { 1403 var is_correct = true; 1404 } 1405 } 1406 if (is_correct) { 1407 if (flag==2) { 1408 a.push(x[i]); 1409 } 1410 } else { 1411 if (flag==1 || flag==3) { 1412 a.push(x[i]); 1413 } 1414 } 1415 } 1416 } 1417 if (flag==1) { 1418 x = a; 1419 a = new Array(); 1420 } 1421 if (flag==1 || flag==4) { 1422 for (var i=0; i<I[q][3].length; i++) { 1423 var s = String.fromCharCode(65+i); 1424 for (var ii=0; ii<x.length; ii++) { 1425 if (x[ii]==s) break; 1426 } 1427 if (ii==x.length) a.push(s); 1428 } 1429 } 1430 x = a; 1431 } 1432 // convert answer indexes to values, if required 1433 if (JQuiz[6]==false) { 1434 for (var i=0; i<x.length; i++) { 1435 if (x[i].length==1) { // single letter 1436 var ii = x[i].charCodeAt(0) - 65; 1437 if (I[q][3] && I[q][3][ii]) { 1438 x[i] = I[q][3][ii][0]; 1439 } 1440 } 1441 } 1442 } 1443 } else { 1444 x = new Array(); 1445 } 1446 return x; 1447 } 1448 function GetRhubarbDetails(v) { 1449 qDetails = ''; 1450 if (v==6) { 1451 var q = 0; // always zero 1452 var Q = getQ('Rhubarb', q); 1453 if (document.title) { // use quiz title as question name 1454 qDetails += hpHiddenField(Q+'name', document.title); 1455 } 1456 if (Rhubarb[0]) { // correct words 1457 var x = (HP[_correct][q]) ? HP[_correct][q] : ''; 1458 if (Rhubarb[1]) { // count of correct words 1459 for (var i=0,ii=0; i<x.length; i++) { 1460 if (x[i]) ii++; 1461 } 1462 x = ii; 1463 } 1464 qDetails += hpHiddenField(Q+'correct', x); 1465 } 1466 if (Rhubarb[2]) { // wrong words 1467 var x = (HP[_wrong][q]) ? HP[_wrong][q] : ''; 1468 if (Rhubarb[3]) { // count of wrong words 1469 x = x.length; 1470 } 1471 qDetails += hpHiddenField(Q+'wrong', x); 1472 } 1473 if (Rhubarb[4]) { // ignored 1474 var x = ''; 1475 qDetails += hpHiddenField(Q+'ignored', x); 1476 } 1477 if (Rhubarb[5]) { // hints 1478 var x = (HP[_hints][q]) ? HP[_hints][q] : ''; 1479 qDetails += hpHiddenField(Q+'hints', x); 1480 } 1481 } 1482 return qDetails; 1483 } 1484 function GetSequiturDetails(v) { 1485 qDetails = ''; 1486 if (v==6) { 1487 var q = 0; // always zero 1488 var Q = getQ('Sequitur', q); 1489 if (document.title) { // use quiz title as question name 1490 qDetails += hpHiddenField(Q+'name', document.title); 1491 } 1492 if (Sequitur[0]) { // number of correct buttons chosen 1493 var x = (HP[_correct][q]) ? HP[_correct][q] : ''; 1494 qDetails += hpHiddenField(Q+'correct', x); 1495 } 1496 if (Sequitur[1]) { // number of wrong buttons chosen 1497 var x = (HP[_wrong][q]) ? HP[_wrong][q] : ''; 1498 qDetails += hpHiddenField(Q+'wrong', x); 1499 } 1500 } 1501 return qDetails; 1502 } 1503 // ********************* 1504 // click event handlers 1505 // ********************* 1506 function hpClick(x, args) { 1507 // x is the button type 1508 // args is either empty, a single argument, or an array of arguments 1509 var btn = (x==1) ? 'Hint' : (x==2) ? 'Clue' : (x==3) ? 'Check' : (x==4) ? 'Enter' : ''; 1510 if (btn) { 1511 // convert args to array, if necessary 1512 var t = typeof(args); 1513 if (t=='object') { 1514 // do nothing (args is already an array) 1515 } else if (t=='undefined') { 1516 args = new Array(); 1517 } else { 1518 args = new Array(''+args); 1519 } 1520 // call handler for this kind of button 1521 var x = eval('hpClick'+btn+'('+hpVersion()+','+hpQuizType()+','+hpQuizVersion()+',args);'); 1522 } 1523 } 1524 function hpClickHint(hp, t, v, args) { 1525 if (t==2 || t==5 || t==6 || t==7) { // JCloze, JMix, JQuiz, Rhubarb 1526 var q = args[0]; // clue/question number 1527 if (!HP[_hints][q]) HP[_hints][q] = 0; 1528 HP[_hints][q]++; 1529 } 1530 if (t==3) { // JCross 1531 if (v==6 || v==5) { 1532 var q = args[0]; // clue/question number 1533 var AD = args[1]; // direction ('A' or 'D') 1534 if (!HP[_hints][AD]) HP[_hints][AD] = new Array(); 1535 if (!HP[_hints][AD][q]) HP[_hints][AD][q] = 0; 1536 HP[_hints][AD][q]++; 1537 } 1538 } 1539 return true; 1540 } 1541 function hpClickClue(hp, t, v, args) { 1542 if (t==2 || t==3 || t==6) { // JCloze or JCross, or JQuiz (ShowAnswer button) 1543 var q = args[0]; // clue/question number 1544 if (!HP[_clues][q]) HP[_clues][q] = 0; 1545 HP[_clues][q]++; 1546 } 1547 return true; 1548 } 1549 function hpClickCheck(hp, t, v, args) { 1550 if (t==2) { // JCloze 1551 if (v==5 || v==6) { 1552 var r = hpRottmeier(); 1553 var already_correct = 'true'; 1554 if (r==0) { 1555 already_correct = (hp==5) ? 'State[i][4]==1' : 'State[i].AnsweredCorrectly==true'; 1556 } else if (r==1) { // DropDown 1557 already_correct = 'GapList[i][1].GapLocked==true'; 1558 } else if (r==2.1) { // Find-It 3a 1559 already_correct = 'GapList[i][1].ErrorFound==true'; 1560 } else if (r==2.2) { // Find-It 3b 1561 already_correct = 'GapList[i][1].GapSolved==true'; 1562 } 1563 var i_max = I.length; 1564 for (var i=0; i<i_max; i++) { 1565 if (eval(already_correct)) continue; 1566 var g = ''; 1567 if (r==0 || r==2.2) { 1568 g = GetGapValue(i); 1569 } else if (r==1) { // DropDown 1570 if (hp==5) { 1571 g = eval('document.Cloze.Gap'+i+'.value'); 1572 } else if (hp==6) { 1573 var ii = Get_SelectedDropValue(i); 1574 if (isNaN(ii) || ii<0) { // 'null' || -1 1575 g = ''; // no guess yet 1576 } else { 1577 if (window.MakeIndividualDropdowns) { 1578 var is_wrong = (ii!=0); 1579 g = I[i][1][ii][0]; 1580 } else { 1581 var is_wrong = (ii!=i); 1582 g = I[ii][1][0][0]; 1583 } 1584 } 1585 } 1586 } else if (r==2.1 && i==args[0]) { // Find-It 3a 1587 g = I[i][1][0][0]; 1588 } 1589 if (g) { 1590 if (!HP[_checks][i]) HP[_checks][i] = 0; 1591 HP[_checks][i]++; 1592 if (!HP[_guesses][i]) HP[_guesses][i] = new Array(); 1593 var ii = HP[_guesses][i].length; 1594 // is this a new guess at this gap? 1595 if (ii==0 || g!=HP[_guesses][i][ii-1]) { 1596 HP[_guesses][i][ii] = g; 1597 if (r==1) { 1598 // Rottmeier DropDown 2.4 1599 // do nothing 1600 } else { 1601 var G = g.toUpperCase(); 1602 var ii_max = I[i][1].length; 1603 for (var ii=0; ii<ii_max; ii++) { 1604 if (window.CaseSensitive) { 1605 if (g==I[i][1][ii][0]) break; 1606 } else { 1607 if (G==I[i][1][ii][0].toUpperCase()) break; 1608 } 1609 } 1610 var is_wrong = (ii==ii_max); 1611 } 1612 if (is_wrong) { // guess is wrong 1613 if (!HP[_wrong][i]) HP[_wrong][i] = new Array(); 1614 var ii_max = HP[_wrong][i].length; 1615 for (var ii=0; ii<ii_max; ii++) { 1616 if (HP[_wrong][i][ii]==g) break; 1617 } 1618 if (ii==ii_max) { 1619 HP[_wrong][i][ii] = g; 1620 } 1621 } else { // guess is correct 1622 HP[_correct][i] = g; 1623 } 1624 } 1625 } 1626 } 1627 } 1628 } 1629 if (t==3) { // JCross 1630 if (v==5 || v==6) { 1631 var q = args[0]; // clue/question number 1632 for (var row=0; row<L.length; row++) { 1633 for (var col=0; col<L[row].length; col++) { 1634 var q = (v==5) ? C[row][col] : CL[row][col]; 1635 if (q) { 1636 hpClickCheckJCrossV5V6(hp, v, 'A', q, row, col); 1637 hpClickCheckJCrossV5V6(hp, v, 'D', q, row, col); 1638 } 1639 } 1640 } 1641 } 1642 } 1643 if (t==4) { // JMatch 1644 var a = new Array(); 1645 var extra = ''; // extra js code to eval(uate) 1646 var guess = ''; // js code to eval(uate) guess 1647 var correct = ''; // js code to eval(uate) correct answer 1648 if (window.D && window.F) { 1649 // drag-and-drop, i.e. v5+ and v6+ (HP5 and HP6) 1650 a = F; 1651 guess = 'GetJMatchRHS(v,i)'; 1652 correct = 'GetJMatchRHS(v,i,true)'; 1653 } else if (window.GetKeyFromSelect) { 1654 // HP6 v6 1655 a = Status; 1656 guess = 'GetJMatchRHS(v,i)'; 1657 correct = 'GetJMatchRHS(v,i,true)'; 1658 } else if (window.GetAnswer) { 1659 // HP5 v6,v5 1660 a = I; 1661 guess = "(I[i][2]==0||I[i][0]=='')?'':GetAnswer(i)"; 1662 correct = 'I[i][3])'; 1663 } else if (window.Draggables) { 1664 // HP5 v4 1665 a = Draggables; 1666 s = "Draggables[i].correct=='1'"; 1667 } else if (window.CorrectAnswers) { 1668 // HP5 v3 1669 a = CorrectAnswers; 1670 guess = 'document.QuizForm.elements[i*2].selectedIndex'; 1671 correct = 'CorrectAnswers[i]'; 1672 } 1673 for (var i=0; i<a.length; i++) { 1674 // check this match has not already been finished 1675 if (!HP[_correct][i]) { 1676 // do extra setup, if necessary 1677 if (extra) eval(extra); 1678 // get the guess, if any 1679 var g = ''+eval(guess); 1680 if (g) { 1681 // is the guess correct? 1682 if (g==eval(correct)) { 1683 HP[_correct][i] = g; 1684 } else { // wrong answer 1685 // initialize wrong guess array if necessary 1686 if (!HP[_wrong][i]) HP[_wrong][i] = new Array(); 1687 // check to see if the guess is already in the guess array 1688 var i_max = HP[_wrong][i].length; 1689 for (var ii=0; ii<i_max; ii++) { 1690 if (HP[_wrong][i][ii]==g) break; 1691 } 1692 // add the guess if it was not found 1693 if (ii==i_max) { 1694 HP[_wrong][i][ii]=g; 1695 } else { 1696 g = null; // this is not a new answer 1697 } 1698 } 1699 // increment checks for this question, if necessary 1700 if (g) { 1701 if (!HP[_checks][i]) HP[_checks][i] = 0; 1702 HP[_checks][i]++; 1703 } 1704 } 1705 } 1706 } 1707 } // end if JMatch 1708 if (t==5) { // JMix 1709 // get question number (always 0) 1710 var q = args[0]; 1711 // check question has not already been answered correctly 1712 if (!HP[_correct][q]) { 1713 // match current guess against possible correct answers 1714 var a_max = Answers.length; 1715 for (var a=0; a<a_max; a++) { 1716 var i_max = Answers[a].length; 1717 for (var i=0; i<i_max; i++) { 1718 if (Answers[a][i] != GuessSequence[i]) break; 1719 } 1720 if (i==i_max) break; // correct answer was found 1721 } 1722 // at this point, (a==a_max) means guess is wrong 1723 // get array of segment texts in this g(uess) 1724 var g = GetJMixSequence(GuessSequence); 1725 // convert g(uess) array and to a s(tring) 1726 var s = ''; 1727 var i_max = g.length; 1728 for (var i=0; i<i_max; i++) { 1729 g[i] = trim(g[i]); 1730 if (g[i]!='') { 1731 s += (s=='' ? '' : '+') + g[i]; 1732 } 1733 } 1734 if (s) { 1735 if (a==a_max) { // wrong 1736 if (!HP[_wrong][q]) HP[_wrong][q] = new Array(); 1737 var i = HP[_wrong][q].length; 1738 HP[_wrong][q][i] = s; 1739 } else { // correct 1740 HP[_correct][q] = s; 1741 } 1742 // increment checks for this question 1743 if (!HP[_checks][q]) HP[_checks][q] = 0; 1744 HP[_checks][q]++; 1745 } 1746 } 1747 } 1748 if (t==6) { // JQuiz 1749 if (hp==5 || hp==6) { 1750 var q = args[0]; // clue/question number 1751 if (hp==5) { 1752 if (v==5) { 1753 var g = TrimString(eval('BottomFrame.document.QForm' + q + '.Guess').value); 1754 } else if (v==6) { 1755 var g = TrimString(eval('document.QForm.Guess').value); 1756 } 1757 } else { // HP 6 1758 var g = args[1]; 1759 } 1760 // increment check count 1761 if (!HP[_checks][q]) HP[_checks][q] = 0; 1762 HP[_checks][q]++; 1763 if (g) { 1764 var G = g.toUpperCase(); // used for shortanswer only 1765 var correct_answer = ''; // used for multiselect only 1766 // set index of answer array in I (the question array) 1767 var ans = (hp==5) ? 1 : 3; 1768 var i_max = I[q][ans].length; 1769 for (var i=0; i<i_max; i++) { 1770 // is this a (possible) correct answer? 1771 if (hp==5 || (hp==6 && I[q][ans][i][2])) { 1772 if (hp==6 && I[q][2]==3) { // multiselect 1773 correct_answer += (correct_answer ? '+' : '') + I[q][ans][i][0]; 1774 } else { // multichoice, shortanswer 1775 if (window.CaseSensitive) { 1776 if (g==I[q][ans][i][0]) break; 1777 } else { 1778 if (G==I[q][ans][i][0].toUpperCase()) break; 1779 } 1780 } 1781 } 1782 } 1783 if (i==i_max && g!=correct_answer) { // wrong 1784 if (!HP[_wrong][q]) HP[_wrong][q] = new Array(); 1785 var i_max = HP[_wrong][q].length; 1786 for (var i=0; i<i_max; i++) { 1787 if (HP[_wrong][q][i]==g) break; 1788 } 1789 if (i==i_max) HP[_wrong][q][i] = g; 1790 } else { 1791 HP[_correct][q] = g; 1792 } 1793 } 1794 } 1795 } 1796 if (t==7) { // Rhubarb 1797 if (hp==6) { 1798 var q = 0; // question number (always zero) 1799 var g = args[0]; // InputWord from CheckGuess() 1800 if (g) { 1801 var G = g.toUpperCase(); 1802 var i_max = Words.length; 1803 for (var i=0; i<i_max; i++) { 1804 if (G==Words[i].toUpperCase()) break; 1805 } 1806 if (i<i_max) { // correct 1807 if (!HP[_correct][q]) HP[_correct][q] = new Array(); 1808 HP[_correct][q][i] = g; 1809 } else { // wrong 1810 if (!HP[_wrong][q]) HP[_wrong][q] = new Array(); 1811 var i_max = HP[_wrong][q].length; 1812 for (var i=0; i<i_max; i++) { 1813 if (G==HP[_wrong][q][i].toUpperCase()) break; 1814 } 1815 if (i==i_max) HP[_wrong][q][i] = g; 1816 } 1817 } 1818 } 1819 } 1820 if (t==8) { // Sequitur 1821 if (hp==6) { 1822 var q = 0; // question number (always zero) 1823 if (CurrentCorrect==args[0]) { // correct button chosen 1824 if (!HP[_correct][q]) HP[_correct][q] = 0; 1825 HP[_correct][q]++; 1826 } else { 1827 if (!HP[_wrong][q]) HP[_wrong][q] = 0; 1828 HP[_wrong][q]++; 1829 } 1830 } 1831 } 1832 //return true; 1833 } 1834 function hpClickCheckJCrossV5V6(hp, v, AD, q, row, col) { 1835 // v is the version of Hot Potatoes 1836 // AD is the direction ('A' or 'D') 1837 // make sure HP[_checks] and HP[_correct] are initialized 1838 if (!HP[_checks][AD]) HP[_checks][AD] = new Array(); 1839 if (!HP[_correct][AD]) HP[_correct][AD] = new Array(); 1840 // get clue, if any 1841 var clue = (hp==5) ? eval('window.'+AD) : GetJCrossClue('Clue_'+AD+'_' + q); 1842 // is this a question that has not been answered correctly yet? 1843 if (clue && !HP[_correct][AD][q]) { 1844 var check = false; 1845 var guess = GetJCrossWord(G, row, col, (AD=='D')); 1846 var correct = GetJCrossWord(L, row, col, (AD=='D')); 1847 if (guess==correct) { 1848 HP[_correct][AD][q] = correct; 1849 check = true; 1850 } else if (guess) { 1851 // make sure HP[_wrong] is initialized 1852 if (!HP[_wrong][AD]) HP[_wrong][AD] = new Array(); 1853 if (!HP[_wrong][AD][q]) HP[_wrong][AD][q] = new Array(); 1854 // check this guess has not been entered before 1855 var i_max = HP[_wrong][AD][q].length; 1856 for (var i=0; i<i_max; i++) { 1857 if (HP[_wrong][AD][q]==guess) break; 1858 } 1859 // add the guess if it has not been entered before 1860 if (i>=i_max) { 1861 HP[_wrong][AD][q][i] = guess; 1862 check = true; 1863 } 1864 } 1865 // update HP[_checks], if necessary 1866 if (check) { 1867 if (!HP[_checks][AD]) HP[_checks][AD] = new Array(); 1868 if (!HP[_checks][AD][q]) HP[_checks][AD][q] = 0; 1869 HP[_checks][AD][q]++; 1870 } 1871 } 1872 } 1873 function hpClickEnter(hp, t, v, args) { 1874 if (t==3) { // JCross 1875 var q = args[0]; // clue/question number 1876 if (!HP[_enter][q]) HP[_enter][q] = 0; 1877 HP[_enter][q]++; 1878 } 1879 return true; 1880 } 1881 function GetJMatchQuestionDetails(hp, v) { 1882 var qDetails = ''; 1883 // HP5.5 uses "I" for v5 and v6 JMatch quizzes 1884 // var hp5 = (window.I) ? true : false; 1885 // check the quiz version 1886 if (hp==5 || hp==6) { 1887 if (JMatch[1] && v==6.1) { // attempts 1888 qDetails += hpHiddenField('JMatch_attempts', Penalties+1); 1889 } 1890 // get number of questions 1891 var max_q = (hp==5 || v==6) ? Status.length : F.length; 1892 // get details for each question 1893 for (var q=0; q<max_q; q++) { 1894 // format 'Q' (a padded, two-digit version of 'q') 1895 var Q = getQ('JMatch', q); 1896 // add separator, if required 1897 if (JMatch[0] && (JMatch[1] || JMatch[2] || JMatch[3])) { 1898 qDetails += makeSeparator(Q); 1899 } 1900 if (JMatch[1] && (hp==5 || v==6)) { // attempts 1901 qDetails += hpHiddenField(Q+'attempts', Status[q][1]); 1902 } 1903 if (JMatch[2]) { // LHS text (the question) 1904 var x = (v==5) ? I[q][0] : (v==6) ? GetJMatchText(q, 'LeftItem') : F[q][0]; 1905 qDetails += hpHiddenField(Q+'lhs', x); 1906 } 1907 if (JMatch[3]) { // correct answer (if any) 1908 var x = HP[_correct][q] ? HP[_correct][q] : ''; 1909 qDetails += hpHiddenField(Q+'correct', x); 1910 } 1911 if (JMatch[4]) { // wrong answers (if any) 1912 var x = HP[_wrong][q] ? HP[_wrong][q] : ''; 1913 qDetails += hpHiddenField(Q+'wrong', x); 1914 } 1915 if (JMatch[5]) { // checks 1916 var x = HP[_checks][q] ? HP[_checks][q] : 0; 1917 qDetails += hpHiddenField(Q+'checks', x); 1918 } 1919 } // end for 1920 } 1921 return qDetails; 1922 } 1923 // ********************* 1924 // library functions 1925 // ********************* 1926 function pad(i, l) { 1927 var s = (i+''); 1928 while (s.length<l) s = '0' + s; 1929 return s; 1930 } 1931 function getQ(section, q) { 1932 // Q is a padded, two-digit version of the question number, 'q', prefixed by 'section' 1933 return section + '_q' + (q<9 ? '0' : '') + (q+1) + '_'; 1934 } 1935 function makeSeparator(Q) { 1936 return is_LMS() ? '' : hpHiddenField(Q.substring(0, Q.length-1), '---------------------------------'); 1937 } 1938 function hpHiddenField(name, value, comma, forceHTML) { 1939 var field = ''; 1940 var t = typeof(value); 1941 if (t=='string') { 1942 value = encode_entities(value); 1943 } else if (t=='object') { // array 1944 var values = value; 1945 var i_max = values.length; 1946 value = ''; 1947 if (comma==null) comma = ','; 1948 for (var i=0; i<i_max; i++) { 1949 values[i] = trim(values[i]); 1950 if (values[i]!=null && values[i]!='') { 1951 value += (i==0 ? '' : comma) + encode_entities(values[i]); 1952 } 1953 } 1954 } 1955 if (is_LMS() && !forceHTML) { 1956 if (value && value.indexOf && value.indexOf('<')>=0 && value.indexOf('>')>=0) { 1957 value = '<![CDATA[' + value + ']]>'; 1958 } 1959 field = '<field><fieldname>' + name + '</fieldname><fielddata>' + value + '</fielddata></field>'; 1960 } else { 1961 field = '<input type=hidden name="' + name + '" value="' + value + '">'; 1962 } 1963 return field; 1964 } 1965 function trim(s) { 1966 if (s==null) s = ''; 1967 var i = 0; 1968 var ii = s.length; 1969 while (i<ii && s.charAt(i)==' ') { 1970 i++; 1971 } 1972 while (ii>i && s.charAt(ii-1)==' ') { 1973 ii--; 1974 } 1975 return s.substring(i, ii); 1976 } 1977 function encode_entities(s_in) { 1978 var i_max = (s_in) ? s_in.length : 0; 1979 var s_out = ''; 1980 for (var i=0; i<i_max; i++) { 1981 var c = s_in.charCodeAt(i); 1982 // 34 : double quote .......["] & 1983 // 38 : single quote .......['] ' 1984 // 43 : plus sign ..........[+] 1985 // 44 : comma ..............[,] 1986 // 60 : left angle bracket .[<] < 1987 // 62 : right angle bracket [>] > 1988 // >=128 multibyte character 1989 s_out += (c==43 || c==44 || c>=128) ? ('&#x' + pad(c.toString(16), 4) + ';') : s_in.charAt(i); 1990 } 1991 return s_out; 1992 } 1993 // ********************* 1994 // initialization 1995 // functions 1996 // ********************* 1997 function getTime(obj) { 1998 obj = obj ? obj : new Date(); 1999 // get year, month and day 2000 // for an LMS : yyyy-mm-dd 2001 // for email : DayName MonthName dd yyyy 2002 var s = is_LMS() ? 2003 obj.getFullYear() + '-' + pad(obj.getMonth()+1, 2) + '-' + pad(obj.getDate(), 2) : 2004 MSG[16][obj.getDay()] + ' ' + MSG[17][obj.getMonth()] + ' ' + pad(obj.getDate(), 2) + ' ' + obj.getFullYear() 2005 ; 2006 // get hours, minutes and seconds (hh:mm:ss) 2007 s += ' ' + pad(obj.getHours(), 2) + ':' + pad(obj.getMinutes(), 2) + ':' + pad(obj.getSeconds(), 2); 2008 // get time difference 2009 // for an LMS : +xxxx 2010 // for email : GMT+xxxx 2011 var x = obj.getTimezoneOffset(); // e.g. -540 2012 if (!isNaN(x)) { 2013 s += ' ' + (is_LMS() ? '' : 'GMT') + (x<0 ? '+' : '-'); 2014 x = Math.abs(x); 2015 s += pad(parseInt(x/60), 2) + pad(x - (parseInt(x/60)*60), 2); 2016 } 2017 return s; 2018 } 2019 function getFunc(fn) { 2020 if (typeof(fn)=='string') { 2021 fn = eval('window.' + fn); 2022 } 2023 return (typeof(fn)=='function') ? fn : null; 2024 } 2025 function getFuncCode(fn, extraCode, anchorCode, beforeAnchor) { 2026 var s = ''; 2027 var obj = getFunc(fn); 2028 if (obj) { 2029 s = obj.toString(); 2030 var i1 = s.indexOf('{')+1; 2031 var i2 = s.lastIndexOf('}'); 2032 if (i1>0 && i1<i2) { 2033 s = s.substring(i1, i2); 2034 } 2035 } 2036 if (extraCode) { 2037 if (anchorCode) { 2038 if (beforeAnchor) { 2039 s = replaceLast(anchorCode, extraCode + anchorCode, s); 2040 } else { 2041 s = replaceLast(anchorCode, anchorCode + extraCode, s); 2042 } 2043 } else { 2044 if (beforeAnchor) { 2045 s = extraCode + s; 2046 } else { 2047 s = s + extraCode; 2048 } 2049 } 2050 } 2051 return s; 2052 } 2053 function getArgsStr(args, addQuotes) { 2054 // make s(tring) version of function args array 2055 var s = ''; 2056 var i_max = args.length; 2057 for (var i=0; i<i_max; i++) { 2058 if (addQuotes) { 2059 s += '"' + args[i] + '",'; 2060 } else { 2061 if (s) { 2062 s += ','; 2063 } 2064 s += args[i]; 2065 } 2066 } 2067 return s; 2068 } 2069 function getFuncArgs(fn, flag) { 2070 // flag==0 : return args as string 2071 // flag==1 ; return args as array 2072 var i = 0; 2073 var a = new Array(); 2074 var obj = getFunc(fn); 2075 if (obj) { 2076 var s = obj.toString(); 2077 var i1 = s.indexOf('(') + 1; 2078 var i2 = s.indexOf(')', i1); 2079 // add args to a(rray) 2080 while (i1>0 && i1<i2) { 2081 var i3 = s.indexOf(',', i1); // next comma 2082 if (i3<0 || i3>i2) i3 = i2; 2083 a[i++] = trim(s.substring(i1, i3)); 2084 i1 = i3+1; 2085 } 2086 } 2087 return flag ? a : getArgsStr(a); 2088 } 2089 function getPrompt(fn) { 2090 // the LoginPrompt is the text string in the first prompt(...) statement 2091 // v5 : in the StartUp function 2092 // v6 : in the GetUserName function 2093 // Note: netscape uses double-quote as delimiter, others use single quote 2094 var s = getFuncCode(fn); 2095 var i1 = s.indexOf('prompt') + 8; 2096 var i2 = s.indexOf(s.charAt(i1-1), i1); 2097 var p = (i1>=8 && i2>i1) ? s.substring(i1, i2) : ''; 2098 // make sure browser has decoded the unicode prompt properly 2099 // this check is mainly for ns4, but there may be others 2100 if (window.RegExp) { 2101 var r = new RegExp('u([0-9A-F]{4})'); 2102 var m = r.exec(p); 2103 while (m) { 2104 p = p.replace(m[0], '&#' + parseInt(m[1], 16) + ';'); 2105 m = r.exec(p); 2106 } 2107 } 2108 return p; 2109 } 2110 function getStartUpCode(fn) { 2111 // the main initialization code comes from the StartUp function 2112 // v5 : the code before "UserName", if any, 2113 // and the code after the 2nd subsequent '}' 2114 // v6 : the code before and after 'GetUserName();' 2115 // i.e. all the code except the call to 'GetUserName();' 2116 var s = getFuncCode(fn); 2117 var i1 = s.indexOf('GetUserName();'); 2118 if (i1>=0) { // v6 2119 var i2 = i1 + 14; 2120 } else { // v5 2121 var i1 = s.indexOf('UserName'); 2122 var i2 = s.indexOf('}', s.indexOf('}', i1+8)+1)+1; 2123 } 2124 return (0<i1 && i1<i2) ? s.substring(0, i1) + s.substring(i2) : ''; 2125 } 2126 function is_LMS() { 2127 if (!window.hpCheckedForm) { 2128 window.hpCheckedForm = true; 2129 window.hpFoundForm = hpFindForm('store') ? true : false; 2130 } 2131 return hpFoundForm; 2132 } 2133 function hpFeedback() { 2134 if (FEEDBACK[0]) { 2135 var url = ''; 2136 var html = ''; 2137 if (FEEDBACK[1] && FEEDBACK[2]) { // formmail 2138 html += '<html><body>' 2139 + '<form action="' + FEEDBACK[0] + '" method="POST">' 2140 + '<table border="0">' 2141 + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>' 2142 + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>' 2143 ; 2144 if (typeof(FEEDBACK[1])=='string') { 2145 html += FEEDBACK[1] + hpHiddenField('recipient', FEEDBACK[1], ',', true); 2146 } else if (typeof(FEEDBACK[1])=='object') { 2147 var i_max = FEEDBACK[1].length; 2148 if (i_max==1) { // one teacher 2149 html += FEEDBACK[1][0][0] + hpHiddenField('recipient', FEEDBACK[1][0][0]+' <'+FEEDBACK[1][0][1]+'>', ',', true); 2150 } else if (i_max>1) { // several teachers 2151 html += '<select name="recipient">'; 2152 for (var i=0; i<i_max; i++) { 2153 html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>'; 2154 } 2155 html += '</select>'; 2156 } 2157 } 2158 html += '</td></tr>' 2159 + '<tr><th valign="top" align="right">' + FEEDBACK[9] + ':</th>' 2160 + '<td><TEXTAREA name="message" rows="10" cols="40"></TEXTAREA></td></tr>' 2161 + '<tr><td> </td><td><input type="submit" value="' + FEEDBACK[6] + '">' 2162 + hpHiddenField('realname', FEEDBACK[2], ',', true) 2163 + hpHiddenField('email', FEEDBACK[3], ',', true) 2164 + hpHiddenField('subject', document.title, ',', true) 2165 + hpHiddenField('title', document.title, ',', true) 2166 + hpHiddenField('return_link_title', FEEDBACK[10], ',', true) 2167 + hpHiddenField('return_link_url', 'javascript:self.close()', ',', true) 2168 + '</td></tr></table></form></body></html>' 2169 ; 2170 } else if (FEEDBACK[1]) { // url only 2171 if (typeof(FEEDBACK[1])=='object') { 2172 var i_max = FEEDBACK[1].length; 2173 if (i_max>1) { // several teachers 2174 html += '<html><body>' 2175 + '<form action="' + FEEDBACK[0] + '" method="POST" onsubmit="this.action+=this.recipient.options[this.recipient.selectedIndex].value">' 2176 + '<table border="0">' 2177 + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>' 2178 + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>' 2179 ; 2180 html += '<select name="recipient">'; 2181 for (var i=0; i<i_max; i++) { 2182 html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>'; 2183 } 2184 html += '</select>'; 2185 html += '</td></tr>' 2186 + '<tr><td> </td><td><input type="submit" value="' + FEEDBACK[6] + '">' 2187 + '</td></tr></table></form></body></html>' 2188 ; 2189 } else if (i_max==1) { // one teacher 2190 url = FEEDBACK[0] + FEEDBACK[1][0][1]; 2191 } 2192 } else if (typeof(FEEDBACK[1])=='string') { 2193 url = FEEDBACK[0] + FEEDBACK[1]; 2194 } 2195 } else { 2196 url = FEEDBACK[0]; 2197 } 2198 if (url || html) { 2199 var w = openWindow(url, 'feedback', FEEDBACK[4], FEEDBACK[5], 'RESIZABLE,SCROLLBARS', html); 2200 if (!w) { 2201 // unable to open popup window 2202 alert(MSG[18]); 2203 } 2204 } 2205 } 2206 } 2207 // ******************** 2208 // intercept clicks 2209 // ******************** 2210 function hpNewFunction(f, a, s) { 2211 if (window.C && C.safari) { 2212 if (f=='CheckAnswers') { 2213 if (s.indexOf('TotalChars-State[i].HintsAndChecks/')>=0) { 2214 // special fix for "CheckAnswers" in JCloze 2215 s = s.replace(/TotalChars-State\[i\]\.HintsAndChecks/g, '(TotalChars-State[i].HintsAndChecks)'); 2216 } 2217 if (s.indexOf('TotalChars-GapList[x][1].HintsAndChecks/')>=0) { 2218 // special fix for "CheckAnswers" in JCloze (Find-It) 2219 s = s.replace(/TotalChars-GapList\[x\]\[1\]\.HintsAndChecks/g, '(TotalChars-GapList[x][1].HintsAndChecks)'); 2220 } 2221 if (s.indexOf('CorrectLetters-Penalties/')>=0) { 2222 // special fix for "CheckAnswers" in JMatch 2223 s = s.replace(/CorrectLetters-Penalties/g, '(CorrectLetters-Penalties)'); 2224 } 2225 if (s.indexOf('TotCorrectChoices-Penalties/')>=0) { 2226 // special fix for "CheckAnswers" in JMix (v6) 2227 s = s.replace(/TotCorrectChoices-Penalties/g, '(TotCorrectChoices-Penalties)'); 2228 } 2229 if (s.indexOf('TotalCorrect-Penalties/')>=0) { 2230 // special fix for "CheckAnswers" in JMix (v6+) Drag-and_Drop 2231 s = s.replace(/TotalCorrect-Penalties/g, '(TotalCorrect-Penalties)'); 2232 } 2233 } 2234 if (s.indexOf('replace(\\[')>=0) { 2235 s = s.replace(/\\\[/g, '/\\['); 2236 s = s.replace(/\\\]/g, '\\]/g'); 2237 } 2238 if (s.indexOf('for (i')>=0 || s.indexOf('for (x')>=0) { 2239 s = s.replace(/for \(/g, 'for (var '); 2240 } 2241 eval('window.' + f + '=function(' + getArgsStr(a) + '){' + s + '}'); 2242 } else { 2243 eval('window.' + f + '=new Function(' + getArgsStr(a, true) + 's);'); 2244 } 2245 } 2246 function hpInterceptFeedback() { 2247 // modify the function which writes feedback 2248 // v6: ShowMessage(Feedback) 2249 // but Rhubarb prints score in other functions, so use 'CheckFinished' 2250 // v5: WriteFeedback(Feedback) 2251 // v4: WriteFeedback(Stuff) 2252 // v3: WriteFeedback(Feedback) [except JMatch] 2253 // v3: CheckAnswer() [JMatch only] 2254 var f = ''; 2255 if (window.CheckWord) { // Rhubarb 2256 f = 'CheckFinished'; 2257 window.FEEDBACK = null; 2258 } else if (window.ShowText) { // Sequitur 2259 f = 'CheckAnswer'; 2260 window.FEEDBACK = null; 2261 } else { // JBC, JCloze, JCross, JMatch, JMix, JQuiz 2262 f = window.ShowMessage ? 'ShowMessage' : window.WriteFeedback ? 'WriteFeedback' : 'CheckAnswer'; 2263 } 2264 if (f) { 2265 var s = getFuncCode(f) + 'Finish();'; 2266 var a = getFuncArgs(f, true); 2267 if (a[0] && window.FEEDBACK && FEEDBACK[0]) { 2268 s = a[0] + "+='<br /><br />" + '<a href="javascript:hpFeedback();">' + FEEDBACK[6] + "</A>';" + s; 2269 } 2270 hpNewFunction(f, a, s); 2271 } 2272 } 2273 function hpInterceptHints() { 2274 // modify the function which shows hints 2275 // JBC: none 2276 // JCloze v3-v6: ShowHint() 2277 // JCross v3: Cheat(), v4: ShowHint(), v5-v6[HP5]: ShowHint(Across,x,y,BoxName), v6[HP6]: ShowHint(Across,ClueNum,x,y,BoxId) 2278 // JMatch: none 2279 // JMix v5-v6: CheckAnswer(CheckType=1) 2280 // JQuiz v3: CheckAnswer(ShowHint=true, QNum), v4: CheckAnswer(ShowHint=true), v5-v6[HP5]: CheckAnswer(ShowHint=true,QNum), v6[HP6]: ShowHint(QNum) 2281 var x = ''; // extra code, if any 2282 if (window.Cheat) { 2283 // JCross v3 ? 2284 } else if (window.ShowHint) { 2285 var f = 'ShowHint'; 2286 var a = getFuncArgs(f, true); 2287 if (a.length==0) { 2288 if (window.FindCurrent) { 2289 // JCloze v3-v6 2290 x = 'var q=window.Locked?-1:FindCurrent();if(q>=0&&GetHint(q))hpClick(1,q);'; 2291 } else { 2292 // JCross v4 2293 // work out which box would have a hint added 2294 // work out which question that box is part of using GridMap and WinLetters 2295 } 2296 } else if (a[0]=='Across') { 2297 if (a[1]=='ClueNum') { 2298 // JCross v6 [HP6] 2299 x = "var args=new Array(ClueNum,Across?'A':'D');hpClick(1,args);"; 2300 } else if (a[1]=='x' && a[2]=='y') { 2301 // JCross v5-v6 [HP5] 2302 x = "var args=new Array(C[x][y],Across?'A':'D');hpClick(1,args);"; 2303 } 2304 } else if (a[0]=='QNum') { 2305 // JQuiz v6[HP6] 2306 x = 'hpClick(1,QNum);'; 2307 } 2308 } else if (window.Hint) { 2309 // Rhubarb 2310 var f = 'Hint'; 2311 var a = getFuncArgs(f, true); 2312 x = 'hpClick(1,0);'; // question number is always zero 2313 2314 } else if (window.CheckAnswer) { 2315 var f = 'CheckAnswer'; 2316 var a = getFuncArgs(f, true); 2317 if (a[0]=='ShowHint') { 2318 if (a[1]=='QNum') { 2319 // JQuiz v3, v5-v6[HP5] 2320 x = 'if(ShowHint)hpClick(1,QNum);'; 2321 } else { 2322 // JQuiz v4 2323 x = 'if(ShowHint)hpClick(1,QNum-1);'; // QNum is a global variable 2324 } 2325 } else if (a[0]=='CheckType') { 2326 // JMix v5-v6 2327 x = 'if(CheckType==1)hpClick(1,0);'; // question number is always 0; 2328 } 2329 } 2330 // add the e(x)tra code, if any, to the start of the hint (f)unction 2331 if (x) { 2332 var s = getFuncCode(f, x, '', true); 2333 hpNewFunction(f, a, s); 2334 } 2335 } 2336 function hpInterceptClues() { 2337 // modify the function which shows clues (or ShowAnswers in JQuiz) 2338 // JBC: none 2339 // JCloze v3-v6: ShowClue(ItemNum) 2340 // JCross v3-v4: ShowClue(ClueNum), v5-v6: ShowClue(ClueNum,x,y) 2341 // JMatch none 2342 // JMix none 2343 // JQuiz ShowAnswers(QNum) 2344 var x = ''; // extra code, if any 2345 if (window.ShowClue) { 2346 var f = 'ShowClue'; 2347 var a = getFuncArgs(f, true); 2348 if (a[0]=='ItemNum') { 2349 // JCloze (v3-v6) 2350 x = 'if(!window.Locked)hpClick(2,ItemNum);'; // v6 [HP6] uses window.Locked 2351 } else if (a[0]=='ClueNum') { 2352 if (a[1]=='x' && a[2]=='y') { 2353 if (window.A && window.D) { 2354 // JCross v5-v6 [HP5] 2355 x = 'if(A[ClueNum]||D[ClueNum])hpClick(2,ClueNum);'; 2356 } else if (document.getElementById) { 2357 // JCross v6 [HP6] 2358 x = "if(document.getElementById('clue_' + ClueNum)||document.getElementById('Clue_D_' + ClueNum))hpClick(2,ClueNum);"; 2359 } 2360 } else { 2361 if (window.AClues && window.DClues) { 2362 // JCross v3-v4 2363 x = 'if(AClues[ClueNum]||DClues[ClueNum])hpClick(2,ClueNum);'; 2364 } 2365 } 2366 } 2367 } 2368 // JQuiz: there is no "ShowClue" function but there is a "ShowAnswer" function 2369 if (window.ShowAnswers) { 2370 var f = 'ShowAnswers'; 2371 var a = getFuncArgs(f, true); 2372 if (window.State) { 2373 if (window.ShowMessage) { 2374 // JQuiz v6 [HP6] 2375 x = 'if(State[QNum][0]<1)hpClick(2,QNum);'; 2376 } else if (window.WriteFeedback) { 2377 // JQuiz v3-v4 2378 x = 'if(State[QNum-1][0]<1)hpClick(2,QNum-1);'; 2379 } 2380 } else if (window.Status) { 2381 // JQuiz v5-v6 [HP5] 2382 x = 'if(Status[QNum][0]<0)hpClick(5,QNum);'; 2383 } 2384 } 2385 // add the e(x)tra code, if any, to the start of the clue (f)unction 2386 if (x) { 2387 var s = getFuncCode(f, x, '', true); 2388 var s = getFuncCode(f, '', '', true); 2389 hpNewFunction(f, a, s); 2390 } 2391 } 2392 function hpInterceptChecks() { 2393 // modify the function which handles checks 2394 // JBC: none 2395 // JCloze CheckAnswers() 2396 // NB: Rottmeier Find-It 3a: CheckText(GapState,GapId) 2397 // JCross none 2398 // JMatch HP5 v3, v5, v6: CheckAnswer(), HP5 v4: CheckResults(), HP6: CheckAnswers() 2399 // JMix CheckAnswer(CheckType) 2400 // JQuiz 2401 // HP5: CheckAnswer(ShowHint, QNum) 2402 // HP6: CheckMCAnswer, CheckMultiSelAnswer, CheckShortAnswer 2403 // Rhubarb CheckWord(InputWord) 2404 // Sequitur CheckAnswer(Chosen, Btn) 2405 // HP6 JQuiz has three "Check Answer" functions 2406 var f = new Array('CheckMCAnswer', 'CheckMultiSelAnswer', 'CheckShortAnswer'); 2407 for (var i=0; i<f.length; i++) { 2408 if (eval('window.' + f[i])) { 2409 var a = getFuncArgs(f[i], true); 2410 var x = ""; 2411 if (f[i]=='CheckMCAnswer') { 2412 x += "var args=new Array(QNum,I[QNum][3][ANum][0]);"; 2413 } else if (f[i]=='CheckShortAnswer') { 2414 x += "" 2415 + "var obj=document.getElementById('Q_'+QNum+'_Guess');" 2416 + "var args=new Array(QNum,obj.value);" 2417 ; 2418 } else if (f[i]=='CheckMultiSelAnswer') { 2419 x += "" 2420 + "var g='';" 2421 + "for (var ANum=0; ANum<I[QNum][3].length; ANum++){" 2422 + "var obj=document.getElementById('Q_'+QNum+'_'+ANum+'_Chk');" 2423 + "if (obj.checked)g+=(g?'+':'')+I[QNum][3][ANum][0];" 2424 + "}" 2425 + "var args=new Array(QNum,g);" 2426 ; 2427 } 2428 if (x) { 2429 x = "if(!Finished&&State[QNum].length&&State[QNum][0]<0){" + x + "hpClick(3,args)}"; 2430 var s = getFuncCode(f[i], x, '', true); 2431 hpNewFunction(f[i], a, s); 2432 } 2433 } 2434 } 2435 var f = ''; // function name 2436 var x = ''; // extra code, if any 2437 if (window.CheckAnswer) { 2438 f = 'CheckAnswer'; 2439 var a = getFuncArgs(f, true); 2440 if (a[0]=='ShowHint') { 2441 if (a[1]=='QNum') { 2442 // JQuiz v3, v5-v6[HP5] 2443 x = 'if(!ShowHint&&Status[QNum][0]<1)hpClick(3,QNum);'; 2444 } else { 2445 // JQuiz v4 2446 x = 'if(!ShowHint&&State[QNum-1][0]<1)hpClick(3,QNum-1);'; // QNum is a global variable 2447 } 2448 } else if (a[0]=='CheckType') { 2449 // JMix v5-v6 2450 x = 'if(CheckType==0)hpClick(3,0);'; // question number is always 0; 2451 } else if (a[0]=='Chosen') { 2452 // Sequitur 2453 x = 'if (!(CurrentNumber==TotalSegments||AllDone||Btn.innerHTML==IncorrectIndicator))hpClick(3,Chosen);'; 2454 } 2455 } else if (window.CheckWord) { 2456 f = 'CheckWord'; 2457 var a = getFuncArgs(f, true); 2458 if (a[0]=='InputWord') { 2459 // Rhubarb 2460 x = 'if(!window.AllDone)hpClick(3,InputWord);'; 2461 } 2462 } else if (window.CheckText && !window.CheckAnswers) { // Rottmeier Find-It (3a) 2463 f = 'CheckText'; 2464 var a = getFuncArgs(f, true); 2465 if ((a[0]=='bool' && a[1]=='item') || (a[0]=='GapState' && a[1]=='GapId')) { 2466 x = 'if(!window.Finished&&'+a[0]+')hpClick(3,'+a[1]+');'; 2467 } 2468 } 2469 if (f) { 2470 var s = getFuncCode(f, x, '', true); 2471 hpNewFunction(f, a, s); 2472 } 2473 // JMatch has three possible check functions, depending on the version 2474 // (NB: other quiz types also have these functions) 2475 var f = new Array('CheckAnswers', 'CheckAnswer', 'CheckResults'); 2476 for (var i=0; i<f.length; i++) { 2477 if (eval('window.' + f[i])) { 2478 var a = getFuncArgs(f[i], true); 2479 if (a.length==0) { 2480 var s = getFuncCode(f[i], "hpClick(3);", '', true); 2481 hpNewFunction(f[i], a, s); 2482 break; // out of the loop 2483 } 2484 } 2485 } 2486 } 2487 // *************** 2488 // fix IE5 and NS6 2489 // *************** 2490 // add Array.push if required (allows v6 quizzes to run on ie5win) 2491 if (Array.prototype && Array.prototype.push==null) { 2492 Array.prototype.push = new Function("x", "this[this.length]=x"); 2493 } 2494 // add attachEvent function, if required (allows HP5 v6 quizzes to run on ie5mac) 2495 // NOTE: to allow v6 quizzes on ie5mac, the following code 2496 // needs to be inserted BEFORE the Hot Potatoes javascript 2497 if (window.attachEvent==null) { 2498 window.attachEvent = new Function('evt', 'fn', 'eval("window."+evt+"="+fn)'); 2499 } 2500 if (document.attachEvent==null) { 2501 document.attachEvent = new Function('evt', 'fn', 'eval("document."+evt+"="+fn)'); 2502 } 2503 // fix the ShowMessage function for NS6 2504 // by removing calls to a button's "focus()" method 2505 if (navigator.userAgent.indexOf("Netscape6")>=0 && window.ShowMessage) { 2506 var s = ShowMessage.toString(); 2507 var r = new RegExp('document\\.getElementById\\((\'|")FeedbackOKButton(\'|")\\)\\.focus\\(\\);', 'gi'); 2508 s = s.substring(s.indexOf('{')+1, s.lastIndexOf('}')).replace(r, ''); 2509 window.ShowMessage = new Function('Feedback', s); 2510 } 2511 // ns6.0 (in JMix at least) has an error in the FocusAButton function too 2512 // this could be fixed as follows ... 2513 //if (window.FocusAButton) { 2514 // window.FocusAButton = new Function('return true'); 2515 //} 2516 // however, ns6.0 then crashes completely when the mouse moves over a link, so don't bother 2517 // Hot Potatoes quiz sniffing 2518 // === v3 === 2519 // JBC uses "QuizForm", which contains elements called "Q*_**" (* and ** start at 1) 2520 // JCloze uses "Cloze" form 2521 // JCross uses "Crossword" form 2522 // JMatch uses "QuizForm", which contains elements called "1,2,3..x" and "x+1,x+2...", 2523 // and "CheckForm" form, which contains an element called "ScoreBox" 2524 // it is also the only HP quiz type to use an array called "CorrectAnswers" 2525 // JQuiz uses "QForm*" forms (* starts at 1), which each contain an element called "Guess" 2526 // === v4 === 2527 // JBC uses "QForm" form in "QuestionDiv", which contains elements called "FB* (* starts at 0)" 2528 // JCloze uses "Cloze" form in "QuestionDiv" 2529 // JCross uses "Crossword" form in "CWDiv" 2530 // JMatch uses "ExCheck" form in "TitleDiv" 2531 // (no JMix in hp4) 2532 // JQuiz uses "QForm" form in "QuestionDiv", which contains an element called "Answer" 2533 // === v5 === 2534 // JBC uses "QForm" form, which contains elements called "FB_*_**" (* and ** start at 0) 2535 // JCloze uses "Cloze" form 2536 // JCross writes out "AnswerForm" from a variable called "GetAnswerOpener" 2537 // HP5.3: uses "AnswerForm" in "BottomFrame" 2538 // HP5.5: uses "AnswerForm" in "TopFrame", but it is only there when an answer is being input 2539 // JMatch uses "QForm" form, which contains elements called "sel*" (which disappear by the time the quiz is finished) 2540 // JMix uses "ButtonForm" 2541 // JQuiz uses "QForm*" and "Buttons*" (one for each question) 2542 // === v6 === 2543 // JBC uses "QForm" form (elements have no name or id) 2544 // JCloze uses "Cloze" form (elements have no name or id) 2545 // JCross does not use any forms, 2546 // HP5: has "GridDiv" in "MainDiv" 2547 // HP6: has "Clues" table in "MainDiv" 2548 // JMatch has "MatchDiv" in "MainDiv" 2549 // HP5: uses "QForm" form, which contains elements called "sel*" 2550 // HP6: uses "QForm" form, which contains elements called "s*_**" 2551 // JMix does not use any forms, but has "SegmentDiv" in "MainDiv" 2552 // JQuiz 2553 // HP5: uses "QForm" form, which contains an element called "Guess" 2554 // HP6: has "Questions" ordered list in "MainDiv" 2555 // === v6+ === 2556 // JMatch has DIVs called "D*" and "F*" (* starts at 0) 2557 // JMix has DIVs called "D*" and "Drop*" (* starts at 0) 2558 // useful sniffing tools (Cut and Paste to browser address box) 2559 //javascript:var s="";var x=new quiz_obj();for(X in x)s+=","+X+"="+x[X];alert(s.substring(1)); 2560 //javascript:var s="";var x=document.layers;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1)) 2561 //javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1)) 2562 //javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1)) 2563 //javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1)) 2564 //javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1)) 2565 function hpDetectQuiz() { 2566 // "sniff" (=detect) the quiz's type and intended browser version 2567 // and cache the values in a global variable called "quiz" 2568 // Hot Potatoes version 2569 // 5 : HP5.3 (mac) or HP5.5 (win) 2570 // 6 : HP6.0 (mac) or HP6.0 (win) 2571 // intended browser version 2572 // 3 : ns3, ie3 (frames) 2573 // 4 : ns4, ie4 (cross browser dhtml) 2574 // 5 : ie5 (frames, send results via CGI) 2575 // 6 : ie6, op7, gecko (w3 standards) 2576 // 6.1 : "drag and drop" versions of JMatch and JMix v6 2577 // quiz type 2578 // 0 : unknown 2579 // 1 : jbc 2580 // 2 : jcloze 2581 // 3 : jcross 2582 // 4 : jmatch 2583 // 5 : jmix 2584 // 6 : jquiz 2585 // 7 : rhubarb (TexToys) 2586 // 8 : Sequitur (TexToys) 2587 // rottmeier quiz type 2588 // 1 : drop-down (JCloze) 2589 // 2 : find-it (JCloze) 2590 // shortcut to window object 2591 var w = window; 2592 // create the global "quiz" object, if necessary 2593 if (!w.quiz) w.quiz = new Object(); 2594 // Hot Potatoes version 2595 // HP6 v6: Client() 2596 // HP5 v4-v5: BrowserCheck() 2597 // v3: WinStringToMac() [JCloze, JCross, JQuiz] 2598 // v3: winrightchar [JBC, JMatch] 2599 // v3: DownTime() [JBC, JCloze, JQuiz] 2600 if (!quiz.hp) { 2601 quiz.hp = (w.Client) ? 6 : (w.BrowserCheck) ? 5 : (w.WinStringToMac || w.winrightchar) ? 5 : -1; 2602 } 2603 // check the version and type are not already set 2604 if (!quiz.v || !quiz.t) { 2605 // initialize version and type 2606 var v = 0; 2607 var t = 0; 2608 // set shortcuts to DOM objects 2609 var d = document; 2610 var f = d.forms; 2611 if (f.QuizForm && f.CheckForm && w.CorrectAnswers) { 2612 v = 3; 2613 t = 4; // jmatch 2614 } else if (w.FeedbackFrame && w.CodeFrame) { 2615 v = 3; 2616 f = CodeFrame.document.forms; 2617 t = (f.QuizForm) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.QForm1) ? 6 : 0; 2618 } else if (w.DynLayer) { 2619 v = 4; 2620 if (d.layers) { 2621 // for NS4, adjust "f" to point to a forms object in a layer 2622 var lyr = d.QuestionDiv || d.CWDiv || d.TitleDiv || null; 2623 if (lyr) f = lyr.document.forms; 2624 } 2625 t = (f.QForm && f.QForm.FB0) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.ExCheck) ? 4 : (f.QForm && f.QForm.Answer) ? 6 : 0; 2626 } else if (w.TopFrame && w.BottomFrame) { 2627 v = 5; 2628 f = BottomFrame.document.forms; 2629 t = (f.QForm && f.QForm.elements[0].name.substring(0,3)=='FB_') ? 1 : (f.Cloze) ? 2 : (w.GetAnswerOpener && GetAnswerOpener.indexOf('AnswerForm')>=0) ? 3 : (f.QForm && w.RItems) ? 4 : (f.ButtonForm) ? 5 : (f.QForm0 && f.Buttons0) ? 6 : 0; 2630 } else if (hpObj(d, 'MainDiv')) { 2631 v = 6; 2632 var obj = (f.QForm) ? f.QForm.elements : null; 2633 t = (obj && obj.length>0 && obj[0].id=='') ? 1 : (f.Cloze) ? 2 : (hpObj(d, 'GridDiv') || hpObj(d, 'Clues')) ? 3 : hpObj(d, 'MatchDiv') ? 4 : hpObj(d, 'SegmentDiv') ? 5 : ((f.QForm && f.QForm.Guess) || hpObj(d, 'Questions')) ? 6 : 0; 2634 } else if (hpObj(d, 'D0')) { 2635 v = 6.1; // drag and drop (HP5 and HP6) 2636 t = (hpObj(d, 'F0')) ? 4 : (hpObj(d, 'Drop0')) ? 5 : 0; 2637 } else if (w.Words && f.Rhubarb) { 2638 v = 6; 2639 t = 7; // rhubarb (TexToys) 2640 } else if (w.Segments && hpObj(d, 'Story')) { 2641 v = 6; 2642 t = 8; // sequitur (TexToys) 2643 } 2644 quiz.v = v; // intended browser version 2645 quiz.t = t; // quiz type 2646 } 2647 } 2648 function hpRottmeier() { 2649 hpDetectQuiz(); 2650 if (typeof(quiz.r)=='undefined') { // first-time only 2651 quiz.r = 0; 2652 if (quiz.t==2) { // JCloze 2653 if (quiz.hp==5) { // HP5 2654 // ?? 2655 } else if (quiz.hp==6) { // HP6 2656 if (window.Create_StateArray) { // Rottmeier 2657 var obj = new Create_StateArray(); 2658 if (typeof(obj.GapLocked)=='boolean') { 2659 quiz.r = 1; // drop-down (v2.4) 2660 } else if (typeof(obj.ErrorFound)=='boolean') { 2661 if (typeof(obj.GapSolved)!='boolean') { 2662 quiz.r = 2.1; // find-it (v3.1a) 2663 } else { 2664 quiz.r = 2.2; // find-it (v3.1b) 2665 } 2666 } 2667 obj = null; // prevents memory leakage on some versions of IE 2668 } 2669 } 2670 } 2671 } 2672 return quiz.r; 2673 } 2674 function hpVersion() { 2675 hpDetectQuiz(); 2676 return quiz.hp; 2677 } 2678 function hpQuizType() { 2679 hpDetectQuiz(); 2680 return quiz.t; 2681 } 2682 function hpQuizVersion() { 2683 hpDetectQuiz(); 2684 return quiz.v; 2685 } 2686 function hpScoreEngine(score_i, a, s, aa, ss, count_c, count_i) { 2687 // calculate the score for the quiz so far 2688 // score_i : amount by which to increment "score" 2689 // a : outer array 2690 // s : condition, if any, on outer array (=a) 2691 // if true, the score will be incremented by "score_i" 2692 // aa : inner array, if any 2693 // ss : condition, if any, on inner array (=aa) 2694 // count_c : condition, if any, on which "count" is to be incremented 2695 // count_i : amount by which to increment "count" 2696 // "a" and "aa" may be passed as arrays or strings containing the name of an array 2697 // "s" and "ss" are strings containing an expression to be eval(uated) 2698 // "score_i", "count_i" and "count_c" strings containing an expression to be eval(uated) 2699 var score = 0; 2700 var count = 0; 2701 // set default condition to increment "count", and amount by which to increment the count 2702 if (count_c==null) count_c = "true"; 2703 if (count_i==null) count_i = "1"; 2704 // set length of outer array. if any 2705 var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0; 2706 // loop through outer array 2707 for (var i=0; i<l; i++) { 2708 if (s==null && ss==null) { 2709 score += eval(score_i); 2710 if (eval(count_c)) count += eval(count_i); 2711 } else if (s) { 2712 score += eval(s) ? eval(score_i) : 0; 2713 if (eval(count_c)) count += eval(count_i); 2714 } else if (ss) { 2715 // set length of inner array, if any 2716 var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0; 2717 // loop through inner array. checking inner condition 2718 for (var ii=0; ii<ll; ii++) { 2719 score += eval(ss) ? eval(score_i) : 0; 2720 if (eval(count_c)) count += eval(count_i); 2721 } 2722 } 2723 } 2724 if (count) { 2725 // get p(enalties) for JCross and JMatch (and JMix ?) 2726 if (window.Penalties) { 2727 score -= (Penalties - (hpFinished() ? 0 : 1)); 2728 } 2729 // adjust count for Find-It 3a and 3b 2730 if (window.TotWrongChoices) { 2731 if (window.CheckText && !window.CheckAnswers) { // Find-It 3a 2732 // this seems a little odd, but will replicate behavior of CalculateScore() 2733 count = score + TotWrongChoices; 2734 } else { 2735 count += TotWrongChoices; 2736 } 2737 } 2738 score = Math.floor(100*score/count); 2739 if (score<0) { // just in case 2740 score = 0; 2741 } 2742 } 2743 return score; 2744 } 2745 function hpScore() { 2746 var x = ''; // score 2747 var hp = hpVersion(); 2748 var t = hpQuizType(); 2749 var v = hpQuizVersion(); 2750 if (t==1) { // jbc 2751 if (v==3) x = hpScoreEngine(1, DoneStatus, "i>0 && a[i]=='0'"); // doesn't work 2752 else if (v==4) x = hpScoreEngine(1, DoneStatus, "a[i]==0"); // doesn't work 2753 else if (v==5 || v==6) x = hpScoreEngine("a[i][3]", Status, "a[i][3]"); 2754 } else if (t==2) { // jcloze 2755 if (v==3 || v==4) x = hpScoreEngine("a[i]", Scores); 2756 else if (hp==5) x = hpScoreEngine("a[i][3]", State); // v==5 && v==6 2757 else if (hp==6) { 2758 var r = hpRottmeier(); 2759 if (r==0) x = x = hpScoreEngine("a[i].ItemScore", State); 2760 else if (r==1) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapLocked"); // dropdown 2761 else if (r==2.1) x = hpScoreEngine(1, GapList, "a[i][1].ErrorFound"); // Find-It 3a 2762 else if (r==2.2) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapSolved"); // Find-It 3b 2763 } 2764 } else if (t==3) { // jcross 2765 if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]"); 2766 else if (v==4) x = hpScoreEngine(1, WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0)==a[i].charAt(0)"); 2767 else if (v==5 || v==6) { 2768 if (window.CaseSensitive) { // HP 6.2 2769 x = hpScoreEngine(1, L, "", "L[i]", "L[i][ii] && L[i][ii]==G[i][ii]", "L[i][ii]"); 2770 } else { 2771 x = hpScoreEngine(1, L, "", "L[i]", "L[i][ii] && L[i][ii].toUpperCase()==G[i][ii].toUpperCase()", "L[i][ii]"); 2772 } 2773 } 2774 } else if (t==4) { // jmatch 2775 if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]"); 2776 else if (v==4) x = hpScoreEngine(1, Draggables, "a[i].correct=='1'"); 2777 else if (v==5) x = hpScoreEngine(1, I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]==1"); 2778 else if (v==6) x = hpScoreEngine(1, Status, "Status[i][0]==1"); 2779 else if (v==5.1 || v==6.1) x = hpScoreEngine(1, D, "D[i][2]==D[i][1] && D[i][2]>0", "", "", "i<F.length"); 2780 } else if (t==5) { // jmix 2781 // there was no v3 or v4 of JMix 2782 if (v==5 || v==6 || v==6.1) x = Math.floor(100*(Segments.length-Penalties)/Segments.length); 2783 } else if (t==6) { // jquiz 2784 if (hp==5) { 2785 if (v==3 || v==4) x = hpScoreEngine("a[i][4]/10", State, "a[i][0]==1"); 2786 else if (v==5 || v==6) x = hpScoreEngine("a[i][4]/10", Status, "a[i][0]==1", "", "", "true", "1"); 2787 } else if (hp==6) { 2788 if (v==6) x = hpScoreEngine("I[i][0]*a[i][0]", State, "a[i]&&a[i][0]>=0", "", "", "a[i]", "I[i][0]"); 2789 } 2790 } else if (t==7) { // rhubarb 2791 if (v==6) { 2792 x = Math.floor(100*Correct/TotalWords); 2793 } 2794 } else if (t==8) { // sequitur 2795 if (v==6) { 2796 var myTotalPoints = TotalPoints - (hpFinished() ? 0 : (OptionsThisQ-1)); 2797 x = Math.floor(100*ScoredPoints/myTotalPoints); 2798 } 2799 } 2800 return x; // result 2801 } 2802 function hpFinishedEngine(a, s, aa, ss) { 2803 // determine whether or not all quistions in a quiz are finished 2804 // a : outer array 2805 // s : condition, if any, on outer array 2806 // if true for any element in "a", the quiz is NOT finished 2807 // aa : inner array, if any 2808 // ss : condition, if any, on inner array 2809 // if true for any element in "aa", the quiz is NOT finished 2810 // the arrays "a" and "aa" may be passed as arrays or strings to be eval(uated) 2811 // the conditions "s" and "ss" are specified as strings to be eval(uated) 2812 // assume a positive result 2813 var x = true; 2814 // set length of outer array. if any 2815 var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0; 2816 // loop through outer array 2817 for (var i=0; i<l; i++) { 2818 // do outer condition, if any 2819 if (s && eval(s)) x = false; 2820 // set length of inner array, if any 2821 var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0; 2822 // loop through inner array. checking inner condition 2823 for (var ii=0; ii<ll; ii++) { 2824 if (ss && eval(ss)) x = false; 2825 } 2826 } 2827 return x; 2828 } 2829 function hpTimedOut() { 2830 // v5 uses "min" and "sec" 2831 // v6 uses Seconds 2832 return (typeof(self.Seconds)=='number' && Seconds==0) || (typeof(self.min)=='number' && min==0 && typeof(self.sec)=='number' && sec==0); 2833 } 2834 function hpFinished() { 2835 // assume false result 2836 var x = false; 2837 var hp = hpVersion(); 2838 var t = hpQuizType(); 2839 var v = hpQuizVersion(); 2840 if (t==1) { // jbc 2841 if (v==3) x = hpFinishedEngine(DoneStatus, "i>0 && a[i]=='0'"); 2842 else if (v==4) x = hpFinishedEngine(DoneStatus, "a[i]==0"); 2843 else if (v==5 || v==6) x = hpFinishedEngine(Status, "a[i][0]==0"); 2844 } else if (t==2) { // jcloze 2845 var r = hpRottmeier(); 2846 if (r==1) x = hpFinishedEngine(GapList, "a[i][1].GapLocked==false"); // drop-down 2847 else if (r==2.1) x = hpFinishedEngine(GapList, "a[i][1].ErrorFound==false"); // find-it 3a 2848 else if (r==2.2) x = hpFinishedEngine(GapList, "a[i][1].GapSolved==false"); // find-it 3b 2849 else if (v==3 || v==4 || v==5 || v==6) x = hpFinishedEngine(I, "CheckAnswer(i)==-1"); 2850 // also: else if (v==5 || v==6) x = hpFinishedEngine(State, "a[i][4]!=1") 2851 } else if (t==3) { // jcross 2852 if (v==3) x = hpFinishedEngine(document.Crossword.elements, "ConvertCase(is.mac?unescape(MacStringToWin(a[i].value)):a[i].value,1)!=Letters[i]"); 2853 else if (v==4) x = hpFinishedEngine(WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0) != a[i].charAt(0)"); 2854 else if (v==5 || v==6) { 2855 if (window.CaseSensitive) { // 6.2 2856 x = hpFinishedEngine(L, "", "L[i]", "L[i][ii] && L[i][ii]!=G[i][ii]"); 2857 } else { 2858 x = hpFinishedEngine(L, "", "L[i]", "L[i][ii] && L[i][ii].toUpperCase()!=G[i][ii].toUpperCase()"); 2859 } 2860 } 2861 } else if (t==4) { // jmatch 2862 if (v==3) x = hpFinishedEngine(CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex != a[i]"); 2863 else if (v==4) x = hpFinishedEngine(Draggables, "a[i].correct!='1'"); 2864 else if (v==5) x = hpFinishedEngine(I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]<1 && GetAnswer(i)!=I[i][3]"); 2865 else if (v==6) x = hpFinishedEngine(Status, "Status[i][0]<1"); 2866 else if (v==5.1 || v==6.1) x = hpFinishedEngine(D, "", F, "F[ii][1]==D[i][1]&&D[i][1]!=D[i][2]"); 2867 } else if (t==5) { // jmix 2868 // there was no v3 or v4 of JMix 2869 if (v==5 || v==6 || v==6.1) x = !hpFinishedEngine(Answers, "a[i].join(',')=='" + GuessSequence.join(',') + "'"); 2870 } else if (t==6) { // jquiz 2871 if (v==3 || v==4) x = hpFinishedEngine(State, "a[i][0]==0"); 2872 else if (v==5 || v==6) { 2873 if (hp==5) x = hpFinishedEngine(Status, "a[i][0]<1"); 2874 else if (hp==6) x = hpFinishedEngine(State, "a[i] && a[i][0]<0"); 2875 } 2876 } else if (t==7) { // rhubarb 2877 if (v==6) x = hpFinishedEngine(DoneList, "a[i]==1"); 2878 } else if (t==8) { // sequitur 2879 if (v==6) x = (CurrentNumber==TotalSegments || AllDone); 2880 } 2881 return x; 2882 } 2883 function hpObj(d, id) { 2884 return d.getElementById ? d.getElementById(id) : d.all ? d.all[id] : d[id]; 2885 } 2886 function GetViewportHeight() { 2887 if (window.innerHeight) { 2888 return innerHeight; 2889 } else { 2890 if (hpIsStrict()) { 2891 return document.documentElement.clientHeight; 2892 } else { 2893 return document.body.clientHeight; 2894 } 2895 } 2896 } 2897 function hpIsStrict() { 2898 if (!window.hpStrictIsSet) { 2899 window.hpStrictIsSet = true; 2900 window.hpStrict = false; 2901 var s = document.compatMode; 2902 if (s && s=="CSS1Compat") { // ie6 2903 window.hpStrict = true; 2904 } else { 2905 var obj = document.doctype; 2906 if (obj) { 2907 var s = obj.systemId || obj.name; // n6 || ie5mac 2908 if (s && s.indexOf("strict.dtd") >= 0) { 2909 window.hpStrict = true; 2910 } 2911 } 2912 } 2913 } 2914 return window.hpStrict; 2915 } 2916 // ************** 2917 // initialization 2918 // ************** 2919 hpInterceptFeedback(); 2920 hpInterceptHints(); 2921 hpInterceptClues(); 2922 hpInterceptChecks(); 2923 function hpFindForm(formname, w) { 2924 if (w==null) w = self; 2925 var f = w.document.forms[formname]; 2926 if (f==null && w.frames) { 2927 for (var i=0; i<w.frames.length; i++) { 2928 f = hpFindForm(formname, w.frames[i]); 2929 if (f) break; 2930 } 2931 } 2932 return f; 2933 } 2934 function Finish(quizstatus) { 2935 var mark = hpScore(); 2936 window.hpForm = hpFindForm('store'); 2937 if (hpForm) { // LMS 2938 hpForm.starttime.value = getTime(Start_Time); 2939 hpForm.endtime.value = getTime(); 2940 hpForm.mark.value = mark; 2941 hpForm.detail.value = '<?xml version="1.0"?><hpjsresult><fields>'+GetQuestionDetails()+'</fields></hpjsresult>'; 2942 if (hpForm.status) { 2943 if (!quizstatus) { 2944 // 4=completed, 3=abandoned, 2=timed-out or 1=in-progress 2945 quizstatus = hpFinished() ? 4 : hpTimedOut() ? 2 : 1; 2946 } 2947 hpForm.status.value = quizstatus; 2948 } 2949 if (!window.hpQuizResultsSent) { 2950 if (hpForm.status && quizstatus==4) { 2951 window.hpQuizResultsSent = true; 2952 } 2953 if (quizstatus==4) { // completed 2954 // wait 2 seconds for student to see feedback 2955 setTimeout("hpForm.submit();", 2000); 2956 } else { 2957 hpForm.submit(); 2958 } 2959 } 2960 } else if (hpFinished()) { 2961 SendAllResults(mark); 2962 } 2963 } 2964 // create form to send results 2965 if (DB[7] && DB[8] && !is_LMS()) { 2966 ResultForm = '' 2967 + '<html><body>' 2968 + '<form name="Results" action="" method="post" enctype="x-www-form-encoded">' 2969 + hpHiddenField('recipient', '') 2970 + hpHiddenField('subject', '') 2971 + hpHiddenField('Exercise', '') 2972 + hpHiddenField('realname', '') 2973 + hpHiddenField('Score', '') 2974 + hpHiddenField('Start_Time', '') 2975 + hpHiddenField('End_Time', '') 2976 + hpHiddenField('title', 'Thanks!') 2977 + '</form>' 2978 + '</body></html>' 2979 ; 2980 } 2981 // reassign the StartUp function 2982 var p = getPrompt(window.GetUserName || window.StartUp); 2983 var c = getStartUpCode(window.StartUp); 2984 if (p && c) { 2985 if (window.C && C.safari) { 2986 eval('window.StartUp=function(){QuizLogin("' + p + '")}'); 2987 eval('window.StartQuiz=function(){' + c + '}'); 2988 } else { 2989 window.StartUp = new Function('QuizLogin("' + p + '")'); 2990 window.StartQuiz = new Function(c); 2991 } 2992 // "QuizLogin" finshes by calling "StartQuiz" 2993 } 2994 // reassign the SendResults function 2995 window.SendResults = SendAllResults; 2996 // set start time 2997 var Start_Time = new Date(); 2998 //-->
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |