exercise_submit.php 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * Exercise submission
  5. * This script allows to run an exercise. According to the exercise type, questions
  6. * can be on an unique page, or one per page with a Next button.
  7. *
  8. * One exercise may contain different types of answers (unique or multiple selection,
  9. * matching, fill in blanks, free answer, hot-spot).
  10. *
  11. * Questions are selected randomly or not.
  12. *
  13. * When the user has answered all questions and clicks on the button "Ok",
  14. * it goes to exercise_result.php
  15. *
  16. * Notice : This script is also used to show a question before modifying it by
  17. * the administrator
  18. * @package chamilo.exercise
  19. * @author Olivier Brouckaert
  20. * @author Julio Montoya <gugli100@gmail.com>
  21. * Fill in blank option added (2008)
  22. * Cleaning exercises (2010),
  23. * Adding hotspot delineation support (2011)
  24. * Adding reminder + ajax support (2011)
  25. * Modified by hubert.borderiou (2011-10-21 question category)
  26. */
  27. use \ChamiloSession as Session;
  28. require_once '../inc/global.inc.php';
  29. $current_course_tool = TOOL_QUIZ;
  30. $this_section = SECTION_COURSES;
  31. $debug = false;
  32. // Notice for unauthorized people.
  33. api_protect_course_script(true);
  34. $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
  35. $is_allowedToEdit = api_is_allowed_to_edit(null,true);
  36. $glossaryExtraTools = api_get_setting('show_glossary_in_extra_tools');
  37. $showGlossary = in_array($glossaryExtraTools, array('true', 'exercise', 'exercise_and_lp'));
  38. if ($origin == 'learnpath') {
  39. $showGlossary = in_array($glossaryExtraTools, array('true', 'lp', 'exercise_and_lp'));
  40. }
  41. if ($showGlossary) {
  42. $htmlHeadXtra[] = '<script type="text/javascript" src="'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php"></script>';
  43. $htmlHeadXtra[] = api_get_js('jquery.highlight.js');
  44. }
  45. //This library is necessary for the time control feature
  46. $htmlHeadXtra[] = api_get_css(api_get_path(WEB_LIBRARY_PATH).'javascript/epiclock/stylesheet/jquery.epiclock.css');
  47. $htmlHeadXtra[] = api_get_css(api_get_path(WEB_LIBRARY_PATH).'javascript/epiclock/renderers/minute/epiclock.minute.css');
  48. $htmlHeadXtra[] = api_get_js('epiclock/javascript/jquery.dateformat.min.js');
  49. $htmlHeadXtra[] = api_get_js('epiclock/javascript/jquery.epiclock.min.js');
  50. $htmlHeadXtra[] = api_get_js('epiclock/renderers/minute/epiclock.minute.js');
  51. // General parameters passed via POST/GET
  52. $learnpath_id = isset($_REQUEST['learnpath_id']) ? intval($_REQUEST['learnpath_id']) : 0;
  53. $learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? intval($_REQUEST['learnpath_item_id']) : 0;
  54. $learnpath_item_view_id = isset($_REQUEST['learnpath_item_view_id']) ? intval($_REQUEST['learnpath_item_view_id']) : 0;
  55. $reminder = isset($_REQUEST['reminder']) ? intval($_REQUEST['reminder']) : 0;
  56. $remind_question_id = isset($_REQUEST['remind_question_id']) ? intval($_REQUEST['remind_question_id']) : 0;
  57. $exerciseId = isset($_REQUEST['exerciseId']) ? intval($_REQUEST['exerciseId']) : 0;
  58. $formSent = isset($_REQUEST['formSent']) ? $_REQUEST['formSent'] : null;
  59. $exerciseResult = isset($_REQUEST['exerciseResult']) ? $_REQUEST['exerciseResult'] : null;
  60. $exerciseResultCoordinates = isset($_REQUEST['exerciseResultCoordinates']) ? $_REQUEST['exerciseResultCoordinates'] : null;
  61. $choice = isset($_REQUEST['choice']) ? $_REQUEST['choice'] : null;
  62. $choice = empty($choice) ? isset($_REQUEST['choice2']) ? $_REQUEST['choice2'] : null : null;
  63. //From submit modal
  64. $current_question = isset($_REQUEST['num']) ? intval($_REQUEST['num']) : null;
  65. $currentAnswer = isset($_REQUEST['num_answer']) ? intval($_REQUEST['num_answer']) : null;
  66. //Error message
  67. $error = '';
  68. //Table calls
  69. $exercice_attemp_table = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
  70. /* Teacher takes an exam and want to see a preview,
  71. we delete the objExercise from the session in order to get the latest
  72. changes in the exercise */
  73. if (api_is_allowed_to_edit(null,true) && isset($_GET['preview']) && $_GET['preview'] == 1 ) {
  74. Session::erase('objExercise');
  75. }
  76. // 1. Loading the $objExercise variable
  77. if (!isset($_SESSION['objExercise']) || $_SESSION['objExercise']->id != $_REQUEST['exerciseId']) {
  78. // Construction of Exercise
  79. $objExercise = new Exercise();
  80. Session::write('firstTime', true);
  81. if ($debug) {error_log('1. Setting the $objExercise variable'); };
  82. unset($_SESSION['questionList']);
  83. // if the specified exercise doesn't exist or is disabled
  84. if (!$objExercise->read($exerciseId) ||
  85. (!$objExercise->selectStatus() && !$is_allowedToEdit && $origin != 'learnpath')
  86. ) {
  87. if ($debug) {error_log('1.1. Error while reading the exercise'); };
  88. unset ($objExercise);
  89. $error = get_lang('ExerciseNotFound');
  90. } else {
  91. // Saves the object into the session
  92. Session::write('objExercise', $objExercise);
  93. if ($debug) {error_log('1.1. $_SESSION[objExercise] was unset - set now - end'); };
  94. }
  95. } else {
  96. Session::write('firstTime', false);
  97. }
  98. //2. Checking if $objExercise is set
  99. if (!isset($objExercise) && isset($_SESSION['objExercise'])) {
  100. if ($debug) { error_log('2. Loading $objExercise from session'); };
  101. $objExercise = $_SESSION['objExercise'];
  102. }
  103. //3. $objExercise is not set, then return to the exercise list
  104. if (!is_object($objExercise)) {
  105. if ($debug) {error_log('3. $objExercise was not set, kill the script'); };
  106. header('Location: exercice.php');
  107. exit;
  108. }
  109. // If reminder ends we jump to the exercise_reminder
  110. if ($objExercise->review_answers) {
  111. if ($remind_question_id == -1) {
  112. header('Location: exercise_reminder.php?origin='.$origin.'&exerciseId='.$exerciseId);
  113. exit;
  114. }
  115. }
  116. $current_timestamp = time();
  117. $my_remind_list = array();
  118. $time_control = false;
  119. if ($objExercise->expired_time != 0) {
  120. $time_control = true;
  121. }
  122. // Generating the time control key for the user
  123. $current_expired_time_key = ExerciseLib::get_time_control_key($objExercise->id, $learnpath_id, $learnpath_item_id);
  124. $_SESSION['duration_time'][$current_expired_time_key] = $current_timestamp;
  125. if ($time_control) {
  126. // Get the expired time of the current exercice in track_e_exercises
  127. $total_seconds = $objExercise->expired_time*60;
  128. }
  129. $show_clock = true;
  130. $user_id = api_get_user_id();
  131. if ($objExercise->selectAttempts() > 0) {
  132. $attempt_html = '';
  133. $attempt_count = Event::get_attempt_count(
  134. $user_id,
  135. $exerciseId,
  136. $learnpath_id,
  137. $learnpath_item_id,
  138. $learnpath_item_view_id
  139. );
  140. if ($attempt_count >= $objExercise->selectAttempts()) {
  141. $show_clock = false;
  142. if (!api_is_allowed_to_edit(null,true)) {
  143. if ($objExercise->results_disabled == 0 && $origin != 'learnpath') {
  144. // Showing latest attempt according with task BT#1628
  145. $exercise_stat_info = Event::getExerciseResultsByUser(
  146. $user_id,
  147. $exerciseId,
  148. api_get_course_id(),
  149. api_get_session_id()
  150. );
  151. if (!empty($exercise_stat_info)) {
  152. $max_exe_id = max(array_keys($exercise_stat_info));
  153. $last_attempt_info = $exercise_stat_info[$max_exe_id];
  154. $attempt_html .= Display::div(get_lang('Date').': '.api_get_local_time($last_attempt_info['exe_date']), array('id'=>''));
  155. $attempt_html .= Display::return_message(sprintf(get_lang('ReachedMaxAttempts'), $exercise_title, $objExercise->selectAttempts()), 'warning', false);
  156. if (!empty($last_attempt_info['question_list'])) {
  157. foreach($last_attempt_info['question_list'] as $question_data) {
  158. $question_id = $question_data['question_id'];
  159. $marks = $question_data['marks'];
  160. $question_info = Question::read($question_id);
  161. $attempt_html .= Display::div($question_info->question, array('class'=>'question_title'));
  162. $attempt_html .= Display::div(get_lang('Score').' '.$marks, array('id'=>'question_score'));
  163. }
  164. }
  165. $score = ExerciseLib::show_score($last_attempt_info['exe_result'], $last_attempt_info['exe_weighting']);
  166. $attempt_html .= Display::div(get_lang('YourTotalScore').' '.$score, array('id'=>'question_score'));
  167. } else {
  168. $attempt_html .= Display::return_message(sprintf(get_lang('ReachedMaxAttempts'), $exercise_title, $objExercise->selectAttempts()), 'warning', false);
  169. }
  170. } else {
  171. $attempt_html .= Display::return_message(sprintf(get_lang('ReachedMaxAttempts'), $exercise_title, $objExercise->selectAttempts()), 'warning', false);
  172. }
  173. } else {
  174. $attempt_html .= Display :: return_message(sprintf(get_lang('ReachedMaxAttempts'), $exercise_title, $objExercise->selectAttempts()), 'warning', false);
  175. }
  176. if ($origin == 'learnpath') {
  177. Display :: display_reduced_header();
  178. } else {
  179. Display :: display_header($nameTools,'Exercises');
  180. }
  181. echo $attempt_html;
  182. if ($origin != 'learnpath')
  183. Display :: display_footer();
  184. exit;
  185. }
  186. }
  187. if ($debug) {
  188. error_log("4. Setting the exe_id: $exe_id");
  189. }
  190. /* 5. Getting user exercise info (if the user took the exam before)
  191. generating exe_id */
  192. $exercise_stat_info = $objExercise->get_stat_track_exercise_info(
  193. $learnpath_id,
  194. $learnpath_item_id,
  195. $learnpath_item_view_id
  196. );
  197. $clock_expired_time = null;
  198. if (empty($exercise_stat_info)) {
  199. if ($debug) error_log('5 $exercise_stat_info is empty ');
  200. $total_weight = 0;
  201. $questionList = $objExercise->get_validated_question_list();
  202. foreach ($questionList as $question_id) {
  203. $objQuestionTmp = Question::read($question_id);
  204. $total_weight += floatval($objQuestionTmp->weighting);
  205. }
  206. if ($time_control) {
  207. $expected_time = $current_timestamp + $total_seconds;
  208. if ($debug) error_log('5.1. $current_timestamp '.$current_timestamp);
  209. if ($debug) error_log('5.2. $expected_time '.$expected_time);
  210. $clock_expired_time = api_get_utc_datetime($expected_time);
  211. if ($debug) error_log('5.3. $expected_time '.$clock_expired_time);
  212. //Sessions that contain the expired time
  213. $_SESSION['expired_time'][$current_expired_time_key] = $clock_expired_time;
  214. if ($debug) { error_log('5.4. Setting the $_SESSION[expired_time]: '.$_SESSION['expired_time'][$current_expired_time_key] ); };
  215. }
  216. $exe_id = $objExercise->save_stat_track_exercise_info(
  217. $clock_expired_time,
  218. $learnpath_id,
  219. $learnpath_item_id,
  220. $learnpath_item_view_id,
  221. $questionList,
  222. $total_weight
  223. );
  224. $exercise_stat_info = $objExercise->get_stat_track_exercise_info(
  225. $learnpath_id,
  226. $learnpath_item_id,
  227. $learnpath_item_view_id
  228. );
  229. if ($debug) error_log("5.5 exercise_stat_info[] exists getting exe_id $exe_id");
  230. } else {
  231. $exe_id = $exercise_stat_info['exe_id'];
  232. // Remember last question id position.
  233. $isFirstTime = Session::read('firstTime');
  234. if ($isFirstTime && $objExercise->type == ONE_PER_PAGE) {
  235. $resolvedQuestions = Event::getAllExerciseEventByExeId($exe_id);
  236. if (!empty($resolvedQuestions) &&
  237. !empty($exercise_stat_info['data_tracking'])
  238. ) {
  239. $last = current(end($resolvedQuestions));
  240. $attemptQuestionList = explode(',', $exercise_stat_info['data_tracking']);
  241. $count = 1;
  242. foreach ($attemptQuestionList as $question) {
  243. if ($last['question_id'] == $question) {
  244. break;
  245. }
  246. $count++;
  247. }
  248. $current_question = $count;
  249. }
  250. }
  251. if ($debug) error_log("5 exercise_stat_info[] exists getting exe_id $exe_id ");
  252. }
  253. // Array to check in order to block the chat
  254. ExerciseLib::create_chat_exercise_session($exe_id);
  255. if ($debug) { error_log('6. $objExercise->get_stat_track_exercise_info function called:: '.print_r($exercise_stat_info, 1)); };
  256. if (!empty($exercise_stat_info['questions_to_check'])) {
  257. $my_remind_list = $exercise_stat_info['questions_to_check'];
  258. $my_remind_list = explode(',', $my_remind_list);
  259. $my_remind_list = array_filter($my_remind_list);
  260. }
  261. $params = "exe_id=$exe_id&exerciseId=$exerciseId&origin=$origin&learnpath_id=$learnpath_id&learnpath_item_id=$learnpath_item_id&learnpath_item_view_id=$learnpath_item_view_id&".api_get_cidreq();
  262. if ($debug) { error_log("6.1 params: -> $params"); };
  263. if ($reminder == 2 && empty($my_remind_list)) {
  264. if ($debug) { error_log("6.2 calling the exercise_reminder.php "); };
  265. header('Location: exercise_reminder.php?'.$params);
  266. exit;
  267. }
  268. /*
  269. * 7. Loading Time control parameters
  270. * If the expired time is major that zero(0) then the expired time is compute on this time.
  271. */
  272. if ($time_control) {
  273. if ($debug) error_log('7.1. Time control is enabled');
  274. if ($debug) error_log('7.2. $current_expired_time_key '.$current_expired_time_key);
  275. if ($debug) error_log('7.3. $_SESSION[expired_time][$current_expired_time_key] '.$_SESSION['expired_time'][$current_expired_time_key]);
  276. if (!isset($_SESSION['expired_time'][$current_expired_time_key])) {
  277. //Timer - Get expired_time for a student
  278. if (!empty($exercise_stat_info)) {
  279. if ($debug) {error_log('7.4 Seems that the session ends and the user want to retake the exam'); };
  280. $expired_time_of_this_attempt = $exercise_stat_info['expired_time_control'];
  281. if ($debug) {error_log('7.5 $expired_time_of_this_attempt: '.$expired_time_of_this_attempt); }
  282. // Get the last attempt of an exercise
  283. $last_attempt_date = Event::getLastAttemptDateOfExercise($exercise_stat_info['exe_id']);
  284. /* This means that the user enters the exam but do not answer the
  285. first question we get the date from the track_e_exercises not from
  286. the track_et_attempt see #2069 */
  287. if (empty($last_attempt_date)) {
  288. $diff = $current_timestamp - api_strtotime($exercise_stat_info['start_date'], 'UTC');
  289. $last_attempt_date = api_get_utc_datetime(api_strtotime($exercise_stat_info['start_date'],'UTC') + $diff);
  290. } else {
  291. //Recalculate the time control due #2069
  292. $diff = $current_timestamp - api_strtotime($last_attempt_date,'UTC');
  293. $last_attempt_date = api_get_utc_datetime(api_strtotime($last_attempt_date,'UTC') + $diff);
  294. }
  295. if ($debug) {error_log('7.6. $last_attempt_date: '.$last_attempt_date); }
  296. //New expired time - it is due to the possible closure of session
  297. $new_expired_time_in_seconds = api_strtotime($expired_time_of_this_attempt, 'UTC') - api_strtotime($last_attempt_date,'UTC');
  298. if ($debug) {error_log('7.7. $new_expired_time_in_seconds: '.$new_expired_time_in_seconds); }
  299. $expected_time = $current_timestamp + $new_expired_time_in_seconds;
  300. if ($debug) {error_log('7.8. $expected_time1: '.$expected_time); }
  301. $clock_expired_time = api_get_utc_datetime($expected_time);
  302. if ($debug) {error_log('7.9. $clock_expired_time: '.$clock_expired_time); }
  303. // First we update the attempt to today
  304. /* How the expired time is changed into "track_e_exercises" table,
  305. then the last attempt for this student should be changed too */
  306. $sql = "UPDATE $exercice_attemp_table SET
  307. tms = '".api_get_utc_datetime()."'
  308. WHERE
  309. exe_id = '".$exercise_stat_info['exe_id']."' AND
  310. tms = '".$last_attempt_date."' ";
  311. if ($debug) {error_log('7.10. $sql: '.$sql); }
  312. Database::query($sql);
  313. //Sessions that contain the expired time
  314. $_SESSION['expired_time'][$current_expired_time_key] = $clock_expired_time;
  315. if ($debug) {error_log('7.11. Setting the $_SESSION[expired_time]: '.$_SESSION['expired_time'][$current_expired_time_key] ); };
  316. }
  317. } else {
  318. $clock_expired_time = $_SESSION['expired_time'][$current_expired_time_key];
  319. }
  320. } else {
  321. if ($debug) { error_log("7 No time control"); };
  322. }
  323. // Get time left for expiring time
  324. $time_left = api_strtotime($clock_expired_time,'UTC') - time();
  325. /*
  326. * The time control feature is enable here - this feature is enable for a jquery plugin called epiclock
  327. * for more details of how it works see this link : http://eric.garside.name/docs.html?p=epiclock
  328. */
  329. if ($time_control) { //Sends the exercise form when the expired time is finished
  330. $htmlHeadXtra[] = $objExercise->show_time_control_js($time_left);
  331. }
  332. // if the user has submitted the form
  333. $exercise_title = $objExercise->selectTitle();
  334. $exercise_sound = $objExercise->selectSound();
  335. //in LP's is enabled the "remember question" feature?
  336. if (!isset($_SESSION['questionList'])) {
  337. // selects the list of question ID
  338. $questionList = $objExercise->get_validated_question_list();
  339. if ($objExercise->isRandom() && !empty($exercise_stat_info['data_tracking'])) {
  340. $questionList = explode(',', $exercise_stat_info['data_tracking']);
  341. }
  342. Session::write('questionList', $questionList);
  343. if ($debug > 0) { error_log('$_SESSION[questionList] was set'); }
  344. } else {
  345. if (isset($objExercise) && isset($_SESSION['objExercise'])) {
  346. $questionList = $_SESSION['questionList'];
  347. }
  348. }
  349. if ($debug) error_log('8. Question list loaded '.print_r($questionList, 1));
  350. //Real question count
  351. $question_count = 0;
  352. if (!empty($questionList)) {
  353. $question_count = count($questionList);
  354. }
  355. if ($formSent && isset($_POST)) {
  356. if ($debug) { error_log('9. $formSent was set'); }
  357. // Initializing
  358. if (!is_array($exerciseResult)) {
  359. $exerciseResult = array();
  360. $exerciseResultCoordinates = array();
  361. }
  362. //Only for hotspot
  363. if (!isset($choice) && isset($_REQUEST['hidden_hotspot_id'])) {
  364. $hotspot_id = (int)($_REQUEST['hidden_hotspot_id']);
  365. $choice = array($hotspot_id => '');
  366. }
  367. // if the user has answered at least one question
  368. if (is_array($choice)) {
  369. if ($debug) { error_log('9.1. $choice is an array '.print_r($choice, 1)); }
  370. // Also store hotspot spots in the session ($exerciseResultCoordinates
  371. // will be stored in the session at the end of this script)
  372. if (isset($_POST['hotspot'])) {
  373. $exerciseResultCoordinates = $_POST['hotspot'];
  374. if ($debug) { error_log('9.2. $_POST[hotspot] data '.print_r($exerciseResultCoordinates, 1)); }
  375. }
  376. if ($objExercise->type == ALL_ON_ONE_PAGE) {
  377. // $exerciseResult receives the content of the form.
  378. // Each choice of the student is stored into the array $choice
  379. $exerciseResult = $choice;
  380. } else {
  381. // gets the question ID from $choice. It is the key of the array
  382. list ($key) = array_keys($choice);
  383. // if the user didn't already answer this question
  384. if (!isset($exerciseResult[$key])) {
  385. // stores the user answer into the array
  386. $exerciseResult[$key] = $choice[$key];
  387. //saving each question
  388. if ($objExercise->feedback_type != EXERCISE_FEEDBACK_TYPE_DIRECT) {
  389. $nro_question = $current_question; // - 1;
  390. $questionId = $key;
  391. // gets the student choice for this question
  392. $choice = $exerciseResult[$questionId];
  393. if (isset($exe_id)) {
  394. // Manage the question and answer attempts
  395. if ($debug) { error_log('8.3. manage_answer exe_id: '.$exe_id.' - $questionId: '.$questionId.' Choice'.print_r($choice,1)); }
  396. $objExercise->manage_answer(
  397. $exe_id,
  398. $questionId,
  399. $choice,
  400. 'exercise_show',
  401. $exerciseResultCoordinates,
  402. true,
  403. false,
  404. false,
  405. $objExercise->propagate_neg,
  406. array()
  407. );
  408. }
  409. //END of saving and qualifying
  410. }
  411. }
  412. }
  413. if ($debug) { error_log('9.3. $choice is an array - end'); }
  414. if ($debug) { error_log('9.4. $exerciseResult '.print_r($exerciseResult,1)); }
  415. }
  416. // the script "exercise_result.php" will take the variable $exerciseResult from the session
  417. Session::write('exerciseResult', $exerciseResult);
  418. Session::write('remind_list', $remind_list);
  419. Session::write('exerciseResultCoordinates',$exerciseResultCoordinates);
  420. // if all questions on one page OR if it is the last question (only for an exercise with one question per page)
  421. if ($objExercise->type == ALL_ON_ONE_PAGE || $current_question >= $question_count) {
  422. if (api_is_allowed_to_session_edit()) {
  423. // goes to the script that will show the result of the exercise
  424. if ($objExercise->type == ALL_ON_ONE_PAGE) {
  425. if ($debug) { error_log('10. Exercise ALL_ON_ONE_PAGE -> Redirecting to exercise_result.php'); }
  426. //We check if the user attempts before sending to the exercise_result.php
  427. if ($objExercise->selectAttempts() > 0) {
  428. $attempt_count = Event::get_attempt_count(
  429. api_get_user_id(),
  430. $exerciseId,
  431. $learnpath_id,
  432. $learnpath_item_id,
  433. $learnpath_item_view_id
  434. );
  435. if ($attempt_count >= $objExercise->selectAttempts()) {
  436. Display :: display_warning_message(
  437. sprintf(get_lang('ReachedMaxAttempts'), $exercise_title, $objExercise->selectAttempts()),
  438. false
  439. );
  440. if ($origin != 'learnpath') {
  441. //so we are not in learnpath tool
  442. echo '</div>'; //End glossary div
  443. Display :: display_footer();
  444. } else {
  445. echo '</body></html>';
  446. }
  447. }
  448. }
  449. header("Location: exercise_result.php?".api_get_cidreq()."&exe_id=$exe_id&origin=$origin&learnpath_id=$learnpath_id&learnpath_item_id=$learnpath_item_id&learnpath_item_view_id=$learnpath_item_view_id");
  450. exit;
  451. } else {
  452. if ($debug) { error_log('10. Redirecting to exercise_show.php'); }
  453. header("Location: exercise_result.php?".api_get_cidreq()."&exe_id=$exe_id&origin=$origin&learnpath_id=$learnpath_id&learnpath_item_id=$learnpath_item_id&learnpath_item_view_id=$learnpath_item_view_id");
  454. exit;
  455. }
  456. } else {
  457. if ($debug) { error_log('10. Redirecting to exercise_submit.php'); }
  458. header("Location: exercise_submit.php?".api_get_cidreq()."&exerciseId=$exerciseId&origin=$origin");
  459. exit;
  460. }
  461. }
  462. if ($debug) { error_log('11. $formSent was set - end'); }
  463. } else {
  464. if ($debug) { error_log('9. $formSent was NOT sent'); }
  465. }
  466. // If questionNum comes from POST and not from GET
  467. if (!$current_question || isset($_REQUEST['num']) && $_REQUEST['num']) {
  468. if (!$current_question) {
  469. $current_question = 1;
  470. } else {
  471. $current_question++;
  472. }
  473. }
  474. if ($question_count != 0) {
  475. if (($objExercise->type == ALL_ON_ONE_PAGE ||
  476. $current_question > $question_count)
  477. ) {
  478. if (api_is_allowed_to_session_edit()) {
  479. // goes to the script that will show the result of the exercise
  480. if ($objExercise->type == ALL_ON_ONE_PAGE) {
  481. if ($debug) { error_log('12. Exercise ALL_ON_ONE_PAGE -> Redirecting to exercise_result.php'); }
  482. //We check if the user attempts before sending to the exercise_result.php
  483. if ($objExercise->selectAttempts() > 0) {
  484. $attempt_count = Event::get_attempt_count(
  485. api_get_user_id(),
  486. $exerciseId,
  487. $learnpath_id,
  488. $learnpath_item_id,
  489. $learnpath_item_view_id
  490. );
  491. if ($attempt_count >= $objExercise->selectAttempts()) {
  492. Display :: display_warning_message(
  493. sprintf(get_lang('ReachedMaxAttempts'), $exercise_title, $objExercise->selectAttempts()),
  494. false
  495. );
  496. if ($origin != 'learnpath') {
  497. //so we are not in learnpath tool
  498. echo '</div>'; //End glossary div
  499. Display :: display_footer();
  500. } else {
  501. echo '</body></html>';
  502. }
  503. exit;
  504. }
  505. }
  506. } else {
  507. if ($objExercise->review_answers) {
  508. header('Location: exercise_reminder.php?'.$params);
  509. exit;
  510. } else {
  511. header("Location: exercise_result.php?".api_get_cidreq()."&exe_id=$exe_id&origin=$origin&learnpath_id=$learnpath_id&learnpath_item_id=$learnpath_item_id&learnpath_item_view_id=$learnpath_item_view_id");
  512. exit;
  513. }
  514. }
  515. } else {
  516. if ($debug) { error_log('Redirecting to exercise_submit.php'); }
  517. exit;
  518. }
  519. }
  520. } else {
  521. $error = get_lang('ThereAreNoQuestionsForThisExercise');
  522. // if we are in the case where user select random by category, but didn't choose the number of random question
  523. if ($objExercise->selectRandomByCat() > 0 && $objExercise->random <= 0) {
  524. $error .= "<br/>".get_lang('PleaseSelectSomeRandomQuestion');
  525. }
  526. }
  527. if (!empty ($_GET['gradebook']) && $_GET['gradebook'] == 'view') {
  528. $_SESSION['gradebook'] = Security :: remove_XSS($_GET['gradebook']);
  529. $gradebook = $_SESSION['gradebook'];
  530. } elseif (empty ($_GET['gradebook'])) {
  531. unset ($_SESSION['gradebook']);
  532. $gradebook = '';
  533. }
  534. if (!empty ($gradebook) && $gradebook == 'view') {
  535. $interbreadcrumb[] = array ('url' => '../gradebook/' . Security::remove_XSS($_SESSION['gradebook_dest']),'name' => get_lang('ToolGradebook'));
  536. }
  537. $interbreadcrumb[] = array ("url" => "exercice.php?".api_get_cidreq(), "name" => get_lang('Exercices'));
  538. $interbreadcrumb[] = array ("url" => "#", "name" => $objExercise->name);
  539. if ($origin != 'learnpath') { //so we are not in learnpath tool
  540. Display :: display_header(null,'Exercises');
  541. if (!api_is_allowed_to_session_edit() ) {
  542. Display :: display_warning_message(get_lang('SessionIsReadOnly'));
  543. }
  544. } else {
  545. Display::display_reduced_header();
  546. echo '<div style="height:10px">&nbsp;</div>';
  547. }
  548. $show_quiz_edition = $objExercise->added_in_lp();
  549. // I'm in a preview mode
  550. if (api_is_course_admin() && $origin != 'learnpath') {
  551. echo '<div class="actions">';
  552. if ($show_quiz_edition == false) {
  553. echo '<a href="exercise_admin.php?' . api_get_cidreq() . '&modifyExercise=yes&exerciseId=' . $objExercise->id . '">'.Display :: return_icon('settings.png', get_lang('ModifyExercise'),'',ICON_SIZE_MEDIUM).'</a>';
  554. } else {
  555. echo '<a href="#">'.Display::return_icon('settings_na.png', get_lang('ModifyExercise'),'',ICON_SIZE_MEDIUM).'</a>';
  556. }
  557. echo '</div>';
  558. }
  559. $is_visible_return = $objExercise->is_visible(
  560. $learnpath_id,
  561. $learnpath_item_id,
  562. $learnpath_item_view_id
  563. );
  564. if ($is_visible_return['value'] == false) {
  565. echo $is_visible_return['message'];
  566. if ($origin != 'learnpath') {
  567. Display :: display_footer();
  568. }
  569. exit;
  570. }
  571. $limit_time_exists = (($objExercise->start_time != '0000-00-00 00:00:00') || ($objExercise->end_time != '0000-00-00 00:00:00')) ? true : false;
  572. if ($limit_time_exists) {
  573. $exercise_start_time = api_strtotime($objExercise->start_time, 'UTC');
  574. $exercise_end_time = api_strtotime($objExercise->end_time, 'UTC');
  575. $time_now = time();
  576. if ($objExercise->start_time != '0000-00-00 00:00:00') {
  577. $permission_to_start = (($time_now - $exercise_start_time) > 0) ? true : false;
  578. } else {
  579. $permission_to_start = true;
  580. }
  581. if ($_SERVER['REQUEST_METHOD'] != 'POST') {
  582. if ($objExercise->end_time != '0000-00-00 00:00:00') {
  583. $exercise_timeover = (($time_now - $exercise_end_time) > 0) ? true : false;
  584. } else {
  585. $exercise_timeover = false;
  586. }
  587. }
  588. if (!$permission_to_start || $exercise_timeover) {
  589. if (!api_is_allowed_to_edit(null,true)) {
  590. $message_warning = $permission_to_start ? get_lang('ReachedTimeLimit') : get_lang('ExerciseNoStartedYet');
  591. Display :: display_warning_message(sprintf($message_warning, $exercise_title, $objExercise->selectAttempts()));
  592. if ($origin != 'learnpath') {
  593. Display :: display_footer();
  594. }
  595. exit;
  596. } else {
  597. $message_warning = $permission_to_start ? get_lang('ReachedTimeLimitAdmin') : get_lang('ExerciseNoStartedAdmin');
  598. Display :: display_warning_message(sprintf($message_warning, $exercise_title, $objExercise->selectAttempts()));
  599. }
  600. }
  601. }
  602. // Blocking empty start times see BT#2800
  603. global $_custom;
  604. if (isset($_custom['exercises_hidden_when_no_start_date']) &&
  605. $_custom['exercises_hidden_when_no_start_date']
  606. ) {
  607. if (empty($objExercise->start_time) || $objExercise->start_time == '0000-00-00 00:00:00') {
  608. Display:: display_warning_message(
  609. sprintf(
  610. get_lang('ExerciseNoStartedYet'),
  611. $exercise_title,
  612. $objExercise->selectAttempts()
  613. )
  614. );
  615. if ($origin != 'learnpath') {
  616. Display :: display_footer();
  617. }
  618. }
  619. }
  620. //Timer control
  621. if ($time_control) {
  622. echo $objExercise->return_time_left_div();
  623. echo '<div style="display:none" class="warning-message" id="expired-message-id">'.get_lang('ExerciceExpiredTimeMessage').'</div>';
  624. }
  625. if (!empty($objExercise->description)) {
  626. echo "<script>
  627. $(function() {
  628. $('#description_content').accordion({
  629. changestart: function(event, ui) {
  630. //var clicked = $(this).find('.ui-state-active').attr('id');
  631. //$('#'+clicked).load('/widgets/'+clicked);
  632. $('#collapse1').html(".json_encode($objExercise->description).");
  633. }
  634. });
  635. });
  636. </script>";
  637. echo Display::generate_accordion(array(array('title' => get_lang('ExerciseDescriptionLabel'), 'content' => null)), 'jquery', 'description_content');
  638. }
  639. if ($origin != 'learnpath') {
  640. echo '<div id="highlight-plugin" class="glossary-content">';
  641. }
  642. if ($reminder == 2) {
  643. if ($debug) { error_log(' $reminder == 2'); }
  644. $data_tracking = $exercise_stat_info['data_tracking'];
  645. $data_tracking = explode(',', $data_tracking);
  646. $current_question = 1; //set by default the 1st question
  647. if (!empty($my_remind_list)) {
  648. //Checking which questions we are going to call from the remind list
  649. for ($i = 0; $i < count($data_tracking); $i++) {
  650. for($j = 0; $j < count($my_remind_list); $j++) {
  651. if (!empty($remind_question_id)) {
  652. if ($remind_question_id == $my_remind_list[$j]) {
  653. if ($remind_question_id == $data_tracking[$i]) {
  654. if (isset($my_remind_list[$j+1])) {
  655. $remind_question_id = $my_remind_list[$j+1];
  656. $current_question = $i + 1;
  657. } else {
  658. // We end the remind list we go to the exercise_reminder.php please
  659. $remind_question_id = -1;
  660. $current_question = $i + 1; // last question
  661. }
  662. break 2;
  663. }
  664. }
  665. } else {
  666. if ($my_remind_list[$j] == $data_tracking[$i]) {
  667. if (isset($my_remind_list[$j+1])) {
  668. $remind_question_id = $my_remind_list[$j+1];
  669. $current_question = $i + 1; // last question
  670. } else {
  671. // We end the remind list we go to the exercise_reminder.php please
  672. $remind_question_id = -1;
  673. $current_question = $i + 1; // last question
  674. }
  675. break 2;
  676. }
  677. }
  678. }
  679. }
  680. } else {
  681. if ($objExercise->review_answers) {
  682. if ($debug) { error_log('. redirecting to exercise_reminder.php '); }
  683. header("Location: exercise_reminder.php?$params");
  684. exit;
  685. }
  686. }
  687. }
  688. if ($objExercise->review_answers) {
  689. $script_php = 'exercise_reminder.php';
  690. } else {
  691. $script_php = 'exercise_result.php';
  692. }
  693. if (!empty($error)) {
  694. Display :: display_error_message($error, false);
  695. } else {
  696. if (!empty ($exercise_sound)) {
  697. echo "<a href=\"../document/download.php?doc_url=%2Faudio%2F" . Security::remove_XSS($exercise_sound) . "\" target=\"_blank\">", "<img src=\"../img/sound.gif\" border=\"0\" align=\"absmiddle\" alt=", get_lang('Sound') . "\" /></a>";
  698. }
  699. // Get number of hotspot questions for javascript validation
  700. $number_of_hotspot_questions = 0;
  701. $onsubmit = '';
  702. $i = 0;
  703. if (!empty($questionList)) {
  704. foreach ($questionList as $questionId) {
  705. $i++;
  706. $objQuestionTmp = Question::read($questionId);
  707. // for sequential exercises
  708. if ($objExercise->type == ONE_PER_PAGE) {
  709. // if it is not the right question, goes to the next loop iteration
  710. if ($current_question != $i) {
  711. continue;
  712. } else {
  713. if ($objQuestionTmp->selectType() == HOT_SPOT || $objQuestionTmp->selectType() == HOT_SPOT_DELINEATION) {
  714. $number_of_hotspot_questions++;
  715. }
  716. break;
  717. }
  718. } else {
  719. if ($objQuestionTmp->selectType() == HOT_SPOT || $objQuestionTmp->selectType() == HOT_SPOT_DELINEATION) {
  720. $number_of_hotspot_questions++;
  721. }
  722. }
  723. }
  724. }
  725. if ($number_of_hotspot_questions > 0) {
  726. $onsubmit = "onsubmit=\"return validateFlashVar('" . $number_of_hotspot_questions . "', '" . get_lang('HotspotValidateError1') . "', '" . get_lang('HotspotValidateError2') . "');\"";
  727. }
  728. echo '<script>
  729. $(function() {
  730. //$(".exercise_save_now_button").hide();
  731. $(".main_question").mouseover(function() {
  732. //$(this).find(".exercise_save_now_button").show();
  733. //$(this).addClass("question_highlight");
  734. });
  735. $(".main_question").mouseout(function() {
  736. //$(this).find(".exercise_save_now_button").hide();
  737. $(this).removeClass("question_highlight");
  738. });
  739. $(".no_remind_highlight").hide();
  740. // if the users validates the form using return key, prevent form action and simulates click on validation button
  741. /*$("#exercise_form").submit(function(){
  742. $(".question-validate-btn").first().trigger("click");
  743. return false;
  744. });*/
  745. });
  746. function previous_question(question_num) {
  747. url = "exercise_submit.php?'.$params.'&num="+question_num;
  748. window.location = url;
  749. }
  750. function previous_question_and_save(previous_question_id, question_id_to_save) {
  751. url = "exercise_submit.php?'.$params.'&num="+previous_question_id;
  752. //Save the current question
  753. save_now(question_id_to_save, url);
  754. }
  755. function save_question_list(question_list) {
  756. $.each(question_list, function(key, question_id) {
  757. save_now(question_id, null, false);
  758. });
  759. var url = "";
  760. if ('.$reminder.' == 1 ) {
  761. url = "exercise_reminder.php?'.$params.'&num='.$current_question.'";
  762. } else if ('.$reminder.' == 2 ) {
  763. url = "exercise_submit.php?'.$params.'&num='.$current_question.'&remind_question_id='.$remind_question_id.'&reminder=2";
  764. } else {
  765. url = "exercise_submit.php?'.$params.'&num='.$current_question.'&remind_question_id='.$remind_question_id.'";
  766. }
  767. //$("#save_for_now_"+question_id).html("'.addslashes(Display::return_icon('save.png', get_lang('Saved'), array(), ICON_SIZE_SMALL)).'");
  768. window.location = url;
  769. }
  770. function save_now(question_id, url_extra) {
  771. //1. Normal choice inputs
  772. var my_choice = $(\'*[name*="choice[\'+question_id+\']"]\').serialize();
  773. //2. Reminder checkbox
  774. var remind_list = $(\'*[name*="remind_list"]\').serialize();
  775. //3. Hotspots
  776. var hotspot = $(\'*[name*="hotspot[\'+question_id+\']"]\').serialize();
  777. // Checking FCK
  778. if (question_id) {
  779. if (CKEDITOR.instances["choice["+question_id+"]"]) {
  780. var ckContent = CKEDITOR.instances["choice["+question_id+"]"].getData();
  781. my_choice = {};
  782. my_choice["choice["+question_id+"]"] = ckContent;
  783. my_choice = $.param(my_choice);
  784. }
  785. }
  786. if ($(\'input[name="remind_list[\'+question_id+\']"]\').is(\':checked\')) {
  787. $("#question_div_"+question_id).addClass("remind_highlight");
  788. } else {
  789. $("#question_div_"+question_id).removeClass("remind_highlight");
  790. }
  791. // Only for the first time
  792. $("#save_for_now_"+question_id).html("'.addslashes(Display::return_icon('loading1.gif')).'");
  793. $.ajax({
  794. type:"post",
  795. async: false,
  796. url: "'.api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?a=save_exercise_by_now",
  797. data: "'.$params.'&type=simple&question_id="+question_id+"&"+my_choice+"&"+hotspot+"&"+remind_list,
  798. success: function(return_value) {
  799. if (return_value == "ok") {
  800. $("#save_for_now_"+question_id).html("'.addslashes(Display::return_icon('save.png', get_lang('Saved'), array(), ICON_SIZE_SMALL)).'");
  801. } else if (return_value == "error") {
  802. $("#save_for_now_"+question_id).html("'.addslashes(Display::return_icon('error.png', get_lang('Error'), array(), ICON_SIZE_SMALL)).'");
  803. } else if (return_value == "one_per_page") {
  804. var url = "";
  805. if ('.$reminder.' == 1 ) {
  806. url = "exercise_reminder.php?'.$params.'&num='.$current_question.'";
  807. } else if ('.$reminder.' == 2 ) {
  808. url = "exercise_submit.php?'.$params.'&num='.$current_question.'&remind_question_id='.$remind_question_id.'&reminder=2";
  809. } else {
  810. url = "exercise_submit.php?'.$params.'&num='.$current_question.'&remind_question_id='.$remind_question_id.'";
  811. }
  812. if (url_extra) {
  813. url = url_extra;
  814. }
  815. $("#save_for_now_"+question_id).html("'.addslashes(Display::return_icon('save.png', get_lang('Saved'), array(), ICON_SIZE_SMALL)).'");
  816. window.location = url;
  817. }
  818. },
  819. error: function() {
  820. $("#save_for_now_"+question_id).html("'.addslashes(Display::return_icon('error.png', get_lang('Error'), array(), ICON_SIZE_SMALL)).'");
  821. }
  822. });
  823. return false;
  824. }
  825. function save_now_all(validate) {
  826. // 1. Input choice.
  827. var my_choice = $(\'*[name*="choice"]\').serialize();
  828. // 2. Reminder.
  829. var remind_list = $(\'*[name*="remind_list"]\').serialize();
  830. // 3. Hotspots.
  831. var hotspot = $(\'*[name*="hotspot"]\').serialize();
  832. // Question list.
  833. var question_list = ['.implode(',', $questionList).'];
  834. var free_answers = {};
  835. $.each(question_list, function(index, my_question_id) {
  836. // Checking FCK
  837. if (my_question_id) {
  838. if (CKEDITOR.instances["choice["+my_question_id+"]"]) {
  839. var ckContent = CKEDITOR.instances["choice["+my_question_id+"]"].getData();
  840. free_answers["free_choice["+my_question_id+"]"] = ckContent;
  841. }
  842. }
  843. });
  844. free_answers = $.param(free_answers);
  845. $("#save_all_reponse").html("'.addslashes(Display::return_icon('loading1.gif')).'");
  846. $.ajax({
  847. type:"post",
  848. async: false,
  849. url: "'.api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?a=save_exercise_by_now",
  850. data: "'.$params.'&type=all&"+my_choice+"&"+hotspot+"&"+free_answers+"&"+remind_list,
  851. success: function(return_value) {
  852. if (return_value == "ok") {
  853. //$("#save_all_reponse").html("'.addslashes(Display::return_icon('accept.png')).'");
  854. if (validate == "validate") {
  855. window.location = "'.$script_php.'?'.$params.'";
  856. } else {
  857. $("#save_all_reponse").html("'.addslashes(Display::return_icon('accept.png')).'");
  858. }
  859. } else {
  860. $("#save_all_reponse").html("'.addslashes(Display::return_icon('wrong.gif')).'");
  861. }
  862. }
  863. });
  864. return false;
  865. }
  866. function validate_all() {
  867. save_now_all("validate");
  868. return false;
  869. }
  870. </script>';
  871. echo '<form id="exercise_form" method="post" action="'.api_get_self().'?'.api_get_cidreq().'&autocomplete=off&&exerciseId='.$exerciseId .'" name="frm_exercise" '.$onsubmit.'>
  872. <input type="hidden" name="formSent" value="1" />
  873. <input type="hidden" name="exerciseId" value="'.$exerciseId . '" />
  874. <input type="hidden" name="num" value="'.$current_question.'" id="num_current_id" />
  875. <input type="hidden" name="num_answer" value="'.$currentAnswer.'" id="num_current_answer_id" />
  876. <input type="hidden" name="exe_id" value="'.$exe_id . '" />
  877. <input type="hidden" name="origin" value="'.$origin . '" />
  878. <input type="hidden" name="learnpath_id" value="'.$learnpath_id . '" />
  879. <input type="hidden" name="learnpath_item_id" value="'.$learnpath_item_id . '" />
  880. <input type="hidden" name="learnpath_item_view_id" value="'.$learnpath_item_view_id . '" />';
  881. // Show list of questions
  882. $i = 1;
  883. $attempt_list = array();
  884. if (isset($exe_id)) {
  885. $attempt_list = Event::getAllExerciseEventByExeId($exe_id);
  886. }
  887. $remind_list = array();
  888. if (isset($exercise_stat_info['questions_to_check']) && !empty($exercise_stat_info['questions_to_check'])) {
  889. $remind_list = explode(',', $exercise_stat_info['questions_to_check']);
  890. }
  891. foreach ($questionList as $questionId) {
  892. // for sequential exercises
  893. if ($objExercise->type == ONE_PER_PAGE) {
  894. // if it is not the right question, goes to the next loop iteration
  895. if ($current_question != $i) {
  896. $i++;
  897. continue;
  898. } else {
  899. if ($objExercise->feedback_type != EXERCISE_FEEDBACK_TYPE_DIRECT) {
  900. // if the user has already answered this question
  901. if (isset($exerciseResult[$questionId])) {
  902. // construction of the Question object
  903. $objQuestionTmp = Question::read($questionId);
  904. $questionName = $objQuestionTmp->selectTitle();
  905. // destruction of the Question object
  906. unset ($objQuestionTmp);
  907. Display :: display_normal_message(get_lang('AlreadyAnswered'));
  908. $i++;
  909. break;
  910. }
  911. }
  912. }
  913. }
  914. $user_choice = isset($attempt_list[$questionId]) ? $attempt_list[$questionId] : null;
  915. $remind_highlight = '';
  916. //Hides questions when reviewing a ALL_ON_ONE_PAGE exercise see #4542 no_remind_highlight class hide with jquery
  917. if ($objExercise->type == ALL_ON_ONE_PAGE && isset($_GET['reminder']) && $_GET['reminder'] == 2) {
  918. $remind_highlight = 'no_remind_highlight';
  919. }
  920. $exercise_actions = '';
  921. $is_remind_on = false;
  922. $attributes = array('id' =>'remind_list['.$questionId.']');
  923. if (in_array($questionId, $remind_list)) {
  924. $is_remind_on = true;
  925. $attributes['checked'] = 1;
  926. $remind_question = true;
  927. $remind_highlight = ' remind_highlight ';
  928. }
  929. // Showing the question
  930. echo '<div id="question_div_'.$questionId.'" class="main_question '.$remind_highlight.'" >';
  931. // Shows the question and its answers
  932. ExerciseLib::showQuestion($questionId, false, $origin, $i, true, false, $user_choice, false);
  933. // Button save and continue
  934. switch ($objExercise->type) {
  935. case ONE_PER_PAGE:
  936. $exercise_actions .= $objExercise->show_button($questionId, $current_question);
  937. break;
  938. case ALL_ON_ONE_PAGE :
  939. $button = '<a href="javascript://" class="btn btn-info" onclick="save_now(\''.$questionId.'\'); ">'.get_lang('SaveForNow').'</a>';
  940. $button .= '<span id="save_for_now_'.$questionId.'"></span>&nbsp;';
  941. $exercise_actions .= Display::div($button, array('class'=>'exercise_save_now_button'));
  942. break;
  943. }
  944. // Checkbox review answers
  945. if ($objExercise->review_answers) {
  946. $remind_question_div = Display::tag(
  947. 'label',
  948. Display::input(
  949. 'checkbox',
  950. 'remind_list[' . $questionId . ']',
  951. '',
  952. $attributes
  953. ) . get_lang('ReviewQuestionLater'),
  954. array(
  955. 'class' => 'checkbox',
  956. 'for' => 'remind_list[' . $questionId . ']'
  957. )
  958. );
  959. $exercise_actions .= Display::div($remind_question_div, array('class'=>'exercise_save_now_button'));
  960. }
  961. echo Display::div($exercise_actions, array('class'=>'form-actions'));
  962. echo '</div>';
  963. $i++;
  964. // for sequential exercises
  965. if ($objExercise->type == ONE_PER_PAGE) {
  966. // quits the loop
  967. break;
  968. }
  969. }
  970. // end foreach()
  971. if ($objExercise->type == ALL_ON_ONE_PAGE) {
  972. $exercise_actions = $objExercise->show_button($questionId, $current_question);
  973. echo Display::div($exercise_actions, array('class'=>'exercise_actions'));
  974. }
  975. echo '</form>';
  976. }
  977. if ($origin != 'learnpath') {
  978. // So we are not in learnpath tool
  979. echo '</div>'; //End glossary div
  980. Display :: display_footer();
  981. } else {
  982. echo '</body></html>';
  983. }