Step 7 – The LMSGetValue() Function

In my last post, I talked about how to create the JavaScript XMLHttpRequest object that I need to send information to the server, and read the server’s response. Now, I’m going to integrate that with the API code that I created earlier in the api.html file. I’m going to start with LMSGetValue(). This is what the new LMSGetValue() function looks like.

function LMSGetValue(varname) {

  // create request object
  var req = createRequest();

  // set up request parameters - uses GET method
  req.open('GET','getValue.php?varname='+urlencode(varname)
          +'&code='+Math.random(),false);

  // submit to the server for processing
  req.send(null);

  // process returned data - error condition
  if (req.status != 200) {
    alert('Problem with Request');
    return "";
  }

  // process returned data - OK
  else {
    return req.responseText;
  }

}

Once again, this isn’t a tutorial on AJAX. But I’ll highlight some of the key aspects of the code.

  • Line 4 – I’m creating the JavaScript request object by calling the createRequest() function that I talked about in my last post.
     
  • Lines 7 and 8 – This is the guts of the function. Although the method that I use is called ‘open’, it doesn’t actually submit the query to the server – just sets it up. It has 3 parameters:
     
    1. The first parameter specifies that I’m going to use a GET method to transfer the data to the server. GET and POST methods should be familiar to anyone who programs HTML forms, and I’ll talk about a limitation of the GET method when we get to the LMSetValue() function in my next post.
       
    2. The second parameter is the query string that I’m going to send to the server for processing. I’m going to send it to a PHP script in my ‘imaginary LMS’ called getValue.php. I’m going to pass across the name of the SCORM variable that I’m trying to read and, to make sure that there are no troublesome characters, I’m going to urlencode it. Again, if you’re familiar with basic HTML form coding, that last sentence should make sense to you. Finally, I’ll add a random number which should prevent the server from caching the response. Caching is a real pain in the neck and, rather than fiddle around with the headers that the server sends back, this is a relatively simple solution.
       
    3. The third parameter tells the server whether this is an asynchronous request – in which case it will process it in parallel with any other requests that it receives – or synchronous – in which case it will make the calling program (api.html in this case) wait for a response from this query before it can send the next. I’ll set it to ‘false’ because I need the system to be synchronous as I noted in my previous post.
       
  • Line 11 – Now, after all that work, I send the request to the server for processing. At this time, my API code is prevented from sending more requests since we’re using AJAX in synchronous mode.
     
  • Lines 14 through 17 – This little bit of code handles the situation when the request isn’t successful i.e. when the status code returned by the request isn’t 200.
     
  • Lines 20 through 22 – At long last(!) we read the information returned by the server – the value of the SCORM variable stored in the database – and return it to the API, and then back to the course that originally requested it.
     

So that’s it except for one key element. You’ll see in line 7 that I ‘urlencoded’ the variable name that I send to the server. Unfortunately, JavaScript doesn’t have a native ‘urlencode’ function like other languages. So we need to hunt around for a 3rd party function that we can use. Here’s one that I came across and that seems to work pretty well for my purposes.

function urlencode( str ) {
  //
  // Ref: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_urlencode/
  //
  
    var histogram = {}, unicodeStr='', hexEscStr='';
    var ret = (str+'').toString();
    
    var replacer = function(search, replace, str) {
        var tmp_arr = [];
        tmp_arr = str.split(search);
        return tmp_arr.join(replace);
    };
    
    // The histogram is identical to the one in urldecode.
    histogram["'"]   = '%27';
    histogram['(']   = '%28';
    histogram[')']   = '%29';
    histogram['*']   = '%2A';
    histogram['~']   = '%7E';
    histogram['!']   = '%21';
    histogram['%20'] = '+';
    histogram['\u00DC'] = '%DC';
    histogram['\u00FC'] = '%FC';
    histogram['\u00C4'] = '%D4';
    histogram['\u00E4'] = '%E4';
    histogram['\u00D6'] = '%D6';
    histogram['\u00F6'] = '%F6';
    histogram['\u00DF'] = '%DF';
    histogram['\u20AC'] = '%80';
    histogram['\u0081'] = '%81';
    histogram['\u201A'] = '%82';
    histogram['\u0192'] = '%83';
    histogram['\u201E'] = '%84';
    histogram['\u2026'] = '%85';
    histogram['\u2020'] = '%86';
    histogram['\u2021'] = '%87';
    histogram['\u02C6'] = '%88';
    histogram['\u2030'] = '%89';
    histogram['\u0160'] = '%8A';
    histogram['\u2039'] = '%8B';
    histogram['\u0152'] = '%8C';
    histogram['\u008D'] = '%8D';
    histogram['\u017D'] = '%8E';
    histogram['\u008F'] = '%8F';
    histogram['\u0090'] = '%90';
    histogram['\u2018'] = '%91';
    histogram['\u2019'] = '%92';
    histogram['\u201C'] = '%93';
    histogram['\u201D'] = '%94';
    histogram['\u2022'] = '%95';
    histogram['\u2013'] = '%96';
    histogram['\u2014'] = '%97';
    histogram['\u02DC'] = '%98';
    histogram['\u2122'] = '%99';
    histogram['\u0161'] = '%9A';
    histogram['\u203A'] = '%9B';
    histogram['\u0153'] = '%9C';
    histogram['\u009D'] = '%9D';
    histogram['\u017E'] = '%9E';
    histogram['\u0178'] = '%9F';
    
    // Begin with encodeURIComponent, which most resembles PHP's encoding functions
    ret = encodeURIComponent(ret);
 
    for (unicodeStr in histogram) {
        hexEscStr = histogram[unicodeStr];
        ret = replacer(unicodeStr, hexEscStr, ret); // Custom replace. No regexing
    }
    
    // Uppercase for full PHP compatibility
    return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
        return "%"+m2.toUpperCase();
    });
}

I’ll include that in my api.html file as well. Next stage … repeat the process for LMSSetValue().

This entry was posted in Run Time Environment. Bookmark the permalink.

5 Responses to Step 7 – The LMSGetValue() Function

  1. Khoi Legend says:

    JavaScript does provide escape() and unescape() to url encode strings.

    Try replacing urlencode(varname) with escape(varname).

  2. Khoi Legend says:

    Or better yet, encodeURI(varname).

  3. Steve Addison says:

    Actually, there are small (but significant) differences between JavaScript’s escape() function and ‘urlencode’ as this article, and several others that you can find through Google, point out.

  4. Steve Addison says:

    I’ll have to look into this since the encodeURI documentation seems to suggest that it might be browser dependent. Thanks for the suggestion but, for the time being, I’m going to stuck with the function that I have since a) it’s working, and b) I have other things to worry about! 🙂

  5. Khoi Legend says:

    Cool, just thought I’d give some feedback. I’ve enjoyed your articles thus far and thought I could contribute.

    Btw .. I did try both escape and encodeURI in your code and since its for such a limited range of varname strings, they both tested successfully. Looking forward to the rest of your articles.

Leave a Reply

Your email address will not be published. Required fields are marked *