diff --git a/main/lp/learnpath.class.php b/main/lp/learnpath.class.php index b5aa2e2f45..94ee3e4618 100755 --- a/main/lp/learnpath.class.php +++ b/main/lp/learnpath.class.php @@ -2574,6 +2574,7 @@ class learnpath // path, then the rules are completely different: we assume only one // item exists and the progress of the LP depends on the score $scoreAsProgressSetting = api_get_configuration_value('lp_score_as_progress_enable'); + if ($scoreAsProgressSetting === true) { $scoreAsProgress = $this->getUseScoreAsProgress(); if ($scoreAsProgress) { @@ -2605,6 +2606,7 @@ class learnpath if ($completeItems > $total_items) { $completeItems = $total_items; } + if ($mode == '%') { if ($total_items > 0) { $percentage = ((float) $completeItems / (float) $total_items) * 100; @@ -5596,10 +5598,14 @@ class learnpath if ($debug) { error_log('start_current_item will save item with prereq: '.$prereq_check); } - $this->items[$this->current]->save(false, $prereq_check); + + $saveStatus = learnpathItem::isLpItemAutoComplete($this->current); + if ($saveStatus) { + $this->items[$this->current]->save(false, $prereq_check); + } } // If sco, then it is supposed to have been updated by some other call. - if ($item_type == 'sco') { + if ($item_type === 'sco') { $this->items[$this->current]->restart(); } } diff --git a/main/lp/learnpathItem.class.php b/main/lp/learnpathItem.class.php index 93ef2acce1..4905247fe1 100755 --- a/main/lp/learnpathItem.class.php +++ b/main/lp/learnpathItem.class.php @@ -4536,4 +4536,21 @@ class learnpathItem return $resultFromOtherSessions; } } + + public static function isLpItemAutoComplete($lpItemId): bool + { + $extraFieldValue = new ExtraFieldValue('lp_item'); + $saveAutomatic = $extraFieldValue->get_values_by_handler_and_field_variable( + $lpItemId, + 'no_automatic_validation' + ); + + if (false !== $saveAutomatic && is_array($saveAutomatic) && isset($saveAutomatic['value'])) { + if (1 === (int) $saveAutomatic['value']) { + return false; + } + } + + return true; + } } diff --git a/main/lp/lp_ajax_initialize.php b/main/lp/lp_ajax_initialize.php index 7770da49f0..89ec501cfe 100755 --- a/main/lp/lp_ajax_initialize.php +++ b/main/lp/lp_ajax_initialize.php @@ -45,6 +45,7 @@ function initialize_item($lp_id, $user_id, $view_id, $next_item) if ($debug) { error_log('In initialize_item() - new item is '.$next_item); } + $mylp->start_current_item(true); if (is_object($mylp->items[$next_item])) { @@ -111,7 +112,6 @@ function initialize_item($lp_id, $user_id, $view_id, $next_item) } } $myobjectives = json_encode($phpobjectives); - $return .= "olms.score=".$myscore.";". "olms.max=".$mymax.";". diff --git a/main/lp/lp_ajax_save_item.php b/main/lp/lp_ajax_save_item.php index 2332dbc721..bd906136a6 100755 --- a/main/lp/lp_ajax_save_item.php +++ b/main/lp/lp_ajax_save_item.php @@ -58,7 +58,8 @@ function save_item( $courseId = null, $lmsFinish = 0, $userNavigatesAway = 0, - $statusSignalReceived = 0 + $statusSignalReceived = 0, + $forceIframeSave = 0 ) { $debug = 0; $return = null; @@ -107,6 +108,15 @@ function save_item( // This functions sets the $this->db_item_view_id variable needed in get_status() see BT#5069 $myLPI->set_lp_view($view_id); + $my_type = $myLPI->get_type(); + + $saveStatus = true; + if ('document' === $my_type) { + $saveStatus = learnpathItem::isLpItemAutoComplete($myLPI->getIid()); + if ($forceIframeSave) { + $saveStatus = true; + } + } // Launch the prerequisites check and set error if needed if (true !== $prerequisitesCheck) { @@ -171,16 +181,22 @@ function save_item( } $statusIsSet = false; - // Default behaviour. - if (isset($status) && $status != '' && $status != 'undefined') { - if ($debug > 1) { - error_log('Calling set_status('.$status.')'); - } + if ($saveStatus) { + // Default behaviour. + if (isset($status) && $status != '' && $status != 'undefined') { + if ($debug > 1) { + error_log('Calling 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)); + $myLPI->set_status($status); + $statusIsSet = true; + if ($debug > 1) { + error_log('Done calling set_status: checking from memory: '.$myLPI->get_status(false)); + } + } else { + if ($debug > 1) { + error_log('Status not updated'); + } } } else { if ($debug > 1) { @@ -188,7 +204,6 @@ function save_item( } } - $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) { @@ -370,25 +385,30 @@ function save_item( // 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.')'); - } + // If no previous condition changed the SCO status, proceed with a generic behaviour + if ($saveStatus) { + if (!$statusIsSet && !$statusSignalReceived) { + // Default behaviour + if (isset($status) && $status != '' && $status != 'undefined') { + if ($debug > 1) { + error_log('Calling set_status('.$status.')'); + } - $myLPI->set_status($status); + $myLPI->set_status($status); - if ($debug > 1) { - error_log('Done calling set_status: checking from memory: '.$myLPI->get_status(false)); - } - } else { - if ($debug > 1) { - error_log("Status not updated"); + if ($debug > 1) { + error_log('Done calling set_status: checking from memory: '.$myLPI->get_status(false)); + } + } else { + if ($debug > 1) { + error_log("Status not updated"); + } } } + } else { + if ($debug > 1) { + error_log("Status not updated"); + } } if (isset($time) && $time != '' && $time != 'undefined') { @@ -440,7 +460,10 @@ function save_item( if ($core_exit != 'undefined') { $myLPI->set_core_exit($core_exit); } - $myLP->save_item($item_id, false); + + if ($saveStatus) { + $myLP->save_item($item_id, false); + } } $myStatusInDB = $myLPI->get_status(true); @@ -478,37 +501,39 @@ function save_item( error_log("progress: $myComplete / $myTotal"); } - 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 .= "update_toc('".$myStatus."','".$item_id."');"; - $update_list = $myLP->get_update_queue(); - - 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."');"; + if ($saveStatus) { + 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."';"; } - } - $progressBarSpecial = false; - $scoreAsProgressSetting = api_get_configuration_value('lp_score_as_progress_enable'); - if ($scoreAsProgressSetting === true) { - $scoreAsProgress = $myLP->getUseScoreAsProgress(); - if ($scoreAsProgress) { - // Only update score if it was set by scorm. - if (isset($score) && $score != -1) { - $score = $myLPI->get_score(); - $maxScore = $myLPI->get_max(); - $return .= "update_progress_bar('$score', '$maxScore', '$myProgressMode');"; + $return .= "update_toc('".$myStatus."','".$item_id."');"; + $update_list = $myLP->get_update_queue(); + 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."');"; } - $progressBarSpecial = true; } - } - if (!$progressBarSpecial) { - $return .= "update_progress_bar('$myComplete', '$myTotal', '$myProgressMode');"; + $progressBarSpecial = false; + $scoreAsProgressSetting = api_get_configuration_value('lp_score_as_progress_enable'); + if ($scoreAsProgressSetting === true) { + $scoreAsProgress = $myLP->getUseScoreAsProgress(); + if ($scoreAsProgress) { + // Only update score if it was set by scorm. + if (isset($score) && $score != -1) { + $score = $myLPI->get_score(); + $maxScore = $myLPI->get_max(); + $return .= "update_progress_bar('$score', '$maxScore', '$myProgressMode');"; + } + $progressBarSpecial = true; + } + } + + if (!$progressBarSpecial) { + $return .= "update_progress_bar('$myComplete', '$myTotal', '$myProgressMode');"; + } } if (!Session::read('login_as')) { @@ -537,15 +562,17 @@ function save_item( $return .= 'update_stats();'; } - // To be sure progress is updated. - $myLP->save_last($score); + if ($saveStatus) { + // To be sure progress is updated. + $myLP->save_last($score); + HookLearningPathItemViewed::create() + ->setEventData(['item_view_id' => $myLPI->db_item_view_id]) + ->notifyLearningPathItemViewed(); - HookLearningPathItemViewed::create() - ->setEventData(['item_view_id' => $myLPI->db_item_view_id]) - ->notifyLearningPathItemViewed(); + Session::write('lpobject', serialize($myLP)); + Session::write('oLP', $myLP); + } - Session::write('lpobject', serialize($myLP)); - Session::write('oLP', $myLP); if ($debug > 0) { error_log("lp_view_session_id :".$myLP->lp_view_session_id); error_log('---------------- lp_ajax_save_item.php : save_item end ----- '); @@ -593,5 +620,6 @@ echo save_item( (!empty($_REQUEST['course_id']) ? $_REQUEST['course_id'] : ''), (empty($_REQUEST['finish']) ? 0 : 1), (empty($_REQUEST['userNavigatesAway']) ? 0 : 1), - (empty($_REQUEST['statusSignalReceived']) ? 0 : 1) + (empty($_REQUEST['statusSignalReceived']) ? 0 : 1), + isset($_REQUEST['forceIframeSave']) ? (int) $_REQUEST['forceIframeSave'] : 0 ); diff --git a/main/lp/lp_ajax_switch_item.php b/main/lp/lp_ajax_switch_item.php index fa0d79f3c9..81f2fcb8ec 100755 --- a/main/lp/lp_ajax_switch_item.php +++ b/main/lp/lp_ajax_switch_item.php @@ -44,6 +44,8 @@ function switch_item_details($lp_id, $user_id, $view_id, $current_item, $next_it */ $mylp = learnpath::getLpFromSession(api_get_course_id(), $lp_id, $user_id); $new_item_id = 0; + $saveStatus = learnpathItem::isLpItemAutoComplete($current_item); + switch ($next_item) { case 'next': $mylp->set_current_item($current_item); @@ -93,8 +95,11 @@ function switch_item_details($lp_id, $user_id, $view_id, $current_item, $next_it } $mylp->start_current_item(true); - if ($mylp->force_commit) { - $mylp->save_current(); + + if ($saveStatus) { + if ($mylp->force_commit) { + $mylp->save_current(); + } } if (is_object($mylp->items[$new_item_id])) { @@ -106,6 +111,7 @@ function switch_item_details($lp_id, $user_id, $view_id, $current_item, $next_it $mylpi = new learnpathItem($new_item_id, $user_id); $mylpi->set_lp_view($view_id); } + /* * now get what's needed by the SCORM API: * -score @@ -263,7 +269,6 @@ function switch_item_details($lp_id, $user_id, $view_id, $current_item, $next_it "update_progress_bar('$mycomplete','$mytotal','$myprogress_mode');". $updateMinTime ; - $return .= 'updateGamificationValues(); '; $mylp->set_error_msg(''); $mylp->prerequisites_match(); // Check the prerequisites are all complete. diff --git a/main/lp/lp_ajax_switch_item_toc.php b/main/lp/lp_ajax_switch_item_toc.php index 976032412c..55712094a5 100755 --- a/main/lp/lp_ajax_switch_item_toc.php +++ b/main/lp/lp_ajax_switch_item_toc.php @@ -34,6 +34,8 @@ function switch_item_toc($lpId, $userId, $viewId, $currentItem, $nextItem) error_log('In switch_item_toc('.$lpId.','.$userId.','.$viewId.','.$currentItem.','.$nextItem.')', 0); } $myLP = learnpath::getLpFromSession(api_get_course_id(), $lpId, $userId); + $saveStatus = learnpathItem::isLpItemAutoComplete($currentItem); + $newItemId = 0; $oldItemId = 0; switch ($nextItem) { @@ -79,7 +81,8 @@ function switch_item_toc($lpId, $userId, $viewId, $currentItem, $nextItem) break; } $myLP->start_current_item(true); - if ($myLP->force_commit) { + + if ($myLP->force_commit && $saveStatus) { $myLP->save_current(); } if (is_object($myLP->items[$newItemId])) { diff --git a/main/lp/lp_edit_item.php b/main/lp/lp_edit_item.php index d9e3b2c91a..8e21ad5268 100755 --- a/main/lp/lp_edit_item.php +++ b/main/lp/lp_edit_item.php @@ -151,7 +151,7 @@ if (empty($documentInfo)) { $path_parts = pathinfo($path_file); -if (!empty($path_file) && isset($path_parts['extension']) && $path_parts['extension'] == 'html') { +if (!empty($path_file) && isset($path_parts['extension']) && $path_parts['extension'] === 'html') { echo $learnPath->return_new_tree(); // Show the template list echo '
'; @@ -167,6 +167,7 @@ $excludeExtraFields = [ 'authorlpitem', 'price', ]; + if (api_is_platform_admin()) { // Only admins can edit this items $excludeExtraFields = []; @@ -178,6 +179,9 @@ if (isset($is_success) && $is_success === true) { echo $learnPath->display_item($_GET['id'], $msg); } else { $item = $learnPath->getItem($_GET['id']); + if ('document' !== $item->get_type()) { + $excludeExtraFields[] = 'no_automatic_validation'; + } echo $learnPath->display_edit_item($item->getIid(), $excludeExtraFields); $finalItem = Session::read('finalItem'); if ($finalItem) { diff --git a/main/lp/lp_view.php b/main/lp/lp_view.php index 9361955420..9032b08b99 100755 --- a/main/lp/lp_view.php +++ b/main/lp/lp_view.php @@ -288,6 +288,7 @@ if (!isset($src)) { break; } + // This change the status to complete in Chamilo LP. $lp->start_current_item(); // starts time counter manually if asset } else { $src = 'blank.php?error=prerequisites'; diff --git a/main/lp/scorm_api.php b/main/lp/scorm_api.php index d68d8ec418..265b677ab8 100755 --- a/main/lp/scorm_api.php +++ b/main/lp/scorm_api.php @@ -280,7 +280,6 @@ function LMSInitialize() { olms.G_LastError = G_NoError ; olms.G_LastErrorMessage = 'No error'; - olms.lms_initialized = 0; olms.finishSignalReceived = 0; olms.statusSignalReceived = 0; @@ -874,7 +873,7 @@ function SetValue(param, val) { /** * Saves the current data from JS memory to the LMS database */ -function savedata(item_id) { +function savedata(item_id, forceIframeSave = 0) { // Origin can be 'commit', 'finish' or 'terminate' (depending on the calling function) logit_lms('function savedata(' + item_id + ')', 3); @@ -883,6 +882,10 @@ function savedata(item_id) { //olms.updatable_vars_list['cmi.core.lesson_status'] = true; } + if (typeof(forceIframeSave) == 'undefined') { + forceIframeSave = 0; + } + old_item_id = olms.info_lms_item[0]; var item_to_save = olms.lms_item_id; logit_lms('item_to_save (original value): ' + item_to_save, 3); @@ -890,7 +893,7 @@ function savedata(item_id) { // If saving session_time value, we assume that all the new info is about // the old item, not the current one // if (olms.session_time != '' && olms.session_time != '0') { - if (olms.switch_finished == 0) { + if (olms.switch_finished == 0 && forceIframeSave == 0) { logit_lms('item_to_save (changed to): ' + old_item_id, 3); item_to_save = old_item_id; } @@ -904,7 +907,9 @@ function savedata(item_id) { olms.lms_course_id, olms.finishSignalReceived, olms.userNavigatesAway, - olms.statusSignalReceived + olms.statusSignalReceived, + false, + forceIframeSave ); olms.info_lms_item[1] = olms.lms_item_id; @@ -935,7 +940,13 @@ function LMSCommit(val) { olms.G_LastError = G_NoError ; olms.G_LastErrorMessage = 'No error'; - savedata(olms.lms_item_id); + let forceIframeSave = 0; + if (val && 'iframe' == val) { + forceIframeSave = 1; + } + + console.log(forceIframeSave); + savedata(olms.lms_item_id, forceIframeSave); //reinit_updatable_vars_list(); logit_scorm('LMSCommit() end ', 0); @@ -1927,7 +1938,8 @@ function xajax_save_item_scorm( finishSignalReceived, userNavigatesAway, statusSignalReceived, - useSendBeacon + useSendBeacon, + forceIframeSave ) { if (typeof(finishSignalReceived) == 'undefined') { finishSignalReceived = 0; @@ -1940,6 +1952,10 @@ function xajax_save_item_scorm( statusSignalReceived = 0; } + if (typeof(forceIframeSave) == 'undefined') { + forceIframeSave = 0; + } + var is_interactions='false'; 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 @@ -1949,6 +1965,8 @@ function xajax_save_item_scorm( params += '&finishSignalReceived='+finishSignalReceived; params += '&userNavigatesAway='+userNavigatesAway; params += '&statusSignalReceived='+statusSignalReceived; + params += '&forceIframeSave='+forceIframeSave; + var my_scorm_values = new Array(); my_scorm_values = process_scorm_values(); for (k=0; k < my_scorm_values.length; k++) {