Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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