c32789869b538138f0df2efb09e47a3de0c4bb0d
[moodle.git] / mod / scorm / datamodels / aicc.js.php
1 <?php
2     if (isset($userdata->status)) {
3         if ($userdata->status == '') {
4             $userdata->entry = 'ab-initio';
5         } else {
6             if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
7                 $userdata->entry = 'resume';
8             } else {
9                 $userdata->entry = '';
10             }
11         }
12     }
13 ?>
14 //
15 // SCORM 1.2 API Implementation
16 //
17 function AICCapi() {
18     // Standard Data Type Definition
19     CMIString256 = '^.{0,255}$';
20     CMIString4096 = '^.{0,4096}$';
21     CMITime = '^([0-2]{1}[0-9]{1}):([0-5]{1}[0-9]{1}):([0-5]{1}[0-9]{1})(\.[0-9]{1,2})?$';
22     CMITimespan = '^([0-9]{2,4}):([0-9]{2}):([0-9]{2})(\.[0-9]{1,2})?$';
23     CMIInteger = '^\\d+$';
24     CMISInteger = '^-?([0-9]+)$';
25     CMIDecimal = '^-?([0-9]{0,3})(\.[0-9]{1,2})?$';
26     CMIIdentifier = '^\\w{1,255}$';
27     CMIFeedback = CMIString256; // This must be redefined
28     CMIIndex = '[._](\\d+).';
30     // Vocabulary Data Type Definition
31     CMIStatus = '^passed$|^completed$|^failed$|^incomplete$|^browsed$';
32     CMIStatus2 = '^passed$|^completed$|^failed$|^incomplete$|^browsed$|^not attempted$';
33     CMIExit = '^time-out$|^suspend$|^logout$|^$';
34     CMIType = '^true-false$|^choice$|^fill-in$|^matching$|^performance$|^sequencing$|^likert$|^numeric$';
35     CMIResult = '^correct$|^wrong$|^unanticipated$|^neutral$|^([0-9]{0,3})?(\.[0-9]{1,2})?$';
36     NAVEvent = '^previous$|^continue$';
38     // Children lists
39     cmi_children = 'core, suspend_data, launch_data, comments, objectives, student_data, student_preference, interactions';
40     core_children = 'student_id, student_name, lesson_location, credit, lesson_status, entry, score, total_time, lesson_mode, exit, session_time';
41     score_children = 'raw, min, max';
42     comments_children = 'content, location, time';
43     objectives_children = 'id, score, status';
44     student_data_children = 'attempt_number, tries, mastery_score, max_time_allowed, time_limit_action';
45     student_preference_children = 'audio, language, speed, text';
46     interactions_children = 'id, objectives, time, type, correct_responses, weighting, student_response, result, latency';
48     // Data ranges
49     score_range = '0#100';
50     audio_range = '-1#100';
51     speed_range = '-100#100';
52     weighting_range = '-100#100';
53     text_range = '-1#1';
55     // The AICC data model
56     var datamodel =  {
57         'cmi._children':{'defaultvalue':cmi_children, 'mod':'r', 'writeerror':'402'},
58         'cmi._version':{'defaultvalue':'3.4', 'mod':'r', 'writeerror':'402'},
59         'cmi.core._children':{'defaultvalue':core_children, 'mod':'r', 'writeerror':'402'},
60         'cmi.core.student_id':{'defaultvalue':'<?php echo $userdata->student_id ?>', 'mod':'r', 'writeerror':'403'},
61         'cmi.core.student_name':{'defaultvalue':'<?php echo $userdata->student_name ?>', 'mod':'r', 'writeerror':'403'},
62         'cmi.core.lesson_location':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_location'})?$userdata->{'cmi.core.lesson_location'}:'' ?>', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
63         'cmi.core.credit':{'defaultvalue':'<?php echo $userdata->credit ?>', 'mod':'r', 'writeerror':'403'},
64         'cmi.core.lesson_status':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_status'})?$userdata->{'cmi.core.lesson_status'}:'' ?>', 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
65         'cmi.core.exit':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.exit'})?$userdata->{'cmi.core.exit'}:'' ?>', 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
66         'cmi.core.entry':{'defaultvalue':'<?php echo $userdata->entry ?>', 'mod':'r', 'writeerror':'403'},
67         'cmi.core.score._children':{'defaultvalue':score_children, 'mod':'r', 'writeerror':'402'},
68         'cmi.core.score.raw':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.raw'})?$userdata->{'cmi.core.score.raw'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
69         'cmi.core.score.max':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.max'})?$userdata->{'cmi.core.score.max'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
70         'cmi.core.score.min':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.min'})?$userdata->{'cmi.core.score.min'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
71         'cmi.core.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'00:00:00', 'readerror':'404', 'writeerror':'405'},
72         'cmi.core.total_time':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.total_time'})?$userdata->{'cmi.core.total_time'}:'00:00:00' ?>', 'mod':'r', 'writeerror':'403'},
73         'cmi.core.lesson_mode':{'defaultvalue':'<?php echo $userdata->mode ?>', 'mod':'r', 'writeerror':'403'},
74         'cmi.suspend_data':{'defaultvalue':'<?php echo isset($userdata->{'cmi.suspend_data'})?$userdata->{'cmi.suspend_data'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
75         'cmi.launch_data':{'defaultvalue':'<?php echo isset($userdata->datafromlms)?$userdata->datafromlms:'' ?>', 'mod':'r', 'writeerror':'403'},
76         'cmi.comments':{'defaultvalue':'<?php echo isset($userdata->{'cmi.comments'})?$userdata->{'cmi.comments'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
77         // deprecated evaluation attributes
78         'cmi.evaluation.comments._count':{'defaultvalue':'0', 'mod':'r', 'writeerror':'402'},
79         'cmi.evaluation.comments._children':{'defaultvalue':comments_children, 'mod':'r', 'writeerror':'402'},
80         'cmi.evaluation.comments.n.content':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
81         'cmi.evaluation.comments.n.location':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
82         'cmi.evaluation.comments.n.time':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMITime, 'mod':'rw', 'writeerror':'405'},
83         'cmi.comments_from_lms':{'mod':'r', 'writeerror':'403'},
84         'cmi.objectives._children':{'defaultvalue':objectives_children, 'mod':'r', 'writeerror':'402'},
85         'cmi.objectives._count':{'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
86         'cmi.objectives.n.id':{'pattern':CMIIndex, 'format':CMIIdentifier, 'mod':'rw', 'writeerror':'405'},
87         'cmi.objectives.n.score._children':{'pattern':CMIIndex, 'mod':'r', 'writeerror':'402'},
88         'cmi.objectives.n.score.raw':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
89         'cmi.objectives.n.score.min':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
90         'cmi.objectives.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
91         'cmi.objectives.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
92         'cmi.student_data._children':{'defaultvalue':student_data_children, 'mod':'r', 'writeerror':'402'},
93         'cmi.student_data.attempt_number':{'defaultvalue':'<?php echo isset($userdata->{'cmi.student_data.attempt_number'})?$userdata->{'cmi.student_data.attempt_number'}:'' ?>', 'mod':'r', 'writeerror':'402'},
94         'cmi.student_data.tries.n.score.raw':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
95         'cmi.student_data.tries.n.score.min':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
96         'cmi.student_data.tries.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
97         'cmi.student_data.tries.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
98         'cmi.student_data.tries.n.time':{'pattern':CMIIndex, 'format':CMITime, 'mod':'rw', 'writeerror':'405'},
99         'cmi.student_data.mastery_score':{'defaultvalue':'<?php echo isset($userdata->mastery_score)?$userdata->mastery_score:'' ?>', 'mod':'r', 'writeerror':'403'},
100         'cmi.student_data.max_time_allowed':{'defaultvalue':'<?php echo isset($userdata->max_time_allowed)?$userdata->max_time_allowed:'' ?>', 'mod':'r', 'writeerror':'403'},
101         'cmi.student_data.time_limit_action':{'defaultvalue':'<?php echo isset($userdata->time_limit_action)?$userdata->time_limit_action:'' ?>', 'mod':'r', 'writeerror':'403'},
102         'cmi.student_data.tries_during_lesson':{'defaultvalue':'<?php echo isset($userdata->{'cmi.student_data.tries_during_lesson'})?$userdata->{'cmi.student_data.tries_during_lesson'}:'' ?>', 'mod':'r', 'writeerror':'402'},
103         'cmi.student_preference._children':{'defaultvalue':student_preference_children, 'mod':'r', 'writeerror':'402'},
104         'cmi.student_preference.audio':{'defaultvalue':'0', 'format':CMISInteger, 'range':audio_range, 'mod':'rw', 'writeerror':'405'},
105         'cmi.student_preference.language':{'defaultvalue':'', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
106         'cmi.student_preference.speed':{'defaultvalue':'0', 'format':CMISInteger, 'range':speed_range, 'mod':'rw', 'writeerror':'405'},
107         'cmi.student_preference.text':{'defaultvalue':'0', 'format':CMISInteger, 'range':text_range, 'mod':'rw', 'writeerror':'405'},
108         'cmi.interactions._children':{'defaultvalue':interactions_children, 'mod':'r', 'writeerror':'402'},
109         'cmi.interactions._count':{'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
110         'cmi.interactions.n.id':{'pattern':CMIIndex, 'format':CMIIdentifier, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
111         'cmi.interactions.n.objectives._count':{'pattern':CMIIndex, 'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
112         'cmi.interactions.n.objectives.n.id':{'pattern':CMIIndex, 'format':CMIIdentifier, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
113         'cmi.interactions.n.time':{'pattern':CMIIndex, 'format':CMITime, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
114         'cmi.interactions.n.type':{'pattern':CMIIndex, 'format':CMIType, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
115         'cmi.interactions.n.correct_responses._count':{'pattern':CMIIndex, 'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
116         'cmi.interactions.n.correct_responses.n.pattern':{'pattern':CMIIndex, 'format':CMIFeedback, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
117         'cmi.interactions.n.weighting':{'pattern':CMIIndex, 'format':CMIDecimal, 'range':weighting_range, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
118         'cmi.interactions.n.student_response':{'pattern':CMIIndex, 'format':CMIFeedback, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
119         'cmi.interactions.n.result':{'pattern':CMIIndex, 'format':CMIResult, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
120         'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
121         'nav.event':{'defaultvalue':'', 'format':NAVEvent, 'mod':'w', 'readerror':'404', 'writeerror':'405'}
122     };
124     //
125     // Datamodel inizialization
126     //
127     var cmi = new Object();
128         cmi.core = new Object();
129         cmi.core.score = new Object();
130         cmi.objectives = new Object();
131         cmi.student_data = new Object();
132         cmi.student_preference = new Object();
133         cmi.interactions = new Object();
134         // deprecated evaluation attributes
135         cmi.evaluation = new Object();
136         cmi.evaluation.comments = new Object();
138     // Navigation Object
139     var nav = new Object();
141     for (element in datamodel) {
142         if (element.match(/\.n\./) == null) {
143             if ((typeof eval('datamodel["'+element+'"].defaultvalue')) != 'undefined') {
144                 eval(element+' = datamodel["'+element+'"].defaultvalue;');
145             } else {
146                 eval(element+' = "";');
147             }
148         }
149     }
151 <?php
152     $current_objective = '';
153     $count = 0;
154     $objectives = '';
155     foreach($userdata as $element => $value){
156         if (substr($element,0,14) == 'cmi.objectives') {
157             $element = preg_replace('/\.(\d+)\./', "_\$1.", $element);
158             preg_match('/\_(\d+)\./', $element, $matches);
159             if (count($matches) > 0 && $current_objective != $matches[1]) {
160                 $current_objective = $matches[1];
161                 $count++;
162                 $end = strpos($element,$matches[1])+strlen($matches[1]);
163                 $subelement = substr($element,0,$end);
164                 echo '    '.$subelement." = new Object();\n";
165                 echo '    '.$subelement.".score = new Object();\n";
166                 echo '    '.$subelement.".score._children = score_children;\n";
167                 echo '    '.$subelement.".score.raw = '';\n";
168                 echo '    '.$subelement.".score.min = '';\n";
169                 echo '    '.$subelement.".score.max = '';\n";
170             }
171             echo '    '.$element.' = \''.$value."';\n";
172         }
173     }
174     if ($count > 0) {
175         echo '    cmi.objectives._count = '.$count.";\n";
176     }
177 ?>
179     if (cmi.core.lesson_status == '') {
180         cmi.core.lesson_status = 'not attempted';
181     }
183     //
184     // API Methods definition
185     //
186     var Initialized = false;
188     function LMSInitialize (param) {
189         errorCode = "0";
190         if (param == "") {
191             if (!Initialized) {
192                 Initialized = true;
193                 errorCode = "0";
194                 return "true";
195             } else {
196                 errorCode = "101";
197             }
198         } else {
199             errorCode = "201";
200         }
201         return "false";
202     }
205     this.connectPrereqCallback = {
207         success: function(o) {
208             scorm_tree_node = YAHOO.widget.TreeView.getTree('scorm_tree');
209             if (o.responseText !== undefined) {
210                 if (scorm_tree_node && o.responseText) {
211                     var hnode = scorm_tree_node.getHighlightedNode();
212                     var hidx = null;
213                     if (hnode) {
214                         hidx = hnode.index + scorm_tree_node.getNodeCount();
215                     }
216                     // all gone
217                     var root_node = scorm_tree_node.getRoot();
218                         scorm_tree_node.removeNode(root_node.children[0]);
219                     }
220                     // make sure the temporary tree element is not there
221                     var el_old_tree = document.getElementById('scormtree123');
222                     if (el_old_tree) {
223                         el_old_tree.parentNode.removeChild(el_old_tree);
224                     }
225                     var el_new_tree = document.createElement('div');
226                     var pagecontent = document.getElementById("page-content");
227                     el_new_tree.setAttribute('id','scormtree123');
228                     el_new_tree.innerHTML = o.responseText;
229                     // make sure it doesnt show
230                     el_new_tree.style.display = 'none';
231                     pagecontent.appendChild(el_new_tree)
232                     // ignore the first level element as this is the title
233                     scorm_tree_node.buildTreeFromMarkup(el_new_tree.firstChild.firstChild);
234                     var el = document.getElementById('scormtree123');
235                     el.parentNode.removeChild(el);
236                     scorm_tree_node.expandAll();
237                     scorm_tree_node.render();
238                     if (hidx != null) {
239                         hnode = scorm_tree_node.getNodeByIndex(hidx);
240                         if (hnode) {
241                             hnode.highlight();
242                             scorm_layout_widget = YAHOO.widget.Layout.getLayoutById('scorm_layout');
243                             var left = scorm_layout_widget.getUnitByPosition('left');
244                             if (left.expanded) {
245                                 hnode.focus();
246                             }
247                         }
248                     }
249                 }
250         },
252         failure: function(o) {
253             // do some sort of error handling
254             var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
255             //TODO: Enable this error handing correctly - avoiding issues when closing player MDL-23470 
256             //alert('Prerequisites update failed - must restart SCORM player');
257             //window.location.href = sURL;
258         }
260     };
263     function LMSFinish (param) {
264         errorCode = "0";
265         if (param == "") {
266             if (Initialized) {
267                 Initialized = false;
268                 result = StoreData(cmi,true);
269                 if (nav.event != '') {
270                     if (nav.event == 'continue') {
271                         setTimeout('top.nextSCO();',500);
272                     } else {
273                         setTimeout('top.prevSCO();',500);
274                     }
275                 } else {
276                     if (<?php echo $scorm->auto ?> == 1) {
277                         setTimeout('top.nextSCO();',500);
278                     }
279                 }
280                 // trigger TOC update
281                 var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
282                 YAHOO.util.Connect.asyncRequest('GET', sURL, this.connectPrereqCallback, null);
283                 return "true";
284             } else {
285                 errorCode = "301";
286             }
287         } else {
288             errorCode = "201";
289         }
290         return "false";
291     }
293     function LMSGetValue (element) {
294         errorCode = "0";
295         if (Initialized) {
296             if (element !="") {
297                 expression = new RegExp(CMIIndex,'g');
298                 elementmodel = String(element).replace(expression,'.n.');
299                 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
300                     if (eval('datamodel["'+elementmodel+'"].mod') != 'w') {
301                             element = String(element).replace(expression, "_$1.");
302                             elementIndexes = element.split('.');
303                         subelement = 'cmi';
304                         i = 1;
305                         while ((i < elementIndexes.length) && (typeof eval(subelement) != "undefined")) {
306                             subelement += '.'+elementIndexes[i++];
307                         }
308                         if (subelement == element) {
309                             errorCode = "0";
310                             return eval(element);
311                         } else {
312                             errorCode = "0"; // Need to check if it is the right errorCode
313                         }
314                     } else {
315                         errorCode = eval('datamodel["'+elementmodel+'"].readerror');
316                     }
317                 } else {
318                     childrenstr = '._children';
319                     countstr = '._count';
320                     if (elementmodel.substr(elementmodel.length-childrenstr.length,elementmodel.length) == childrenstr) {
321                         parentmodel = elementmodel.substr(0,elementmodel.length-childrenstr.length);
322                         if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
323                             errorCode = "202";
324                         } else {
325                             errorCode = "201";
326                         }
327                     } else if (elementmodel.substr(elementmodel.length-countstr.length,elementmodel.length) == countstr) {
328                         parentmodel = elementmodel.substr(0,elementmodel.length-countstr.length);
329                         if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
330                             errorCode = "203";
331                         } else {
332                             errorCode = "201";
333                         }
334                     } else {
335                         errorCode = "201";
336                     }
337                 }
338             } else {
339                 errorCode = "201";
340             }
341         } else {
342             errorCode = "301";
343         }
344         return "";
345     }
347     function LMSSetValue (element,value) {
348         errorCode = "0";
349         if (Initialized) {
350             if (element != "") {
351                 expression = new RegExp(CMIIndex,'g');
352                 elementmodel = String(element).replace(expression,'.n.');
353                 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
354                     if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
355                         expression = new RegExp(eval('datamodel["'+elementmodel+'"].format'));
356                         value = value+'';
357                         matches = value.match(expression);
358                         if (matches != null) {
359                             //Create dynamic data model element
360                             if (element != elementmodel) {
361                                 elementIndexes = element.split('.');
362                                 subelement = 'cmi';
363                                 for (i=1;i < elementIndexes.length-1;i++) {
364                                     elementIndex = elementIndexes[i];
365                                     if (elementIndexes[i+1].match(/^\d+$/)) {
366                                         if ((typeof eval(subelement+'.'+elementIndex)) == "undefined") {
367                                             eval(subelement+'.'+elementIndex+' = new Object();');
368                                             eval(subelement+'.'+elementIndex+'._count = 0;');
369                                         }
370                                         if (elementIndexes[i+1] == eval(subelement+'.'+elementIndex+'._count')) {
371                                             eval(subelement+'.'+elementIndex+'._count++;');
372                                         }
373                                         if (elementIndexes[i+1] > eval(subelement+'.'+elementIndex+'._count')) {
374                                             errorCode = "201";
375                                         }
376                                         subelement = subelement.concat('.'+elementIndex+'_'+elementIndexes[i+1]);
377                                         i++;
378                                     } else {
379                                         subelement = subelement.concat('.'+elementIndex);
380                                     }
381                                     if ((typeof eval(subelement)) == "undefined") {
382                                         eval(subelement+' = new Object();');
383                                         if (subelement.substr(0,14) == 'cmi.objectives') {
384                                             eval(subelement+'.score = new Object();');
385                                             eval(subelement+'.score._children = score_children;');
386                                             eval(subelement+'.score.raw = "";');
387                                             eval(subelement+'.score.min = "";');
388                                             eval(subelement+'.score.max = "";');
389                                         }
390                                         if (subelement.substr(0,16) == 'cmi.interactions') {
391                                             eval(subelement+'.objectives = new Object();');
392                                             eval(subelement+'.objectives._count = 0;');
393                                             eval(subelement+'.correct_responses = new Object();');
394                                             eval(subelement+'.correct_responses._count = 0;');
395                                         }
396                                     }
397                                 }
398                                 element = subelement.concat('.'+elementIndexes[elementIndexes.length-1]);
399                             }
400                             //Store data
401                             if (errorCode == "0") {
402                                 if ((typeof eval('datamodel["'+elementmodel+'"].range')) != "undefined") {
403                                     range = eval('datamodel["'+elementmodel+'"].range');
404                                     ranges = range.split('#');
405                                     value = value*1.0;
406                                     if ((value >= ranges[0]) && (value <= ranges[1])) {
407                                         eval(element+'="'+value+'";');
408                                         errorCode = "0";
409                                         return "true";
410                                     } else {
411                                         errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
412                                     }
413                                 } else {
414                                     if (element == 'cmi.comments') {
415                                         eval(element+'+="'+value+'";');
416                                     } else {
417                                         eval(element+'="'+value+'";');
418                                     }
419                                     errorCode = "0";
420                                     return "true";
421                                 }
422                             }
423                         } else {
424                             errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
425                         }
426                     } else {
427                         errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
428                     }
429                 } else {
430                     errorCode = "201"
431                 }
432             } else {
433                 errorCode = "201";
434             }
435         } else {
436             errorCode = "301";
437         }
438         return "false";
439     }
441     function LMSCommit (param) {
442         errorCode = "0";
443         if (param == "") {
444             if (Initialized) {
445                 result = StoreData(cmi,false);
446                 return "true";
447             } else {
448                 errorCode = "301";
449             }
450         } else {
451             errorCode = "201";
452         }
453         return "false";
454     }
456     function LMSGetLastError () {
457         return errorCode;
458     }
460     function LMSGetErrorString (param) {
461         if (param != "") {
462             var errorString = new Array();
463             errorString["0"] = "No error";
464             errorString["101"] = "General exception";
465             errorString["201"] = "Invalid argument error";
466             errorString["202"] = "Element cannot have children";
467             errorString["203"] = "Element not an array - cannot have count";
468             errorString["301"] = "Not initialized";
469             errorString["401"] = "Not implemented error";
470             errorString["402"] = "Invalid set value, element is a keyword";
471             errorString["403"] = "Element is read only";
472             errorString["404"] = "Element is write only";
473             errorString["405"] = "Incorrect data type";
474             return errorString[param];
475         } else {
476            return "";
477         }
478     }
480     function LMSGetDiagnostic (param) {
481         if (param == "") {
482             param = errorCode;
483         }
484         return param;
485     }
487     function AddTime (first, second) {
488         var sFirst = first.split(":");
489         var sSecond = second.split(":");
490         var cFirst = sFirst[2].split(".");
491         var cSecond = sSecond[2].split(".");
492         var change = 0;
494         FirstCents = 0;  //Cents
495         if (cFirst.length > 1) {
496             FirstCents = parseInt(cFirst[1],10);
497         }
498         SecondCents = 0;
499         if (cSecond.length > 1) {
500             SecondCents = parseInt(cSecond[1],10);
501         }
502         var cents = FirstCents + SecondCents;
503         change = Math.floor(cents / 100);
504         cents = cents - (change * 100);
505         if (Math.floor(cents) < 10) {
506             cents = "0" + cents.toString();
507         }
509         var secs = parseInt(cFirst[0],10)+parseInt(cSecond[0],10)+change;  //Seconds
510         change = Math.floor(secs / 60);
511         secs = secs - (change * 60);
512         if (Math.floor(secs) < 10) {
513             secs = "0" + secs.toString();
514         }
516         mins = parseInt(sFirst[1],10)+parseInt(sSecond[1],10)+change;   //Minutes
517         change = Math.floor(mins / 60);
518         mins = mins - (change * 60);
519         if (mins < 10) {
520             mins = "0" + mins.toString();
521         }
523         hours = parseInt(sFirst[0],10)+parseInt(sSecond[0],10)+change;  //Hours
524         if (hours < 10) {
525             hours = "0" + hours.toString();
526         }
528         if (cents != '0') {
529             return hours + ":" + mins + ":" + secs + '.' + cents;
530         } else {
531             return hours + ":" + mins + ":" + secs;
532         }
533     }
535     function TotalTime() {
536         total_time = AddTime(cmi.core.total_time, cmi.core.session_time);
537         return '&'+underscore('cmi.core.total_time')+'='+escape(total_time);
538     }
540     function CollectData(data,parent) {
541         var datastring = '';
542         for (property in data) {
543             if (typeof data[property] == 'object') {
544                 datastring += CollectData(data[property],parent+'.'+property);
545             } else {
546                 element = parent+'.'+property;
547                 expression = new RegExp(CMIIndex,'g');
548                 elementmodel = String(element).replace(expression,'.n.');
549                 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
550                     if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
551                         elementstring = '&'+underscore(element)+'='+escape(data[property]);
552                         if ((typeof eval('datamodel["'+elementmodel+'"].defaultvalue')) != "undefined") {
553                             if (eval('datamodel["'+elementmodel+'"].defaultvalue') != data[property]) {
554                                 datastring += elementstring;
555                             }
556                         } else {
557                             datastring += elementstring;
558                         }
559                     }
560                 }
561             }
562         }
563         return datastring;
564     }
566     function StoreData(data,storetotaltime) {
567         if (storetotaltime) {
568             if (cmi.core.lesson_mode == 'normal') {
569                 if (cmi.core.credit == 'credit') {
570                     if (cmi.student_data.mastery_score != '' && cmi.core.score.raw != '') {
571                         if (cmi.core.score.raw >= cmi.student_data.mastery_score) {
572                             cmi.core.lesson_status = 'passed';
573                         } else {
574                             cmi.core.lesson_status = 'failed';
575                         }
576                     }
577                 }
578             }
579             if (cmi.core.lesson_mode == 'browse') {
580                 if (datamodel['cmi.core.lesson_status'].defaultvalue == '' && cmi.core.lesson_status == 'not attempted') {
581                     cmi.core.lesson_status = 'browsed';
582                 }
583             }
584             datastring = CollectData(data,'cmi');
585             datastring += TotalTime();
586         } else {
587             datastring = CollectData(data,'cmi');
588         }
589         datastring += '&attempt=<?php echo $attempt ?>';
590         datastring += '&scoid=<?php echo $scoid ?>';
592         //popupwin(datastring);
593         var myRequest = NewHttpReq();
594         result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php","id=<?php p($id) ?>&sesskey=<?php echo sesskey() ?>"+datastring);
595         results = String(result).split('\n');
596         errorCode = results[1];
597         return results[0];
598     }
600     this.LMSInitialize = LMSInitialize;
601     this.LMSFinish = LMSFinish;
602     this.LMSGetValue = LMSGetValue;
603     this.LMSSetValue = LMSSetValue;
604     this.LMSCommit = LMSCommit;
605     this.LMSGetLastError = LMSGetLastError;
606     this.LMSGetErrorString = LMSGetErrorString;
607     this.LMSGetDiagnostic = LMSGetDiagnostic;
610 var API = new AICCapi();