MDL-25757 SCORM fix issue with duplicate cmi values being saved
[moodle.git] / mod / scorm / datamodels / scorm_12.js.php
CommitLineData
dc383b6f 1<?php
f7b5c6aa
DM
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
e5dd8e3b 16
f7b5c6aa
DM
17require_once($CFG->dirroot.'/mod/scorm/locallib.php');
18
19if (isset($userdata->status)) {
20 if ($userdata->status == '') {
21 $userdata->entry = 'ab-initio';
22 } else {
23 if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
24 $userdata->entry = 'resume';
dc383b6f 25 } else {
f7b5c6aa 26 $userdata->entry = '';
dc383b6f 27 }
28 }
f7b5c6aa
DM
29}
30if (!isset($currentorg)) {
31 $currentorg = '';
32}
dc383b6f 33?>
34//
35// SCORM 1.2 API Implementation
36//
37function SCORMapi1_2() {
38 // Standard Data Type Definition
d5f3bdc9 39 CMIString256 = '^[\\u0000-\\uffff]{0,255}$';
40 CMIString4096 = '^[\\u0000-\\uffff]{0,4096}$';
dc383b6f 41 CMITime = '^([0-2]{1}[0-9]{1}):([0-5]{1}[0-9]{1}):([0-5]{1}[0-9]{1})(\.[0-9]{1,2})?$';
42 CMITimespan = '^([0-9]{2,4}):([0-9]{2}):([0-9]{2})(\.[0-9]{1,2})?$';
43 CMIInteger = '^\\d+$';
44 CMISInteger = '^-?([0-9]+)$';
45 CMIDecimal = '^-?([0-9]{0,3})(\.[0-9]{1,2})?$';
e5905528 46 CMIIdentifier = '^[\\u0021-\\u007E]{0,255}$';
dc383b6f 47 CMIFeedback = CMIString256; // This must be redefined
48 CMIIndex = '[._](\\d+).';
49 // Vocabulary Data Type Definition
50 CMIStatus = '^passed$|^completed$|^failed$|^incomplete$|^browsed$';
51 CMIStatus2 = '^passed$|^completed$|^failed$|^incomplete$|^browsed$|^not attempted$';
52 CMIExit = '^time-out$|^suspend$|^logout$|^$';
53 CMIType = '^true-false$|^choice$|^fill-in$|^matching$|^performance$|^sequencing$|^likert$|^numeric$';
54 CMIResult = '^correct$|^wrong$|^unanticipated$|^neutral$|^([0-9]{0,3})?(\.[0-9]{1,2})?$';
55 NAVEvent = '^previous$|^continue$';
56 // Children lists
1ed0a96c
DM
57 cmi_children = 'core,suspend_data,launch_data,comments,objectives,student_data,student_preference,interactions';
58 core_children = 'student_id,student_name,lesson_location,credit,lesson_status,entry,score,total_time,lesson_mode,exit,session_time';
59 score_children = 'raw,min,max';
60 comments_children = 'content,location,time';
61 objectives_children = 'id,score,status';
bf34ac0f 62 correct_responses_children = 'pattern';
1ed0a96c
DM
63 student_data_children = 'mastery_score,max_time_allowed,time_limit_action';
64 student_preference_children = 'audio,language,speed,text';
65 interactions_children = 'id,objectives,time,type,correct_responses,weighting,student_response,result,latency';
dc383b6f 66 // Data ranges
67 score_range = '0#100';
68 audio_range = '-1#100';
69 speed_range = '-100#100';
70 weighting_range = '-100#100';
71 text_range = '-1#1';
72 // The SCORM 1.2 data model
73 var datamodel = {
74 'cmi._children':{'defaultvalue':cmi_children, 'mod':'r', 'writeerror':'402'},
75 'cmi._version':{'defaultvalue':'3.4', 'mod':'r', 'writeerror':'402'},
76 'cmi.core._children':{'defaultvalue':core_children, 'mod':'r', 'writeerror':'402'},
77 'cmi.core.student_id':{'defaultvalue':'<?php echo $userdata->student_id ?>', 'mod':'r', 'writeerror':'403'},
dac958fc 78 'cmi.core.student_name':{'defaultvalue':'<?php echo $userdata->student_name ?>', 'mod':'r', 'writeerror':'403'},
dc383b6f 79 'cmi.core.lesson_location':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_location'})?$userdata->{'cmi.core.lesson_location'}:'' ?>', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
80 'cmi.core.credit':{'defaultvalue':'<?php echo $userdata->credit ?>', 'mod':'r', 'writeerror':'403'},
81 'cmi.core.lesson_status':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_status'})?$userdata->{'cmi.core.lesson_status'}:'' ?>', 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
82 'cmi.core.entry':{'defaultvalue':'<?php echo $userdata->entry ?>', 'mod':'r', 'writeerror':'403'},
83 'cmi.core.score._children':{'defaultvalue':score_children, 'mod':'r', 'writeerror':'402'},
84 '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'},
85 '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'},
86 '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'},
87 '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'},
88 'cmi.core.lesson_mode':{'defaultvalue':'<?php echo $userdata->mode ?>', 'mod':'r', 'writeerror':'403'},
89 'cmi.core.exit':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.exit'})?$userdata->{'cmi.core.exit'}:'' ?>', 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
90 'cmi.core.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'00:00:00', 'readerror':'404', 'writeerror':'405'},
91 'cmi.suspend_data':{'defaultvalue':'<?php echo isset($userdata->{'cmi.suspend_data'})?$userdata->{'cmi.suspend_data'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
b3659259 92 'cmi.launch_data':{'defaultvalue':'<?php echo isset($userdata->datafromlms)?$userdata->datafromlms:'' ?>', 'mod':'r', 'writeerror':'403'},
dc383b6f 93 'cmi.comments':{'defaultvalue':'<?php echo isset($userdata->{'cmi.comments'})?$userdata->{'cmi.comments'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
7bbb7f49 94 // deprecated evaluation attributes
95 'cmi.evaluation.comments._count':{'defaultvalue':'0', 'mod':'r', 'writeerror':'402'},
96 'cmi.evaluation.comments._children':{'defaultvalue':comments_children, 'mod':'r', 'writeerror':'402'},
97 'cmi.evaluation.comments.n.content':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
98 'cmi.evaluation.comments.n.location':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
99 'cmi.evaluation.comments.n.time':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMITime, 'mod':'rw', 'writeerror':'405'},
dc383b6f 100 'cmi.comments_from_lms':{'mod':'r', 'writeerror':'403'},
101 'cmi.objectives._children':{'defaultvalue':objectives_children, 'mod':'r', 'writeerror':'402'},
102 'cmi.objectives._count':{'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
103 'cmi.objectives.n.id':{'pattern':CMIIndex, 'format':CMIIdentifier, 'mod':'rw', 'writeerror':'405'},
104 'cmi.objectives.n.score._children':{'pattern':CMIIndex, 'mod':'r', 'writeerror':'402'},
105 'cmi.objectives.n.score.raw':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
106 'cmi.objectives.n.score.min':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
107 'cmi.objectives.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
108 'cmi.objectives.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
109 'cmi.student_data._children':{'defaultvalue':student_data_children, 'mod':'r', 'writeerror':'402'},
b3659259 110 'cmi.student_data.mastery_score':{'defaultvalue':'<?php echo isset($userdata->masteryscore)?$userdata->masteryscore:'' ?>', 'mod':'r', 'writeerror':'403'},
111 'cmi.student_data.max_time_allowed':{'defaultvalue':'<?php echo isset($userdata->maxtimeallowed)?$userdata->maxtimeallowed:'' ?>', 'mod':'r', 'writeerror':'403'},
112 'cmi.student_data.time_limit_action':{'defaultvalue':'<?php echo isset($userdata->timelimitaction)?$userdata->timelimitaction:'' ?>', 'mod':'r', 'writeerror':'403'},
dc383b6f 113 'cmi.student_preference._children':{'defaultvalue':student_preference_children, 'mod':'r', 'writeerror':'402'},
114 'cmi.student_preference.audio':{'defaultvalue':'0', 'format':CMISInteger, 'range':audio_range, 'mod':'rw', 'writeerror':'405'},
115 'cmi.student_preference.language':{'defaultvalue':'', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
116 'cmi.student_preference.speed':{'defaultvalue':'0', 'format':CMISInteger, 'range':speed_range, 'mod':'rw', 'writeerror':'405'},
117 'cmi.student_preference.text':{'defaultvalue':'0', 'format':CMISInteger, 'range':text_range, 'mod':'rw', 'writeerror':'405'},
118 'cmi.interactions._children':{'defaultvalue':interactions_children, 'mod':'r', 'writeerror':'402'},
119 'cmi.interactions._count':{'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
120 'cmi.interactions.n.id':{'pattern':CMIIndex, 'format':CMIIdentifier, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
121 'cmi.interactions.n.objectives._count':{'pattern':CMIIndex, 'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
122 'cmi.interactions.n.objectives.n.id':{'pattern':CMIIndex, 'format':CMIIdentifier, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
123 'cmi.interactions.n.time':{'pattern':CMIIndex, 'format':CMITime, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
124 'cmi.interactions.n.type':{'pattern':CMIIndex, 'format':CMIType, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
125 'cmi.interactions.n.correct_responses._count':{'pattern':CMIIndex, 'mod':'r', 'defaultvalue':'0', 'writeerror':'402'},
126 'cmi.interactions.n.correct_responses.n.pattern':{'pattern':CMIIndex, 'format':CMIFeedback, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
127 'cmi.interactions.n.weighting':{'pattern':CMIIndex, 'format':CMIDecimal, 'range':weighting_range, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
128 'cmi.interactions.n.student_response':{'pattern':CMIIndex, 'format':CMIFeedback, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
129 'cmi.interactions.n.result':{'pattern':CMIIndex, 'format':CMIResult, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
130 'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
131 'nav.event':{'defaultvalue':'', 'format':NAVEvent, 'mod':'w', 'readerror':'404', 'writeerror':'405'}
132 };
133 //
134 // Datamodel inizialization
135 //
136 var cmi = new Object();
137 cmi.core = new Object();
138 cmi.core.score = new Object();
139 cmi.objectives = new Object();
140 cmi.student_data = new Object();
141 cmi.student_preference = new Object();
142 cmi.interactions = new Object();
7bbb7f49 143 // deprecated evaluation attributes
144 cmi.evaluation = new Object();
145 cmi.evaluation.comments = new Object();
dc383b6f 146
147 // Navigation Object
148 var nav = new Object();
149
150 for (element in datamodel) {
151 if (element.match(/\.n\./) == null) {
152 if ((typeof eval('datamodel["'+element+'"].defaultvalue')) != 'undefined') {
153 eval(element+' = datamodel["'+element+'"].defaultvalue;');
154 } else {
155 eval(element+' = "";');
156 }
157 }
158 }
159
160<?php
527af457 161 // reconstitute objectives
162 scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.objectives', array('score'));
bf34ac0f 163 scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.interactions', array('objectives', 'correct_responses'));
164 ?>
e5dd8e3b 165
dc383b6f 166 if (cmi.core.lesson_status == '') {
167 cmi.core.lesson_status = 'not attempted';
e5dd8e3b
PS
168 }
169
dc383b6f 170 //
171 // API Methods definition
172 //
173 var Initialized = false;
174
175 function LMSInitialize (param) {
176 errorCode = "0";
177 if (param == "") {
178 if (!Initialized) {
7bbb7f49 179 Initialized = true;
180 errorCode = "0";
e5dd8e3b 181 <?php
1881df27 182 if (scorm_debugging($scorm)) {
7bbb7f49 183 echo 'LogAPICall("LMSInitialize", param, "", errorCode);';
dc383b6f 184 }
185 ?>
dc383b6f 186 return "true";
187 } else {
188 errorCode = "101";
189 }
190 } else {
191 errorCode = "201";
192 }
e5dd8e3b 193 <?php
1881df27 194 if (scorm_debugging($scorm)) {
7bbb7f49 195 echo 'LogAPICall("LMSInitialize", param, "", errorCode);';
196 }
197 ?>
dc383b6f 198 return "false";
199 }
e5dd8e3b 200
e62c1d22
PH
201<?php
202 // pull in the TOC callback
f7b5c6aa
DM
203 require_once($CFG->dirroot.'/mod/scorm/datamodels/callback.js.php');
204?>
5c2aa157 205
dc383b6f 206 function LMSFinish (param) {
207 errorCode = "0";
208 if (param == "") {
209 if (Initialized) {
dc383b6f 210 Initialized = false;
211 result = StoreData(cmi,true);
212 if (nav.event != '') {
213 if (nav.event == 'continue') {
22a79674 214 setTimeout('scorm_get_next();',500);
dc383b6f 215 } else {
22a79674 216 setTimeout('scorm_get_prev();',500);
dc383b6f 217 }
218 } else {
219 if (<?php echo $scorm->auto ?> == 1) {
22a79674 220 setTimeout('scorm_get_next();',500);
dc383b6f 221 }
e5dd8e3b 222 }
7f82b2e3
DM
223 <?php
224 if (scorm_debugging($scorm)) {
225 echo 'LogAPICall("LMSFinish", "AJAXResult", result, 0);';
226 }
227 ?>
228 result = ('true' == result) ? 'true' : 'false';
229 errorCode = (result == 'true')? '0' : '101';
e5dd8e3b 230 <?php
1881df27 231 if (scorm_debugging($scorm)) {
7f82b2e3 232 echo 'LogAPICall("LMSFinish", "result", result, 0);';
7bbb7f49 233 echo 'LogAPICall("LMSFinish", param, "", 0);';
234 }
235 ?>
eea0c8ea 236 // trigger TOC update
24d29a27
PH
237 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(); ?>";
238 YAHOO.util.Connect.asyncRequest('GET', sURL, this.connectPrereqCallback, null);
67f94109 239 return result;
dc383b6f 240 } else {
241 errorCode = "301";
242 }
243 } else {
244 errorCode = "201";
245 }
e5dd8e3b 246 <?php
1881df27 247 if (scorm_debugging($scorm)) {
7bbb7f49 248 echo 'LogAPICall("LMSFinish", param, "", errorCode);';
249 }
250 ?>
dc383b6f 251 return "false";
252 }
e5dd8e3b 253
dc383b6f 254 function LMSGetValue (element) {
255 errorCode = "0";
256 if (Initialized) {
257 if (element !="") {
258 expression = new RegExp(CMIIndex,'g');
d5f3bdc9 259 elementmodel = String(element).replace(expression,'.n.');
dc383b6f 260 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
261 if (eval('datamodel["'+elementmodel+'"].mod') != 'w') {
527af457 262 element = String(element).replace(expression, "_$1.");
263 elementIndexes = element.split('.');
dc383b6f 264 subelement = 'cmi';
265 i = 1;
266 while ((i < elementIndexes.length) && (typeof eval(subelement) != "undefined")) {
267 subelement += '.'+elementIndexes[i++];
268 }
269 if (subelement == element) {
270 errorCode = "0";
e5dd8e3b 271 <?php
1881df27 272 if (scorm_debugging($scorm)) {
7bbb7f49 273 echo 'LogAPICall("LMSGetValue", element, eval(element), 0);';
dc383b6f 274 }
275 ?>
276 return eval(element);
277 } else {
278 errorCode = "0"; // Need to check if it is the right errorCode
279 }
280 } else {
281 errorCode = eval('datamodel["'+elementmodel+'"].readerror');
282 }
283 } else {
284 childrenstr = '._children';
285 countstr = '._count';
286 if (elementmodel.substr(elementmodel.length-childrenstr.length,elementmodel.length) == childrenstr) {
287 parentmodel = elementmodel.substr(0,elementmodel.length-childrenstr.length);
288 if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
289 errorCode = "202";
290 } else {
291 errorCode = "201";
292 }
293 } else if (elementmodel.substr(elementmodel.length-countstr.length,elementmodel.length) == countstr) {
294 parentmodel = elementmodel.substr(0,elementmodel.length-countstr.length);
295 if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
296 errorCode = "203";
297 } else {
298 errorCode = "201";
299 }
300 } else {
301 errorCode = "201";
302 }
303 }
304 } else {
305 errorCode = "201";
306 }
307 } else {
308 errorCode = "301";
309 }
e5dd8e3b 310 <?php
1881df27 311 if (scorm_debugging($scorm)) {
7bbb7f49 312 echo 'LogAPICall("LMSGetValue", element, "", errorCode);';
313 }
314 ?>
dc383b6f 315 return "";
316 }
e5dd8e3b 317
dc383b6f 318 function LMSSetValue (element,value) {
319 errorCode = "0";
320 if (Initialized) {
321 if (element != "") {
322 expression = new RegExp(CMIIndex,'g');
d5f3bdc9 323 elementmodel = String(element).replace(expression,'.n.');
dc383b6f 324 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
325 if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
326 expression = new RegExp(eval('datamodel["'+elementmodel+'"].format'));
327 value = value+'';
328 matches = value.match(expression);
329 if (matches != null) {
330 //Create dynamic data model element
331 if (element != elementmodel) {
332 elementIndexes = element.split('.');
333 subelement = 'cmi';
334 for (i=1;i < elementIndexes.length-1;i++) {
335 elementIndex = elementIndexes[i];
336 if (elementIndexes[i+1].match(/^\d+$/)) {
337 if ((typeof eval(subelement+'.'+elementIndex)) == "undefined") {
338 eval(subelement+'.'+elementIndex+' = new Object();');
339 eval(subelement+'.'+elementIndex+'._count = 0;');
340 }
341 if (elementIndexes[i+1] == eval(subelement+'.'+elementIndex+'._count')) {
342 eval(subelement+'.'+elementIndex+'._count++;');
e5dd8e3b 343 }
dc383b6f 344 if (elementIndexes[i+1] > eval(subelement+'.'+elementIndex+'._count')) {
345 errorCode = "201";
346 }
347 subelement = subelement.concat('.'+elementIndex+'_'+elementIndexes[i+1]);
348 i++;
349 } else {
350 subelement = subelement.concat('.'+elementIndex);
351 }
352 if ((typeof eval(subelement)) == "undefined") {
353 eval(subelement+' = new Object();');
354 if (subelement.substr(0,14) == 'cmi.objectives') {
355 eval(subelement+'.score = new Object();');
356 eval(subelement+'.score._children = score_children;');
357 eval(subelement+'.score.raw = "";');
358 eval(subelement+'.score.min = "";');
359 eval(subelement+'.score.max = "";');
360 }
361 if (subelement.substr(0,16) == 'cmi.interactions') {
362 eval(subelement+'.objectives = new Object();');
363 eval(subelement+'.objectives._count = 0;');
364 eval(subelement+'.correct_responses = new Object();');
365 eval(subelement+'.correct_responses._count = 0;');
366 }
367 }
368 }
369 element = subelement.concat('.'+elementIndexes[elementIndexes.length-1]);
370 }
371 //Store data
372 if (errorCode == "0") {
373 if ((typeof eval('datamodel["'+elementmodel+'"].range')) != "undefined") {
374 range = eval('datamodel["'+elementmodel+'"].range');
375 ranges = range.split('#');
376 value = value*1.0;
377 if ((value >= ranges[0]) && (value <= ranges[1])) {
021d903e 378 eval(element+'=value;');
dc383b6f 379 errorCode = "0";
e5dd8e3b 380 <?php
1881df27 381 if (scorm_debugging($scorm)) {
7bbb7f49 382 echo 'LogAPICall("LMSSetValue", element, value, errorCode);';
dc383b6f 383 }
384 ?>
385 return "true";
386 } else {
387 errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
388 }
389 } else {
390 if (element == 'cmi.comments') {
9797d144 391 cmi.comments = cmi.comments + value;
dc383b6f 392 } else {
021d903e 393 eval(element+'=value;');
dc383b6f 394 }
395 errorCode = "0";
e5dd8e3b 396 <?php
1881df27 397 if (scorm_debugging($scorm)) {
7bbb7f49 398 echo 'LogAPICall("LMSSetValue", element, value, errorCode);';
dc383b6f 399 }
400 ?>
401 return "true";
402 }
403 }
404 } else {
405 errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
406 }
407 } else {
408 errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
409 }
410 } else {
411 errorCode = "201"
412 }
413 } else {
414 errorCode = "201";
415 }
416 } else {
417 errorCode = "301";
418 }
e5dd8e3b 419 <?php
1881df27 420 if (scorm_debugging($scorm)) {
7bbb7f49 421 echo 'LogAPICall("LMSSetValue", element, value, errorCode);';
422 }
423 ?>
dc383b6f 424 return "false";
425 }
e5dd8e3b 426
dc383b6f 427 function LMSCommit (param) {
428 errorCode = "0";
429 if (param == "") {
430 if (Initialized) {
431 result = StoreData(cmi,false);
e5dd8e3b 432 <?php
1881df27 433 if (scorm_debugging($scorm)) {
7bbb7f49 434 echo 'LogAPICall("Commit", param, "", 0);';
dc383b6f 435 }
436 ?>
8d316925
DM
437 <?php
438 if (scorm_debugging($scorm)) {
439 echo 'LogAPICall("LMSCommit", "AJAXResult", result, 0);';
440 }
441 ?>
442 result = ('true' == result) ? 'true' : 'false';
ed5c4cf4 443 errorCode = (result =='true')? '0' : '101';
8d316925
DM
444 <?php
445 if (scorm_debugging($scorm)) {
8d316925 446 echo 'LogAPICall("LMSCommit", "result", result, 0);';
07b5ee31 447 echo 'LogAPICall("LMSCommit", "errorCode", errorCode, 0);';
8d316925
DM
448 }
449 ?>
450 return result;
dc383b6f 451 } else {
452 errorCode = "301";
453 }
454 } else {
455 errorCode = "201";
456 }
e5dd8e3b 457 <?php
1881df27 458 if (scorm_debugging($scorm)) {
7bbb7f49 459 echo 'LogAPICall("LMSCommit", param, "", 0);';
460 }
461 ?>
dc383b6f 462 return "false";
463 }
e5dd8e3b 464
dc383b6f 465 function LMSGetLastError () {
e5dd8e3b 466 <?php
1881df27 467 if (scorm_debugging($scorm)) {
7bbb7f49 468 echo 'LogAPICall("LMSGetLastError", "", "", errorCode);';
469 }
470 ?>
dc383b6f 471 return errorCode;
472 }
e5dd8e3b 473
dc383b6f 474 function LMSGetErrorString (param) {
475 if (param != "") {
476 var errorString = new Array();
477 errorString["0"] = "No error";
478 errorString["101"] = "General exception";
479 errorString["201"] = "Invalid argument error";
480 errorString["202"] = "Element cannot have children";
481 errorString["203"] = "Element not an array - cannot have count";
482 errorString["301"] = "Not initialized";
483 errorString["401"] = "Not implemented error";
484 errorString["402"] = "Invalid set value, element is a keyword";
485 errorString["403"] = "Element is read only";
486 errorString["404"] = "Element is write only";
487 errorString["405"] = "Incorrect data type";
e5dd8e3b 488 <?php
1881df27 489 if (scorm_debugging($scorm)) {
7bbb7f49 490 echo 'LogAPICall("LMSGetErrorString", param, errorString[param], 0);';
491 }
492 ?>
dc383b6f 493 return errorString[param];
494 } else {
e5dd8e3b 495 <?php
1881df27 496 if (scorm_debugging($scorm)) {
7bbb7f49 497 echo 'LogAPICall("LMSGetErrorString", param, "No error string found!", 0);';
498 }
499 ?>
dc383b6f 500 return "";
501 }
502 }
e5dd8e3b 503
dc383b6f 504 function LMSGetDiagnostic (param) {
505 if (param == "") {
506 param = errorCode;
507 }
e5dd8e3b 508 <?php
1881df27 509 if (scorm_debugging($scorm)) {
7bbb7f49 510 echo 'LogAPICall("LMSGetDiagnostic", param, param, 0);';
511 }
512 ?>
dc383b6f 513 return param;
514 }
515
516 function AddTime (first, second) {
517 var sFirst = first.split(":");
518 var sSecond = second.split(":");
519 var cFirst = sFirst[2].split(".");
520 var cSecond = sSecond[2].split(".");
521 var change = 0;
522
523 FirstCents = 0; //Cents
524 if (cFirst.length > 1) {
525 FirstCents = parseInt(cFirst[1],10);
526 }
527 SecondCents = 0;
528 if (cSecond.length > 1) {
529 SecondCents = parseInt(cSecond[1],10);
530 }
531 var cents = FirstCents + SecondCents;
532 change = Math.floor(cents / 100);
533 cents = cents - (change * 100);
534 if (Math.floor(cents) < 10) {
535 cents = "0" + cents.toString();
536 }
537
538 var secs = parseInt(cFirst[0],10)+parseInt(cSecond[0],10)+change; //Seconds
539 change = Math.floor(secs / 60);
540 secs = secs - (change * 60);
541 if (Math.floor(secs) < 10) {
542 secs = "0" + secs.toString();
543 }
544
545 mins = parseInt(sFirst[1],10)+parseInt(sSecond[1],10)+change; //Minutes
546 change = Math.floor(mins / 60);
547 mins = mins - (change * 60);
548 if (mins < 10) {
549 mins = "0" + mins.toString();
550 }
551
552 hours = parseInt(sFirst[0],10)+parseInt(sSecond[0],10)+change; //Hours
553 if (hours < 10) {
554 hours = "0" + hours.toString();
555 }
556
557 if (cents != '0') {
558 return hours + ":" + mins + ":" + secs + '.' + cents;
559 } else {
560 return hours + ":" + mins + ":" + secs;
561 }
562 }
563
564 function TotalTime() {
565 total_time = AddTime(cmi.core.total_time, cmi.core.session_time);
021d903e 566 return '&'+underscore('cmi.core.total_time')+'='+encodeURIComponent(total_time);
dc383b6f 567 }
568
569 function CollectData(data,parent) {
570 var datastring = '';
571 for (property in data) {
572 if (typeof data[property] == 'object') {
573 datastring += CollectData(data[property],parent+'.'+property);
574 } else {
575 element = parent+'.'+property;
576 expression = new RegExp(CMIIndex,'g');
d5f3bdc9 577 elementmodel = String(element).replace(expression,'.n.');
dc383b6f 578 if (elementmodel != "cmi.core.session_time") {
579 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
580 if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
021d903e 581 elementstring = '&'+underscore(element)+'='+encodeURIComponent(data[property]);
dc383b6f 582 if ((typeof eval('datamodel["'+elementmodel+'"].defaultvalue')) != "undefined") {
67859ce6 583 if (eval('datamodel["'+elementmodel+'"].defaultvalue') != data[property] || eval('typeof(datamodel["'+elementmodel+'"].defaultvalue)') != typeof(data[property])) {
dc383b6f 584 datastring += elementstring;
7857560e 585 eval('datamodel["'+elementmodel+'"].defaultvalue=data[property];');
dc383b6f 586 }
587 } else {
588 datastring += elementstring;
589 }
590 }
591 }
592 }
593 }
594 }
595 return datastring;
596 }
597
598 function StoreData(data,storetotaltime) {
599 if (storetotaltime) {
600 if (cmi.core.lesson_status == 'not attempted') {
601 cmi.core.lesson_status = 'completed';
602 }
603 if (cmi.core.lesson_mode == 'normal') {
604 if (cmi.core.credit == 'credit') {
d2597870
DM
605 if (cmi.student_data.mastery_score != '' && cmi.core.score.raw != '') {
606 if (parseFloat(cmi.core.score.raw) >= parseFloat(cmi.student_data.mastery_score)) {
607 cmi.core.lesson_status = 'passed';
608 } else {
609 cmi.core.lesson_status = 'failed';
dc383b6f 610 }
611 }
612 }
613 }
614 if (cmi.core.lesson_mode == 'browse') {
e4f976a8 615 if (datamodel['cmi.core.lesson_status'].defaultvalue == '' && cmi.core.lesson_status == 'not attempted') {
dc383b6f 616 cmi.core.lesson_status = 'browsed';
617 }
618 }
619 datastring = CollectData(data,'cmi');
620 datastring += TotalTime();
621 } else {
622 datastring = CollectData(data,'cmi');
623 }
624 datastring += '&attempt=<?php echo $attempt ?>';
b3659259 625 datastring += '&scoid=<?php echo $scoid ?>';
e5dd8e3b 626
dc383b6f 627 var myRequest = NewHttpReq();
5c2aa157
DM
628 //alert('going to:' + "<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php" + "id=<?php p($id) ?>&a=<?php p($a) ?>&sesskey=<?php echo sesskey() ?>"+datastring);
629 result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php","id=<?php p($id) ?>&a=<?php p($a) ?>&sesskey=<?php echo sesskey() ?>"+datastring);
45e94d82 630 results = String(result).split('\n');
dc383b6f 631 errorCode = results[1];
632 return results[0];
633 }
634
635 this.LMSInitialize = LMSInitialize;
636 this.LMSFinish = LMSFinish;
637 this.LMSGetValue = LMSGetValue;
638 this.LMSSetValue = LMSSetValue;
639 this.LMSCommit = LMSCommit;
640 this.LMSGetLastError = LMSGetLastError;
641 this.LMSGetErrorString = LMSGetErrorString;
642 this.LMSGetDiagnostic = LMSGetDiagnostic;
643}
644
645var API = new SCORMapi1_2();
7bbb7f49 646
647<?php
648// pull in the debugging utilities
1881df27 649if (scorm_debugging($scorm)) {
f7b5c6aa
DM
650 include_once($CFG->dirroot.'/mod/scorm/datamodels/debug.js.php');
651 echo 'AppendToLog("Moodle SCORM 1.2 API Loaded, Activity: '.$scorm->name.', SCO: '.$sco->identifier.'", 0);';
7bbb7f49 652}
7bbb7f49 653