﻿$TTFlash med SCORM 1.2-uppföljning
$DS
Publiceringsmall för ADL/SCORM 1.2-kommunikation. Mallen har modifierats särskilt för Utbildningsinteraktioner. Innehåller JavaScript för att söka efter och initera ett ADL API 1.2-objekt samt FSCommand-"klister" som gör att LMS-funktioner kan anropas från Flash.

$DF

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="sv" lang="sv">
<head>
$CS
<script type="text/javascript" language="JavaScript" name="fsIeVbscript">
<!--
// Koppling för Internet Explorer
if (navigator.appName && navigator.appName.indexOf("Microsoft") != -1 && navigator.userAgent.indexOf("Windows") != -1 && navigator.userAgent.indexOf("Windows 3.1") == -1) {
	document.write('<script language=\"VBScript\"\>\n');
	document.write('On Error Resume Next\n');
	document.write('Sub $TI_FSCommand(ByVal command, ByVal args)\n');
	document.write('	Call $TI_DoFSCommand(command, args)\n');
	document.write('End Sub\n');
	document.write('</script\>\n');
}
//-->
</script>
<title>$TI</title>
</head>
<script type="text/javascript" language="JavaScript" name="cmifrag">
<!--

// FS SCORM – fscommand-adapter för ADL SCORM 1.2 och Flash MX 2004 Learning Interactions
// version 1.0    08/19/03
// Modified by Andrew Chemey, Macromedia
// Baseras på version 1.2.4 av FS SCORM-adaptern:
// \t\tFragments Copyright 2002 Pathlore Software Corporation All rights Reserved
// \t\tFragments Copyright 2002 Macromedia Inc. All rights reserved.
// \t\tFragments Copyright 2003 Click2learn, Inc. All rights reserved.
// \t\tDeveloped by Tom King, Macromedia, Leonard Greenberg, Pathlore, and Claude Ostyn, Click2learn, Inc.
// \t\tIncludes code by Jeff Burton and Andrew Chemey, Macromedia (01/09/02)
// -----------------------------------------------------------------

// Ändra dessa förinställda värden så att det passar dina behov.

var g_bShowApiErrors = false; 	// ändra till true för att visa felmeddelanden

var g_bInitializeOnLoad = true; // ändra till false om LMS inte ska initieras när HTML-sidan läses in

// Översätt dessa strängar om g_bShowApiErrors är true och programmet behöver lokaliseras
var g_strAPINotFound = "Management system interface not found.";
var g_strAPITooDeep = "Cannot find API - too deeply nested.";
var g_strAPIInitFailed = "Found API but LMSInitialize failed.";
var g_strAPISetError = "Trying to set value but API not available.";
var g_strFSAPIError = 'LMS API adapter returned error code: "%1"\nWhen FScommand called API.%2\nwith "%3"';
var g_strDisableErrorMsgs = "Select cancel to disable future warnings.";

// Ändra g_bSetCompletedAutomatically till true om du vill att statusen ska ställas in på completed automatiskt när LMSFinish anropas.
// Den här flaggan förblir normalt false om Flash-filmen själv anger att statusen är completed genom att ett FSCommand-kommando används för att ställa in statusen på "completed", "passed" eller "failed" (båda dessa innebär även "completed"). "passed" or "failed" (both of which imply "completed")
var g_bSetCompletedAutomatically = false;

// Det här värdet anges normalt av LMS, men om det inte gör det är det här standardvärdet som används för att avgöra om statusen är passed eller failed.
// Ställ in värdet på null om Flash-skriptet har en egen metod som avgör om statusen är passed eller failed. Ange annars ett värde från 0 till 1 (inklusivt, kan vara ett flyttal, till exempel "0.75").
var g_SCO_MasteryScore = null; // tillåtna värden: 0.0..1.0, or null

//==================================================================

