Browse Source

[svn r13590] Added management of SCORM objectives. Needs some testing but the feature seems to work.

Yannick Warnier 17 years ago
parent
commit
473ff00ac3

+ 21 - 1
main/inc/lib/add_course.lib.inc.php

@@ -349,6 +349,7 @@ function update_Db_course($courseDbName)
 	$TABLELPVIEW				= $courseDbName . "lp_view";
 	$TABLELPITEMVIEW			= $courseDbName . "lp_item_view";
 	$TABLELPIVINTERACTION		= $courseDbName . "lp_iv_interaction";
+	$TABLELPIVOBJECTIVE			= $courseDbName . "lp_iv_objective";
 
 	// Smartblogs (Kevin Van Den Haute :: kevin@develop-it.be)
 	$tbl_blogs					= $courseDbName . 'blog';
@@ -972,7 +973,7 @@ function update_Db_course($courseDbName)
 		"start_time		int unsigned	not null," . //when did the user open it?
 		"total_time		int unsigned not null default 0," . //after how many seconds did he close it?
 		"score			float unsigned not null default 0," . //score returned by SCORM or other techs
-		"status			char(32) not null default 'Not attempted'," . //status for this item (SCORM)
+		"status			char(32) not null default 'not attempted'," . //status for this item (SCORM)
 		"suspend_data	text null default ''," .
 		"lesson_location text null default ''," .
 		"core_exit		varchar(32) not null default 'none'," .
@@ -1015,6 +1016,25 @@ function update_Db_course($courseDbName)
 	{
 		error_log($sql,0);
 	}
+	
+	$sql = "CREATE TABLE IF NOT EXISTS `$TABLELPIVOBJECTIVE`(" .
+		"id				bigint	unsigned 		primary key auto_increment," .
+		"lp_iv_id		bigint	unsigned not null," . //identifier of the related sco_view
+		"objective_id	varchar(255) not null default ''," . //sco-specific, given by the sco
+		"score_raw		float unsigned not null default 0," . //score
+		"score_max		float unsigned not null default 0," . //max score
+		"score_min		float unsigned not null default 0," . //min score
+		"status			char(32) not null default 'not attempted'" . //status, just as sco status
+		")";
+	if(!api_sql_query($sql))
+	{
+		error_log($sql,0);
+	}
+	$sql = "ALTER TABLE `$TABLELPIVOBJECTIVE` ADD INDEX (lp_iv_id) ";
+	if(!api_sql_query($sql))
+	{
+		error_log($sql,0);
+	}
 
 	/*
 	-----------------------------------------------------------

+ 2 - 0
main/install/migrate-db-1.8.4-1.8.5-pre.sql

@@ -26,3 +26,5 @@ INSERT INTO settings_current (variable, subkey, type, category, selected_value,
 -- xxUSERxx
 
 -- xxCOURSExx
+CREATE TABLE lp_iv_interaction(id bigint unsigned primary key auto_increment, lp_iv_id bigint unsigned not null, objective_id	varchar(255) not null default '', score_raw		float unsigned not null default 0, score_max		float unsigned not null default 0, score_min		float unsigned not null default 0, status char(32) not null default 'not attempted');
+ALTER TABLE lp_iv_interaction ADD INDEX (lp_iv_id);

+ 95 - 3
main/newscorm/learnpathItem.class.php

@@ -26,6 +26,8 @@ class learnpathItem{
 	//id(0), type(1), time(2), weighting(3),correct_responses(4),student_response(5),result(6),latency(7)
 	var $interactions = array();
 	var $interactions_count = 0;
+	var $objectives = array();
+	var $objectives_count = 0;
 	var $launch_data = '';
 	var $lesson_location = '';
 	var $level = 0;
@@ -142,6 +144,22 @@ class learnpathItem{
     	}
     	*/
     }
