AppleScript for generating SCORM manifest nodes

SCORM requires all of the course assets to be listed as a <file> item in the <resource> node. This is not evenly enforced — some LMSs don’t care of you do it or not — but is still a good practice.

If you’re anything like me, you find it to be a major pain and try to avoid it.

Today I decided to whip up an AppleScript that automates the generation of the <file> nodes to make my life a little easier. If you’re on a Mac, you may find it useful, too. I’ve posted it on GitHub as gist:

https://gist.github.com/pipwerks/9179518

Note that it doesn’t include the name of the root folder. Let’s say you have a root folder named content. If needed, you can simply specify the root using the “xml:base” attribute of the resource node, like so:


<resource identifier="reosurceID" adlcp:scormType="sco" href="index.html" type="webcontent" xml:base="content/">
   <file href="index.html" />
   <file href="Lesson01/index.html" />
</resource>

Clean out the root of your SCORM 2004 package

Anyone who works with SCORM 2004 has seen something like this:

Image of file directory with all schema files at root of directory

With just a little effort, you can make it look like this, and still be perfectly valid:

Image of file directory with all schema files placed in subfolder

SCORM manifests are required to specify a slew of schema files via the schemaLocation attribute. Here’s what you’d typically see:


<manifest identifier="pipwerks-schema-example" version="1.0"
          xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" 
          xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3" 
          xmlns:adlseq="http://www.adlnet.org/xsd/adlseq_v1p3" 
          xmlns:adlnav="http://www.adlnet.org/xsd/adlnav_v1p3" 
          xmlns:imsss="http://www.imsglobal.org/xsd/imsss" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
          xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd 
                              http://www.adlnet.org/xsd/adlcp_v1p3 adlcp_v1p3.xsd 
                              http://www.adlnet.org/xsd/adlseq_v1p3 adlseq_v1p3.xsd 
                              http://www.adlnet.org/xsd/adlnav_v1p3 adlnav_v1p3.xsd 
                              http://www.imsglobal.org/xsd/imsss imsss_v1p0.xsd">

Notice the structure of the data in the schemaLocation attribute: external URL followed by a space then the local (relative) URL. For example:


http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd

In this example, imscp_v1p1.xsd is at the root of the package, in the same folder as the imsmanifext.xml file. The trick is to create a subfolder in the root of the package, then update schemaLocation to point to the subfolder. I created a subfolder named SCORM-schemas, which you can see in the following code exerpt:


<manifest identifier="pipwerks-schema-example" version="1.0"
          xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" 
          xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3" 
          xmlns:adlseq="http://www.adlnet.org/xsd/adlseq_v1p3" 
          xmlns:adlnav="http://www.adlnet.org/xsd/adlnav_v1p3" 
          xmlns:imsss="http://www.imsglobal.org/xsd/imsss" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
          xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 SCORM-schemas/imscp_v1p1.xsd 
                              http://www.adlnet.org/xsd/adlcp_v1p3 SCORM-schemas/adlcp_v1p3.xsd 
                              http://www.adlnet.org/xsd/adlseq_v1p3 SCORM-schemas/adlseq_v1p3.xsd 
                              http://www.adlnet.org/xsd/adlnav_v1p3 SCORM-schemas/adlnav_v1p3.xsd 
                              http://www.imsglobal.org/xsd/imsss SCORM-schemas/imsss_v1p0.xsd">

Test, test, test! I’ve tested this in SCORM Cloud as well as a couple of real-world LMSs and haven’t encountered any issues. Your mileage may vary depending on your LMS’s SCORM implementation, but this is perfectly valid XML and shouldn’t break in any LMSs — unless the LMS is poorly coded, but that’s a rarity, right? (LOL)

On Converting Flash to HTML

I received a question from Bob (no, really), who wrote:

I have a question about the newest version of Flash and its HTML publishing option using CreateJS. What do you think of that approach going forward?

I started to write an email response but figured I should probably post it here.

