Automatic installer.php lang files by installer_builder (20070726)
[moodle-linuxchix.git] / mod / hotpot / template / v6.php
blobc0f1f5cbc8d3e86dee0182db48328e5f7a22b3f4
1 <?PHP
3 class hotpot_xml_quiz_template extends hotpot_xml_template_default {
5 // constructor function for this class
6 function hotpot_xml_quiz_template(&$parent) {
8 $this->parent = &$parent;
10 $get_js = optional_param('js', false);
11 $get_css = optional_param('css', false);
13 if (!empty($get_css)) {
14 // set $this->css
15 $this->v6_expand_StyleSheet();
17 } else if (!empty($get_js)) {
18 // set $this->js
19 $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.js_', 'js');
21 } else {
22 // set $this->html
23 $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.ht_', 'html');
26 // expand special strings, if any
27 $pattern = '';
28 switch ($this->parent->quiztype) {
29 case 'jcloze':
30 $pattern = '/\[(PreloadImageList)\]/';
31 break;
32 case 'jcross':
33 $pattern = '/\[(PreloadImageList|ShowHideClueList)\]/';
34 break;
35 case 'jmatch':
36 $pattern = '/\[(PreloadImageList|QsToShow|FixedArray|DragArray)\]/';
37 break;
38 case 'jmix':
39 $pattern = '/\[(PreloadImageList|SegmentArray|AnswerArray)\]/';
40 break;
41 case 'jquiz':
42 $pattern = '/\[(PreloadImageList|QsToShow)\]/';
43 break;
45 if (!empty($pattern)) {
46 $this->expand_strings('html', $pattern);
50 // captions and messages
52 function v6_expand_AlsoCorrect() {
53 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');
55 function v6_expand_CapitalizeFirst() {
56 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',capitalize-first-letter');
58 function v6_expand_CheckCaption() {
59 return $this->parent->xml_value('hotpot-config-file,global,check-caption');
61 function v6_expand_CorrectIndicator() {
62 return $this->js_value('hotpot-config-file,global,correct-indicator');
64 function v6_expand_Back() {
65 return $this->int_value('hotpot-config-file,global,include-back');
67 function v6_expand_BackCaption() {
68 return $this->parent->xml_value('hotpot-config-file,global,back-caption');
70 function v6_expand_ClickToAdd() {
71 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',click-to-add');
73 function v6_expand_ClueCaption() {
74 return $this->parent->xml_value('hotpot-config-file,global,clue-caption');
76 function v6_expand_Clues() {
77 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clues');
79 function v6_expand_Contents() {
80 return $this->int_value('hotpot-config-file,global,include-contents');
82 function v6_expand_ContentsCaption() {
83 return $this->parent->xml_value('hotpot-config-file,global,contents-caption');
85 function v6_expand_GuessCorrect() {
86 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-correct');
88 function v6_expand_GuessIncorrect() {
89 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-incorrect');
91 function v6_expand_Hint() {
92 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-hint');
94 function v6_expand_HintCaption() {
95 return $this->parent->xml_value('hotpot-config-file,global,hint-caption');
97 function v6_expand_IncorrectIndicator() {
98 return $this->js_value('hotpot-config-file,global,incorrect-indicator');
100 function v6_expand_LastQCaption() {
101 return $this->parent->xml_value('hotpot-config-file,global,last-q-caption');
103 function v6_expand_NextCorrect() {
104 $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-part');
105 if (empty($value)) { // jquiz
106 $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');
108 return $value;
110 function v6_expand_NextEx() {
111 return $this->int_value('hotpot-config-file,global,include-next-ex');
113 function v6_expand_NextExCaption() {
114 return $this->parent->xml_value('hotpot-config-file,global,next-ex-caption');
116 function v6_expand_NextQCaption() {
117 return $this->parent->xml_value('hotpot-config-file,global,next-q-caption');
119 function v6_expand_OKCaption() {
120 return $this->parent->xml_value('hotpot-config-file,global,ok-caption');
122 function v6_expand_Restart() {
123 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-restart');
125 function v6_expand_RestartCaption() {
126 return $this->parent->xml_value('hotpot-config-file,global,restart-caption');
128 function v6_expand_ShowAllQuestionsCaption() {
129 return $this->js_value('hotpot-config-file,global,show-all-questions-caption');
131 function v6_expand_ShowOneByOneCaption() {
132 return $this->js_value('hotpot-config-file,global,show-one-by-one-caption');
134 function v6_expand_TheseAnswersToo() {
135 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');
137 function v6_expand_ThisMuch() {
138 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',this-much-correct');
140 function v6_expand_Undo() {
141 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-undo');
143 function v6_expand_UndoCaption() {
144 return $this->parent->xml_value('hotpot-config-file,global,undo-caption');
146 function v6_expand_YourScoreIs() {
147 return $this->js_value('hotpot-config-file,global,your-score-is');
150 // reading
152 function v6_expand_Reading() {
153 return $this->int_value('data,reading,include-reading');
155 function v6_expand_ReadingText() {
156 $title = $this->v6_expand_ReadingTitle();
157 $value = $this->parent->xml_value('data,reading,reading-text');
158 $value = empty($value) ? '' : ('<div class="ReadingText">'.$value.'</div>');
159 return $title.$value;
161 function v6_expand_ReadingTitle() {
162 $value = $this->parent->xml_value('data,reading,reading-title');
163 return empty($value) ? '' : ('<h3 class="ExerciseSubtitle">'.$value.'</h3>');
166 // timer
168 function v6_expand_Timer() {
169 return $this->int_value('data,timer,include-timer');
171 function v6_expand_JSTimer() {
172 return $this->read_template('hp6timer.js_');
174 function v6_expand_Seconds() {
175 return $this->parent->xml_value('data,timer,seconds');
178 // send results
180 function v6_expand_SendResults() {
181 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',send-email');
183 function v6_expand_JSSendResults() {
184 return $this->read_template('hp6sendresults.js_');
186 function v6_expand_FormMailURL() {
187 return $this->parent->xml_value('hotpot-config-file,global,formmail-url');
189 function v6_expand_EMail() {
190 return $this->parent->xml_value('hotpot-config-file,global,email');
192 function v6_expand_NamePlease() {
193 return $this->js_value('hotpot-config-file,global,name-please');
196 // preload images
198 function v6_expand_PreloadImages() {
199 $value = $this->v6_expand_PreloadImageList();
200 return empty($value) ? false : true;
202 function v6_expand_PreloadImageList() {
204 // check it has not been set already
205 if (!isset($this->PreloadImageList)) {
207 // the list of image urls
208 $list = array();
210 // extract <img> tags
211 $img_tag = htmlspecialchars('|&#x003C;img.*?src="(.*?)".*?&#x003E;|is');
212 if (preg_match_all($img_tag, $this->parent->source, $matches)) {
213 $list = $matches[1];
215 // remove duplicates
216 $list = array_unique($list);
219 // convert to comma delimited string
220 $this->PreloadImageList = empty($list) ? '' : "'".implode(',', $list)."'";
222 return $this->PreloadImageList;
225 // html files (all quiz types)
227 function v6_expand_PlainTitle() {
228 return $this->parent->xml_value('data,title');
230 function v6_expand_ExerciseSubtitle() {
231 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',exercise-subtitle');
233 function v6_expand_Instructions() {
234 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',instructions');
236 function v6_expand_DublinCoreMetadata() {
237 $dc = '<link rel="schema.DC" href="'.$this->parent->xml_value('', "['rdf:RDF'][0]['@']['xmlns:dc']").'" />'."\n";
238 if (is_string($this->parent->xml_value('rdf:RDF,rdf:Description'))) {
239 // do nothing (there is no more dc info)
240 } else {
241 $dc .= '<meta name="DC:Creator" content="'.$this->parent->xml_value('rdf:RDF,rdf:Description,dc:creator').'" />'."\n";
242 $dc .= '<meta name="DC:Title" content="'.strip_tags($this->parent->xml_value('rdf:RDF,rdf:Description,dc:title')).'" />'."\n";
244 return $dc;
246 function v6_expand_FullVersionInfo() {
247 global $CFG;
248 require_once($CFG->hotpotroot.DIRECTORY_SEPARATOR.'version.php'); // set $module
249 return $this->parent->xml_value('version').'.x (Moodle '.$CFG->release.', hotpot-module '.$this->parent->obj_value($module, 'release').')';
251 function v6_expand_HeaderCode() {
252 return $this->parent->xml_value('hotpot-config-file,global,header-code');
254 function v6_expand_StyleSheet() {
255 $this->read_template('hp6.cs_', 'css');
256 $this->css = hotpot_convert_stylesheets_urls($this->parent->get_baseurl(), $this->parent->reference, $this->css);
257 return $this->css;
260 // stylesheet (hp6.cs_)
262 function v6_expand_PageBGColor() {
263 return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');
265 function v6_expand_GraphicURL() {
266 return $this->parent->xml_value('hotpot-config-file,global,graphic-url');
268 function v6_expand_ExBGColor() {
269 return $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');
272 function v6_expand_FontFace() {
273 return $this->parent->xml_value('hotpot-config-file,global,font-face');
275 function v6_expand_FontSize() {
276 $value = $this->parent->xml_value('hotpot-config-file,global,font-size');
277 return (empty($value) ? 'small' : $value);
279 function v6_expand_TextColor() {
280 return $this->parent->xml_value('hotpot-config-file,global,text-color');
282 function v6_expand_TitleColor() {
283 return $this->parent->xml_value('hotpot-config-file,global,title-color');
285 function v6_expand_LinkColor() {
286 return $this->parent->xml_value('hotpot-config-file,global,link-color');
288 function v6_expand_VLinkColor() {
289 return $this->parent->xml_value('hotpot-config-file,global,vlink-color');
292 function v6_expand_NavTextColor() {
293 return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');
295 function v6_expand_NavBarColor() {
296 return $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');
298 function v6_expand_NavLightColor() {
299 $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');
300 return $this->get_halfway_color($color, '#ffffff');
302 function v6_expand_NavShadeColor() {
303 $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');
304 return $this->get_halfway_color($color, '#000000');
307 function v6_expand_FuncLightColor() { // top-left of buttons
308 $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');
309 return $this->get_halfway_color($color, '#ffffff');
311 function v6_expand_FuncShadeColor() { // bottom right of buttons
312 $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');
313 return $this->get_halfway_color($color, '#000000');
316 // navigation buttons
318 function v6_expand_NavButtons() {
319 $back = $this->v6_expand_Back();
320 $next_ex = $this->v6_expand_NextEx();
321 $contents = $this->v6_expand_Contents();
322 return (empty($back) && empty($next_ex) && empty($contents) ? false : true);
324 function v6_expand_NavBarJS() {
325 return $this->v6_expand_NavButtons();
328 // switch off scorm
329 function v6_expand_Scorm12() {
330 return false;
333 // js files (all quiz types)
335 function v6_expand_JSBrowserCheck() {
336 return $this->read_template('hp6browsercheck.js_');
338 function v6_expand_JSButtons() {
339 return $this->read_template('hp6buttons.js_');
341 function v6_expand_JSCard() {
342 return $this->read_template('hp6card.js_');
344 function v6_expand_JSCheckShortAnswer() {
345 return $this->read_template('hp6checkshortanswer.js_');
347 function v6_expand_JSHotPotNet() {
348 return $this->read_template('hp6hotpotnet.js_');
350 function v6_expand_JSShowMessage() {
351 return $this->read_template('hp6showmessage.js_');
353 function v6_expand_JSUtilities() {
354 return $this->read_template('hp6utilities.js_');
357 // js files
359 function v6_expand_JSJCloze6() {
360 return $this->read_template('jcloze6.js_');
362 function v6_expand_JSJCross6() {
363 return $this->read_template('jcross6.js_');
365 function v6_expand_JSJMatch6() {
366 return $this->read_template('jmatch6.js_');
368 function v6_expand_JSJMix6() {
369 return $this->read_template('jmix6.js_');
371 function v6_expand_JSJQuiz6() {
372 return $this->read_template('jquiz6.js_');
375 // drag and drop
377 function v6_expand_JSDJMatch6() {
378 return $this->read_template('djmatch6.js_');
380 function v6_expand_JSDJMix6() {
381 return $this->read_template('djmix6.js_');
384 // what are these for?
386 function v6_expand_JSFJMatch6() {
387 return $this->read_template('fjmatch6.js_');
389 function v6_expand_JSFJMix6() {
390 return $this->read_template('fjmix6.js_');
393 // jmatch6.js_
395 function v6_expand_ShuffleQs() {
396 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-questions');
398 function v6_expand_QsToShow() {
399 $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-limited-questions');
400 if ($i) {
401 $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',questions-to-show');
403 if (empty($i)) {
404 $i = 0;
405 switch ($this->parent->quiztype) {
406 case 'jmatch':
407 $values = $this->parent->xml_values('data,matching-exercise,pair');
408 $i = count($values);
409 break;
410 case 'jquiz':
411 $tags = 'data,questions,question-record';
412 while (($question="[$i]['#']") && $this->parent->xml_value($tags, $question)) {
413 $i++;
415 break;
416 } // end switch
418 return $i;
420 function v6_expand_MatchDivItems() {
421 $l_items = array();
422 $r_items = array();
423 $this->get_jmatch_items($l_items, $r_items);
425 $l_keys = $this->shuffle_jmatch_items($l_items);
426 $r_keys = $this->shuffle_jmatch_items($r_items);
428 $options = '<option value="x">'.$this->parent->xml_value('data,matching-exercise,default-right-item').'</option>';
429 foreach ($r_keys as $key) {
430 if (empty($r_items[$key]['fixed'][0]['#'])) {
431 $options .= '<option value="'.$key.'">'.$r_items[$key]['text'][0]['#'].'</option>'."\n";
435 $str = '';
436 foreach ($l_keys as $key) {
437 $str .= '<tr><td class="LeftItem">'.$l_items[$key]['text'][0]['#'].'</td>';
438 $str .= '<td class="RightItem">';
439 if (empty($r_items[$key]['fixed'][0]['#'])) {
440 $str .= '<select id="s'.$key.'_'.$key.'">'.$options.'</select>';
441 } else {
442 $str .= $r_items[$key]['text'][0]['#'];
444 $str .= '</td><td></td></tr>';
446 return $str;
449 // jmix6.js_
451 function v6_expand_Punctuation() {
452 $tags = 'data,jumbled-order-exercise';
453 $chars = array_merge(
454 $this->jmix_Punctuation("$tags,main-order,segment"),
455 $this->jmix_Punctuation("$tags,alternate")
457 $chars = array_unique($chars);
458 $chars = implode('', $chars);
459 $chars = $this->js_safe($chars, true);
460 return $chars;
462 function jmix_Punctuation($tags) {
463 $chars = array();
465 // all punctutation except '&#;' (because they are used in html entities)
466 $ENTITIES = $this->jmix_encode_punctuation('!"$%'."'".'()*+,-./:<=>?@[\]^_`{|}~');
467 $pattern = "/&#x([0-9A-F]+);/i";
468 $i = 0;
470 // get next segment (or alternate answer)
471 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
473 // convert low-ascii punctuation to entities
474 $value = strtr($value, $ENTITIES);
476 // extract all hex HTML entities
477 if (preg_match_all($pattern, $value, $matches)) {
479 // loop through hex entities
480 $m_max = count($matches[0]);
481 for ($m=0; $m<$m_max; $m++) {
483 // convert to hex number
484 eval('$hex=0x'.$matches[1][$m].';');
486 // is this a punctuation character?
487 if (
488 ($hex>=0x0020 && $hex<=0x00BF) || // ascii punctuation
489 ($hex>=0x2000 && $hex<=0x206F) || // general punctuation
490 ($hex>=0x3000 && $hex<=0x303F) || // CJK punctuation
491 ($hex>=0xFE30 && $hex<=0xFE4F) || // CJK compatability
492 ($hex>=0xFE50 && $hex<=0xFE6F) || // small form variants
493 ($hex>=0xFF00 && $hex<=0xFF40) || // halfwidth and fullwidth forms (1)
494 ($hex>=0xFF5B && $hex<=0xFF65) || // halfwidth and fullwidth forms (2)
495 ($hex>=0xFFE0 && $hex<=0xFFEE) // halfwidth and fullwidth forms (3)
497 // add this character
498 $chars[] = $matches[0][$m];
502 $i++;
505 return $chars;
507 function v6_expand_OpenPunctuation() {
508 $tags = 'data,jumbled-order-exercise';
509 $chars = array_merge(
510 $this->jmix_OpenPunctuation("$tags,main-order,segment"),
511 $this->jmix_OpenPunctuation("$tags,alternate")
513 $chars = array_unique($chars);
514 $chars = implode('', $chars);
515 $chars = $this->js_safe($chars, true);
516 return $chars;
518 function jmix_OpenPunctuation($tags) {
519 $chars = array();
521 // unicode punctuation designations (pi="initial quote", ps="open")
522 // http://www.sql-und-xml.de/unicode-database/pi.html
523 // http://www.sql-und-xml.de/unicode-database/ps.html
524 $pi = '0022|0027|00AB|2018|201B|201C|201F|2039';
525 $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';
526 $pattern = "/(&#x($pi|$ps);)/i";
528 $ENTITIES = $this->jmix_encode_punctuation('"'."'".'(<[{');
530 $i = 0;
531 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
532 $value = strtr($value, $ENTITIES);
533 if (preg_match_all($pattern, $value, $matches)) {
534 $chars = array_merge($chars, $matches[0]);
536 $i++;
539 return $chars;
541 function jmix_encode_punctuation($str) {
542 $ENTITIES = array();
543 $i_max = strlen($str);
544 for ($i=0; $i<$i_max; $i++) {
545 $ENTITIES[$str{$i}] = '&#x'.sprintf('%04X', ord($str{$i})).';';
547 return $ENTITIES;
549 function v6_expand_ExerciseTitle() {
550 return $this->parent->xml_value('data,title');
553 // Jmix specials
555 function v6_expand_SegmentArray() {
557 $segments = array();
558 $values = array();
559 $VALUES = array();
561 // XML tags to the start of a segment
562 $tags = 'data,jumbled-order-exercise,main-order,segment';
564 $i = 0;
565 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
566 $VALUE = strtoupper($value);
567 $key = array_search($VALUE, $VALUES);
568 if (is_numeric($key)) {
569 $segments[] = $key;
570 } else {
571 $segments[] = $i;
572 $values[$i] = $value;
573 $VALUES[$i] = $VALUE;
575 $i++;
578 $this->seed_random_number_generator();
579 $keys = array_keys($segments);
580 shuffle($keys);
582 $str = '';
583 for($i=0; $i<count($keys); $i++) {
584 $key = $segments[$keys[$i]];
585 $str .= "Segments[$i] = new Array();\n";
586 $str .= "Segments[$i][0] = '".$this->js_safe($values[$key], true)."';\n";
587 $str .= "Segments[$i][1] = ".($key+1).";\n";
588 $str .= "Segments[$i][2] = 0;\n";
590 return $str;
592 function v6_expand_AnswerArray() {
594 $segments = array();
595 $values = array();
596 $VALUES = array();
597 $escapedvalues = array();
599 // XML tags to the start of a segment
600 $tags = 'data,jumbled-order-exercise,main-order,segment';
602 $i = 0;
603 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
604 $VALUE = strtoupper($value);
605 $key = array_search($VALUE, $VALUES);
606 if (is_numeric($key)) {
607 $segments[] = $key+1;
608 } else {
609 $segments[] = $i+1;
610 $values[$i] = $value;
611 $VALUES[$i] = $VALUE;
612 $escapedvalues[] = preg_quote($value, '/');
614 $i++;
617 // start the answers array
618 $a = 0;
619 $str = 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";
621 // pattern to match the next part of an alternate answer
622 $pattern = '/^('.implode('|', $escapedvalues).')\\s*/i';
624 // XML tags to the start of an alternate answer
625 $tags = 'data,jumbled-order-exercise,alternate';
627 $i = 0;
628 while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
629 $segments = array();
630 while (strlen($value) && preg_match($pattern, $value, $matches)) {
631 $key = array_search($matches[1], $values);
632 if (is_numeric($key)) {
633 $segments[] = $key+1;
634 $value = substr($value, strlen($matches[0]));
635 } else {
636 // invalid alternate sequence
637 $segments = array();
638 break;
641 if (count($segments)) {
642 $str .= 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";
644 $i++;
646 return $str;
649 // ===============================================================
651 // JMix (jmix6.js_)
653 function v6_expand_RemainingWords() {
654 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',remaining-words');
656 function v6_expand_TimesUp() {
657 return $this->parent->xml_value('hotpot-config-file,global,times-up');
660 // nav bar
662 function v6_expand_NavBar($navbarid='') {
663 $this->navbarid = $navbarid;
665 $tag = 'navbar';
666 $this->read_template('hp6navbar.ht_', $tag);
668 unset($this->navbarid);
670 return $this->$tag;
672 function v6_expand_TopNavBar() {
673 return $this->v6_expand_NavBar('TopNavBar');
675 function v6_expand_BottomNavBar() {
676 return $this->v6_expand_NavBar('BottomNavBar');
679 // hp6navbar.ht_
681 function v6_expand_NavBarID() {
682 // $this->navbarid is set in "$this->v6_expand_NavBar"
683 return empty($this->navbarid) ? '' : $this->navbarid;
685 function v6_expand_ContentsURL() {
686 $url = $this->parent->xml_value('hotpot-config-file,global,contents-url');
687 if ($url) {
688 $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);
690 return $url;
692 function v6_expand_NextExURL() {
693 $url = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',next-ex-url');
694 if ($url) {
695 $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);
697 return $url;
700 // conditional blocks
702 function v6_expand_ShowAnswer() {
703 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-show-answer');
705 function v6_expand_Slide() {
706 return true; // whats's this (JMatch drag and drop)
709 // specials (JMatch)
711 function v6_expand_FixedArray() {
712 $l_items = array();
713 $r_items = array();
714 $this->get_jmatch_items($l_items, $r_items);
716 $str = '';
717 foreach ($l_items as $i=>$item) {
718 $str .= "F[$i] = new Array();\n";
719 $str .= "F[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";
720 $str .= "F[$i][1] = ".($i+1).";\n";
722 return $str;
724 function v6_expand_DragArray() {
725 $l_items = array();
726 $r_items = array();
727 $this->get_jmatch_items($l_items, $r_items);
729 $str = '';
730 foreach ($r_items as $i=>$item) {
731 $str .= "D[$i] = new Array();\n";
732 $str .= "D[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";
733 $str .= "D[$i][1] = ".($i+1).";\n";
734 $str .= "D[$i][2] = '".(empty($item['fixed'][0]['#']) ? 0 : 1)."';\n";
736 return $str;
739 function get_jmatch_items(&$l_items, &$r_items) {
740 $tags = 'data,matching-exercise,pair';
741 $i = 0;
742 while($item = $this->parent->xml_value($tags,"[$i]['#']['left-item'][0]['#']")) {
743 if (!empty($item['text'][0]['#'])) {
744 $l_items[] = $item;
746 $i++;
748 $i = 0;
749 while($item = $this->parent->xml_value($tags,"[$i]['#']['right-item'][0]['#']")) {
750 if (!empty($item['text'][0]['#'])) {
751 $r_items[] = $item;
753 $i++;
756 function shuffle_jmatch_items(&$items) {
757 // get moveable items
758 $moveable_keys = array();
759 for($i=0; $i<count($items); $i++) {
760 if(empty($items[$i]['fixed'][0]['#'])) {
761 $moveable_keys[] = $i;
764 // shuffle moveable items
765 $this->seed_random_number_generator();
766 shuffle($moveable_keys);
768 $keys = array();
769 for($i=0, $ii=0; $i<count($items); $i++) {
770 if(empty($items[$i]['fixed'][0]['#'])) {
771 // moveable items are inserted in a shuffled order
772 $keys[] = $moveable_keys[$ii++];
773 } else {
774 // fixed items stay where they are
775 $keys[] = $i;
778 return $keys;
780 function seed_random_number_generator() {
781 static $seeded_RNG = FALSE;
782 if (!$seeded_RNG) {
783 srand((double) microtime() * 1000000);
784 $seeded_RNG = TRUE;
788 // specials (JMix)
791 // specials (JCloze)
793 function v6_expand_ItemArray() {
794 $q = 0;
795 $str = '';
796 switch ($this->parent->quiztype) {
797 case 'jcloze':
798 $tags = 'data,gap-fill,question-record';
799 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
800 $a = 0;
801 $aa = 0;
802 while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
803 $text = $this->js_value($tags, $answer."['text'][0]['#']", true);
804 if (strlen($text)) {
805 if ($aa==0) { // first time only
806 $str .= "\n";
807 $str .= "I[$q] = new Array();\n";
808 $str .= "I[$q][1] = new Array();\n";
810 $str .= "I[$q][1][$aa] = new Array();\n";
811 $str .= "I[$q][1][$aa][0] = '$text';\n";
812 $aa++;
814 $a++;
816 // add clue, if any answers were found
817 if ($aa) {
818 $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);
819 $str .= "I[$q][2] = '$clue';\n";
821 $q++;
823 break;
824 case 'jquiz':
825 $str .= "I=new Array();\n";
826 $tags = 'data,questions,question-record';
827 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
829 $question_type = $this->int_value($tags, $question."['question-type'][0]['#']");
830 $weighting = $this->int_value($tags, $question."['weighting'][0]['#']");
831 $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);
833 $answers = $question."['answers'][0]['#']";
835 $a = 0;
836 $aa = 0;
837 while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
838 $text = $this->js_value($tags, $answer."['text'][0]['#']", true);
839 $feedback = $this->js_value($tags, $answer."['feedback'][0]['#']", true);
840 $correct = $this->int_value($tags, $answer."['correct'][0]['#']");
841 $percent = $this->int_value($tags, $answer."['percent-correct'][0]['#']");
842 $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");
843 if (strlen($text)) {
844 if ($aa==0) { // first time only
845 $str .= "\n";
846 $str .= "I[$q] = new Array();\n";
847 $str .= "I[$q][0] = $weighting;\n";
848 $str .= "I[$q][1] = '$clue';\n";
849 $str .= "I[$q][2] = '".($question_type-1)."';\n";
850 $str .= "I[$q][3] = new Array();\n";
852 $str .= "I[$q][3][$aa] = new Array('$text','$feedback',$correct,$percent,$include);\n";
853 $aa++;
855 $a++;
857 $q++;
859 break;
861 return $str;
864 function v6_expand_ClozeBody() {
865 $str = '';
867 // get drop down list of words, if required
868 $dropdownlist = '';
869 if ($this->v6_use_DropDownList()) {
870 $this->v6_set_WordList();
871 foreach ($this->wordlist as $word) {
872 $dropdownlist .= '<option value="'.$word.'">'.$word.'</option>';
876 // cache clues flag and caption
877 $includeclues = $this->v6_expand_Clues();
878 $cluecaption = $this->v6_expand_ClueCaption();
880 // detect if cloze starts with gap
881 $strpos = strpos($this->parent->source, '<gap-fill><question-record>');
882 if (is_numeric($strpos)) {
883 $startwithgap = true;
884 } else {
885 $startwithgap = false;
888 // initialize loop values
889 $q = 0;
890 $tags = 'data,gap-fill';
891 $question_record = "$tags,question-record";
893 // loop through text and gaps
894 do {
895 $text = $this->parent->xml_value($tags, "[0]['#'][$q]");
896 $gap = '';
897 if (($question="[$q]['#']") && $this->parent->xml_value($question_record, $question)) {
898 $gap .= '<span class="GapSpan" id="GapSpan'.$q.'">';
899 if ($this->v6_use_DropDownList()) {
900 $gap .= '<select id="Gap'.$q.'"><option value=""></option>'.$dropdownlist.'</select>';
901 } else {
902 // minimum gap size
903 $gapsize = 6;
905 // increase gap size to length of longest answer for this gap
906 $a = 0;
907 while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($question_record, $answer)) {
908 $answertext = $this->parent->xml_value($question_record, $answer."['text'][0]['#']");
909 $answertext = preg_replace('|&[#a-zA-Z0-9]+;|', 'x', $answertext);
910 $gapsize = max($gapsize, strlen($answertext));
911 $a++;
914 $gap .= '<input type="text" id="Gap'.$q.'" onfocus="TrackFocus('.$q.')" onblur="LeaveGap()" class="GapBox" size="'.$gapsize.'" /></input>';
916 if ($includeclues) {
917 $clue = $this->parent->xml_value($question_record, $question."['clue'][0]['#']");
918 if (strlen($clue)) {
919 $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>';
922 $gap .= '</span>';
924 if ($startwithgap) {
925 $str .= "$gap$text";
926 } else {
927 $str .= "$text$gap";
929 $q++;
930 } while (strlen($text) || strlen($gap));
932 return $str;
935 // JCloze quiztype
937 function v6_expand_WordList() {
938 $str = '';
939 if ($this->v6_include_WordList()) {
940 $this->v6_set_WordList();
941 $str = implode(' &#160;&#160; ', $this->wordlist);
943 return $str;
945 function v6_include_WordList() {
946 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-word-list');
948 function v6_use_DropDownList() {
949 return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',use-drop-down-list');
951 function v6_set_WordList() {
953 if (isset($this->wordlist)) {
954 // do nothing
955 } else {
956 $this->wordlist = array();
958 // is the wordlist required
959 if ($this->v6_include_WordList() || $this->v6_use_DropDownList()) {
961 $q = 0;
962 $tags = 'data,gap-fill,question-record';
963 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
964 $a = 0;
965 $aa = 0;
966 while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
967 $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']");
968 $correct = $this->int_value($tags, $answer."['correct'][0]['#']");
969 if ($text && $correct) { // $correct is always true
970 $this->wordlist[] = $text;
971 $aa++;
973 $a++;
975 $q++;
977 $this->wordlist = array_unique($this->wordlist);
978 sort($this->wordlist);
982 function v6_expand_Keypad() {
983 $str = '';
984 if ($this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-keypad')) {
986 // these characters must always be in the keypad
987 $chars = array();
988 $this->add_keypad_chars($chars, $this->parent->xml_value('hotpot-config-file,global,keypad-characters'));
990 // append other characters used in the answers
991 $tags = '';
992 switch ($this->parent->quiztype) {
993 case 'jcloze':
994 $tags = 'data,gap-fill,question-record';
995 break;
996 case 'jquiz':
997 $tags = 'data,questions,question-record';
998 break;
1000 if ($tags) {
1001 $q = 0;
1002 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
1004 if ($this->parent->quiztype=='jquiz') {
1005 $answers = $question."['answers'][0]['#']";
1006 } else {
1007 $answers = $question;
1010 $a = 0;
1011 while (($answer=$answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
1012 $this->add_keypad_chars($chars, $this->parent->xml_value($tags, $answer."['text'][0]['#']"));
1013 $a++;
1015 $q++;
1019 // remove duplicate characters and sort
1020 $chars = array_unique($chars);
1021 usort($chars, "hotpot_sort_keypad_chars");
1023 // create keypad buttons for each character
1024 foreach ($chars as $char) {
1025 $str .= "<button onclick=\"TypeChars('".$this->js_safe($char, true)."'); return false;\">$char</button>";
1028 return $str;
1030 function add_keypad_chars(&$chars, $text) {
1031 if (preg_match_all('|&[^;]+;|i', $text, $more_chars)) {
1032 $chars = array_merge($chars, $more_chars[0]);
1035 function v6_expand_Correct() {
1036 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-correct');
1038 function v6_expand_Incorrect() {
1039 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-incorrect');
1041 function v6_expand_GiveHint() {
1042 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');
1044 function v6_expand_CaseSensitive() {
1045 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',case-sensitive');
1048 // JCross quiztype
1050 function v6_expand_CluesAcrossLabel() {
1051 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-across');
1053 function v6_expand_CluesDownLabel() {
1054 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-down');
1056 function v6_expand_EnterCaption() {
1057 return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',enter-caption');
1059 function v6_expand_ShowHideClueList() {
1060 $value = $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clue-list');
1061 return empty($value) ? ' style="display: none;"' : '';
1064 // JCross specials
1066 function v6_expand_CluesDown() {
1067 return $this->v6_expand_jcross_clues('D');
1069 function v6_expand_CluesAcross() {
1070 return $this->v6_expand_jcross_clues('A');
1072 function v6_expand_jcross_clues($direction) {
1073 // $direction: A(cross) or D(own)
1074 $row = NULL;
1075 $r_max = 0;
1076 $c_max = 0;
1077 $this->v6_get_jcross_grid($row, $r_max, $c_max);
1079 $i = 0; // clue index;
1080 $str = '';
1081 for($r=0; $r<=$r_max; $r++) {
1082 for($c=0; $c<=$c_max; $c++) {
1083 $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);
1084 $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);
1085 if ($aword || $dword) {
1086 $i++; // increment clue index
1088 // get the definition for this word
1089 $def = '';
1090 $word = ($direction=='A') ? $aword : $dword;
1091 $clues = $this->parent->xml_values('data,crossword,clues,item');
1092 foreach ($clues as $clue) {
1093 if ($clue['word'][0]['#']==$word) {
1094 $def = $clue['def'][0]['#'];
1095 $def = strtr($def, array('&#x003C;'=>'<', '&#x003E;'=>'>', "\n"=>'<br />'));
1096 break;
1100 if (!empty($def)) {
1101 $str .= '<tr><td class="ClueNum">'.$i.'. </td><td id="Clue_'.$direction.'_'.$i.'" class="Clue">'.$def.'</td></tr>';
1106 return $str;
1109 // jcross6.js_
1111 function v6_expand_LetterArray() {
1112 $row = NULL;
1113 $r_max = 0;
1114 $c_max = 0;
1115 $this->v6_get_jcross_grid($row, $r_max, $c_max);
1117 $str = '';
1118 for($r=0; $r<=$r_max; $r++) {
1119 $str .= "L[$r] = new Array(";
1120 for($c=0; $c<=$c_max; $c++) {
1121 $str .= ($c>0 ? ',' : '')."'".$this->js_safe($row[$r]['cell'][$c]['#'], true)."'";
1123 $str .= ");\n";
1125 return $str;
1127 function v6_expand_GuessArray() {
1128 $row = NULL;
1129 $r_max = 0;
1130 $c_max = 0;
1131 $this->v6_get_jcross_grid($row, $r_max, $c_max);
1133 $str = '';
1134 for($r=0; $r<=$r_max; $r++) {
1135 $str .= "G[$r] = new Array('".str_repeat("','", $c_max)."');\n";
1137 return $str;
1139 function v6_expand_ClueNumArray() {
1140 $row = NULL;
1141 $r_max = 0;
1142 $c_max = 0;
1143 $this->v6_get_jcross_grid($row, $r_max, $c_max);
1145 $i = 0; // clue index
1146 $str = '';
1147 for($r=0; $r<=$r_max; $r++) {
1148 $str .= "CL[$r] = new Array(";
1149 for($c=0; $c<=$c_max; $c++) {
1150 if ($c>0) {
1151 $str .= ',';
1153 $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);
1154 $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);
1155 if (empty($aword) && empty($dword)) {
1156 $str .= 0;
1157 } else {
1158 $i++; // increment the clue index
1159 $str .= $i;
1162 $str .= ");\n";
1164 return $str;
1166 function v6_expand_GridBody() {
1167 $row = NULL;
1168 $r_max = 0;
1169 $c_max = 0;
1170 $this->v6_get_jcross_grid($row, $r_max, $c_max);
1172 $i = 0; // clue index;
1173 $str = '';
1174 for($r=0; $r<=$r_max; $r++) {
1175 $str .= '<tr id="Row_'.$r.'">';
1176 for($c=0; $c<=$c_max; $c++) {
1177 if (empty($row[$r]['cell'][$c]['#'])) {
1178 $str .= '<td class="BlankCell">&nbsp;</td>';
1179 } else {
1180 $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);
1181 $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);
1182 if (empty($aword) && empty($dword)) {
1183 $str .= '<td class="LetterOnlyCell"><span id="L_'.$r.'_'.$c.'">&nbsp;</span></td>';
1184 } else {
1185 $i++; // increment clue index
1186 $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.')">&nbsp;&nbsp;&nbsp;</span></td>';
1190 $str .= '</tr>';
1192 return $str;
1194 function v6_get_jcross_grid(&$row, &$r_max, &$c_max) {
1195 $row = $this->parent->xml_values('data,crossword,grid,row');
1196 $r_max = 0;
1197 $c_max = 0;
1198 if (isset($row) && is_array($row)) {
1199 for($r=0; $r<count($row); $r++) {
1200 if (isset($row[$r]['cell']) && is_array($row[$r]['cell'])) {
1201 for($c=0; $c<count($row[$r]['cell']); $c++) {
1202 if (!empty($row[$r]['cell'][$c]['#'])) {
1203 $r_max = max($r, $r_max);
1204 $c_max = max($c, $c_max);
1206 } // end for $c
1208 } // end for $r
1211 function get_jcross_dword(&$row, $r, $r_max, $c, $c_max) {
1212 $str = '';
1213 if (($r==0 || empty($row[$r-1]['cell'][$c]['#'])) && $r<$r_max && !empty($row[$r+1]['cell'][$c]['#'])) {
1214 $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, true);
1216 return $str;
1218 function get_jcross_aword(&$row, $r, $r_max, $c, $c_max) {
1219 $str = '';
1220 if (($c==0 || empty($row[$r]['cell'][$c-1]['#'])) && $c<$c_max && !empty($row[$r]['cell'][$c+1]['#'])) {
1221 $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, false);
1223 return $str;
1225 function get_jcross_word(&$row, $r, $r_max, $c, $c_max, $go_down=false) {
1226 $str = '';
1227 while ($r<=$r_max && $c<=$c_max && !empty($row[$r]['cell'][$c]['#'])) {
1228 $str .= $row[$r]['cell'][$c]['#'];
1229 if ($go_down) {
1230 $r++;
1231 } else {
1232 $c++;
1235 return $str;
1238 // specials (JQuiz)
1240 function v6_expand_QuestionOutput() {
1241 $str = '';
1242 $str .= '<ol class="QuizQuestions" id="Questions">'."\n";
1244 $q = 0;
1245 $tags = 'data,questions,question-record';
1246 while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
1248 // get question
1249 $question_text = $this->parent->xml_value($tags, $question."['question'][0]['#']");
1250 $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");
1252 $first_answer_text = $this->parent->xml_value($tags, $question."['answers'][0]['#']['answer'][0]['#']['text'][0]['#']");
1254 // check we have a question (or at least one answer)
1255 if (($question_text || $first_answer_text) && $question_type) {
1257 $str .= '<li class="QuizQuestion" id="Q_'.$q.'" style="display: none;">';
1258 $str .= '<p class="QuestionText">'.$question_text.'</p>';
1260 if (
1261 $question_type==HOTPOT_JQUIZ_SHORTANSWER ||
1262 $question_type==HOTPOT_JQUIZ_HYBRID
1264 $str .= '<div class="ShortAnswer" id="Q_'.$q.'_SA"><form method="post" action="" onsubmit="return false;"><div>';
1265 $str .= '<input type="text" id="Q_'.$q.'_Guess" onfocus="TrackFocus('."'".'Q_'.$q.'_Guess'."'".')" onblur="LeaveGap()" class="ShortAnswerBox" size="9" /></input><br /><br />';
1267 $caption = $this->v6_expand_CheckCaption();
1268 $str .= $this->v6_expand_jquiz_button($caption, "CheckShortAnswer($q)");
1270 if ($this->v6_expand_Hint()) {
1271 $caption = $this->v6_expand_HintCaption();
1272 $str .= $this->v6_expand_jquiz_button($caption, "ShowHint($q)");
1275 if ($this->v6_expand_ShowAnswer()) {
1276 $caption = $this->v6_expand_ShowAnswerCaption();
1277 $str .= $this->v6_expand_jquiz_button($caption, "ShowAnswers($q)");
1280 $str .= '</div></form></div>';
1283 if (
1284 $question_type==HOTPOT_JQUIZ_MULTICHOICE ||
1285 $question_type==HOTPOT_JQUIZ_HYBRID ||
1286 $question_type==HOTPOT_JQUIZ_MULTISELECT
1289 switch ($question_type) {
1290 case HOTPOT_JQUIZ_MULTICHOICE:
1291 $str .= '<ol class="MCAnswers">'."\n";
1292 break;
1293 case HOTPOT_JQUIZ_HYBRID:
1294 $str .= '<ol class="MCAnswers" id="Q_'.$q.'_Hybrid_MC" style="display: none;">'."\n";
1295 break;
1296 case HOTPOT_JQUIZ_MULTISELECT:
1297 $str .= '<ol class="MSelAnswers">'."\n";
1298 break;
1301 $a = 0;
1302 $aa = 0;
1303 $answers = $question."['answers'][0]['#']";
1304 while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
1305 $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']");
1306 if ($text) {
1307 switch ($question_type) {
1308 case HOTPOT_JQUIZ_MULTICHOICE:
1309 case HOTPOT_JQUIZ_HYBRID:
1310 $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");
1311 if ($include) {
1312 $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)">&nbsp;&nbsp;?&nbsp;&nbsp;</button>&nbsp;&nbsp;'.$text.'</li>'."\n";
1314 break;
1315 case HOTPOT_JQUIZ_MULTISELECT:
1316 $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";
1317 break;
1319 $aa++;
1321 $a++;
1324 $str .= '</ol>';
1326 if ($question_type==HOTPOT_JQUIZ_MULTISELECT) {
1327 $caption = $this->v6_expand_CheckCaption();
1328 $str .= $this->v6_expand_jquiz_button($caption, "CheckMultiSelAnswer($q)");
1332 $str .= "</li>\n";
1334 $q++;
1336 } // end while $question
1338 $str .= "</ol>\n";
1339 return $str;
1342 function v6_expand_jquiz_button($caption, $onclick) {
1343 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>';
1346 // jquiz.js_
1348 function v6_expand_MultiChoice() {
1349 return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTICHOICE);
1351 function v6_expand_ShortAnswer() {
1352 return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_SHORTANSWER);
1354 function v6_expand_MultiSelect() {
1355 return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTISELECT);
1357 function v6_jquiz_question_type($type) {
1358 // does this quiz have any questions of the given $type?
1359 $flag = false;
1361 $q = 0;
1362 $tags = 'data,questions,question-record';
1363 while (($question = "[$q]['#']") && $this->parent->xml_value($tags, $question)) {
1364 $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");
1365 if ($question_type==$type || ($question_type==HOTPOT_JQUIZ_HYBRID && ($type==HOTPOT_JQUIZ_MULTICHOICE || $type==HOTPOT_JQUIZ_SHORTANSWER))) {
1366 $flag = true;
1367 break;
1369 $q++;
1371 return $flag;
1373 function v6_expand_CorrectFirstTime() {
1374 return $this->js_value('hotpot-config-file,global,correct-first-time');
1376 function v6_expand_ContinuousScoring() {
1377 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',continuous-scoring');
1379 function v6_expand_ShowCorrectFirstTime() {
1380 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',show-correct-first-time');
1382 function v6_expand_ShuffleAs() {
1383 return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-answers');
1386 function v6_expand_DefaultRight() {
1387 return $this->v6_expand_GuessCorrect();
1389 function v6_expand_DefaultWrong() {
1390 return $this->v6_expand_GuessIncorrect();
1392 function v6_expand_ShowAllQuestionsCaptionJS() {
1393 return $this->v6_expand_ShowAllQuestionsCaption();
1395 function v6_expand_ShowOneByOneCaptionJS() {
1396 return $this->v6_expand_ShowOneByOneCaption();
1399 // hp6checkshortanswers.js_ (JQuiz)
1401 function v6_expand_CorrectList() {
1402 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',correct-answers');
1404 function v6_expand_HybridTries() {
1405 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',short-answer-tries-on-hybrid-q');
1407 function v6_expand_PleaseEnter() {
1408 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',enter-a-guess');
1410 function v6_expand_PartlyIncorrect() {
1411 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',partly-incorrect');
1413 function v6_expand_ShowAnswerCaption() {
1414 return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-answer-caption');
1416 function v6_expand_ShowAlsoCorrect() {
1417 return $this->bool_value('hotpot-config-file,global,show-also-correct');
1420 } // end class
1421 function hotpot_sort_keypad_chars($a, $b) {
1422 $a = hotpot_keypad_sort_value($a);
1423 $b = hotpot_keypad_sort_value($b);
1424 return ($a<$b) ? -1 : ($a==$b ? 0 : 1);
1426 function hotpot_keypad_sort_value($char) {
1428 // hexadecimal
1429 if (preg_match('|&#x([0-9A-F]+);|ie', $char, $matches)) {
1430 $ord = hexdec($matches[1]);
1432 // decimal
1433 } else if (preg_match('|&#(\d+);|i', $char, $matches)) {
1434 $ord = intval($matches[1]);
1436 // other html entity
1437 } else if (preg_match('|&[^;]+;|', $char, $matches)) {
1438 $char = html_entity_decode($matches[0]);
1439 $ord = empty($char) ? 0 : ord($char);
1441 // not an html entity
1442 } else {
1443 $char = trim($char);
1444 $ord = empty($char) ? 0 : ord($char);
1447 // lowercase letters (plain or accented)
1448 if (($ord>=97 && $ord<=122) || ($ord>=224 && $ord<=255)) {
1449 $sort_value = ($ord-31).'.'.sprintf('%04d', $ord);
1451 // all other characters
1452 } else {
1453 $sort_value = $ord;
1456 return $sort_value;