// VARNING!
// Ändra ingenting nedanför den här raden om du inte är säker på att du vet vad du gör.
// Du behöver normalt inte ändra dessa två värden eftersom Flash-mallens förinställda värden baseras på dem.
var g_nSCO_ScoreMin = 0; 		// måste vara ett tal
var g_nSCO_ScoreMax = 100; 		// måste vara ett tal > nSCO_Score_Min

// Enligt SCORM-specifikationen ersätter en eventuell färdighetspoäng från LMS SCO för att avgöra om poängen ska tolkas när statusen (passed eller failed) avgörs.
// Mallen försöker hämta färdighetspoängen. Om den är tillgänglig ställs statusen in på passed eller failed när SCO skickar ett poängvärde.
// LMS kan inte göra bedömningen förrän SCO har avslutats.
// Standardvärdet för den här flaggan är true. Ställ in den på false om du inte vill förutse hur LMS kommer att ställa in statusen (passed eller failed) baserat på färdighetspoängen (LMS är ändå alltid avgörande).
var g_bInterpretMasteryScore = true;

// Skriptet implementerar olika typer av normalt logiskt beteende för en SCO.

/////////// API-GRÄNSSNITTSINITIERING OCH CATCH-FUNKTIONER ////////
var g_nFindAPITries = 0;
var g_objAPI = null;
var g_bInitDone = false;
var g_bFinishDone = false;
var	g_bSCOBrowse = false;
var g_dtmInitialized = new Date(); // justeras efter initieringen
var g_bMasteryScoreInitialized = false;

function AlertUserOfAPIError(strText) {
	if (g_bShowApiErrors) {
		var s = strText + "\n\n" + g_strDisableErrorMsgs;
		if (!confirm(s)){
			g_bShowApiErrors = false
		}
	}
}

function ExpandString(s){
	var re = new RegExp("%","g")
	for (i = arguments.length-1; i > 0; i--){
		s2 = "%" + i;
		if (s.indexOf(s2) > -1){
			re.compile(s2,"g")
			s = s.replace(re, arguments[i]);
		}
	}
	return s
}

function FindAPI(win) {
	while ((win.API == null) && (win.parent != null) && (win.parent != win)) {
		g_nFindAPITries ++;
		if (g_nFindAPITries > 500) {
			AlertUserOfAPIError(g_strAPITooDeep);
			return null;
		}
		win = win.parent;
	}
	return win.API;
}

function APIOK() {
	return ((typeof(g_objAPI)!= "undefined") && (g_objAPI != null))
}

function SCOInitialize() {
	var err = true;
	if (!g_bInitDone) {
		if ((window.parent) && (window.parent != window)){
			g_objAPI = FindAPI(window.parent)
		}
		if ((g_objAPI == null) && (window.opener != null))	{
			g_objAPI = FindAPI(window.opener)
		}
		if (!APIOK()) {
			AlertUserOfAPIError(g_strAPINotFound);
			err = false
		} else {
			err = g_objAPI.LMSInitialize("");
			if (err == "true") {
				g_bSCOBrowse = (g_objAPI.LMSGetValue("cmi.core.lesson_mode") == "browse");						if (!g_bSCOBrowse) {
					if (g_objAPI.LMSGetValue("cmi.core.lesson_status") == "not attempted") {
						err = g_objAPI.LMSSetValue("cmi.core.lesson_status","incomplete")
					}
				}
			} else {
				AlertUserOfAPIError(g_strAPIInitFailed)
			}
		}
		if (typeof(SCOInitData) != "undefined") {
			// Funktionen SCOInitData kan definieras i ett annat skript i SCO
			SCOInitData()
		}
		g_dtmInitialized = new Date();
	}
	g_bInitDone = true;
	return (err + "") // Tvinga typ för sträng
}

function SCOFinish() {
	if ((APIOK()) && (g_bFinishDone == false)) {
		SCOReportSessionTime()
		if (g_bSetCompletedAutomatically){
			SCOSetStatusCompleted();
		}
		if (typeof(SCOSaveData) != "undefined"){
			// Funktionen SCOSaveData kan definieras i ett annat skript i SCO
			SCOSaveData();
		}
		g_bFinishDone = (g_objAPI.LMSFinish("") == "true");
	}
	return (g_bFinishDone + "" ) // Tvinga typ för sträng
}

