From fe0e5633e680d06bbe670e495523cf15c387330c Mon Sep 17 00:00:00 2001 From: Vincent Vanwaelscappel Date: Wed, 23 Mar 2016 19:01:17 +0000 Subject: [PATCH] #scorm : improve status management @2 --- js/libs/scorm/apiwrapper.js | 761 +++++++++++++++++------------------- js/libs/scorm/scorm.js | 36 +- js/main.js | 1 + 3 files changed, 393 insertions(+), 405 deletions(-) diff --git a/js/libs/scorm/apiwrapper.js b/js/libs/scorm/apiwrapper.js index 6752f01b..113feee0 100644 --- a/js/libs/scorm/apiwrapper.js +++ b/js/libs/scorm/apiwrapper.js @@ -1,24 +1,24 @@ /******************************************************************************* -** -** This software is provided "AS IS," without a warranty of any kind. ALL -** EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY -** IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- -** INFRINGEMENT, ARE HEREBY EXCLUDED. PAUL BECKWITH AND HIS LICENSORS SHALL NOT BE LIABLE -** FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR -** DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL PAUL BECKWITH OR ITS -** LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, -** INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER -** CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF -** OR INABILITY TO USE SOFTWARE, EVEN IF CTC HAS BEEN ADVISED OF THE POSSIBILITY -** OF SUCH DAMAGES. -** javascript: -** var result = doLMSInitialize(); -** if (result != true) -** { + ** + ** This software is provided "AS IS," without a warranty of any kind. ALL + ** EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY + ** IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- + ** INFRINGEMENT, ARE HEREBY EXCLUDED. PAUL BECKWITH AND HIS LICENSORS SHALL NOT BE LIABLE + ** FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + ** DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL PAUL BECKWITH OR ITS + ** LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, + ** INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER + ** CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF + ** OR INABILITY TO USE SOFTWARE, EVEN IF CTC HAS BEEN ADVISED OF THE POSSIBILITY + ** OF SUCH DAMAGES. + ** javascript: + ** var result = doLMSInitialize(); + ** if (result != true) + ** { ** // handle error ** } -** -*******************************************************************************/ + ** + *******************************************************************************/ var _Debug = false; // set this to false to turn debugging off @@ -46,460 +46,415 @@ var findAPITries = 0; /******************************************************************************* -** -** Function: doLMSInitialize() -** Inputs: None -** Return: CMIBoolean true if the initialization was successful, or -** CMIBoolean false if the initialization failed. -** -** Description: -** Initialize communication with LMS by calling the LMSInitialize -** function which will be implemented by the LMS. -** -*******************************************************************************/ -function doLMSInitialize() -{ - startTimer(); - - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nLMSInitialize was not successful."); - return "false"; - } - - var result = api.LMSInitialize(""); - - if (result.toString() != "true") - { - var err = ErrorHandler(); - } - - return result.toString(); + ** + ** Function: doLMSInitialize() + ** Inputs: None + ** Return: CMIBoolean true if the initialization was successful, or + ** CMIBoolean false if the initialization failed. + ** + ** Description: + ** Initialize communication with LMS by calling the LMSInitialize + ** function which will be implemented by the LMS. + ** + *******************************************************************************/ +function doLMSInitialize() { + startTimer(); + + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nLMSInitialize was not successful."); + return "false"; + } + + var result = api.LMSInitialize(""); + + if (result.toString() != "true") { + var err = ErrorHandler(); + } + + return result.toString(); } /******************************************************************************* -** -** Function doLMSFinish() -** Inputs: None -** Return: CMIBoolean true if successful -** CMIBoolean false if failed. -** -** Description: -** Close communication with LMS by calling the LMSFinish -** function which will be implemented by the LMS -** -*******************************************************************************/ -function doLMSFinish() -{ - - setSessionTime(); - - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nLMSFinish was not successful."); - return "false"; - } - else - { - // call the LMSFinish function that should be implemented by the API - - var result = api.LMSFinish(""); - if (result.toString() != "true") - { - var err = ErrorHandler(); - } - - } - - return result.toString(); + ** + ** Function doLMSFinish() + ** Inputs: None + ** Return: CMIBoolean true if successful + ** CMIBoolean false if failed. + ** + ** Description: + ** Close communication with LMS by calling the LMSFinish + ** function which will be implemented by the LMS + ** + *******************************************************************************/ +function doLMSFinish() { + + setSessionTime(); + + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nLMSFinish was not successful."); + return "false"; + } + else { + // call the LMSFinish function that should be implemented by the API + + var result = api.LMSFinish(""); + if (result.toString() != "true") { + var err = ErrorHandler(); + } + + } + + return result.toString(); } /******************************************************************************* -** -** Function doLMSGetValue(name) -** Inputs: name - string representing the cmi data model defined category or -** element (e.g. cmi.core.student_id) -** Return: The value presently assigned by the LMS to the cmi data model -** element defined by the element or category identified by the name -** input value. -** -** Description: -** Wraps the call to the LMS LMSGetValue method -** -*******************************************************************************/ -function doLMSGetValue(name) -{ - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nLMSGetValue was not successful."); - return ""; - } - else - { - var value = api.LMSGetValue(name); - var errCode = api.LMSGetLastError().toString(); - if (errCode != _NoError) - { - // an error was encountered so display the error description - var errDescription = api.LMSGetErrorString(errCode); - alert("LMSGetValue("+name+") failed. \n"+ errDescription); - return ""; - } - else - { - - return value.toString(); - } - } + ** + ** Function doLMSGetValue(name) + ** Inputs: name - string representing the cmi data model defined category or + ** element (e.g. cmi.core.student_id) + ** Return: The value presently assigned by the LMS to the cmi data model + ** element defined by the element or category identified by the name + ** input value. + ** + ** Description: + ** Wraps the call to the LMS LMSGetValue method + ** + *******************************************************************************/ +function doLMSGetValue(name) { + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nLMSGetValue was not successful."); + return ""; + } + else { + var value = api.LMSGetValue(name); + var errCode = api.LMSGetLastError().toString(); + if (errCode != _NoError) { + // an error was encountered so display the error description + var errDescription = api.LMSGetErrorString(errCode); + fb("LMSGetValue(" + name + ") failed. \n" + errDescription); + return ""; + } + else { + + return value.toString(); + } + } } /******************************************************************************* -** -** Function doLMSSetValue(name, value) -** Inputs: name -string representing the data model defined category or element -** value -the value that the named element or category will be assigned -** Return: CMIBoolean true if successful -** CMIBoolean false if failed. -** -** Description: -** Wraps the call to the LMS LMSSetValue function -** -*******************************************************************************/ -function doLMSSetValue(name, value) -{ - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nLMSSetValue was not successful."); - return; - } - else - { - var result = api.LMSSetValue(name, value); - if (result.toString() != "true") - { - var err = ErrorHandler(); - } - } - - return; + ** + ** Function doLMSSetValue(name, value) + ** Inputs: name -string representing the data model defined category or element + ** value -the value that the named element or category will be assigned + ** Return: CMIBoolean true if successful + ** CMIBoolean false if failed. + ** + ** Description: + ** Wraps the call to the LMS LMSSetValue function + ** + *******************************************************************************/ +function doLMSSetValue(name, value) { + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nLMSSetValue was not successful."); + return; + } + else { + var result = api.LMSSetValue(name, value); + if (result.toString() != "true") { + var err = ErrorHandler(); + } + } + + return; } /******************************************************************************* -** -** Function doLMSCommit() -** Inputs: None -** Return: None -** -** Description: -** Call the LMSCommit function -** -*******************************************************************************/ -function doLMSCommit() -{ - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nLMSCommit was not successful."); - return "false"; - } - else - { - var result = api.LMSCommit(""); - if (result != "true") - { - var err = ErrorHandler(); - } - } - - return result.toString(); + ** + ** Function doLMSCommit() + ** Inputs: None + ** Return: None + ** + ** Description: + ** Call the LMSCommit function + ** + *******************************************************************************/ +function doLMSCommit() { + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nLMSCommit was not successful."); + return "false"; + } + else { + var result = api.LMSCommit(""); + if (result != "true") { + var err = ErrorHandler(); + } + } + + return result.toString(); } /******************************************************************************* -** -** Function doLMSGetLastError() -** Inputs: None -** Return: The error code that was set by the last LMS function call -** -** Description: -** Call the LMSGetLastError function -** -*******************************************************************************/ -function doLMSGetLastError() -{ - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nLMSGetLastError was not successful."); - //since we can't get the error code from the LMS, return a general error - return _GeneralError; - } - - return api.LMSGetLastError().toString(); + ** + ** Function doLMSGetLastError() + ** Inputs: None + ** Return: The error code that was set by the last LMS function call + ** + ** Description: + ** Call the LMSGetLastError function + ** + *******************************************************************************/ +function doLMSGetLastError() { + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nLMSGetLastError was not successful."); + //since we can't get the error code from the LMS, return a general error + return _GeneralError; + } + + return api.LMSGetLastError().toString(); } /******************************************************************************* -** -** Function doLMSGetErrorString(errorCode) -** Inputs: errorCode - Error Code -** Return: The textual description that corresponds to the input error code -** -** Description: -** Call the LMSGetErrorString function -** -********************************************************************************/ -function doLMSGetErrorString(errorCode) -{ - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nLMSGetErrorString was not successful."); - } - - return api.LMSGetErrorString(errorCode).toString(); + ** + ** Function doLMSGetErrorString(errorCode) + ** Inputs: errorCode - Error Code + ** Return: The textual description that corresponds to the input error code + ** + ** Description: + ** Call the LMSGetErrorString function + ** + ********************************************************************************/ +function doLMSGetErrorString(errorCode) { + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nLMSGetErrorString was not successful."); + } + + return api.LMSGetErrorString(errorCode).toString(); } /******************************************************************************* -** -** Function doLMSGetDiagnostic(errorCode) -** Inputs: errorCode - Error Code(integer format), or null -** Return: The vendor specific textual description that corresponds to the -** input error code -** -** Description: -** Call the LMSGetDiagnostic function -** -*******************************************************************************/ -function doLMSGetDiagnostic(errorCode) -{ - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nLMSGetDiagnostic was not successful."); - } - - return api.LMSGetDiagnostic(errorCode).toString(); + ** + ** Function doLMSGetDiagnostic(errorCode) + ** Inputs: errorCode - Error Code(integer format), or null + ** Return: The vendor specific textual description that corresponds to the + ** input error code + ** + ** Description: + ** Call the LMSGetDiagnostic function + ** + *******************************************************************************/ +function doLMSGetDiagnostic(errorCode) { + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nLMSGetDiagnostic was not successful."); + } + + return api.LMSGetDiagnostic(errorCode).toString(); } /******************************************************************************* -** -** Function LMSIsInitialized() -** Inputs: none -** Return: true if the LMS API is currently initialized, otherwise false -** -** Description: -** Determines if the LMS API is currently initialized or not. -** -*******************************************************************************/ -function LMSIsInitialized() -{ - // there is no direct method for determining if the LMS API is initialized - // for example an LMSIsInitialized function defined on the API so we'll try - // a simple LMSGetValue and trap for the LMS Not Initialized Error - - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nLMSIsInitialized() failed."); - return false; - } - else - { - var value = api.LMSGetValue("cmi.core.student_name"); - var errCode = api.LMSGetLastError().toString(); - if (errCode == _NotInitialized) - { - return false; - } - else - { - return true; - } - } + ** + ** Function LMSIsInitialized() + ** Inputs: none + ** Return: true if the LMS API is currently initialized, otherwise false + ** + ** Description: + ** Determines if the LMS API is currently initialized or not. + ** + *******************************************************************************/ +function LMSIsInitialized() { + // there is no direct method for determining if the LMS API is initialized + // for example an LMSIsInitialized function defined on the API so we'll try + // a simple LMSGetValue and trap for the LMS Not Initialized Error + + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nLMSIsInitialized() failed."); + return false; + } + else { + var value = api.LMSGetValue("cmi.core.student_name"); + var errCode = api.LMSGetLastError().toString(); + if (errCode == _NotInitialized) { + return false; + } + else { + return true; + } + } } /******************************************************************************* -** -** Function ErrorHandler() -** Inputs: None -** Return: The current value of the LMS Error Code -** -** Description: -** Determines if an error was encountered by the previous API call -** and if so, displays a message to the user. If the error code -** has associated text it is also displayed. -** -*******************************************************************************/ -function ErrorHandler() -{ - var api = getAPIHandle(); - if (api == null) - { - alert("Unable to locate the LMS's API Implementation.\nCannot determine LMS error code."); - return; - } - - // check for errors caused by or from the LMS - var errCode = api.LMSGetLastError().toString(); - if (errCode != _NoError) - { - // an error was encountered so display the error description - var errDescription = api.LMSGetErrorString(errCode); - - if (_Debug == true) - { - errDescription += "\n"; - errDescription += api.LMSGetDiagnostic(null); - // by passing null to LMSGetDiagnostic, we get any available diagnostics - // on the previous error. - } - - alert(errDescription); - } - - return errCode; + ** + ** Function ErrorHandler() + ** Inputs: None + ** Return: The current value of the LMS Error Code + ** + ** Description: + ** Determines if an error was encountered by the previous API call + ** and if so, displays a message to the user. If the error code + ** has associated text it is also displayed. + ** + *******************************************************************************/ +function ErrorHandler() { + var api = getAPIHandle(); + if (api == null) { + fb("Unable to locate the LMS's API Implementation.\nCannot determine LMS error code."); + return; + } + + // check for errors caused by or from the LMS + var errCode = api.LMSGetLastError().toString(); + if (errCode != _NoError) { + // an error was encountered so display the error description + var errDescription = api.LMSGetErrorString(errCode); + + if (_Debug == true) { + errDescription += "\n"; + errDescription += api.LMSGetDiagnostic(null); + // by passing null to LMSGetDiagnostic, we get any available diagnostics + // on the previous error. + } + + fb(errDescription); + } + + return errCode; } /****************************************************************************** -** -** Function getAPIHandle() -** Inputs: None -** Return: value contained by APIHandle -** -** Description: -** Returns the handle to API object if it was previously set, -** otherwise it returns null -** -*******************************************************************************/ -function getAPIHandle() -{ - if (apiHandle == null) - { - apiHandle = getAPI(); - } - - return apiHandle; + ** + ** Function getAPIHandle() + ** Inputs: None + ** Return: value contained by APIHandle + ** + ** Description: + ** Returns the handle to API object if it was previously set, + ** otherwise it returns null + ** + *******************************************************************************/ +function getAPIHandle() { + if (apiHandle == null) { + apiHandle = getAPI(); + } + + return apiHandle; } /******************************************************************************* -** -** Function findAPI(win) -** Inputs: win - a Window Object -** Return: If an API object is found, it's returned, otherwise null is returned -** -** Description: -** This function looks for an object named API in parent and opener windows -** -*******************************************************************************/ -function findAPI(win) -{ - while ((win.API == null) && (win.parent != null) && (win.parent != win)) - { - findAPITries++; - // Note: 7 is an arbitrary number, but should be more than sufficient - if (findAPITries > 7) - { - alert("Error finding API -- too deeply nested."); - return null; - } - - win = win.parent; - - } - return win.API; + ** + ** Function findAPI(win) + ** Inputs: win - a Window Object + ** Return: If an API object is found, it's returned, otherwise null is returned + ** + ** Description: + ** This function looks for an object named API in parent and opener windows + ** + *******************************************************************************/ +function findAPI(win) { + while ((win.API == null) && (win.parent != null) && (win.parent != win)) { + findAPITries++; + // Note: 7 is an arbitrary number, but should be more than sufficient + if (findAPITries > 7) { + fb("Error finding API -- too deeply nested."); + return null; + } + + win = win.parent; + + } + return win.API; } - /******************************************************************************* -** -** Function getAPI() -** Inputs: none -** Return: If an API object is found, it's returned, otherwise null is returned -** -** Description: -** This function looks for an object named API, first in the current window's -** frame hierarchy and then, if necessary, in the current window's opener window -** hierarchy (if there is an opener window). -** -*******************************************************************************/ -function getAPI() -{ - var theAPI = findAPI(window); - if ((theAPI == null) && (window.opener != null) && (typeof(window.opener) != "undefined")) - { - theAPI = findAPI(window.opener); - } - if (theAPI == null) - { - alert("Unable to find an API adapter"); - } - return theAPI + ** + ** Function getAPI() + ** Inputs: none + ** Return: If an API object is found, it's returned, otherwise null is returned + ** + ** Description: + ** This function looks for an object named API, first in the current window's + ** frame hierarchy and then, if necessary, in the current window's opener window + ** hierarchy (if there is an opener window). + ** + *******************************************************************************/ +function getAPI() { + var theAPI = findAPI(window); + if ((theAPI == null) && (window.opener != null) && (typeof(window.opener) != "undefined")) { + theAPI = findAPI(window.opener); + } + if (theAPI == null) { + fb("Unable to find an API adapter"); + } + return theAPI } var startTime; -function startTimer() -{ - startTime = new Date().getTime(); +function startTimer() { + startTime = new Date().getTime(); } - + // call function right before LMSFinish function setSessionTime() { - var currentTime = new Date(); + var currentTime = new Date(); + + var endTime = currentTime.getTime() + + var calculatedTime = endTime - startTime; + + var totalHours = Math.floor(calculatedTime / 1000 / 60 / 60); - var endTime = currentTime.getTime() - - var calculatedTime = endTime-startTime; + calculatedTime = calculatedTime - totalHours * 1000 * 60 * 60 - var totalHours = Math.floor(calculatedTime/1000/60/60); + if (totalHours < 1000 && totalHours > 99) { - calculatedTime = calculatedTime - totalHours*1000*60*60 + totalHours = "0" + totalHours; - if ( totalHours < 1000 && totalHours > 99 ) { + } else if (totalHours < 100 && totalHours > 9) { - totalHours = "0"+totalHours; + totalHours = "00" + totalHours; - } else if ( totalHours < 100 && totalHours > 9 ) { + } else if (totalHours < 10) { - totalHours = "00"+totalHours; + totalHours = "000" + totalHours; - } else if ( totalHours < 10 ) { + } - totalHours = "000"+totalHours; - } - + var totalMinutes = Math.floor(calculatedTime / 1000 / 60); - var totalMinutes = Math.floor(calculatedTime/1000/60); + calculatedTime = calculatedTime - totalMinutes * 1000 * 60; - calculatedTime = calculatedTime - totalMinutes*1000*60; + if (totalMinutes < 10) { - if ( totalMinutes < 10 ) { + totalMinutes = "0" + totalMinutes; - totalMinutes = "0"+totalMinutes; + } - } - - var totalSeconds = Math.floor(calculatedTime/1000); + var totalSeconds = Math.floor(calculatedTime / 1000); - if ( totalSeconds < 10 ) { + if (totalSeconds < 10) { - totalSeconds = "0"+totalSeconds; + totalSeconds = "0" + totalSeconds; - } + } - var sessionTime = totalHours+":"+totalMinutes+":"+totalSeconds; + var sessionTime = totalHours + ":" + totalMinutes + ":" + totalSeconds; - doLMSSetValue("cmi.core.session_time", sessionTime); + doLMSSetValue("cmi.core.session_time", sessionTime); } diff --git a/js/libs/scorm/scorm.js b/js/libs/scorm/scorm.js index b7a5d09d..cfa032c8 100644 --- a/js/libs/scorm/scorm.js +++ b/js/libs/scorm/scorm.js @@ -1,11 +1,42 @@ SCORM = true; $(function () { - doLMSInitialize(); + if (fluidbook) { + initScormEvents(); + } else { + $(document).on('fluidbookready', function () { + initScormEvents(); + }); + } +}); +function initScormEvents() { + doLMSInitialize(); $(window).on('unload', function () { doLMSFinish(); }); -}); + + var currentStatus = getScormValue('cmi.core.lesson_status'); + if (currentStatus != 'passed' || currentStatus != 'completed') { + setScormValue('cmi.core.lesson_status', 'incomplete'); + } + + var currentPage = getScormValue('cmi.core.lesson_location'); + try { + if (currentPage != '') { + var e = currentPage.split('_'); + if (e.length == 2 && e[0] == 'page') { + fluidbook.setCurrentPage(e[1]); + } + } + } catch (err) { + fb(err); + } + + $(fluidbook).on('changePage', function (e, page) { + setScormValue('cmi.core.lesson_location', 'page_' + page); + doLMSCommit(); + }); +} function getScormValue(elementName) { @@ -15,5 +46,6 @@ function getScormValue(elementName) { function setScormValue(elementName, value) { var result = doLMSSetValue(elementName, value); + doLMSCommit(); return result; } \ No newline at end of file diff --git a/js/main.js b/js/main.js index f1942969..cfce6f38 100644 --- a/js/main.js +++ b/js/main.js @@ -426,6 +426,7 @@ try { return true; }); + $(document).trigger('fluidbookready'); setTimeout(function () { resize(); -- 2.39.5