Last active
November 25, 2015 12:05
-
-
Save jleyva/c1df66f7c3df37496999 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Check if the given SCORM is available (time restrictions). | |
* The remote Web Service check that, but if we are offline maybe we have passed the timeclose date. | |
*/ | |
isAvailable = function(scorm) { | |
var timeNow = $mmUtil.timestamp(); | |
if (scorm.timeopen > 0 && scorm.timeopen > timeNow) { | |
return false; | |
} | |
if (scorm.timeclose >0 && timeNow > scorm.timeclose) { | |
return false; | |
} | |
}; | |
/** | |
* Check if is a valid SCORM 1.2 | |
*/ | |
isValidVersion = function(scorm) { | |
return scorm.version == 'scorm_12'; | |
}; | |
/** | |
* Check if the package is downloadable | |
*/ | |
isDownloadable = function(scorm) { | |
var downloadsEnabled = typeof scorm.protectpackagedownloads != 'undefined' && scorm.protectpackagedownloads == true; | |
var hasURL = typeof scorm.packageurl != 'undefined'; | |
return downloadsEnabled && hasURL; | |
}; | |
/** | |
* Check if the TOC should be displayed | |
*/ | |
displayToc = function(scorm) { | |
return scorm.displaycoursestructure == 1; | |
}; | |
/** | |
* Calls the get_scorm_user_data WS | |
*/ | |
getUserData = function(scormId, attemptId) { | |
}; | |
/** | |
* Check if the given SCORM is imcompleted | |
*/ | |
isIncomplete = function(scorm, attemptId) { | |
return self.getUserData(scorm.id, attemptId).then(function(data) { | |
var imcomplete = false; | |
data.forEach(function(sco) { | |
if (sco.userdata.len == 0) { | |
incomplete = true; | |
return; | |
} else { | |
sco.forEach(function(el) { | |
if (el.element == 'status' && (el.value == 'notattempted' || el.value == 'incomplete' || el.value == 'browsed')) { | |
incomplete = true; | |
} | |
}); | |
} | |
}); | |
return incomplete; | |
}); | |
}; | |
/** | |
* Calls remote WS get_attempt_count | |
*/ | |
getAttemptCount = function(scormId, userId, ignoreMissing) { | |
}; | |
/** | |
* Count the attempts left for the given scorm | |
*/ | |
countAttemptsLeft = function(scorm) { | |
if (scorm.maxattempt == 0) { | |
return $q.when(1); | |
} | |
return self.getAttemptCount(scorm.id, $mmSite.getUserId(), false).then(function(result) { | |
return scorm.maxattempt - result.attemptscount; | |
}); | |
}; | |
/** | |
* Call the remote get_scorm_scoes WS for retrieving a list of SCOs | |
* @param {int} scormId the SCORM id | |
* @param {str} organization The organization id | |
* @return {array} A list of SCO objects | |
*/ | |
getScoes = function(scormId, organization) { | |
organization = organization || ''; | |
}; | |
/** | |
* Get the list of a organizations defined in a given SCORM package | |
* @param {int} scormId the SCORM id | |
* @return {array} A list of organizations | |
*/ | |
getOrganizations = function(scormId) { | |
return self.getScoes(scormId, '').then(function(result) { | |
var organizations = []; | |
angular.forEach(result.scoes, function(sco) { | |
// Is an organization entry? | |
if (sco.organization == '' && sco.parent == '/' && sco.scormtype == '') { | |
organizations.push({ | |
identifier: sco.identifier, | |
title: sco.title, | |
sortorder: sco.sortorder | |
}); | |
} | |
}); | |
return organizations; | |
}); | |
}; | |
/** | |
* Get the organization Toc object | |
* | |
* @param {int} scormId The SCORM id | |
* @param {str} organization The organization | |
* @param {int} attemptId The attempt number (to populate SCO track data) | |
* @return {array} The toc object | |
*/ | |
getOrganizationToc = function(scormId, organization, attemptId) { | |
// First of all, get the track data for all the SCOes in the organization for the given attempt. | |
// We need this data to display the SCO status in the toc. | |
return self.getUserData(scormId, attemptId).then(function(data) { | |
var trackData = {}; | |
// Extract data for each SCO. | |
angular.forEach(data, function(scoData) { | |
scoTracks = {}; | |
// Data from array to object. | |
angular.forEach(scoData.userdata, function(el) { | |
scoTracks[el.element] = el.value; | |
}); | |
trackData[scoData.scoid] = scoTracks; | |
}); | |
self.getScoes(scormId, organization).then(function(result) { | |
var map = {}, node, root, trackDataBySCO = {}; | |
// First populate trackDataBySCO to index by SCO identifier. | |
angular.forEAch(result.scoes, function(sco) { | |
trackDataBySCO[sco.identifier] = trackData[sco.id]; | |
}); | |
for (var i = 0; i < result.scoes.length; i += 1) { | |
// Keep the reference to the node. | |
node = result.scoes[i]; | |
node.children = []; | |
map[node.identifier] = i; | |
if (node.parent !== "/") { | |
// Add specific SCO information (related to tracked data). | |
// Check isvisible attribute. | |
node.isvisible = typeof trackData[node.id].isvisible != 'undefined' ? trackData[node.id].isvisible : true; | |
// Check pre-requisites status. | |
node.prereq = typeof trackData[node.id].prerequisites == 'undefined' || self.evalPrerequisites(trackData[node.id].prerequisites, trackDataBySCO); | |
// Add status. | |
node.status = typeof trackData[node.id].status == 'undefined' ? 'notattempted' : trackData[node.id].status; | |
// typeof exit. | |
node.exitvar = typeof trackData[node.id].exitvar == 'undefined' ? 'cmi.core.exit' : trackData[node.id].exitvar; | |
result.scoes[map[node.parent]].children.push(node); | |
} else { | |
root = node; | |
} | |
} | |
return root; | |
}); | |
}); | |
}; | |
evalPrerequisites = function(prerequisites, trackData) { | |
// This is really a little language parser - AICC_SCRIPT is the reference | |
// see 2.3.2.5.1. Sequencing/Navigation Today - from the SCORM 1.2 spec. | |
var element = ''; | |
var stack = []; | |
var statuses = { | |
'passed': 'passed', | |
'completed': 'completed', | |
'failed': 'failed', | |
'incomplete': 'incomplete', | |
'browsed': 'browsed', | |
'not attempted': 'notattempted', | |
'p': 'passed', | |
'c': 'completed', | |
'f': 'failed', | |
'i': 'incomplete', | |
'b': 'browsed', | |
'n': 'notattempted' | |
}; | |
var i = 0; | |
// Expand the amp entities. | |
prerequisites = prerequisites.replace(/&/gi, '&'); | |
// Find all my parsable tokens. | |
prerequisites = prerequisites.replace(/(&|\||\(|\)|\~)/gi, '\t$1\t'); | |
// Expand operators. | |
prerequisites = prerequisites.replace(/&/gi, '&&'); | |
prerequisites = prerequisites.replace(/\|/gi, '||'); | |
// Now - grab all the tokens. | |
var elements = prerequisites.trim().split('\t'); | |
// Process each token to build an expression to be evaluated. | |
angular.forEach(elements, function(element) { | |
element = element.trim(); | |
if (!element) { | |
return; | |
} | |
if (!element.match(/^(&&|\|\||\(|\))$/gi)) { | |
// Create each individual expression. | |
// Search for ~ = <> X*{} . | |
// Sets like 3*{S34, S36, S37, S39}. | |
var re = /^(\d+)\*\{(.+)\}$/; | |
// Other symbols. | |
var reOther = /^(.+)(\=|\<\>)(.+)$/; | |
if (re.test(element)) { | |
var matches = element.match(re); | |
var repeat = matches[1]; | |
var set = matches[2].split(','); | |
var count = 0; | |
angular.forEach(set, function(setelement) { | |
setelement = setelement.trim(); | |
if (typeof trackData[setelement] != 'undefined' && | |
(trackData[setelement].status == 'completed' || trackData[setelement].status == 'passed')) { | |
count++; | |
} | |
}); | |
if (count >= repeat) { | |
element = 'true'; | |
} else { | |
element = 'false'; | |
} | |
} else if (element == '~') { | |
// Not maps ~. | |
element = '!'; | |
} else if (reOther.test(element)) { | |
// Other symbols = | <> . | |
var matches = element.match(reOther); | |
element = matches[1].trim(); | |
if (typeof trackData[element] != 'undefined') { | |
value = matches[3].trim().replace(/(\'|\")/gi); | |
if (typeof statuses[value] != 'undefined') { | |
value = statuses[value]; | |
} | |
if (matches[2] == '<>') { | |
oper = '!='; | |
} else { | |
oper = '=='; | |
} | |
element = '(\'' + trackData[element].status + '\' ' + oper + ' \'' + value + '\')'; | |
} else { | |
element = 'false'; | |
} | |
} else { | |
// Everything else must be an element defined like S45 ... | |
if (typeof trackData[element] != 'undefined' && | |
(trackData[element].status == 'completed' || trackData[element].status == 'passed')) { | |
element = 'true'; | |
} else { | |
element = 'false'; | |
} | |
} | |
} | |
stack.push(' ' + element + ' '); | |
}); | |
return eval(stack.join('') + ';'); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment