diff --git a/mod/scorm/datamodel.php b/mod/scorm/datamodel.php index 6a81130b90b..eb1f1b546c3 100644 --- a/mod/scorm/datamodel.php +++ b/mod/scorm/datamodel.php @@ -62,7 +62,7 @@ if (confirm_sesskey() && (!empty($scoid))) { } if (substr($element, 0, 15) == 'adl.nav.request') { // SCORM 2004 Sequencing Request - require_once($CFG->dirroot.'/mod/scorm/datamodels/sequencinglib.php'); + require_once($CFG->dirroot.'/mod/scorm/datamodels/scorm_13lib.php'); $search = array('@continue@', '@previous@', '@\{target=(\S+)\}choice@', '@exit@', '@exitAll@', '@abandon@', '@abandonAll@'); $replace = array('continue_', 'previous_', '\1', 'exit_', 'exitall_', 'abandon_', 'abandonall'); diff --git a/mod/scorm/datamodels/aicc.js.php b/mod/scorm/datamodels/aicc.js.php index 0b1964c4718..a5dd434bb33 100644 --- a/mod/scorm/datamodels/aicc.js.php +++ b/mod/scorm/datamodels/aicc.js.php @@ -234,13 +234,13 @@ require_once($CFG->dirroot.'/mod/scorm/datamodels/callback.js.php'); result = StoreData(cmi,true); if (nav.event != '') { if (nav.event == 'continue') { - setTimeout('scorm_get_next();',500); + setTimeout('mod_scorm_launch_next_sco();',500); } else { - setTimeout('scorm_get_prev();',500); + setTimeout('mod_scorm_launch_prev_sco();',500); } } else { if (auto ?> == 1) { - setTimeout('scorm_get_next();',500); + setTimeout('mod_scorm_launch_next_sco();',500); } } // trigger TOC update diff --git a/mod/scorm/datamodels/callback.js.php b/mod/scorm/datamodels/callback.js.php index 22b944efc5a..a51fc44ec51 100644 --- a/mod/scorm/datamodels/callback.js.php +++ b/mod/scorm/datamodels/callback.js.php @@ -53,7 +53,7 @@ startNode = el_new_tree; } //var sXML = new XMLSerializer().serializeToString(startNode); - scorm_tree_node.buildTreeFromMarkup(startNode); + scorm_tree_node.buildTreeFromMarkup('scormtree123'); var el = document.getElementById('scormtree123'); el.parentNode.removeChild(el); scorm_tree_node.expandAll(); diff --git a/mod/scorm/datamodels/scorm_12.js.php b/mod/scorm/datamodels/scorm_12.js.php index f6a4523c1af..f8b69633cc2 100644 --- a/mod/scorm/datamodels/scorm_12.js.php +++ b/mod/scorm/datamodels/scorm_12.js.php @@ -211,13 +211,13 @@ function SCORMapi1_2() { result = StoreData(cmi,true); if (nav.event != '') { if (nav.event == 'continue') { - setTimeout('scorm_get_next();',500); + setTimeout('mod_scorm_launch_next_sco();',500); } else { - setTimeout('scorm_get_prev();',500); + setTimeout('mod_scorm_launch_prev_sco();',500); } } else { if (auto ?> == 1) { - setTimeout('scorm_get_next();',500); + setTimeout('mod_scorm_launch_next_sco();',500); } } auto ?> == 1) { - setTimeout('scorm_get_next();',500); + setTimeout('mod_scorm_launch_next_sco();',500); } } // trigger TOC update diff --git a/mod/scorm/datamodels/scorm_13lib.php b/mod/scorm/datamodels/scorm_13lib.php index a7b697ddbc9..ba7f76eb4f1 100644 --- a/mod/scorm/datamodels/scorm_13lib.php +++ b/mod/scorm/datamodels/scorm_13lib.php @@ -14,3 +14,1130 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . +require_once($CFG->dirroot.'/mod/scorm/datamodels/scormlib.php'); + +function scorm_seq_overall ($scoid, $userid, $request, $attempt) { + $seq = scorm_seq_navigation($scoid, $userid, $request, $attempt); + if ($seq->navigation) { + if ($seq->termination != null) { + $seq = scorm_seq_termination($scoid, $userid, $seq); + } + if ($seq->sequencing != null) { + $seq = scorm_seq_sequencing($scoid, $userid, $seq); + if($seq->sequencing == 'exit'){//return the control to the LTS + return 'true'; + } + } + if ($seq->delivery != null) { + $seq = scorm_sequencing_delivery($scoid, $userid, $seq); + $seq = scorm_content_delivery_environment ($seq, $userid); + } + } + if ($seq->exception != null) { + $seq = scorm_sequencing_exception($seq); + } + return 'true'; +} + +function scorm_seq_navigation ($scoid, $userid, $request, $attempt=0) { + global $DB; + + // Sequencing structure + $seq = new stdClass(); + $seq->currentactivity = scorm_get_sco($scoid); + $seq->traversaldir = null; + $seq->nextactivity = null; + $seq->deliveryvalid = null; + $seq->attempt = $attempt; + + $seq->identifiedactivity = null; + $seq->delivery = null; + $seq->deliverable = false; + $seq->active = scorm_seq_is('active', $scoid, $userid); + $seq->suspended = scorm_seq_is('suspended', $scoid, $userid); + $seq->navigation = null; + $seq->termination = null; + $seq->sequencing = null; + $seq->target = null; + $seq->endsession = null; + $seq->exception = null; + $seq->reachable = true; + $seq->prevact = true; + + $sco = scorm_get_sco($scoid); + + switch ($request) { + case 'start_': + if (empty($seq->currentactivity)) { + $seq->navigation = true; + $seq->sequencing = 'start'; + } else { + $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun + } + break; + case 'resumeall_': + if (empty($seq->currentactivity)) { + if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'suspendedactivity'))) {//I think it's suspend instead of suspendedactivity + $seq->navigation = true; + $seq->sequencing = 'resumeall'; + } else { + $seq->exception = 'NB.2.1-3'; /// No suspended activity found + } + } else { + $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun + } + break; + case 'continue_': + case 'previous_': + if (!empty($seq->currentactivity)) { + $sco = $seq->currentactivity; + if ($sco->parent != '/') { + if ($parentsco = scorm_get_parent($sco)) { + + if (isset($parentsco->flow) && ($parentsco->flow == true)) {//I think it's parentsco + // Current activity is active ! + if (scorm_seq_is('active',$sco->id,$userid)) { + if ($request == 'continue_') { + $seq->navigation = true; + $seq->termination = 'exit'; + $seq->sequencing = 'continue'; + } else { + if (!isset($parentsco->forwardonly) || ($parentsco->forwardonly == false)) { + $seq->navigation = true; + $seq->termination = 'exit'; + $seq->sequencing = 'previous'; + } else { + $seq->exception = 'NB.2.1-5'; /// Violates control mode + } + } + } + } + + } + } + } else { + $seq->exception = 'NB.2.1-2'; /// Current activity not defined + } + break; + case 'forward_': + case 'backward_': + $seq->exception = 'NB.2.1-7' ; /// None to be done, behavior not defined + break; + case 'exit_': + case 'abandon_': + if (!empty($seq->currentactivity)) { + // Current activity is active ! + $seq->navigation = true; + $seq->termination = substr($request,0,-1); + $seq->sequencing = 'exit'; + } else { + $seq->exception = 'NB.2.1-2'; /// Current activity not defined + } + case 'exitall_': + case 'abandonall_': + case 'suspendall_': + if (!empty($seq->currentactivity)) { + $seq->navigation = true; + $seq->termination = substr($request,0,-1); + $seq->sequencing = 'exit'; + } else { + $seq->exception = 'NB.2.1-2'; /// Current activity not defined + } + break; + default: /// {target=}choice + if ($targetsco = $DB->get_record('scorm_scoes', array('scorm'=>$sco->scorm,'identifier'=>$request))) { + if ($targetsco->parent != '/') { + $seq->target = $request; + } else { + if ($parentsco = scorm_get_parent($targetsco)) { + if (!isset($parentsco->choice) || ($parentsco->choice == true)) { + $seq->target = $request; + } + } + } + if ($seq->target != null) { + if (empty($seq->currentactivity)) { + $seq->navigation = true; + $seq->sequencing = 'choice'; + } else { + if (!$sco = scorm_get_sco($scoid)) { + return $seq; + } + if ($sco->parent != $targetsco->parent) { + $ancestors = scorm_get_ancestors($sco); + $commonpos = scorm_find_common_ancestor($ancestors,$targetsco); + if ($commonpos !== false) { + if ($activitypath = array_slice($ancestors,0,$commonpos)) { + foreach ($activitypath as $activity) { + if (scorm_seq_is('active',$activity->id,$userid) && (isset($activity->choiceexit) && ($activity->choiceexit == false))) { + $seq->navigation = false; + $seq->termination = null; + $seq->sequencing = null; + $seq->target = null; + $seq->exception = 'NB.2.1-8'; /// Violates control mode + return $seq; + } + } + } else { + $seq->navigation = false; + $seq->termination = null; + $seq->sequencing = null; + $seq->target = null; + $seq->exception = 'NB.2.1-9'; + } + } + } + // Current activity is active ! + $seq->navigation = true; + $seq->sequencing = 'choice'; + } + } else { + $seq->exception = 'NB.2.1-10'; /// Violates control mode + } + } else { + $seq->exception = 'NB.2.1-11'; /// Target activity does not exists + } + break; + } + return $seq; +} + +function scorm_seq_termination ($seq,$userid) { + if (empty($seq->currentactivity)) { + $seq->termination = false; + $seq->exception = 'TB.2.3-1'; + return $seq; + } + + $sco = $seq->currentactivity; + + if ((($seq->termination == 'exit') || ($seq->termination == 'abandon')) && !$seq->active) { + $seq->termination = false; + $seq->exception = 'TB.2.3-2'; + return $seq; + } + switch ($seq->termination) { + case 'exit': + scorm_seq_end_attempt($sco,$userid,$seq); + $seq = scorm_seq_exit_action_rules($seq,$userid); + do { + $exit = false;// I think this is false. Originally this was true + $seq = scorm_seq_post_cond_rules($seq,$userid); + if ($seq->termination == 'exitparent') { + if ($sco->parent != '/') { + $sco = scorm_get_parent($sco); + $seq->currentactivity = $sco; + $seq->active = scorm_seq_is('active',$sco->id,$userid); + scorm_seq_end_attempt($sco,$userid,$seq); + $exit = true;//I think it's true. Originally this was false + } else { + $seq->termination = false; + $seq->exception = 'TB.2.3-4'; + return $seq; + } + } + } while (($exit == false) && ($seq->termination == 'exit')); + if ($seq->termination == 'exit') { + $seq->termination = true; + return $seq; + } + case 'exitall': + if ($seq->active) { + scorm_seq_end_attempt($sco,$userid,$seq); + } + /// Terminate Descendent Attempts Process + + + if ($ancestors = scorm_get_ancestors($sco)) { + foreach ($ancestors as $ancestor) { + scorm_seq_end_attempt($ancestor,$userid,$seq); + $seq->currentactivity = $ancestor; + } + } + + $seq->active = scorm_seq_is('active',$seq->currentactivity->id,$userid); + $seq->termination = true; + $seq->sequencing = exit; + break; + case 'suspendall': + if (($seq->active) || ($seq->suspended)) { + scorm_seq_set('suspended',$sco->id,$userid, $attempt); + } else { + if ($sco->parent != '/') { + $parentsco = scorm_get_parent($sco); + scorm_seq_set('suspended',$parentsco->id,$userid, $attempt); + } else { + $seq->termination = false; + $seq->exception = 'TB.2.3-3'; + // return $seq; + } + } + if ($ancestors = scorm_get_ancestors($sco)) { + foreach ($ancestors as $ancestor) { + scorm_seq_set('active',$ancestor->id,$userid, $attempt, false); + scorm_seq_set('suspended',$ancestor->id,$userid, $attempt); + $seq->currentactivity = $ancestor; + } + $seq->termination = true; + $seq->sequencing = 'exit'; + } else { + $seq->termination = false; + $seq->exception = 'TB.2.3-5'; + } + break; + case 'abandon': + scorm_seq_set('active',$sco->id,$userid, $attempt, false); + $seq->active = null; + $seq->termination = true; + break; + case 'abandonall': + if ($ancestors = scorm_get_ancestors($sco)) { + foreach ($ancestors as $ancestor) { + scorm_seq_set('active',$ancestor->id,$userid, $attempt, false); + $seq->currentactivity = $ancestor; + } + $seq->termination = true; + $seq->sequencing = 'exit'; + } else { + $seq->termination = false; + $seq->exception = 'TB.2.3-6'; + } + break; + default: + $seq->termination = false; + $seq->exception = 'TB.2.3-7'; + break; + } + return $seq; +} + +function scorm_seq_end_attempt($sco, $userid, $seq) { + global $DB; + if (scorm_is_leaf($sco)) { + if (!isset($sco->tracked) || ($sco->tracked == 1)) { + if (!scorm_seq_is('suspended',$sco->id,$userid)) { + if (!isset($sco->completionsetbycontent) || ($sco->completionsetbycontent == 0)) { + if (!scorm_seq_is('attemptprogressstatus',$sco->id, $userid, $seq->attempt)) { + $incomplete = $DB->get_field('scorm_scoes_track', 'value', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'cmi.completion_status')); + if ($incomplete != 'incomplete') { + scorm_seq_set('attemptprogressstatus',$sco->id,$userid, $seq->attempt); + scorm_seq_set('attemptcompletionstatus',$sco->id,$userid, $seq->attempt); + } + } + } + if (!isset($sco->objectivesetbycontent) || ($sco->objectivesetbycontent == 0)) { + if ($objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id))) { + foreach ($objectives as $objective) { + if ($objective->primaryobj) { + //if (!scorm_seq_objective_progress_status($sco,$userid,$objective)) { + if (!scorm_seq_is('objectiveprogressstatus', $sco->id, $userid, $seq->attempt)) { + scorm_seq_set('objectiveprogressstatus', $sco->id, $userid, $seq->attempt); + scorm_seq_set('objectivesatisfiedstatus', $sco->id, $userid, $seq->attempt); + } + } + } + } + } + } + } + } else if ($children = scorm_get_children($sco)) { + $suspended = false; + foreach ($children as $child) { + if (scorm_seq_is('suspended',$child, $userid, $seq->attempt)) { + $suspended = true; + break; + } + } + if ($suspended) { + scorm_seq_set('suspended',$sco, $userid, $seq->attempt); + } else { + scorm_seq_set('suspended',$sco,$userid, $seq->attempt, false); + } + } + scorm_seq_set('active', $sco->id, $userid, $seq->attempt, false); + scorm_seq_overall_rollup($sco, $userid, $seq); +} + +function scorm_seq_is($what, $scoid, $userid, $attempt=0) { + global $DB; + + /// Check if passed activity $what is active + $active = false; + if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what))) { + $active = true; + } + return $active; +} + +function scorm_seq_set($what, $scoid, $userid, $attempt=0, $value='true') { + global $DB; + + $sco = scorm_get_sco($scoid); + + /// set passed activity to active or not + if ($value == false) { + $DB->delete_records('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what)); + } else { + scorm_insert_track($userid, $sco->scorm, $sco->id, $attempt, $what, $value); + } + + // update grades in gradebook + $scorm = $DB->get_record('scorm', array('id'=>$sco->scorm)); + scorm_update_grades($scorm, $userid, true); +} + +function scorm_evaluate_condition ($rollupruleconds, $sco, $userid) { + global $DB; + + $res = false; + + if (strpos($rollupruleconds, 'and ')) { + $rollupruleconds = array_filter(explode(' and ', $rollupruleconds)); + $conditioncombination = 'all'; + } else { + $rollupruleconds = array_filter(explode(' or ', $rollupruleconds)); + $conditioncombination = 'or'; + } + foreach($rollupruleconds as $rolluprulecond) { + $notflag = false; + if (strpos($rolluprulecond, 'not') !== false) { + $rolluprulecond = str_replace('not', '', $rolluprulecond); + $notflag = true; + } + $conditionarray['condition'] = $rolluprulecond; + $conditionarray['notflag'] = $notflag; + $conditions[] = $conditionarray; + } + foreach ($conditions as $condition) { + $checknot = true; + $res = false; + if ($condition['notflag']) { + $checknot = false; + } + switch ($condition['condition']) { + case 'satisfied': + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivesatisfiedstatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $res = true; + } + } + break; + + case 'objectiveStatusKnown': + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $res = true; + } + break; + + case 'notobjectiveStatusKnown': + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $res = true; + } + break; + + case 'objectiveMeasureKnown': + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivemeasurestatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $res = true; + } + break; + + case 'notobjectiveMeasureKnown': + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivemeasurestatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $res = true; + } + break; + + case 'completed': + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptcompletionstatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $res = true; + } + } + break; + + case 'attempted': + $attempt = $DB->get_field('scorm_scoes_track', 'attempt', array('scoid'=>$sco->id, 'userid'=>$userid, 'element'=>'x.start.time')); + if ($checknot && $attempt > 0) { + $res = true; + } else if (!$checknot && $attempt <= 0) { + $res = true; + } + break; + + case 'attemptLimitExceeded': + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'limitconditionattemptlimitcontrol')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + if ($r = $DB->get_field('scorm_scoes_track', 'attempt', array('scoid'=>$sco->id,'userid'=>$userid)) && + $r2 = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'limitconditionattemptlimit')) ){ + if ($checknot && ($r->value >= $r2->value)) { + $res = true; + } else if (!$checknot && ($r->value < $r2->value)) { + $res = true; + } + } + } + } + break; + + case 'activityProgressKnown': + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus')); + if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) { + $res = true; + } + } + break; + } + + if ($conditioncombination == 'all' && !$res) { + break; + } else if ($conditioncombination == 'or' && $res) { + break; + } + } + + return $res; +} + +function scorm_check_activity ($activity,$userid){ + $act = scorm_seq_rules_check($activity,'disabled'); + if ($act != null){ + return true; + } + if(scorm_limit_cond_check ($activity,$userid)){ + return true; + } + return false; +} + +function scorm_limit_cond_check ($activity,$userid){ + global $DB; + + if (isset($activity->tracked) && ($activity->tracked == 0)){ + + return false; + } + + if (scorm_seq_is('active',$activity->id,$userid) || scorm_seq_is('suspended',$activity->id,$userid)){ + return false; + } + + if (!isset($activity->limitcontrol) || ($activity->limitcontrol == 1)){ + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount')); + if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattempt)){ + return true; + } + } + + if (!isset($activity->limitabsdurcontrol) || ($activity->limitabsdurcontrol == 1)){ + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityabsoluteduration')); + if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitabsduration)){ + return true; + } + } + + if (!isset($activity->limitexpdurcontrol) || ($activity->limitexpdurcontrol == 1)){ + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityexperiencedduration')); + if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitexpduration)){ + return true; + } + } + + if (!isset($activity->limitattabsdurcontrol) || ($activity->limitattabsdurcontrol == 1)){ + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration')); + if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattabsduration)){ + return true; + } + } + + if (!isset($activity->limitattexpdurcontrol) || ($activity->limitattexpdurcontrol == 1)){ + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration')); + if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattexpduration)){ + return true; + } + } + + if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){ + $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'begintime')); + if (isset($activity->limitbegintime) && time() >= $activity->limitbegintime){ + return true; + } + } + + if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){ + if (isset($activity->limitbegintime) && time() < $activity->limitbegintime){ + return true; + } + } + + if (!isset($activity->limitendcontrol) || ($activity->limitendcontrol == 1)){ + if (isset($activity->limitendtime) && time() > $activity->limitendtime) { + return true; + } + } + return false; + + +} + +function scorm_seq_rules_check ($sco, $action){ + global $DB; + $act = null; + + if ($rules = $DB->get_records('scorm_seq_ruleconds', array('scoid' => $sco->id, 'action' => $action))) { + foreach ($rules as $rule) { + if ($act = scorm_seq_rule_check($sco, $rule)){ + return $act; + } + } + } + return $act; + +} + +function scorm_seq_rule_check ($sco, $rule){ + global $DB; + + $bag = Array(); + $cond = ''; + $ruleconds = $DB->get_records('scorm_seq_rulecond', array('scoid'=>$sco->id,'ruleconditionsid'=>$rule->id)); + foreach ($ruleconds as $rulecond){ + if ($rulecond->operator == 'not') { + if ($rulecond->cond != 'unknown' ){ + $rulecond->cond = 'not'.$rulecond->cond; + } + } + $bag[] = $rulecond->cond; + } + if (empty($bag)){ + $cond = 'unknown'; + return $cond; + } + + if ($rule->conditioncombination == 'all') { + foreach ($bag as $con){ + $cond = $cond.' and '.$con; + } + } else { + foreach ($bag as $con){ + $cond = $cond.' or '.$con; + } + } + return $cond; +} + +function scorm_seq_overall_rollup($sco,$userid, $seq){//Carlos + + if ($ancestors = scorm_get_ancestors($sco)) { + foreach ($ancestors as $ancestor) { + if(!scorm_is_leaf($ancestor)){ + scorm_seq_measure_rollup($sco, $userid, $seq->attempt); + } + scorm_seq_objective_rollup($sco, $userid, $seq->attempt); + scorm_seq_activity_progress_rollup($sco,$userid, $seq); + + } + + } +} + +function scorm_seq_measure_rollup($sco, $userid, $attempt = 0) { + global $DB; + + $totalmeasure = 0; //Check if there is something similar in the database + $valid = false; //Same as in the last line + $countedmeasures = 0; //Same too + $targetobjective = null; + $readable = true; //to check if status and measure weight are readable + $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id)); + + foreach ($objectives as $objective){ + if ($objective->primaryobj == true){ //Objective contributes to rollup + $targetobjective = $objective; + break; + } + + } + if ($targetobjective != null){ + $children = scorm_get_children($sco); + if (!empty ($children)) { + foreach ($children as $child){ + $child = scorm_get_sco ($child); + if (!isset($child->tracked) || ($child->tracked == 1)){ + $rolledupobjective = null;// we set the rolled up activity to undefined + $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$child->id)); + foreach ($objectives as $objective){ + if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not + $rolledupobjective = $objective; + break; + } + } + if ($rolledupobjective != null){ + $child = scorm_get_sco($child->id); + $countedmeasures = $countedmeasures + ($child->measureweight); + if (!scorm_seq_is('objectivemeasurestatus', $sco->id, $userid, $attempt)) { + $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure')); + $totalmeasure = $totalmeasure + (($normalizedmeasure->value) * ($child->measureweight)); + $valid = true; + } + } + } + } + } + + if (!$valid) { + scorm_seq_set('objectivemeasurestatus', $sco->id, $userid, $attempt, false); + } else { + if ($countedmeasures > 0) { + scorm_seq_set('objectivemeasurestatus', $sco->id, $userid, $attempt); + $val = $totalmeasure/$countedmeasures; + scorm_seq_set('objectivenormalizedmeasure',$sco->id, $userid, $attempt, $val); + } else { + scorm_seq_set('objectivemeasurestatus', $sco->id, $userid, $attempt, false); + } + } + } +} + +function scorm_seq_objective_rollup($sco,$userid, $attempt = 0){ + global $DB; + + scorm_seq_objective_rollup_measure($sco,$userid, $attempt); + scorm_seq_objective_rollup_rules($sco, $userid, $attempt); + scorm_seq_objective_rollup_default($sco, $userid, $attempt); + +/* + if($targetobjective->satisfiedbymeasure){ + scorm_seq_objective_rollup_measure($sco,$userid); + } + else{ + if ((scorm_seq_rollup_rule_check($sco,$userid,'incomplete'))|| (scorm_seq_rollup_rule_check($sco,$userid,'completed'))){ + scorm_seq_objective_rollup_rules($sco,$userid); + } + else{ + + $rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid)); + foreach($rolluprules as $rolluprule){ + $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id)); + foreach($rollupruleconds as $rolluprulecond){ + + switch ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){ + + scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false); + + break; + } + } + + + } + } +*/ +} + +function scorm_seq_objective_rollup_measure($sco, $userid, $attempt = 0) { + global $DB; + + $targetobjective = null; + + + $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id)); + foreach ($objectives as $objective){ + if ($objective->primaryobj == true){ + $targetobjective = $objective; + break; + } + } + if ($targetobjective != null){ + if($targetobjective->satisfiedbymeasure){ + if (!scorm_seq_is('objectiveprogressstatus',$sco->id, $userid, $attempt)) { + scorm_seq_set('objectiveprogressstatus',$sco->id, $userid, $attempt, false); + } else { + if (scorm_seq_is('active', $sco->id, $userid, $attempt)) { + $isactive = true; + } else { + $isactive = false; + } + + $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure')); + + $sco = scorm_get_sco ($sco->id); + + if (!$isactive || ($isactive && (!isset($sco->measuresatisfactionifactive) || $sco->measuresatisfactionifactive == true))){ + if (isset($normalizedmeasure->value) && ($normalizedmeasure->value >= $targetobjective->minnormalizedmeasure)) { + scorm_seq_set('objectiveprogressstatus', $sco->id, $userid, $attempt); + scorm_seq_set('objectivesatisfiedstatus', $sco->id, $userid, $attempt); + } else { + // TODO: handle the case where cmi.success_status is passed and objectivenormalizedmeasure undefined + scorm_seq_set('objectiveprogressstatus', $sco->id, $userid, $attempt); + // scorm_seq_set('objectivesatisfiedstatus', $sco->id, $userid, $attempt, false); + } + } else { + scorm_seq_set('objectiveprogressstatus', $sco->id, $userid, $attempt, false); + } + } + } + } +} + +function scorm_seq_objective_rollup_default($sco, $userid, $attempt = 0) { + global $DB; + + if (!(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')) && !(scorm_seq_rollup_rule_check($sco,$userid,'completed'))){ + if ($rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id))) { + foreach($rolluprules as $rolluprule){ + $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id)); + foreach($rollupruleconds as $rolluprulecond){ + if ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){ + scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, $attempt, false); + break; + } + } + } + } + } +} + + +function scorm_seq_objective_rollup_rules($sco,$userid, $attempt = 0){ + global $DB; + + $targetobjective = null; + + $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id)); + foreach ($objectives as $objective){ + if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not + $targetobjective = $objective; + break; + } + } + if ($targetobjective != null){ + + if(scorm_seq_rollup_rule_check($sco,$userid,'notsatisfied')){//with not satisfied rollup for the activity + scorm_seq_set('objectiveprogressstatus', $sco->id, $userid, $attempt); + scorm_seq_set('objectivesatisfiedstatus', $sco->id, $userid, $attempt, false); + } + if(scorm_seq_rollup_rule_check($sco, $userid, 'satisfied')){//with satisfied rollup for the activity + scorm_seq_set('objectiveprogressstatus', $sco->id, $userid, $attempt); + scorm_seq_set('objectivesatisfiedstatus', $sco->id, $userid, $attempt); + } + + } + +} + +function scorm_seq_activity_progress_rollup ($sco, $userid, $seq){ + + if(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')){ + //incomplete rollup action + scorm_seq_set('attemptcompletionstatus', $sco->id,$userid, $seq->attempt, false); + scorm_seq_set('attemptprogressstatus', $sco->id,$userid, $seq->attempt, true); + + } + if(scorm_seq_rollup_rule_check($sco,$userid,'completed')){ + //incomplete rollup action + scorm_seq_set('attemptcompletionstatus',$sco->id,$userid, $seq->attempt, true); + scorm_seq_set('attemptprogressstatus',$sco->id,$userid, $seq->attempt, true); + } + +} + +function scorm_seq_rollup_rule_check ($sco, $userid, $action){ + global $DB; + + if($rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id, 'action'=>$action))) { + $childrenbag = Array (); + $children = scorm_get_children ($sco); + + foreach($rolluprules as $rolluprule){ + foreach ($children as $child){ + + /*$tracked = $DB->get_records('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid)); + if($tracked && $tracked->attemp != 0){*/ + $child = scorm_get_sco ($child); + if (!isset($child->tracked) || ($child->tracked == 1)) { + if(scorm_seq_check_child ($child,$action,$userid)) { + $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id)); + $evaluate = scorm_seq_evaluate_rollupcond($child,$rolluprule->conditioncombination,$rollupruleconds,$userid); + if ($evaluate=='unknown'){ + array_push($childrenbag,'unknown'); + } else { + if($evaluate == true){ + array_push($childrenbag,true); + } + else{ + array_push($childrenbag,false); + } + } + } + } + + } + $change = false; + + switch ($rolluprule->childactivityset){ + + case 'all': + if((array_search(false,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR + $change = true; + } + break; + + case 'any': + if(array_search(true,$childrenbag)!==false){//I think I can use this condition instead equivalent to OR + $change = true; + } + break; + + case 'none': + if((array_search(true,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR + $change = true; + } + break; + + case 'atleastcount': + foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR + $cont = 0; + if($itm === true){ + $cont++; + } + if($cont >= $rolluprule->minimumcount){ + $change = true; + } + } + break; + + case 'atleastcount': + foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR + $cont = 0; + if($itm === true){ + $cont++; + } + if($cont >= $rolluprule->minimumcount){ + $change = true; + } + } + break; + + case 'atleastpercent': + foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR + $cont = 0; + if($itm === true){ + $cont++; + } + if(($cont/sizeof($childrenbag)) >= $rolluprule->minimumcount){ + $change = true; + } + } + break; + } + if ($change==true){ + return true; + } + } + } + return false; +} + +function scorm_seq_flow_tree_traversal($activity, $direction, $childrenflag, $prevdirection, $seq, $userid, $skip = false) { + $revdirection = false; + $parent = scorm_get_parent($activity); + $children = scorm_get_available_children($parent); + $childrensize = sizeof($children); + + if (($prevdirection != null && $prevdirection == 'backward') && ($children[$childrensize-1]->id == $activity->id)) { + $direction = 'backward'; + $activity = $children[0]; + $revdirection = true; + } + + if($direction == 'forward'){ + $ancestors = scorm_get_ancestors($activity); + $ancestorsroot = array_reverse($ancestors); + $preorder = array(); + $preorder = scorm_get_preorder($preorder, $ancestorsroot[0]); + $preordersize = sizeof($preorder); + if (($activity->id == $preorder[$preordersize - 1]->id) || (($activity->parent == '/') && !($childrenflag))) { + //scorm_seq_terminate_descent($ancestorsroot,$userid); TODO: undefined + $seq->endsession = true; + $seq->nextactivity = null; + return $seq; + } + if (scorm_is_leaf ($activity) || !$childrenflag) { + if ($children[$childrensize-1]->id == $activity->id) { + $seq = scorm_seq_flow_tree_traversal ($parent, $direction, false, null, $seq, $userid); + if ($seq->nextactivity->launch == null) { + $seq = scorm_seq_flow_tree_traversal ($seq->nextactivity, $direction, true, null, $seq, $userid); + } + return $seq; + } else { + $position = 0; + foreach ($children as $sco) { + if ($sco->id == $activity->id) { + break; + } + $position++; + } + if ($position != ($childrensize - 1)) { + $seq->nextactivity = $children[$position + 1]; + $seq->traversaldir = $direction; + return $seq; + } else { + $siblings = scorm_get_siblings($activity); + $children = scorm_get_children($siblings[0]); + $seq->nextactivity = $children[0]; + return $seq; + } + } + } else { + $children = scorm_get_available_children($activity); + if (!empty($children)) { + $seq->traversaldir = $direction; + $seq->nextactivity = $children[0]; + return $seq; + } else { + $seq->traversaldir = null; + $seq->nextactivity = null; + $seq->exception = 'SB.2.1-2'; + return $seq; + } + } + } else if($direction == 'backward') { + if ($activity->parent == '/') { + $seq->traversaldir = null; + $seq->nextactivity = null; + $seq->exception = 'SB.2.1-3'; + return $seq; + } + if (scorm_is_leaf ($activity) || !$childrenflag) { + if (!$revdirection) { + if (isset($parent->forwardonly) && ($parent->forwardonly == true && !$skip)) { + $seq->traversaldir = null; + $seq->nextactivity = null; + $seq->exception = 'SB.2.1-4'; + return $seq; + } + } + if ($children[0]->id == $activity->id) { + $seq = scorm_seq_flow_tree_traversal($parent, 'backward', false, null, $seq, $userid); + return $seq; + } else { + $ancestors = scorm_get_ancestors($activity); + $ancestorsroot = array_reverse($ancestors); + $preorder = array(); + $preorder = scorm_get_preorder($preorder, $ancestorsroot[0]); + $position = 0; + foreach ($preorder as $sco) { + if ($sco->id == $activity->id) { + break; + } + $position++; + } + if (isset($preorder[$position])) { + $seq->nextactivity = $preorder[$position - 1]; + $seq->traversaldir = $direction; + } + return $seq; + } + } + else{ + $children = scorm_get_available_children($activity); + if (!empty($children)){ + $activity = scorm_get_sco($activity->id); + if (isset($parent->flow) && ($parent->flow == true)) { + $seq->traversaldir = 'forward'; + $seq->nextactivity = $children[0]; + return $seq; + } else { + $seq->traversaldir = 'backward'; + $seq->nextactivity = $children[sizeof($children) - 1]; + return $seq; + } + } else { + $seq->traversaldir = null; + $seq->nextactivity = null; + $seq->exception = 'SB.2.1-2'; + return $seq; + } + } + } +} + +function scorm_seq_flow_activity_traversal ($activity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid) {// returns the next activity on the tree, traversal direction, control returned to the LTS, (may) exception + $parent = scorm_get_parent ($activity); + if (!isset($parent->flow) || ($parent->flow == false)) { + $seq->deliverable = false; + $seq->exception = 'SB.2.2-1'; + $seq->nextactivity = $activity; + return $seq; + } + + $rulecheck = scorm_seq_rules_check($activity, 'skip'); + if ($rulecheck != null) { + $skip = scorm_evaluate_condition ($rulecheck, $activity, $userid); + if ($skip) { + $seq = scorm_seq_flow_tree_traversal($activity, $direction, false, $prevdirection, $seq, $userid, $skip); + $seq = scorm_seq_flow_activity_traversal($seq->nextactivity, $userid, $direction, $childrenflag, $prevdirection, $seq, $userid); + } else if (!empty($seq->identifiedactivity)) { + $seq->nextactivity = $activity; + } + return $seq; + } + + $ch = scorm_check_activity ($activity,$userid); + if ($ch){ + $seq->deliverable = false; + $seq->exception = 'SB.2.2-2'; + $seq->nextactivity = $activity; + return $seq; + } + + if (!scorm_is_leaf($activity)){ + $seq = scorm_seq_flow_tree_traversal ($activity, $direction, true, null, $seq, $userid); + if ($seq->identifiedactivity == null){ + $seq->deliverable = false; + $seq->nextactivity = $activity; + return $seq; + } else { + if ($direction == 'backward' && $seq->traversaldir == 'forward'){ + $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, 'forward', $childrenflag, 'backward', $seq, $userid); + } else { + $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, null, $seq, $userid); + } + return $seq; + } + + } + + $seq->deliverable = true; + $seq->nextactivity = $activity; + $seq->exception = null; + return $seq; + +} + +function scorm_seq_flow ($activity, $direction, $seq, $childrenflag, $userid){ + //TODO: $PREVDIRECTION NOT DEFINED YET + $prevdirection = null; + $seq = scorm_seq_flow_tree_traversal ($activity, $direction, $childrenflag, $prevdirection, $seq, $userid); + if($seq->nextactivity == null) { + $seq->nextactivity = $activity; + $seq->deliverable = false; + return $seq; + } else { + $activity = $seq->nextactivity; + $seq = scorm_seq_flow_activity_traversal($activity, $userid, $direction, $childrenflag, null, $seq, $userid); + return $seq; + } +} diff --git a/mod/scorm/datamodels/scormlib.php b/mod/scorm/datamodels/scormlib.php index 10c4555ea97..27faf2031f0 100644 --- a/mod/scorm/datamodels/scormlib.php +++ b/mod/scorm/datamodels/scormlib.php @@ -275,6 +275,17 @@ function scorm_get_manifest($blocks, $scoes) { $scoes->elements[$manifest][$parent->organization][$parent->identifier]->usecurrentattemptprogressinfo = $sequencing['attrs']['USECURRENTATTEMPTPROGRESSINFO'] == 'true'?1:0; } } + if ($sequencing['name'] == 'IMSSS:DELIVERYCONTROLS') { + if (isset($sequencing['attrs']['TRACKED'])) { + $scoes->elements[$manifest][$parent->organization][$parent->identifier]->tracked = $sequencing['attrs']['TRACKED'] == 'true'?1:0; + } + if (isset($sequencing['attrs']['COMPLETIONSETBYCONTENT'])) { + $scoes->elements[$manifest][$parent->organization][$parent->identifier]->completionsetbycontent = $sequencing['attrs']['COMPLETIONSETBYCONTENT'] == 'true'?1:0; + } + if (isset($sequencing['attrs']['OBJECTIVESETBYCONTENT'])) { + $scoes->elements[$manifest][$parent->organization][$parent->identifier]->objectivesetbycontent = $sequencing['attrs']['OBJECTIVESETBYCONTENT'] == 'true'?1:0; + } + } if ($sequencing['name']=='ADLSEQ:CONSTRAINEDCHOICECONSIDERATIONS') { if (isset($sequencing['attrs']['CONSTRAINCHOICE'])) { $scoes->elements[$manifest][$parent->organization][$parent->identifier]->constrainChoice = $sequencing['attrs']['CONSTRAINCHOICE'] == 'true'?1:0; @@ -564,6 +575,7 @@ function scorm_parse_scorm($scorm, $manifest) { $rulecond->ruleconditionsid = $ruleid; $rulecond->referencedobjective = $rulecondition->referencedobjective; $rulecond->measurethreshold = $rulecondition->measurethreshold; + $rulecond->operator = $rulecondition->operator; $rulecond->cond = $rulecondition->cond; $rulecondid = $DB->insert_record('scorm_seq_rulecond', $rulecond); } @@ -669,7 +681,7 @@ function scorm_optionals_data($item, $standarddata) { function scorm_is_leaf($sco) { global $DB; - if ($DB->get_record('scorm_scoes', array('scorm'=>$sco->scorm, 'parent'=>$sco->identifier))) { + if ($DB->get_records('scorm_scoes', array('scorm'=>$sco->scorm, 'parent'=>$sco->identifier))) { return false; } return true; @@ -695,16 +707,17 @@ function scorm_get_children($sco) { return null; } -function scorm_get_available_children($sco) { // TODO: undefined vars!!! +function scorm_get_available_children($sco) { global $DB; - $res = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid, - 'userid'=>$userid, - 'element'=>'availablechildren')); + $res = $DB->get_records('scorm_scoes', array('scorm'=>$sco->scorm, 'parent'=>$sco->identifier)); if (!$res || $res == null) { return false; } else { - return unserialize($res->value); + foreach ($res as $sco) { + $result[] = $sco; + } + return $result; } } @@ -752,16 +765,16 @@ function scorm_get_ancestors($sco) { return $ancestors; } -function scorm_get_preorder($preorder=array(), $sco) { +function scorm_get_preorder(&$preorder = array(), $sco = null) { if ($sco != null) { array_push($preorder, $sco); - $children = scorm_get_children($sco); - foreach ($children as $child) { - scorm_get_preorder($sco); + if ($children = scorm_get_children($sco)) { + foreach ($children as $child) { + scorm_get_preorder($preorder, $child); + } } - } else { - return $preorder; } + return $preorder; } function scorm_find_common_ancestor($ancestors, $sco) { diff --git a/mod/scorm/datamodels/sequencinghandler.php b/mod/scorm/datamodels/sequencinghandler.php new file mode 100644 index 00000000000..40acedb462f --- /dev/null +++ b/mod/scorm/datamodels/sequencinghandler.php @@ -0,0 +1,74 @@ +. + +require_once('../../../config.php'); +require_once($CFG->dirroot.'/mod/scorm/locallib.php'); + +$id = optional_param('id', '', PARAM_INT); // Course Module ID, or +$a = optional_param('a', '', PARAM_INT); // scorm ID +$scoid = required_param('scoid', PARAM_INT); // sco ID +$attempt = required_param('attempt', PARAM_INT); // attempt number +$function = required_param('function', PARAM_RAW); // function to call +$request = optional_param('request', '', PARAM_RAW); // scorm ID + +if (!empty($id)) { + if (! $cm = get_coursemodule_from_id('scorm', $id)) { + print_error('invalidcoursemodule'); + } + if (! $course = $DB->get_record("course", array("id"=>$cm->course))) { + print_error('coursemisconf'); + } + if (! $scorm = $DB->get_record("scorm", array("id"=>$cm->instance))) { + print_error('invalidcoursemodule'); + } +} else if (!empty($a)) { + if (! $scorm = $DB->get_record("scorm", array("id"=>$a))) { + print_error('invalidcoursemodule'); + } + if (! $course = $DB->get_record("course", array("id"=>$scorm->course))) { + print_error('coursemisconf'); + } + if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) { + print_error('invalidcoursemodule'); + } +} else { + print_error('missingparameter'); +} + +$PAGE->set_url('/mod/scorm/datamodels/sequencinghandler.php', array('scoid'=>$scoid, 'attempt'=>$attempt, 'id'=>$cm->id, 'function' => $function, 'request' => $request)); + +require_login($course, false, $cm); + +if (!empty($scoid) && !empty($function)) { + require_once($CFG->dirroot.'/mod/scorm/datamodels/scorm_13lib.php'); + + if (has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE, $cm->id))) { + $result = null; + switch ($function) { + case 'scorm_seq_flow' : + if ($request == 'forward' || $request == 'backward') { + $seq = scorm_seq_navigation ($scoid, $USER->id, $request.'_', $attempt); + $sco = scorm_get_sco($scoid); + $seq = scorm_seq_flow($sco, $request, $seq, true, $USER->id); + if (!empty($seq->nextactivity)) { + scorm_seq_end_attempt($sco, $USER->id, $seq); + } + } + echo json_encode($seq); + break; + } + } +} diff --git a/mod/scorm/datamodels/sequencinglib.php b/mod/scorm/datamodels/sequencinglib.php index 1eac805d4a8..75838cb3ae6 100644 --- a/mod/scorm/datamodels/sequencinglib.php +++ b/mod/scorm/datamodels/sequencinglib.php @@ -14,382 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . -require ($CFG->dirroot.'/mod/scorm/datamodels/scormlib.php'); - function scorm_seq_evaluate($scoid,$usertracks) { return true; } -function scorm_seq_overall ($scoid,$userid,$request,$attempt) { - $seq = scorm_seq_navigation($scoid,$userid,$request,$attempt); - if ($seq->navigation) { - if ($seq->termination != null) { - $seq = scorm_seq_termination($scoid,$userid,$seq); - } - if ($seq->sequencing != null) { - $seq = scorm_seq_sequencing($scoid,$userid,$seq); - if($seq->sequencing == 'exit'){//return the control to the LTS - return 'true'; - } - } - if ($seq->delivery != null) { - $seq = scorm_sequencing_delivery($scoid,$userid,$seq); - $seq = scorm_content_delivery_environment ($seq,$userid); - } - } - if ($seq->exception != null) { - $seq = scorm_sequencing_exception($seq); - } - return 'true'; -} - - -function scorm_seq_navigation ($scoid,$userid,$request,$attempt=0) { - global $DB; - - /// Sequencing structure - $seq = new stdClass(); - $seq->currentactivity = scorm_get_sco($scoid); - $seq->traversaldir = null; - $seq->nextactivity = null; - $seq->deliveryvalid = null; - $seq->attempt = $attempt; - - $seq->identifiedactivity = null; - $seq->delivery = null; - $seq->deliverable = false; - $seq->active = scorm_seq_is('active',$scoid,$userid); - $seq->suspended = scorm_seq_is('suspended',$scoid,$userid); - $seq->navigation = null; - $seq->termination = null; - $seq->sequencing = null; - $seq->target = null; - $seq->endsession = null; - $seq->exception = null; - $seq->reachable = true; - $seq->prevact = true; - - switch ($request) { - case 'start_': - if (empty($seq->currentactivity)) { - $seq->navigation = true; - $seq->sequencing = 'start'; - } else { - $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun - } - break; - case 'resumeall_': - if (empty($seq->currentactivity)) { - if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'element'=>'suspendedactivity'))) {//I think it's suspend instead of suspendedactivity - $seq->navigation = true; - $seq->sequencing = 'resumeall'; - } else { - $seq->exception = 'NB.2.1-3'; /// No suspended activity found - } - } else { - $seq->exception = 'NB.2.1-1'; /// Sequencing session already begun - } - break; - case 'continue_': - case 'previous_': - if (!empty($seq->currentactivity)) { - $sco = $seq->currentactivity; - if ($sco->parent != '/') { - if ($parentsco = scorm_get_parent($sco)) { - - if (isset($parentsco->flow) && ($parentsco->flow == true)) {//I think it's parentsco - // Current activity is active ! - if (scorm_seq_is('active',$sco->id,$userid)) { - if ($request == 'continue_') { - $seq->navigation = true; - $seq->termination = 'exit'; - $seq->sequencing = 'continue'; - } else { - if (!isset($parentsco->forwardonly) || ($parentsco->forwardonly == false)) { - $seq->navigation = true; - $seq->termination = 'exit'; - $seq->sequencing = 'previous'; - } else { - $seq->exception = 'NB.2.1-5'; /// Violates control mode - } - } - } - } - - } - } - } else { - $seq->exception = 'NB.2.1-2'; /// Current activity not defined - } - break; - case 'forward_': - case 'backward_': - $seq->exception = 'NB.2.1-7' ; /// None to be done, behavior not defined - break; - case 'exit_': - case 'abandon_': - if (!empty($seq->currentactivity)) { - // Current activity is active ! - $seq->navigation = true; - $seq->termination = substr($request,0,-1); - $seq->sequencing = 'exit'; - } else { - $seq->exception = 'NB.2.1-2'; /// Current activity not defined - } - case 'exitall_': - case 'abandonall_': - case 'suspendall_': - if (!empty($seq->currentactivity)) { - $seq->navigation = true; - $seq->termination = substr($request,0,-1); - $seq->sequencing = 'exit'; - } else { - $seq->exception = 'NB.2.1-2'; /// Current activity not defined - } - break; - default: /// {target=}choice - if ($targetsco = $DB->get_record('scorm_scoes', array('scorm'=>$sco->scorm,'identifier'=>$request))) { - if ($targetsco->parent != '/') { - $seq->target = $request; - } else { - if ($parentsco = scorm_get_parent($targetsco)) { - if (!isset($parentsco->choice) || ($parentsco->choice == true)) { - $seq->target = $request; - } - } - } - if ($seq->target != null) { - if (empty($seq->currentactivity)) { - $seq->navigation = true; - $seq->sequencing = 'choice'; - } else { - if (!$sco = scorm_get_sco($scoid)) { - return $seq; - } - if ($sco->parent != $targetsco->parent) { - $ancestors = scorm_get_ancestors($sco); - $commonpos = scorm_find_common_ancestor($ancestors,$targetsco); - if ($commonpos !== false) { - if ($activitypath = array_slice($ancestors,0,$commonpos)) { - foreach ($activitypath as $activity) { - if (scorm_seq_is('active',$activity->id,$userid) && (isset($activity->choiceexit) && ($activity->choiceexit == false))) { - $seq->navigation = false; - $seq->termination = null; - $seq->sequencing = null; - $seq->target = null; - $seq->exception = 'NB.2.1-8'; /// Violates control mode - return $seq; - } - } - } else { - $seq->navigation = false; - $seq->termination = null; - $seq->sequencing = null; - $seq->target = null; - $seq->exception = 'NB.2.1-9'; - } - } - } - // Current activity is active ! - $seq->navigation = true; - $seq->sequencing = 'choice'; - } - } else { - $seq->exception = 'NB.2.1-10'; /// Violates control mode - } - } else { - $seq->exception = 'NB.2.1-11'; /// Target activity does not exists - } - break; - } - return $seq; -} - -function scorm_seq_termination ($seq,$userid) { - if (empty($seq->currentactivity)) { - $seq->termination = false; - $seq->exception = 'TB.2.3-1'; - return $seq; - } - - $sco = $seq->currentactivity; - - if ((($seq->termination == 'exit') || ($seq->termination == 'abandon')) && !$seq->active) { - $seq->termination = false; - $seq->exception = 'TB.2.3-2'; - return $seq; - } - switch ($seq->termination) { - case 'exit': - scorm_seq_end_attempt($sco,$userid,$seq); - $seq = scorm_seq_exit_action_rules($seq,$userid); - do { - $exit = false;// I think this is false. Originally this was true - $seq = scorm_seq_post_cond_rules($seq,$userid); - if ($seq->termination == 'exitparent') { - if ($sco->parent != '/') { - $sco = scorm_get_parent($sco); - $seq->currentactivity = $sco; - $seq->active = scorm_seq_is('active',$sco->id,$userid); - scorm_seq_end_attempt($sco,$userid,$seq); - $exit = true;//I think it's true. Originally this was false - } else { - $seq->termination = false; - $seq->exception = 'TB.2.3-4'; - return $seq; - } - } - } while (($exit == false) && ($seq->termination == 'exit')); - if ($seq->termination == 'exit') { - $seq->termination = true; - return $seq; - } - case 'exitall': - if ($seq->active) { - scorm_seq_end_attempt($sco,$userid,$seq); - } - /// Terminate Descendent Attempts Process - - - if ($ancestors = scorm_get_ancestors($sco)) { - foreach ($ancestors as $ancestor) { - scorm_seq_end_attempt($ancestor,$userid,$seq); - $seq->currentactivity = $ancestor; - } - } - - $seq->active = scorm_seq_is('active',$seq->currentactivity->id,$userid); - $seq->termination = true; - $seq->sequencing = exit; - break; - case 'suspendall': - if (($seq->active) || ($seq->suspended)) { - scorm_seq_set('suspended',$sco->id,$userid); - } else { - if ($sco->parent != '/') { - $parentsco = scorm_get_parent($sco); - scorm_seq_set('suspended',$parentsco->id,$userid); - } else { - $seq->termination = false; - $seq->exception = 'TB.2.3-3'; - // return $seq; - } - } - if ($ancestors = scorm_get_ancestors($sco)) { - foreach ($ancestors as $ancestor) { - scorm_seq_set('active',$ancestor->id,$userid,false); - scorm_seq_set('suspended',$ancestor->id,$userid); - $seq->currentactivity = $ancestor; - } - $seq->termination = true; - $seq->sequencing = 'exit'; - } else { - $seq->termination = false; - $seq->exception = 'TB.2.3-5'; - } - break; - case 'abandon': - scorm_seq_set('active',$sco->id,$userid,false); - $seq->active = null; - $seq->termination = true; - break; - case 'abandonall': - if ($ancestors = scorm_get_ancestors($sco)) { - foreach ($ancestors as $ancestor) { - scorm_seq_set('active',$ancestor->id,$userid,false); - $seq->currentactivity = $ancestor; - } - $seq->termination = true; - $seq->sequencing = 'exit'; - } else { - $seq->termination = false; - $seq->exception = 'TB.2.3-6'; - } - break; - default: - $seq->termination = false; - $seq->exception = 'TB.2.3-7'; - break; - } - return $seq; -} - -function scorm_seq_end_attempt($sco,$userid,$seq) { - global $DB; - - if (scorm_is_leaf($sco)) { - if (!isset($sco->tracked) || ($sco->tracked == 1)) { - if (!scorm_seq_is('suspended',$sco->id,$userid)) { - if (!isset($sco->completionsetbycontent) || ($sco->completionsetbycontent == 0)) { - if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid,$seq->attempt)) { - // if (!scorm_seq_is('attemptprogressstatus',$sco->id,$userid)) { - scorm_seq_set('attemptprogressstatus',$sco->id,$userid); - scorm_seq_set('attemptcompletionstatus',$sco->id,$userid); - } - } - if (!isset($sco->objectivesetbycontent) || ($sco->objectivesetbycontent == 0)) { - if ($objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id))) { - foreach ($objectives as $objective) { - if ($objective->primaryobj) { - //if (!scorm_seq_objective_progress_status($sco,$userid,$objective)) { - if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) { - scorm_seq_set('objectiveprogressstatus',$sco->id,$userid); - scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid); - } - } - } - } - } - } - } - } else { - if ($children = scorm_get_children($sco)) { - $suspended = false; - foreach ($children as $child) { - if (scorm_seq_is('suspended',$child,$userid)) { - $suspended = true; - break; - } - } - if ($suspended) { - scorm_seq_set('suspended',$sco,$userid); - } else { - scorm_seq_set('suspended',$sco,$userid,false); - } - } - } - scorm_seq_set('active',$sco,$userid,0,false); - scorm_seq_overall_rollup($sco,$userid, $seq); -} - -function scorm_seq_is($what, $scoid, $userid, $attempt=0) { - global $DB; - - /// Check if passed activity $what is active - $active = false; - if ($track = $DB->get_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what))) { - $active = true; - } - return $active; -} - -function scorm_seq_set($what, $scoid, $userid, $attempt=0, $value='true') { - global $DB; - - $sco = scorm_get_sco($scoid); - - /// set passed activity to active or not - if ($value == false) { - $DB->delete_record('scorm_scoes_track', array('scoid'=>$scoid,'userid'=>$userid,'attempt'=>$attempt,'element'=>$what)); - } else { - scorm_insert_track($userid, $sco->scorm, $sco->id, 0, $what, $value); - } - - // update grades in gradebook - $scorm = $DB->get_record('scorm', array('id'=>$sco->scorm)); - scorm_update_grades($scorm, $userid, true); -} - function scorm_seq_exit_action_rules($seq,$userid) { $sco = $seq->currentactivity; $ancestors = scorm_get_ancestors($sco); @@ -439,415 +67,6 @@ function scorm_seq_post_cond_rules($seq,$userid) { return $seq; } -function scorm_seq_rules_check ($sco, $action){ - global $DB; - - $act = null; - if($rules = $DB->get_records('scorm_seq_ruleconds', array('scoid'=>$sco->id,'action'=>$action))) { - foreach ($rules as $rule){ - if($act = scorm_seq_rule_check($sco,$rule)){ - return $act; - } - } - } - return $act; - -} - -function scorm_seq_rule_check ($sco, $rule){ - global $DB; - - $bag = Array(); - $cond = ''; - $ruleconds = $DB->get_records('scorm_seq_rulecond', array('scoid'=>$sco->id,'ruleconditionsid'=>$rule->id)); - foreach ($ruleconds as $rulecond){ - if ($rulecond->operator = 'not') { - if ($rulecond->cond != 'unknown' ){ - $rulecond->cond = 'not'.$rulecond; - } - } - $bag [$rule->id] = $rulecond->cond; - - } - if (empty($bag)){ - $cond = 'unknown'; - return $cond; - } - - $size= sizeof($bag); - $i=0; - - if ($rule->conditioncombination = 'all'){ - foreach ($bag as $con){ - $cond = $cond.' and '.$con; - - } - } - else{ - foreach ($bag as $con){ - $cond = $cond.' or '.$con; - } - } - return $cond; -} - - -function scorm_seq_overall_rollup($sco,$userid, $seq){//Carlos - - if ($ancestors = scorm_get_ancestors($sco)) { - foreach ($ancestors as $ancestor) { - if(!scorm_is_leaf($ancestor)){ - scorm_seq_measure_rollup($sco,$userid); - } - scorm_seq_objective_rollup($sco,$userid); - scorm_seq_activity_progress_rollup($sco,$userid, $seq); - - } - - } -} - -/* For this next function I have defined measure weight and measure status as records with the attempt = 0 on the scorm_scoes_track table. According to the page 89 of the SeqNav.pdf those datas give us some information about the progress of the objective*/ - -function scorm_seq_measure_rollup($sco,$userid){ - global $DB; - - $totalmeasure = 0; //Check if there is something similar in the database - $valid = false;//Same as in the last line - $countedmeasures = 0;//Same too - $targetobjective = null; - $readable = true;//to check if status and measure weight are readable - $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id)); - - foreach ($objectives as $objective){ - - if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not - $targetobjective = $objective; - break; - } - - } - - if ($targetobjective != null){ - $children = scorm_get_children($sco); - foreach ($children as $child){ - $child = scorm_get_sco ($child); - if (!isset($child->tracked) || ($child->tracked == 1)){ - - $rolledupobjective = null;// we set the rolled up activity to undefined - $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$child->id)); - foreach ($objectives as $objective){ - if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not - $rolledupobjective = $objective; - break; - } - } - if ($rolledupobjective != null){ - $child = scorm_get_sco($child->id); - - $countedmeasures = $countedmeasures + ($child->measureweight); - if (!scorm_seq_is('objectivemeasurestatus',$sco->id,$userid)) { - $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure')); - $totalmeasure = $totalmeasure + (($normalizedmeasure->value) * ($child->measureweight)); - $valid = true; - } - - - - } - } - } - - - if(!$valid){ - - scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false); - - } - else{ - if($countedmeasures>0){ - scorm_seq_set('objectivemeasurestatus',$sco->id,$userid); - $val=$totalmeasure/$countedmeasures; - scorm_seq_set('objectivenormalizedmeasure',$sco->id,$userid,$val); - - } - else{ - scorm_seq_set('objectivemeasurestatus',$sco->id,$userid,false); - - } - } - - } - -} - -function scorm_seq_objective_rollup($sco,$userid){ - global $DB; - - scorm_seq_objective_rollup_measure($sco,$userid); - scorm_seq_objective_rollup_rules($sco,$userid); - scorm_seq_objective_rollup_default($sco,$userid); - -/* - if($targetobjective->satisfiedbymeasure){ - scorm_seq_objective_rollup_measure($sco,$userid); - } - else{ - if ((scorm_seq_rollup_rule_check($sco,$userid,'incomplete'))|| (scorm_seq_rollup_rule_check($sco,$userid,'completed'))){ - scorm_seq_objective_rollup_rules($sco,$userid); - } - else{ - - $rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid)); - foreach($rolluprules as $rolluprule){ - $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id)); - foreach($rollupruleconds as $rolluprulecond){ - - switch ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){ - - scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false); - - break; - } - } - - - } - } -*/ -} - -function scorm_seq_objective_rollup_measure($sco,$userid){ - global $DB; - - $targetobjective = null; - - - $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id)); - foreach ($objectives as $objective){ - if ($objective->primaryobj == true){ - $targetobjective = $objective; - break; - } - } - if ($targetobjective != null){ - - if($targetobjective->satisfiedbymeasure){ - - - if (!scorm_seq_is('objectiveprogressstatus',$sco->id,$userid)) { - - scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false); - - } - - else{ - if (scorm_seq_is('active',$sco->id,$userid)) { - $isactive = true; - } - else{ - $isactive = false; - } - - $normalizedmeasure = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivenormalizedmeasure')); - - $sco = scorm_get_sco ($sco->id); - - if (!$isactive || ($isactive && (!isset($sco->measuresatisfactionifactive) || $sco->measuresatisfactionifactive == true))){ - if($normalizedmeasure->value >= $targetobjective->minnormalizedmeasure){ - scorm_seq_set('objectiveprogressstatus',$sco->id,$userid); - scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid); - } - else{ - scorm_seq_set('objectiveprogressstatus',$sco->id,$userid); - scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false); - } - } - else{ - - scorm_seq_set('objectiveprogressstatus',$sco->id,$userid,false); - - } - } - } - } - -} - -function scorm_seq_objective_rollup_default($sco,$userid){ - global $DB; - - if (!(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')) && !(scorm_seq_rollup_rule_check($sco,$userid,'completed'))){ - - $rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid)); - foreach($rolluprules as $rolluprule){ - $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id)); - foreach($rollupruleconds as $rolluprulecond){ - - if ($rolluprulecond->cond!='satisfied' && $rolluprulecond->cond!='completed' && $rolluprulecond->cond!='attempted'){ - - scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid, false); - - break; - } - } - - - } - } - -} - - -function scorm_seq_objective_rollup_rules($sco,$userid){ - global $DB; - - $targetobjective = null; - - $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$sco->id)); - foreach ($objectives as $objective){ - if ($objective->primaryobj == true){//Objective contributes to rollup I'm using primaryobj field, but not - $targetobjective = $objective; - break; - } - } - if ($targetobjective != null){ - - - - if(scorm_seq_rollup_rule_check($sco,$userid,'notsatisfied')){//with not satisfied rollup for the activity - - - scorm_seq_set('objectiveprogressstatus',$sco->id,$userid); - scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid,false); - } - if(scorm_seq_rollup_rule_check($sco,$userid,'satisfied')){//with satisfied rollup for the activity - scorm_seq_set('objectiveprogressstatus',$sco->id,$userid); - scorm_seq_set('objectivesatisfiedstatus',$sco->id,$userid); - } - - } - -} - -function scorm_seq_activity_progress_rollup ($sco, $userid, $seq){ - - if(scorm_seq_rollup_rule_check($sco,$userid,'incomplete')){ - //incomplete rollup action - scorm_seq_set('attemptcompletionstatus',$sco->id,$userid,false,$seq->attempt); - scorm_seq_set('attemptprogressstatus',$sco->id,$userid,true,$seq->attempt); - - } - if(scorm_seq_rollup_rule_check($sco,$userid,'completed')){ - //incomplete rollup action - scorm_seq_set('attemptcompletionstatus',$sco->id,true,$userid); - scorm_seq_set('attemptprogressstatus',$sco->id,true,$userid); - } - -} - -function scorm_seq_rollup_rule_check ($sco,$userid,$action){ - global $DB; - - if($rolluprules = $DB->get_record('scorm_seq_rolluprule', array('scoid'=>$sco->id,'userid'=>$userid,'action'=>$action))) { - - $childrenbag = Array (); - $children = scorm_get_children ($sco); - - foreach($rolluprules as $rolluprule){ - - foreach ($children as $child){ - - /*$tracked = $DB->get_records('scorm_scoes_track', array('scoid'=>$child->id,'userid'=>$userid)); - if($tracked && $tracked->attemp != 0){*/ - $child = scorm_get_sco ($child); - if (!isset($child->tracked) || ($child->tracked == 1)){ - - if(scorm_seq_check_child ($child,$action,$userid)){ - - $rollupruleconds = $DB->get_records('scorm_seq_rolluprulecond', array('rollupruleid'=>$rolluprule->id)); - $evaluate = scorm_seq_evaluate_rollupcond($child,$rolluprule->conditioncombination,$rollupruleconds,$userid); - if ($evaluate=='unknown'){ - array_push($childrenbag,'unknown'); - } - else{ - if($evaluate == true){ - array_push($childrenbag,true); - } - else{ - array_push($childrenbag,false); - } - } - } - } - - } - $change = false; - - switch ($rolluprule->childactivityset){ - - case 'all': - if((array_search(false,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR - $change = true; - } - break; - - case 'any': - if(array_search(true,$childrenbag)!==false){//I think I can use this condition instead equivalent to OR - $change = true; - } - break; - - case 'none': - if((array_search(true,$childrenbag)===false)&&(array_search('unknown',$childrenbag)===false)){//I think I can use this condition instead equivalent to OR - $change = true; - } - break; - - case 'atleastcount': - foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR - $cont = 0; - if($itm === true){ - $cont++; - } - if($cont >= $rolluprule->minimumcount){ - $change = true; - } - } - break; - - case 'atleastcount': - foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR - $cont = 0; - if($itm === true){ - $cont++; - } - if($cont >= $rolluprule->minimumcount){ - $change = true; - } - } - break; - - case 'atleastpercent': - foreach ($childrenbag as $itm){//I think I can use this condition instead equivalent to OR - $cont = 0; - if($itm === true){ - $cont++; - } - if(($cont/sizeof($childrenbag)) >= $rolluprule->minimumcount){ - $change = true; - } - } - break; - } - if ($change==true){ - return true; - } - } - } - return false; -} - function scorm_seq_evaluate_rollupcond($sco,$conditioncombination,$rollupruleconds,$userid){ $bag = Array(); @@ -914,114 +133,6 @@ function scorm_seq_evaluate_rollupcond($sco,$conditioncombination,$rolluprulecon } -function scorm_evaluate_condition ($rolluprulecond,$sco,$userid){ - global $DB; - - $res = false; - - switch ($rolluprulecond->cond){ - - case 'satisfied': - if($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivesatisfiedstatus'))) { - if($r->value == true){ - if ($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus'))) { - if($r->value == true){ - $res= true; - } - } - } - } - break; - - case 'objectiveStatusKnown': - if ($r=$DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectiveprogressstatus'))) { - if($r->value == true){ - $res= true; - } - } - break; - - case 'objectiveMeasureKnown': - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'objectivemeasurestatus'))) { - if($r->value == true){ - $res = true; - } - - } - - break; - - case 'completed': - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptcompletionstatus'))) { - if($r->value){ - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus'))) { - if($r->value){ - $res = true; - } - - } - } - - } - break; - - case 'attempted': - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) { - if($r->value){ - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount'))) { - if($r->value > 0){ - $res = true; - } - - } - } - - } - break; - - - case 'attemptLimitExceeded': - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) { - if($r->value){ - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'limitconditionattemptlimitcontrol'))) { - if($r->value){ - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityattemptcount')) && $r2 = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'limitconditionattemptlimit')) ){ - if($r->value >= $r2->value){ - $res = true; - } - - } - - } - - } - - } - - } - - break; - - case 'activityProgressKnown': - - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'activityprogressstatus'))) { - if($r->value){ - if ($r = $DB->get_record('scorm_scoes_track', array('scoid'=>$sco->id,'userid'=>$userid,'element'=>'attemptprogressstatus'))) { - if($r->value){ - $res = true; - } - - } - - } - - } - - break; - } - return $res; - -} function scorm_seq_check_child ($sco, $action, $userid){ global $DB; @@ -1273,7 +384,6 @@ function scorm_seq_exit_sequencing($scoid,$userid,$seq){ return $seq; } - function scorm_seq_retry_sequencing($scoid,$userid,$seq){ if (empty($seq->currentactivity)) { $seq->delivery = null; @@ -1305,309 +415,6 @@ function scorm_seq_retry_sequencing($scoid,$userid,$seq){ } -function scorm_seq_flow ($candidate,$direction,$seq,$childrenflag,$userid){ - //TODO: $PREVDIRECTION NOT DEFINED YET - - $activity=$candidate; - $prevdirection = null; - $seq = scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid); - if($seq->identifiedactivity == null){//if identifies - $seq->identifiedactivity = $candidate; - $seq->deliverable = false; - return $seq; - } - else{ - $activity = $seq->identifiedactivity; - $seq = scorm_seq_flow_activity_traversal($activity,$userid,$direction,$childrenflag,$prevdirection,$seq,$userid);// - return $seq; - - } -} - -function scorm_seq_flow_activity_traversal ($activity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid){//returns the next activity on the tree, traversal direction, control returned to the LTS, (may) exception - $activity = scorm_get_sco ($activity); - $parent = scorm_get_parent ($activity); - if (!isset($parent->flow) || ($parent->flow == false)) { - $seq->deliverable = false; - $seq->exception = 'SB.2.2-1'; - $seq->nextactivity = $activity; - return $seq; - } - - $rulch = scorm_seq_rules_check($sco, 'skipped'); // TODO: undefined - if ($rulch != null){ - $seq = scorm_seq_flow_tree_traversal ($activity, $direction, false, $prevdirection, $seq,$userid);//endsession and exception - if ($seq->identifiedactivity == null){ - $seq->deliverable = false; - $seq->nextactivity = $activity; - return $seq; - } - else{ - - if ($prevdirection = 'backward' && $seq->traversaldir == 'backward'){ - $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid); - $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid); - } - else{ - $seq = scorm_seq_flow_tree_traversal ($activity,$direction,false,null,$seq,$userid); - $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, $prevdirection, $seq,$userid); - } - return $seq; - } - } - - $ch=scorm_check_activity ($activity,$userid); - - if ($ch){ - - $seq->deliverable = false; - $seq->exception = 'SB.2.2-2'; - $seq->nextactivity = $activity; - return $seq; - - } - - if (!scorm_is_leaf($activity)){ - - $seq = scorm_seq_flow_tree_traversal ($activity,$direction,true,null,$seq,$userid); - - if ($seq->identifiedactivity == null){ - $seq->deliverable = false; - $seq->nextactivity = $activity; - return $seq; - } - - else{ - if($direction == 'backward' && $seq->traversaldir == 'forward'){ - $seq = scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, 'forward', $childrenflag, 'backward', $seq,$userid); - } - else{ - scorm_seq_flow_activity_traversal($seq->identifiedactivity, $userid, $direction, $childrenflag, null, $seq,$userid); - } - return $seq; - } - - } - - $seq->deliverable = true; - $seq->nextactivity = $activity; - return $seq; - -} -function scorm_seq_flow_tree_traversal ($activity,$direction,$childrenflag,$prevdirection,$seq,$userid){ - - $revdirection = false; - $parent = scorm_get_parent ($activity); - $children = scorm_get_available_children ($parent); - $siz = sizeof ($children); - - if (($prevdirection != null && $prevdirection == 'backward') && ($children[$siz-1]->id == $activity->id)){ - $direction = 'backward'; - $children[0] = $activity; - $revdirection = true; - } - - if($direction = 'forward'){ - $ancestors = scorm_get_ancestors($activity); - $ancestorsroot = array_reverse($ancestors); - $preorder = scorm_get_preorder ($ancestorsroot); - $siz= sizeof ($preorder); - if (($activity->id == $preorder[$siz-1]->id) || (($activity->parent == '/') && !($childrenflag))){ - scorm_seq_terminate_descent($ancestorsroot,$userid); - $seq->endsession = true; - $seq->nextactivity = null; - return $seq; - } - if (scorm_is_leaf ($activity) || !$childrenflag){ - if ($children[$siz-1]->id == $activity->id){ - - $seq = scorm_seq_flow_tree_traversal ($parent, $direction, false, null, $seq,$userid); - // I think it's not necessary to do a return in here - } - else{ - $parent = scorm_get_parent($activity); - $children = scorm_get_available_children($parent); - $seq->traversaldir = $direction; - $sib = scorm_get_siblings($activity); - $pos = array_search($sib, $activity); - if ($pos !== false) { - if ($pos != sizeof ($sib)){ - $seq->nextactivity = $sib [$pos+1]; - return $seq; - } - else{ - $ch = scorm_get_children($sib[0]); - $seq->nextactivity = $ch[0]; - return $seq; - } - } - } - } - else{ - if (!empty ($children)){ - $seq->traversaldir = $direction; - $seq->nextactivity = $children[0]; - return $seq; - } - else{ - $seq->traversaldir = null; - $seq->nextactivity = $children[0]; - $seq->exception = 'SB.2.1-2'; - return $seq; - } - } - - } - if($direction = 'backward'){ - - if ($activity->parent == '/'){ - $seq->traversaldir = null; - $seq->nextactivity = null; - $seq->exception = 'SB.2.1-3'; - return $seq; - } - if (scorm_is_leaf ($activity) || !$childrenflag){ - if (!$revdirection){ - if (isset($parent->forwardonly) && ($parent->forwardonly == true)) { - $seq->traversaldir = null; - $seq->nextactivity = null; - $seq->exception = 'SB.2.1-4'; - return $seq; - } - } - if ($children[0]->id == $activity->id){ - $seq = scorm_seq_flow_tree_traversal ($parent, 'backward', false, null, $seq, $userid); - return $seq; - } - else{ - $ancestors = scorm_get_ancestors($activity); - $ancestorsroot = array_reverse ($ancestors); - $preorder = scorm_get_preorder ($ancestorsroot); - $pos = array_search($preorder, $children[$siz]); - $preord = array_slice($preorder, 0, $pos-1); - $revpreorder = array_reverse($preord); - $position = array_search($revpreorder, $activity); - $seq->nextactivity = $revpreorder[$pos+1]; - $seq->traversaldir = $direction; - return $seq; - } - } - else{ - if (!empty($children)){ - $activity = scorm_get_sco($activity->id); - if (isset($parent->flow) && ($parent->flow == true)) { - $children = scorm_get_children ($activity); - $seq->traversaldir = 'forward'; - $seq->nextactivity = $children[0]; - return $seq; - - } - else{ - $children = scorm_get_children ($activity); - $seq->traversaldir = 'backward'; - $seq->nextactivity = $children[sizeof($children)-1]; - return $seq; - } - - } - else{ - - $seq->traversaldir = null; - $seq->nextactivity = null; - $seq->exception = 'SB.2.1-2'; - return $seq; - } - } - - } - - -} -function scorm_check_activity ($activity,$userid){ - $act = scorm_seq_rules_check($activity,'disabled'); - if ($act != null){ - return true; - } - if(scorm_limit_cond_check ($activity,$userid)){ - return true; - } - return false; - - -} - -function scorm_limit_cond_check ($activity,$userid){ - global $DB; - - if (isset($activity->tracked) && ($activity->tracked == 0)){ - - return false; - } - - if (scorm_seq_is('active',$activity->id,$userid) || scorm_seq_is('suspended',$activity->id,$userid)){ - return false; - } - - if (!isset($activity->limitcontrol) || ($activity->limitcontrol == 1)){ - $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityattemptcount')); - if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattempt)){ - return true; - } - } - - if (!isset($activity->limitabsdurcontrol) || ($activity->limitabsdurcontrol == 1)){ - $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityabsoluteduration')); - if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitabsduration)){ - return true; - } - } - - if (!isset($activity->limitexpdurcontrol) || ($activity->limitexpdurcontrol == 1)){ - $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'activityexperiencedduration')); - if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitexpduration)){ - return true; - } - } - - if (!isset($activity->limitattabsdurcontrol) || ($activity->limitattabsdurcontrol == 1)){ - $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptabsoluteduration')); - if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattabsduration)){ - return true; - } - } - - if (!isset($activity->limitattexpdurcontrol) || ($activity->limitattexpdurcontrol == 1)){ - $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'attemptexperiencedduration')); - if (scorm_seq_is('activityprogressstatus',$activity->id,$userid) && ($r->value >=$activity->limitattexpduration)){ - return true; - } - } - - if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){ - $r = $DB->get_record('scorm_scoes_track', array('scoid'=>$activity->id,'userid'=>$userid,'element'=>'begintime')); - if (time()>=$activity->limitbegintime){ - return true; - } - } - - if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)){ - if (time()<$activity->limitbegintime){ - return true; - } - } - - if (!isset($activity->limitendcontrol) || ($activity->limitendcontrol == 1)){ - - if (time()>$activity->limitendtime){ - return true; - } - } - return false; - - -} - - function scorm_seq_choice_sequencing($sco,$userid,$seq){ $avchildren = Array (); @@ -2382,8 +1189,3 @@ function scorm_sequencing_exception($seq){ } } - - - - - diff --git a/mod/scorm/loaddatamodel.php b/mod/scorm/loaddatamodel.php index d6e2ebccbe4..931e6246d0a 100644 --- a/mod/scorm/loaddatamodel.php +++ b/mod/scorm/loaddatamodel.php @@ -85,7 +85,17 @@ if (!$sco = scorm_get_sco($scoid)) { print_error('cannotfindsco', 'scorm'); } if (scorm_version_check($scorm->version, SCORM_13)) { - $userdata->{'cmi.scaled_passing_score'} = $DB->get_field('scorm_seq_objective', 'minnormalizedmeasure', array('scoid'=>$scoid)); + $objectives = $DB->get_records('scorm_seq_objective', array('scoid'=>$scoid)); + $index = 0; + foreach ($objectives as $objective) { + if (!empty($objective->minnormalizedmeasure)) { + $userdata->{'cmi.scaled_passing_score'} = $objective->minnormalizedmeasure; + } + if (!empty($objective->objectiveid)) { + $userdata->{'cmi.objectives.N'.$index.'.id'} = $objective->objectiveid; + $index++; + } + } } header('Content-Type: text/javascript; charset=UTF-8'); diff --git a/mod/scorm/locallib.php b/mod/scorm/locallib.php index c8277782959..87e7c425153 100644 --- a/mod/scorm/locallib.php +++ b/mod/scorm/locallib.php @@ -417,6 +417,58 @@ function scorm_insert_track($userid, $scormid, $scoid, $attempt, $element, $valu } } } + if (($element == 'cmi.success_status') && ($value == 'passed' || $value == 'failed')) { + if ($DB->get_record('scorm_scoes_data', array('scoid'=>$scoid, 'name'=>'objectivesetbycontent'))) { + $objectiveprogressstatus = true; + $objectivesatisfiedstatus = false; + if ($value == 'passed') { + $objectivesatisfiedstatus = true; + } + + if ($track = $DB->get_record('scorm_scoes_track', array('userid'=>$userid, 'scormid'=>$scormid, 'scoid'=>$scoid, 'attempt'=>$attempt, 'element'=>'objectiveprogressstatus'))) { + $track->value = $objectiveprogressstatus; + $track->timemodified = time(); + $DB->update_record('scorm_scoes_track', $track); + $id = $track->id; + } else { + $track = new stdClass(); + $track->userid = $userid; + $track->scormid = $scormid; + $track->scoid = $scoid; + $track->attempt = $attempt; + $track->element = 'objectiveprogressstatus'; + $track->value = $objectiveprogressstatus; + $track->timemodified = time(); + $id = $DB->insert_record('scorm_scoes_track', $track); + } + if ($objectivesatisfiedstatus) { + if ($track = $DB->get_record('scorm_scoes_track', array('userid'=>$userid, 'scormid'=>$scormid, 'scoid'=>$scoid, 'attempt'=>$attempt, 'element'=>'objectivesatisfiedstatus'))) { + $track->value = $objectivesatisfiedstatus; + $track->timemodified = time(); + $DB->update_record('scorm_scoes_track', $track); + $id = $track->id; + } else { + $track = new stdClass(); + $track->userid = $userid; + $track->scormid = $scormid; + $track->scoid = $scoid; + $track->attempt = $attempt; + $track->element = 'objectivesatisfiedstatus'; + $track->value = $objectivesatisfiedstatus; + $track->timemodified = time(); + $id = $DB->insert_record('scorm_scoes_track', $track); + ob_start(); + $filepath = $CFG->dataroot."\\temp\\tempfile.txt"; + $fh = fopen($filepath, "a+"); + var_dump($track); + $string = ob_get_clean(); + fwrite($fh, $string); + fclose($fh); + } + } + } + } + } if ($track = $DB->get_record('scorm_scoes_track', array('userid'=>$userid, 'scormid'=>$scormid, 'scoid'=>$scoid, 'attempt'=>$attempt, 'element'=>$element))) { @@ -479,7 +531,6 @@ function scorm_get_tracks($scoid, $userid, $attempt='') { // Defined in order to unify scorm1.2 and scorm2004 $usertrack->score_raw = ''; $usertrack->status = ''; - $usertrack->progress = ''; $usertrack->total_time = '00:00:00'; $usertrack->session_time = '00:00:00'; $usertrack->timemodified = 0; @@ -493,35 +544,19 @@ function scorm_get_tracks($scoid, $userid, $attempt='') { $track->value = 'notattempted'; } $usertrack->status = $track->value; - break; - case 'cmi.success_status': - $usertrack->progress = $track->value; - break; - case 'cmi.progress_measure': - if (!empty($track->value) && (empty($usertrack->progress) || $usertrack->progress == 'unknown') ) { - $usertrack->progress = $track->value; - } - break; + break; case 'cmi.core.score.raw': case 'cmi.score.raw': $usertrack->score_raw = (float) sprintf('%2.2f', $track->value); - break; - case 'cmi.core.score.max': - case 'cmi.score.max': - $usertrack->score_max = (float) sprintf('%2.2f', $track->value); - break; - case 'cmi.core.score.min': - case 'cmi.score.min': - $usertrack->score_min = (float) sprintf('%2.2f', $track->value); - break; + break; case 'cmi.core.session_time': case 'cmi.session_time': $usertrack->session_time = $track->value; - break; + break; case 'cmi.core.total_time': case 'cmi.total_time': $usertrack->total_time = $track->value; - break; + break; } if (isset($track->timemodified) && ($track->timemodified > $usertrack->timemodified)) { $usertrack->timemodified = $track->timemodified; @@ -1330,7 +1365,7 @@ function scorm_format_duration($duration) { return $result; } -function scorm_get_toc($user,$scorm,$cmid,$toclink=TOCJSLINK,$currentorg='',$scoid='',$mode='normal',$attempt='',$play=false, $tocheader=false) { +function scorm_get_toc_object($user, $scorm, $currentorg='', $scoid='', $mode='normal', $attempt='', $play=false, $organizationsco=null) { global $CFG, $DB, $PAGE, $OUTPUT; $modestr = ''; @@ -1338,47 +1373,22 @@ function scorm_get_toc($user,$scorm,$cmid,$toclink=TOCJSLINK,$currentorg='',$sco $modestr = '&mode='.$mode; } - $result = new stdClass(); - if ($tocheader) { - $result->toc = '
'; - $result->toc .= '
'; - $result->toc .= '
'; - } - $result->toc .= '
    '; - $tocmenus = array(); - $result->prerequisites = true; + $result = array(); $incomplete = false; - // - // Get the current organization infos - // - if (!empty($currentorg)) { - if (($organizationtitle = $DB->get_field('scorm_scoes','title', array('scorm'=>$scorm->id,'identifier'=>$currentorg))) != '') { - if ($play) { - $result->toctitle = "$organizationtitle"; - } - else { - $result->toc .= "\t
  • $organizationtitle
  • \n"; - } - $tocmenus[] = $organizationtitle; - } + if (!empty($organizationsco)) { + $result[0] = $organizationsco; + $result[0]->isvisible = true; + $result[0]->statusicon = ''; + $result[0]->url = ''; } - // - // If not specified retrieve the last attempt number - // - if (empty($attempt)) { - $attempt = scorm_get_attempt_count($user->id, $scorm); - } - $result->attemptleft = $scorm->maxattempt == 0 ? 1 : $scorm->maxattempt - $attempt; if ($scoes = scorm_get_scoes($scorm->id, $currentorg)){ - // - // Retrieve user tracking data for each learning object - // + // Retrieve user tracking data for each learning object. $usertracks = array(); foreach ($scoes as $sco) { if (!empty($sco->launch)) { - if ($usertrack = scorm_get_tracks($sco->id,$user->id,$attempt)) { + if ($usertrack = scorm_get_tracks($sco->id,$user->id, $attempt)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } @@ -1386,80 +1396,36 @@ function scorm_get_toc($user,$scorm,$cmid,$toclink=TOCJSLINK,$currentorg='',$sco } } } + foreach ($scoes as $sco) { + if (!isset($sco->isvisible)) { + $sco->isvisible = true; + } - $level=0; - $sublist=1; - $previd = 0; - $nextid = 0; - $findnext = false; - $parents[$level]='/'; - $prevsco = ''; - foreach ($scoes as $pos => $sco) { - $isvisible = false; - $sco->title = $sco->title; - if (!isset($sco->isvisible) || (isset($sco->isvisible) && ($sco->isvisible == 'true'))) { - $isvisible = true; - } - if ($parents[$level] != $sco->parent) { - $newlevel = array_search($sco->parent,$parents); - if ($newlevel !== false) { - for ($i=0; $i<($level-$newlevel); $i++) { - $result->toc .= "\t\t
\n"; - } - $level = $newlevel; - } else { - $i = $level; - $closelist = ''; - while (($i > 0) && ($parents[$level] != $sco->parent)) { - if ($i === 1 && $level > 1) { - $closelist .= "\t\t\n"; - } else { - $closelist .= "\t\n"; - } - $i--; - } - if (($i == 0) && ($sco->parent != $currentorg)) { - $result->toc .= "\n\t
    \n"; - $level++; - } else { - $result->toc .= $closelist; - $level = $i; - } - $parents[$level] = $sco->parent; - } - } - if ($isvisible) { - $result->toc .= "
  • "; - } - if (isset($scoes[$pos+1])) { - $nextsco = $scoes[$pos+1]; - } else { - $nextsco = false; - } - $nextisvisible = false; - if (($nextsco !== false) && (!isset($nextsco->isvisible) || (isset($nextsco->isvisible) && ($nextsco->isvisible == 'true')))) { - $nextisvisible = true; - } - if ($nextisvisible && ($nextsco !== false) && ($sco->parent != $nextsco->parent) && - (($level==0) || (($level>0) && ($nextsco->parent == $sco->identifier)))) { - $sublist++; - } if (empty($sco->title)) { $sco->title = $sco->identifier; } - if ($isvisible) { + + if (scorm_version_check($scorm->version, SCORM_13)) { + require_once($CFG->dirroot.'/mod/scorm/datamodels/sequencinglib.php'); + $sco->prereq = scorm_seq_evaluate($sco->id, $usertracks); + } else { + $sco->prereq = empty($sco->prerequisites) || scorm_eval_prerequisites($sco->prerequisites, $usertracks); + } + + if ($sco->isvisible) { if (!empty($sco->launch)) { - $score = ''; if (empty($scoid) && ($mode != 'normal')) { $scoid = $sco->id; } + if (isset($usertracks[$sco->identifier])) { $usertrack = $usertracks[$sco->identifier]; $strstatus = get_string($usertrack->status,'scorm'); + if ($sco->scormtype == 'sco') { $statusicon = ''.$strstatus.''; } else { - $statusicon = ''.get_string('assetlaunched','scorm').''; + $statusicon = ''.get_string('assetlaunched', 'scorm').''; } if (($usertrack->status == 'notattempted') || ($usertrack->status == 'incomplete') || ($usertrack->status == 'browsed')) { @@ -1468,114 +1434,422 @@ function scorm_get_toc($user,$scorm,$cmid,$toclink=TOCJSLINK,$currentorg='',$sco $scoid = $sco->id; } } - if ($usertrack->score_raw != '' && has_capability('mod/scorm:viewscores', context_module::instance($cmid))) { - $score = '('.get_string('score','scorm').': '.$usertrack->score_raw.')'; - } - $strsuspended = get_string('suspended','scorm'); + + $strsuspended = get_string('suspended', 'scorm'); + $exitvar = 'cmi.core.exit'; + if (scorm_version_check($scorm->version, SCORM_13)) { $exitvar = 'cmi.exit'; } + if ($incomplete && isset($usertrack->{$exitvar}) && ($usertrack->{$exitvar} == 'suspend')) { $statusicon = ''.$strstatus.' - '.$strsuspended.''; } + } else { if ($play && empty($scoid)) { $scoid = $sco->id; } - $incomplete = true; - if ($sco->scormtype == 'sco') { - $statusicon = ''.get_string('notattempted','scorm').''; - } else { - $statusicon = ''.get_string('asset','scorm').''; - } - } - if ($sco->id == $scoid) { - $findnext = true; - } - if (($nextid == 0) && (scorm_count_launchable($scorm->id,$currentorg) > 1) && ($nextsco!==false) && (!$findnext)) { - if (!empty($sco->launch)) { - $previd = $sco->id; - } - } - if (scorm_version_check($scorm->version, SCORM_13)) { - require_once($CFG->dirroot.'/mod/scorm/datamodels/sequencinglib.php'); - $prereq = scorm_seq_evaluate($sco->id,$usertracks); - } else { - //TODO: split check for sco->prerequisites only for AICC as I think that's the only case it's set. - $prereq = empty($sco->prerequisites) || scorm_eval_prerequisites($sco->prerequisites,$usertracks); - } - if ($prereq) { - if ($sco->id == $scoid) { - $result->prerequisites = true; - } - if (!empty($prevsco) && scorm_version_check($scorm->version, SCORM_13) && !empty($prevsco->hidecontinue)) { - $result->toc .= ''.$statusicon.' '.format_string($sco->title).''; - } else if ($toclink == TOCFULLURL) { //display toc with urls for structure page - $url = $CFG->wwwroot.'/mod/scorm/player.php?a='.$scorm->id.'&currentorg='.$currentorg.$modestr.'&scoid='.$sco->id; - $result->toc .= $statusicon.' '.format_string($sco->title).''.$score."\n"; - } else { //display toc for inside scorm player - if ($sco->launch) { - $link = 'a='.$scorm->id.'&scoid='.$sco->id.'¤torg='.$currentorg.$modestr.'&attempt='.$attempt; - $result->toc .= ''.$statusicon.' '.format_string($sco->title).' '.$score.''; - } else { - $result->toc .= ''.$statusicon.' '.format_string($sco->title).''; - } - } - $tocmenus[$sco->id] = scorm_repeater('−',$level) . '>' . format_string($sco->title); - } else { - if ($sco->id == $scoid) { - $result->prerequisites = false; - } - if ($play) { - // should be disabled - $result->toc .= ''.$statusicon.' '.format_string($sco->title).''; + $incomplete = true; + + if ($sco->scormtype == 'sco') { + $statusicon = ''.get_string('notattempted', 'scorm').''; } else { - $result->toc .= $statusicon.' '.format_string($sco->title)."\n"; + $statusicon = ''.get_string('asset', 'scorm').''; } } - } else { - $result->toc .= ' '.format_string($sco->title); - } - if (($nextsco === false) || $nextsco->parent == $sco->parent) { - $result->toc .= "
  • \n"; } } - if (($nextsco !== false) && ($nextid == 0) && ($findnext)) { - if (!empty($nextsco->launch)) { - $nextid = $nextsco->id; + + if (empty($statusicon)) { + $sco->statusicon = ''.get_string('notattempted', 'scorm').''; + } else { + $sco->statusicon = $statusicon; + } + + $sco->url = 'a='.$scorm->id.'&scoid='.$sco->id.'¤torg='.$currentorg.$modestr.'&attempt='.$attempt; + $sco->incomplete = $incomplete; + + if (!in_array($sco->id, array_keys($result))) { + $result[$sco->id] = $sco; + } + } + } + + // Get the parent scoes! + $result = scorm_get_toc_get_parent_child($result); + + // Be safe, prevent warnings from showing up while returning array + if (!isset($scoid)) { + $scoid = ''; + } + + return array('scoes' => $result, 'usertracks' => $usertracks, 'scoid' => $scoid); +} + +function scorm_get_toc_get_parent_child(&$result) { + $final = array(); + $level = 0; + $prevparent = '/'; + ksort($result); + + foreach ($result as $sco) { + if ($sco->parent == '/') { + $final[$level][$sco->identifier] = $sco; + $prevparent = $sco->identifier; + unset($result[$sco->id]); + } else { + if ($sco->parent == $prevparent) { + $final[$level][$sco->identifier] = $sco; + $prevparent = $sco->identifier; + unset($result[$sco->id]); + } else { + if (!empty($final[$level])) { + $found = false; + foreach ($final[$level] as $fin) { + if ($sco->parent == $fin->identifier) { + $found = true; + } + } + + if ($found) { + $final[$level][$sco->identifier] = $sco; + unset($result[$sco->id]); + $found = false; + } else { + $level++; + $final[$level][$sco->identifier] = $sco; + unset($result[$sco->id]); + } } } + } + } + + for ($i = 0; $i <= $level; $i++) { + $prevparent = ''; + foreach ($final[$i] as $ident => $sco) { + if (empty($prevparent)) { + $prevparent = $ident; + } + + if ($sco->parent == $prevparent) { + if (!isset($final[$i][$prevparent]->children)) { + $final[$i][$prevparent]->children = array(); + } + $final[$i][$prevparent]->children[] = $sco; + $prevparent = $ident; + } else { + $parent = false; + foreach ($final[$i] as $identifier => $scoobj) { + if ($identifier == $sco->parent) { + $parent = $identifier; + } + } + + if ($parent !== false) { + $final[$i][$parent]->children[] = $sco; + } + } + } + } + + $results = array(); + for ($i = 0; $i <= $level; $i++) { + $keys = array_keys($final[$i]); + $results[] = $final[$i][$keys[0]]; + } + + return $results; +} + +function scorm_format_toc_for_treeview($user, $scorm, $scoes, $usertracks, $cmid, $toclink=TOCJSLINK, $currentorg='', $attempt='', $play=false, $organizationsco=null, $children=false) { + global $CFG; + + $result = new stdClass(); + $result->prerequisites = true; + + if (!$children) { + $result->attemptleft = $scorm->maxattempt == 0 ? 1 : $scorm->maxattempt - $attempt; + } + + if (!$children) { + $result->toc = "
      \n"; + + if (!$play && !empty($organizationsco)) { + $result->toc .= "\t
    • ".$organizationsco->title."
    • \n"; + } + } + + $prevsco = ''; + if (!empty($scoes)) { + foreach ($scoes as $sco) { + $result->toc .= "\t
    • \n"; + $scoid = $sco->id; + + $sco->isvisible = true; + + if ($sco->isvisible) { + $score = ''; + + if (isset($usertracks[$sco->identifier])) { + $viewscore = has_capability('mod/scorm:viewscores', get_context_instance(CONTEXT_MODULE, $cmid)); + if (isset($usertracks[$sco->identifier]->score_raw) && $viewscore) { + if ($usertracks[$sco->identifier]->score_raw != '') { + $score = '('.get_string('score','scorm').': '.$usertracks[$sco->identifier]->score_raw.')'; + } + } + } + + if (!empty($sco->prereq)) { + if ($sco->id == $scoid) { + $result->prerequisites = true; + } + + if (!empty($prevsco) && scorm_version_check($scorm->version, SCORM_13) && !empty($prevsco->hidecontinue)) { + if ($sco->scormtype == 'sco') { + $result->toc .= ''.$sco->statusicon.' '.format_string($sco->title).''; + } else { + $result->toc .= ' '.format_string($sco->title).''; + } + } else if ($toclink == TOCFULLURL) { + $url = $CFG->wwwroot.'/mod/scorm/player.php?'.$sco->url; + if ($sco->scormtype == 'sco') { + $result->toc .= $sco->statusicon.' '.format_string($sco->title).''.$score."\n"; + } else { + $result->toc .= ' '.format_string($sco->title).''.$score."\n"; + } + } else { + if ($sco->launch) { + if ($sco->scormtype == 'sco') { + $result->toc .= ''.$sco->statusicon.' '.format_string($sco->title).' '.$score.''; + } else { + $result->toc .= ' '.format_string($sco->title).' '.$score.''; + } + } else { + if ($sco->scormtype == 'sco') { + $result->toc .= ''.$sco->statusicon.' '.format_string($sco->title).''; + } else { + $result->toc .= ' '.format_string($sco->title).''; + } + } + } + + } else { + if ($play) { + if ($sco->scormtype == 'sco') { + $result->toc .= ''.$sco->statusicon.' '.format_string($sco->title).''; + } else { + $result->toc .= ' '.format_string($sco->title).''; + } + } else { + if ($sco->scormtype == 'sco') { + $result->toc .= $sco->statusicon.' '.format_string($sco->title)."\n"; + } else { + $result->toc .= ' '.format_string($sco->title)."\n"; + } + } + } + + } else { + $result->toc .= "\t\t ".format_string($sco->title)."\n"; + } + + if (!empty($sco->children)) { + $result->toc .= "\n\t\t
        \n"; + $childresult = scorm_format_toc_for_treeview($user, $scorm, $sco->children, $usertracks, $cmid, $toclink, $currentorg, $attempt, $play, $organizationsco, true); + $result->toc .= $childresult->toc; + $result->toc .= "\t\t
      \n"; + $result->toc .= "\t
    • \n"; + } else { + $result->toc .= "\t\n"; + } $prevsco = $sco; } - for ($i=0;$i<$level;$i++) { - $result->toc .= "\t\t
    \n"; - } - - if ($play) { - // it is possible that $scoid is still not set, in this case we don't want an empty object - if ($scoid) { - $sco = scorm_get_sco($scoid); - } - $sco->previd = $previd; - $sco->nextid = $nextid; - $result->sco = $sco; - $result->incomplete = $incomplete; - } else { - $result->incomplete = $incomplete; - } - } - $result->toc .= '
'; - - // NEW IMS TOC - if ($tocheader) { - $result->toc .= '
'; - $result->toc .= '
'; + $result->incomplete = $sco->incomplete; } - $url = new moodle_url('/mod/scorm/player.php?a='.$scorm->id.'¤torg='.$currentorg.$modestr); - $result->tocmenu = $OUTPUT->single_select($url, 'scoid', $tocmenus, $sco->id, null, "tocmenu"); + if (!$children) { + $result->toc .= "\n"; + } return $result; } + +function scorm_format_toc_for_droplist($scorm, $scoes, $usertracks, $currentorg='', $organizationsco=null, $children=false, $level=0, $tocmenus=array()) { + if (!empty($scoes)) { + if (!empty($organizationsco) && !$children) { + $tocmenus[$organizationsco->id] = $organizationsco->title; + } + + $parents[$level]='/'; + foreach ($scoes as $sco) { + if ($parents[$level] != $sco->parent) { + if ($newlevel = array_search($sco->parent, $parents)) { + $level = $newlevel; + } else { + $i = $level; + while (($i > 0) && ($parents[$level] != $sco->parent)) { + $i--; + } + + if (($i == 0) && ($sco->parent != $currentorg)) { + $level++; + } else { + $level = $i; + } + + $parents[$level] = $sco->parent; + } + } + + if ($sco->prereq) { + if ($sco->scormtype == 'sco') { + $tocmenus[$sco->id] = scorm_repeater('−', $level) . '>' . format_string($sco->title); + } + } else { + if ($sco->scormtype == 'sco') { + $tocmenus[$sco->id] = scorm_repeater('−', $level) . '>' . format_string($sco->title); + } + } + + if (!empty($sco->children)) { + $tocmenus = scorm_format_toc_for_droplist($scorm, $sco->children, $usertracks, $currentorg, $organizationsco, true, $level, $tocmenus); + } + } + } + + return $tocmenus; +} + +function scorm_get_toc($user, $scorm, $cmid, $toclink=TOCJSLINK, $currentorg='', $scoid='', $mode='normal', $attempt='', $play=false, $tocheader=false) { + global $CFG, $DB, $OUTPUT; + + if (empty($attempt)) { + $attempt = scorm_get_attempt_count($user->id, $scorm); + } + + $result = new stdClass(); + $organizationsco = null; + + if ($tocheader) { + $result->toc = "
\n"; + $result->toc .= "
\n"; + $result->toc .= "
\n"; + } + + if (!empty($currentorg)) { + $organizationsco = $DB->get_record('scorm_scoes', array('scorm'=>$scorm->id, 'identifier'=>$currentorg)); + if (!empty($organizationsco->title)) { + if ($play) { + $result->toctitle = $organizationsco->title; + } + } + } + + $scoes = scorm_get_toc_object($user, $scorm, $currentorg, $scoid, $mode, $attempt, $play, $organizationsco); + + $treeview = scorm_format_toc_for_treeview($user, $scorm, $scoes['scoes'][0]->children, $scoes['usertracks'], $cmid, $toclink, $currentorg, $attempt, $play, $organizationsco, false); + + if ($tocheader) { + $result->toc .= $treeview->toc; + } else { + $result->toc = $treeview->toc; + } + + if (!empty($scoes['scoid'])) { + $scoid = $scoes['scoid']; + } + + if (empty($scoid)) { + $result->sco = $scoes['scoes'][0]->children; + } else { + $result->sco = scorm_get_sco($scoid); + } + + if ($scorm->hidetoc == SCORM_TOC_POPUP) { + $tocmenu = scorm_format_toc_for_droplist($scorm, $scoes['scoes'][0]->children, $scoes['usertracks'], $currentorg, $organizationsco); + + $modestr = ''; + if ($mode == 'browse') { + $modestr = '&mode='.$mode; + } + + $url = new moodle_url('/mod/scorm/player.php?a='.$scorm->id.'¤torg='.$currentorg.$modestr); + $result->tocmenu = $OUTPUT->single_select($url, 'scoid', $tocmenu, $result->sco->id, null, "tocmenu"); + } + + $result->prerequisites = $treeview->prerequisites; + $result->incomplete = $treeview->incomplete; + $result->attemptleft = $treeview->attemptleft; + + if ($tocheader) { + $result->toc .= "
\n"; + $result->toc .= "
\n"; + } + + return $result; +} + +function scorm_get_adlnav_json ($scoes, &$adlnav = array(), $parentscoid = null) { + if (is_object($scoes)) { + $sco = $scoes; + if (isset($sco->url)) { + $adlnav[$sco->id]['identifier'] = $sco->identifier; + $adlnav[$sco->id]['launch'] = $sco->launch; + $adlnav[$sco->id]['title'] = $sco->title; + $adlnav[$sco->id]['url'] = $sco->url; + $adlnav[$sco->id]['parent'] = $sco->parent; + if (isset($sco->choice)) { + $adlnav[$sco->id]['choice'] = $sco->choice; + } + if (isset($sco->flow)) { + $adlnav[$sco->id]['flow'] = $sco->flow; + } else if (isset($parentscoid) && isset($adlnav[$parentscoid]['flow'])) { + $adlnav[$sco->id]['flow'] = $adlnav[$parentscoid]['flow']; + } + if (isset($sco->isvisible)) { + $adlnav[$sco->id]['isvisible'] = $sco->isvisible; + } + if (isset($sco->parameters)) { + $adlnav[$sco->id]['parameters'] = $sco->parameters; + } + if (isset($sco->hidecontinue)) { + $adlnav[$sco->id]['hidecontinue'] = $sco->hidecontinue; + } + if (isset($sco->hideprevious)) { + $adlnav[$sco->id]['hideprevious'] = $sco->hideprevious; + } + if (isset($sco->hidesuspendall)) { + $adlnav[$sco->id]['hidesuspendall'] = $sco->hidesuspendall; + } + if (!empty($parentscoid)) { + $adlnav[$sco->id]['parentscoid'] = $parentscoid; + } + if (isset($adlnav['prevscoid'])) { + $adlnav[$sco->id]['prevscoid'] = $adlnav['prevscoid']; + $adlnav[$adlnav['prevscoid']]['nextscoid'] = $sco->id; + if (isset($adlnav['prevparent']) && $adlnav['prevparent'] == $sco->parent) { + $adlnav[$sco->id]['prevsibling'] = $adlnav['prevscoid']; + $adlnav[$adlnav['prevscoid']]['nextsibling'] = $sco->id; + } + } + $adlnav['prevscoid'] = $sco->id; + $adlnav['prevparent'] = $sco->parent; + } + if (isset($sco->children)) { + foreach ($sco->children as $children) { + scorm_get_adlnav_json($children, $adlnav, $sco->id); + } + } + } else { + foreach ($scoes as $sco) { + scorm_get_adlnav_json ($sco, $adlnav); + } + unset($adlnav['prevscoid']); + unset($adlnav['prevparent']); + } + return json_encode($adlnav); +} diff --git a/mod/scorm/module.js b/mod/scorm/module.js index 0b2f2b7cbe5..9b63673d7cc 100644 --- a/mod/scorm/module.js +++ b/mod/scorm/module.js @@ -21,13 +21,13 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -mod_scorm_next = null; -mod_scorm_prev = null; +mod_scorm_launch_next_sco = null; +mod_scorm_launch_prev_sco = null; mod_scorm_activate_item = null; M.mod_scorm = {}; -M.mod_scorm.init = function(Y, hide_nav, hide_toc, toc_title, window_name, launch_sco) { +M.mod_scorm.init = function(Y, hide_nav, hide_toc, toc_title, window_name, launch_sco, scoes_nav) { var scorm_disable_toc = false; var scorm_hide_nav = true; var scorm_hide_toc = true; @@ -40,6 +40,7 @@ M.mod_scorm.init = function(Y, hide_nav, hide_toc, toc_title, window_name, launc scorm_disable_toc = true; } + scoes_nav = JSON.parse(scoes_nav); var scorm_layout_widget; var scorm_current_node; var scorm_buttons = []; @@ -166,11 +167,15 @@ M.mod_scorm.init = function(Y, hide_nav, hide_toc, toc_title, window_name, launc * @return void */ var scorm_fixnav = function() { - scorm_buttons[0].set('disabled', (scorm_skipprev(scorm_current_node) == null || scorm_skipprev(scorm_current_node).title == null)); - scorm_buttons[1].set('disabled', (scorm_prev(scorm_current_node) == null || scorm_prev(scorm_current_node).title == null)); + scorm_buttons[0].set('disabled', (scorm_skipprev(scorm_current_node) == null || scorm_skipprev(scorm_current_node).title == null || + scoes_nav[launch_sco].hideprevious == 1)); + scorm_buttons[1].set('disabled', (scorm_prev(scorm_current_node) == null || scorm_prev(scorm_current_node).title == null || + scoes_nav[launch_sco].hideprevious == 1)); scorm_buttons[2].set('disabled', (scorm_up(scorm_current_node) == null) || scorm_up(scorm_current_node).title == null); - scorm_buttons[3].set('disabled', (scorm_next(scorm_current_node) == null) || scorm_next(scorm_current_node).title == null); - scorm_buttons[4].set('disabled', (scorm_skipnext(scorm_current_node) == null || scorm_skipnext(scorm_current_node).title == null)); + scorm_buttons[3].set('disabled', (((scorm_next(scorm_current_node) == null || scorm_next(scorm_current_node).title == null) && + (scoes_nav[launch_sco].flow != 1)) || (scoes_nav[launch_sco].hidecontinue == 1))); + scorm_buttons[4].set('disabled', (scorm_skipnext(scorm_current_node) == null || scorm_skipnext(scorm_current_node).title == null || + scoes_nav[launch_sco].hidecontinue == 1)); }; var scorm_resize_parent = function() { @@ -253,9 +258,21 @@ M.mod_scorm.init = function(Y, hide_nav, hide_toc, toc_title, window_name, launc } }; - var scorm_up = function(node) { + // Handle AJAX Request + var scorm_ajax_request = function(url, datastring) { + var myRequest = NewHttpReq(); + var result = DoRequest(myRequest, url + datastring); + return result; + }; + + var scorm_up = function(node, update_launch_sco) { var node = scorm_tree_node.getHighlightedNode(); - if (node.depth > 0) { + if (node.depth > 0 && typeof scoes_nav[launch_sco].parentscoid != 'undefined') { + var parentscoid = scoes_nav[launch_sco].parentscoid; + node.parent.title = scoes_nav[parentscoid].url; + if (update_launch_sco) { + launch_sco = parentscoid; + } return node.parent; } return null; @@ -269,43 +286,131 @@ M.mod_scorm.init = function(Y, hide_nav, hide_toc, toc_title, window_name, launc } }; - var scorm_prev = function(node) { - if (node.previousSibling && node.previousSibling.children.length) { - return scorm_lastchild(node.previousSibling); + var scorm_prev = function(node, update_launch_sco) { + if (node.previousSibling && node.previousSibling.children.length && + typeof scoes_nav[launch_sco].prevscoid != 'undefined') { + var node = scorm_lastchild(node.previousSibling); + if (node) { + var prevscoid = scoes_nav[launch_sco].prevscoid; + node.title = scoes_nav[prevscoid].url; + if (update_launch_sco) { + launch_sco = prevscoid; + } + return node; + } else { + return null; + } } - return scorm_skipprev(node); + return scorm_skipprev(node, update_launch_sco); }; - var scorm_skipprev = function(node) { - if (node.previousSibling) { + var scorm_skipprev = function(node, update_launch_sco) { + if (node.previousSibling && typeof scoes_nav[launch_sco].prevsibling != 'undefined') { + var prevsibling = scoes_nav[launch_sco].prevsibling; + node.previousSibling.title = scoes_nav[prevsibling].url; + if (update_launch_sco) { + launch_sco = prevsibling; + } return node.previousSibling; - } else if (node.depth > 0) { + } else if (node.depth > 0 && typeof scoes_nav[launch_sco].parentscoid != 'undefined') { + var parentscoid = scoes_nav[launch_sco].parentscoid; + node.parent.title = scoes_nav[parentscoid].url; + if (update_launch_sco) { + launch_sco = parentscoid; + } return node.parent; } return null; }; - var scorm_next = function(node) { + var scorm_next = function(node, update_launch_sco) { if (node === false) { return scorm_tree_node.getRoot().children[0]; } - if (node.children.length) { - return node.children[0]; + if (node.children.length && typeof scoes_nav[launch_sco].nextscoid != 'undefined') { + var node = node.children[0]; + var nextscoid = scoes_nav[launch_sco].nextscoid; + node.title = scoes_nav[nextscoid].url; + if (update_launch_sco) { + launch_sco = nextscoid; + } + return node; } - return scorm_skipnext(node); + return scorm_skipnext(node, update_launch_sco); }; - var scorm_skipnext = function(node) { - if (node.nextSibling) { + var scorm_skipnext = function(node, update_launch_sco) { + if (node.nextSibling && typeof scoes_nav[launch_sco].nextsibling != 'undefined') { + var nextsibling = scoes_nav[launch_sco].nextsibling; + node.nextSibling.title = scoes_nav[nextsibling].url; + if (update_launch_sco) { + launch_sco = nextsibling; + } return node.nextSibling; - } else if (node.depth > 0) { - return scorm_skipnext(node.parent); + } else if (node.depth > 0 && typeof scoes_nav[launch_sco].parentscoid != 'undefined') { + var parentscoid = scoes_nav[launch_sco].parentscoid; + if (update_launch_sco) { + launch_sco = parentscoid; + } + return scorm_skipnext(node.parent, update_launch_sco); } return null; }; - mod_scorm_next = scorm_next; - mod_scorm_prev = scorm_prev; + // Launch prev sco + var scorm_launch_prev_sco = function() { + var result = null; + if (scoes_nav[launch_sco].flow == 1) { + var datastring = scoes_nav[launch_sco].url + '&function=scorm_seq_flow&request=backward'; + result = scorm_ajax_request(M.cfg.wwwroot + '/mod/scorm/datamodels/sequencinghandler.php?', datastring); + mod_scorm_seq = encodeURIComponent(result); + result = JSON.parse (result); + if (typeof result.nextactivity.id != undefined) { + var node = scorm_prev(scorm_tree_node.getHighlightedNode()) + if (node == null) { + // Avoid use of TreeView for Navigation + node = scorm_tree_node.getHighlightedNode(); + } + node.title = scoes_nav[result.nextactivity.id].url; + launch_sco = result.nextactivity.id; + scorm_activate_item(node); + scorm_fixnav(); + } else { + scorm_activate_item(scorm_prev(scorm_tree_node.getHighlightedNode(), true)); + } + } else { + scorm_activate_item(scorm_prev(scorm_tree_node.getHighlightedNode(), true)); + } + }; + + // Launch next sco + var scorm_launch_next_sco = function () { + var result = null; + if (scoes_nav[launch_sco].flow == 1) { + var datastring = scoes_nav[launch_sco].url + '&function=scorm_seq_flow&request=forward'; + result = scorm_ajax_request(M.cfg.wwwroot + '/mod/scorm/datamodels/sequencinghandler.php?', datastring); + mod_scorm_seq = encodeURIComponent(result); + result = JSON.parse (result); + if (typeof result.nextactivity.id != undefined) { + var node = scorm_next(scorm_tree_node.getHighlightedNode()) + if (node == null) { + // Avoid use of TreeView for Navigation + node = scorm_tree_node.getHighlightedNode(); + } + node.title = scoes_nav[result.nextactivity.id].url; + launch_sco = result.nextactivity.id; + scorm_activate_item(node); + scorm_fixnav(); + } else { + scorm_activate_item(scorm_next(scorm_tree_node.getHighlightedNode(), true)); + } + } else { + scorm_activate_item(scorm_next(scorm_tree_node.getHighlightedNode(), true)); + } + }; + + mod_scorm_launch_prev_sco = scorm_launch_prev_sco; + mod_scorm_launch_next_sco = scorm_launch_next_sco; // layout Y.YUI2.widget.LayoutUnit.prototype.STR_COLLAPSE = M.str.moodle.hide; @@ -403,36 +508,26 @@ M.mod_scorm.init = function(Y, hide_nav, hide_toc, toc_title, window_name, launc scorm_buttons[3] = new Y.YUI2.widget.Button('nav_next'); scorm_buttons[4] = new Y.YUI2.widget.Button('nav_skipnext'); scorm_buttons[0].on('click', function(ev) { - scorm_activate_item(scorm_skipprev(scorm_tree_node.getHighlightedNode())); + scorm_activate_item(scorm_skipprev(scorm_tree_node.getHighlightedNode(), true)); }); scorm_buttons[1].on('click', function(ev) { - scorm_activate_item(scorm_prev(scorm_tree_node.getHighlightedNode())); + scorm_launch_prev_sco(); }); scorm_buttons[2].on('click', function(ev) { - scorm_activate_item(scorm_up(scorm_tree_node.getHighlightedNode())); + scorm_activate_item(scorm_up(scorm_tree_node.getHighlightedNode(), true)); }); scorm_buttons[3].on('click', function(ev) { - scorm_activate_item(scorm_next(scorm_tree_node.getHighlightedNode())); + scorm_launch_next_sco(); }); scorm_buttons[4].on('click', function(ev) { - scorm_activate_item(scorm_skipnext(scorm_tree_node.getHighlightedNode())); + scorm_activate_item(scorm_skipnext(scorm_tree_node.getHighlightedNode(), true)); }); scorm_nav_panel.render(); } // finally activate the chosen item - var scorm_first_url = tree.getRoot().children[0]; - var nxt = false; - while (nxt = scorm_next(nxt)) { - if (nxt.title) { - expression = new RegExp('^.*?scoid=' + launch_sco + '.*?$'); - matches = nxt.title.match(expression); - if (matches != null) { - scorm_first_url = nxt; - break; - } - } - } + var scorm_first_url = tree.getRoot().children[0]; + scorm_first_url.title = scoes_nav[launch_sco].url; scorm_activate_item(scorm_first_url); // resizing @@ -443,31 +538,4 @@ M.mod_scorm.init = function(Y, hide_nav, hide_toc, toc_title, window_name, launc scorm_resize_layout(true); }; }); -}; - - -function scorm_get_prev() { - YUI.use('yui2-treeview', function(Y) { - scorm_tree_node = Y.YUI2.widget.TreeView.getTree('scorm_tree'); - if (scorm_tree_node) { - var hnode = scorm_tree_node.getHighlightedNode(); - var prev = mod_scorm_prev(hnode); - if (prev) { - mod_scorm_activate_item(prev); - } - } - }); -} - -function scorm_get_next() { - YUI.use('yui2-treeview', function(Y) { - scorm_tree_node = Y.YUI2.widget.TreeView.getTree('scorm_tree'); - if (scorm_tree_node) { - var hnode = scorm_tree_node.getHighlightedNode(); - var next = mod_scorm_next(hnode); - if (next) { - mod_scorm_activate_item(next); - } - } - }); -} +}; \ No newline at end of file diff --git a/mod/scorm/player.php b/mod/scorm/player.php index 982052cdb3e..6a7dda3749c 100644 --- a/mod/scorm/player.php +++ b/mod/scorm/player.php @@ -269,12 +269,14 @@ if ($result->prerequisites) { ?> id, $mode, $attempt); +$adlnav = scorm_get_adlnav_json($scoes['scoes']); // NEW IMS TOC if (empty($scorm->popup) || $displaymode == 'popup') { if (!isset($result->toctitle)) { $result->toctitle = get_string('toc', 'scorm'); } - $PAGE->requires->js_init_call('M.mod_scorm.init', array($scorm->hidenav, $scorm->hidetoc, $result->toctitle, $name, $sco->id)); + $PAGE->requires->js_init_call('M.mod_scorm.init', array($scorm->hidenav, $scorm->hidetoc, $result->toctitle, $name, $sco->id, $adlnav)); } if (!empty($forcejs)) { echo $OUTPUT->box(get_string("forcejavascriptmessage", "scorm"), "generalbox boxaligncenter forcejavascriptmessage");