0

Hi,

I'm developing scorm based project, I've to play the scorm 2004 packages. courses are playing
and capturing the data working properly with the using of LMS functions(LMSFinish(), commit()..etc).
Now I've to implement one more function i.e RESUME the package where user left last time.

Sample cmi data

scoid:"1234"

data[cmi.completion_status]:"incomplete"

data[cmi.exit]:"suspend"

data[cmi.location]:"page3"

Hope you help.

4 Answers4

3

Commonly 'cmi.suspend_data' is used so you can store a string (JSON, or other delimiter format if you want or need structure) to resume answers.
'cmi.location' has 1000 characters for you to also store a string and it can be as simple as "3" or "page3" as you have it.

Your navigation in your content presentation/player would need to be able to respond to having a location to go to. And you can use the suspend_data to put student answers back the way they were when they left.

How you decide if you are 'resuming' is a little tricky since anything except 'cmi.entry' = 'ab-initio' is a resume. Some LMS systems return blank or 'resume' so then you know to fetch your 'cmi.location' and 'cmi.suspend_data' if you use it.

This is all code you have to write, or you can read up a bit on my Wiki. https://github.com/cybercussion/SCOBot/wiki.

Mark
  • 2,429
  • 20
  • 20
  • Hi Mark, SCOBot is awesome, Thanks lot for your kind information. – Damodar Naidu M Jun 24 '15 at 03:48
  • I'll just point out that cmi.location has a minimum 1000 bytes - in the runtime docs SPM stands for "Smallest Permitted Maximum" - so it could be larger depending on the implementation. – Rycochet Jun 29 '15 at 13:06
  • @Mark Is there a way to popup the Player bultin Resume dialog? I saved the suspended data as well location and then able to retrieve them and continue where they left but I want it to show the bultin Resume dialog. Is that doable? – Ammar Khan May 09 '17 at 23:04
  • @user2866746 how did you resume using Scobot I am trying to achieve the same but I am unable to resume still. I am just saving suspended data not location. Can you help? – Haseeb Khan May 10 '17 at 10:15
  • @user2866746 I did not include a event for confirming the desire to resume a prior session. Technically, once they've suspended previously there is a series of platform checks performed to verify the fact the content is being resumed since LMS Platforms can some times skip setting `cmi.entry`. SCOBot mainly checks if the suspend_data length is > than 0 and then checks the cmi.entry value @ line 1069. https://github.com/cybercussion/SCOBot/blob/master/QUnit-Tests/js/scorm/SCOBot.js – Mark May 10 '17 at 22:50
  • Feature added (event) .. I'll let you sort out the modal/prompt ;) – Mark May 11 '17 at 00:43
  • @Hasseeb I see your message in email. Your issue I believe is platform (Moodle) specific and will require further log reviews to find out why suspend is not resuming. As I've stated on other threads sometimes Moodle will put you in 'review' mode upon setting status/score on a SCO. – Mark May 11 '17 at 00:58
  • Hi guys, could someone help me with [this](https://stackoverflow.com/questions/46008375/cannot-retrieve-previously-saved-data-from-lms-scorm-2004) question/issue about the same topic? – Mauro Aguilar Sep 01 '17 at 21:58
0

I had some workaround for resume and is working for me . I saved suspended_data and then retrieved that data so player resumed for that position .

0

@kishor-koshti How did you do that, I mean, tell the player to resume from a given position? I'm being able to capture the suspended_data but I don't know how to set it back the next time I launch that course. The API object that I have on javascript seems to be read only.

    <html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
    <style>
        body { margin: 0; }
    </style>
    <script type="text/javascript">
        var API = {};

        function setupScormApi() {
            API.LMSInitialize = LMSInitialize;
            API.LMSGetValue = LMSGetValue;
            API.LMSSetValue = LMSSetValue;
            API.LMSCommit = LMSCommit;
            API.LMSFinish = LMSFinish;
            API.LMSGetLastError = LMSGetLastError;
            API.LMSGetDiagnostic = LMSGetDiagnostic;
            API.LMSGetErrorString = LMSGetErrorString;
        }
        function LMSInitialize(initializeInput) {
            console.log("LMSInitialize: " + initializeInput);
            // invokeCSharp("LMSInitialize: " + initializeInput);
            return true;
        }
        function LMSGetValue(varname) {
            console.log("LMSGetValue: " + varname);
            //invokeCSharp("LMSGetValue: " + varname);
            return "";
        }
        function LMSSetValue(varname, varvalue) {
            console.log("LMSSetValue: " + varname + "=" + varvalue);
            // invokeCSharp("LMSSetValue: " + varname + "=" + varvalue);
            return "";
        }
        function LMSCommit(commitInput) {
            console.log("LMSCommit: " + commitInput);
            // invokeCSharp("LMSCommit: " + commitInput);
            return true;
        }
        function LMSFinish(finishInput) {
            console.log("LMSFinish: " + finishInput);
            // invokeCSharp("LMSFinish: " + finishInput);
            return true;
        }
        function LMSGetLastError() {
            console.log("LMSGetLastError: ");
            // invokeCSharp("LMSGetLastError: ");
            return 0;
        }
        function LMSGetDiagnostic(errorCode) {
            console.log("LMSGetDiagnostic: " + errorCode);
            // invokeCSharp("LMSGetDiagnostic: " + errorCode);
            return "";
        }
        function LMSGetErrorString(errorCode) {
            console.log("LMSGetErrorString: " + errorCode);
            // invokeCSharp("LMSGetErrorString: " + errorCode);
            return "";
        }

        setupScormApi();
    </script>
    <iframe id="frm1" src="./Content/index_lms.html" style="width: 100%; height: 100%"></iframe>
</body>
</html>
  • SCO is typically setting its `cmi.location` and `cmi.suspend_data`. Not all SCO's do this or have to. Mainly depends how they are coded. Some will even base64 their suspend_data so there is no set structure since everything in SCORM is a string regarding these two namespaces. I'll also call out LMSCommit is more in line with SCORM 1.2 vs 2004. SCORM 1.2 would be `cmi.core.lesson_location` and you are limited to 255 chars. `cmi.suspend_data` is then limited to 4096 chars down from 64000. [breakdown](https://www.dropbox.com/s/a2w1vym4dm7bjrd/SCOBot-Content-API-Standards-Breakdown.pdf?dl=0) – Mark Feb 14 '20 at 20:51
0

Exec solution by Mehonder

// story_content/user.js

let lastSlideLoaded = ''; //global variable
function Script1() {
    if (lastSlideLoaded == '') {
        lastSlideLoaded = 'X';
        var ACT_firstID = window.globals.parsedParams["last_slide"]; //URL Argument
        if (!ACT_firstID == (null || "" || "0")) {
            Jump_Slide(ACT_firstID); //Set Slide
        }
    } else {
        SetLastSlide(); 
    }
}

function SetLastSlide() {
// send to last slide info to server//
    var xhttp = new XMLHttpRequest();
    var PACKID = window.globals.parsedParams["pack_id"];
    var LASTID = window.DS.presentation.playerProps.attributes.CurrentSlideId;
    var lastSlideURL = "/services_index.php?page=last_slide&pack_id=" + PACKID + "&last_slide=" + LASTID;
    xhttp.open('GET', lastSlideURL, true);
    xhttp.send();
}

function Jump_Slide(Target_Slide) {     
// trigger slide change event //                              
    g = DS.pubSub;              
    p = DS.events;              
    i =  "_player." + Target_Slide;              
    g.trigger(p.request.NEXT_SLIDE, i, "_current")
}