Browse Source

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

Yannick Warnier 10 years ago
parent
commit
1d68db47b2

+ 2 - 1
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

+ 2 - 1
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

+ 99 - 43
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 <darkden@freemail.hu> (original author - 2003-2004)
  * @author   Yannick Warnier <ywarnier@beeznest.org> (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=<?php echo $oItem->get_score();?>;
@@ -182,6 +186,7 @@ olms.lms_item_core_exit = '<?php echo $oItem->get_core_exit();?>';
 olms.lms_course_id = '<?php echo $oLP->get_course_int_id(); ?>';
 olms.lms_session_id = '<?php echo api_get_session_id(); ?>';
 olms.lms_course_code = '<?php echo $oLP->getCourseCode(); ?>';
+olms.lms_course_id =  '<?php echo $oLP->get_course_int_id(); ?>';
 <?php echo $oLP->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] = '<?php echo $oItem->get_id();?>';
     olms.info_lms_item[1] = '<?php echo $oItem->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');
             }
-        <?php } elseif (api_get_setting('show_glossary_in_documents') == 'isautomatic') { ?>
+            <?php } elseif (api_get_setting('show_glossary_in_documents') == 'isautomatic') { ?>
             attach_glossary_into_scorm('automatic');
         <?php } ?>
         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() {