MDL-46397 mod_scorm : binding cmi values with scoid

This commit is contained in:
Nobelium 2014-07-28 05:37:21 +00:00
parent ec36fafc0f
commit bf4f65fbb6
9 changed files with 497 additions and 401 deletions

View file

@ -60,27 +60,29 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
text_range = '-1#1';
// The AICC data model
var datamodel = {
var datamodel = {};
for(scoid in def){
datamodel[scoid] = {
'cmi._children':{'defaultvalue':cmi_children, 'mod':'r', 'writeerror':'402'},
'cmi._version':{'defaultvalue':'3.4', 'mod':'r', 'writeerror':'402'},
'cmi.core._children':{'defaultvalue':core_children, 'mod':'r', 'writeerror':'402'},
'cmi.core.student_id':{'defaultvalue':def['cmi.core.student_id'], 'mod':'r', 'writeerror':'403'},
'cmi.core.student_name':{'defaultvalue':def['cmi.core.student_name'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_location':{'defaultvalue':def['cmi.core.lesson_location'], 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
'cmi.core.credit':{'defaultvalue':def['cmi.core.credit'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_status':{'defaultvalue':def['cmi.core.lesson_status'], 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
'cmi.core.exit':{'defaultvalue':def['cmi.core.exit'], 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
'cmi.core.entry':{'defaultvalue':def['cmi.core.entry'], 'mod':'r', 'writeerror':'403'},
'cmi.core.student_id':{'defaultvalue':def[scoid]['cmi.core.student_id'], 'mod':'r', 'writeerror':'403'},
'cmi.core.student_name':{'defaultvalue':def[scoid]['cmi.core.student_name'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_location':{'defaultvalue':def[scoid]['cmi.core.lesson_location'], 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
'cmi.core.credit':{'defaultvalue':def[scoid]['cmi.core.credit'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_status':{'defaultvalue':def[scoid]['cmi.core.lesson_status'], 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
'cmi.core.exit':{'defaultvalue':def[scoid]['cmi.core.exit'], 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
'cmi.core.entry':{'defaultvalue':def[scoid]['cmi.core.entry'], 'mod':'r', 'writeerror':'403'},
'cmi.core.score._children':{'defaultvalue':score_children, 'mod':'r', 'writeerror':'402'},
'cmi.core.score.raw':{'defaultvalue':def['cmi.core.score.raw'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.score.max':{'defaultvalue':def['cmi.core.score.max'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.score.min':{'defaultvalue':def['cmi.core.score.min'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.score.raw':{'defaultvalue':def[scoid]['cmi.core.score.raw'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.score.max':{'defaultvalue':def[scoid]['cmi.core.score.max'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.score.min':{'defaultvalue':def[scoid]['cmi.core.score.min'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'00:00:00', 'readerror':'404', 'writeerror':'405'},
'cmi.core.total_time':{'defaultvalue':def['cmi.core.total_time'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_mode':{'defaultvalue':def['cmi.core.lesson_mode'], 'mod':'r', 'writeerror':'403'},
'cmi.suspend_data':{'defaultvalue':def['cmi.suspend_data'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
'cmi.launch_data':{'defaultvalue':def['cmi.launch_data'], 'mod':'r', 'writeerror':'403'},
'cmi.comments':{'defaultvalue':def['cmi.comments'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
'cmi.core.total_time':{'defaultvalue':def[scoid]['cmi.core.total_time'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_mode':{'defaultvalue':def[scoid]['cmi.core.lesson_mode'], 'mod':'r', 'writeerror':'403'},
'cmi.suspend_data':{'defaultvalue':def[scoid]['cmi.suspend_data'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
'cmi.launch_data':{'defaultvalue':def[scoid]['cmi.launch_data'], 'mod':'r', 'writeerror':'403'},
'cmi.comments':{'defaultvalue':def[scoid]['cmi.comments'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
// deprecated evaluation attributes
'cmi.evaluation.comments._count':{'defaultvalue':'0', 'mod':'r', 'writeerror':'402'},
'cmi.evaluation.comments._children':{'defaultvalue':comments_children, 'mod':'r', 'writeerror':'402'},
@ -97,16 +99,16 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
'cmi.objectives.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.objectives.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
'cmi.student_data._children':{'defaultvalue':student_data_children, 'mod':'r', 'writeerror':'402'},
'cmi.student_data.attempt_number':{'defaultvalue':def['cmi.student_data.attempt_number'], 'mod':'r', 'writeerror':'402'},
'cmi.student_data.attempt_number':{'defaultvalue':def[scoid]['cmi.student_data.attempt_number'], 'mod':'r', 'writeerror':'402'},
'cmi.student_data.tries.n.score.raw':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.student_data.tries.n.score.min':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.student_data.tries.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.student_data.tries.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
'cmi.student_data.tries.n.time':{'pattern':CMIIndex, 'format':CMITime, 'mod':'rw', 'writeerror':'405'},
'cmi.student_data.mastery_score':{'defaultvalue':def['cmi.student_data.mastery_score'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.max_time_allowed':{'defaultvalue':def['cmi.student_data.max_time_allowed'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.time_limit_action':{'defaultvalue':def['cmi.student_data.time_limit_action'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.tries_during_lesson':{'defaultvalue':def['cmi.student_data.tries_during_lesson'], 'mod':'r', 'writeerror':'402'},
'cmi.student_data.mastery_score':{'defaultvalue':def[scoid]['cmi.student_data.mastery_score'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.max_time_allowed':{'defaultvalue':def[scoid]['cmi.student_data.max_time_allowed'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.time_limit_action':{'defaultvalue':def[scoid]['cmi.student_data.time_limit_action'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.tries_during_lesson':{'defaultvalue':def[scoid]['cmi.student_data.tries_during_lesson'], 'mod':'r', 'writeerror':'402'},
'cmi.student_preference._children':{'defaultvalue':student_preference_children, 'mod':'r', 'writeerror':'402'},
'cmi.student_preference.audio':{'defaultvalue':'0', 'format':CMISInteger, 'range':audio_range, 'mod':'rw', 'writeerror':'405'},
'cmi.student_preference.language':{'defaultvalue':'', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
@ -127,11 +129,17 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
'nav.event':{'defaultvalue':'', 'format':NAVEvent, 'mod':'w', 'readerror':'404', 'writeerror':'405'}
};
}
var cmi, nav;
function initdatamodel(scoid){
prerequrl = cfgwwwroot + "/mod/scorm/prereqs.php?a="+scormid+"&scoid="+scoid+"&attempt="+attempt+"&mode="+viewmode+"&currentorg="+currentorg+"&sesskey="+sesskey;
datamodelurlparams = "id="+cmid+"&a="+scormid+"&sesskey="+sesskey+"&attempt="+attempt+"&scoid="+scoid;
//
// Datamodel inizialization
//
var cmi = new Object();
cmi = new Object();
cmi.core = new Object();
cmi.core.score = new Object();
cmi.objectives = new Object();
@ -143,23 +151,24 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
cmi.evaluation.comments = new Object();
// Navigation Object
var nav = new Object();
nav = new Object();
for (element in datamodel) {
for (element in datamodel[scoid]) {
if (element.match(/\.n\./) == null) {
if ((typeof eval('datamodel["'+element+'"].defaultvalue')) != 'undefined') {
eval(element+' = datamodel["'+element+'"].defaultvalue;');
if ((typeof eval('datamodel["'+scoid+'"]["'+element+'"].defaultvalue')) != 'undefined') {
eval(element+' = datamodel["'+scoid+'"]["'+element+'"].defaultvalue;');
} else {
eval(element+' = "";');
}
}
}
eval(cmiobj);
eval(cmiobj[scoid]);
if (cmi.core.lesson_status == '') {
cmi.core.lesson_status = 'not attempted';
}
}
//
// API Methods definition
@ -167,6 +176,9 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
var Initialized = false;
function LMSInitialize (param) {
scoid = scorm_current_node ? scorm_current_node.scoid : scoid ;
initdatamodel(scoid);
errorCode = "0";
if (param == "") {
if (!Initialized) {
@ -221,8 +233,8 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
if (element !="") {
expression = new RegExp(CMIIndex,'g');
elementmodel = String(element).replace(expression,'.n.');
if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].mod') != 'w') {
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].mod') != 'w') {
element = String(element).replace(expression, "_$1.");
elementIndexes = element.split('.');
subelement = 'cmi';
@ -237,21 +249,21 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
errorCode = "0"; // Need to check if it is the right errorCode
}
} else {
errorCode = eval('datamodel["'+elementmodel+'"].readerror');
errorCode = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].readerror');
}
} else {
childrenstr = '._children';
countstr = '._count';
if (elementmodel.substr(elementmodel.length-childrenstr.length,elementmodel.length) == childrenstr) {
parentmodel = elementmodel.substr(0,elementmodel.length-childrenstr.length);
if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
if ((typeof eval('datamodel["'+scoid+'"]["'+parentmodel+'"]')) != "undefined") {
errorCode = "202";
} else {
errorCode = "201";
}
} else if (elementmodel.substr(elementmodel.length-countstr.length,elementmodel.length) == countstr) {
parentmodel = elementmodel.substr(0,elementmodel.length-countstr.length);
if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
if ((typeof eval('datamodel["'+scoid+'"]["'+parentmodel+'"]')) != "undefined") {
errorCode = "203";
} else {
errorCode = "201";
@ -275,9 +287,9 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
if (element != "") {
expression = new RegExp(CMIIndex,'g');
elementmodel = String(element).replace(expression,'.n.');
if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
expression = new RegExp(eval('datamodel["'+elementmodel+'"].format'));
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].mod') != 'r') {
expression = new RegExp(eval('datamodel["'+scoid+'"]["'+elementmodel+'"].format'));
value = value+'';
matches = value.match(expression);
if (matches != null) {
@ -324,8 +336,8 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
}
//Store data
if (errorCode == "0") {
if ((typeof eval('datamodel["'+elementmodel+'"].range')) != "undefined") {
range = eval('datamodel["'+elementmodel+'"].range');
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"].range')) != "undefined") {
range = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].range');
ranges = range.split('#');
value = value*1.0;
if ((value >= ranges[0]) && (value <= ranges[1])) {
@ -333,7 +345,7 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
errorCode = "0";
return "true";
} else {
errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
errorCode = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].writeerror');
}
} else {
if (element == 'cmi.comments') {
@ -346,10 +358,10 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
}
}
} else {
errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
errorCode = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].writeerror');
}
} else {
errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
errorCode = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].writeerror');
}
} else {
errorCode = "201"
@ -471,11 +483,11 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
element = parent+'.'+property;
expression = new RegExp(CMIIndex,'g');
elementmodel = String(element).replace(expression,'.n.');
if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].mod') != 'r') {
elementstring = '&'+underscore(element)+'='+escape(data[property]);
if ((typeof eval('datamodel["'+elementmodel+'"].defaultvalue')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].defaultvalue') != data[property]) {
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"].defaultvalue')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].defaultvalue') != data[property]) {
datastring += elementstring;
}
} else {
@ -502,7 +514,7 @@ function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, vi
}
}
if (cmi.core.lesson_mode == 'browse') {
if (datamodel['cmi.core.lesson_status'].defaultvalue == '' && cmi.core.lesson_status == 'not attempted') {
if (datamodel[scoid]['cmi.core.lesson_status'].defaultvalue == '' && cmi.core.lesson_status == 'not attempted') {
cmi.core.lesson_status = 'browsed';
}
}

View file

@ -17,13 +17,23 @@
require_once($CFG->dirroot.'/mod/scorm/locallib.php');
$userdata = new stdClass();
$def = get_scorm_default($userdata, $scorm, $scoid, $attempt, $mode);
$def = new stdClass();
$cmiobj = new stdClass();
if (!isset($currentorg)) {
$currentorg = '';
}
$cmiobj = '';
if ($scoes = $DB->get_records('scorm_scoes', array('scorm' => $scorm->id), 'sortorder, id')) {
// Drop keys so that it is a simple array.
$scoes = array_values($scoes);
foreach ($scoes as $sco) {
$def->{($sco->id)} = new stdClass();
$userdata->{($sco->id)} = new stdClass();
$def->{($sco->id)} = get_scorm_default($userdata->{($sco->id)}, $scorm, $sco->id, $attempt, $mode);
// Reconstitute objectives, comments_from_learner and comments_from_lms.
$cmiobj->{($sco->id)} = '';
$currentobj = '';
$count = 0;
foreach ($userdata as $element => $value) {
@ -35,19 +45,22 @@ foreach ($userdata as $element => $value) {
$count++;
$end = strpos($element, $matches[1]) + strlen($matches[1]);
$subelement = substr($element, 0, $end);
$cmiobj .= ' '.$subelement." = new Object();\n";
$cmiobj .= ' '.$subelement.".score = new Object();\n";
$cmiobj .= ' '.$subelement.".score._children = score_children;\n";
$cmiobj .= ' '.$subelement.".score.raw = '';\n";
$cmiobj .= ' '.$subelement.".score.min = '';\n";
$cmiobj .= ' '.$subelement.".score.max = '';\n";
$cmiobj->{($sco->id)} .= ' '.$subelement." = new Object();\n";
$cmiobj->{($sco->id)} .= ' '.$subelement.".score = new Object();\n";
$cmiobj->{($sco->id)} .= ' '.$subelement.".score._children = score_children;\n";
$cmiobj->{($sco->id)} .= ' '.$subelement.".score.raw = '';\n";
$cmiobj->{($sco->id)} .= ' '.$subelement.".score.min = '';\n";
$cmiobj->{($sco->id)} .= ' '.$subelement.".score.max = '';\n";
}
$cmiobj .= ' '.$element.' = \''.$value."';\n";
$cmiobj->{($sco->id)} .= ' '.$element.' = \''.$value."';\n";
}
}
if ($count > 0) {
$cmiobj .= ' cmi.objectives._count = '.$count.";\n";
$cmiobj->{($sco->id)} .= ' cmi.objectives._count = '.$count.";\n";
}
}
}
$PAGE->requires->js_init_call('M.scorm_api.init', array($def, $cmiobj, $scorm->auto, $CFG->wwwroot, $scorm->id, $scoid, $attempt,
$mode, $currentorg, sesskey(), $id));

View file

@ -736,7 +736,7 @@ function LogAPICall(func, nam, val, rc) {
if (func.match(/GetValue/)) {
s += ' - ' + val;
}
s += ' => ' + String(rc);
s += ' => ' + String(rc) + " scoid = " + scorm_current_node.scoid;
AppendToLog(s, rc);
<?php
if (scorm_debugging($scorm) && ($sco->scormtype == 'asset')) {

View file

@ -56,28 +56,32 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
speed_range = '-100#100';
weighting_range = '-100#100';
text_range = '-1#1';
// The SCORM 1.2 data model
var datamodel = {
// Set up data model for each sco
var datamodel = {};
for(scoid in def){
datamodel[scoid] = {
'cmi._children':{'defaultvalue':cmi_children, 'mod':'r', 'writeerror':'402'},
'cmi._version':{'defaultvalue':'3.4', 'mod':'r', 'writeerror':'402'},
'cmi.core._children':{'defaultvalue':core_children, 'mod':'r', 'writeerror':'402'},
'cmi.core.student_id':{'defaultvalue':def['cmi.core.student_id'], 'mod':'r', 'writeerror':'403'},
'cmi.core.student_name':{'defaultvalue':def['cmi.core.student_name'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_location':{'defaultvalue':def['cmi.core.lesson_location'], 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
'cmi.core.credit':{'defaultvalue':def['cmi.core.credit'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_status':{'defaultvalue':def['cmi.core.lesson_status'], 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
'cmi.core.entry':{'defaultvalue':def['cmi.core.entry'], 'mod':'r', 'writeerror':'403'},
'cmi.core.student_id':{'defaultvalue':def[scoid]['cmi.core.student_id'], 'mod':'r', 'writeerror':'403'},
'cmi.core.student_name':{'defaultvalue':def[scoid]['cmi.core.student_name'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_location':{'defaultvalue':def[scoid]['cmi.core.lesson_location'], 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
'cmi.core.credit':{'defaultvalue':def[scoid]['cmi.core.credit'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_status':{'defaultvalue':def[scoid]['cmi.core.lesson_status'], 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
'cmi.core.entry':{'defaultvalue':def[scoid]['cmi.core.entry'], 'mod':'r', 'writeerror':'403'},
'cmi.core.score._children':{'defaultvalue':score_children, 'mod':'r', 'writeerror':'402'},
'cmi.core.score.raw':{'defaultvalue':def['cmi.core.score.raw'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.score.max':{'defaultvalue':def['cmi.core.score.max'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.score.min':{'defaultvalue':def['cmi.core.score.min'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.total_time':{'defaultvalue':def['cmi.core.total_time'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_mode':{'defaultvalue':def['cmi.core.lesson_mode'], 'mod':'r', 'writeerror':'403'},
'cmi.core.exit':{'defaultvalue':def['cmi.core.exit'], 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
'cmi.core.score.raw':{'defaultvalue':def[scoid]['cmi.core.score.raw'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.score.max':{'defaultvalue':def[scoid]['cmi.core.score.max'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.score.min':{'defaultvalue':def[scoid]['cmi.core.score.min'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.core.total_time':{'defaultvalue':def[scoid]['cmi.core.total_time'], 'mod':'r', 'writeerror':'403'},
'cmi.core.lesson_mode':{'defaultvalue':def[scoid]['cmi.core.lesson_mode'], 'mod':'r', 'writeerror':'403'},
'cmi.core.exit':{'defaultvalue':def[scoid]['cmi.core.exit'], 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
'cmi.core.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'00:00:00', 'readerror':'404', 'writeerror':'405'},
'cmi.suspend_data':{'defaultvalue':def['cmi.suspend_data'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
'cmi.launch_data':{'defaultvalue':def['cmi.launch_data'], 'mod':'r', 'writeerror':'403'},
'cmi.comments':{'defaultvalue':def['cmi.comments'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
'cmi.suspend_data':{'defaultvalue':def[scoid]['cmi.suspend_data'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
'cmi.launch_data':{'defaultvalue':def[scoid]['cmi.launch_data'], 'mod':'r', 'writeerror':'403'},
'cmi.comments':{'defaultvalue':def[scoid]['cmi.comments'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
// deprecated evaluation attributes
'cmi.evaluation.comments._count':{'defaultvalue':'0', 'mod':'r', 'writeerror':'402'},
'cmi.evaluation.comments._children':{'defaultvalue':comments_children, 'mod':'r', 'writeerror':'402'},
@ -94,9 +98,9 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
'cmi.objectives.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
'cmi.objectives.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
'cmi.student_data._children':{'defaultvalue':student_data_children, 'mod':'r', 'writeerror':'402'},
'cmi.student_data.mastery_score':{'defaultvalue':def['cmi.student_data.mastery_score'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.max_time_allowed':{'defaultvalue':def['cmi.student_data.max_time_allowed'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.time_limit_action':{'defaultvalue':def['cmi.student_data.time_limit_action'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.mastery_score':{'defaultvalue':def[scoid]['cmi.student_data.mastery_score'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.max_time_allowed':{'defaultvalue':def[scoid]['cmi.student_data.max_time_allowed'], 'mod':'r', 'writeerror':'403'},
'cmi.student_data.time_limit_action':{'defaultvalue':def[scoid]['cmi.student_data.time_limit_action'], 'mod':'r', 'writeerror':'403'},
'cmi.student_preference._children':{'defaultvalue':student_preference_children, 'mod':'r', 'writeerror':'402'},
'cmi.student_preference.audio':{'defaultvalue':'0', 'format':CMISInteger, 'range':audio_range, 'mod':'rw', 'writeerror':'405'},
'cmi.student_preference.language':{'defaultvalue':'', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
@ -117,10 +121,17 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
'nav.event':{'defaultvalue':'', 'format':NAVEvent, 'mod':'w', 'readerror':'404', 'writeerror':'405'}
};
}
var cmi, nav;
function initdatamodel(scoid){
prerequrl = cfgwwwroot + "/mod/scorm/prereqs.php?a="+scormid+"&scoid="+scoid+"&attempt="+attempt+"&mode="+viewmode+"&currentorg="+currentorg+"&sesskey="+sesskey;
datamodelurlparams = "id="+cmid+"&a="+scormid+"&sesskey="+sesskey+"&attempt="+attempt+"&scoid="+scoid;
//
// Datamodel inizialization
//
var cmi = new Object();
cmi = new Object();
cmi.core = new Object();
cmi.core.score = new Object();
cmi.objectives = new Object();
@ -132,24 +143,25 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
cmi.evaluation.comments = new Object();
// Navigation Object
var nav = new Object();
nav = new Object();
for (element in datamodel) {
for (element in datamodel[scoid]) {
if (element.match(/\.n\./) == null) {
if ((typeof eval('datamodel["'+element+'"].defaultvalue')) != 'undefined') {
eval(element+' = datamodel["'+element+'"].defaultvalue;');
if ((typeof eval('datamodel["'+scoid+'"]["'+element+'"].defaultvalue')) != 'undefined') {
eval(element+' = datamodel["'+scoid+'"]["'+element+'"].defaultvalue;');
} else {
eval(element+' = "";');
}
}
}
eval(cmiobj);
eval(cmiint);
eval(cmiobj[scoid]);
eval(cmiint[scoid]);
if (cmi.core.lesson_status == '') {
cmi.core.lesson_status = 'not attempted';
}
}
//
// API Methods definition
@ -157,6 +169,9 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
var Initialized = false;
function LMSInitialize (param) {
scoid = scorm_current_node ? scorm_current_node.scoid : scoid ;
initdatamodel(scoid);
errorCode = "0";
if (param == "") {
if (!Initialized) {
@ -229,8 +244,8 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
if (element !="") {
expression = new RegExp(CMIIndex,'g');
elementmodel = String(element).replace(expression,'.n.');
if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].mod') != 'w') {
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].mod') != 'w') {
element = String(element).replace(expression, "_$1.");
elementIndexes = element.split('.');
subelement = 'cmi';
@ -248,21 +263,21 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
errorCode = "0"; // Need to check if it is the right errorCode
}
} else {
errorCode = eval('datamodel["'+elementmodel+'"].readerror');
errorCode = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].readerror');
}
} else {
childrenstr = '._children';
countstr = '._count';
if (elementmodel.substr(elementmodel.length-childrenstr.length,elementmodel.length) == childrenstr) {
parentmodel = elementmodel.substr(0,elementmodel.length-childrenstr.length);
if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
if ((typeof eval('datamodel["'+scoid+'"]["'+parentmodel+'"]')) != "undefined") {
errorCode = "202";
} else {
errorCode = "201";
}
} else if (elementmodel.substr(elementmodel.length-countstr.length,elementmodel.length) == countstr) {
parentmodel = elementmodel.substr(0,elementmodel.length-countstr.length);
if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
if ((typeof eval('datamodel["'+scoid+'"]["'+parentmodel+'"]')) != "undefined") {
errorCode = "203";
} else {
errorCode = "201";
@ -289,9 +304,9 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
if (element != "") {
expression = new RegExp(CMIIndex,'g');
elementmodel = String(element).replace(expression,'.n.');
if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
expression = new RegExp(eval('datamodel["'+elementmodel+'"].format'));
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].mod') != 'r') {
expression = new RegExp(eval('datamodel["'+scoid+'"]["'+elementmodel+'"].format'));
value = value+'';
matches = value.match(expression);
if (matches != null) {
@ -338,8 +353,8 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
}
//Store data
if (errorCode == "0") {
if ((typeof eval('datamodel["'+elementmodel+'"].range')) != "undefined") {
range = eval('datamodel["'+elementmodel+'"].range');
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"].range')) != "undefined") {
range = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].range');
ranges = range.split('#');
value = value*1.0;
if ((value >= ranges[0]) && (value <= ranges[1])) {
@ -350,7 +365,7 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
}
return "true";
} else {
errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
errorCode = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].writeerror');
}
} else {
if (element == 'cmi.comments') {
@ -366,10 +381,10 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
}
}
} else {
errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
errorCode = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].writeerror');
}
} else {
errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
errorCode = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].writeerror');
}
} else {
errorCode = "201"
@ -535,40 +550,40 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
// check if this specific element is not defined in the datamodel,
// but the generic element name is
if ((eval('typeof datamodel["'+element+'"]')) == "undefined"
&& (eval('typeof datamodel["'+elementmodel+'"]')) != "undefined") {
if ((eval('typeof datamodel["'+scoid+'"]["'+element+'"]')) == "undefined"
&& (eval('typeof datamodel["'+scoid+'"]["'+elementmodel+'"]')) != "undefined") {
// add this specific element to the data model (by cloning
// the generic element) so we can track changes to it
eval('datamodel["'+element+'"]=CloneObj(datamodel["'+elementmodel+'"]);');
eval('datamodel["'+scoid+'"]["'+element+'"]=CloneObj(datamodel["'+scoid+'"]["'+elementmodel+'"]);');
}
// check if the current element exists in the datamodel
if ((typeof eval('datamodel["'+element+'"]')) != "undefined") {
if ((typeof eval('datamodel["'+scoid+'"]["'+element+'"]')) != "undefined") {
// make sure this is not a read only element
if (eval('datamodel["'+element+'"].mod') != 'r') {
if (eval('datamodel["'+scoid+'"]["'+element+'"].mod') != 'r') {
elementstring = '&'+underscore(element)+'='+encodeURIComponent(data[property]);
// check if the element has a default value
if ((typeof eval('datamodel["'+element+'"].defaultvalue')) != "undefined") {
if ((typeof eval('datamodel["'+scoid+'"]["'+element+'"].defaultvalue')) != "undefined") {
// check if the default value is different from the current value
if (eval('datamodel["'+element+'"].defaultvalue') != data[property]
|| eval('typeof(datamodel["'+element+'"].defaultvalue)') != typeof(data[property])) {
if (eval('datamodel["'+scoid+'"]["'+element+'"].defaultvalue') != data[property]
|| eval('typeof(datamodel["'+scoid+'"]["'+element+'"].defaultvalue)') != typeof(data[property])) {
// append the URI fragment to the string we plan to commit
datastring += elementstring;
// update the element default to reflect the current committed value
eval('datamodel["'+element+'"].defaultvalue=data[property];');
eval('datamodel["'+scoid+'"]["'+element+'"].defaultvalue=data[property];');
}
} else {
// append the URI fragment to the string we plan to commit
datastring += elementstring;
// no default value for the element, so set it now
eval('datamodel["'+element+'"].defaultvalue=data[property];');
eval('datamodel["'+scoid+'"]["'+element+'"].defaultvalue=data[property];');
}
}
}
@ -608,7 +623,7 @@ function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebu
}
}
if (cmi.core.lesson_mode == 'browse') {
if (datamodel['cmi.core.lesson_status'].defaultvalue == '' && cmi.core.lesson_status == 'not attempted') {
if (datamodel[scoid]['cmi.core.lesson_status'].defaultvalue == '' && cmi.core.lesson_status == 'not attempted') {
cmi.core.lesson_status = 'browsed';
}
}

View file

@ -18,12 +18,30 @@ require_once($CFG->dirroot.'/mod/scorm/locallib.php');
// Set some vars to use as default values.
$userdata = new stdClass();
$def = get_scorm_default($userdata, $scorm, $scoid, $attempt, $mode);
$def = new stdClass();
$cmiobj = new stdClass();
$cmiint = new stdClass();
if (!isset($currentorg)) {
$currentorg = '';
}
if ($scoes = $DB->get_records('scorm_scoes', array('scorm' => $scorm->id), 'sortorder, id')) {
// Drop keys so that it is a simple array.
$scoes = array_values($scoes);
foreach ($scoes as $sco) {
$def->{($sco->id)} = new stdClass();
$userdata->{($sco->id)} = new stdClass();
$def->{($sco->id)} = get_scorm_default($userdata->{($sco->id)}, $scorm, $sco->id, $attempt, $mode);
// Reconstitute objectives.
$cmiobj->{($sco->id)} = scorm_reconstitute_array_element($scorm->version, $userdata->{($sco->id)},
'cmi.objectives', array('score'));
$cmiint->{($sco->id)} = scorm_reconstitute_array_element($scorm->version, $userdata->{($sco->id)},
'cmi.interactions', array('objectives', 'correct_responses'));
}
}
// If SCORM 1.2 standard mode is disabled allow higher datamodel limits.
if (intval(get_config("scorm", "scorm12standard"))) {
$cmistring256 = '^[\\u0000-\\uFFFF]{0,255}$';
@ -33,10 +51,6 @@ if (intval(get_config("scorm", "scorm12standard"))) {
$cmistring4096 = $cmistring256;
}
// reconstitute objectives
$cmiobj = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.objectives', array('score'));
$cmiint = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.interactions', array('objectives', 'correct_responses'));
$PAGE->requires->js_init_call('M.scorm_api.init', array($def, $cmiobj, $cmiint, $cmistring256, $cmistring4096,
scorm_debugging($scorm), $scorm->auto, $scorm->id, $CFG->wwwroot,
sesskey(), $scoid, $attempt, $mode, $id, $currentorg));

View file

@ -150,7 +150,10 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
}
// The SCORM 1.3 data model
var datamodel = {
// Set up data model for each sco
var datamodel = {};
for(scoid in def){
datamodel[scoid] = {
'cmi._children':{'defaultvalue':cmi_children, 'mod':'r'},
'cmi._version':{'defaultvalue':'1.0', 'mod':'r'},
'cmi.comments_from_learner._children':{'defaultvalue':comments_children, 'mod':'r'},
@ -163,11 +166,11 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
'cmi.comments_from_lms.n.comment':{'format':CMILangString4000, 'mod':'r'},
'cmi.comments_from_lms.n.location':{'format':CMIString250, 'mod':'r'},
'cmi.comments_from_lms.n.timestamp':{'format':CMITime, 'mod':'r'},
'cmi.completion_status':{'defaultvalue':def['cmi.completion_status'], 'format':CMICStatus, 'mod':'rw'},
'cmi.completion_threshold':{'defaultvalue':def['cmi.completion_threshold'], 'mod':'r'},
'cmi.credit':{'defaultvalue':def['cmi.credit'], 'mod':'r'},
'cmi.entry':{'defaultvalue':def['cmi.entry'], 'mod':'r'},
'cmi.exit':{'defaultvalue':def['cmi.exit'], 'format':CMIExit, 'mod':'w'},
'cmi.completion_status':{'defaultvalue':def[scoid]['cmi.completion_status'], 'format':CMICStatus, 'mod':'rw'},
'cmi.completion_threshold':{'defaultvalue':def[scoid]['cmi.completion_threshold'], 'mod':'r'},
'cmi.credit':{'defaultvalue':def[scoid]['cmi.credit'], 'mod':'r'},
'cmi.entry':{'defaultvalue':def[scoid]['cmi.entry'], 'mod':'r'},
'cmi.exit':{'defaultvalue':def[scoid]['cmi.exit'], 'format':CMIExit, 'mod':'w'},
'cmi.interactions._children':{'defaultvalue':interactions_children, 'mod':'r'},
'cmi.interactions._count':{'mod':'r', 'defaultvalue':'0'},
'cmi.interactions.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'},
@ -182,17 +185,17 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
'cmi.interactions.n.result':{'pattern':CMIIndex, 'format':CMIResult, 'mod':'rw'},
'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'rw'},
'cmi.interactions.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'},
'cmi.launch_data':{'defaultvalue':def['cmi.exit'], 'mod':'r'},
'cmi.learner_id':{'defaultvalue':def['cmi.learner_id'], 'mod':'r'},
'cmi.learner_name':{'defaultvalue':def['cmi.learner_name'], 'mod':'r'},
'cmi.launch_data':{'defaultvalue':def[scoid]['cmi.exit'], 'mod':'r'},
'cmi.learner_id':{'defaultvalue':def[scoid]['cmi.learner_id'], 'mod':'r'},
'cmi.learner_name':{'defaultvalue':def[scoid]['cmi.learner_name'], 'mod':'r'},
'cmi.learner_preference._children':{'defaultvalue':student_preference_children, 'mod':'r'},
'cmi.learner_preference.audio_level':{'defaultvalue':def['cmi.learner_preference.audio_level'], 'format':CMIDecimal, 'range':audio_range, 'mod':'rw'},
'cmi.learner_preference.language':{'defaultvalue':def['cmi.learner_preference.language'], 'format':CMILang, 'mod':'rw'},
'cmi.learner_preference.delivery_speed':{'defaultvalue':def['cmi.learner_preference.delivery_speed'], 'format':CMIDecimal, 'range':speed_range, 'mod':'rw'},
'cmi.learner_preference.audio_captioning':{'defaultvalue':def['cmi.learner_preference.audio_captioning'], 'format':CMISInteger, 'range':text_range, 'mod':'rw'},
'cmi.location':{'defaultvalue':def['cmi.location'], 'format':CMIString1000, 'mod':'rw'},
'cmi.max_time_allowed':{'defaultvalue':def['cmi.max_time_allowed'], 'mod':'r'},
'cmi.mode':{'defaultvalue':def['cmi.mode'], 'mod':'r'},
'cmi.learner_preference.audio_level':{'defaultvalue':def[scoid]['cmi.learner_preference.audio_level'], 'format':CMIDecimal, 'range':audio_range, 'mod':'rw'},
'cmi.learner_preference.language':{'defaultvalue':def[scoid]['cmi.learner_preference.language'], 'format':CMILang, 'mod':'rw'},
'cmi.learner_preference.delivery_speed':{'defaultvalue':def[scoid]['cmi.learner_preference.delivery_speed'], 'format':CMIDecimal, 'range':speed_range, 'mod':'rw'},
'cmi.learner_preference.audio_captioning':{'defaultvalue':def[scoid]['cmi.learner_preference.audio_captioning'], 'format':CMISInteger, 'range':text_range, 'mod':'rw'},
'cmi.location':{'defaultvalue':def[scoid]['cmi.location'], 'format':CMIString1000, 'mod':'rw'},
'cmi.max_time_allowed':{'defaultvalue':def[scoid]['cmi.max_time_allowed'], 'mod':'r'},
'cmi.mode':{'defaultvalue':def[scoid]['cmi.mode'], 'mod':'r'},
'cmi.objectives._children':{'defaultvalue':objectives_children, 'mod':'r'},
'cmi.objectives._count':{'mod':'r', 'defaultvalue':'0'},
'cmi.objectives.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'},
@ -205,24 +208,31 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
'cmi.objectives.n.completion_status':{'defaultvalue':'unknown', 'pattern':CMIIndex, 'format':CMICStatus, 'mod':'rw'},
'cmi.objectives.n.progress_measure':{'defaultvalue':null, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
'cmi.objectives.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'},
'cmi.progress_measure':{'defaultvalue':def['cmi.progress_measure'], 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
'cmi.scaled_passing_score':{'defaultvalue':def['cmi.scaled_passing_score'], 'format':CMIDecimal, 'range':scaled_range, 'mod':'r'},
'cmi.progress_measure':{'defaultvalue':def[scoid]['cmi.progress_measure'], 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
'cmi.scaled_passing_score':{'defaultvalue':def[scoid]['cmi.scaled_passing_score'], 'format':CMIDecimal, 'range':scaled_range, 'mod':'r'},
'cmi.score._children':{'defaultvalue':score_children, 'mod':'r'},
'cmi.score.scaled':{'defaultvalue':def['cmi.score.scaled'], 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'},
'cmi.score.raw':{'defaultvalue':def['cmi.score.raw'], 'format':CMIDecimal, 'mod':'rw'},
'cmi.score.min':{'defaultvalue':def['cmi.score.min'], 'format':CMIDecimal, 'mod':'rw'},
'cmi.score.max':{'defaultvalue':def['cmi.score.max'], 'format':CMIDecimal, 'mod':'rw'},
'cmi.score.scaled':{'defaultvalue':def[scoid]['cmi.score.scaled'], 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'},
'cmi.score.raw':{'defaultvalue':def[scoid]['cmi.score.raw'], 'format':CMIDecimal, 'mod':'rw'},
'cmi.score.min':{'defaultvalue':def[scoid]['cmi.score.min'], 'format':CMIDecimal, 'mod':'rw'},
'cmi.score.max':{'defaultvalue':def[scoid]['cmi.score.max'], 'format':CMIDecimal, 'mod':'rw'},
'cmi.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'PT0H0M0S'},
'cmi.success_status':{'defaultvalue':def['cmi.success_status'], 'format':CMISStatus, 'mod':'rw'},
'cmi.suspend_data':{'defaultvalue':def['cmi.suspend_data'], 'format':CMIString64000, 'mod':'rw'},
'cmi.time_limit_action':{'defaultvalue':def['cmi.time_limit_action'], 'mod':'r'},
'cmi.total_time':{'defaultvalue':def['cmi.total_time'], 'mod':'r'},
'cmi.success_status':{'defaultvalue':def[scoid]['cmi.success_status'], 'format':CMISStatus, 'mod':'rw'},
'cmi.suspend_data':{'defaultvalue':def[scoid]['cmi.suspend_data'], 'format':CMIString64000, 'mod':'rw'},
'cmi.time_limit_action':{'defaultvalue':def[scoid]['cmi.time_limit_action'], 'mod':'r'},
'cmi.total_time':{'defaultvalue':def[scoid]['cmi.total_time'], 'mod':'r'},
'adl.nav.request':{'defaultvalue':'_none_', 'format':NAVEvent, 'mod':'rw'}
};
}
var cmi, adl;
function initdatamodel(scoid){
prerequrl = cfgwwwroot + "/mod/scorm/prereqs.php?a="+scormid+"&scoid="+scoid+"&attempt="+attempt+"&mode="+viewmode+"&currentorg="+currentorg+"&sesskey="+sesskey;
datamodelurlparams = "id="+cmid+"&a="+scormid+"&sesskey="+sesskey+"&attempt="+attempt+"&scoid="+scoid;
//
// Datamodel inizialization
//
var cmi = new Object();
cmi = new Object();
cmi.comments_from_learner = new Object();
cmi.comments_from_learner._count = 0;
cmi.comments_from_lms = new Object();
@ -235,28 +245,29 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
cmi.score = new Object();
// Navigation Object
var adl = new Object();
adl = new Object();
adl.nav = new Object();
adl.nav.request_valid = new Array();
for (element in datamodel) {
for (element in datamodel[scoid]) {
if (element.match(/\.n\./) == null) {
if ((typeof eval('datamodel["'+element+'"].defaultvalue')) != 'undefined') {
eval(element+' = datamodel["'+element+'"].defaultvalue;');
if ((typeof eval('datamodel["'+scoid+'"]["'+element+'"].defaultvalue')) != 'undefined') {
eval(element+' = datamodel["'+scoid+'"]["'+element+'"].defaultvalue;');
} else {
eval(element+' = "";');
}
}
}
eval(cmiobj);
eval(cmiint);
eval(cmicommentsuser);
eval(cmicommentslms);
eval(cmiobj[scoid]);
eval(cmiint[scoid]);
eval(cmicommentsuser[scoid]);
eval(cmicommentslms[scoid]);
if (cmi.completion_status == '') {
cmi.completion_status = 'not attempted';
}
}
//
// API Methods definition
@ -267,6 +278,9 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
var errorCode = "0";
function Initialize (param) {
scoid = scorm_current_node ? scorm_current_node.scoid : scoid ;
initdatamodel(scoid);
errorCode = "0";
if (param == "") {
if ((!Initialized) && (!Terminated)) {
@ -365,8 +379,8 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
if (element !="") {
var expression = new RegExp(CMIIndex,'g');
var elementmodel = String(element).replace(expression,'.n.');
if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].mod') != 'w') {
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].mod') != 'w') {
element = String(element).replace(/\.(\d+)\./, ".N$1.");
element = element.replace(/\.(\d+)\./, ".N$1.");
@ -393,7 +407,7 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
errorCode = "301";
}
} else {
//errorCode = eval('datamodel["'+elementmodel+'"].readerror');
//errorCode = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].readerror');
errorCode = "405";
}
} else {
@ -402,7 +416,7 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
var parentmodel = '';
if (elementmodel.substr(elementmodel.length-childrenstr.length,elementmodel.length) == childrenstr) {
parentmodel = elementmodel.substr(0,elementmodel.length-childrenstr.length);
if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
if ((typeof eval('datamodel["'+scoid+'"]["'+parentmodel+'"]')) != "undefined") {
errorCode = "301";
diagnostic = "Data Model Element Does Not Have Children";
} else {
@ -410,7 +424,7 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
}
} else if (elementmodel.substr(elementmodel.length-countstr.length,elementmodel.length) == countstr) {
parentmodel = elementmodel.substr(0,elementmodel.length-countstr.length);
if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
if ((typeof eval('datamodel["'+scoid+'"]["'+parentmodel+'"]')) != "undefined") {
errorCode = "301";
diagnostic = "Data Model Element Cannot Have Count";
} else {
@ -458,10 +472,10 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
if (element != "") {
var expression = new RegExp(CMIIndex,'g');
var elementmodel = String(element).replace(expression,'.n.');
if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
if (eval('datamodel["'+elementmodel+'"].format') != 'CMIFeedback') {
expression = new RegExp(eval('datamodel["'+elementmodel+'"].format'));
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].mod') != 'r') {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].format') != 'CMIFeedback') {
expression = new RegExp(eval('datamodel["'+scoid+'"]["'+elementmodel+'"].format'));
} else {
// cmi.interactions.n.type depending format accept everything at this stage
expression = new RegExp(CMIFeedback);
@ -517,15 +531,15 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
eval(parentelement+'._count++;');
eval(subelement+' = new Object();');
var subobject = eval(subelement);
subobject.success_status = datamodel["cmi.objectives.n.success_status"].defaultvalue;
subobject.completion_status = datamodel["cmi.objectives.n.completion_status"].defaultvalue;
subobject.progress_measure = datamodel["cmi.objectives.n.progress_measure"].defaultvalue;
subobject.success_status = datamodel[scoid]["cmi.objectives.n.success_status"].defaultvalue;
subobject.completion_status = datamodel[scoid]["cmi.objectives.n.completion_status"].defaultvalue;
subobject.progress_measure = datamodel[scoid]["cmi.objectives.n.progress_measure"].defaultvalue;
subobject.score = new Object();
subobject.score._children = score_children;
subobject.score.scaled = datamodel["cmi.objectives.n.score.scaled"].defaultvalue;
subobject.score.raw = datamodel["cmi.objectives.n.score.raw"].defaultvalue;
subobject.score.min = datamodel["cmi.objectives.n.score.min"].defaultvalue;
subobject.score.max = datamodel["cmi.objectives.n.score.max"].defaultvalue;
subobject.score.scaled = datamodel[scoid]["cmi.objectives.n.score.scaled"].defaultvalue;
subobject.score.raw = datamodel[scoid]["cmi.objectives.n.score.raw"].defaultvalue;
subobject.score.min = datamodel[scoid]["cmi.objectives.n.score.min"].defaultvalue;
subobject.score.max = datamodel[scoid]["cmi.objectives.n.score.max"].defaultvalue;
}
} else {
errorCode="351";
@ -731,8 +745,8 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
//Store data
if (errorCode == "0") {
if ((typeof eval('datamodel["'+elementmodel+'"].range')) != "undefined") {
range = eval('datamodel["'+elementmodel+'"].range');
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"].range')) != "undefined") {
range = eval('datamodel["'+scoid+'"]["'+elementmodel+'"].range');
ranges = range.split('#');
value = value*1.0;
if (value >= ranges[0]) {
@ -1068,12 +1082,12 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
}
function getElementModel(element) {
if (typeof datamodel[element] != "undefined") {
if (typeof datamodel[scoid][element] != "undefined") {
return element;
} else {
var expression = new RegExp(CMIIndex,'g');
var elementmodel = String(element).replace(expression,'.n.');
if (typeof datamodel[elementmodel] != "undefined") {
if (typeof datamodel[scoid][elementmodel] != "undefined") {
return elementmodel;
}
}
@ -1161,11 +1175,11 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
var element = parent+'.'+property;
var expression = new RegExp(CMIIndexStore,'g');
var elementmodel = String(element).replace(expression,'.n.');
if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"]')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].mod') != 'r') {
var elementstring = '&'+underscore(element)+'='+encodeURIComponent(data[property]);
if ((typeof eval('datamodel["'+elementmodel+'"].defaultvalue')) != "undefined") {
if (eval('datamodel["'+elementmodel+'"].defaultvalue') != data[property] || eval('typeof(datamodel["'+elementmodel+'"].defaultvalue)') != typeof(data[property])) {
if ((typeof eval('datamodel["'+scoid+'"]["'+elementmodel+'"].defaultvalue')) != "undefined") {
if (eval('datamodel["'+scoid+'"]["'+elementmodel+'"].defaultvalue') != data[property] || eval('typeof(datamodel["'+scoid+'"]["'+elementmodel+'"].defaultvalue)') != typeof(data[property])) {
datastring += elementstring;
}
} else {
@ -1203,7 +1217,7 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
}
datastring += CollectData(data,'cmi');
var element = 'adl.nav.request';
var navrequest = eval(element) != datamodel[element].defaultvalue ? '&'+underscore(element)+'='+encodeURIComponent(eval(element)) : '';
var navrequest = eval(element) != datamodel[scoid][element].defaultvalue ? '&'+underscore(element)+'='+encodeURIComponent(eval(element)) : '';
datastring += navrequest;
var myRequest = NewHttpReq();

View file

@ -17,24 +17,43 @@
require_once($CFG->dirroot.'/mod/scorm/locallib.php');
$userdata = new stdClass();
$def = get_scorm_default($userdata, $scorm, $scoid, $attempt, $mode);
$def = new stdClass();
$cmiobj = new stdClass();
$cmiint = new stdClass();
$cmicommentsuser = new stdClass();
$cmicommentslms = new stdClass();
if (!isset($currentorg)) {
$currentorg = '';
}
// reconstitute objectives, comments_from_learner and comments_from_lms
$cmiobj = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.objectives', array('score'));
$cmiint = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.interactions', array('objectives', 'correct_responses'));
$cmicommentsuser = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_learner', array());
$cmicommentslms = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_lms', array());
if ($scoes = $DB->get_records('scorm_scoes', array('scorm' => $scorm->id), 'sortorder, id')) {
// Drop keys so that it is a simple array.
$scoes = array_values($scoes);
foreach ($scoes as $sco) {
$def->{($sco->id)} = new stdClass();
$userdata->{($sco->id)} = new stdClass();
$def->{($sco->id)} = get_scorm_default($userdata->{($sco->id)}, $scorm, $sco->id, $attempt, $mode);
// Reconstitute objectives, comments_from_learner and comments_from_lms.
$cmiobj->{($sco->id)} = scorm_reconstitute_array_element($scorm->version, $userdata->{($sco->id)},
'cmi.objectives', array('score'));
$cmiint->{($sco->id)} = scorm_reconstitute_array_element($scorm->version, $userdata->{($sco->id)},
'cmi.interactions', array('objectives', 'correct_responses'));
$cmicommentsuser->{($sco->id)} = scorm_reconstitute_array_element($scorm->version, $userdata->{($sco->id)},
'cmi.comments_from_learner', array());
$cmicommentslms->{($sco->id)} = scorm_reconstitute_array_element($scorm->version, $userdata->{($sco->id)},
'cmi.comments_from_lms', array());
}
}
$PAGE->requires->js_init_call('M.scorm_api.init', array($def, $cmiobj, $cmiint, $cmicommentsuser, $cmicommentslms,
scorm_debugging($scorm), $scorm->auto, $scorm->id, $CFG->wwwroot,
sesskey(), $scoid, $attempt, $mode, $id, $currentorg));
// pull in the debugging utilities
// Pull in the debugging utilities.
if (scorm_debugging($scorm)) {
require_once($CFG->dirroot.'/mod/scorm/datamodels/debug.js.php');
echo html_writer::script('AppendToLog("Moodle SCORM 1.3 API Loaded, Activity: '.$scorm->name.', SCO: '.$sco->identifier.'", 0);');

View file

@ -909,7 +909,7 @@ function scorm_view_display ($user, $scorm, $action, $cm) {
}
} else if (!empty($attemptcount) && ($incomplete === false) && (($result->attemptleft > 0)||($scorm->maxattempt == 0))) {
echo html_writer::empty_tag('br');
echo html_writer::checkbox('newattempt', '', false, '', array('id' => 'a'));
echo html_writer::checkbox('newattempt', 'on', false, '', array('id' => 'a'));
echo html_writer::label(get_string('newattempt', 'scorm'), 'a');
}
if (!empty($scorm->popup)) {

View file

@ -27,6 +27,8 @@ mod_scorm_activate_item = null;
mod_scorm_parse_toc_tree = null;
scorm_layout_widget = null;
window.scorm_current_node = null;
function underscore(str) {
str = String(str).replace(/.N/g,".");
return str.replace(/\./g,"__");
@ -48,7 +50,6 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
}
scoes_nav = Y.JSON.parse(scoes_nav);
var scorm_current_node;
var scorm_buttons = [];
var scorm_bloody_labelclick = false;
var scorm_nav_panel;
@ -124,15 +125,23 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
return;
}
// Check if the item is already active, avoid recursive calls.
if (Y.one('#scorm_object')) {
var content = Y.one('#scorm_content');
var old = Y.one('#scorm_object');
if (old) {
var scorm_active_url = Y.one('#scorm_object').getAttribute('src');
var node_full_url = M.cfg.wwwroot + '/mod/scorm/loadSCO.php?' + node.title;
if (node_full_url === scorm_active_url) {
return;
}
// Start to unload iframe here
if(!window_name){
content.removeChild(old);
old = null;
}
}
// End of - Avoid recursive calls.
scorm_current_node = node;
// Avoid recursive calls.
if (!scorm_current_node.state.selected) {
scorm_current_node.select();
}
@ -144,7 +153,6 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
el_old_api.parentNode.removeChild(el_old_api);
}
var content = Y.one('#scorm_content');
var obj = document.createElement('iframe');
obj.setAttribute('id', 'scorm_object');
obj.setAttribute('type', 'text/html');
@ -159,7 +167,6 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
mine.close();
}
var old = Y.one('#scorm_object');
if (old) {
if(window_name) {
var cwidth = scormplayerdata.cwidth;
@ -167,8 +174,6 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
var poptions = scormplayerdata.popupoptions;
poptions = poptions + ',resizable=yes'; // Added for IE (MDL-32506).
scorm_openpopup(M.cfg.wwwroot + "/mod/scorm/loadSCO.php?" + node.title, window_name, poptions, cwidth, cheight);
} else {
content.replaceChild(obj, old);
}
} else {
content.prepend(obj);
@ -577,14 +582,18 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
if (node.title == '' || node.title == null) {
return; //this item has no navigation
}
// If item is already active, return; avoid recursive calls.
if (Y.one('#scorm_data')) {
var scorm_active_url = Y.one('#scorm_object').getAttribute('src');
if (obj = Y.one('#scorm_object')) {
var scorm_active_url = obj.getAttribute('src');
var node_full_url = M.cfg.wwwroot + '/mod/scorm/loadSCO.php?' + node.title;
if (node_full_url === scorm_active_url) {
return;
}
} else if(scorm_current_node == node){
return;
}
// Update launch_sco.
if (typeof node.scoid !== 'undefined') {
launch_sco = node.scoid;