// Anropa dessa catch-funktioner i stället för att försöka anropa API-adaptern direkt
function SCOGetValue(nam)			{return ((APIOK())?g_objAPI.LMSGetValue(nam.toString()):"")}
function SCOCommit()					{return ((APIOK())?g_objAPI.LMSCommit(""):"false")}
function SCOGetLastError()		{return ((APIOK())?g_objAPI.LMSGetLastError():"-1")}
function SCOGetErrorString(n)	{return ((APIOK())?g_objAPI.LMSGetErrorString(n):"No API")}
function SCOGetDiagnostic(p)	{return ((APIOK())?g_objAPI.LMSGetDiagnostic(p):"No API")}

//LMSSetValue implementeras med mer komplicerad datahanteringslogik nedan

var g_bMinScoreAcquired = false;
var g_bMaxScoreAcquired = false;

// Speciallogik börjar här
function SCOSetValue(nam,val){
	var err = "";
	if (!APIOK()){
			AlertUserOfAPIError(g_strAPISetError + "\n" + nam + "\n" + val);
			err = "false"
	} else if (nam == "cmi.core.score.raw") err = privReportRawScore(val)
	if (err == ""){
			err = g_objAPI.LMSSetValue(nam,val.toString() + "");
			if (err != "true") return err
	}
	if (nam == "cmi.core.score.min"){
		g_bMinScoreAcquired = true;
		g_nSCO_ScoreMin = val
	}
	else if (nam == "cmi.core.score.max"){
		g_bMaxScoreAcquired = true;
		g_nSCO_ScoreMax = val
	}
	return err
}

function privReportRawScore(nRaw) { // anropas bara av SCOSetValue
	if (isNaN(nRaw)) return "false";
	if (!g_bMinScoreAcquired){
		if (g_objAPI.LMSSetValue("cmi.core.score.min",g_nSCO_ScoreMin+"")!= "true") return "false"
	}
	if (!g_bMaxScoreAcquired){
		if (g_objAPI.LMSSetValue("cmi.core.score.max",g_nSCO_ScoreMax+"")!= "true") return "false"
	}
	if (g_objAPI.LMSSetValue("cmi.core.score.raw", nRaw)!= "true") return "false";
	g_bMinScoreAcquired = false;
	g_bMaxScoreAcquired = false;
	if (!g_bMasteryScoreInitialized){
		var nMasteryScore = parseInt(SCOGetValue("cmi.student_data.mastery_score"),10);
		if (!isNaN(nMasteryScore)) g_SCO_MasteryScore = nMasteryScore
	}
  	if ((g_bInterpretMasteryScore)&&(!isNaN(g_SCO_MasteryScore))){
    	var stat = (nRaw >= g_SCO_MasteryScore? "passed" : "failed");
    	if (SCOSetValue("cmi.core.lesson_status",stat) != "true") return "false";
  	}
  	return "true"
}

function MillisecondsToCMIDuration(n) {
//Konvertera varaktighet från millisekunder till formatet 0000:00:00.00
	var hms = "";
	var dtm = new Date();	dtm.setTime(n);
	var h = "000" + Math.floor(n / 3600000);
	var m = "0" + dtm.getMinutes();
	var s = "0" + dtm.getSeconds();
	var cs = "0" + Math.round(dtm.getMilliseconds() / 10);
	hms = h.substr(h.length-4)+":"+m.substr(m.length-2)+":";
	hms += s.substr(s.length-2)+"."+cs.substr(cs.length-2);
	return hms
}

