[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/mod/hotpot/template/ -> v6.php (source)

   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=='<=' ? '&lt;=' : $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=='=>' ? '=&gt;' : $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('|&#x003C;img.*?src="(.*?)".*?&#x003E;|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(' &#160;&#160; ', $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('&#x003C;'=>'<', '&#x003E;'=>'>', "\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">&nbsp;</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.'">&nbsp;</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.')">&nbsp;&nbsp;&nbsp;</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)">&nbsp;&nbsp;?&nbsp;&nbsp;</button>&nbsp;&nbsp;'.$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  ?>


Generated: Wed Jan 14 11:33:29 2009 Cross-referenced by PHPXref 0.7