I haven’t been paying much attention to Flash, so I don’t know what the ‘HTML export’ is capable of these days. In general, I’m very wary of converting Flash-based projects to HTML. When Adobe Captivate first released a “publish to HTML5” feature, all it did was convert the SWF animation to a video file, losing all interactivity along the way.

The limitations of the browsers and the HTML5 spec mean you can’t expect a fully 1:1 conversion from Flash to HTML, regardless of libraries like CreateJS. Some of the features found in Flash are still not quite supported in browsers, or might not work quite the way you’d expect. For example, CSS transitions, CSS gradients, and SVG/Canvas support vary widely from browser to browser (though it’s getting better, and there are workarounds aka “polyfills”). Streaming video, which is a breeze in Flash, is not part of the HTML5 Video spec (yet) and is unsupported in browsers. Video and audio codec support is inconsistent. In some cases, devices add new limitations — last time I checked, iOS devices wouldn’t autoplay audio or video in Safari. ‘Play’ couldn’t be scripted, it required the user to press a button.

Publishing to HTML (with the aid of JavaScript libraries like CreateJS) is definitely the way of the future, but I would flip the workflow: use a tool that’s “HTML first”. For my workflow, I always start in HTML then only fall back to Flash if I absolutely have to. I hand-code, but if you want to stick to a WYSIWYG editor, maybe try some of the Adobe Edge products, or go with a third-party product such as Tumult Hype.

If you continue to use Flash as an HTML development tool, temper expectations and test widely, as some things might not work the way you expect when converted to HTML.

And regardless of whether you publish to Flash or HTML, always test the accessibility of your project. Just because it’s HTML doesn’t mean it’s accessible; HTML by nature is more accessible than Flash, but libraries like CreateJS add a lot of complexity to the page, which can easily impact accessibility.

Flash support is increasingly a minefield

Back in 2011, I mentioned that Microsoft was about to halt development of the Silverlight plugin, that Flash mobile was being discontinued, and that Adobe recommended HTML5 for enterprise RIA development instead of Flex, which was being open-sourced. My post was a little long-winded, but the short version was: whoa, the times-are-a-changin’, it’s getting dangerous to rely on browser plugins.

Over the last year, the situation has evolved in an interesting way — browser support for plugins (especially Flash Player) has been considerably restricted by browser vendors due to repeated security vulnerabilities in Flash Player and Java.

Automatically disabling Flash Player

In May 2012, Apple’s Safari browser began automatically disabling outdated versions of Flash Player: “Out-of-date versions of Adobe Flash Player do not include the latest security updates and will be disabled to help keep your Mac secure.” If a webpage contains a SWF but the installed edition of Flash Player is deemed out of date, Safari will display a “blocked plugin” message and inform the user they need to download the latest edition of Flash Player at adobe.com. This change came with Adobe’s blessing.

In January 2013, Mozilla introduced a global “click to play” mechanism that disables ALL plugins in Firefox by default, except the latest edition of Flash Player:  “Our plan is to enable Click to Play for all versions of all plugins except the current version of Flash.”

To Adobe’s credit, Flash Player updates are being released at a fast clip to address known security vulnerabilities. Unfortunately, this has a nasty side effect: you’re very likely to have an outdated edition of Flash Player when you try to view Flash content on a website. (By my unofficial count, there have been at least 13 updates over the past calendar year, averaging about once a month.)

At a recent job, I managed a small network of Macs in classrooms. The Macs were set up to use Adobe’s ‘automatic updates’ feature for Flash Player, but they never seemed to update fast enough — we received numerous complaints from classroom users who couldn’t view Flash content because Safari blocked it.

Internet Explorer’s on-again, off-again relationship with Flash Player

I previously mentioned that Microsoft’s Windows 8 ‘Metro’ mode disabled all plugins, including Flash Player; Microsoft said Internet Explorer in Windows 8 Metro mode “provides an add-on–free experience, so browser plugins don’t load and dependent content isn’t displayed“.

