{"id":33,"date":"2015-10-18T16:15:54","date_gmt":"2015-10-18T20:15:54","guid":{"rendered":"https:\/\/willchinda.com\/blog\/?p=33"},"modified":"2015-10-18T16:20:52","modified_gmt":"2015-10-18T20:20:52","slug":"xapi-captivate-part-1","status":"publish","type":"post","link":"https:\/\/willchinda.com\/blog\/2015\/10\/18\/xapi-captivate-part-1\/","title":{"rendered":"xAPI + Captivate (Part 1)"},"content":{"rendered":"<p>From the moment I learned about it, I&#8217;ve been in love with the idea of what the Experience API (xAPI) could do. While adoption among some L&amp;D departments (mostly at companies with large budgets and\/or technical know-how)\u00a0has been steadily gaining steam, the majority of us seem to be sitting around twiddling our thumbs, waiting for Adobe and Articulate to pull us into this new elearning world. Credit where credit is due, with a <em>limited number<\/em> of\u00a0LMSs, you can actually use Adobe Captivate and Articulate Storyline to send a <em>limited<\/em> set of xAPI statements under a <em>limited<\/em> set of conditions (if you&#8217;re interested in reading more,\u00a0<a href=\"http:\/\/xapiquarterly.com\/2015\/09\/fall-2015-table-of-contents\/\">Sean Putman has thoroughly documented how in the first xAPI Quarterly<\/a>).<\/p>\n<p>When it comes to rapid elearning development tools, stuff like this makes me want to pull my hair out (what little that hasn&#8217;t already gone). Why can&#8217;t I have\u00a0Captivate send whatever statement I want to whatever LRS that I want?<\/p>\n<p>So that&#8217;s the genesis behind this. I&#8217;ve found lots of information about xAPI at a high-level, and lots of information about xAPI at a very technical level, but very little information for instructional designers trying to bridge the gap between rapid development tools and writing code. Over the course of several blog posts (and hopefully on an ongoing basis as I continue to learn things) I&#8217;ll be documenting how I&#8217;m getting Captivate to bend to my will and play nice with xAPI, hopefully in a way that makes sense to instructional designers with little to no programming experience. For this first one, I&#8217;ll\u00a0be demonstrating how to:<\/p>\n<ul>\n<li>Retrieve user information to create an xAPI statement<\/li>\n<li>Send that statement to an LRS when the user clicks a button<\/li>\n<\/ul>\n<p>In order to send the statement, we need (at minimum) three pieces of information: an actor, a verb, and an object. Let&#8217;s start by\u00a0creating a Captivate project\u00a0and using our first slide to obtain information from the actor. In this case, we&#8217;ll be capturing the user&#8217;s name and email address using two text input boxes.<\/p>\n<p><a href=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/userinput.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-44\" src=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/userinput.jpg\" alt=\"userinput\" width=\"436\" height=\"170\" srcset=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/userinput.jpg 436w, https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/userinput-300x117.jpg 300w\" sizes=\"auto, (max-width: 436px) 100vw, 436px\" \/><\/a><\/p>\n<p>By default, Captivate assigns the generic variable Text_Entry_Box_1 to our input box, but it&#8217;ll make it a little clearer to assign it a more descriptive variable name. To do this, select the text entry box. In the <strong>Properties <\/strong>window, scroll down to <strong>Variable<\/strong> and click the <strong>[X]<\/strong> and create a new variable called <em>user_name<\/em>. For the email address box, set the variable to <em>user_email<\/em>.<\/p>\n<p><a href=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/textentryvariable.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-45\" src=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/textentryvariable.jpg\" alt=\"textentryvariable\" width=\"300\" height=\"57\" \/><\/a><\/p>\n<p>On success, the action is set to <strong>Go to the next slide<\/strong>.<\/p>\n<p>Create a second slide and add a button. This will be where the magic happens, but let&#8217;s get all our ducks in a row before we move any further.<\/p>\n<p><a href=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/button.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-46\" src=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/button.jpg\" alt=\"button\" width=\"115\" height=\"72\" \/><\/a><\/p>\n<p>Let&#8217;s publish our project and take a closer look at the files that Captivate outputs:<\/p>\n<p><a href=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatefiles.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-41\" src=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatefiles.jpg\" alt=\"captivatefiles\" width=\"523\" height=\"121\" srcset=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatefiles.jpg 523w, https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatefiles-300x69.jpg 300w\" sizes=\"auto, (max-width: 523px) 100vw, 523px\" \/><\/a><\/p>\n<p>Each type of file has a specific role to play, and (in some cases) uses a different language to accomplish it. For those without web development experience, here&#8217;s what each file type means:<\/p>\n<ul>\n<li>HTML (Hypertext Markup Language) &#8211; is the content itself. It&#8217;s useful to think of the HTML file as the &#8220;hub,&#8221; since it pulls in and links all of the other files.<\/li>\n<li>CSS (Cascading Style Sheet) &#8211; styles the content in the HTML file. This file sets your colors, your fonts, your alignment, etc.<\/li>\n<li>SWF (Flash) &#8211; is the meat of what Captivate outputs. All your slides, graphics, animations, and interface elements make up this file.<\/li>\n<li>JS (Javascript) &#8211; are the\u00a0dynamic elements. We&#8217;ll be doing most of our work today in Javascript.<\/li>\n<\/ul>\n<p>To simplify our task, we can add a Javascript library\u00a0to this folder to handle a lot of the behind the scenes communication between our project and the LRS. For this project, I&#8217;ll be using a library called xAPI Wrapper, which you can download from the <a href=\"https:\/\/github.com\/adlnet\/xAPIWrapper\">ADL&#8217;s github<\/a>. Download and copy the <em>xapiwrapper.min.js<\/em> file into your folder.<\/p>\n<p>It&#8217;s not enough just to add the library file, however. We&#8217;ve got to create another Javascript file to tell it what to do! If you&#8217;re looking to go as simple as possible, you can do this in Notepad or TextEdit, but I prefer using a nice code editor such as <a href=\"https:\/\/notepad-plus-plus.org\/\">Notepad++<\/a> (on Windows) or <a href=\"http:\/\/brackets.io\/\">Brackets <\/a>(on Mac). Both are free.<\/p>\n<p>So let&#8217;s use our code editor to create a new file. Let&#8217;s call it <em>setup.js<\/em> and save it in the same folder. Start off by setting up our communication with the LRS.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">function setupConfig() {\r\n var endpoint = 'https:\/\/lrs.adlnet.gov\/xapi\/';\r\n var user = 'xapi-tools';\r\n var password = 'xapi-tools';\r\n\r\n var conf = {\r\n  \"endpoint\" : endpoint,\r\n  \"auth\" : \"Basic \" + toBase64(user + \":\" + password),\r\n };\r\n \r\n ADL.XAPIWrapper.changeConfig(conf);\r\n}<\/pre>\n<p>In this example, I&#8217;m using the <a href=\"https:\/\/lrs.adlnet.gov\/xAPI\/\">ADL&#8217;s Public LRS<\/a>. Whichever\u00a0LRS you sign up for should provide you with an endpoint, username, and password, so simply change these\u00a0fields to suit your LRS. Most LRS providers (<a href=\"http:\/\/scorm.com\/scorm-solved\/scorm-cloud-features\/\">SCORM Cloud<\/a>, <a href=\"http:\/\/saltbox.com\/\">Saltbox<\/a>, etc.) have free options available for those just looking to tinker, and I heartily recommend signing up for an account if you&#8217;re looking to dive deeper.<\/p>\n<p>Since this is a function, we&#8217;ll need to call it.<\/p>\n<p>[js]<br \/>\nsetupConfig();<br \/>\n[\/js]<\/p>\n<p>Our LRS setup complete, let&#8217;s actually go about actually crafting our statement. Let&#8217;s create a new statement and name it <em>stmt<\/em>.<\/p>\n<p>[js]<br \/>\nvar stmt = new ADL.XAPIStatement();<br \/>\n[\/js]<\/p>\n<p>Since our actor information is going to be dynamically set from within Captivate based on the user&#8217;s input, we&#8217;ll only handle the verb and object here. Let&#8217;s create a statement that reads:<\/p>\n<p>[actor] <em>experienced<\/em> <strong>Captivate button tutorial<\/strong><\/p>\n<p>Where <em>experienced<\/em> is the verb and <strong>Captivate button tutorial<\/strong> is the object. In addition to their plain English names, we&#8217;ll also need IDs for each.<\/p>\n<p>You can select from a preset library of verbs in the <a href=\"https:\/\/registry.tincanapi.com\/#home\/verbs\">Tin Can Registry<\/a> or on <a href=\"http:\/\/xapi.vocab.pub\/datasets\/adl\/verbs\/index.html\">ADL&#8217;s Controlled Vocabulary<\/a>. I find in conversations with those who haven&#8217;t worked with xAPI, people are really interested in the idea of creating their own verbs. In some cases, it makes sense, but it&#8217;s the sort of thing that adds an unnecessary complication unless you <em>really<\/em> need to.<\/p>\n<p>The verb that I&#8217;m using here is already defined, so there&#8217;s no point in reinventing the wheel. Let&#8217;s grab the information we need, the verb (<em>experienced<\/em>) and its ID (<em>http:\/\/adlnet.gov\/expapi\/verbs\/experienced<\/em>) and add it to our statement:<\/p>\n<p>[js]<br \/>\nstmt.verb = new ADL.XAPIStatement.Verb(&#8216;http:\/\/adlnet.gov\/expapi\/verbs\/experienced&#8217;, &#8216;experienced&#8217;);<br \/>\n[\/js]<\/p>\n<p>Now we need to determine what our object is. <a href=\"http:\/\/xapi.vocab.pub\/datasets\/adl\/activityTypes\/index.html\">Object types are standardized<\/a> &#8211; in this case, I want it to be an Activity &#8211; but the rest of the object is entirely up to us to define, since we (as instructional designers) are usually the ones creating it. In this case, I&#8217;m giving it a name that&#8217;s logical and makes sense (<strong>Captivate button tutorial<\/strong>) and assigning it an ID that also happens to make sense &#8211; the URL for this blog post (<strong>https:\/\/willchinda.com\/blog\/2015\/10\/14\/xapi-captivate-part-1\/<\/strong>). There&#8217;s some debate about whether IDs can just be random codes (courses\/tutorials\/buttontutorial101) or actual URLs that open webpages. I tend to prefer the latter, since a URL can provide a great deal more context and information.<\/p>\n<p>At any rate, let&#8217;s add this information to our statement:<\/p>\n<p>[js]<br \/>\nstmt.object = new ADL.XAPIStatement.Activity(&#8216;https:\/\/willchinda.com\/blog\/2015\/10\/14\/xapi-captivate-part-1\/&#8217;, &#8216;Captivate button tutorial&#8217;);<br \/>\n[\/js]<\/p>\n<p>That&#8217;s it! Pretty simple, eh? Let&#8217;s get back to our Captivate file and add our actor to this statement.<\/p>\n<p>We&#8217;ve already captured our actor information from user inputs &#8211; all we need to do is translate these Captivate variables (<em>user_email<\/em> and <em>user_name<\/em>) into Javascript ones. Thanks to a new Javascript framework available since Captivate 8, this is fairly simple. Then we can add\u00a0them to our statement and send it. Thanks to our inclusion of the xAPI Wrapper library in the\u00a0published folder, we can easily trigger all of these actions to occur when the user clicks the button.<\/p>\n<p>Select the button on the second slide and open the <strong>Properties<\/strong> window. Under <strong>Actions,<\/strong> set the <strong>On Success<\/strong> action to <strong>Execute Javascript<\/strong>. Click the <strong>Script_Window<\/strong> button, and we can add Javascript code that will execute when the user clicks the button.<\/p>\n<p><a href=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/button_javascript.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51\" src=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/button_javascript.jpg\" alt=\"button_javascript\" width=\"290\" height=\"132\" \/><\/a><\/p>\n<p>[js]<br \/>\nvar userName = window.cpAPIInterface.getVariableValue(&#8220;user_name&#8221;);<br \/>\nvar userEmail = &#8216;mailto:&#8217; + window.cpAPIInterface.getVariableValue(&#8220;user_email&#8221;);<\/p>\n<p>stmt.actor = new ADL.XAPIStatement.Agent(userEmail, userName);<\/p>\n<p>var resp_obj = ADL.XAPIWrapper.sendStatement(stmt);<br \/>\n[\/js]<\/p>\n<p>Here, all we&#8217;re doing is creating two new variables (<em>userName<\/em> and <em>userEmail<\/em>) to accept the variables entered in by the user in the first slide. Note that we&#8217;re also adding &#8216;mailto:&#8217; to the user&#8217;s email (a necessary format for the actor&#8217;s ID). Then, much like we set the verb and object, we&#8217;re adding these elements to our statement.\u00a0Finally, we send\u00a0our statement.<\/p>\n<p>Let&#8217;s republish our project and have another look at our published folder.<\/p>\n<p><a href=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatefiles2.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-52\" src=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatefiles2.jpg\" alt=\"captivatefiles2\" width=\"527\" height=\"165\" srcset=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatefiles2.jpg 527w, https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatefiles2-300x94.jpg 300w\" sizes=\"auto, (max-width: 527px) 100vw, 527px\" \/><\/a><\/p>\n<p>In addition to the four files that Captivate publishes, we should also have our <em>xapiwrapper.min.js<\/em> library as well as the <em>setup.js<\/em> file that we created. Now the question is, how do we bring those two files into our project? We can do that with two lines of code added to our HTML file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;script src=\"xapiwrapper.min.js\" type=\"text\/javascript\"&gt;&lt;\/script&gt;\r\n&lt;script src=\"setup.js\" type=\"text\/javascript\"&gt;&lt;\/script&gt;<\/pre>\n<p>Open up the test.html file and add it anywhere in between the &lt;head&gt; tags. For consistency&#8217;s sake, I just like pasting them\u00a0right underneath where the standard.js file is being added.<\/p>\n<p><a href=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatehtml.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-54\" src=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatehtml.jpg\" alt=\"captivatehtml\" width=\"613\" height=\"166\" srcset=\"https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatehtml.jpg 613w, https:\/\/willchinda.com\/blog\/wp-content\/uploads\/2015\/10\/captivatehtml-300x81.jpg 300w\" sizes=\"auto, (max-width: 613px) 100vw, 613px\" \/><\/a><\/p>\n<p>Note that if you decide to publish again, you&#8217;ll have to go back in and add these two lines to the html file.<\/p>\n<p>That&#8217;s it!\u00a0Want to try it out? I&#8217;ve got <a href=\"https:\/\/willchinda.com\/xapi\/xapi-captivate1\/test.htm\">a live version of the project here<\/a> sending statements to the <a href=\"http:\/\/adlnet.github.io\/xapi-statement-viewer\/\">ADL Public LRS<\/a>. Click the button and see your statement show up in the LRS! Since it is sending to a Public LRS, don&#8217;t type anything into those input fields you don&#8217;t want public.<\/p>\n<p><a href=\"https:\/\/github.com\/willchinda\/captivatexapipart1\">I&#8217;ve also posted the source files to github<\/a> if you want to download and start playing around with them. Get busy making statements!<\/p>\n","protected":false},"excerpt":{"rendered":"<p class=\"excerpt\">From the moment I learned about it, I&#8217;ve been in love with the idea of what the Experience API (xAPI) could do. While adoption among some L&amp;D departments (mostly at companies with large budgets and\/or technical know-how)\u00a0has been steadily gaining steam, the majority of us seem to be sitting around twiddling our thumbs, waiting for Adobe and Articulate to pull &#8230; <a class=\"read-more\" href=\"https:\/\/willchinda.com\/blog\/2015\/10\/18\/xapi-captivate-part-1\/\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21,11],"tags":[24,23,26,27,25,22],"class_list":["post-33","post","type-post","status-publish","format-standard","hentry","category-learning","category-technology","tag-adobe","tag-captivate","tag-instructional-design","tag-javascript","tag-rapid-development","tag-xapi"],"_links":{"self":[{"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/posts\/33","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/comments?post=33"}],"version-history":[{"count":10,"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/posts\/33\/revisions"}],"predecessor-version":[{"id":59,"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/posts\/33\/revisions\/59"}],"wp:attachment":[{"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/media?parent=33"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/categories?post=33"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/willchinda.com\/blog\/wp-json\/wp\/v2\/tags?post=33"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}