+    /**
+	 * Adds an objective to the current item
+	 * @param	array	Array of parameters: id(0), status(1), score_raw(2), score_max(3), score_min(4)
+	 * @result	void
+     */
+    function add_objective($index,$params)
+    {
+    	if(empty($params[0])){return null;}
+    	error_log(__FILE__.' '.__LINE__.' '.print_r($params,true),0);
+		$this->objectives[$index] = $params;
+		//take the current maximum index to generate the objectives_count
+		if((count($this->objectives)+1)>$this->objectives_count){
+			$this->objectives_count = (count($this->objectives)+1);
+		}
+    }
+    
     /**
      * Closes/stops the item viewing. Finalises runtime values. If required, save to DB.
      * @return	boolean	True on success, false otherwise
@@ -352,6 +370,19 @@ class learnpathItem{
     	}
     	return $res;
     }
+    /**
+     * Gets the current count of objectives recorded in the database
+     * @return	int	The current number of objectives recorder
+     */
+    function get_objectives_count()
+    {
+    	if($this->debug>1){error_log('New LP - In learnpathItem::get_objectives_count()',0);}
+    	$res = 0;
+    	if(!empty($this->objectives_count)){
+    		$res = $this->objectives_count;
+    	}
+    	return $res;
+    }
     /**
      * Gets the launch_data field found in imsmanifests (this is SCORM- or AICC-related, really)
      * @return	string	Launch data as found in imsmanifest and stored in Dokeos (read only). Defaults to ''.
@@ -385,6 +416,7 @@ class learnpathItem{
 				$mode = 'review';
 			}
 		}
+		return $mode;
 	}
     /**
      * Gets the depth level
@@ -1434,6 +1466,8 @@ class learnpathItem{
 			$this->status = $this->possible_status[0];
 			$this->interactions_count = 0;
 			$this->interactions = array();
+			$this->objectives_count = 0;
+			$this->objectives = array();
 			$this->lesson_location = '';
 			$this->write_to_db();
 		}else{ 
@@ -1516,6 +1550,8 @@ class learnpathItem{
 		     				//	;
 		     				//}
 		     				break;
+		     			case 'objectives':
+		     				break;
 		     			//case 'maxtimeallowed':
 		     			//	$this->set_max_time_allowed($value);
 		     			//	break;
@@ -1682,6 +1718,15 @@ class learnpathItem{
 				}else{
 					$this->interactions_count = 0;
 				}
+		     	//now get the number of objectives for this little guy
+		     	$item_view_objective_table = Database::get_course_table('lp_iv_objective');
+		     	$sql = "SELECT * FROM $item_view_objective_table WHERE lp_iv_id = '".$this->db_item_view_id."'"; 
+				$res = api_sql_query($sql,__FILE__,__LINE__);
+				if($res !== false){
+					$this->objectives_count = Database::num_rows($res);
+				}else{
+					$this->objectives_count = 0;
+				}
 	     	}
      	}
 		//end
@@ -1966,8 +2011,8 @@ class learnpathItem{
 	     			if($this->debug>2){error_log('New LP - In learnpathItem::write_to_db() - Got item_view_id '.$lp_iv_id.', now checking interactions ',0);}
 		     		foreach($this->interactions as $index => $interaction){
 		     			$correct_resp = '';
-		     			if(is_array($interaction[4]) && !empty($interactions[4][0]) ){
-		     				foreach($interactions[4] as $resp){
+		     			if(is_array($interaction[4]) && !empty($interaction[4][0]) ){
+		     				foreach($interaction[4] as $resp){
 		     					$correct_resp .= $resp.',';
 		     				}
 		     				$correct_resp = substr($correct_resp,0,strlen($correct_resp)-1);
@@ -2012,9 +2057,56 @@ class learnpathItem{
 		     		}
 	     		}
 	     	}
+	     	if(is_array($this->objectives) && count($this->objectives)>0){
+	     		//save objectives
+	     		$tbl = Database::get_course_table('lp_item_view');
+	     		$sql = "SELECT id FROM $tbl " .
+	     				"WHERE lp_item_id = ".$this->db_id." " .
+	     				"AND   lp_view_id = ".$this->view_id." " .
+	     				"AND   view_count = ".$this->attempt_id;
+	     		$res = api_sql_query($sql,__FILE__,__LINE__);
+	     		if(Database::num_rows($res)>0){
+	     			$row = Database::fetch_array($res);
+	     			$lp_iv_id = $row[0];
+	     			if($this->debug>2){error_log('New LP - In learnpathItem::write_to_db() - Got item_view_id '.$lp_iv_id.', now checking objectives ',0);}
+		     		foreach($this->objectives as $index => $objective){
+		     			$iva_table = Database::get_course_table('lp_iv_objective');
+		     			$iva_sql = "SELECT id FROM $iva_table " .
+		     					"WHERE lp_iv_id = $lp_iv_id " .
+		     					//"AND order_id = $index";
+								//also check for the objective ID as it must be unique for this SCO view
+		     					"AND objective_id = '".$objective[0]."'";
+		     			$iva_res = api_sql_query($iva_sql,__FILE__,__LINE__);
+						//id(0), type(1), time(2), weighting(3),correct_responses(4),student_response(5),result(6),latency(7)
+		     			if(Database::num_rows($iva_res)>0){
+		     				//update (or don't)
+		     				$iva_row = Database::fetch_array($iva_res);
+		     				$iva_id = $iva_row[0];
+		     				$ivau_sql = "UPDATE $iva_table " .
+		     					"SET objective_id = '".$objective[0]."'," .
+		     					"status = '".$objective[1]."'," .
+		     					"score_raw = '".$objective[2]."'," .
+		     					"score_min = '".$objective[4]."'," .
+		     					"score_max = '".$objective[3]."' " .
+		     					"WHERE id = $iva_id";
+		     				$ivau_res = api_sql_query($ivau_sql,__FILE__,__LINE__);
+		     				error_log($ivau_sql,0);
+		     			}else{
+		     				//insert new one
+		     				$ivai_sql = "INSERT INTO $iva_table " .
+		     						"(lp_iv_id, objective_id, status, score_raw, score_min, score_max )" .
+		     						"VALUES" .
+		     						"(".$lp_iv_id.",'".$objective[0]."','".$objective[1]."'," .
+		     						"'".$objective[2]."','".$objective[4]."','".$objective[3]."')";
+		     				$ivai_res = api_sql_query($ivai_sql,__FILE__,__LINE__);
+		     				error_log($ivai_sql);
+		     			}
+		     		}
+	     		}
+	     	}
    		}
 		if($this->debug>2){error_log('New LP - End of learnpathItem::write_to_db()',0);}
      	return true;
      }
 }
-?>
+?>

+ 1 - 0
main/newscorm/lp_comm.common.php

@@ -18,6 +18,7 @@ require_once('learnpath.class.php');
 require('../inc/lib/xajax/xajax.inc.php');
 $xajax = new xajax(api_get_path(WEB_CODE_PATH).'newscorm/lp_comm.server.php');
 $xajax->registerFunction("save_item");
+$xajax->registerFunction("save_objectives");
 $xajax->registerFunction("switch_item_details");
 $xajax->registerFunction("backup_item_details");
 $xajax->registerFunction("start_timer");

+ 50 - 2
main/newscorm/lp_comm.server.php

@@ -61,7 +61,6 @@ function backup_item_details($lp_id,$user_id,$view_id,$item_id,$score=-1,$max=-1
 function save_item($lp_id,$user_id,$view_id,$item_id,$score=-1,$max=-1,$min=-1,$status='',$time=0,$suspend='',$location='',$interactions=array(),$core_exit='none')
 {
 	global $_configuration;
-	
 	$debug=0;
 	if($debug>0){error_log('In xajax_save_item('.$lp_id.','.$user_id.','.$view_id.','.$item_id.','.$score.','.$max.','.$min.','.$status.','.$time.',"'.$suspend.'","'.$location.'","'.(count($interactions)>0?$interactions[0]:'').'","'.$core_exit.'")',0);}
 	$objResponse = new xajaxResponse();
@@ -181,6 +180,52 @@ function save_item($lp_id,$user_id,$view_id,$item_id,$score=-1,$max=-1,$min=-1,$
 	
 	return $objResponse;
 }
+/**
+ * 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	array	Objectives array
+ */
+function save_objectives($lp_id,$user_id,$view_id,$item_id,$objectives=array())
+{
+	global $_configuration;
+	$debug=0;
+	if($debug>0){error_log('In xajax_save_objectives('.$lp_id.','.$user_id.','.$view_id.','.$item_id.',"'.(count($objectives)>0?count($objectives):'').'")',0);}
+	$objResponse = new xajaxResponse();
+	require_once('learnpath.class.php');
+	require_once('scorm.class.php');
+	require_once('aicc.class.php');
+	require_once('learnpathItem.class.php');
+	require_once('scormItem.class.php');
+	require_once('aiccItem.class.php');
+	$mylp = '';
+	if(isset($_SESSION['lpobject']))
+	{
+		if($debug>1){error_log('////$_SESSION[lpobject] is set',0);}
+		$oLP =& unserialize($_SESSION['lpobject']);
+		if(!is_object($oLP)){
+			if($debug>2){error_log(print_r($oLP,true),0);}
+			if($debug>2){error_log('////Building new lp',0);}
+			unset($oLP);
+			$code = api_get_course_id();
+			$mylp = & new learnpath($code,$lp_id,$user_id);
+		}else{
+			if($debug>2){error_log('////Reusing session lp',0);}
+			$mylp = & $oLP;
+		}
+	}
+	$mylpi =& $mylp->items[$item_id];
+	//error_log(__FILE__.' '.__LINE__.' '.print_r($objectives,true),0);
+	if(is_array($objectives) && count($objectives)>0){
+		foreach($objectives as $index=>$objective){
+			//error_log(__FILE__.' '.__LINE__.' '.$objectives[$index][0],0);
+			$mylpi->add_objective($index,$objectives[$index]);
+		}
+	}
+	return $objResponse;
+}
 /**
  * Get one item's details
  * @param	integer	LP ID
@@ -191,7 +236,7 @@ function save_item($lp_id,$user_id,$view_id,$item_id,$score=-1,$max=-1,$min=-1,$
  */
 function switch_item_details($lp_id,$user_id,$view_id,$current_item,$next_item)
 {
-	$debug=0;
+	$debug=2;
 	if($debug>0){error_log('In xajax_switch_item_details('.$lp_id.','.$user_id.','.$view_id.','.$current_item.','.$next_item.')',0);}
 	$objResponse = new xajaxResponse();
 	/*$item_id may be one of:
@@ -311,6 +356,7 @@ function switch_item_details($lp_id,$user_id,$view_id,$current_item,$next_item)
 			"max_time_allowed = '".$mymax_time_allowed."';" .
 			"launch_data = '".$mylaunch_data."';" .
 			"interactions = new Array();" .
+			"item_objectives = new Array();" .
 			"G_lastError = 0;" .
 			"G_LastErrorMessage = 'No error';");
 	/*
@@ -339,6 +385,7 @@ function switch_item_details($lp_id,$user_id,$view_id,$current_item,$next_item)
 	$mycredit = $mylpi->get_credit();
 	$mylaunch_data = $mylpi->get_launch_data();
 	$myinteractions_count = $mylpi->get_interactions_count();
+	$myobjectives_count = $mylpi->get_objectives_count();
 	$mycore_exit = $mylpi->get_core_exit();
 	$objResponse->addScript(
 			"saved_lesson_status='not attempted';" .
@@ -360,6 +407,7 @@ function switch_item_details($lp_id,$user_id,$view_id,$current_item,$next_item)
 			"lms_item_lesson_mode = '".$mylesson_mode."';" .
 			"lms_item_launch_data = '".$mylaunch_data."';" .
 			"lms_item_interactions_count = '".$myinteractions_count."';" .
+			"lms_item_objectives_count = '".$myinteractions_count."';" .
 			"lms_item_core_exit = '".$mycore_exit."';" .
 			"asset_timer = 0;"
 			);

+ 230 - 154
main/newscorm/scorm_api.php

@@ -136,6 +136,7 @@ var mastery_score = '<?php echo $oItem->get_mastery_score();?>';
 var launch_data = '<?php echo $oItem->get_launch_data();?>';
 var max_time_allowed = '<?php echo $oItem->get_max_time_allowed();?>';
 var interactions = new Array();
+item_objectives = new Array();
 
 //Dokeos internal variables
 var saved_lesson_status = 'not attempted';
@@ -158,7 +159,6 @@ var lms_item_type = '<?php echo $oItem->get_type();?>';
 var lms_item_credit = '<?php echo $oItem->get_credit();?>';
 var lms_item_lesson_mode = '<?php echo $oItem->get_lesson_mode();?>';
 var lms_item_launch_data = '<?php echo $oItem->get_launch_data();?>';
-var lms_item_interactions_count = '<?php echo $oItem->get_interactions_count(); ?>';
 var lms_item_core_exit = '<?php echo $oItem->get_core_exit();?>';
 var asset_timer = 0;
 
@@ -177,27 +177,12 @@ var lms_old_item_id = 0;
 function LMSInitialize() {  //this is the initialize function of all APIobjects
 	logit_scorm('LMSInitialise()',0);
 
-	//give api it's new ID
-	//lesson_status = 'not attempted';
-	//initialise the lesson status between two lessons, to avoid status override
-	//var msg_f = document.getElementById('message_id');
-	//var refresh_url = 'lp_controller.php?cidReq=<?php echo api_get_course_id();?>&action=js_api_refresh&lp_id=<?php echo $oLP->get_id();?>&item_id='+lms_new_item_id;
 	/* 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' 
 	 * and that kind of stuff, so when the content loads in the content frame
 	 * it will have all the correct variables set 
 	 */
-	/*	
-	lms_been_synchronized = 0;
-	if(lms_item_id == lms_new_item_id || lms_new_item_id==0){
-		//no change to be done, it's the same item we just had or it's the first
-		lms_been_synchronized = 1;
-	}else{
-		lms_item_id = lms_new_item_id;
-		//msg_f.src = refresh_url;
-	}
-	*/
 	G_LastError = G_NoError ;
 	G_LastErrorMessage = 'No error';	
 	lms_initialized=1;
@@ -214,9 +199,11 @@ function LMSGetValue(param) {
 	G_LastError = G_NoError ;
 	G_LastErrorMessage = 'No error';	
 	var result='';
+	// ---- cmi.core._children
 	if(param=='cmi.core._children' || param=='cmi.core_children'){
 		result='entry, exit, lesson_status, student_id, student_name, lesson_location, total_time, credit, lesson_mode, score, session_time';
 	}else if(param == 'cmi.core.entry'){
+	// ---- cmi.core.entry
 		if(lms_item_core_exit=='none')
 		{
 			result='ab-initio';
@@ -230,9 +217,11 @@ function LMSGetValue(param) {
 			result='';
 		}
 	}else if(param == 'cmi.core.exit'){
+	// ---- cmi.core.exit
 		result='';
 		G_LastError = G_ElementIsWriteOnly;
 	}else if(param == 'cmi.core.lesson_status'){
+	// ---- cmi.core.lesson_status
 	    if(lesson_status != '') {
 	    	result=lesson_status;
 	    }
@@ -240,144 +229,163 @@ function LMSGetValue(param) {
 	    	result='not attempted';
 	    }
 	}else if(param == 'cmi.core.student_id'){
+	// ---- cmi.core.student_id
 		result='<?php echo $_user['user_id']; ?>';
 	}else if(param == 'cmi.core.student_name'){
+	// ---- cmi.core.student_name
 		  <?php
 			$who=addslashes($_user['lastName'].", ".$_user['firstName']);
 		    echo "result='$who';"; 
 		  ?>
 	}else if(param == 'cmi.core.lesson_location'){
+	// ---- cmi.core.lesson_location
 		result=lesson_location;
 	}else if(param == 'cmi.core.total_time'){
+	// ---- cmi.core.total_time
 		result=total_time;
 	}else if(param == 'cmi.core.score._children'){
+	// ---- cmi.core.score._children
 		result='raw,min,max';
 	}else if(param == 'cmi.core.score.raw'){
+	// ---- cmi.core.score.raw
 		result=score;
 	}else if(param == 'cmi.core.score.max'){
+	// ---- cmi.core.score.max
 		result=max;
 	}else if(param == 'cmi.core.score.min'){
+	// ---- cmi.core.score.min
 		result=min;
 	}else if(param == 'cmi.core.score'){
+	// ---- cmi.core.score -- non-standard item, provided as cmi.core.score.raw just in case
 		result=score;
 	}else if(param == 'cmi.core.credit'){
+	// ---- cmi.core.credit
 		result = lms_item_credit;
 	}else if(param == 'cmi.core.lesson_mode'){
+	// ---- cmi.core.lesson_mode
 		result = lms_item_lesson_mode;
 	}else if(param == 'cmi.suspend_data'){
+	// ---- cmi.suspend_data
 		result = suspend_data;
 	}else if(param == 'cmi.launch_data'){
+	// ---- cmi.launch_data
 		result = lms_item_launch_data;
+	}else if(param == 'cmi.objectives._children'){
+	// ---- cmi.objectives._children
+		result = 'id,score,status';
 	}else if(param == 'cmi.objectives._count'){
+	// ---- cmi.objectives._count
 		//result='<?php echo $oItem->get_view_count();?>';
-		result = 0;
+		result = item_objectives.length;
+	}else if(param.substring(0,15)== 'cmi.objectives.'){
+		var myres = '';
+		if(myres = param.match(/cmi.objectives.(\d+).(id|score|status|_children)(.*)/))
+		{
+			var obj_id = myres[1];
+			var req_type = myres[2];
+			if(item_objectives[obj_id]==null)
+			{
+				if(req_type == 'id')
+				{
+					result = '';
+				}else if(req_type == '_children'){
+					result = 'id,score,status';
+				}else if(req_type == 'score'){
+					if(myres[3]==null)
+					{
+						result = '';
+						G_lastError = G_NotImplementedError;
+						G_lastErrorString = 'Not implemented yet';
+					}else if (myres[3] == '._children'){
+						result = 'raw,min,max'; //non-standard, added for NetG
+					}else if (myres[3] == '.raw'){
+						result = '';
+					}else if (myres[3] == '.max'){
+						result = '';
+					}else if (myres[3] == '.min'){
+						result = '';
+					}else{
+						result = '';
+						G_lastError = G_NotImplementedError;
+						G_lastErrorString = 'Not implemented yet';
+					}
+				}else if(req_type == 'status'){
+					result = 'not attempted';
+				}
+			}
+			else
+			{
+				//the object is not null
+				if(req_type == 'id')
+				{
+					result = item_objectives[obj_id][0];
+				}else if(req_type == '_children'){
+					result = 'id,score,status';
+				}else if(req_type == 'score'){
+					if(myres[3]==null)
+					{
+						result = '';
+						G_lastError = G_NotImplementedError;
+						G_lastErrorString = 'Not implemented yet';
+					}else if (myres[3] == '._children'){
+						result = 'raw,min,max'; //non-standard, added for NetG
+					}else if (myres[3] == '.raw'){
+						if(item_objectives[obj_id][2] != null)
+						{
+							result = item_objectives[obj_id][2];
+						}else{
+							result = '';
+						}
+					}else if (myres[3] == '.max'){
+						if(item_objectives[obj_id][3] != null)
+						{
+							result = item_objectives[obj_id][3];
+						}else{
+							result = '';
+						}
+					}else if (myres[3] == '.min'){
+						if(item_objectives[obj_id][4] != null)
+						{
+							result = item_objectives[obj_id][4];
+						}else{
+							result = '';
+						}
+					}else{
+						result = '';
+						G_lastError = G_NotImplementedError;
+						G_lastErrorString = 'Not implemented yet';
+					}
+				}else if(req_type == 'status'){
+					if(item_objectives[obj_id][1] != null)
+					{
+						result = item_objectives[obj_id][1];
+					}else{
+						result = 'not attempted';
+					}
+				}
+			}
+		}
 	}else if(param == 'cmi.student_data._children'){
+	// ---- cmi.student_data._children
 		result = 'mastery_score,max_time_allowed';
 	}else if(param == 'cmi.student_data.mastery_score'){
+	// ---- cmi.student_data.mastery_score
 		result = mastery_score;
 	}else if(param == 'cmi.student_data.max_time_allowed'){
+	// ---- cmi.student_data.max_time_allowed
 		result = max_time_allowed;
 	}else if(param == 'cmi.interactions._count'){
+	// ---- cmi.interactions._count
 		result = interactions.length;
 	}else if(param == 'cmi.interactions._children'){
+	// ---- cmi.interactions._children
 		result = 'id,time,type,correct_responses,weighting,student_response,result,latency';
 	}else{
+	// ---- anything else
 		result = '';
 		G_lastError = G_NotImplementedError;
 		G_lastErrorString = 'Not implemented yet';
 	}
-	/*
-	//Switch not working??? WTF???
-	switch(param) {
-		case 'cmi.core._children'		:
-			result='entry, exit, lesson_status, student_id, student_name, lesson_location, total_time, credit, lesson_mode, score, session_time';
-			break;
-		case 'cmi.core_children'		:
-			result='entry, exit, lesson_status, student_id, student_name, lesson_location, total_time, credit, lesson_mode, score, session_time';
-			break;
-		case 'cmi.core.entry'			:
-			result='';
-			break;
-		case 'cmi.core.exit'			: 
-			result='';
-			break;
-		case 'cmi.core.lesson_status'	: 
-		    if(lesson_status != '') {
-		    	result=lesson_status;
-		    }
-		    else{
-		    	result='not attempted';
-		    }
-		    break;
-		case 'cmi.core.student_id'	   : 
-			result='<?php echo $_user['user_id']; ?>';
-			break;
-		case 'cmi.core.student_name'	: 
-		  <?php
-			$who=addslashes($_user['firstName'].",".$_user['lastName']);
-		    echo "result='$who';"; 
-		  ?>	break;
-		case 'cmi.core.lesson_location'	:
-			result='';
-			break;
-		case 'cmi.core.total_time'	:	
-			result=total_time;
-			break;
-		case 'cmi.core.score._children'	: 
-			result='raw,min,max';
-			break;
-		case 'cmi.core.score.raw'	: 
-			result=score;
-			break;
-		case 'cmi.core.score.max'	:
-			result=max;
-			break;
-		case 'cmi.core.score.min'	: 
-			result=min;
-			break;
-		case 'cmi.core.score'		: 
-			result=score;
-			break;
-		case 'cmi.score.scaled'		: //1.3
-			if(score < -1 || score >1)
-			{
-				result=score/max;
-			}
-			else
-			{
-				result=score;			
-			}
-			break;
-		case 'cmi.core.credit'		: 
-			result='no-credit';
-			break;
-		case 'cmi.core.lesson_mode'	: 
-			result='normal';
-			break;
-		case 'cmi.suspend_data'		: 
-			result='<?php echo $oItem->get_suspend_data();?>';
-			break;
-		case 'cmi.launch_data'		: 
-			result='';
-			break;
-		case 'cmi.objectives._count': 
-			//result='<?php echo $oItem->get_view_count();?>';
-			result = 0;
-			break;
-		case 'cmi.interactions._count':
-			result = interactions.length;
-			if(result == ''){
-				result = 0;
-			}
-			break;
-		case 'cmi.interactions._children':
-			result = 'id,time,type,correct_responses,weighting,student_response,result,latency'; break;
-			break;
-		default: 
-			result='';
-			break;
-	}
-	*/
 	logit_scorm("LMSGetValue\n\t('"+param+"') returned '"+result+"'",1);
 	return result;
 }
@@ -392,19 +400,24 @@ function LMSSetValue(param, val) {
 	G_LastError = G_NoError ;
 	G_LastErrorMessage = 'No error';	
 	return_value = 'false';
-	switch(param) {
-	case 'cmi.core.score.raw'		: score= val; return_value='true';	break;
-	case 'cmi.core.score.max'		: max = val;return_value='true';break;
-	case 'cmi.core.score.min'		: min = val;return_value='true';break;
-	case 'cmi.core.lesson_location' : lesson_location = val;return_value='true';break;
-	case 'cmi.core.lesson_status'	: 
+	if( param == "cmi.core.score.raw" )
+	{
+		score= val; return_value='true';
+	} else if ( param == "cmi.core.score.max" ) {
+		max = val;return_value='true';
+	} else if ( param == "cmi.core.score.min" ) {
+		min = val;return_value='true';
+	} else if ( param == "cmi.core.lesson_location" ) {
+		lesson_location = val;return_value='true';
+	} else if ( param == "cmi.core.lesson_status" ) {
 		saved_lesson_status = lesson_status;
 		lesson_status = val;
 	    return_value='true';
-		break;
-	case 'cmi.completion_status'	: lesson_status = val;return_value='true';break; //1.3
-	case 'cmi.core.session_time'	: session_time = val;return_value='true';break;
-	case 'cmi.score.scaled'			: //1.3
+	} else if ( param == "cmi.completion_status" ) {
+		lesson_status = val;return_value='true'; //1.3
+	} else if ( param == "cmi.core.session_time" ) {
+		session_time = val;return_value='true';
+	} else if ( param == "cmi.score.scaled") { //1.3
 		if(val<=1 && val>=-1)
 		{ 
 			score = val ;
@@ -414,75 +427,133 @@ function LMSSetValue(param, val) {
 		{
 			return_value='false';
 		}
-		break;
-	case 'cmi.success_status'		: success_status = val;return_value='true';break; //1.3
-	case 'cmi.suspend_data'			: suspend_data = val;return_value='true';break;
-	case 'cmi.core.exit'			: lms_item_core_exit = val;return_value='true';break;
-	case 'cmi.core.entry'			: G_LastError = G_ElementIsReadOnly; break;
-	case 'cmi.student_data.mastery_score' : G_LastError = G_ElementIsReadOnly; break;
-	case 'cmi.student_data.max_time_allowed' : G_LastError = G_ElementIsReadOnly; break;
-	case 'cmi.launch_data'			: G_LastError = G_ElementIsReadOnly; break;
-	default:
+	} else if ( param == "cmi.success_status" ) {
+		success_status = val;return_value='true'; //1.3
+	} else if ( param == "cmi.suspend_data" ) {
+		suspend_data = val;return_value='true';
+	} else if ( param == "cmi.core.exit" ) {
+		lms_item_core_exit = val;return_value='true';
+	} else if ( param == "cmi.core.entry" ) {
+		G_LastError = G_ElementIsReadOnly
+	} else if ( param == "cmi.student_data.mastery_score" ) {
+		G_LastError = G_ElementIsReadOnly;
+	} else if ( param == "cmi.student_data.max_time_allowed" ) {
+		G_LastError = G_ElementIsReadOnly;
+	} else if ( param == "cmi.launch_data" ) {
+		G_LastError = G_ElementIsReadOnly;
+	} else {
 		var myres = new Array();
-		if(myres = param.match(/cmi.interactions.(\d+).(id|time|type|correct_responses|weighting|student_response|result|latency)(.*)/)){
-			//elems = param.split('.');
-			//elem_id = elems[2];
+		if(myres = param.match(/cmi.interactions.(\d+).(id|time|type|correct_responses|weighting|student_response|result|latency)(.*)/))
+		{
 			elem_id = myres[1];
 			if(interactions[elem_id] == null){
 				interactions[elem_id] = ['','','','','','','',''];
 				//id(0), type(1), time(2), weighting(3),correct_responses(4),student_response(5),result(6),latency(7)
 				interactions[elem_id][4] = new Array();
 			}
-			//elem_attrib = elems[3];
 			elem_attrib = myres[2];
 			switch(elem_attrib) {
-				case 'id':
+				case "id":
 					interactions[elem_id][0] = val;
 					logit_scorm("Interaction "+elem_id+"'s id updated",2);
 					return_value='true';
 					break;
-				case 'time':
+				case "time":
 					interactions[elem_id][2] = val;
 					logit_scorm("Interaction "+elem_id+"'s time updated",2);
 					return_value='true';
 					break;
-				case 'type':
+				case "type":
 					interactions[elem_id][1] = val;
 					logit_scorm("Interaction "+elem_id+"'s type updated",2);
 					return_value='true';
 					break;
-				case 'correct_responses':
+				case "correct_responses":
 					//do nothing yet
 					interactions[elem_id][4].push(val);
 					logit_scorm("Interaction "+elem_id+"'s correct_responses not updated",2);
 					return_value='true';
 					break;
-				case 'weighting':
+				case "weighting":
 					interactions[elem_id][3] = val;
 					logit_scorm("Interaction "+elem_id+"'s weighting updated",2);
 					return_value='true';
 					break;
-				case 'student_response':
+				case "student_response":
 					interactions[elem_id][5] = val;
 					logit_scorm("Interaction "+elem_id+"'s student_response updated",2);
 					return_value='true';
 					break;
-				case 'result':
+				case "result":
 					interactions[elem_id][6] = val;
 					logit_scorm("Interaction "+elem_id+"'s result updated",2);
 					return_value='true';
 					break;
-				case 'latency':
+				case "latency":
 					interactions[elem_id][7] = val;
 					logit_scorm("Interaction "+elem_id+"'s latency updated",2);
 					return_value='true';
 					break;
-			}  
+				default:
+						G_lastError = G_NotImplementedError;
+						G_lastErrorString = 'Not implemented yet';
+			}
+		}else if(param.substring(0,15)== 'cmi.objectives.'){
+			var myres = '';
+			if(myres = param.match(/cmi.objectives.(\d+).(id|score|status)(.*)/))
+			{
+				obj_id = myres[1];
+				req_type = myres[2];
+				if(obj_id == null || obj_id == '')
+				{
+					;//do nothing
+				}
+				else
+				{
+					if(item_objectives[obj_id]==null)
+					{
+						item_objectives[obj_id] = ['','','','',''];
+					}
+					if( req_type == "id" ) {
+							item_objectives[obj_id][0] = val.substring(51,57);
+							logit_scorm("Objective "+obj_id+"'s id updated",2);
+							return_value = 'true';
+					} else if ( req_type == "score" ) {
+							if (myres[3] == '._children'){
+								return_value = '';
+								G_lastError = G_InvalidSetValue;
+								G_lastErrorString = 'Invalid set value, element is a keyword';
+							}else if (myres[3] == '.raw'){
+								item_objectives[obj_id][2] = val;
+								logit_scorm("Objective "+obj_id+"'s score raw updated",2);
+								return_value = 'true';
+							}else if (myres[3] == '.max'){
+								item_objectives[obj_id][3] = val;
+								logit_scorm("Objective "+obj_id+"'s score max updated",2);
+								return_value = 'true';
+							}else if (myres[3] == '.min'){
+								item_objectives[obj_id][4] = val;
+								logit_scorm("Objective "+obj_id+"'s score min updated",2);
+								return_value = 'true';
+							}else{
+								return_value = '';
+								G_lastError = G_NotImplementedError;
+								G_lastErrorString = 'Not implemented yet';
+							}
+					} else if ( req_type == "status" ) {
+							item_objectives[obj_id][1] = val;
+							logit_scorm("Objective "+obj_id+"'s status updated",2);
+							return_value = 'true';
+					} else {
+							G_lastError = G_NotImplementedError;
+							G_lastErrorString = 'Not implemented yet';
+					}
+				}
+			}
 		}else{
 			G_lastError = G_NotImplementedError;
 			G_lastErrorString = 'Not implemented yet';
 		}
-		break;
 	}
 	<?php 
 	if ($oLP->force_commit == 1){
@@ -511,6 +582,10 @@ function savedata(origin) { //origin can be 'commit', 'finish' or 'terminate'
     }
 	logit_lms('saving data (status='+lesson_status+' - interactions: '+ interactions.length +')',1);
 	xajax_save_item(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, score, max, min, lesson_status, session_time, suspend_data, lesson_location, interactions, lms_item_core_exit);
+	if(item_objectives.length>0)
+	{
+		xajax_save_objectives(lms_lp_id,lms_user_id,lms_view_id,lms_item_id,item_objectives);
+	}
 }
 
 function LMSCommit(val) {
@@ -595,6 +670,8 @@ function Terminate(){
 function XAJAXobject() {
   this.xajax_switch_item_details=xajax_switch_item_details;
   this.switch_item=switch_item;
+  this.xajax_save_objectives=xajax_save_objectives;
+  this.xajax_save_item = xajax_save_item;
 }
 
 //it is not sure that the scos use the above declarations
@@ -670,12 +747,6 @@ function load_item(item_id,url){
 			cont_f.src = url;
 			update_toc('unhighlight',lms_old_item_id);
 			update_toc('highlight',item_id);
-			/* legacy code
-			lms_been_synchronized = 0;
-			lms_initialized = 0;
-			if(lms_lp_type==1 || lms_item_type=='asset'){
-				lms_item_id = lms_new_item_id;
-			}*/
 			return true;
 		}
 		logit_lms('cont_f.src has no properties',0);
@@ -688,11 +759,12 @@ function load_item(item_id,url){
  * leaving it
  */
 function dokeos_save_asset(){
-    //var linkparams = 'id='+lms_item_id+'&score='+score+'&max='+max+'&min='+min+'&lesson_status='+lesson_status+'&time='+session_time+'&suspend_data='+suspend_data;
-    //var url = "<?php echo api_get_path(WEB_CODE_PATH).'newscorm/lp_controller.php' ?>?action=save&" + linkparams + "";
 	logit_lms('dokeos_save_asset: '+url,0);
-    //frames["message_name"].src = url;
-    xajax_save_item(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, score, max, min, lesson_status, session_time, suspend_data, lesson_location,interactions);
+    xajax_save_item(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, score, max, min, lesson_status, session_time, suspend_data, lesson_location,interactions, lms_item_core_exit);
+    if(item_objectives.length>0)
+	{
+		xajax_save_objectives(lms_lp_id,lms_user_id,lms_view_id,lms_item_id,item_objectives);
+	}
 }
 /**
  * Logs information about SCORM messages into the log frame
@@ -861,9 +933,13 @@ function switch_item(current_item, next_item){
 	//(1) save the current item
 	logit_lms('Called switch_item with params '+lms_item_id+' and '+next_item+'',0);
 	if(lms_lp_type==1 || lms_item_type=='asset' || session_time == '0' || session_time == '0:00:00'){
-		xajax_save_item(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, score, max, min, lesson_status, asset_timer, suspend_data, lesson_location,interactions);
+		xajax_save_item(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, score, max, min, lesson_status, asset_timer, suspend_data, lesson_location,interactions, lms_item_core_exit);		
 	}else{
-		xajax_save_item(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, score, max, min, lesson_status, session_time, suspend_data, lesson_location,interactions);
+		xajax_save_item(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, score, max, min, lesson_status, session_time, suspend_data, lesson_location,interactions, lms_item_core_exit);
+	}
+	if(item_objectives.length>0)
+	{
+		xajax_save_objectives(lms_lp_id,lms_user_id,lms_view_id,lms_item_id,item_objectives);
 	}
 	//(2) Refresh all the values inside this SCORM API object - use AJAX
 	//xajax_backup_item_details(lms_lp_id, lms_user_id, lms_view_id, lms_item_id, score, max, min, lesson_status, session_time, suspend_data);