ScormQuestion.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * The ScormQuestion class is a gateway to getting the answers exported
  5. * (the question is just an HTML text, while the answers are the most important).
  6. * It is important to note that the SCORM export process is done in two parts.
  7. * First, the HTML part (which is the presentation), and second the JavaScript
  8. * part (the process).
  9. * The two bits are separate to allow for a one-big-javascript and a one-big-html
  10. * files to be built. Each export function thus returns an array of HTML+JS.
  11. *
  12. *
  13. * @author Claro Team <cvs@claroline.net>
  14. * @author Yannick Warnier <yannick.warnier@beeznest.com>
  15. *
  16. * @package chamilo.exercise.scorm
  17. */
  18. class ScormQuestion extends Question
  19. {
  20. public $js_id;
  21. public $answer;
  22. /**
  23. * ScormQuestion constructor.
  24. */
  25. public function __construct()
  26. {
  27. parent::__construct();
  28. }
  29. /**
  30. * Returns the HTML + JS flow corresponding to one question.
  31. *
  32. * @param int $questionId The question ID
  33. * @param bool $standalone (ie including XML tag, DTD declaration, etc)
  34. * @param int $jsId The JavaScript ID for this question.
  35. * Due to the nature of interactions, we must have a natural sequence for
  36. * questions in the generated JavaScript.
  37. *
  38. * @return string|array
  39. */
  40. public function exportQuestionToScorm(
  41. $questionId,
  42. $jsId
  43. ) {
  44. $question = self::read($questionId);
  45. if (!$question) {
  46. return '';
  47. }
  48. $this->id = $question->id;
  49. $this->js_id = $jsId;
  50. $this->type = $question->type;
  51. $this->question = $question->question;
  52. $this->description = $question->description;
  53. $this->weighting = $question->weighting;
  54. $this->position = $question->position;
  55. $this->picture = $question->picture;
  56. $assessmentItem = new ScormAssessmentItem($this);
  57. return $assessmentItem->export();
  58. }
  59. /**
  60. * Include the correct answer class and create answer.
  61. */
  62. public function setAnswer()
  63. {
  64. switch ($this->type) {
  65. case MCUA:
  66. $this->answer = new ScormAnswerMultipleChoice($this->id);
  67. $this->answer->questionJSId = $this->js_id;
  68. break;
  69. case MCMA:
  70. case GLOBAL_MULTIPLE_ANSWER:
  71. $this->answer = new ScormAnswerMultipleChoice($this->id);
  72. $this->answer->questionJSId = $this->js_id;
  73. break;
  74. case TF:
  75. $this->answer = new ScormAnswerTrueFalse($this->id);
  76. $this->answer->questionJSId = $this->js_id;
  77. break;
  78. case FIB:
  79. $this->answer = new ScormAnswerFillInBlanks($this->id);
  80. $this->answer->questionJSId = $this->js_id;
  81. break;
  82. case MATCHING:
  83. case MATCHING_DRAGGABLE:
  84. case DRAGGABLE:
  85. $this->answer = new ScormAnswerMatching($this->id);
  86. $this->answer->questionJSId = $this->js_id;
  87. break;
  88. case ORAL_EXPRESSION:
  89. case FREE_ANSWER:
  90. $this->answer = new ScormAnswerFree($this->id);
  91. $this->answer->questionJSId = $this->js_id;
  92. break;
  93. case HOT_SPOT:
  94. $this->answer = new ScormAnswerHotspot($this->id);
  95. $this->answer->questionJSId = $this->js_id;
  96. break;
  97. case MULTIPLE_ANSWER_COMBINATION:
  98. $this->answer = new ScormAnswerMultipleChoice($this->id);
  99. $this->answer->questionJSId = $this->js_id;
  100. break;
  101. case HOT_SPOT_ORDER:
  102. $this->answer = new ScormAnswerHotspot($this->id);
  103. $this->answer->questionJSId = $this->js_id;
  104. break;
  105. case HOT_SPOT_DELINEATION:
  106. $this->answer = new ScormAnswerHotspot($this->id);
  107. $this->answer->questionJSId = $this->js_id;
  108. break;
  109. // not supported
  110. case UNIQUE_ANSWER_NO_OPTION:
  111. case MULTIPLE_ANSWER_TRUE_FALSE:
  112. case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE:
  113. case UNIQUE_ANSWER_IMAGE:
  114. case CALCULATED_ANSWER:
  115. $this->answer = new ScormAnswerMultipleChoice($this->id);
  116. $this->answer->questionJSId = $this->js_id;
  117. break;
  118. default:
  119. $this->answer = new stdClass();
  120. $this->answer->questionJSId = $this->js_id;
  121. break;
  122. }
  123. return true;
  124. }
  125. /**
  126. * @throws Exception
  127. *
  128. * @return array
  129. */
  130. public function export()
  131. {
  132. $html = $this->getQuestionHTML();
  133. $js = $this->getQuestionJS();
  134. if (is_object($this->answer) && $this->answer instanceof Answer) {
  135. list($js2, $html2) = $this->answer->export();
  136. $js .= $js2;
  137. $html .= $html2;
  138. } else {
  139. throw new \Exception('Question not supported. Exercise: '.$this->selectTitle());
  140. }
  141. return [$js, $html];
  142. }
  143. /**
  144. * {@inheritdoc}
  145. */
  146. public function createAnswersForm($form)
  147. {
  148. return true;
  149. }
  150. /**
  151. * {@inheritdoc}
  152. */
  153. public function processAnswersCreation($form, $exercise)
  154. {
  155. return true;
  156. }
  157. /**
  158. * Returns an HTML-formatted question.
  159. */
  160. public function getQuestionHTML()
  161. {
  162. $title = $this->selectTitle();
  163. $description = $this->selectDescription();
  164. $cols = 2;
  165. $s = '<tr>
  166. <td colspan="'.$cols.'" id="question_'.$this->id.'_title" valign="middle" style="background-color:#d6d6d6;">
  167. '.$title.'
  168. </td>
  169. </tr>
  170. <tr>
  171. <td valign="top" colspan="'.$cols.'">
  172. <i>'.$description.'</i>
  173. </td>
  174. </tr>';
  175. return $s;
  176. }
  177. /**
  178. * Return the JavaScript code bound to the question.
  179. */
  180. public function getQuestionJS()
  181. {
  182. $weight = $this->selectWeighting();
  183. $js = '
  184. questions.push('.$this->js_id.');
  185. $(function() {
  186. if (exerciseInfo.randomAnswers == true) {
  187. $("#question_'.$this->js_id.'").shuffleRows();
  188. }
  189. });';
  190. $js .= "\n";
  191. switch ($this->type) {
  192. case ORAL_EXPRESSION:
  193. /*$script = file_get_contents(api_get_path(LIBRARY_PATH) . 'javascript/rtc/RecordRTC.js');
  194. $script .= file_get_contents(api_get_path(LIBRARY_PATH) . 'wami-recorder/recorder.js');
  195. $script .= file_get_contents(api_get_path(LIBRARY_PATH) . 'wami-recorder/gui.js');
  196. $js .= $script;*/
  197. break;
  198. case HOT_SPOT:
  199. //put the max score to 0 to avoid discounting the points of
  200. //non-exported quiz types in the SCORM
  201. $weight = 0;
  202. break;
  203. }
  204. $js .= 'questions_score_max['.$this->js_id.'] = '.$weight.";";
  205. return $js;
  206. }
  207. }