Copy link to clipboard
Copied
I know since Captivate 6, Captivate has used the Rustici SCORM engine which is by far the best that I know of, and this has continued to my knowledge through to version 9. But, the difficulties come in when you do ANYTHING outside the norm in terms of slides, pages and assessments, for example using a single slide with numerous frames which match the frames of an imported video. Trying to get ANY information or specific examples of interacting with SCORM between the various versions is like milking a gerbil. I am specifically using Captivate 9, and I've tried SCORM_Call, etc. since I'm using SCORM 1.2 but no code that I've tried is doing what I want, which is simply detecting if the entire movie has been watched based on current frame, and bouncing that against total frames of the slide the SCO would set either "completed" or "incomplete" setting resume data as appropriate and then calling an LMSFinish(). TO exacerbate the problem, I'm forced to used a significantly customized version of an older LMS that displays SCORM 1.2 content in a pop-up window, first with a frameset that has course description on top , outline parsed from manifest on left frame, and any metadata info tied to each SCO within the right frame. Either the window closes entirely, closing the SCORM Session, and not allowing the user to choose the next SCO, or it just sits there at completion of video, and the user ultimately has to close the window manually via top right window controls, with same result, entire SCORM session is closed, instead of simply the SCO closing via a properly interpreted LMSFinish() and if completed, the SCO gets it's little "checkmark" and you would go onto the next SCO. I have tried so many differing iterations at this point, I'm just getting frustrated, and I need to reach out to the Captivate Users here on Adobe forums to try and get me going in the right direction.
Here's and example of the last thing I tried, and as I said, I don't know if in Captivate 9 I MUST user JSInterface or not!? Here's a few different versions of what I have tried to no avail.
var CpObj = document.Captivate;
var cpFC = cpInfoFrameCount;
var cpCF = cpInfoCurrentFrame;
if (this.CpObj.cpCF == this.CpObj.cpFC) {
SCORM_CallLMSSetValue('cmi.core.lesson_status', 'completed');
SCORM_CallLMSSetValue('cmi.core.suspend_data','');
SCORM_CallLMSSetValue('cmi.core.exit','');
SCORM_CallLMSFinish();
SetReachedEnd();
}
else {
SCORM_CallLMSSetValue('cmi.core.lesson_status', 'incomplete');
SCORM_CallLMSSetValue('cmi.suspend_data', this.CpObj.cpCF);
SCORM_CallLMSSetValue('cmi.core.exit','suspend');
SCORM_CallLMSFinish();
}
V2
var CpObj = document.Captivate;
var cpFC = cpInfoFrameCount;
var cpCF = cpInfoCurrentFrame;
if (this.CpObj.cpCF == this.CpObj.cpFC) {
SCORM_CallLMSSetValue('cmi.core.lesson_status', 'completed');
SCORM_CallLMSSetValue('cmi.core.suspend_data','');
SCORM_CallLMSSetValue('cmi.core.exit','');
SCORM_CallLMSFinish();
SetReachedEnd();
window.history.go(0);
}
else {
SCORM_CallLMSSetValue('cmi.core.lesson_status', 'incomplete');
SCORM_CallLMSSetValue('cmi.suspend_data', this.CpObj.cpCF);
SCORM_CallLMSSetValue('cmi.core.exit','suspend');
SCORM_CallLMSFinish();
window.history.go(0);
}
Copy link to clipboard
Copied
This sort of detailed JS integration is over my head, so I was going to paste links to Jim L's older JS references, but see from here:
http://www.infosemantics.com.au/adobe-captivate-advanced-elearning-tutorials/javascript-guide
That you've already been down that road.
Maybe Rod can be of more direct assistance...
BUT I don't think you can do what you want.. Even if you could customize the value of 'completed/incomplete' via JS - so it was based on how many frames of a video were watched, Captivate can't resume to a specific frame in a slide...
Best you could probably do is break up the video across CP slides - maybe average 15 seconds per slide. If the video is not 'Event' but is embedded on the timeline itself, then CP could resume to the last slide, so at worst the viewer repeats the 14 seconds they've already seen.
Keep completion based on if they've seen all slides or not...
?
Copy link to clipboard
Copied
When are you calling the JavaScript? Unless you call it at the exact moment, the if will never register;
if (this.CpObj.cpCF == this.CpObj.cpFC) {
You need to set up an event listener for onVariableChange using the commonJSInterface and check it on every frame.
Copy link to clipboard
Copied
Hi, That makes sense, But I had the script tied to the EXIT_Btn, so I'm going to have to place the new script with the JSInterface eventHandler onVariableChange for CurrentFrame onto the main slide itself, I assume I can still have the Lesson_Status call on the EXIT_Btn I'm not sure how to handle that end of it, unless I add an OnExit function to the eventHandler on the main slide as well, which would take care of the "completed" or "incomplete" based on what frame the slide was on when the "DoFinish()" or "SCORM_CallLMSfinish()" that syntax is what has me a bit confused, I see examples using ObjAPI, SCORM_API, if I want to communicate with SCORM using the Common JS Interface Which call should be used, and what would the dot notation look like, what scope would it have? eg., "this.cpObj. or would it be better if possible to actually query the video itself eg., this.cpObj.video1? I'm not as much concerned with any bookmarking function, although it would be nice, all I really care about is if the user exits before viewing the entire video it's marked "incomplete" and set resume (Although, there's if there's no way to document tracked frames, don't know other than setting exit to "suspend") and if the video hits its last frame, the set some variable as "Completed" and pass that as cmi.core.lesson_status, this also brings up the windowing issue, if you want to close out a SCO being displayed in a SCORM Player popup, obviously top.window.close (); is going to close the whole window, but I've tried simply window.close (): and it didn't work, that's why I thought to try the Windows history using a back function, but I don't know if onbeforeunload or onunload will fire off the "DoFinish ();" that's set in the HTML shell page.
I signed up as a member of your Site (TLCMediaDesign) I thought I has seen that you folks were also dealing with monitoring videos, how did you handle these issues to document SCO status and properly close it out?? That's for your advice, it does make sense, now I just have to figure out where and when the listener should be for EXIT_btn, etc.
Eric Thanks for your feedback/info as well, much appreciated....
Copy link to clipboard
Copied
We don't use Captivates SCORM at all. We create our own Manifest and have SCORM functions in Flash Navigation widgets. For HTML 5 we use the slideEnter and variable change events to make SCORM calls for bookmarking and resume data.
I think you need to make the SCORM calls if your current frame is within 100 frames of the total frames. I would start the variable change listener only if on the last slide. Just add a slide enter listener and test if cpInfoCurrentSlide = cpInfoSlideCount , if not remove the listener and return.
If you are publishing to Captivates SCORM it is making calls at the same time depending on what criteria you are using for completion.
Also, I don't know if you are using swf or html5, but I've found discrepancies with currentFrame and totalFrames being off by a couple in swf. To test for the end of a slide I always check if currentFrame > totalFrames (endFrame) - 5 so I'm sure to catch the end.
Copy link to clipboard
Copied
Out of curiosity, which LMS are you using and what format are you publishing swf, html5 or both?
If you are publishing to SORM you should not have to make all of those calls yourself as Captivate should be making them also, depending on the success criteria.
It is possible to bookmark a location in a video, but would be iffy using Captivates bookmarking.
The best bet is to use you own SCORM file and manifest, that way you control what call is made and when.
You would add the lesson_location as single number representing the current slide. Or you can use and array with values of 0, 1 and 2.
They represent 0=not visited, 1=visited but not complete, 2=complete.
If the cmi.entry = "ab-initio" initial the array to zeros, else get the lesson location and jump to the first location that = 1. You don't have to use an array for the lesson_location, you can just set a slide number also, but there is better tracking with an array. We actually use the suspend_data for the slide status and use the _lesson_location as the index also, it depends on if there are scored quizzes.
When you enter a slide, set the previous slide to complete using (cpInfoCurrentSlide -1) = 2 and the current slide to 1.
Setting the last slide is different so you must evaluate it separately, easy if it is a congratulations page.
You can store the video frame location in the suspend_data. If the user returns to that slide, check if there is any suspend_data to coincide and jump to that frame and resume.
I would create the video in an html page and monitor it using JavaScript. You can still make scorm calls and check cp variable in the "parent".
When entering a slide check if the location array is all 2's to set completion. Or if using a congratulations, you've completed this lesson screen, set completion if current slide equals total slides.
If your LMS is not exiting the right frame correctly when using the LMSFinish(), you may need to parse the URL to get the user back to the SCO selection screen, ie left frame with the menu and the right frame metadata. We had this issue using SCORM 1.2 course in a SCORM 2004 player in the Learn.com LMS.
Copy link to clipboard
Copied
See, that's EXACTLY why I came here, for you can stare at a problem all day long, but if you don't get a fresh perspective on things sometimes, you'll end up down the wrong road. We have decided to do basically what you suggested, using a JavaScript-based video player, although because of it using frames as well, we had a situation where it wasn't fully traversing the entire "stack" in terms of windows/content frames, so you basically had to initiate the SCO twice, my fix was totally by accident, using history.back(0), to reload the same SCO content frame, but hey it works. and this has bookmarking etc. for frames. I will STILL be trying and re-trying at getting this going in Captivate, for it a much more robust authoring platform/tool so I have to get a better handle on talking directly to its core functions to manipulate things the way I want. To answer your first question, it's a much older version of the Meridian KSI LMS which has had numerous modifications to support the US Air Force's ADL delivery requirements. My client who I've worked for the past 12 years is an AF agency with a significant ADL program in place, and although we have a standardized "pipeline", it's flash-based, and I'm trying to push towards using alternative authoring tools which can output either flash or HTML5 as technology and browser security requirements change, so we can re-output content to HTML5 with a minimum of hassle down the road - some others in our development pipeline aren't as convinced and want to keep "business as usual" but, I'd prefer to learn all these idiosyncrasies of an industry standard like Captivate (to be fair, I'm also trying to learn/use Storyline 2 where I can) as you suggested, I'm scouring through the included SCORM API to make the best closing call possible, whether it's simply LMSFinish(), or that has been further encapsulated into another function. I very much appreciate your very thoughtful feedback and obvious expertise on the issue, and I appreciate all others feedback as well. VERY helpful.
Copy link to clipboard
Copied
I have actually developed a course that is on ADLS. My SCORM 1.2 package works perfectly there.
I have also assisted the USAFSAM folks with their manifest and metadata files for Captivate content. Captivate's files were getting warnings/fatal errors on ADLS.
You really are better off using your own files, much smaller and you have the control. One of the biggest issues we've faced is trying to initialize the LMS when there is a swf on the page. We always use a start.htm that initializes. When the API is found it then launches the index.htm (content) which then grabs the API without going through the initialize again.
Contact us through TLC and we'll be glad to help.