SCORM课程对接线上课程学习平台
1,什么是SCORM课件?
SCORM是一种标准,是在线学习系统的一种内容标准,课件的内容主要由HTML、XML标签、JS代码组成。
其中,HTML 用于展现文字、图像、音视频等学习资源,XML标签用于组织课程结构,譬如章节目录,JS代码用于控制课程播放进度,或者制作一些效果。
2,SCORM课件有什么优点?
一、 SCORM课件可以对内容的重新组织和编排。
二、 SCORM课件可以定义学习资源的排序和浏览逻辑。
三、定制化的在线学习平台与课件具有交互能力,可以产生出很多效果。
那么如果制作好的SCORM课程如何对接到课程学习平台
(如果你这边是一个线上课程的学习平台,并和一个专门制作SCORM课程的公司合作,要把他们做好的SCORM课程放到自己线上的学习平台,并且记录学习等信息。那么应该如何对接好SCORM课程和线上学习平台)
SCORM主要的函数解析
一、函数
1、doLMSInitialize:初始化时调用的函数
2、doLMSCommit:提交数据时调用的函数
3、doLMSGetValue(name):获取SCORM数据模型某个值
4、doLMSSetValue(name,value):设置SCORM数据模型某个值
5、doLMSFinish:完成时调用的函数
二、数据模型(在项目中可通过window.API获取SCORM数据模型,格式内容如下)
获取数据模型中的某个值:doLMSGetValue(‘cmi.core.lesson_progress’)
{
comments: "", // 存储评论数据
comments_from_lms: "", // 存储LMS关于内容对象的评论数据
core: {
credit: "", // 学分
entry: "", // 入口(进入内容对象)
exit: "", // 退出途径
lesson_location: "", // 记录上次离开sco时的位置
lesson_mode: "normal", // 课的模式
lesson_progress: "", // 记录课程学习进度
lesson_status: "incomplete", // 记录课程的完成情况
score: {
max: "100", // 最高成绩
min: "", // 最低成绩
raw: "0", // 最后一次成绩
},
session_time: "00:00:00", // 本次学习时间
student_id: "", // 学生学号
student_name: "", // 学生姓名
total_time: "", // 学习总时间
},
interactions: {
childArray: [], // 返回集合中元素总数
},
launch_data: "", // 内容对象运行时所需的数据
objectives: {
childArray: [], // 返回所有属性
},
student_data: {
mastery_score: "", // 掌握得分
max_time_allowed: "", // 最大允许时间
time_limit_action: "", // 限时反应
},
student_preference: {
audio: "", // 音频
language: "", // 语言
speed: "", // 速度
text: "", // 文本
},
suspend_data: "", // 暂存数据
},
SCORM课程制作端
首先他们制作端会在SCORM课程课程中加入 linkSCORM12.js 文件,这是执行调用SCORM标准的函数的必须文件(这是调用SCORM标准执行函数的js代码,下面是一段示例代码)
var _Debug = false;
var _NoError = 0;
var _ServerBusy = 102;
var _InvalidArgumentError = 201;
var _ElementCannotHaveChildren = 202;
var _ElementIsNotAnArray = 203;
var _NotInitialized = 301;
var _NotImplementedError = 401;
var _InvalidSetValue = 402;
var _ElementIsReadOnly = 403;
var _ElementIsWriteOnly = 404;
var _IncorrectDataType = 405;
var apiHandle = null;
var API = null;
var exitPageStatus;
var numTry = 0;
var isrenchuan = 0;
var startDate;
var lessonProgress = 0;
var dataStatus = "";
//alert("-------------SCORM--------------------001");
function runSeekStr(str, from, to) {
//alert("--------------------SCORM------------002");
var mystr = str;
var str = str.toLowerCase();
var from = from.toLowerCase();
var to = to.toLowerCase();
if (!(str.indexOf(from) + 1)) {
return "";
}
var fromhere = str.indexOf(from) + from.length;
var tostr = str.substr(fromhere, str.length - fromhere);
mystr = mystr.substr(fromhere, str.length - fromhere);
var tothere = tostr.length;
if (to != "" && (tostr.indexOf(to) + 1)) {
tothere = tostr.indexOf(to);
}
return mystr.substr(0, tothere);
}
function runFind(url) {
//alert("--------------------SCORM------------003");
try {
isrenchuan = runSeekStr(url, "isrenchuan=", "&");
if (isrenchuan.length) {
return true;
}
else {
return false;
}
}
catch (e) {
return false;
//alert("读取参数时发生错误:\n\n" + e);
}
}
function runURL(win) {
//alert("--------------------SCORM------------004");
try {
if (runFind(win.document.location + "")) {
return true;
}
else {
numTry++;
if (numTry > 1) {
return false;
}
if (win.opener != null) {
if (win == window.top) {
return (runURL(win.opener));
}
}
return (runURL(win.parent));
}
}
catch (e) {
//alert("读取参数时发生错误:\n\n" + e);
return false;
}
}
runURL(window);
function doLMSInitialize() {
//alert("Lms init");
//alert("--------------------SCORM------------005");
var api = getAPIHandle();
if (api == null) {
return "false";
}
var result = api.LMSInitialize("");
if (result.toString() != "true") {
var err = ErrorHandler();
}
doLMSSetValue("cmi.core.score.raw", 0 + "")
return result.toString();
}
function doLMSFinish() {
//alert("--------------------SCORM------------006");
var api = getAPIHandle();
if (api == null) {
return "false";
}
else {
var result = api.LMSFinish("");
if (result.toString() != "true") {
var err = ErrorHandler();
}
}
return result.toString();
}
function doLMSCommit(...data) {
return new Promise(async (resolve, reject) => {
//alert("Lms commit'");
//alert("--------------------SCORM------------007");
var api = getAPIHandle();
if (api == null) {
resolve("false");
} else {
var result = await api.LMSCommit(...data || "");
if (result != "true") {
var err = ErrorHandler();
}
}
resolve(result);
})
}
function doLMSGetValue(name) {
//console.log("Lms read data '" + name +"'");
//alert("--------------------SCORM------------008");
//alert(name);
var api = getAPIHandle();
if (api == null) {
return "";
}
else {
var value = api.LMSGetValue(name);
var errCode = api.LMSGetLastError().toString();
if (errCode != _NoError) {
var errDescription = api.LMSGetErrorString(errCode);
return "";
}
else {
if (parseInt(isrenchuan)) {
//alert("doLMSGetValue: "+name+" = "+value.toString());
}
return value;
}
}
}
function doLMSSetValue(name, value) {
//console.log("Lms write data '" + name +"' = " + value);
//alert("--------------------SCORM------------009");
//alert(name+":" +value);
if (parseInt(isrenchuan)) {
//alert("doLMSSetValue: "+name+" = "+value);
}
var api = getAPIHandle();
if (api == null) {
return;
}
else {
var result = api.LMSSetValue(name, value);
if (result.toString() != "true") {
var err = ErrorHandler();
}
}
if (name == "cmi.core.lesson_status") {
computeTime();
doLMSCommit();
if (value == "completed") {
//doLMSFinish();
}
}
return;
}
function doLMSGetLastError() {
//alert("--------------------SCORM------------010");
var api = getAPIHandle();
if (api == null) {
return _GeneralError;
}
return api.LMSGetLastError().toString();
}
function doLMSGetErrorString(errorCode) {
//alert("--------------------SCORM------------011");
var api = getAPIHandle();
if (api == null) {
return "false";
}
return api.LMSGetErrorString(errorCode).toString();
}
function doLMSGetDiagnostic(errorCode) {
//alert("--------------------SCORM------------012");
var api = getAPIHandle();
if (api == null) {
return "false";
}
return api.LMSGetDiagnostic(errorCode).toString();
}
function LMSIsInitialized() {
//alert("--------------------SCORM------------013");
var api = getAPIHandle();
if (api == null) {
return "false";
}
else {
var value = api.LMSGetValue("cmi.core.student_name");
var errCode = api.LMSGetLastError().toString();
if (errCode == _NotInitialized) {
return false;
}
else {
return true;
}
}
}
function ErrorHandler() {
//alert("--------------------SCORM------------014");
var api = getAPIHandle();
if (api == null) {
return "false";
}
var errCode = api.LMSGetLastError().toString();
if (errCode != _NoError) {
var errDescription = api.LMSGetErrorString(errCode);
if (_Debug == true) {
errDescription += "\n";
errDescription += api.LMSGetDiagnostic(null);
}
}
return errCode;
}
function getAPIHandle() {
//alert("--------------------SCORM------------015");
if (apiHandle == null) {
var tries = 0;
var win = window;
while ((win.API == null)) {
tries++;
if (tries < 50) {
if ((win.parent != null) && (win.parent != win)) {
win = win.parent;
}
else if ((win.opener != null) && (typeof (win.opener) != "undefined")) {
win = win.opener;
}
else {
break;
}
}
else {
break;
}
}
apiHandle = win.API;
}
return apiHandle;
}
function doSetSCOID(id) {
//alert("--------------------SCORM------------016");
var api = getAPIHandle();
if (api == null) {
return "false";
}
doTurnoff();
api.setSCOID(id);
doTurnon();
}
function doTurnon() {
//console.log("doTurnon");
//alert("--------------------SCORM------------017");
startTimer();
var result = doLMSInitialize();
var status = doLMSGetValue("cmi.core.lesson_status");
if (status == "not attempted") {
doLMSSetValue("cmi.core.lesson_status", "incomplete");
}
//var mySCOstatusStr = doLMSGetValue("cmi.suspend_data");
//var location = doLMSGetValue( "cmi.suspend_data" );
//alert("mySCOstatusStr:" +mySCOstatusStr);
//findSWF("main").SetVariable("jsCore",location);
//findSWF("study").SetVariable("jsCore",mySCOstatusStr);
exitPageStatus = false;
if (parseInt(isrenchuan)) {
//alert("jsCore = "+location);
}
}
function startTimer() {
//console.log("startTimer");
//alert("--------------------SCORM------------018");
startDate = new Date().getTime();
}
function computeTime() {
//alert("--------------------SCORM------------019");
if (startDate != 0 && startDate != undefined) {
var currentDate = new Date().getTime();
var elapsedSeconds = ((currentDate - startDate) / 1000);
var formattedTime = convertTotalSeconds(elapsedSeconds);
}
else {
formattedTime = "00:00:00.0";
}
doLMSSetValue("cmi.core.session_time", formattedTime);
}
function doBack() {
//alert("--------------------SCORM------------020");
computeTime();
exitPageStatus = true;
var result;
//result = doLMSCommit();
//result = doLMSFinish();
}
function doContinue(status) {
//alert("--------------------SCORM------------021");
// doLMSSetValue( "cmi.core.exit", "" );
var mode = doLMSGetValue("cmi.core.lesson_mode");
if (mode != "review" && mode != "browse") {
doLMSSetValue("cmi.core.lesson_status", status);
}
exitPageStatus = true;
var result;
//result = doLMSCommit();
//result = doLMSFinish();
}
function doQuit() {
//alert("--------------------SCORM------------022");
doLMSSetValue("cmi.core.exit", "suspend");
computeTime();
exitPageStatus = true;
var result;
//result = doLMSCommit();
//result = doLMSFinish();
}
function unloadPage() {
//alert("--------------------SCORM------------023");
//alert("lessonProgress" + lessonProgress)
if (lessonProgress >= 100) {
scoFinished()
}
if (exitPageStatus != true) {
//doQuit();
}
}
function doTurnok() {
//alert("--------------------SCORM------------024");
var mode = doLMSGetValue("cmi.core.lesson_mode");
if (mode != "review" && mode != "browse") {
doLMSSetValue("cmi.core.lesson_status", "completed");
}
exitPageStatus = true;
doLMSSetValue("cmi.core.exit", "");
//doLMSCommit();
//doLMSFinish();
}
function doTurnoff() {
//alert("--------------------SCORM------------025");
if (exitPageStatus != true) {
exitPageStatus = true;
computeTime();
doLMSSetValue("cmi.core.exit", "");
doLMSCommit();
doLMSFinish();
}
}
function getMYSCOstatus(len) {
//alert("--------------------SCORM------------026");
var mySCOstatusStr = doLMSGetValue("cmi.suspend_data");
//alert("mySCOstatusStr:"+mySCOstatusStr);
var arrmySCO = mySCOstatusStr.split("|");
//alert("arrmySCO.length:"+arrmySCO.length);
//alert("len:"+len);
if (arrmySCO.length > len) {
scoFinished();
}
}
function scoFinished() {
//alert("--------------------SCORM------------027");
//alert("本章学习完毕,请点击章节目录继续学习!");
doContinue('completed');
}
function SWFSetValue(type, val) {
//alert("--------------------SCORM------------028");
//alert("type:" + type);
//alert("val:" + val);
if (type == "cmi.core.lesson_progress") {
lessonProgress = val
//alert("lessonProgress:" + lessonProgress)
}
if (type == "cmi.suspend_data") {
dataStatus = val
//alert("dataStatus:" + dataStatus)
}
var error = doLMSSetValue(type, val);
document.study.SCOReturnValue("ERROR", error);
doLMSCommit()
}
function saveScos(i) {
//alert("--------------------SCORM------------029");
//alert("提交分数"+i+"分!");
doLMSSetValue("cmi.core.score.raw", i + "")
}
if (window.attachEvent) {
//alert("--------------------SCORM------------030");
window.attachEvent('onunload', function () {
doTurnoff();
});
}
else if (window.addEventListener) {
//alert("--------------------SCORM------------031");
window.addEventListener('onunload', function () {
doTurnoff();
});
}
function convertTotalSeconds(ts) {
//alert("--------------------SCORM------------032");
var sec = (ts % 60);
ts -= sec;
var tmp = (ts % 3600);
ts -= tmp;
sec = Math.round(sec * 100) / 100;
var strSec = new String(sec);
var strWholeSec = strSec;
var strFractionSec = "";
if (strSec.indexOf(".") != -1) {
strWholeSec = strSec.substring(0, strSec.indexOf("."));
strFractionSec = strSec.substring(strSec.indexOf(".") + 1, strSec.length);
}
if (strWholeSec.length < 2) {
strWholeSec = "0" + strWholeSec;
}
strSec = strWholeSec;
if (strFractionSec.length) {
strSec = strSec + "." + strFractionSec;
}
if ((ts % 3600) != 0)
var hour = 0;
else var hour = (ts / 3600);
if ((tmp % 60) != 0)
var min = 0;
else var min = (tmp / 60);
if ((new String(hour)).length < 2)
hour = "0" + hour;
if ((new String(min)).length < 2)
min = "0" + min;
var rtnVal = hour + ":" + min + ":" + strSec;
return rtnVal;
}
线上课程学习平台
在SCORM课程中引入SCORMAPI12.js,这个js文件是对接了SCORM函数和设置了SCORM数据模型的接口,就是在window.API上挂载函数和数据,然后SCORM课程里面调用SCORM的函数来实现两端的对接,文件示例如下(可根据个人情况进行修改)
(function () {
window.simplifyScorm = {};
/**
* 全局配置
*/
window.simplifyScorm.constants = {
SCORM_TRUE: "true",
SCORM_FALSE: "false",
STATE_NOT_INITIALIZED: 0,
STATE_INITIALIZED: 1,
STATE_TERMINATED: 2,
LOG_LEVEL_DEBUG: 1,
LOG_LEVEL_INFO: 2,
LOG_LEVEL_WARNING: 3,
LOG_LEVEL_ERROR: 4,
LOG_LEVEL_NONE: 5
};
window.simplifyScorm.jsonFormatter = jsonFormatter;
/**
* jsonFormatter//转为json格式
*
* @returns {json}
*/
function jsonFormatter() {
this.jsonString = true;
delete this.toJSON;
var jsonValue = JSON.stringify(this);
delete this.jsonString;
this.toJSON = jsonFormatter;
var returnObject = JSON.parse(jsonValue);
delete returnObject.jsonString;
for (var key in returnObject) {
if (returnObject.hasOwnProperty(key) && key.indexOf("_") === 0) {
delete returnObject[key];
}
}
return returnObject;
}
})();
/**
* BaseAPI
*/
(function () {
window.simplifyScorm.BaseAPI = BaseAPI;
var constants = window.simplifyScorm.constants;
function BaseAPI() {
var _self = this;
// Internal State
_self.currentState = constants.STATE_NOT_INITIALIZED;
_self.lastErrorCode = 0;
// Utility Functions
_self.apiLog = apiLog;
_self.apiLogLevel = constants.LOG_LEVEL_ERROR;
_self.clearSCORMError = clearSCORMError;
_self.getLmsErrorMessageDetails = getLmsErrorMessageDetails;
_self.isInitialized = isInitialized;
_self.isNotInitialized = isNotInitialized;
_self.isTerminated = isTerminated;
_self.listenerArray = [];
_self.on = onListener;
_self.processListeners = processListeners;
_self.throwSCORMError = throwSCORMError;
}
/**
* Logging for all SCORM actions
*
* @param functionName
* @param CMIElement
* @param logMessage
* @param messageLevel
*/
function apiLog(functionName, CMIElement, logMessage, messageLevel) {
logMessage = formatMessage(functionName, CMIElement, logMessage);
if (messageLevel >= this.apiLogLevel) {
switch (messageLevel) {
case constants.LOG_LEVEL_ERROR:
console.error(logMessage);
break;
case constants.LOG_LEVEL_WARNING:
console.warn(logMessage);
break;
case constants.LOG_LEVEL_INFO:
console.info(logMessage);
break;
}
}
}
/**
* Clears the last SCORM error code on success
*/
function clearSCORMError(success) {
if (success !== constants.SCORM_FALSE) {
this.lastErrorCode = 0;
}
}
/**
* Formats the SCORM messages for easy reading
*
* @param functionName
* @param CMIElement
* @param message
* @returns {string}
*/
function formatMessage(functionName, CMIElement, message) {
var baseLength = 20;
var messageString = "";
messageString += functionName;
var fillChars = baseLength - messageString.length;
for (var i = 0; i < fillChars; i++) {
messageString += " ";
}
messageString += ": ";
if (CMIElement) {
var CMIElementBaseLength = 70;
messageString += CMIElement;
fillChars = CMIElementBaseLength - messageString.length;
for (var j = 0; j < fillChars; j++) {
messageString += " ";
}
}
if (message) {
messageString += message;
}
return messageString;
}
/**
* Returns the message that corresponds to errrorNumber
* APIs that inherit BaseAPI should override this function
*/
function getLmsErrorMessageDetails(_errorNumber, _detail) {
return "No error";
}
/**
* Returns true if the API's current state is STATE_INITIALIZED
*/
function isInitialized() {
return this.currentState === constants.STATE_INITIALIZED;
}
/**
* Returns true if the API's current state is STATE_NOT_INITIALIZED
*/
function isNotInitialized() {
return this.currentState === constants.STATE_NOT_INITIALIZED;
}
/**
* Returns true if the API's current state is STATE_TERMINATED
*/
function isTerminated() {
return this.currentState === constants.STATE_TERMINATED;
}
/**
* Provides a mechanism for attaching to a specific SCORM event
*
* @param listenerString
* @param callback
*/
function onListener(listenerString, callback) {
if (!callback) return;
var listenerFunctions = listenerString.split(" ");
for (var i = 0; i < listenerFunctions.length; i++) {
var listenerSplit = listenerFunctions[i].split(".");
if (listenerSplit.length === 0) return;
var functionName = listenerSplit[0];
var CMIElement = null;
if (listenerSplit.length > 1) {
CMIElement = listenerString.replace(functionName + ".", "");
}
this.listenerArray.push({
functionName: functionName,
CMIElement: CMIElement,
callback: callback
});
}
}
/**
* Processes any 'on' listeners that have been created
*
* @param functionName
* @param CMIElement
* @param value
*/
function processListeners(functionName, CMIElement, value) {
for (var i = 0; i < this.listenerArray.length; i++) {
var listener = this.listenerArray[i];
console.log(11, listener)
var functionsMatch = listener.functionName === functionName;
var listenerHasCMIElement = !!listener.CMIElement;
var CMIElementsMatch = listener.CMIElement === CMIElement;
if (functionsMatch && (!listenerHasCMIElement || CMIElementsMatch)) {
listener.callback(CMIElement, value);
}
}
}
/**
* Throws a SCORM error
*
* @param errorNumber
* @param message
*/
function throwSCORMError(errorNumber, message) {
if (!message) {
message = this.getLmsErrorMessageDetails(errorNumber);
}
this.apiLog("throwSCORMError", null, errorNumber + ": " + message, constants.LOG_LEVEL_ERROR);
this.lastErrorCode = String(errorNumber);
}
})();
/**
* ScormAPI
*/
(function () {
window.simplifyScorm.ScormAPI = ScormAPI;
var BaseAPI = window.simplifyScorm.BaseAPI;
var constants = window.simplifyScorm.constants;
var jsonFormatter = window.simplifyScorm.jsonFormatter;
window.API = new ScormAPI();
function ScormAPI() {
var _self = this;
BaseAPI.call(_self);
// API Signature
_self.LMSInitialize = LMSInitialize;
_self.LMSFinish = LMSFinish;
_self.LMSGetValue = LMSGetValue;
_self.LMSSetValue = LMSSetValue;
_self.LMSCommit = LMSCommit;
_self.LMSGetLastError = LMSGetLastError;
_self.LMSGetErrorString = LMSGetErrorString;
_self.LMSGetDiagnostic = LMSGetDiagnostic;
// Data Model
_self.cmi = new CMI(_self);
// Utility Functions
_self.checkState = checkState;
_self.getLmsErrorMessageDetails = getLmsErrorMessageDetails;
_self.loadFromJSON = loadFromJSON;
_self.replaceWithAnotherScormAPI = replaceWithAnotherScormAPI;
/**
* @returns {string} bool 初始化
*/
function LMSInitialize() {
var returnValue = constants.SCORM_FALSE;
if (_self.isInitialized()) {
_self.throwSCORMError(101, "LMS已经初始化!");
} else if (_self.isTerminated()) {
_self.throwSCORMError(101, "LMS已经完成!");
} else {
_self.currentState = constants.STATE_INITIALIZED;
returnValue = constants.SCORM_TRUE;
_self.processListeners("LMSInitialize");
}
_self.apiLog("LMSInitialize", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
return returnValue;
}
/**
* @returns {string} bool
*/
async function LMSFinish() {
console.log('完成课程', window.API.cmi.toJSON())
var returnValue = constants.SCORM_FALSE;
if (_self.checkState()) {
_self.currentState = constants.STATE_TERMINATED;
returnValue = constants.SCORM_TRUE;
_self.processListeners("LMSFinish");
}
_self.apiLog("LMSFinish", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
var ifSend = await updateCourseApi() //修改课程学习
if (ifSend) {
returnValue = constants.SCORM_TRUE
} else {
returnValue = constants.SCORM_FALSE
}
return returnValue;
}
/**
* @param CMIElement
* @returns {string}
*/
function LMSGetValue(CMIElement) {
var returnValue = "";
if (_self.checkState()) {
returnValue = getCMIValue(CMIElement);
_self.processListeners("LMSGetValue", CMIElement);
}
_self.apiLog("LMSGetValue", CMIElement, ": returned: " + returnValue, constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
console.log('获取数据', CMIElement, returnValue)
return returnValue;
}
/**
* @param CMIElement
* @param value
* @returns {string}
*/
function LMSSetValue(CMIElement, value) {
console.log('设置数据', CMIElement, value)
var returnValue = "";
if (_self.checkState()) {
returnValue = setCMIValue(CMIElement, value);
_self.processListeners("LMSSetValue", CMIElement, value);
}
_self.apiLog("LMSSetValue", CMIElement, ": " + value + ": returned: " + returnValue, constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
return returnValue;
}
/**
* Orders LMS to store all content parameters
*
* @returns {string} bool
*/
async function LMSCommit(type, data) {
console.log('提交数据', window.API.cmi.toJSON())
var returnValue = constants.SCORM_FALSE;
if (_self.checkState()) {
returnValue = constants.SCORM_TRUE;
_self.processListeners("LMSCommit");
}
_self.apiLog("LMSCommit", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
// 判断调用什么接口
console.log('提交接口的参数----------', type, data)
if (type == 'uploadImg') { //上传图片
return await uploadImgFuc(data)
} else if (type == 'getRank') { //排行榜
return await getRankListFuc(data)
} else if (type == 'getUser') { //用户信息
return await getUserInfoFuc(data)
} else if (type == 'setScore') { //设置分数
return await updateUserScore()
} else { //修改课程学习
let ifSend = await updateCourseApi()
if (ifSend) {
returnValue = constants.SCORM_TRUE
} else {
returnValue = constants.SCORM_FALSE
}
return returnValue;
}
}
/**
* Returns last error code
*
* @returns {string}
*/
function LMSGetLastError() {
var returnValue = _self.lastErrorCode;
_self.processListeners("LMSGetLastError");
_self.apiLog("LMSGetLastError", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
return returnValue;
}
/**
* Returns the errorNumber error description
*
* @param CMIErrorCode
* @returns {string}
*/
function LMSGetErrorString(CMIErrorCode) {
var returnValue = "";
if (CMIErrorCode !== null && CMIErrorCode !== "") {
returnValue = _self.getLmsErrorMessageDetails(CMIErrorCode);
_self.processListeners("LMSGetErrorString");
}
_self.apiLog("LMSGetErrorString", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
return returnValue;
}
/**
* Returns a comprehensive description of the errorNumber error.
*
* @param CMIErrorCode
* @returns {string}
*/
function LMSGetDiagnostic(CMIErrorCode) {
var returnValue = "";
if (CMIErrorCode !== null && CMIErrorCode !== "") {
returnValue = _self.getLmsErrorMessageDetails(CMIErrorCode, true);
_self.processListeners("LMSGetDiagnostic");
}
_self.apiLog("LMSGetDiagnostic", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
return returnValue;
}
/**
* Checks the LMS state and ensures it has been initialized
*/
function checkState() {
if (!this.isInitialized()) {
this.throwSCORMError(301);
return false;
}
return true;
}
/**
* Sets a value on the CMI Object
*
* @param CMIElement
* @param value
* @returns {string}
*/
function setCMIValue(CMIElement, value) {
if (!CMIElement || CMIElement === "") {
return constants.SCORM_FALSE;
}
var structure = CMIElement.split(".");
var refObject = _self;
var found = constants.SCORM_FALSE;
for (var i = 0; i < structure.length; i++) {
if (i === structure.length - 1) {
if (!refObject.hasOwnProperty(structure[i])) {
_self.throwSCORMError(101, "setCMIValue未找到以下项的元素:" + CMIElement);
} else {
refObject[structure[i]] = value;
found = constants.SCORM_TRUE;
}
} else {
refObject = refObject[structure[i]];
if (!refObject) {
_self.throwSCORMError(101, "setCMIValue未找到以下项的元素:" + CMIElement);
break;
}
if (refObject.hasOwnProperty("childArray")) {
var index = parseInt(structure[i + 1], 10);
// SCO is trying to set an item on an array
if (!isNaN(index)) {
var item = refObject.childArray[index];
if (item) {
refObject = item;
} else {
var newChild;
if (CMIElement.indexOf("cmi.objectives") > -1) {
newChild = new CMI_ObjectivesObject(_self);
} else if (CMIElement.indexOf(".correct_responses") > -1) {
newChild = new CMI_InteractionsCorrectResponsesObject(_self);
} else if (CMIElement.indexOf(".objectives") > -1) {
newChild = new CMI_InteractionsObjectivesObject(_self);
} else if (CMIElement.indexOf("cmi.interactions") > -1) {
newChild = new CMI_InteractionsObject(_self);
}
if (!newChild) {
_self.throwSCORMError(101, "无法创建新的子实体:" + CMIElement);
} else {
refObject.childArray.push(newChild);
refObject = newChild;
}
}
// Have to update i value to skip the array position
i++;
}
}
}
}
if (found === constants.SCORM_FALSE) {
_self.apiLog("LMSSetValue", null, "There was an error setting the value for: " + CMIElement + ", value of: " + value, constants.LOG_LEVEL_WARNING);
}
return found;
}
/**
* Gets a value from the CMI Object
*
* @param CMIElement
* @returns {*}
*/
function getCMIValue(CMIElement) {
if (!CMIElement || CMIElement === "") {
return "";
}
var structure = CMIElement.split(".");
var refObject = _self;
var lastProperty = null;
for (var i = 0; i < structure.length; i++) {
lastProperty = structure[i];
if (i === structure.length - 1) {
if (!refObject.hasOwnProperty(structure[i])) {
_self.throwSCORMError(101, "getCMIValue未找到以下项的值:" + CMIElement);
}
}
refObject = refObject[structure[i]];
}
if (refObject === null || refObject === undefined) {
if (lastProperty === "_children") {
_self.throwSCORMError(202);
} else if (lastProperty === "_count") {
_self.throwSCORMError(203);
}
return "";
} else {
return refObject;
}
}
/**
* Returns the message that corresponds to errrorNumber.
*/
function getLmsErrorMessageDetails(errorNumber, detail) {
var basicMessage = "";
var detailMessage = "";
// Set error number to string since inconsistent from modules if string or number
errorNumber = String(errorNumber);
switch (errorNumber) {
case "101":
basicMessage = "General Exception";
detailMessage = "No specific error code exists to describe the error. Use LMSGetDiagnostic for more information";
break;
case "201":
basicMessage = "Invalid argument error";
detailMessage = "Indicates that an argument represents an invalid data model element or is otherwise incorrect.";
break;
case "202":
basicMessage = "Element cannot have children";
detailMessage = "Indicates that LMSGetValue was called with a data model element name that ends in \"_children\" for a data model element that does not support the \"_children\" suffix.";
break;
case "203":
basicMessage = "Element not an array - cannot have count";
detailMessage = "Indicates that LMSGetValue was called with a data model element name that ends in \"_count\" for a data model element that does not support the \"_count\" suffix.";
break;
case "301":
basicMessage = "Not initialized";
detailMessage = "Indicates that an API call was made before the call to LMSInitialize.";
break;
case "401":
basicMessage = "Not implemented error";
detailMessage = "The data model element indicated in a call to LMSGetValue or LMSSetValue is valid, but was not implemented by this LMS. SCORM 1.2 defines a set of data model elements as being optional for an LMS to implement.";
break;
case "402":
basicMessage = "Invalid set value, element is a keyword";
detailMessage = "Indicates that LMSSetValue was called on a data model element that represents a keyword (elements that end in \"_children\" and \"_count\").";
break;
case "403":
basicMessage = "Element is read only";
detailMessage = "LMSSetValue was called with a data model element that can only be read.";
break;
case "404":
basicMessage = "Element is write only";
detailMessage = "LMSGetValue was called on a data model element that can only be written to.";
break;
case "405":
basicMessage = "Incorrect Data Type";
detailMessage = "LMSSetValue was called with a value that is not consistent with the data format of the supplied data model element.";
break;
default:
basicMessage = "No Error";
detailMessage = "No Error";
break;
}
return detail ? detailMessage : basicMessage;
}
/**
* Loads CMI data from a JSON object.
*/
function loadFromJSON(json, CMIElement) {
if (!_self.isNotInitialized()) {
console.error("loadFromJSON can only be called before the call to LMSInitialize.");
return;
}
CMIElement = CMIElement || "cmi";
for (var key in json) {
if (json.hasOwnProperty(key) && json[key]) {
var currentCMIElement = CMIElement + "." + key;
var value = json[key];
if (value["childArray"]) {
for (var i = 0; i < value["childArray"].length; i++) {
_self.loadFromJSON(value["childArray"][i], currentCMIElement + "." + i);
}
} else if (value.constructor === Object) {
_self.loadFromJSON(value, currentCMIElement);
} else {
setCMIValue(currentCMIElement, value);
}
}
}
}
/**
* Replace the whole API with another
*/
function replaceWithAnotherScormAPI(newAPI) {
// API Signature
_self.LMSInitialize = newAPI.LMSInitialize;
_self.LMSFinish = newAPI.LMSFinish;
_self.LMSGetValue = newAPI.LMSGetValue;
_self.LMSSetValue = newAPI.LMSSetValue;
_self.LMSCommit = newAPI.LMSCommit;
_self.LMSGetLastError = newAPI.LMSGetLastError;
_self.LMSGetErrorString = newAPI.LMSGetErrorString;
_self.LMSGetDiagnostic = newAPI.LMSGetDiagnostic;
// Data Model
_self.cmi = newAPI.cmi;
// Utility Functions
_self.checkState = newAPI.checkState;
_self.getLmsErrorMessageDetails = newAPI.getLmsErrorMessageDetails;
_self.loadFromJSON = newAPI.loadFromJSON;
_self.replaceWithAnotherScormAPI = newAPI.replaceWithAnotherScormAPI;
// API itself
_self = newAPI; // eslint-disable-line consistent-this
}
return _self;
}
/**
* Scorm 1.2 Cmi data model 数据模型
*/
function CMI(API) {
return {
_suspend_data: "",//暂存数据
get suspend_data() { return this._suspend_data; },
set suspend_data(suspend_data) { this._suspend_data = suspend_data; },
_launch_data: "",//内容对象运行时所需的数据
get launch_data() { return this._launch_data; },
set launch_data(launch_data) { API.isNotInitialized() ? this._launch_data = launch_data : API.throwSCORMError(403); },
_comments: "",//存储评论数据
get comments() { return this._comments; },
set comments(comments) { this._comments = comments; },
_comments_from_lms: "",//存储LMS关于内容对象的评论数据
get comments_from_lms() { return this._comments_from_lms; },
set comments_from_lms(comments_from_lms) { API.isNotInitialized() ? this._comments_from_lms = comments_from_lms : API.throwSCORMError(403); },
core: {
__children: "student_id,student_name,lesson_location,credit,lesson_status,entry,score,total_time,lesson_mode,exit,session_time",
get _children() { return this.__children; },
set _children(_children) { API.throwSCORMError(402); },
_student_id: "",//学生学号
get student_id() { return this._student_id; },
set student_id(student_id) { API.isNotInitialized() ? this._student_id = student_id : API.throwSCORMError(403); },
_student_name: "",//学生姓名
get student_name() { return this._student_name; },
set student_name(student_name) { API.isNotInitialized() ? this._student_name = student_name : API.throwSCORMError(403); },
_lesson_location: "", //记录上次离开sco时的位置
get lesson_location() { return this._lesson_location; },
set lesson_location(lesson_location) { this._lesson_location = lesson_location; },
_lesson_progress: "", //记录课程学习进度
get lesson_progress() { return this._lesson_progress; },
set lesson_progress(lesson_progress) { this._lesson_progress = lesson_progress; },
_credit: "",//是否有学分
get credit() { return this._credit; },
set credit(credit) { API.isNotInitialized() ? this._credit = credit : API.throwSCORMError(403); },
_lesson_status: "not attempted",//记录sco的完成情况
get lesson_status() { return this._lesson_status; },
set lesson_status(lesson_status) { this._lesson_status = lesson_status; },
_entry: "", //入口(进入内容对象)
get entry() { return this._entry; },
set entry(entry) { API.isNotInitialized() ? this._entry = entry : API.throwSCORMError(403); },
_total_time: "",//学习总时间
get total_time() { return this._total_time; },
set total_time(total_time) { API.isNotInitialized() ? this._total_time = total_time : API.throwSCORMError(403); },
_lesson_mode: "normal",//课的模式
get lesson_mode() { return this._lesson_mode; },
set lesson_mode(lesson_mode) { API.isNotInitialized() ? this._lesson_mode = lesson_mode : API.throwSCORMError(403); },
_exit: "",//退出途径
get exit() { return (!this.jsonString) ? API.throwSCORMError(404) : this._exit; },
set exit(exit) { this._exit = exit; },
_session_time: "", //本次学习时间
get session_time() { return (!this.jsonString) ? API.throwSCORMError(404) : this._session_time; },
set session_time(session_time) { this._session_time = session_time; },
score: {
__children: "raw,min,max",
get _children() { return this.__children; },
set _children(_children) { API.throwSCORMError(402); },
_raw: "",//最后一次成绩
get raw() { return this._raw; },
set raw(raw) { this._raw = raw; },
_min: "",//最低成绩
get min() { return this._min; },
set min(min) { this._min = min; },
_max: "100",//最高成绩
get max() { return this._max; },
set max(max) { this._max = max; },
toJSON: jsonFormatter
},
toJSON: jsonFormatter
},
objectives: {
__children: "id,score,status",
get _children() { return this.__children; },
set _children(_children) { API.throwSCORMError(402); },
childArray: [],//返回所有属性
get _count() { return this.childArray.length; },
set _count(_count) { API.throwSCORMError(402); },
toJSON: jsonFormatter
},
student_data: {
__children: "mastery_score,max_time_allowed,time_limit_action",
get _children() { return this.__children; },
set _children(_children) { API.throwSCORMError(402); },
_mastery_score: "",//掌握得分
get mastery_score() { return this._mastery_score; },
set mastery_score(mastery_score) { API.isNotInitialized() ? this._mastery_score = mastery_score : API.throwSCORMError(403); },
_max_time_allowed: "", //最大允许时间
get max_time_allowed() { return this._max_time_allowed; },
set max_time_allowed(max_time_allowed) { API.isNotInitialized() ? this._max_time_allowed = max_time_allowed : API.throwSCORMError(403); },
_time_limit_action: "", //限时反应
get time_limit_action() { return this._time_limit_action; },
set time_limit_action(time_limit_action) { API.isNotInitialized() ? this._time_limit_action = time_limit_action : API.throwSCORMError(403); },
toJSON: jsonFormatter
},
student_preference: { //针对内容对象的用户偏好设置
__children: "audio,language,speed,text",
get _children() { return this.__children; },
set _children(_children) { API.throwSCORMError(402); },
_audio: "",//音频
get audio() { return this._audio; },
set audio(audio) { this._audio = audio; },
_language: "", //语言
get language() { return this._language; },
set language(language) { this._language = language; },
_speed: "", //速度
get speed() { return this._speed; },
set speed(speed) { this._speed = speed; },
_text: "", //文本
get text() { return this._text; },
set text(text) { this._text = text; },
toJSON: jsonFormatter
},
interactions: {
__children: "id,objectives,time,type,correct_responses,weighting,student_response,result,latency",
get _children() { return this.__children; },
set _children(_children) { API.throwSCORMError(402); },
childArray: [],// 返回集合中元素总数
get _count() { return this.childArray.length; },
set _count(_count) { API.throwSCORMError(402); },
toJSON: jsonFormatter
},
toJSON: jsonFormatter
};
}
function CMI_InteractionsObject(API) {
return {
_id: "",//某一交互ID
get id() { return (!this.jsonString) ? API.throwSCORMError(404) : this._id; },
set id(id) { this._id = id; },
_time: "",//交互完成时间
get time() { return (!this.jsonString) ? API.throwSCORMError(404) : this._time; },
set time(time) { this._time = time; },
_type: "",//交互类型(true-false/choice/fill-in/matching/performance/sequencing/likert/numeric)
get type() { return (!this.jsonString) ? API.throwSCORMError(404) : this._type; },
set type(type) { this._type = type; },
_weighting: "",//一个交互的权重
get weighting() { return (!this.jsonString) ? API.throwSCORMError(404) : this._weighting; },
set weighting(weighting) { this._weighting = weighting; },
_student_response: "",//用户提供的答案
get student_response() { return (!this.jsonString) ? API.throwSCORMError(404) : this._student_response; },
set student_response(student_response) { this._student_response = student_response; },
_result: "",//由用户答案计算的交互结果 (correct/wrong/unanticipated/neutral/x.x)
get result() { return (!this.jsonString) ? API.throwSCORMError(404) : this._result; },
set result(result) { this._result = result; },
_latency: "",// 交互时间间隔
get latency() { return (!this.jsonString) ? API.throwSCORMError(404) : this._latency; },
set latency(latency) { this._latency = latency; },
objectives: {//交互目标集合中总数
childArray: [],
get _count() { return this.childArray.length; },
set _count(_count) { API.throwSCORMError(402); },
toJSON: jsonFormatter
},
correct_responses: {//存储一个交互的答案数
childArray: [],
get _count() { return this.childArray.length; },
set _count(_count) { API.throwSCORMError(402); },
toJSON: jsonFormatter
},
toJSON: jsonFormatter
};
}
function CMI_ObjectivesObject(API) {
return {
_id: "",//一个目标对象ID
get id() { return this._id; },
set id(id) { this._id = id; },
_status: "",//目标完成状态(passed/completed/failed/incomplete/browsed/not attempted)
get status() { return this._status; },
set status(status) { this._status = status; },
score: {
__children: "raw,min,max",//获得score子属性
get _children() { return this.__children; },
set _children(children) { API.throwSCORMError(402); },
_raw: "",//目标分数
get raw() { return this._raw; },
set raw(raw) { this._raw = raw; },
_min: "",//目标分数最小值
get min() { return this._min; },
set min(min) { this._min = min; },
_max: "",//目标分数最大值
get max() { return this._max; },
set max(max) { this._max = max; },
toJSON: jsonFormatter
},
toJSON: jsonFormatter
};
}
function CMI_InteractionsObjectivesObject(API) {
return {
_id: "", //交互的目标ID
get id() { return (!this.jsonString) ? API.throwSCORMError(404) : this._id; },
set id(id) { this._id = id; },
toJSON: jsonFormatter
};
}
function CMI_InteractionsCorrectResponsesObject(API) {
return {
_pattern: "",//存储一个交互的答案
get pattern() { return (!this.jsonString) ? API.throwSCORMError(404) : this._pattern; },
set pattern(pattern) { this._pattern = pattern; },
toJSON: jsonFormatter
};
}
})();