// SCOReportSessionTime anropas automatiskt av det här skriptet, men du kan dessutom anropa det från SCO när som helst
function SCOReportSessionTime() {
	var dtm = new Date();
	var n = dtm.getTime() - g_dtmInitialized.getTime();
	return SCOSetValue("cmi.core.session_time",MillisecondsToCMIDuration(n))
}

// Eftersom bara den som konstruerat en SCO vet vad "completed" innebär, kan ett annat skript i SCO:n anropa funktionen för att ställa in statusen på "completed".
// Funktionen kontrollerar att SCO inte är i bläddringsläge utan att ange statusen "passed" eller "failed" eftersom de även innebär "completed".
function SCOSetStatusCompleted(){
	var stat = SCOGetValue("cmi.core.lesson_status");
	if (SCOGetValue("cmi.core.lesson_mode") != "browse"){
		if ((stat!="completed") && (stat != "passed") && (stat != "failed")){
			return SCOSetValue("cmi.core.lesson_status","completed")
		}
	} else return "false"
}

// Objektiv hanteringslogik

function SCOSetObjectiveData(id, elem, v) {
	var result = "false";
	var i = SCOGetObjectiveIndex(id);
	if (isNaN(i)) {
		i = parseInt(SCOGetValue("cmi.objectives._count"));
		if (isNaN(i)) i = 0;
		if (SCOSetValue("cmi.objectives." + i + ".id", id) == "true"){
			result = SCOSetValue("cmi.objectives." + i + "." + elem, v)
		}
	} else {
		result = SCOSetValue("cmi.objectives." + i + "." + elem, v);
		if (result != "true") {
			// Denna LMS kanske bara accepterar journalposter
			i = parseInt(SCOGetValue("cmi.objectives._count"));
			if (!isNaN(i)) {
				if (SCOSetValue("cmi.objectives." + i + ".id", id) == "true"){
					result = SCOSetValue("cmi.objectives." + i + "." + elem, v)
				}
			}
		}
	}
	return result
}

function SCOGetObjectiveData(id, elem) {
	var i = SCOGetObjectiveIndex(id);
	if (!isNaN(i)) {
		return SCOGetValue("cmi.objectives." + i + "."+elem)
	}
	return ""
}

function SCOGetObjectiveIndex(id){
	var i = -1;
	var nCount = parseInt(SCOGetValue("cmi.objectives._count"));
	if (!isNaN(nCount)) {
		for (i = nCount-1; i >= 0; i--){ //gå bakåt om LMS för journal
			if (SCOGetValue("cmi.objectives." + i + ".id") == id) {
				return i
			}
		}
	}
	return NaN
}

// Konverterar AICC-kompatibla token eller förkortningar till SCORM-token
function AICCTokenToSCORMToken(strList,strTest){
	var a = strList.split(",");
	var c = strTest.substr(0,1).toLowerCase();
	for (i=0;i<a.length;i++){
			if (c == a[i].substr(0,1)) return a[i]
	}
	return strTest
}

function normalizeStatus(status){
	return AICCTokenToSCORMToken("completed,incomplete,not attempted,failed,passed", status)
}

function normalizeInteractionType(theType){
	return AICCTokenToSCORMToken("true-false,choice,fill-in,matching,performance,sequencing,likert,numeric", theType)
}

function normalizeInteractionResult(result){
	return AICCTokenToSCORMToken("correct,wrong,unanticipated,neutral", result)
}

// Identifiera Internet Explorer
var g_bIsInternetExplorer = navigator.appName.indexOf("Microsoft") != -1;

