| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?PHP 2 3 class hotpot_xml_quiz_template extends hotpot_xml_template_default { 4 // left and right items for JMatch 5 var $l_items = array(); 6 var $r_items = array(); 7 8 // constructor function for this class 9 function hotpot_xml_quiz_template(&$parent) { 10 11 $this->parent = &$parent; 12 13 $get_js = optional_param('js', false); 14 $get_css = optional_param('css', false); 15 16 if (!empty($get_css)) { 17 // set $this->css 18 $this->v6_expand_StyleSheet(); 19 20 } else if (!empty($get_js)) { 21 // set $this->js 22 $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.js_', 'js'); 23 24 } else { 25 // set $this->html 26 $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.ht_', 'html'); 27 } 28 29 // expand special strings, if any 30 $pattern = ''; 31 switch ($this->parent->quiztype) { 32 case 'jcloze': 33 $pattern = '/\[(PreloadImageList)\]/'; 34 break; 35 case 'jcross': 36 $pattern = '/\[(PreloadImageList|ShowHideClueList)\]/'; 37 break; 38 case 'jmatch': 39 $pattern = '/\[(PreloadImageList|QsToShow|FixedArray|DragArray)\]/'; 40 break; 41 case 'jmix': 42 $pattern = '/\[(PreloadImageList|SegmentArray|AnswerArray)\]/'; 43 break; 44 case 'jquiz': 45 $pattern = '/\[(PreloadImageList|QsToShow)\]/'; 46 break; 47 } 48 if (!empty($pattern)) { 49 $this->expand_strings('html', $pattern); 50 } 51 } 52 53 // captions and messages 54 55 function v6_expand_AlsoCorrect() { 56 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct'); 57 } 58 function v6_expand_CapitalizeFirst() { 59 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',capitalize-first-letter'); 60 } 61 function v6_expand_CheckCaption() { 62 return $this->parent->xml_value('hotpot-config-file,global,check-caption'); 63 } 64 function v6_expand_CorrectIndicator() { 65 return $this->js_value('hotpot-config-file,global,correct-indicator'); 66 } 67 function v6_expand_Back() { 68 return $this->int_value('hotpot-config-file,global,include-back'); 69 } 70 function v6_expand_BackCaption() { 71 return $this->parent->xml_value('hotpot-config-file,global,back-caption'); 72 } 73 function v6_expand_ClickToAdd() { 74 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',click-to-add'); 75 } 76 function v6_expand_ClueCaption() { 77 return $this->parent->xml_value('hotpot-config-file,global,clue-caption'); 78 } 79 function v6_expand_Clues() { 80 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clues'); 81 } 82 function v6_expand_Contents() { 83 return $this->int_value('hotpot-config-file,global,include-contents'); 84 } 85 function v6_expand_ContentsCaption() { 86 return $this->parent->xml_value('hotpot-config-file,global,contents-caption'); 87 } 88 function v6_expand_GuessCorrect() { 89 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-correct'); 90 } 91 function v6_expand_GuessIncorrect() { 92 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-incorrect'); 93 } 94 function v6_expand_Hint() { 95 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-hint'); 96 } 97 function v6_expand_HintCaption() { 98 return $this->parent->xml_value('hotpot-config-file,global,hint-caption'); 99 } 100 function v6_expand_IncorrectIndicator() { 101 return $this->js_value('hotpot-config-file,global,incorrect-indicator'); 102 } 103 function v6_expand_LastQCaption() { 104 $caption = $this->parent->xml_value('hotpot-config-file,global,last-q-caption'); 105 return ($caption=='<=' ? '<=' : $caption); 106 } 107 function v6_expand_NextCorrect() { 108 $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-part'); 109 if (empty($value)) { // jquiz 110 $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter'); 111 } 112 return $value; 113 } 114 function v6_expand_NextEx() { 115 return $this->int_value('hotpot-config-file,global,include-next-ex'); 116 } 117 function v6_expand_NextExCaption() { 118 $caption = $this->parent->xml_value('hotpot-config-file,global,next-ex-caption'); 119 return ($caption=='=>' ? '=>' : $caption); 120 } 121 function v6_expand_NextQCaption() { 122 return $this->parent->xml_value('hotpot-config-file,global,next-q-caption'); 123 } 124 function v6_expand_OKCaption() { 125 return $this->parent->xml_value('hotpot-config-file,global,ok-caption'); 126 } 127 function v6_expand_Restart() { 128 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-restart'); 129 } 130 function v6_expand_RestartCaption() { 131 return $this->parent->xml_value('hotpot-config-file,global,restart-caption'); 132 } 133 function v6_expand_ShowAllQuestionsCaption() { 134 return $this->js_value('hotpot-config-file,global,show-all-questions-caption'); 135 } 136 function v6_expand_ShowOneByOneCaption() { 137 return $this->js_value('hotpot-config-file,global,show-one-by-one-caption'); 138 } 139 function v6_expand_TheseAnswersToo() { 140 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct'); 141 } 142 function v6_expand_ThisMuch() { 143 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',this-much-correct'); 144 } 145 function v6_expand_Undo() { 146 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-undo'); 147 } 148 function v6_expand_UndoCaption() { 149 return $this->parent->xml_value('hotpot-config-file,global,undo-caption'); 150 } 151 function v6_expand_YourScoreIs() { 152 return $this->js_value('hotpot-config-file,global,your-score-is'); 153 } 154 155 // reading 156 157 function v6_expand_Reading() { 158 return $this->int_value('data,reading,include-reading'); 159 } 160 function v6_expand_ReadingText() { 161 $title = $this->v6_expand_ReadingTitle(); 162 $value = $this->parent->xml_value('data,reading,reading-text'); 163 $value = empty($value) ? '' : ('<div class="ReadingText">'.$value.'</div>'); 164 return $title.$value; 165 } 166 function v6_expand_ReadingTitle() { 167 $value = $this->parent->xml_value('data,reading,reading-title'); 168 return empty($value) ? '' : ('<h3 class="ExerciseSubtitle">'.$value.'</h3>'); 169 } 170 171 // timer 172 173 function v6_expand_Timer() { 174 return $this->int_value('data,timer,include-timer'); 175 } 176 function v6_expand_JSTimer() { 177 return $this->read_template('hp6timer.js_'); 178 } 179 function v6_expand_Seconds() { 180 return $this->parent->xml_value('data,timer,seconds'); 181 } 182 183 // send results 184 185 function v6_expand_SendResults() { 186 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',send-email'); 187 } 188 function v6_expand_JSSendResults() { 189 return $this->read_template('hp6sendresults.js_'); 190 } 191 function v6_expand_FormMailURL() { 192 return $this->parent->xml_value('hotpot-config-file,global,formmail-url'); 193 } 194 function v6_expand_EMail() { 195 return $this->parent->xml_value('hotpot-config-file,global,email'); 196 } 197 function v6_expand_NamePlease() { 198 return $this->js_value('hotpot-config-file,global,name-please'); 199 } 200 201 // preload images 202 203 function v6_expand_PreloadImages() { 204 $value = $this->v6_expand_PreloadImageList(); 205 return empty($value) ? false : true; 206 } 207 function v6_expand_PreloadImageList() { 208 209 // check it has not been set already 210 if (!isset($this->PreloadImageList)) { 211 212 // the list of image urls 213 $list = array(); 214 215 // extract <img> tags 216 $img_tag = htmlspecialchars('|<img.*?src="(.*?)".*?>|is'); 217 if (preg_match_all($img_tag, $this->parent->source, $matches)) { 218 $list = $matches[1]; 219 220 // remove duplicates 221 $list = array_unique($list); 222 } 223 224 // convert to comma delimited string 225 $this->PreloadImageList = empty($list) ? '' : "'".implode(',', $list)."'"; 226 } 227 return $this->PreloadImageList; 228 } 229 230 // html files (all quiz types) 231 232 function v6_expand_PlainTitle() { 233 return $this->parent->xml_value('data,title'); 234 } 235 function v6_expand_ExerciseSubtitle() { 236 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',exercise-subtitle'); 237 } 238 function v6_expand_Instructions() { 239 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',instructions'); 240 } 241 function v6_expand_DublinCoreMetadata() { 242 $dc = '<link rel="schema.DC" href="'.$this->parent->xml_value('', "['rdf:RDF'][0]['@']['xmlns:dc']").'" />'."\n"; 243 if (is_string($this->parent->xml_value('rdf:RDF,rdf:Description'))) { 244 // do nothing (there is no more dc info) 245 } else { 246 $dc .= '<meta name="DC:Creator" content="'.$this->parent->xml_value('rdf:RDF,rdf:Description,dc:creator').'" />'."\n"; 247 $dc .= '<meta name="DC:Title" content="'.strip_tags($this->parent->xml_value('rdf:RDF,rdf:Description,dc:title')).'" />'."\n"; 248 } 249 return $dc; 250 } 251 function v6_expand_FullVersionInfo() { 252 global $CFG; 253 require_once($CFG->hotpotroot.DIRECTORY_SEPARATOR.'version.php'); // set $module 254 return $this->parent->xml_value('version').'.x (Moodle '.$CFG->release.', hotpot-module '.$this->parent->obj_value($module, 'release').')'; 255 } 256 function v6_expand_HeaderCode() { 257 return $this->parent->xml_value('hotpot-config-file,global,header-code'); 258 } 259 function v6_expand_StyleSheet() { 260 $this->read_template('hp6.cs_', 'css'); 261 $this->css = hotpot_convert_stylesheets_urls($this->parent->get_baseurl(), $this->parent->reference, $this->css); 262 return $this->css; 263 } 264 265 // stylesheet (hp6.cs_) 266 267 function v6_expand_PageBGColor() { 268 return $this->parent->xml_value('hotpot-config-file,global,page-bg-color'); 269 } 270 function v6_expand_GraphicURL() { 271 return $this->parent->xml_value('hotpot-config-file,global,graphic-url'); 272 } 273 function v6_expand_ExBGColor() { 274 return $this->parent->xml_value('hotpot-config-file,global,ex-bg-color'); 275 } 276 277 function v6_expand_FontFace() { 278 return $this->parent->xml_value('hotpot-config-file,global,font-face'); 279 } 280 function v6_expand_FontSize() { 281 $value = $this->parent->xml_value('hotpot-config-file,global,font-size'); 282 return (empty($value) ? 'small' : $value); 283 } 284 function v6_expand_TextColor() { 285 return $this->parent->xml_value('hotpot-config-file,global,text-color'); 286 } 287 function v6_expand_TitleColor() { 288 return $this->parent->xml_value('hotpot-config-file,global,title-color'); 289 } 290 function v6_expand_LinkColor() { 291 return $this->parent->xml_value('hotpot-config-file,global,link-color'); 292 } 293 function v6_expand_VLinkColor() { 294 return $this->parent->xml_value('hotpot-config-file,global,vlink-color'); 295 } 296 297 function v6_expand_NavTextColor() { 298 return $this->parent->xml_value('hotpot-config-file,global,page-bg-color'); 299 } 300 function v6_expand_NavBarColor() { 301 return $this->parent->xml_value('hotpot-config-file,global,nav-bar-color'); 302 } 303 function v6_expand_NavLightColor() { 304 $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color'); 305 return $this->get_halfway_color($color, '#ffffff'); 306 } 307 function v6_expand_NavShadeColor() { 308 $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color'); 309 return $this->get_halfway_color($color, '#000000'); 310 } 311 312 function v6_expand_FuncLightColor() { // top-left of buttons 313 $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color'); 314 return $this->get_halfway_color($color, '#ffffff'); 315 } 316 function v6_expand_FuncShadeColor() { // bottom right of buttons 317 $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color'); 318 return $this->get_halfway_color($color, '#000000'); 319 } 320 321 // navigation buttons 322 323 function v6_expand_NavButtons() { 324 $back = $this->v6_expand_Back(); 325 $next_ex = $this->v6_expand_NextEx(); 326 $contents = $this->v6_expand_Contents(); 327 return (empty($back) && empty($next_ex) && empty($contents) ? false : true); 328 } 329 function v6_expand_NavBarJS() { 330 return $this->v6_expand_NavButtons(); 331 } 332 333 // switch off scorm 334 function v6_expand_Scorm12() { 335 return false; 336 } 337 338 // js files (all quiz types) 339 340 function v6_expand_JSBrowserCheck() { 341 return $this->read_template('hp6browsercheck.js_'); 342 } 343 function v6_expand_JSButtons() { 344 return $this->read_template('hp6buttons.js_'); 345 } 346 function v6_expand_JSCard() { 347 return $this->read_template('hp6card.js_'); 348 } 349 function v6_expand_JSCheckShortAnswer() { 350 return $this->read_template('hp6checkshortanswer.js_'); 351 } 352 function v6_expand_JSHotPotNet() { 353 return $this->read_template('hp6hotpotnet.js_'); 354 } 355 function v6_expand_JSShowMessage() { 356 return $this->read_template('hp6showmessage.js_'); 357 } 358 function v6_expand_JSUtilities() { 359 return $this->read_template('hp6utilities.js_'); 360 } 361 362 // js files 363 364 function v6_expand_JSJCloze6() { 365 return $this->read_template('jcloze6.js_'); 366 } 367 function v6_expand_JSJCross6() { 368 return $this->read_template('jcross6.js_'); 369 } 370 function v6_expand_JSJMatch6() { 371 return $this->read_template('jmatch6.js_'); 372 } 373 function v6_expand_JSJMix6() { 374 return $this->read_template('jmix6.js_'); 375 } 376 function v6_expand_JSJQuiz6() { 377 return $this->read_template('jquiz6.js_'); 378 } 379 380 // drag and drop 381 382 function v6_expand_JSDJMatch6() { 383 return $this->read_template('djmatch6.js_'); 384 } 385 function v6_expand_JSDJMix6() { 386 return $this->read_template('djmix6.js_'); 387 } 388 389 // what are these for? 390 391 function v6_expand_JSFJMatch6() { 392 return $this->read_template('fjmatch6.js_'); 393 } 394 function v6_expand_JSFJMix6() { 395 return $this->read_template('fjmix6.js_'); 396 } 397 398 // jmatch6.js_ 399 400 function v6_expand_ShuffleQs() { 401 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-questions'); 402 } 403 function v6_expand_QsToShow() { 404 $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-limited-questions'); 405 if ($i) { 406 $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',questions-to-show'); 407 } 408 if (empty($i)) { 409 $i = 0; 410 switch ($this->parent->quiztype) { 411 case 'jmatch': 412 $values = $this->parent->xml_values('data,matching-exercise,pair'); 413 $i = count($values); 414 break; 415 case 'jquiz': 416 $tags = 'data,questions,question-record'; 417 while (($question="[$i]['#']") && $this->parent->xml_value($tags, $question)) { 418 $i++; 419 } 420 break; 421 } // end switch 422 } 423 return $i; 424 } 425 function v6_expand_MatchDivItems() { 426 $this->set_jmatch_items(); 427 428 $l_keys = $this->shuffle_jmatch_items($this->l_items); 429 $r_keys = $this->shuffle_jmatch_items($this->r_items); 430 431 $options = '<option value="x">'.$this->parent->xml_value('data,matching-exercise,default-right-item').'</option>'; 432 foreach ($r_keys as $key) { 433 if (! $this->r_items[$key]['fixed']) { 434 $options .= '<option value="'.$key.'">'.$this->r_items[$key]['text'].'</option>'."\n"; 435 } 436 } 437 438 $str = ''; 439 foreach ($l_keys as $key) { 440 $str .= '<tr><td class="LeftItem">'.$this->l_items[$key]['text'].'</td>'; 441 $str .= '<td class="RightItem">'; 442 if ($this->r_items[$key]['fixed']) { 443 $str .= $this->r_items[$key]['text']; 444 } else { 445 $str .= '<select id="s'.$key.'_'.$key.'">'.$options.'</select>'; 446 } 447 $str .= '</td><td></td></tr>'; 448 } 449 return $str; 450 } 451 452 // jmix6.js_ 453 454 function v6_expand_Punctuation() { 455 $tags = 'data,jumbled-order-exercise'; 456 $chars = array_merge( 457 $this->jmix_Punctuation("$tags,main-order,segment"), 458 $this->jmix_Punctuation("$tags,alternate") 459 ); 460 $chars = array_unique($chars); 461 $chars = implode('', $chars); 462 $chars = $this->js_safe($chars, true); 463 return $chars; 464 } 465 function jmix_Punctuation($tags) { 466 $chars = array(); 467 468 // all punctutation except '&#;' (because they are used in html entities) 469 $ENTITIES = $this->jmix_encode_punctuation('!"$%'."'".'()*+,-./:<=>?@[\]^_`{|}~'); 470 $pattern = "/&#x([0-9A-F]+);/i"; 471 $i = 0; 472 473 // get next segment (or alternate answer) 474 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) { 475 476 // convert low-ascii punctuation to entities 477 $value = strtr($value, $ENTITIES); 478 479 // extract all hex HTML entities 480 if (preg_match_all($pattern, $value, $matches)) { 481 482 // loop through hex entities 483 $m_max = count($matches[0]); 484 for ($m=0; $m<$m_max; $m++) { 485 486 // convert to hex number 487 eval('$hex=0x'.$matches[1][$m].';'); 488 489 // is this a punctuation character? 490 if ( 491 ($hex>=0x0020 && $hex<=0x00BF) || // ascii punctuation 492 ($hex>=0x2000 && $hex<=0x206F) || // general punctuation 493 ($hex>=0x3000 && $hex<=0x303F) || // CJK punctuation 494 ($hex>=0xFE30 && $hex<=0xFE4F) || // CJK compatability 495 ($hex>=0xFE50 && $hex<=0xFE6F) || // small form variants 496 ($hex>=0xFF00 && $hex<=0xFF40) || // halfwidth and fullwidth forms (1) 497 ($hex>=0xFF5B && $hex<=0xFF65) || // halfwidth and fullwidth forms (2) 498 ($hex>=0xFFE0 && $hex<=0xFFEE) // halfwidth and fullwidth forms (3) 499 ) { 500 // add this character 501 $chars[] = $matches[0][$m]; 502 } 503 } 504 } 505 $i++; 506 } 507 508 return $chars; 509 } 510 function v6_expand_OpenPunctuation() { 511 $tags = 'data,jumbled-order-exercise'; 512 $chars = array_merge( 513 $this->jmix_OpenPunctuation("$tags,main-order,segment"), 514 $this->jmix_OpenPunctuation("$tags,alternate") 515 ); 516 $chars = array_unique($chars); 517 $chars = implode('', $chars); 518 $chars = $this->js_safe($chars, true); 519 return $chars; 520 } 521 function jmix_OpenPunctuation($tags) { 522 $chars = array(); 523 524 // unicode punctuation designations (pi="initial quote", ps="open") 525 // http://www.sql-und-xml.de/unicode-database/pi.html 526 // http://www.sql-und-xml.de/unicode-database/ps.html 527 $pi = '0022|0027|00AB|2018|201B|201C|201F|2039'; 528 $ps = '0028|005B|007B|0F3A|0F3C|169B|201A|201E|2045|207D|208D|2329|23B4|2768|276A|276C|276E|2770|2772|2774|27E6|27E8|27EA|2983|2985|2987|2989|298B|298D|298F|2991|2993|2995|2997|29D8|29DA|29FC|3008|300A|300C|300E|3010|3014|3016|3018|301A|301D|FD3E|FE35|FE37|FE39|FE3B|FE3D|FE3F|FE41|FE43|FE47|FE59|FE5B|FE5D|FF08|FF3B|FF5B|FF5F|FF62'; 529 $pattern = "/(&#x($pi|$ps);)/i"; 530 531 $ENTITIES = $this->jmix_encode_punctuation('"'."'".'(<[{'); 532 533 $i = 0; 534 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) { 535 $value = strtr($value, $ENTITIES); 536 if (preg_match_all($pattern, $value, $matches)) { 537 $chars = array_merge($chars, $matches[0]); 538 } 539 $i++; 540 } 541 542 return $chars; 543 } 544 function jmix_encode_punctuation($str) { 545 $ENTITIES = array(); 546 $i_max = strlen($str); 547 for ($i=0; $i<$i_max; $i++) { 548 $ENTITIES[$str{$i}] = '&#x'.sprintf('%04X', ord($str{$i})).';'; 549 } 550 return $ENTITIES; 551 } 552 function v6_expand_ExerciseTitle() { 553 return $this->parent->xml_value('data,title'); 554 } 555 556 // Jmix specials 557 558 function v6_expand_SegmentArray() { 559 560 $segments = array(); 561 $values = array(); 562 $VALUES = array(); 563 564 // XML tags to the start of a segment 565 $tags = 'data,jumbled-order-exercise,main-order,segment'; 566 567 $i = 0; 568 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) { 569 $VALUE = strtoupper($value); 570 $key = array_search($VALUE, $VALUES); 571 if (is_numeric($key)) { 572 $segments[] = $key; 573 } else { 574 $segments[] = $i; 575 $values[$i] = $value; 576 $VALUES[$i] = $VALUE; 577 } 578 $i++; 579 } 580 581 $this->seed_random_number_generator(); 582 $keys = array_keys($segments); 583 shuffle($keys); 584 585 $str = ''; 586 for($i=0; $i<count($keys); $i++) { 587 $key = $segments[$keys[$i]]; 588 $str .= "Segments[$i] = new Array();\n"; 589 $str .= "Segments[$i][0] = '".$this->js_safe($values[$key], true)."';\n"; 590 $str .= "Segments[$i][1] = ".($key+1).";\n"; 591 $str .= "Segments[$i][2] = 0;\n"; 592 } 593 return $str; 594 } 595 function v6_expand_AnswerArray() { 596 597 $segments = array(); 598 $values = array(); 599 $VALUES = array(); 600 $escapedvalues = array(); 601 602 // XML tags to the start of a segment 603 $tags = 'data,jumbled-order-exercise,main-order,segment'; 604 605 $i = 0; 606 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) { 607 $VALUE = strtoupper($value); 608 $key = array_search($VALUE, $VALUES); 609 if (is_numeric($key)) { 610 $segments[] = $key+1; 611 } else { 612 $segments[] = $i+1; 613 $values[$i] = $value; 614 $VALUES[$i] = $VALUE; 615 $escapedvalues[] = preg_quote($value, '/'); 616 } 617 $i++; 618 } 619 620 // start the answers array 621 $a = 0; 622 $str = 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n"; 623 624 // pattern to match the next part of an alternate answer 625 $pattern = '/^('.implode('|', $escapedvalues).')\\s*/i'; 626 627 // XML tags to the start of an alternate answer 628 $tags = 'data,jumbled-order-exercise,alternate'; 629 630 $i = 0; 631 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) { 632 $segments = array(); 633 while (strlen($value) && preg_match($pattern, $value, $matches)) { 634 $key = array_search($matches[1], $values); 635 if (is_numeric($key)) { 636 $segments[] = $key+1; 637 $value = substr($value, strlen($matches[0])); 638 } else { 639 // invalid alternate sequence 640 $segments = array(); 641 break; 642 } 643 } 644 if (count($segments)) { 645 $str .= 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n"; 646 } 647 $i++; 648 } 649 return $str; 650 } 651 652 // =============================================================== 653 654 // JMix (jmix6.js_) 655 656 function v6_expand_RemainingWords() { 657 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',remaining-words'); 658 } 659 function v6_expand_TimesUp() { 660 return $this->js_safe($this->parent->xml_value('hotpot-config-file,global,times-up')); 661 } 662 663 // nav bar 664 665 function v6_expand_NavBar($navbarid='') { 666 $this->navbarid = $navbarid; 667 668 $tag = 'navbar'; 669 $this->read_template('hp6navbar.ht_', $tag); 670 671 unset($this->navbarid); 672 673 return $this->$tag; 674 } 675 function v6_expand_TopNavBar() { 676 return $this->v6_expand_NavBar('TopNavBar'); 677 } 678 function v6_expand_BottomNavBar() { 679 return $this->v6_expand_NavBar('BottomNavBar'); 680 } 681 682 // hp6navbar.ht_ 683 684 function v6_expand_NavBarID() { 685 // $this->navbarid is set in "$this->v6_expand_NavBar" 686 return empty($this->navbarid) ? '' : $this->navbarid; 687 } 688 function v6_expand_ContentsURL() { 689 $url = $this->parent->xml_value('hotpot-config-file,global,contents-url'); 690 if ($url) { 691 $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course); 692 } 693 return $url; 694 } 695 function v6_expand_NextExURL() { 696 $url = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',next-ex-url'); 697 if ($url) { 698 $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course); 699 } 700 return $url; 701 } 702 703 // conditional blocks 704 705 function v6_expand_ShowAnswer() { 706 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-show-answer'); 707 } 708 function v6_expand_Slide() { 709 return true; // whats's this (JMatch drag and drop) 710 } 711 712 // specials (JMatch) 713 714 function v6_expand_FixedArray() { 715 $this->set_jmatch_items(); 716 $str = ''; 717 foreach ($this->l_items as $i=>$item) { 718 for ($ii=0; $ii<$i; $ii++) { 719 if ($this->r_items[$ii]['text']==$this->r_items[$i]['text']) { 720 break; 721 } 722 } 723 $str .= "F[$i] = new Array();\n"; 724 $str .= "F[$i][0] = '".$this->js_safe($item['text'], true)."';\n"; 725 $str .= "F[$i][1] = ".($ii+1).";\n"; 726 } 727 return $str; 728 } 729 function v6_expand_DragArray() { 730 $this->set_jmatch_items(); 731 $str = ''; 732 foreach ($this->r_items as $i=>$item) { 733 for ($ii=0; $ii<$i; $ii++) { 734 if ($this->r_items[$ii]['text']==$this->r_items[$i]['text']) { 735 break; 736 } 737 } 738 $str .= "D[$i] = new Array();\n"; 739 $str .= "D[$i][0] = '".$this->js_safe($item['text'], true)."';\n"; 740 $str .= "D[$i][1] = ".($ii+1).";\n"; 741 $str .= "D[$i][2] = ".$item['fixed'].";\n"; 742 } 743 return $str; 744 } 745 746 function set_jmatch_items() { 747 if (count($this->l_items)) { 748 return; 749 } 750 $tags = 'data,matching-exercise,pair'; 751 $i = 0; 752 while (($item = "[$i]['#']") && $this->parent->xml_value($tags, $item)) { 753 $leftitem = $item."['left-item'][0]['#']"; 754 $lefttext = $this->parent->xml_value($tags, $leftitem."['text'][0]['#']"); 755 756 $rightitem = $item."['right-item'][0]['#']"; 757 $righttext = $this->parent->xml_value($tags, $rightitem."['text'][0]['#']"); 758 759 if (strlen($righttext)) { 760 $addright = true; 761 } else { 762 $addright = false; 763 } 764 if (strlen($lefttext)) { 765 $this->l_items[] = array( 766 'text' => $lefttext, 767 'fixed' => $this->int_value($tags, $leftitem."['fixed'][0]['#']") 768 ); 769 $addright = true; // force right item to be added 770 } 771 if ($addright) { 772 $this->r_items[] = array( 773 'text' => $righttext, 774 'fixed' => $this->int_value($tags, $rightitem."['fixed'][0]['#']") 775 ); 776 } 777 $i++; 778 } 779 } 780 function shuffle_jmatch_items(&$items) { 781 // get moveable items 782 $moveable_keys = array(); 783 for($i=0; $i<count($items); $i++) { 784 if(empty($items[$i]['fixed'])) { 785 $moveable_keys[] = $i; 786 } 787 } 788 // shuffle moveable items 789 $this->seed_random_number_generator(); 790 shuffle($moveable_keys); 791 792 $keys = array(); 793 for($i=0, $ii=0; $i<count($items); $i++) { 794 if(empty($items[$i]['fixed'])) { 795 // moveable items are inserted in a shuffled order 796 $keys[] = $moveable_keys[$ii++]; 797 } else { 798 // fixed items stay where they are 799 $keys[] = $i; 800 } 801 } 802 return $keys; 803 } 804 function seed_random_number_generator() { 805 static $seeded_RNG = FALSE; 806 if (!$seeded_RNG) { 807 srand((double) microtime() * 1000000); 808 $seeded_RNG = TRUE; 809 } 810 } 811 812 // specials (JMix) 813 814 815 // specials (JCloze) 816 817 function v6_expand_ItemArray() { 818 $q = 0; 819 $str = ''; 820 switch ($this->parent->quiztype) { 821 case 'jcloze': 822 $tags = 'data,gap-fill,question-record'; 823 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) { 824 $a = 0; 825 $aa = 0; 826 while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) { 827 $text = $this->js_value($tags, $answer."['text'][0]['#']", true); 828 if (strlen($text)) { 829 if ($aa==0) { // first time only 830 $str .= "\n"; 831 $str .= "I[$q] = new Array();\n"; 832 $str .= "I[$q][1] = new Array();\n"; 833 } 834 $str .= "I[$q][1][$aa] = new Array();\n"; 835 $str .= "I[$q][1][$aa][0] = '$text';\n"; 836 $aa++; 837 } 838 $a++; 839 } 840 // add clue, if any answers were found 841 if ($aa) { 842 $clue = $this->js_value($tags, $question."['clue'][0]['#']", true); 843 $str .= "I[$q][2] = '$clue';\n"; 844 } 845 $q++; 846 } 847 break; 848 case 'jquiz': 849 $str .= "I=new Array();\n"; 850 $tags = 'data,questions,question-record'; 851 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) { 852 853 $question_type = $this->int_value($tags, $question."['question-type'][0]['#']"); 854 $weighting = $this->int_value($tags, $question."['weighting'][0]['#']"); 855 $clue = $this->js_value($tags, $question."['clue'][0]['#']", true); 856 857 $answers = $question."['answers'][0]['#']"; 858 859 $a = 0; 860 $aa = 0; 861 while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) { 862 $text = $this->js_value($tags, $answer."['text'][0]['#']", true); 863 $feedback = $this->js_value($tags, $answer."['feedback'][0]['#']", true); 864 $correct = $this->int_value($tags, $answer."['correct'][0]['#']"); 865 $percent = $this->int_value($tags, $answer."['percent-correct'][0]['#']"); 866 $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']"); 867 if (strlen($text)) { 868 if ($aa==0) { // first time only 869 $str .= "\n"; 870 $str .= "I[$q] = new Array();\n"; 871 $str .= "I[$q][0] = $weighting;\n"; 872 $str .= "I[$q][1] = '$clue';\n"; 873 $str .= "I[$q][2] = '".($question_type-1)."';\n"; 874 $str .= "I[$q][3] = new Array();\n"; 875 } 876 $str .= "I[$q][3][$aa] = new Array('$text','$feedback',$correct,$percent,$include);\n"; 877 $aa++; 878 } 879 $a++; 880 } 881 $q++; 882 } 883 break; 884 } 885 return $str; 886 } 887 888 function v6_expand_ClozeBody() { 889 $str = ''; 890 891 // get drop down list of words, if required 892 $dropdownlist = ''; 893 if ($this->v6_use_DropDownList()) { 894 $this->v6_set_WordList(); 895 foreach ($this->wordlist as $word) { 896 $dropdownlist .= '<option value="'.$word.'">'.$word.'</option>'; 897 } 898 } 899 900 // cache clues flag and caption 901 $includeclues = $this->v6_expand_Clues(); 902 $cluecaption = $this->v6_expand_ClueCaption(); 903 904 // detect if cloze starts with gap 905 $strpos = strpos($this->parent->source, '<gap-fill><question-record>'); 906 if (is_numeric($strpos)) { 907 $startwithgap = true; 908 } else { 909 $startwithgap = false; 910 } 911 912 // initialize loop values 913 $q = 0; 914 $tags = 'data,gap-fill'; 915 $question_record = "$tags,question-record"; 916 917 // loop through text and gaps 918 do { 919 $text = $this->parent->xml_value($tags, "[0]['#'][$q]"); 920 $gap = ''; 921 if (($question="[$q]['#']") && $this->parent->xml_value($question_record, $question)) { 922 $gap .= '<span class="GapSpan" id="GapSpan'.$q.'">'; 923 if ($this->v6_use_DropDownList()) { 924 $gap .= '<select id="Gap'.$q.'"><option value=""></option>'.$dropdownlist.'</select>'; 925 } else { 926 // minimum gap size 927 if (! $gapsize = $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',minimum-gap-size')) { 928 $gapsize = 6; 929 } 930 931 // increase gap size to length of longest answer for this gap 932 $a = 0; 933 while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($question_record, $answer)) { 934 $answertext = $this->parent->xml_value($question_record, $answer."['text'][0]['#']"); 935 $answertext = preg_replace('|&[#a-zA-Z0-9]+;|', 'x', $answertext); 936 $gapsize = max($gapsize, strlen($answertext)); 937 $a++; 938 } 939 940 $gap .= '<input type="text" id="Gap'.$q.'" onfocus="TrackFocus('.$q.')" onblur="LeaveGap()" class="GapBox" size="'.$gapsize.'"></input>'; 941 } 942 if ($includeclues) { 943 $clue = $this->parent->xml_value($question_record, $question."['clue'][0]['#']"); 944 if (strlen($clue)) { 945 $gap .= '<button style="line-height: 1.0" class="FuncButton" onfocus="FuncBtnOver(this)" onmouseover="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="ShowClue('.$q.')">'.$cluecaption.'</button>'; 946 } 947 } 948 $gap .= '</span>'; 949 } 950 if ($startwithgap) { 951 $str .= "$gap$text"; 952 } else { 953 $str .= "$text$gap"; 954 } 955 $q++; 956 } while (strlen($text) || strlen($gap)); 957 958 return $str; 959 } 960 961 // JCloze quiztype 962 963 function v6_expand_WordList() { 964 $str = ''; 965 if ($this->v6_include_WordList()) { 966 $this->v6_set_WordList(); 967 $str = implode('    ', $this->wordlist); 968 } 969 return $str; 970 } 971 function v6_include_WordList() { 972 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-word-list'); 973 } 974 function v6_use_DropDownList() { 975 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',use-drop-down-list'); 976 } 977 function v6_set_WordList() { 978 979 if (isset($this->wordlist)) { 980 // do nothing 981 } else { 982 $this->wordlist = array(); 983 984 // is the wordlist required 985 if ($this->v6_include_WordList() || $this->v6_use_DropDownList()) { 986 987 $q = 0; 988 $tags = 'data,gap-fill,question-record'; 989 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) { 990 $a = 0; 991 $aa = 0; 992 while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) { 993 $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']"); 994 $correct = $this->int_value($tags, $answer."['correct'][0]['#']"); 995 if ($text && $correct) { // $correct is always true 996 $this->wordlist[] = $text; 997 $aa++; 998 } 999 $a++; 1000 } 1001 $q++; 1002 } 1003 $this->wordlist = array_unique($this->wordlist); 1004 sort($this->wordlist); 1005 } 1006 } 1007 } 1008 function v6_expand_Keypad() { 1009 $str = ''; 1010 if ($this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-keypad')) { 1011 1012 // these characters must always be in the keypad 1013 $chars = array(); 1014 $this->add_keypad_chars($chars, $this->parent->xml_value('hotpot-config-file,global,keypad-characters')); 1015 1016 // append other characters used in the answers 1017 $tags = ''; 1018 switch ($this->parent->quiztype) { 1019 case 'jcloze': 1020 $tags = 'data,gap-fill,question-record'; 1021 break; 1022 case 'jquiz': 1023 $tags = 'data,questions,question-record'; 1024 break; 1025 } 1026 if ($tags) { 1027 $q = 0; 1028 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) { 1029 1030 if ($this->parent->quiztype=='jquiz') { 1031 $answers = $question."['answers'][0]['#']"; 1032 } else { 1033 $answers = $question; 1034 } 1035 1036 $a = 0; 1037 while (($answer=$answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) { 1038 $this->add_keypad_chars($chars, $this->parent->xml_value($tags, $answer."['text'][0]['#']")); 1039 $a++; 1040 } 1041 $q++; 1042 } 1043 } 1044 1045 // remove duplicate characters and sort 1046 $chars = array_unique($chars); 1047 usort($chars, "hotpot_sort_keypad_chars"); 1048 1049 // create keypad buttons for each character 1050 foreach ($chars as $char) { 1051 $str .= "<button onclick=\"TypeChars('".$this->js_safe($char, true)."'); return false;\">$char</button>"; 1052 } 1053 } 1054 return $str; 1055 } 1056 function add_keypad_chars(&$chars, $text) { 1057 if (preg_match_all('|&[^;]+;|i', $text, $more_chars)) { 1058 $chars = array_merge($chars, $more_chars[0]); 1059 } 1060 } 1061 function v6_expand_Correct() { 1062 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-correct'); 1063 } 1064 function v6_expand_Incorrect() { 1065 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-incorrect'); 1066 } 1067 function v6_expand_GiveHint() { 1068 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter'); 1069 } 1070 function v6_expand_CaseSensitive() { 1071 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',case-sensitive'); 1072 } 1073 1074 // JCross quiztype 1075 1076 function v6_expand_CluesAcrossLabel() { 1077 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-across'); 1078 } 1079 function v6_expand_CluesDownLabel() { 1080 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-down'); 1081 } 1082 function v6_expand_EnterCaption() { 1083 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',enter-caption'); 1084 } 1085 function v6_expand_ShowHideClueList() { 1086 $value = $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clue-list'); 1087 return empty($value) ? ' style="display: none;"' : ''; 1088 } 1089 1090 // JCross specials 1091 1092 function v6_expand_CluesDown() { 1093 return $this->v6_expand_jcross_clues('D'); 1094 } 1095 function v6_expand_CluesAcross() { 1096 return $this->v6_expand_jcross_clues('A'); 1097 } 1098 function v6_expand_jcross_clues($direction) { 1099 // $direction: A(cross) or D(own) 1100 $row = NULL; 1101 $r_max = 0; 1102 $c_max = 0; 1103 $this->v6_get_jcross_grid($row, $r_max, $c_max); 1104 1105 $i = 0; // clue index; 1106 $str = ''; 1107 for($r=0; $r<=$r_max; $r++) { 1108 for($c=0; $c<=$c_max; $c++) { 1109 $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max); 1110 $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max); 1111 if ($aword || $dword) { 1112 $i++; // increment clue index 1113 1114 // get the definition for this word 1115 $def = ''; 1116 $word = ($direction=='A') ? $aword : $dword; 1117 $clues = $this->parent->xml_values('data,crossword,clues,item'); 1118 foreach ($clues as $clue) { 1119 if ($clue['word'][0]['#']==$word) { 1120 $def = $clue['def'][0]['#']; 1121 $def = strtr($def, array('<'=>'<', '>'=>'>', "\n"=>'<br />')); 1122 break; 1123 } 1124 } 1125 1126 if (!empty($def)) { 1127 $str .= '<tr><td class="ClueNum">'.$i.'. </td><td id="Clue_'.$direction.'_'.$i.'" class="Clue">'.$def.'</td></tr>'; 1128 } 1129 } 1130 } 1131 } 1132 return $str; 1133 } 1134 1135 // jcross6.js_ 1136 1137 function v6_expand_LetterArray() { 1138 $row = NULL; 1139 $r_max = 0; 1140 $c_max = 0; 1141 $this->v6_get_jcross_grid($row, $r_max, $c_max); 1142 1143 $str = ''; 1144 for($r=0; $r<=$r_max; $r++) { 1145 $str .= "L[$r] = new Array("; 1146 for($c=0; $c<=$c_max; $c++) { 1147 $str .= ($c>0 ? ',' : '')."'".$this->js_safe($row[$r]['cell'][$c]['#'], true)."'"; 1148 } 1149 $str .= ");\n"; 1150 } 1151 return $str; 1152 } 1153 function v6_expand_GuessArray() { 1154 $row = NULL; 1155 $r_max = 0; 1156 $c_max = 0; 1157 $this->v6_get_jcross_grid($row, $r_max, $c_max); 1158 1159 $str = ''; 1160 for($r=0; $r<=$r_max; $r++) { 1161 $str .= "G[$r] = new Array('".str_repeat("','", $c_max)."');\n"; 1162 } 1163 return $str; 1164 } 1165 function v6_expand_ClueNumArray() { 1166 $row = NULL; 1167 $r_max = 0; 1168 $c_max = 0; 1169 $this->v6_get_jcross_grid($row, $r_max, $c_max); 1170 1171 $i = 0; // clue index 1172 $str = ''; 1173 for($r=0; $r<=$r_max; $r++) { 1174 $str .= "CL[$r] = new Array("; 1175 for($c=0; $c<=$c_max; $c++) { 1176 if ($c>0) { 1177 $str .= ','; 1178 } 1179 $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max); 1180 $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max); 1181 if (empty($aword) && empty($dword)) { 1182 $str .= 0; 1183 } else { 1184 $i++; // increment the clue index 1185 $str .= $i; 1186 } 1187 } 1188 $str .= ");\n"; 1189 } 1190 return $str; 1191 } 1192 function v6_expand_GridBody() { 1193 $row = NULL; 1194 $r_max = 0; 1195 $c_max = 0; 1196 $this->v6_get_jcross_grid($row, $r_max, $c_max); 1197 1198 $i = 0; // clue index; 1199 $str = ''; 1200 for($r=0; $r<=$r_max; $r++) { 1201 $str .= '<tr id="Row_'.$r.'">'; 1202 for($c=0; $c<=$c_max; $c++) { 1203 if (empty($row[$r]['cell'][$c]['#'])) { 1204 $str .= '<td class="BlankCell"> </td>'; 1205 } else { 1206 $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max); 1207 $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max); 1208 if (empty($aword) && empty($dword)) { 1209 $str .= '<td class="LetterOnlyCell"><span id="L_'.$r.'_'.$c.'"> </span></td>'; 1210 } else { 1211 $i++; // increment clue index 1212 $str .= '<td class="NumLetterCell"><a href="javascript:void(0);" class="GridNum" onclick="ShowClue('.$i.','.$r.','.$c.')">'.$i.'</a><span class="NumLetterCellText" id="L_'.$r.'_'.$c.'" onclick="ShowClue('.$i.','.$r.','.$c.')"> </span></td>'; 1213 } 1214 } 1215 } 1216 $str .= '</tr>'; 1217 } 1218 return $str; 1219 } 1220 function v6_get_jcross_grid(&$row, &$r_max, &$c_max) { 1221 $row = $this->parent->xml_values('data,crossword,grid,row'); 1222 $r_max = 0; 1223 $c_max = 0; 1224 if (isset($row) && is_array($row)) { 1225 for($r=0; $r<count($row); $r++) { 1226 if (isset($row[$r]['cell']) && is_array($row[$r]['cell'])) { 1227 for($c=0; $c<count($row[$r]['cell']); $c++) { 1228 if (!empty($row[$r]['cell'][$c]['#'])) { 1229 $r_max = max($r, $r_max); 1230 $c_max = max($c, $c_max); 1231 } 1232 } // end for $c 1233 } 1234 } // end for $r 1235 } 1236 } 1237 function get_jcross_dword(&$row, $r, $r_max, $c, $c_max) { 1238 $str = ''; 1239 if (($r==0 || empty($row[$r-1]['cell'][$c]['#'])) && $r<$r_max && !empty($row[$r+1]['cell'][$c]['#'])) { 1240 $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, true); 1241 } 1242 return $str; 1243 } 1244 function get_jcross_aword(&$row, $r, $r_max, $c, $c_max) { 1245 $str = ''; 1246 if (($c==0 || empty($row[$r]['cell'][$c-1]['#'])) && $c<$c_max && !empty($row[$r]['cell'][$c+1]['#'])) { 1247 $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, false); 1248 } 1249 return $str; 1250 } 1251 function get_jcross_word(&$row, $r, $r_max, $c, $c_max, $go_down=false) { 1252 $str = ''; 1253 while ($r<=$r_max && $c<=$c_max && !empty($row[$r]['cell'][$c]['#'])) { 1254 $str .= $row[$r]['cell'][$c]['#']; 1255 if ($go_down) { 1256 $r++; 1257 } else { 1258 $c++; 1259 } 1260 } 1261 return $str; 1262 } 1263 1264 // specials (JQuiz) 1265 1266 function v6_expand_QuestionOutput() { 1267 $str = ''; 1268 $str .= '<ol class="QuizQuestions" id="Questions">'."\n"; 1269 1270 $q = 0; 1271 $tags = 'data,questions,question-record'; 1272 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) { 1273 1274 // get question 1275 $question_text = $this->parent->xml_value($tags, $question."['question'][0]['#']"); 1276 $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']"); 1277 1278 $first_answer_text = $this->parent->xml_value($tags, $question."['answers'][0]['#']['answer'][0]['#']['text'][0]['#']"); 1279 1280 // check we have a question (or at least one answer) 1281 if (($question_text || $first_answer_text) && $question_type) { 1282 1283 $str .= '<li class="QuizQuestion" id="Q_'.$q.'" style="display: none;">'; 1284 $str .= '<p class="QuestionText">'.$question_text.'</p>'; 1285 1286 if ( 1287 $question_type==HOTPOT_JQUIZ_SHORTANSWER || 1288 $question_type==HOTPOT_JQUIZ_HYBRID 1289 ) { 1290 $size = 9; // default size 1291 $a = 0; 1292 $answers = $question."['answers'][0]['#']"; 1293 while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) { 1294 $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']"); 1295 $text = preg_replace('/&[#a-zA-Z0-9]+;/', 'x', $text); 1296 $size = max($size, strlen($text)); 1297 $a++; 1298 } 1299 1300 $str .= '<div class="ShortAnswer" id="Q_'.$q.'_SA"><form method="post" action="" onsubmit="return false;"><div>'; 1301 if ($size<=25) { // text box 1302 $str .= '<input type="text" id="Q_'.$q.'_Guess" onfocus="TrackFocus('."'".'Q_'.$q.'_Guess'."'".')" onblur="LeaveGap()" class="ShortAnswerBox" size="'.$size.'"></input>'; 1303 } else { // textarea (29 cols wide) 1304 $str .= '<textarea id="Q_'.$q.'_Guess" onfocus="TrackFocus('."'".'Q_'.$q.'_Guess'."'".')" onblur="LeaveGap()" class="ShortAnswerBox" cols="29" rows="'.ceil($size/25).'"></textarea>'; 1305 } 1306 $str .= '<br /><br />'; 1307 1308 $caption = $this->v6_expand_CheckCaption(); 1309 $str .= $this->v6_expand_jquiz_button($caption, "CheckShortAnswer($q)"); 1310 1311 if ($this->v6_expand_Hint()) { 1312 $caption = $this->v6_expand_HintCaption(); 1313 $str .= $this->v6_expand_jquiz_button($caption, "ShowHint($q)"); 1314 } 1315 1316 if ($this->v6_expand_ShowAnswer()) { 1317 $caption = $this->v6_expand_ShowAnswerCaption(); 1318 $str .= $this->v6_expand_jquiz_button($caption, "ShowAnswers($q)"); 1319 } 1320 1321 $str .= '</div></form></div>'; 1322 } 1323 1324 if ( 1325 $question_type==HOTPOT_JQUIZ_MULTICHOICE || 1326 $question_type==HOTPOT_JQUIZ_HYBRID || 1327 $question_type==HOTPOT_JQUIZ_MULTISELECT 1328 ) { 1329 1330 switch ($question_type) { 1331 case HOTPOT_JQUIZ_MULTICHOICE: 1332 $str .= '<ol class="MCAnswers">'."\n"; 1333 break; 1334 case HOTPOT_JQUIZ_HYBRID: 1335 $str .= '<ol class="MCAnswers" id="Q_'.$q.'_Hybrid_MC" style="display: none;">'."\n"; 1336 break; 1337 case HOTPOT_JQUIZ_MULTISELECT: 1338 $str .= '<ol class="MSelAnswers">'."\n"; 1339 break; 1340 } 1341 1342 $a = 0; 1343 $aa = 0; 1344 $answers = $question."['answers'][0]['#']"; 1345 while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) { 1346 $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']"); 1347 if ($text) { 1348 switch ($question_type) { 1349 case HOTPOT_JQUIZ_MULTICHOICE: 1350 case HOTPOT_JQUIZ_HYBRID: 1351 $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']"); 1352 if ($include) { 1353 $str .= '<li id="Q_'.$q.'_'.$aa.'"><button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" id="Q_'.$q.'_'.$aa.'_Btn" onclick="CheckMCAnswer('.$q.','.$aa.',this)"> ? </button> '.$text.'</li>'."\n"; 1354 } 1355 break; 1356 case HOTPOT_JQUIZ_MULTISELECT: 1357 $str .= '<li id="Q_'.$q.'_'.$aa.'"><form method="post" action="" onsubmit="return false;"><div><input type="checkbox" id="Q_'.$q.'_'.$aa.'_Chk" class="MSelCheckbox" />'.$text.'</div></form></li>'."\n"; 1358 break; 1359 } 1360 $aa++; 1361 } 1362 $a++; 1363 } 1364 1365 $str .= '</ol>'; 1366 1367 if ($question_type==HOTPOT_JQUIZ_MULTISELECT) { 1368 $caption = $this->v6_expand_CheckCaption(); 1369 $str .= $this->v6_expand_jquiz_button($caption, "CheckMultiSelAnswer($q)"); 1370 } 1371 } 1372 1373 $str .= "</li>\n"; 1374 } 1375 $q++; 1376 1377 } // end while $question 1378 1379 $str .= "</ol>\n"; 1380 return $str; 1381 } 1382 1383 function v6_expand_jquiz_button($caption, $onclick) { 1384 return '<button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="'.$onclick.'">'.$caption.'</button>'; 1385 } 1386 1387 // jquiz.js_ 1388 1389 function v6_expand_MultiChoice() { 1390 return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTICHOICE); 1391 } 1392 function v6_expand_ShortAnswer() { 1393 return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_SHORTANSWER); 1394 } 1395 function v6_expand_MultiSelect() { 1396 return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTISELECT); 1397 } 1398 function v6_jquiz_question_type($type) { 1399 // does this quiz have any questions of the given $type? 1400 $flag = false; 1401 1402 $q = 0; 1403 $tags = 'data,questions,question-record'; 1404 while (($question = "[$q]['#']") && $this->parent->xml_value($tags, $question)) { 1405 $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']"); 1406 if ($question_type==$type || ($question_type==HOTPOT_JQUIZ_HYBRID && ($type==HOTPOT_JQUIZ_MULTICHOICE || $type==HOTPOT_JQUIZ_SHORTANSWER))) { 1407 $flag = true; 1408 break; 1409 } 1410 $q++; 1411 } 1412 return $flag; 1413 } 1414 function v6_expand_CorrectFirstTime() { 1415 return $this->js_value('hotpot-config-file,global,correct-first-time'); 1416 } 1417 function v6_expand_ContinuousScoring() { 1418 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',continuous-scoring'); 1419 } 1420 function v6_expand_ShowCorrectFirstTime() { 1421 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',show-correct-first-time'); 1422 } 1423 function v6_expand_ShuffleAs() { 1424 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-answers'); 1425 } 1426 1427 function v6_expand_DefaultRight() { 1428 return $this->v6_expand_GuessCorrect(); 1429 } 1430 function v6_expand_DefaultWrong() { 1431 return $this->v6_expand_GuessIncorrect(); 1432 } 1433 function v6_expand_ShowAllQuestionsCaptionJS() { 1434 return $this->v6_expand_ShowAllQuestionsCaption(); 1435 } 1436 function v6_expand_ShowOneByOneCaptionJS() { 1437 return $this->v6_expand_ShowOneByOneCaption(); 1438 } 1439 1440 // hp6checkshortanswers.js_ (JQuiz) 1441 1442 function v6_expand_CorrectList() { 1443 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',correct-answers'); 1444 } 1445 function v6_expand_HybridTries() { 1446 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',short-answer-tries-on-hybrid-q'); 1447 } 1448 function v6_expand_PleaseEnter() { 1449 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',enter-a-guess'); 1450 } 1451 function v6_expand_PartlyIncorrect() { 1452 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',partly-incorrect'); 1453 } 1454 function v6_expand_ShowAnswerCaption() { 1455 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-answer-caption'); 1456 } 1457 function v6_expand_ShowAlsoCorrect() { 1458 return $this->bool_value('hotpot-config-file,global,show-also-correct'); 1459 } 1460 1461 } // end class 1462 function hotpot_sort_keypad_chars($a, $b) { 1463 $a = hotpot_keypad_sort_value($a); 1464 $b = hotpot_keypad_sort_value($b); 1465 return ($a<$b) ? -1 : ($a==$b ? 0 : 1); 1466 } 1467 function hotpot_keypad_sort_value($char) { 1468 1469 // hexadecimal 1470 if (preg_match('|&#x([0-9A-F]+);|ie', $char, $matches)) { 1471 $ord = hexdec($matches[1]); 1472 1473 // decimal 1474 } else if (preg_match('|&#(\d+);|i', $char, $matches)) { 1475 $ord = intval($matches[1]); 1476 1477 // other html entity 1478 } else if (preg_match('|&[^;]+;|', $char, $matches)) { 1479 $char = html_entity_decode($matches[0]); 1480 $ord = empty($char) ? 0 : ord($char); 1481 1482 // not an html entity 1483 } else { 1484 $char = trim($char); 1485 $ord = empty($char) ? 0 : ord($char); 1486 } 1487 1488 // lowercase letters (plain or accented) 1489 if (($ord>=97 && $ord<=122) || ($ord>=224 && $ord<=255)) { 1490 $sort_value = ($ord-31).'.'.sprintf('%04d', $ord); 1491 1492 // all other characters 1493 } else { 1494 $sort_value = $ord; 1495 } 1496 1497 return $sort_value; 1498 } 1499 1500 ?>
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 |