From b09b80a479b1045f075442256e2ba5333623ea50 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Fri, 18 Apr 2014 19:34:28 -0500 Subject: [PATCH 1/5] merge --- main/newscorm/learnpathItem.class.php | 21 +-- main/newscorm/lp_ajax_save_item.php | 206 ++++++++++++++++++++++---- main/newscorm/scorm_api.php | 12 +- 3 files changed, 199 insertions(+), 40 deletions(-) diff --git a/main/newscorm/learnpathItem.class.php b/main/newscorm/learnpathItem.class.php index 5675b9049a..b36b0fb56d 100755 --- a/main/newscorm/learnpathItem.class.php +++ b/main/newscorm/learnpathItem.class.php @@ -3240,8 +3240,8 @@ class learnpathItem /** * Sets the score value. If the mastery_score is set and the score reaches * it, then set the status to 'passed'. - * @param float Score - * @return boolean True on success, false otherwise + * @param float Score + * @return boolean True on success, false otherwise */ public function set_score($score) { @@ -3252,21 +3252,23 @@ class learnpathItem } if (($this->max_score <= 0 || $score <= $this->max_score) && ($score >= $this->min_score)) { $this->current_score = $score; - $master = $this->get_mastery_score(); + $masteryScore = $this->get_mastery_score(); $current_status = $this->get_status(false); // Fixes bug when SCORM doesn't send a mastery score even if they sent a score! - if ($master == -1) { - $master = $this->max_score; + if ($masteryScore == -1) { + $masteryScore = $this->max_score; } if ($debug > 0) { - error_log('get_mastery_score: ' . $master); + error_log('get_mastery_score: ' . $masteryScore); error_log('current_status: ' . $current_status); error_log('current score : ' . $this->current_score); } - // If mastery_score is set AND the current score reaches the mastery score AND the current status is different from 'completed', then set it to 'passed'. + // If mastery_score is set AND the current score reaches the mastery + // score AND the current status is different from 'completed', then + // set it to 'passed'. /* if ($master != -1 && $this->current_score >= $master && $current_status != $this->possible_status[2]) { if ($debug > 0) error_log('Status changed to: '.$this->possible_status[3]); @@ -3307,10 +3309,9 @@ class learnpathItem /** * Sets the status for this item - * @param string $status must be one of the values defined - * in $this->possible_status + * @param string $status Status - must be one of the values defined in $this->possible_status * (this affects the status setting) - * @return boolean True on success, false on error + * @return boolean True on success, false on error */ public function set_status($status) { diff --git a/main/newscorm/lp_ajax_save_item.php b/main/newscorm/lp_ajax_save_item.php index 4a1731c61d..88b67ef37b 100755 --- a/main/newscorm/lp_ajax_save_item.php +++ b/main/newscorm/lp_ajax_save_item.php @@ -27,28 +27,31 @@ require_once 'aiccItem.class.php'; /** * Writes an item's new values into the database and returns the operation result - * @param integer Learnpath ID - * @param integer User ID - * @param integer View ID - * @param integer Item ID - * @param double Current score - * @param double Maximum score - * @param double Minimum score - * @param string Lesson status - * @param string Session time - * @param string Suspend data - * @param string Lesson location - * @param array Interactions array - * @param string Core exit SCORM string + * @param int $lp_id Learnpath ID + * @param int $user_id User ID + * @param int $view_id View ID + * @param int $item_id Item ID + * @param float $score Current score + * @param float $max Maximum score + * @param float $min Minimum score + * @param string $status Lesson status + * @param int $time Session time + * @param string $suspend Suspend data + * @param string $location Lesson location + * @param array $interactions Interactions array + * @param string $core_exit Core exit SCORM string + * @param int $lmsFinish Whether the call was issued from SCORM's LMSFinish() + * @param int $userNavigatesAway Whether the user is moving to another item + * @return bool|null|string The resulting JS string */ function save_item( $lp_id, $user_id, $view_id, $item_id, - $score = -1, - $max = -1, - $min = -1, + $score = -1.0, + $max = -1.0, + $min = -1.0, $status = '', $time = 0, $suspend = '', @@ -56,9 +59,13 @@ function save_item( $interactions = array(), $core_exit = 'none', $sessionId = null, - $courseId = null + $courseId = null, + $lmsFinish = 0, + $userNavigatesAway = 0, + $statusSignalReceived = 0 ) { - global $debug; + //global $debug; + $debug = 0; $return = null; if ($debug > 0) { @@ -66,6 +73,7 @@ function save_item( error_log("item_id: $item_id"); error_log("lp_id: $lp_id - user_id: - $user_id - view_id: $view_id - item_id: $item_id"); error_log("score: $score - max:$max - min: $min - status:$status - time:$time - suspend: $suspend - location: $location - core_exit: $core_exit"); + error_log("finish: $lmsFinish - navigatesAway: $userNavigatesAway"); } $mylp = learnpath::getLpFromSession(api_get_course_id(), $lp_id, $user_id); @@ -87,7 +95,6 @@ function save_item( if ($debug > 0) { error_log("item #$item_id not found in the items array: ".print_r($mylp->items, 1)); } - return false; } @@ -100,7 +107,6 @@ function save_item( if ($debug) { error_log("prereq_check: ".intval($prereq_check)); } - return $return; } else { if ($debug > 1) { error_log('Prerequisites are OK'); } @@ -116,7 +122,7 @@ function save_item( if ($debug > 1) { error_log("Setting min_score: $min"); } } - // set_score function already saves the status + // set_score function used to save the status, but this is not the case anymore if (isset($score) && $score != -1) { if ($debug > 1) { error_log('Calling set_score('.$score.')', 0); } if ($debug > 1) { error_log('set_score changes the status to failed/passed if mastery score is provided', 0); } @@ -128,34 +134,180 @@ function save_item( if ($debug > 1) { error_log("Score not updated"); } } + $statusIsSet = false; // Default behaviour. if (isset($status) && $status != '' && $status != 'undefined') { if ($debug > 1) { error_log('Calling set_status('.$status.')', 0); } $mylpi->set_status($status); - + $statusIsSet = true; if ($debug > 1) { error_log('Done calling set_status: checking from memory: '.$mylpi->get_status(false), 0); } } else { if ($debug > 1) { error_log("Status not updated"); } } - // Hack to set status to completed for hotpotatoes if score > 80%. $my_type = $mylpi->get_type(); - + // Set status to completed for hotpotatoes if score > 80%. if ($my_type == 'hotpotatoes') { if ((empty($status) || $status == 'undefined' || $status == 'not attempted') && $max > 0) { if (($score/$max) > 0.8) { $mystatus = 'completed'; if ($debug > 1) { error_log('Calling set_status('.$mystatus.') for hotpotatoes', 0); } $mylpi->set_status($mystatus); + $statusIsSet = true; if ($debug > 1) { error_log('Done calling set_status for hotpotatoes - now '.$mylpi->get_status(false), 0); } } } elseif ($status == 'completed' && $max > 0 && ($score/$max) < 0.8) { $mystatus = 'failed'; if ($debug > 1) { error_log('Calling set_status('.$mystatus.') for hotpotatoes', 0); } $mylpi->set_status($mystatus); + $statusIsSet = true; if ($debug > 1) { error_log('Done calling set_status for hotpotatoes - now '.$mylpi->get_status(false), 0); } } + } elseif ($my_type == 'sco') { + /* + * This is a specific implementation for SCORM 1.2, matching page 26 of SCORM 1.2's RTE + * "Normally the SCO determines its own status and passes it to the LMS. + * 1) If cmi.core.credit is set to “credit” and there is a mastery + * score in the manifest (adlcp:masteryscore), the LMS can change + * the status to either passed or failed depending on the + * student's score compared to the mastery score. + * 2) If there is no mastery score in the manifest + * (adlcp:masteryscore), the LMS cannot override SCO + * determined status. + * 3) If the student is taking the SCO for no-credit, there is no + * change to the lesson_status, with one exception. If the + * lesson_mode is "browse", the lesson_status may change to + * "browsed" even if the cmi.core.credit is set to no-credit. + * " + * Additionally, the LMS behaviour should be: + * If a SCO sets the cmi.core.lesson_status then there is no problem. + * However, the SCORM does not force the SCO to set the cmi.core.lesson_status. + * There is some additional requirements that must be adhered to + * successfully handle these cases: + * Upon initial launch + * the LMS should set the cmi.core.lesson_status to “not attempted”. + * Upon receiving the LMSFinish() call or the user navigates away, + * the LMS should set the cmi.core.lesson_status for the SCO to “completed”. + * After setting the cmi.core.lesson_status to “completed”, + * the LMS should now check to see if a Mastery Score has been + * specified in the cmi.student_data.mastery_score, if supported, + * or the manifest that the SCO is a member of. + * If a Mastery Score is provided and the SCO did set the + * cmi.core.score.raw, the LMS shall compare the cmi.core.score.raw + * to the Mastery Score and set the cmi.core.lesson_status to + * either “passed” or “failed”. If no Mastery Score is provided, + * the LMS will leave the cmi.core.lesson_status as “completed” + */ + $masteryScore = $mylpi->get_mastery_score(); + if ($masteryScore == -1 or empty($masteryScore)) { + $masteryScore = false; + } + $credit = $mylpi->get_credit(); + + /** + * 1) If cmi.core.credit is set to “credit” and there is a mastery + * score in the manifest (adlcp:masteryscore), the LMS can change + * the status to either passed or failed depending on the + * student's score compared to the mastery score. + */ + if ($credit == 'credit' && $masteryScore && (isset($score) && $score != -1) && !$statusIsSet && !$statusSignalReceived) { + if ($score >= $masteryScore) { + $mylpi->set_status('passed'); + } else { + $mylpi->set_status('failed'); + } + $statusIsSet = true; + } + /** + * 2) If there is no mastery score in the manifest + * (adlcp:masteryscore), the LMS cannot override SCO + * determined status. + */ + if (!$statusIsSet && !$masteryScore && !$statusSignalReceived) { + if (!empty($status)) { + $mylpi->set_status($status); + $statusIsSet = true; + } + //if no status was set directly, we keep the previous one + } + /** + * 3) If the student is taking the SCO for no-credit, there is no + * change to the lesson_status, with one exception. If the + * lesson_mode is "browse", the lesson_status may change to + * "browsed" even if the cmi.core.credit is set to no-credit. + */ + if (!$statusIsSet && $credit == 'no-credit' && !$statusSignalReceived) { + $mode = $mylpi->get_lesson_mode(); + if ($mode == 'browse' && $status == 'browsed') { + $mylpi->set_status($status); + $statusIsSet = true; + } + //if no status was set directly, we keep the previous one + } + /** + * If a SCO sets the cmi.core.lesson_status then there is no problem. + * However, the SCORM does not force the SCO to set the + * cmi.core.lesson_status. There is some additional requirements + * that must be adhered to successfully handle these cases: + */ + if (!$statusIsSet && empty($status) && !$statusSignalReceived) { + /** + * Upon initial launch the LMS should set the + * cmi.core.lesson_status to “not attempted”. + */ + // this case should be handled by LMSInitialize() and xajax_switch_item() + /** + * Upon receiving the LMSFinish() call or the user navigates + * away, the LMS should set the cmi.core.lesson_status for the + * SCO to “completed”. + */ + if ($lmsFinish or $userNavigatesAway) { + $myStatus = 'completed'; + /** + * After setting the cmi.core.lesson_status to “completed”, + * the LMS should now check to see if a Mastery Score has been + * specified in the cmi.student_data.mastery_score, if supported, + * or the manifest that the SCO is a member of. + * If a Mastery Score is provided and the SCO did set the + * cmi.core.score.raw, the LMS shall compare the cmi.core.score.raw + * to the Mastery Score and set the cmi.core.lesson_status to + * either “passed” or “failed”. If no Mastery Score is provided, + * the LMS will leave the cmi.core.lesson_status as “completed” + */ + if ($masteryScore && (isset($score) && $score != -1)) { + if ($score >= $masteryScore) { + $myStatus = 'passed'; + } else { + $myStatus = 'failed'; + } + } + $mylpi->set_status($myStatus); + $statusIsSet = true; + } + } + // End of type=='sco' + } + + // If no previous condition changed the SCO status, proceed with a + // generic behaviour + if (!$statusIsSet && !$statusSignalReceived) { + // Default behaviour + if (isset($status) && $status != '' && $status != 'undefined') { + if ($debug > 1) { + error_log('Calling set_status('.$status.')', 0); + } + + $mylpi->set_status($status); + + if ($debug > 1) { + error_log('Done calling set_status: checking from memory: '.$mylpi->get_status(false), 0); + } + } else { + if ($debug > 1) { + error_log("Status not updated"); + } + } } if (isset($time) && $time != '' && $time != 'undefined') { @@ -303,7 +455,9 @@ echo save_item( (!empty($_REQUEST['loc'])?$_REQUEST['loc']:null), $interactions, (!empty($_REQUEST['core_exit'])?$_REQUEST['core_exit']:''), - '', (!empty($_REQUEST['session_id'])?$_REQUEST['session_id']:''), - (!empty($_REQUEST['course_id'])?$_REQUEST['course_id']:'') + (!empty($_REQUEST['course_id'])?$_REQUEST['course_id']:''), + (empty($_REQUEST['finish'])?0:1), + (empty($_REQUEST['userNavigatesAway'])?0:1), + (empty($_REQUEST['statusSignalReceived'])?0:1) ); diff --git a/main/newscorm/scorm_api.php b/main/newscorm/scorm_api.php index 9a49c83c39..09fe9c2495 100755 --- a/main/newscorm/scorm_api.php +++ b/main/newscorm/scorm_api.php @@ -235,7 +235,7 @@ if (olms.lms_lp_type == 1 || olms.lms_item_type == 'asset' || olms.lms_item_type function LMSInitialize() { /* load info for this new item by calling the js_api_refresh command in * the message frame. The message frame will update the JS variables by - * itself, in JS, by doing things like top.lesson_status = 'not attempted' + * itself, in JS, by doing things like top.lescsson_status = 'not attempted' * and that kind of stuff, so when the content loads in the content frame * it will have all the correct variables set */ @@ -549,7 +549,7 @@ function LMSGetValue(param) { } else if(param == 'cmi.interactions._children'){ // ---- cmi.interactions._children result = 'id,time,type,correct_responses,weighting,student_response,result,latency'; - } else { + } else{ // ---- anything else // Invalid argument error olms.G_LastError = G_InvalidArgumentError ; @@ -1543,13 +1543,17 @@ function xajax_save_item( * @param int ID of the user * @param int ID of the view * @param int ID of the item + * @param bool 1 if this call comes from a "LMSFinish()" call, 0 or nothing otherwise * @return void * @uses olms.updatable_vars_list * @uses lp_ajax_save_item.php through an AJAX call */ -function xajax_save_item_scorm(lms_lp_id, lms_user_id, lms_view_id, lms_item_id) { +function xajax_save_item_scorm(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, finish) { + if (typeof(finish) == 'undefined') { + finish = 0; + } var is_interactions='false'; - var params = 'lid='+lms_lp_id+'&uid='+lms_user_id+'&vid='+lms_view_id+'&iid='+lms_item_id; + var params = 'lid='+lms_lp_id+'&uid='+lms_user_id+'&vid='+lms_view_id+'&iid='+lms_item_id+'&finish='+finish; var my_scorm_values = new Array(); my_scorm_values = process_scorm_values(); From 1d68db47b2dcb00a36e5b2d90e5be3cd6494cd56 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Fri, 7 Nov 2014 17:45:15 -0500 Subject: [PATCH 2/5] Support Opale/Scenarii by adding variable to better support SCORM 1.2 by watching over the definition, by the SCO, of the lesson_status and the call to LMSFinish() or the move to another element - refs #398 refs BT#8897 --- main/newscorm/lp_ajax_initialize.php | 3 +- main/newscorm/lp_ajax_switch_item.php | 3 +- main/newscorm/scorm_api.php | 142 ++++++++++++++++++-------- 3 files changed, 103 insertions(+), 45 deletions(-) diff --git a/main/newscorm/lp_ajax_initialize.php b/main/newscorm/lp_ajax_initialize.php index 1a3e55fa7f..a2cee911b4 100755 --- a/main/newscorm/lp_ajax_initialize.php +++ b/main/newscorm/lp_ajax_initialize.php @@ -129,7 +129,8 @@ function initialize_item($lp_id, $user_id, $view_id, $next_item) { //"olms.item_objectives = new Array();" . "olms.item_objectives = ".$myobjectives.";" . "olms.G_lastError = 0;" . - "olms.G_LastErrorMessage = 'No error';" ; + "olms.G_LastErrorMessage = 'No error';". + "olms.finishSignalReceived = 0;"; /* * and re-initialise the rest (proper to the LMS) * -lms_lp_id diff --git a/main/newscorm/lp_ajax_switch_item.php b/main/newscorm/lp_ajax_switch_item.php index 7f628678e0..6107c56995 100755 --- a/main/newscorm/lp_ajax_switch_item.php +++ b/main/newscorm/lp_ajax_switch_item.php @@ -171,7 +171,8 @@ function switch_item_details($lp_id, $user_id, $view_id, $current_item, $next_it "olms.interactions = new Array(".$myistring.");". "olms.item_objectives = new Array();". "olms.G_lastError = 0;". - "olms.G_LastErrorMessage = 'No error';"; + "olms.G_LastErrorMessage = 'No error';". + "olms.finishSignalReceived = 0;"; /* * and re-initialise the rest * -lms_lp_id diff --git a/main/newscorm/scorm_api.php b/main/newscorm/scorm_api.php index 09fe9c2495..60577c1767 100755 --- a/main/newscorm/scorm_api.php +++ b/main/newscorm/scorm_api.php @@ -2,7 +2,7 @@ /* For licensing terms, see /license.txt */ /** - * API event handler functions for Scorm 1.1 and 1.2 and 1.3 + * API event handler functions for Scorm 1.1 and 1.2 and 1.3 (latter not fully supported) * This script is divided into three sections. * The first section (below) is the initialisation part. * The second section is the SCORM object part @@ -10,7 +10,7 @@ * and frames refresh * @author Denes Nagy (original author - 2003-2004) * @author Yannick Warnier (extended and maintained - 2005-2014) - * @version v 1.1 + * @version v 1.2 * @access public * @package chamilo.learnpath.scorm */ @@ -140,6 +140,10 @@ olms.variable_to_send=new Array(); // temporary list of variables (gets set to true when set through LMSSetValue) olms.updatable_vars_list = new Array(); +// marker of whether the LMSFinish() function was called, which is important for SCORM behaviour +olms.finishSignalReceived = 0; +// marker to remember if the SCO has calles a "set" on lesson_status +olms.statusSignalReceived = 0; // Strictly scorm variables olms.score=get_score();?>; @@ -182,6 +186,7 @@ olms.lms_item_core_exit = 'get_core_exit();?>'; olms.lms_course_id = 'get_course_int_id(); ?>'; olms.lms_session_id = ''; olms.lms_course_code = 'getCourseCode(); ?>'; +olms.lms_course_id = 'get_course_int_id(); ?>'; get_items_details_as_js('olms.lms_item_types');?> olms.asset_timer = 0; @@ -198,27 +203,33 @@ addEvent(window, 'load', addListeners, false); // Initialize stuff when the page is loaded $(document).ready(function() { - logit_lms('document.ready start'); + logit_lms('document.ready event starts'); + logit_lms('These logs are generated by the main/newscorm/scorm_api.php JS ' + + 'library when the admin has clicked on the debug icon in the ' + + 'learning paths list: ' + + 'lines prefixed with "LMS:" refer to actions taken on the LMS side, ' + + 'while lines prefixed with "SCORM:" refer to actions taken to match ' + + 'the SCORM standard at the JS level.', 3); + logit_scorm('LMSSetValue calls are shown in red for better visibility.', 0); + logit_scorm('Other SCORM calls are shown in orange.', 1); + logit_lms('To add new messages to these logs, use logit_lms() or logit_scorm().'); olms.info_lms_item[0] = 'get_id();?>'; olms.info_lms_item[1] = 'get_id();?>'; $("#content_id").load(function() { - logit_lms('#content_id on load executing: '); + logit_lms('#content_id load event starts'); olms.info_lms_item[0] = olms.info_lms_item[1]; + // Only trigger the LMSInitialize automatically if not SCO if (olms.lms_item_types['i'+olms.info_lms_item[1]] != 'sco') { LMSInitialize(); } else { - logit_lms('Cant execute LMSInitialize() (type is sco)',2); + logit_lms('Content type is SCO and is responsible to launch LMSInitialize() on its own - Skipping',2); } }); }); -//Seems that this objs are not used -//oXAJAX = new XAJAXobject(); -//oxajax = new XAJAXobject(); - // This code was moved inside LMSInitialize() if (olms.lms_lp_type == 1 || olms.lms_item_type == 'asset' || olms.lms_item_type == 'document') { xajax_start_timer(); @@ -235,7 +246,7 @@ if (olms.lms_lp_type == 1 || olms.lms_item_type == 'asset' || olms.lms_item_type function LMSInitialize() { /* load info for this new item by calling the js_api_refresh command in * the message frame. The message frame will update the JS variables by - * itself, in JS, by doing things like top.lescsson_status = 'not attempted' + * itself, in JS, by doing things like top.lesson_status = 'not attempted' * and that kind of stuff, so when the content loads in the content frame * it will have all the correct variables set */ @@ -246,10 +257,12 @@ function LMSInitialize() { olms.G_LastErrorMessage = 'No error'; olms.lms_initialized = 0; + olms.finishSignalReceived = 0; + olms.statusSignalReceived = 0; // if there are more parameters than "" if (arguments.length > 1) { - olms.G_LastError = G_InvalidArgumentError; - olms.G_LastErrorMessage = G_InvalidArgumentErrorMessage; + olms.G_LastError = G_InvalidArgumentError; + olms.G_LastErrorMessage = G_InvalidArgumentErrorMessage; logit_scorm('Error '+ G_InvalidArgumentError + G_InvalidArgumentErrorMessage, 0); return('false'); } else { @@ -294,11 +307,13 @@ function LMSInitialize() { + '\nlms_lp_id : '+ olms.lms_lp_id + '\nlms_user_id : '+ olms.lms_user_id + '\nlms_view_id : '+ olms.lms_view_id + + '\nfinishSignalReceived : '+ olms.finishSignalReceived + + '\nstatusSignalReceived : '+ olms.statusSignalReceived ; logit_scorm('LMSInitialize() with params: '+log); - if (olms.lms_lp_type == 1 || olms.lms_item_type == 'asset' || olms.lms_item_type == 'document') { + if (olms.lms_lp_type == 1 || olms.lms_item_type == 'asset' || olms.lms_item_type == 'document') { xajax_start_timer(); } @@ -312,7 +327,7 @@ function LMSInitialize() { } else { attach_glossary_into_scorm('manual'); } - + attach_glossary_into_scorm('automatic'); return('true'); @@ -582,6 +597,7 @@ function LMSSetValue(param, val) { olms.commit = true; //value has changed, need to re-commit olms.G_LastError = G_NoError ; olms.G_LastErrorMessage = 'No error'; + return_value = 'false'; if ( param == "cmi.core.score.raw" ) { @@ -603,6 +619,7 @@ function LMSSetValue(param, val) { } else if ( param == "cmi.core.lesson_status" ) { olms.lesson_status = val; olms.updatable_vars_list['cmi.core.lesson_status'] = true; + olms.statusSignalReceived = 1; return_value='true'; } else if ( param == "cmi.completion_status" ) { olms.lesson_status = val; @@ -693,8 +710,8 @@ function LMSSetValue(param, val) { return_value='true'; break; case "correct_responses": - //do nothing yet - olms.interactions[elem_id][4].push(val); + // Add at the end of the array + olms.interactions[elem_id][4][olms.interactions[elem_id][4].length] = val; logit_scorm("Interaction "+elem_id+"'s correct_responses not updated",2); return_value='true'; break; @@ -800,12 +817,10 @@ function SetValue(param, val) { /** * Saves the current data from JS memory to the LMS database - * @param string The origin of the call to save the data ('commit','finish', 'unload' or 'terminate') - * @note origin actually seems deprecated now */ -function savedata(origin) { +function savedata() { //origin can be 'commit', 'finish' or 'terminate' (depending on the calling function) - logit_lms('function savedata() with origin: ' + origin, 3); + logit_lms('function savedata()', 3); //Status is NOT modified here see the lp_ajax_save_item.php file @@ -830,11 +845,27 @@ function savedata(origin) { //xajax_save_item_scorm(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, old_item_id); //Modified version - xajax_save_item_scorm(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, item_to_save); + xajax_save_item_scorm( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + item_to_save, + olms.session_id, + olms.course_id, + olms.finishSignalReceived, + olms.userNavigatesAway, + olms.statusSignalReceived + ); olms.info_lms_item[1] = olms.lms_item_id; if (olms.item_objectives.length > 0) { - xajax_save_objectives(olms.lms_lp_id,olms.lms_user_id,olms.lms_view_id, old_item_id, olms.item_objectives); + xajax_save_objectives( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + old_item_id, + olms.item_objectives + ); } olms.execute_stats = false; //clean array @@ -854,10 +885,11 @@ function LMSCommit(val) { olms.G_LastError = G_NoError ; olms.G_LastErrorMessage = 'No error'; - savedata('commit'); + savedata(); reinit_updatable_vars_list(); - //commit = 'false' ; //now changes have been commited, no need to update until next SetValue() + //now changes have been commited, no need to update until next SetValue() + //commit = 'false' ; return('true'); } @@ -880,17 +912,16 @@ function Commit(val) { function LMSFinish(val) { olms.G_LastError = G_NoError ; olms.G_LastErrorMessage = 'No error'; + olms.finishSignalReceived = 1; // if olms.commit == false, then the SCORM didn't ask for a commit, so we // should at least report that if ( !olms.commit ) { logit_scorm('LMSFinish() (no LMSCommit())',1); } - //if ( olms.commit ) { - logit_scorm('LMSFinish() called',1); - savedata('finish'); - olms.commit = false; - //} + logit_scorm('LMSFinish() called',1); + savedata(); + olms.commit = false; //reinit the list of modified variables reinit_updatable_vars_list(); @@ -971,7 +1002,7 @@ function Terminate() { olms.G_LastError = G_NoError ; olms.G_LastErrorMessage = 'No error'; olms.commit = true; - savedata('terminate'); + savedata(); return ('true'); } } @@ -1064,7 +1095,7 @@ function lms_save_asset() { if (olms.lms_lp_type == 1 || olms.lms_item_type == 'asset' || olms.lms_item_type == 'document') { logit_lms('lms_save_asset'); logit_lms('execute_stats :'+ olms.execute_stats); - xajax_save_item(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.score, olms.max, olms.min, olms.lesson_status, olms.session_time, olms.suspend_data, olms.lesson_location, olms.interactions, olms.lms_item_core_exit, olms.lms_item_type); + xajax_save_item(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.score, olms.max, olms.min, olms.lesson_status, olms.session_time, olms.suspend_data, olms.lesson_location, olms.interactions, olms.lms_item_core_exit, olms.lms_item_type, olms.session_id, olms.course_id); if (olms.item_objectives.length>0) { xajax_save_objectives(olms.lms_lp_id,olms.lms_user_id,olms.lms_view_id,olms.lms_item_id,olms.item_objectives); } @@ -1344,7 +1375,7 @@ function switch_item(current_item, next_item){ } else { logit_lms('Case 2 - current != sco but next == sco'); } - xajax_save_item(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.score, olms.max, olms.min, olms.lesson_status, olms.asset_timer, olms.suspend_data, olms.lesson_location,olms.interactions, olms.lms_item_core_exit, orig_item_type); + xajax_save_item(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.score, olms.max, olms.min, olms.lesson_status, olms.asset_timer, olms.suspend_data, olms.lesson_location,olms.interactions, olms.lms_item_core_exit, olms.session_id, olms.course_id, olms.finishSignalReceived, 1, olms.statusSignalReceived); xajax_switch_item_details(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, next_item); } else { if (next_item_type != 'sco') { @@ -1352,7 +1383,7 @@ function switch_item(current_item, next_item){ } else { logit_lms('Case 4 - current == sco and next == sco'); } - xajax_save_item_scorm(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id); + xajax_save_item_scorm(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.session_id, olms.course_id, olms.finishSignalReceived, 1, olms.statusSignalReceived); reinit_updatable_vars_list(); xajax_switch_item_toc(olms.lms_lp_id,olms.lms_user_id,olms.lms_view_id,olms.lms_item_id,next_item); @@ -1375,18 +1406,18 @@ function switch_item(current_item, next_item){ * because another onunload event can be triggered by the SCO itself, * which can set, for example, the status to incomplete while the * status has already been set to "completed" by the hand-made - * savedata(unload) (and then the status cannot be "incompleted" + * savedata() (and then the status cannot be "incompleted" * anymore) */ /* if (olms.lms_item_type=='sco' && olms.lesson_status != 'completed' && olms.lesson_status != 'passed' && olms.lesson_status != 'browsed' && olms.lesson_status != 'incomplete' && olms.lesson_status != 'failed') { - // savedata('finish') treats the special condition and saves the - // new status to the database, so switch_item_details() enjoys the - // new status - savedata('finish'); + // savedata() with olms.finishSignalReceived == 1 treats the special + // condition and saves the new status to the database, so + // switch_item_details() enjoys the new status + savedata(); } - xajax_save_item(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.score, olms.max, olms.min, olms.lesson_status, olms.session_time, olms.suspend_data, olms.lesson_location,olms.interactions, olms.lms_item_core_exit, olms.lms_item_type); + xajax_save_item(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.score, olms.max, olms.min, olms.lesson_status, olms.session_time, olms.suspend_data, olms.lesson_location,olms.interactions, olms.lms_item_core_exit, olms.session_id, olms.course_id, olms.finishSignalReceived, 1, olms.statusSignalReceived); */ olms.execute_stats = false; @@ -1513,7 +1544,10 @@ function xajax_save_item( lms_item_core_exit, item_type, session_id, - course_id) { + course_id, + finishSignalReceived = 0, + userNavigatesAway = 0, + statusSignalReceived = 0) { var params = ''; params += 'lid='+lms_lp_id+'&uid='+lms_user_id+'&vid='+lms_view_id; params += '&iid='+lms_item_id+'&s='+score+'&max='+max+'&min='+min; @@ -1522,6 +1556,10 @@ function xajax_save_item( params += '&core_exit='+lms_item_core_exit; params += '&session_id='+session_id; params += '&course_id='+course_id; + params += '&finishSignalReceived='+finishSignalReceived; + params += '&userNavigatesAway='+userNavigatesAway; + params += '&statusSignalReceived='+statusSignalReceived; + //console.info(session_time); if (olms.lms_lp_type == 1 || item_type == 'document') { logit_lms('xajax_save_item with params:' + params,3); @@ -1548,12 +1586,30 @@ function xajax_save_item( * @uses olms.updatable_vars_list * @uses lp_ajax_save_item.php through an AJAX call */ -function xajax_save_item_scorm(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, finish) { +function xajax_save_item_scorm( + lms_lp_id, + lms_user_id, + lms_view_id, + lms_item_id, + session_id, + course_id, + finishSignalReceived = 0, + userNavigatesAway = 0, + statusSignalReceived = 0 + ) +{ if (typeof(finish) == 'undefined') { finish = 0; } var is_interactions='false'; - var params = 'lid='+lms_lp_id+'&uid='+lms_user_id+'&vid='+lms_view_id+'&iid='+lms_item_id+'&finish='+finish; + var params = 'lid='+lms_lp_id+'&uid='+lms_user_id+'&vid='+lms_view_id+'&iid='+lms_item_id; + // The missing arguments will be ignored by lp_ajax_save_item.php + //params += '&s=&max=&min=&status=&t=&suspend=&loc=&interact=&core_exit='; + params += '&session_id='+session_id; + params += '&course_id='+course_id; + params += '&finishSignalReceived='+finishSignalReceived; + params += '&userNavigatesAway='+userNavigatesAway; + params += '&statusSignalReceived='+statusSignalReceived; var my_scorm_values = new Array(); my_scorm_values = process_scorm_values(); @@ -1628,7 +1684,7 @@ function xajax_save_item_scorm(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, /** * Starts the timer with the server clock time. * @return void - * @todo check the timer stuff really works + * @todo check the timer stuff really works and rename function to startTimer() * @uses lp_ajax_start_timer.php */ function xajax_start_timer() { From b3862ee36fd916c89ae662f7f566a2e0ddd718c2 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Fri, 7 Nov 2014 18:36:24 -0500 Subject: [PATCH 3/5] Add scorm_failed style and fix section style - refs #398 --- main/css/chamilo/scorm.css | 3 +++ main/newscorm/learnpath.class.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/main/css/chamilo/scorm.css b/main/css/chamilo/scorm.css index d7ed3491af..4e6ab78b66 100755 --- a/main/css/chamilo/scorm.css +++ b/main/css/chamilo/scorm.css @@ -393,6 +393,9 @@ .scorm_item_section.scorm_item_normal.scorm_not_attempted { background-color: #333; } +.scorm_item_section.scorm_item_normal.scorm_failed { + background-color: #333; +} #learning_path_main #control { background-image: none; diff --git a/main/newscorm/learnpath.class.php b/main/newscorm/learnpath.class.php index 77ab818df9..89390b0870 100755 --- a/main/newscorm/learnpath.class.php +++ b/main/newscorm/learnpath.class.php @@ -3129,7 +3129,7 @@ class learnpath $class_name = array ( 'not attempted' => 'scorm_not_attempted', 'incomplete' => 'scorm_not_attempted', - 'failed' => 'scorm_not_attempted', + 'failed' => 'scorm_failed', 'completed' => 'scorm_completed', 'passed' => 'scorm_completed', 'succeeded' => 'scorm_completed', @@ -3150,7 +3150,7 @@ class learnpath } if ($item['id'] == $this->current) { $scorm_color_background .= ' scorm_item_highlight '; - } else { + } elseif (!in_array($item['type'], $dirTypes)) { $scorm_color_background .= ' scorm_item_normal '; } From 83244de97c390d09c861f4da61553f5afb4ef6b6 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Fri, 7 Nov 2014 18:54:15 -0500 Subject: [PATCH 4/5] Minor - code style and local variables renaming - refs #398 refs BT#8897 --- main/newscorm/lp_ajax_save_item.php | 237 +++++++++++++++++----------- main/newscorm/scorm_api.php | 155 ++++++++++++++---- 2 files changed, 272 insertions(+), 120 deletions(-) diff --git a/main/newscorm/lp_ajax_save_item.php b/main/newscorm/lp_ajax_save_item.php index 88b67ef37b..2af7d27216 100755 --- a/main/newscorm/lp_ajax_save_item.php +++ b/main/newscorm/lp_ajax_save_item.php @@ -2,9 +2,8 @@ /* For licensing terms, see /license.txt */ /** - * This script contains the server part of the xajax interaction process. The client part is located + * This script contains the server part of the AJAX interaction process. The client part is located * in lp_api.php or other api's. - * This is a first attempt at using xajax and AJAX in general, so the code might be a bit unsettling. * @package chamilo.learnpath * @author Yannick Warnier */ @@ -40,8 +39,11 @@ require_once 'aiccItem.class.php'; * @param string $location Lesson location * @param array $interactions Interactions array * @param string $core_exit Core exit SCORM string + * @param int $sessionId Session ID + * @param int $courseId Course ID * @param int $lmsFinish Whether the call was issued from SCORM's LMSFinish() * @param int $userNavigatesAway Whether the user is moving to another item + * @param int $statusSignalReceived Whether the SCO called SetValue(lesson_status) * @return bool|null|string The resulting JS string */ function save_item( @@ -72,13 +74,14 @@ function save_item( error_log('lp_ajax_save_item.php : save_item() params: '); error_log("item_id: $item_id"); error_log("lp_id: $lp_id - user_id: - $user_id - view_id: $view_id - item_id: $item_id"); - error_log("score: $score - max:$max - min: $min - status:$status - time:$time - suspend: $suspend - location: $location - core_exit: $core_exit"); + error_log("score: $score - max:$max - min: $min - status:$status"); + error_log("time:$time - suspend: $suspend - location: $location - core_exit: $core_exit"); error_log("finish: $lmsFinish - navigatesAway: $userNavigatesAway"); } - $mylp = learnpath::getLpFromSession(api_get_course_id(), $lp_id, $user_id); + $myLP = learnpath::getLpFromSession(api_get_course_id(), $lp_id, $user_id); - if (!is_a($mylp, 'learnpath')) { + if (!is_a($myLP, 'learnpath')) { if ($debug) { error_log("mylp variable is not an learnpath object"); } @@ -86,83 +89,109 @@ function save_item( return null; } - $prereq_check = $mylp->prerequisites_match($item_id); + $prerequisitesCheck = $myLP->prerequisites_match($item_id); - /** @var learnpathItem $mylpi */ - $mylpi = $mylp->items[$item_id]; + /** @var learnpathItem $myLPI */ + $myLPI = $myLP->items[$item_id]; - if (empty($mylpi)) { + if (empty($myLPI)) { if ($debug > 0) { - error_log("item #$item_id not found in the items array: ".print_r($mylp->items, 1)); + error_log("item #$item_id not found in the items array: ".print_r($myLP->items, 1)); } return false; } // This functions sets the $this->db_item_view_id variable needed in get_status() see BT#5069 - $mylpi->set_lp_view($view_id); + $myLPI->set_lp_view($view_id); // Launch the prerequisites check and set error if needed - if ($prereq_check !== true) { + if ($prerequisitesCheck !== true) { // If prerequisites were not matched, don't update any item info if ($debug) { - error_log("prereq_check: ".intval($prereq_check)); + error_log("prereq_check: ".intval($prerequisitesCheck)); } return $return; } else { - if ($debug > 1) { error_log('Prerequisites are OK'); } + if ($debug > 1) { + error_log('Prerequisites are OK'); + } if (isset($max) && $max != -1) { - $mylpi->max_score = $max; - $mylpi->set_max_score($max); - if ($debug > 1) { error_log("Setting max_score: $max"); } + $myLPI->max_score = $max; + $myLPI->set_max_score($max); + if ($debug > 1) { + error_log("Setting max_score: $max"); + } } if (isset($min) && $min != -1 && $min != 'undefined') { - $mylpi->min_score = $min; - if ($debug > 1) { error_log("Setting min_score: $min"); } + $myLPI->min_score = $min; + if ($debug > 1) { + error_log("Setting min_score: $min"); + } } // set_score function used to save the status, but this is not the case anymore if (isset($score) && $score != -1) { - if ($debug > 1) { error_log('Calling set_score('.$score.')', 0); } - if ($debug > 1) { error_log('set_score changes the status to failed/passed if mastery score is provided', 0); } + if ($debug > 1) { + error_log('Calling set_score('.$score.')', 0); + error_log('set_score changes the status to failed/passed if mastery score is provided', 0); + } - $mylpi->set_score($score); + $myLPI->set_score($score); - if ($debug > 1) { error_log('Done calling set_score '.$mylpi->get_score(), 0); } + if ($debug > 1) { + error_log('Done calling set_score '.$myLPI->get_score(), 0); + } } else { - if ($debug > 1) { error_log("Score not updated"); } + if ($debug > 1) { + error_log("Score not updated"); + } } $statusIsSet = false; // Default behaviour. if (isset($status) && $status != '' && $status != 'undefined') { - if ($debug > 1) { error_log('Calling set_status('.$status.')', 0); } + if ($debug > 1) { + error_log('Calling set_status('.$status.')', 0); + } - $mylpi->set_status($status); + $myLPI->set_status($status); $statusIsSet = true; - if ($debug > 1) { error_log('Done calling set_status: checking from memory: '.$mylpi->get_status(false), 0); } + if ($debug > 1) { + error_log('Done calling set_status: checking from memory: '.$myLPI->get_status(false), 0); + } } else { - if ($debug > 1) { error_log("Status not updated"); } + if ($debug > 1) { + error_log("Status not updated"); + } } - $my_type = $mylpi->get_type(); + $my_type = $myLPI->get_type(); // Set status to completed for hotpotatoes if score > 80%. if ($my_type == 'hotpotatoes') { if ((empty($status) || $status == 'undefined' || $status == 'not attempted') && $max > 0) { if (($score/$max) > 0.8) { - $mystatus = 'completed'; - if ($debug > 1) { error_log('Calling set_status('.$mystatus.') for hotpotatoes', 0); } - $mylpi->set_status($mystatus); + $myStatus = 'completed'; + if ($debug > 1) { + error_log('Calling set_status('.$myStatus.') for hotpotatoes', 0); + } + $myLPI->set_status($myStatus); $statusIsSet = true; - if ($debug > 1) { error_log('Done calling set_status for hotpotatoes - now '.$mylpi->get_status(false), 0); } + if ($debug > 1) { + error_log('Done calling set_status for hotpotatoes - now '.$myLPI->get_status(false), 0); + } } } elseif ($status == 'completed' && $max > 0 && ($score/$max) < 0.8) { - $mystatus = 'failed'; - if ($debug > 1) { error_log('Calling set_status('.$mystatus.') for hotpotatoes', 0); } - $mylpi->set_status($mystatus); + $myStatus = 'failed'; + if ($debug > 1) { + error_log('Calling set_status('.$myStatus.') for hotpotatoes', 0); + } + $myLPI->set_status($myStatus); $statusIsSet = true; - if ($debug > 1) { error_log('Done calling set_status for hotpotatoes - now '.$mylpi->get_status(false), 0); } + if ($debug > 1) { + error_log('Done calling set_status for hotpotatoes - now '.$myLPI->get_status(false), 0); + } } } elseif ($my_type == 'sco') { /* @@ -199,11 +228,11 @@ function save_item( * either “passed” or “failed”. If no Mastery Score is provided, * the LMS will leave the cmi.core.lesson_status as “completed” */ - $masteryScore = $mylpi->get_mastery_score(); + $masteryScore = $myLPI->get_mastery_score(); if ($masteryScore == -1 or empty($masteryScore)) { $masteryScore = false; } - $credit = $mylpi->get_credit(); + $credit = $myLPI->get_credit(); /** * 1) If cmi.core.credit is set to “credit” and there is a mastery @@ -211,11 +240,15 @@ function save_item( * the status to either passed or failed depending on the * student's score compared to the mastery score. */ - if ($credit == 'credit' && $masteryScore && (isset($score) && $score != -1) && !$statusIsSet && !$statusSignalReceived) { + if ($credit == 'credit' && + $masteryScore && + (isset($score) && $score != -1) && + !$statusIsSet && !$statusSignalReceived + ) { if ($score >= $masteryScore) { - $mylpi->set_status('passed'); + $myLPI->set_status('passed'); } else { - $mylpi->set_status('failed'); + $myLPI->set_status('failed'); } $statusIsSet = true; } @@ -226,7 +259,7 @@ function save_item( */ if (!$statusIsSet && !$masteryScore && !$statusSignalReceived) { if (!empty($status)) { - $mylpi->set_status($status); + $myLPI->set_status($status); $statusIsSet = true; } //if no status was set directly, we keep the previous one @@ -238,9 +271,9 @@ function save_item( * "browsed" even if the cmi.core.credit is set to no-credit. */ if (!$statusIsSet && $credit == 'no-credit' && !$statusSignalReceived) { - $mode = $mylpi->get_lesson_mode(); + $mode = $myLPI->get_lesson_mode(); if ($mode == 'browse' && $status == 'browsed') { - $mylpi->set_status($status); + $myLPI->set_status($status); $statusIsSet = true; } //if no status was set directly, we keep the previous one @@ -282,7 +315,7 @@ function save_item( $myStatus = 'failed'; } } - $mylpi->set_status($myStatus); + $myLPI->set_status($myStatus); $statusIsSet = true; } } @@ -298,10 +331,10 @@ function save_item( error_log('Calling set_status('.$status.')', 0); } - $mylpi->set_status($status); + $myLPI->set_status($status); if ($debug > 1) { - error_log('Done calling set_status: checking from memory: '.$mylpi->get_status(false), 0); + error_log('Done calling set_status: checking from memory: '.$myLPI->get_status(false), 0); } } else { if ($debug > 1) { @@ -312,27 +345,37 @@ function save_item( if (isset($time) && $time != '' && $time != 'undefined') { // If big integer, then it's a timestamp, otherwise it's normal scorm time. - if ($debug > 1) { error_log('Calling set_time('.$time.') ', 0); } + if ($debug > 1) { + error_log('Calling set_time('.$time.') ', 0); + } if ($time == intval(strval($time)) && $time > 1000000) { - if ($debug > 1) { error_log("Time is INT"); } + if ($debug > 1) { + error_log("Time is INT"); + } $real_time = time() - $time; - if ($debug > 1) { error_log('Calling $real_time '.$real_time.' ', 0); } - $mylpi->set_time($real_time, 'int'); + if ($debug > 1) { + error_log('Calling $real_time '.$real_time.' ', 0); + } + $myLPI->set_time($real_time, 'int'); } else { - if ($debug > 1) { error_log("Time is in SCORM format"); } - if ($debug > 1) { error_log('Calling $time '.$time.' ', 0); } - $mylpi->set_time($time, 'scorm'); + if ($debug > 1) { + error_log("Time is in SCORM format"); + } + if ($debug > 1) { + error_log('Calling $time '.$time.' ', 0); + } + $myLPI->set_time($time, 'scorm'); } - //if ($debug > 1) { error_log('Done calling set_time - now '.$mylpi->get_total_time(), 0); } + //if ($debug > 1) { error_log('Done calling set_time - now '.$myLPI->get_total_time(), 0); } } else { - $time = $mylpi->get_total_time(); + //$time = $myLPI->get_total_time(); } if (isset($suspend) && $suspend != '' && $suspend != 'undefined') { - $mylpi->current_data = $suspend; + $myLPI->current_data = $suspend; } if (isset($location) && $location != '' && $location!='undefined') { - $mylpi->set_lesson_location($location); + $myLPI->set_lesson_location($location); } // Deal with interactions provided in arrays in the following format: @@ -342,57 +385,65 @@ function save_item( //$mylpi->add_interaction($index,$interactions[$index]); //fix DT#4444 $clean_interaction = str_replace('@.|@', ',', $interactions[$index]); - $mylpi->add_interaction($index, $clean_interaction); + $myLPI->add_interaction($index, $clean_interaction); } } if ($core_exit != 'undefined') { - $mylpi->set_core_exit($core_exit); + $myLPI->set_core_exit($core_exit); } - $mylp->save_item($item_id, false); + $myLP->save_item($item_id, false); } - $mystatus_in_db = $mylpi->get_status(true); - if ($debug) error_log("Status in DB: $mystatus_in_db"); + $myStatusInDB = $myLPI->get_status(true); + if ($debug) { + error_log("Status in DB: $myStatusInDB"); + } - if ($mystatus_in_db != 'completed' && $mystatus_in_db != 'passed' && $mystatus_in_db != 'browsed' && $mystatus_in_db != 'failed') { - $mystatus_in_memory = $mylpi->get_status(false); - if ($mystatus_in_memory != $mystatus_in_db) { - $mystatus = $mystatus_in_memory; - } else { - $mystatus = $mystatus_in_db; - } + if ($myStatusInDB != 'completed' && + $myStatusInDB != 'passed' && + $myStatusInDB != 'browsed' && + $myStatusInDB != 'failed' + ) { + $myStatusInMemory = $myLPI->get_status(false); + if ($myStatusInMemory != $myStatusInDB) { + $myStatus = $myStatusInMemory; + } else { + $myStatus = $myStatusInDB; + } } else { - $mystatus = $mystatus_in_db; + $myStatus = $myStatusInDB; } - $mytotal = $mylp->get_total_items_count_without_chapters(); - $mycomplete = $mylp->get_complete_items_count(); - $myprogress_mode = $mylp->get_progress_bar_mode(); - $myprogress_mode = $myprogress_mode == '' ? '%' : $myprogress_mode; + $myTotal = $myLP->get_total_items_count_without_chapters(); + $myComplete = $myLP->get_complete_items_count(); + $myProgressMode = $myLP->get_progress_bar_mode(); + $myProgressMode = $myProgressMode == '' ? '%' : $myProgressMode; - if ($debug > 1) { error_log("mystatus: $mystatus", 0); } - if ($debug > 1) { error_log("myprogress_mode: $myprogress_mode", 0); } - if ($debug > 1) { error_log("progress: $mycomplete / $mytotal", 0); } + if ($debug > 1) { + error_log("mystatus: $myStatus", 0); + error_log("myprogress_mode: $myProgressMode", 0); + error_log("progress: $myComplete / $myTotal", 0); + } - if ($mylpi->get_type() != 'sco') { + if ($myLPI->get_type() != 'sco') { // If this object's JS status has not been updated by the SCORM API, update now. - $return .= "olms.lesson_status='".$mystatus."';"; + $return .= "olms.lesson_status='".$myStatus."';"; } - $return .= "update_toc('".$mystatus."','".$item_id."');"; - $update_list = $mylp->get_update_queue(); + $return .= "update_toc('".$myStatus."','".$item_id."');"; + $update_list = $myLP->get_update_queue(); - foreach ($update_list as $my_upd_id => $my_upd_status) { + foreach ($update_list as $my_upd_id => $my_upd_status) { if ($my_upd_id != $item_id) { /* Only update the status from other items (i.e. parents and brothers), do not update current as we just did it already. */ $return .= "update_toc('".$my_upd_status."','".$my_upd_id."');"; } } - $return .= "update_progress_bar('$mycomplete', '$mytotal', '$myprogress_mode');"; + $return .= "update_progress_bar('$myComplete', '$myTotal', '$myProgressMode');"; if ($debug > 0) { - $return .= "logit_lms('Saved data for item ".$item_id.", user ".$user_id." (status=".$mystatus.")',2);"; + $return .= "logit_lms('Saved data for item ".$item_id.", user ".$user_id." (status=".$myStatus.")',2);"; } if (!isset($_SESSION['login_as'])) { @@ -401,7 +452,7 @@ function save_item( $sql = "SELECT login_id, login_date FROM $tbl_track_login - WHERE login_user_id='".api_get_user_id()."' + WHERE login_user_id= ".api_get_user_id()." ORDER BY login_date DESC LIMIT 0,1"; $q_last_connection = Database::query($sql); @@ -411,20 +462,22 @@ function save_item( $i_id_last_connection = $row['login_id']; $sql = "UPDATE $tbl_track_login SET logout_date='".$current_time."' - WHERE login_id='$i_id_last_connection'"; + WHERE login_id = $i_id_last_connection"; Database::query($sql); } } - if ($mylp->get_type() == 2) { + if ($myLP->get_type() == 2) { $return .= "update_stats();"; } // To be sure progress is updated. - $mylp->save_last(); + $myLP->save_last(); - Session::write('lpobject', serialize($mylp)); - if ($debug > 0) { error_log('---------------- lp_ajax_save_item.php : save_item end ----- '); } + Session::write('lpobject', serialize($myLP)); + if ($debug > 0) { + error_log('---------------- lp_ajax_save_item.php : save_item end ----- '); + } return $return; } diff --git a/main/newscorm/scorm_api.php b/main/newscorm/scorm_api.php index 60577c1767..42211c40b0 100755 --- a/main/newscorm/scorm_api.php +++ b/main/newscorm/scorm_api.php @@ -35,7 +35,7 @@ $oLP = unserialize($_SESSION['lpobject']); $oItem = isset($oLP->items[$oLP->current]) ? $oLP->items[$oLP->current] : null; if (!is_object($oItem)) { - error_log('New LP - scorm_api - Could not load oItem item',0); + error_log('New LP - scorm_api - Could not load oItem item', 0); exit; } $autocomplete_when_80pct = 0; @@ -112,7 +112,8 @@ var olms = new Object(); olms.G_LastError = G_NoError ; olms.G_LastErrorMessage = 'No error'; -//this is not necessary and is only provided to make bad Articulate contents shut up (and not trigger useless JS messages) +//this is not necessary and is only provided to make bad Articulate contents +// shut up (and not trigger useless JS messages) olms.G_LastErrorString = 'No error'; //these variables are provided for better control of the current status in the @@ -190,8 +191,8 @@ olms.lms_course_id = 'get_course_int_id(); ?>'; get_items_details_as_js('olms.lms_item_types');?> olms.asset_timer = 0; -olms.userfname = ''; -olms.userlname = ''; +olms.userfname = ''; +olms.userlname = ''; olms.execute_stats = false; @@ -1095,9 +1096,32 @@ function lms_save_asset() { if (olms.lms_lp_type == 1 || olms.lms_item_type == 'asset' || olms.lms_item_type == 'document') { logit_lms('lms_save_asset'); logit_lms('execute_stats :'+ olms.execute_stats); - xajax_save_item(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.score, olms.max, olms.min, olms.lesson_status, olms.session_time, olms.suspend_data, olms.lesson_location, olms.interactions, olms.lms_item_core_exit, olms.lms_item_type, olms.session_id, olms.course_id); + xajax_save_item( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + olms.lms_item_id, + olms.score, + olms.max, + olms.min, + olms.lesson_status, + olms.session_time, + olms.suspend_data, + olms.lesson_location, + olms.interactions, + olms.lms_item_core_exit, + olms.lms_item_type, + olms.session_id, + olms.course_id + ); if (olms.item_objectives.length>0) { - xajax_save_objectives(olms.lms_lp_id,olms.lms_user_id,olms.lms_view_id,olms.lms_item_id,olms.item_objectives); + xajax_save_objectives( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + olms.lms_item_id, + olms.item_objectives + ); } } } @@ -1267,7 +1291,11 @@ function update_stats_page() { */ function update_progress_bar(nbr_complete, nbr_total, mode) { logit_lms('update_progress_bar('+nbr_complete+', '+nbr_total+', '+mode+')',3); - logit_lms('update_progress_bar with params: lms_lp_id= '+olms.lms_lp_id+', lms_view_id= '+olms.lms_view_id+' lms_user_id= '+olms.lms_user_id,3); + logit_lms( + 'update_progress_bar with params: lms_lp_id= ' + olms.lms_lp_id + + ', lms_view_id= '+ olms.lms_view_id + ' lms_user_id= '+ olms.lms_user_id, + 3 + ); if (mode == '') { mode='%'; @@ -1375,20 +1403,67 @@ function switch_item(current_item, next_item){ } else { logit_lms('Case 2 - current != sco but next == sco'); } - xajax_save_item(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.score, olms.max, olms.min, olms.lesson_status, olms.asset_timer, olms.suspend_data, olms.lesson_location,olms.interactions, olms.lms_item_core_exit, olms.session_id, olms.course_id, olms.finishSignalReceived, 1, olms.statusSignalReceived); - xajax_switch_item_details(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, next_item); + xajax_save_item( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + olms.lms_item_id, + olms.score, + olms.max, + olms.min, + olms.lesson_status, + olms.asset_timer, + olms.suspend_data, + olms.lesson_location, + olms.interactions, + olms.lms_item_core_exit, + olms.session_id, + olms.course_id, + olms.finishSignalReceived, + 1, + olms.statusSignalReceived + ); + xajax_switch_item_details( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + olms.lms_item_id, + next_item + ); } else { if (next_item_type != 'sco') { logit_lms('Case 3 - current == sco but next != sco'); } else { logit_lms('Case 4 - current == sco and next == sco'); } - xajax_save_item_scorm(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.session_id, olms.course_id, olms.finishSignalReceived, 1, olms.statusSignalReceived); + xajax_save_item_scorm( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + olms.lms_item_id, + olms.session_id, + olms.course_id, + olms.finishSignalReceived, + 1, + olms.statusSignalReceived + ); reinit_updatable_vars_list(); - xajax_switch_item_toc(olms.lms_lp_id,olms.lms_user_id,olms.lms_view_id,olms.lms_item_id,next_item); + xajax_switch_item_toc( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + olms.lms_item_id, + next_item + ); if (olms.item_objectives.length>0) { - xajax_save_objectives(olms.lms_lp_id,olms.lms_user_id,olms.lms_view_id,olms.lms_item_id,olms.item_objectives); + xajax_save_objectives( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + olms.lms_item_id, + olms.item_objectives + ); } } @@ -1411,13 +1486,37 @@ function switch_item(current_item, next_item){ */ /* - if (olms.lms_item_type=='sco' && olms.lesson_status != 'completed' && olms.lesson_status != 'passed' && olms.lesson_status != 'browsed' && olms.lesson_status != 'incomplete' && olms.lesson_status != 'failed') { + if (olms.lms_item_type=='sco' && + olms.lesson_status != 'completed' && + olms.lesson_status != 'passed' && + olms.lesson_status != 'browsed' && + olms.lesson_status != 'incomplete' && + olms.lesson_status != 'failed' + ) { // savedata() with olms.finishSignalReceived == 1 treats the special // condition and saves the new status to the database, so // switch_item_details() enjoys the new status savedata(); } - xajax_save_item(olms.lms_lp_id, olms.lms_user_id, olms.lms_view_id, olms.lms_item_id, olms.score, olms.max, olms.min, olms.lesson_status, olms.session_time, olms.suspend_data, olms.lesson_location,olms.interactions, olms.lms_item_core_exit, olms.session_id, olms.course_id, olms.finishSignalReceived, 1, olms.statusSignalReceived); + xajax_save_item( + olms.lms_lp_id, + olms.lms_user_id, + olms.lms_view_id, + olms.lms_item_id, + olms.score, olms.max, + olms.min, + olms.lesson_status, + olms.session_time, + olms.suspend_data, + olms.lesson_location, + olms.interactions, + olms.lms_item_core_exit, + olms.session_id, + olms.course_id, + olms.finishSignalReceived, + 1, + olms.statusSignalReceived + ); */ olms.execute_stats = false; @@ -1462,17 +1561,18 @@ function switch_item(current_item, next_item){ break; } - var mysrc = 'lp_controller.php?action=content&lp_id='+olms.lms_lp_id+'&item_id='+next_item+'&cidReq='+olms.lms_course_code; + var mysrc = 'lp_controller.php?action=content&lp_id=' + olms.lms_lp_id + + '&item_id=' + next_item + '&cidReq=' + olms.lms_course_code; var cont_f = $("#content_id"); mode == 'fullscreen') { ?> - cont_f = window.open(''+mysrc,'content_id','toolbar=0,location=0,status=0,scrollbars=1,resizable=1'); - cont_f.onload=function(){ - olms.info_lms_item[0]=olms.info_lms_item[1]; - } - cont_f.onunload=function(){ - olms.info_lms_item[0]=olms.info_lms_item[1]; - } + cont_f = window.open('' + mysrc, 'content_id', 'toolbar=0,location=0,status=0,scrollbars=1,resizable=1'); + cont_f.onload=function(){ + olms.info_lms_item[0]=olms.info_lms_item[1]; + } + cont_f.onunload=function(){ + olms.info_lms_item[0]=olms.info_lms_item[1]; + } log_in_log('loading '+mysrc+' in frame'); @@ -1804,7 +1904,7 @@ function xajax_switch_item_toc(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, /** * Allow attach the glossary terms into html document of scorm. This has * nothing to do with SCORM itself, and should not interfere w/ SCORM either. - * @param string automatic or manual values are allowed + * @param string automatic or manual values are allowed */ function attach_glossary_into_scorm(type) { var f = $('#content_id')[0]; @@ -1879,7 +1979,8 @@ function attach_glossary_into_scorm(type) { div_show_id="div_show_id"; div_content_id="div_content_id"; - $("iframe").contents().find("body").append('
 
'); + $("iframe").contents().find("body"). + append('
 
'); show_dialog = $("iframe").contents().find("div#"+div_show_id); show_description = $("iframe").contents().find("div#"+div_content_id); @@ -1928,7 +2029,8 @@ function attach_glossary_into_scorm(type) { div_show_id="div_show_id"; div_content_id="div_content_id"; - $("iframe").contents().find("body").append('
 
'); + $("iframe").contents().find("body"). + append('
 
'); show_dialog = $("iframe").contents().find("div#"+div_show_id); show_description = $("iframe").contents().find("div#"+div_content_id); @@ -1953,9 +2055,6 @@ function attach_glossary_into_scorm(type) { } }); - //$("iframe").contents().find("div#"+div_show_id).attr("style","display:inline;float:left;position:absolute;background-color:#F2F2F2;border-bottom: 1px solid #2E2E2E;border-right: 1px solid #2E2E2E;border-left: 1px solid #2E2E2E;border-top: 1px solid #2E2E2E;color:#305582;margin-left:5px;margin-right:5px;"); - //$("iframe").contents().find("div#"+div_content_id).attr("style","background-color:#F2F2F2;color:#0B3861;margin-left:8px;margin-right:8px;margin-top:5px;margin-bottom:5px;"); - $.ajax({ contentType: "application/x-www-form-urlencoded", type: "POST", From 30ff7ba63cf628c805174e173e7681096a65af39 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Sat, 8 Nov 2014 09:20:46 -0500 Subject: [PATCH 5/5] Minor - code style and local variables renaming - refs #398 refs BT#8897 --- main/newscorm/learnpath.class.php | 117 +++++++++++++++++------------- 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/main/newscorm/learnpath.class.php b/main/newscorm/learnpath.class.php index 89390b0870..b31d69b71c 100755 --- a/main/newscorm/learnpath.class.php +++ b/main/newscorm/learnpath.class.php @@ -122,7 +122,7 @@ class learnpath $this->theme = $row['theme']; $this->maker = $row['content_maker']; $this->prevent_reinit = $row['prevent_reinit']; - $this->seriousgame_mode = $row['seriousgame_mode']; + $this->seriousgame_mode = $row['seriousgame_mode']; $this->license = $row['content_license']; $this->scorm_debug = $row['debug']; $this->js_lib = $row['js_lib']; @@ -240,7 +240,10 @@ class learnpath $this->items[$my_item_id] = $oItem; $this->refs_list[$oItem->ref] = $my_item_id; if ($this->debug > 2) { - error_log('New LP - learnpath::__construct() - aicc object with id ' . $my_item_id . ' set in items[]', 0); + error_log( + 'New LP - learnpath::__construct() - ' . + 'aicc object with id ' . $my_item_id . + ' set in items[]', 0); } } break; @@ -279,7 +282,10 @@ class learnpath $this->items[$my_item_id] = $oItem; $this->refs_list[$my_item_id] = $my_item_id; if ($this->debug > 2) { - error_log('New LP - learnpath::__construct() ' . __LINE__ . ' - object with id ' . $my_item_id . ' set in items[]', 0); + error_log( + 'New LP - learnpath::__construct() ' . __LINE__ . + ' - object with id ' . $my_item_id . ' set in items[]', + 0); } } break; @@ -5299,7 +5305,7 @@ class learnpath } // We need to close the form when we are updating the mp3 files. - if ($update_audio == 'true' && count($arrLP) != 0) { + if ($update_audio == 'true' && count($this->arrMenu) != 0) { $return .= ''; } return $return; @@ -5364,23 +5370,23 @@ class learnpath } if (($i % 2) == 0) { - $oddclass = 'row_odd'; + $oddClass = 'row_odd'; } else { - $oddclass = 'row_even'; + $oddClass = 'row_even'; } - $return_audio .= ''; + $return_audio .= ''; $icon_name = str_replace(' ', '', $arrLP[$i]['item_type']); $icon = ''; if (file_exists('../img/lp_' . $icon_name . '.png')) { - $icon = ''; + $icon = ''; } else { - if (file_exists('../img/lp_' . $icon_name . '.gif')) { - $icon = ''; - } else { - $icon = ''; - } + if (file_exists('../img/lp_' . $icon_name . '.gif')) { + $icon = ''; + } else { + $icon = ''; + } } // The audio column. @@ -5652,7 +5658,6 @@ class learnpath $this->tree_array($arrLP); $arrLP = $this->arrMenu; unset ($this->arrMenu); - $title = ''; for ($i = 0; $i < count($arrLP); $i++) { $title = addslashes($arrLP[$i]['title']); $menu_page = api_get_self() . '?cidReq=' . Security :: remove_XSS($_GET['cidReq']) . '&action=view_item&id=' . $arrLP[$i]['id'] . '&lp_id=' . $_SESSION['oLP']->lp_id; @@ -5683,10 +5688,10 @@ class learnpath */ public static function generate_learning_path_folder($course) { //Creating learning_path folder - $dir = '/learning_path'; - $filepath = api_get_path(SYS_COURSE_PATH).$course['path'] . '/document'; + $dir = '/learning_path'; + $filepath = api_get_path(SYS_COURSE_PATH).$course['path'] . '/document'; $folder = false; - if (!is_dir($filepath.'/'.$dir)) { + if (!is_dir($filepath.'/'.$dir)) { $folderData = create_unexisting_directory( $course, api_get_user_id(), @@ -5701,9 +5706,9 @@ class learnpath if (!empty($folderData)) { $folder = true; } - } else { - $folder = true; - } + } else { + $folder = true; + } return $folder; } @@ -5714,21 +5719,21 @@ class learnpath */ public function generate_lp_folder($course, $lp_name = null) { - $filepath = ''; - $dir = '/learning_path/'; + $filepath = ''; + $dir = '/learning_path/'; if (empty($lp_name)) { $lp_name = $this->name; } $folder = self::generate_learning_path_folder($course); - // Creating LP folder - if ($folder) { - //Limits title size - $title = api_substr(replace_dangerous_char($lp_name), 0 , 80); - $dir = $dir.$title; - $filepath = api_get_path(SYS_COURSE_PATH) . $course['path'] . '/document'; - if (!is_dir($filepath.'/'.$dir)) { + // Creating LP folder + if ($folder) { + //Limits title size + $title = api_substr(replace_dangerous_char($lp_name), 0 , 80); + $dir = $dir.$title; + $filepath = api_get_path(SYS_COURSE_PATH) . $course['path'] . '/document'; + if (!is_dir($filepath.'/'.$dir)) { $folderData = create_unexisting_directory( $course, api_get_user_id(), @@ -5742,20 +5747,20 @@ class learnpath if (!empty($folderData)) { $folder = true; } - } else { - $folder = true; - } - $dir = $dir.'/'; - if ($folder) { - $filepath = api_get_path(SYS_COURSE_PATH) . $course['path'] . '/document'.$dir; - } - } + } else { + $folder = true; + } + $dir = $dir.'/'; + if ($folder) { + $filepath = api_get_path(SYS_COURSE_PATH) . $course['path'] . '/document'.$dir; + } + } $array = array( 'dir' => $dir, 'filepath' => $filepath, 'folder' => $folder ); - return $array; + return $array; } /** @@ -6465,7 +6470,7 @@ class learnpath } $legend .= ''; - $return .= '
'; + $return = ''; $return .= $legend; $return .= ''; $return .= ''; @@ -6639,7 +6644,7 @@ class learnpath $legend .= get_lang('EditCurrentForum') . ' :'; $legend .= ''; - $return .= '
'; + $return = '
'; $return .= ''; $return .= $legend; $return .= '
'; @@ -7505,10 +7510,11 @@ class learnpath $legend = ''; - if ($id != 0 && is_array($extra_info)) + if ($id != 0 && is_array($extra_info)) { $parent = $extra_info['parent_item_id']; - else + } else { $parent = 0; + } $sql = "SELECT * FROM " . $tbl_lp_item . " WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id; @@ -7545,7 +7551,7 @@ class learnpath $legend .= ''; - $return .= '
'; + $return = '
'; $return .= ''; $return .= $legend; $return .= '
'; @@ -7729,14 +7735,16 @@ class learnpath $arrLP = $this->arrMenu; unset ($this->arrMenu); - if ($action == 'add') + if ($action == 'add') { $legend .= get_lang('Student_publication') . ' :' . "\n"; - elseif ($action == 'move') $legend .= get_lang('MoveCurrentStudentPublication') . ' :' . "\n"; - else + } elseif ($action == 'move') { + $legend .= get_lang('MoveCurrentStudentPublication') . ' :' . "\n"; + } else { $legend .= get_lang('EditCurrentStudentPublication') . ' :' . "\n"; + } $legend .= ''; - $return .= '
'; + $return = '
'; $return .= ''; $return .= $legend; $return .= '
'; @@ -8821,8 +8829,13 @@ class learnpath }*/ $file_path = $_SERVER['DOCUMENT_ROOT'].$doc_info[0]; $file_path = str_replace('//', '/', $file_path); + + $abs_path = api_get_path(SYS_PATH).str_replace(api_get_path(WEB_PATH), '', $doc_info[0]); + $current_dir = dirname($abs_path); + $current_dir = str_replace('\\', '/', $current_dir); + if (file_exists($file_path)) { - $file_path = substr($file_path,strlen($current_dir)); // We get the relative path. + $file_path = substr($file_path, strlen($current_dir)); // We get the relative path. $zip_files[] = $my_sub_dir.'/'.$file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href','document/'.$file_path); @@ -9216,12 +9229,12 @@ class learnpath } //Fix to avoid problems with default_course_document if (strpos("main/default_course_document", $old_new['dest'] === false)) { - $new_dest = str_replace('document/', $mult.'document/', $old_new['dest']); + //$newDestination = str_replace('document/', $mult.'document/', $old_new['dest']); + $newDestination = $old_new['dest']; } else { - //$new_dest = $old_new['dest']; - $new_dest = str_replace('document/', '', $old_new['dest']); + $newDestination = str_replace('document/', '', $old_new['dest']); } - $string = str_replace($old_new['orig'], $new_dest, $string); + $string = str_replace($old_new['orig'], $newDestination, $string); //Add files inside the HTMLs $new_path = str_replace('/courses/', '', $old_new['orig']);