// Hantera fscommand-meddelanden från en Flash-film. Alla AICC Flash-mallkommandon mappas om till SCORM om det behövs
function $TI_DoFSCommand(command, args){

	var $TIObj = g_bIsInternetExplorer ? $TI : document.$TI;

	// fungerar inte om det inte finns någon SCORM API

	var myArgs = new String(args);
	var cmd = new String(command);
	var v = "";
	var err = "true";
	var arg1, arg2, n, s, i;
	var sep = myArgs.indexOf(",");
	if (sep > -1){
		arg1 = myArgs.substr(0, sep); // Namn på dataelement som ska hämtas från API
		arg2 = myArgs.substr(sep+1) 	// Namnet på Flash-filmvariabeln som ska ställas in
	} else {
		arg1 = myArgs
	}
	if (!APIOK()) return;

	if (cmd.substring(0,3) == "LMS"){
		// Hantera "LMSxxx"-FScommands (kompatibla med HTML-mallen fsSCORM)
		if ( cmd == "LMSInitialize" ){
			err = (APIOK() + "")
			// Den faktiska LMSInitialize anropas automatiskt av mallen
		}	else if ( cmd == "LMSSetValue" ){
			err = SCOSetValue(arg1,arg2)
		} else if ( cmd == "LMSFinish" ){
			err = SCOFinish()
			// Hanteras automatiskt av mallen, men kan may call it earlier.
		}	else if ( cmd == "LMSCommit" ){
			err = SCOCommit()
		}	else if ( cmd == "LMSFlush" ){
			// no-op
			// LMSFlush för felfunktion är inte definierad i SCORM och om den anropas uppstår fel i testningen
		}	else if ((arg2) && (arg2.length > 0)){
			if ( cmd == "LMSGetValue") {
				$TIObj.SetVariable(arg2, SCOGetValue(arg1));
			}	else if ( cmd == "LMSGetLastError") {
				$TIObj.SetVariable(arg2, SCOGetLastError(arg1));
			}	else if ( cmd == "LMSGetErrorString") {
				$TIObj.SetVariable(arg2, SCOGetLastError(arg1));
			}	else if ( cmd == "LMSGetDiagnostic") {
				$TIObj.SetVariable(arg2, SCOGetDiagnostic(arg1));
			}	else {
				// för okänt LMSGetxxxx-tillägg
				v = eval('g_objAPI.' + cmd + '(\"' + arg1 + '\")');
				$TIObj.SetVariable(arg2,v);
			}
		} else if (cmd.substring(0,3) == "LMSGet") {
			err = "-2: No Flash variable specified"
		}
		// slut på hantering av "LMSxxx"-kommandon
	} else if ((cmd.substring(0,6) == "MM_cmi")||(cmd.substring(0,6) == "CMISet")) {
		// Hantera FScommands för Macromedia Learning Components.
		// För dessa används AICC HACP-datamodellkonventioner. Mappa därför om data från AICC till SCORM när det behövs.
		var F_intData = myArgs.split(";");
		if (cmd == "MM_cmiSendInteractionInfo") {
			n = SCOGetValue("cmi.interactions._count");
			s = "cmi.interactions." + n + ".";
			// Hantera bruttofel så att testfel för SCORM-kompatibilitet kan undvikas
			// Om inget ID anges för den här interaktionen kan den inte registreras
			v = F_intData[2]
			if ((v == null) || (v == "")) err = 201; // Det är meningslöst att registrera utan ID
			if (err =="true"){
				err = SCOSetValue(s + "id", v)
			}
			if (err =="true"){
				var re = new RegExp("[{}]","g")
				for (i=1; (i<9) && (err=="true"); i++){
					v = F_intData[i];
					if ((v == null) || (v == "")) continue
					if (i == 1){
						err = SCOSetValue(s + "time", v)
					} else if (i == 3){
						err = SCOSetValue(s + "objectives.0.id", v)
					} else if (i == 4){
						err = SCOSetValue(s + "type", normalizeInteractionType(v))
					} else if (i == 5){
						// ta bort "{" och "}" från svar
						v = v.replace(re, "");
						err = SCOSetValue(s + "correct_responses.0.pattern", v)
					} else if (i == 6){
						// ta bort "{" och "}" från svar
						v = v.replace(re, "");
						err = SCOSetValue(s + "student_response", v)
					} else if (i == 7){
						err = SCOSetValue(s + "result", normalizeInteractionResult(v))
					} else if (i == 8){
						err = SCOSetValue(s + "weighting", v)
					} else if (i == 9){
						err = SCOSetValue(s + "latency", v)
					}
				}
			}
		} else if (cmd == "MM_cmiSendObjectiveInfo"){
			err = SCOSetObjectiveData(F_intData[1], ".score.raw", F_intData[2])
			if (err=="true"){
				SCOSetObjectiveData(F_intData[1], ".status", normalizeStatus(F_intData[3]))
			}
		} else if ((cmd=="CMISetScore") ||(cmd=="MM_cmiSendScore")){
			err = SCOSetValue("cmi.core.score.raw", F_intData[0]);
		} else if ((cmd=="CMISetStatus") || (cmd=="MM_cmiSetLessonStatus")){
			err = SCOSetValue("cmi.core.lesson_status", normalizeStatus(F_intData[0]))
		} else if (cmd=="CMISetTime"){
			err = SCOSetValue("cmi.core.session_time", F_intData[0])
		} else if (cmd=="CMISetCompleted"){
			err = SCOSetStatusCompleted()
		} else if (cmd=="CMISetStarted"){
			err = SCOSetValue("cmi.core.lesson_status", "incomplete")
		} else if (cmd=="CMISetPassed"){
			err = SCOSetValue("cmi.core.lesson_status", "passed")
		} else if (cmd=="CMISetFailed"){
			err = SCOSetValue("cmi.core.lesson_status", "failed")
		} else if (cmd=="CMISetData"){
			err = SCOSetValue("cmi.suspend_data", F_intData[0])
		} else if (cmd=="CMISetLocation"){
			err = SCOSetValue("cmi.core.lesson_location", F_intData[0])
		} else if (cmd=="CMISetTimedOut"){
			err = SCOSetValue("cmi.core.exit", "time-out")
		} // Inga andra FScommands för Learning Component fungerar i kontexten
	} else {
		if (cmd=="CMIFinish" || cmd=="CMIExitAU"){
			err = SCOFinish()
		} else if (cmd=="CMIInitialize" || cmd=="MM_StartSession"){
			err = SCOInitialize()
		} else {
			// Okänt kommando. Kan anropa ett API-tillägg
			// Anta att ett värde förväntas om kommandot har ett andra argument. otherwise assume it is just a cmd
			if (eval('g_objAPI.' + cmd)) {
				v = eval('g_objAPI.' + cmd + '(\"' + arg1 + '\")');
				if ((arg2) && (arg2.length > 0)){
					$TIObj.SetVariable(arg2,v)
				} else {
					err = v
				}
			} else {
				err = "false"
			}
		}
	}
	// Slut på kommandoöversättning och hantering av
	// identifierade fel. Sådana LMS-fel returneras.
	if ((g_bShowApiErrors) && (err != "true")) {
		AlertUserOfAPIError(ExpandString(g_strFSAPIError, err, cmd, args))
	}
	return err
}
//-->
</script>
<body bgcolor="$BG" onload="SCOInitialize()" onunload="SCOFinish()" onbeforeunload="SCOFinish()">
<script type="text/javascript" language="JavaScript" name="earlyInit">
<!--
// Avgör om försök att initiera API ska göras innan en film läses in om det finns en ActionScript som aktiveras innan resten av HTML-sidan har lästs in.
// Detta kan konfigureras genom att det globala booleska värdet (g_bInitializeOnLoad) ställs in i början av filen. Standardvärdet är TRUE.
if (g_bInitializeOnLoad) {
	SCOInitialize()
}
//-->
</script>
<!--URL:er som används i filmen-->
$MU
<!--text som används i filmen-->
$MT
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=$FV,$JR,$NR,0" id="$TI" width="$WI" height="$HE" align="$HA">
<param name="allowScriptAccess" value="sameDomain" />
$PO
<embed $PEwidth="$WI" height="$HE" name="$TI" align="$HA" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.adobe.com/go/getflashplayer_se" />
</object>
</body>
</html>
