UNPKG

unserver-unify

Version:

264 lines (259 loc) 8.58 kB
angular.module('bamboo.common').service('ScormService', function($timeout, ApiService, $localStorage) { // default options var defaultOpts = { persistFor: 60, model: null }, // SCORM 1.2 error codes errorCodes = { 0: 'No error.', 101: 'General Exception.', 201: 'Invalid argument error.', 202: 'Element cannot have children.', 203: 'Element not an array. Cannot have count.', 301: 'Not initialized.', 401: 'Not implemented error', 402: 'Invalid set value, element is a keyword', 403: 'Element is read only.', 404: 'Element is write only.', 405: 'Incorrect Data Type.' }, // a default sample of a SCORM 1.2 data model defaultModel = { 'cmi.core._children': ['student_id', 'student_name', 'lesson_location', 'credit', 'lesson_status', 'entry', 'score', 'total_time', 'lesson_mode', 'exit', 'session_time'], 'cmi.core.student_id': '770b7a652cee065cbb9759ff1a0d46a927c8ba98', 'cmi.core.student_name': 'Appleseed, John', 'cmi.core.lesson_location': '', 'cmi.core.credit': 'credit', 'cmi.core.lesson_status': 'not attempted', 'cmi.core.entry': 'ab-initio', 'cmi.core.score_children': ['raw', 'min', 'max'], // TODO: limit score.raw to 100 and check its initial value 'cmi.core.score.raw': null, 'cmi.core.score.max': null, 'cmi.core.score.min': null, // TODO: compute total_time, when setting session_time 'cmi.core.total_time': '0000:00:00.00', 'cmi.core.lesson_mode': 'normal', 'cmi.core.exit': '', 'cmi.core.session_time': '00:00:00', // TODO: limit suspend_data to 4096 chars 'cmi.suspend_data': '', 'cmi.launch_data': '', // TODO: limit comments to 4096 chars 'cmi.comments': '', 'cmi.comments_from_lms': '', 'cmi.objectives.0.status': '', 'cmi.objectives._children': ['id', 'score', 'status'], 'cmi.objectives._count': 0, 'cmi.student_data._children': ['mastery_score', 'max_time_allowed', 'time_limit_action'], // TODO: check student_data initial values 'cmi.student_data.mastery_score': null, 'cmi.student_data.max_time_allowed': null, 'cmi.student_data.time_limit_action': 'continue,no message', 'cmi.student_preference._children': ['audio', 'language', 'speed', 'text'], 'cmi.student_preference.audio': null, 'cmi.student_preference.language': null, 'cmi.student_preference.speed': null, 'cmi.student_preference.text': null, 'cmi.interactions._children': ['id', 'objectives', 'time', 'type', 'correct_responses', 'weighting', 'student_response', 'result', 'latency'], 'cmi.interactions._count': 0 // TODO: correct count, after adding interactions }; // returns current time with, optionally, seconds added. function time(s) { return (new Date()).getTime() + ((s || 0) * 1000); } // returns [a shallow copy of] a, including b, without overwriting. function incl(a, b) { var c = {}; a = a || {}; b = b || {}; Object.keys(b).forEach(function(k) { c[k] = typeof a[k] == 'undefined' ? b[k] : a[k]; }); return c; } var courseId, userId; var lmsId; function mvApi(info, callback) { ApiService.post('/mvsubjects', info).then(function(result) { console.log(result); if (result.data.success) { if (!callback) { console.log('success'); } else { callback(result.data.data); } } else { console.log("Error"); console.log(result.data); } }); } function getlmsrecord(callback) { var info = { action: "getlmsrecord", cid: courseId, rid: lmsId, mvId: mvId, } mvApi(info, callback) } // get/set non-default data in lms var timer; function updatelms() { timer = null; var updateFlag; var info = { action: "updatelms", cid: courseId, rid: lmsId, mvId: mvId, object: data, } console.log(info); if(data['cmi.core.lesson_status'] == 'passed'||data['cmi.core.lesson_status'] == 'completed'){ if(!passed){ console.log('force to send completed!'); passed=true; updateFlag=true; } } mvApi(info,function(result){ if(updateFlag){ console.log('successCallBack'); successCallBack(true); }else if(passed){ console.log('already completed out!'); } }) } function store() { data._expireTime = (function() { switch (true) { case (opts.persistFor > 0): return time(opts.persistFor) + 1; case (opts.persistFor < 0): return -1; default: return 0; } })(); if (timer) { $timeout.cancel(timer); } timer = $timeout(updatelms, 2000); } var opts; var initialized, lastError, model, data; var mvId; var passed; var successCallBack; // returns function to create API instances, for different SCOs this.scormLocal = function(cid, mvid, rid, _opts,_successCallBack, callback) { // console.log(user); courseId = cid; lmsId = rid; mvId = mvid; opts = _opts; successCallBack=_successCallBack; // defaultModel['cmi.core.student_id']=user._id; // defaultModel['cmi.core.student_name']=user.fullname; // console.log(defaultModel); opts = incl(opts, defaultOpts); initialized = false; lastError = 0; model = incl(opts.model, defaultModel); getlmsrecord(function(r) { console.log('load server',r); if (!r) { r = {}; } if (!r || {}.toString.call(r) != '[object Object]' || r._flush || r._expireTime === 0) { data = {} } else if (r['cmi.core.lesson_status'] == 'passed'||r['cmi.core.lesson_status'] == 'completed') { // never expire for passed records console.log('already completed in!'); passed=true; data = r; } else if (r._expireTime !== -1 && time() >= (r._expireTime || Number.POSITIVE_INIFINITY)) { data = {}; } else { data = r; } if (callback) { callback(); } }) // data = store(); } this.API = { // imports the API methods to another object importTo: function(obj) { for (var k in this) if (/^LMS/.test(k)) obj[k] = this[k].bind(this); }, // removes data from lms and mark it as flushed // in case it's commited after flushing flush: function() { data = { _flush: true }; store(); }, // TODO: check if return booleans should be strings LMSInitialize: function() { if (initialized) return lastError = 101, false; lastError = 0; initialized = true; return true; }, // TODO: check if return booleans should be strings LMSFinish: function() { if (!initialized) return lastError = 301, false; lastError = 0; initialized = false; return true; }, // TODO: check if return booleans should be strings // TODO: validate arguments LMSGetValue: function(key) { console.log("get value :" + key); if (!initialized) return lastError = 301, false; var v = data[key] || model[key]; if (typeof v == 'undefined') return lastError = 201, null; lastError = 0; return v; }, // TODO: check if return booleans should be strings // TODO: validate arguments LMSSetValue: function(key, value) { // console.log("set value :" +key+" : " +value); if (!initialized) return lastError = 301, false; // if (typeof model[key] == 'undefined') return lastError = 201, false; data[key] = value; lastError = 0; store(data); return 'true'; }, // TODO: check if return booleans should be strings LMSCommit: function() { console.log("commit :"); if (!initialized) return lastError = 301, false; console.log(data); store(data); lastError = 0; return true; }, LMSGetLastError: function() { return lastError; }, LMSGetErrorString: function(code) { return errorCodes[code]; }, // TODO: improve diagnostics LMSGetDiagnostic: function(code) { return errorCodes[code]; } }; });