In May 2012 Microsoft changed their minds and enabled Flash in Metro mode. BUT… Microsoft will ship Flash Player as a component of IE 10 (much like Google Chrome does), and will restrict which sites are allowed to run Flash! “While any site can play Flash content in IE10 on the Windows desktop, only sites that are on the Compatibility View (CV) list can play Flash content within Metro style IE.”

In other words, if you don’t have Microsoft’s blessing, your Flash site will not work when viewed in Metro mode.

Update: @chris_sage pointed me to a post by Microsoft written just three days ago where they apparently changed their minds again — almost a year after saying they’d require a whitelist, they now say they support Flash Player by default in Metro mode without requiring sites to be whitelisted.

What it boils down to…

If you develop Flash-based content, it will be more and more of a challenge to provide a smooth, problem-free user experience. For e-learning developers, one of the original lures of Flash was the ubiquity of Flash Player; Flash made it easy to provide the same e-learning experience across browsers and platforms. Due to fragmentation in Flash support, this no longer appears possible.

  • Adobe says: No Flash Player for mobile devices.
  • Microsoft says: No Flash Player on Surface tablets (or other Windows 8/RT tablets) unless the user switches to desktop mode OR gets on our whitelist for Metro mode. We love us some Flash! But we’ll manage the security updates ourselves, thank-you.
  • Mozilla says: Only the latest edition of Flash Player for Firefox.
  • Apple says: No Flash Player on Apple iOS devices, and only the latest edition of Flash Player for desktop Safari.
  • Opera says: Flash Player on desktop editions of Opera? No problem. Flash Player in Opera Mobile? Don’t get mad at us, Adobe stopped providing Flash Player for mobile devices!
  • Google says: We control Flash Player for Chrome (desktop) ourselves. No worries. Flash Player in Chrome on mobile devices? Don’t get mad at us, Adobe stopped providing Flash Player for mobile devices!

The browser vendors are enforcing their will. You don’t have to be a Flash-hater to see that building Flash-dependent sites is a minefield.

For those of you in e-learning who depend almost completely on Flash-based courseware, it’s a good idea to start looking for alternatives.

 

 

Important Adobe Captivate SCORM template update

Over the last few weeks, I received a few reports that scores were not being saved in the LMS when using my template. Turned out to be a simple oversight on my part, which I have just fixed. Please download the latest version of scorm_support.js (v1.20120328) from GitHub.

Cause and effect

If you’re curious what happened, here’s a quick rundown:

When a SCORM course launches for the first time, the value of cmi.completion_status is "ab-initio". This means the course is a fresh launch with no prior completion attempts, and therefore no historical data in the LMS.

When Captivate launches, it requests a slew of information from the LMS via SCORM_API.GetValue. This includes the usual suspects, such as completion status, suspend data, location, score.raw, score.max, score.min, and score.scaled. However, if the course has never been launched before, suspend_data, location, and the score elements will all be empty (null). If the LMS follows the SCORM spec, it will throw the “element not initialized” error.

In my earlier work on the template, I decided to prevent these “element not initialized” errors by adding some logic to the template, preventing suspend_data, location, and the score elements from being checked when the course status is ab-initio. This was achieved via a regular expression:


if(entryStatus === "ab-initio" && /location|suspend_data|score/g.test(parameter)){
   //prevent action
}

Unfortunately, I overlooked one important detail: when the Captivate course loads, it queries the LMS to see which SCORM fields are supported. This is done by requesting the “._children” CMI elements. For example, cmi.score._children will return the string “scaled,min,max,raw” indicating that cmi.score.scaled, cmi.score.min, cmi.score.max, and cmi.score.raw are supported by the LMS.

See any problems yet?

My regular expression was too broad, and prevented cmi.score._children from being queried, making Captivate believe that cmi.score was not supported. Since Captivate thought cmi.score was not supported, it did the right thing and stopped sending cmi.score data to the LMS.

The solution was to make the regular expression a bit more explicit:


if(entryStatus === "ab-initio" && /location|suspend_data|score\.(raw|min|max|scaled)/g.test(parameter)){
   //prevent action
}

Instead of blocking any GetValue calls requesting “score” data when the course is ab-initio, we now only block GetValue calls that request specific CMI elements: score.raw, score.min, score.max, and score.scaled. Problem solved.

Introducing SWFRightClick

Adobe Captivate currently ships with a 3rd-party JavaScript utility named RightClick.js, which enables the Captivate SWF to detect when a user right-clicks the SWF. While upgrading the Captivate publishing templates, I realized RightClick.js wasn’t built to work with SWFObject 2.x and suffered from a few shortcomings. I modified the Captivate template’s SWFObject code to get around the issue, but marked it down as something to revisit when I have the time.

Now, I’m happy to report I’ve created a replacement for the RightClick.js utility, creatively named SWFRightClick. It uses the same approach to handling right-clicks, but does it with a completely new codebase and a few extra goodies. SWFRightClick is compatible with every edition of SWFObject, and is free to use (MIT license).

Check it out on GitHub. I plan to fold it in to my Captivate publishing templates very soon.

New SCORM 1.2 Template for Adobe Captivate

By popular demand, the SCORM 1.2 edition of my revised SCORM publishing templates for Adobe Captivate 5.x is now available on GitHub.

Instructions can be found here.

While testing the SCORM 1.2 revisions, I noticed Captivate sometimes sends invalid data to the LMS, specifically for cmi.interactions.n.correct_responses.n.pattern, cmi.interactions.n.student_response, and cmi.interactions.n.weighting. I may fix these errors in a future update, but they’re relatively harmless, so I’ll leave them be for now.

Further Tweaks to the Adobe Captivate SCORM Publishing Template

Now that my version of the Adobe Captivate publishing template for SCORM 2004 is on GitHub, it has become a living document, bound to get updates (major and minor) from time to time. For those of you unfamiliar with GitHub, it’s a nifty site for storing code; it provides issues list for tracking bugs, it enables people to leave comments or make code suggestions, and it even lets you copy an entire open-source project with a single click!

Since the code for my templates will remain on GitHub, I highly suggest checking in from time to time to see if the code has been updated. I won’t be posting a blog entry on pipwerks.com for every little edit I make to the code.

Speaking of edits, I made two or three tonight, spurred by an insightful comment from Jimmi Thøgersen.  He noticed a bug or two, and explained some of Saba’s bugginess — thanks Jimmi! If you know of any oddities or bugs, please let me know by posting an issue on GitHub.

Cleaning up Adobe Captivate’s SCORM Publishing Template, Part 7: Giving the Revisions a Home

I decided to post my revised Adobe Captivate publishing template to GitHub, where it can be easily copied, forked, and updated. Currently, the only files are for the Captivate 5.0 and 5.5 templates for SCORM 2004. I hope to add SCORM 1.2 soon, as well as replacing the default ‘standard.htm’ template, which doesn’t use any LMS-related code.

Update: The SCORM 1.2 template is now available.

If you take a look at Default.htm on GitHub, you’ll notice I’ve made a few changes since I wrote my series about editing the templates. I moved a few bits of markup/code around, added some configuration options (such as the ability to turn off centering, turn on logging, and require SCORM when loading), and added a ton of comments to explain some of the new options. Hopefully it’s all self-explanatory.

I also made a small edit to manifest2004.xml, and a few edits to scorm_support.js.

To use these template files, do the following:

  1. Make a backup of your entire publishing folder and put it somewhere safe!
  2. Go to Captivate’s Templates\Publish\SCORM\2004\ folder and replace Default.htm with the new file.
  3. Go to Templates\Publish\SCORM\2004\SCORM_support\ and replace scorm_support.js with the new file.
  4. While you’re in your SCORM_support folder, delete scorm_support.htm and scorm_support.swf, they won’t be used anymore.
  5. Go to Templates\Publish\ and replace manifest2004.xml with the new file.
  6. While you’re still in the Templates\Publish\ folder, replace standard.js with the new file.
  7. Restart Captivate and give it a try!

Find a bug? Think of a good edit for the template? Post a comment here, or better yet, file an issue on GitHub!