function scorm_view_display($user, $scorm, $action, $cm, $boxwidth = '') { global $CFG, $DB, $PAGE, $OUTPUT; if ($scorm->updatefreq == UPDATE_EVERYTIME) { scorm_parse($scorm, false); } $organization = optional_param('organization', '', PARAM_INT); if ($scorm->displaycoursestructure == 1) { echo $OUTPUT->box_start('generalbox boxaligncenter'); ?> <div class="structurehead"><?php print_string('contents', 'scorm'); ?> </div> <?php } if (empty($organization)) { $organization = $scorm->launch; } if ($orgs = $DB->get_records_menu('scorm_scoes', array('scorm' => $scorm->id, 'organization' => '', 'launch' => ''), 'id', 'id,title')) { if (count($orgs) > 1) { ?> <div class='scorm-center'> <?php print_string('organizations', 'scorm'); ?> <form id='changeorg' method='post' action='<?php echo $action; ?> '> <?php $select = new html_select(); $select->options = $orgs; $select->name = 'organization'; $select->selectedvalue = $organization; $select->add_action('change', 'submit_form_by_id', array('id' => 'changeorg')); echo $OUTPUT->select($select); ?> </form> </div> <?php } } $orgidentifier = ''; if ($sco = scorm_get_sco($organization, SCO_ONLY)) { if ($sco->organization == '' && $sco->launch == '') { $orgidentifier = $sco->identifier; } else { $orgidentifier = $sco->organization; } } /* $orgidentifier = ''; if ($org = $DB->get_record('scorm_scoes', array('id'=>$organization))) { if (($org->organization == '') && ($org->launch == '')) { $orgidentifier = $org->identifier; } else { $orgidentifier = $org->organization; } }*/ $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe if (!file_exists($CFG->dirroot . '/mod/scorm/datamodels/' . $scorm->version . 'lib.php')) { $scorm->version = 'scorm_12'; } require_once $CFG->dirroot . '/mod/scorm/datamodels/' . $scorm->version . 'lib.php'; $result = scorm_get_toc($user, $scorm, 'structlist', $orgidentifier); $incomplete = $result->incomplete; // do we want the TOC to be displayed? if ($scorm->displaycoursestructure == 1) { echo $result->toc; echo $OUTPUT->box_end(); } // is this the first attempt ? $attemptcount = scorm_get_attempt_count($user, $scorm); // do not give the player launch FORM if the SCORM object is locked after the final attempt if ($scorm->lastattemptlock == 0 || $result->attemptleft > 0) { ?> <div class="scorm-center"> <form id="theform" method="post" action="<?php echo $CFG->wwwroot; ?> /mod/scorm/player.php"> <?php if ($scorm->hidebrowse == 0) { print_string('mode', 'scorm'); echo ': <input type="radio" id="b" name="mode" value="browse" /><label for="b">' . get_string('browse', 'scorm') . '</label>' . "\n"; echo '<input type="radio" id="n" name="mode" value="normal" checked="checked" /><label for="n">' . get_string('normal', 'scorm') . "</label>\n"; } else { echo '<input type="hidden" name="mode" value="normal" />' . "\n"; } if ($scorm->forcenewattempt == 1) { if ($incomplete === false) { echo '<input type="hidden" name="newattempt" value="on" />' . "\n"; } } elseif ($attemptcount != 0 && $incomplete === false && ($result->attemptleft > 0 || $scorm->maxattempt == 0)) { ?> <br /> <input type="checkbox" id="a" name="newattempt" /> <label for="a"><?php print_string('newattempt', 'scorm'); ?> </label> <?php } ?> <br /> <input type="hidden" name="scoid"/> <input type="hidden" name="id" value="<?php echo $cm->id; ?> "/> <input type="hidden" name="currentorg" value="<?php echo $orgidentifier; ?> " /> <input type="submit" value="<?php print_string('enter', 'scorm'); ?> " /> </form> </div> <?php } }
/** * Check if the current sco is launchable * If not, find the next launchable sco * * @param stdClass $scorm Scorm object * @param integer $scoid id of scorm_scoes record. * @return integer scoid of correct sco to launch or empty if one cannot be found, which will trigger first sco. */ function scorm_check_launchable_sco($scorm, $scoid) { global $DB; if ($sco = scorm_get_sco($scoid, SCO_ONLY)) { if ($sco->launch == '') { // This scoid might be a top level org that can't be launched, find the first launchable sco after this sco. $scoes = $DB->get_records_select('scorm_scoes', 'scorm = ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true). ' AND id > ?', array($scorm->id, $sco->id), 'sortorder, id', 'id', 0, 1); if (!empty($scoes)) { $sco = reset($scoes); // Get first item from the list. return $sco->id; } } else { return $sco->id; } } // Returning 0 will cause default behaviour which will find the first launchable sco in the package. return 0; }
function scorm_get_toc($user,$scorm,$cmid,$toclink=TOCJSLINK,$currentorg='',$scoid='',$mode='normal',$attempt='',$play=false, $tocheader=false) { global $CFG, $DB, $PAGE, $OUTPUT; $modestr = ''; if ($mode == 'browse') { $modestr = '&mode='.$mode; } $result = new stdClass(); if ($tocheader) { $result->toc = '<div id="scorm_layout">'; $result->toc .= '<div id="scorm_toc">'; $result->toc .= '<div id="scorm_tree">'; } $result->toc .= '<ul>'; $tocmenus = array(); $result->prerequisites = true; $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<li>$organizationtitle</li>\n"; } $tocmenus[] = $organizationtitle; } } // // 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 // $usertracks = array(); foreach ($scoes as $sco) { if (!empty($sco->launch)) { if ($usertrack = scorm_get_tracks($sco->id,$user->id,$attempt)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } $usertracks[$sco->identifier] = $usertrack; } } } $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) { if ($newlevel = array_search($sco->parent,$parents)) { for ($i=0; $i<($level-$newlevel); $i++) { $result->toc .= "\t\t</li></ul></li>\n"; } $level = $newlevel; } else { $i = $level; $closelist = ''; while (($i > 0) && ($parents[$level] != $sco->parent)) { if ($i === 1 && $level > 1) { $closelist .= "\t\t</ul></li>\n"; } else { $closelist .= "\t</li></ul></li>\n"; } $i--; } if (($i == 0) && ($sco->parent != $currentorg)) { $result->toc .= "\n\t<ul>\n"; $level++; } else { $result->toc .= $closelist; $level = $i; } $parents[$level] = $sco->parent; } } if ($isvisible) { $result->toc .= "<li>"; } 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 (!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 = '<img src="'.$OUTPUT->pix_url($usertrack->status, 'scorm').'" alt="'.$strstatus.'" title="'.$strstatus.'" />'; } else { $statusicon = '<img src="'.$OUTPUT->pix_url('assetc', 'scorm').'" alt="'.get_string('assetlaunched','scorm').'" title="'.get_string('assetlaunched','scorm').'" />'; } if (($usertrack->status == 'notattempted') || ($usertrack->status == 'incomplete') || ($usertrack->status == 'browsed')) { $incomplete = true; if ($play && empty($scoid)) { $scoid = $sco->id; } } if ($usertrack->score_raw != '' && has_capability('mod/scorm:viewscores', get_context_instance(CONTEXT_MODULE,$cmid))) { $score = '('.get_string('score','scorm').': '.$usertrack->score_raw.')'; } $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 = '<img src="'.$OUTPUT->pix_url('suspend', 'scorm').'" alt="'.$strstatus.' - '.$strsuspended.'" title="'.$strstatus.' - '.$strsuspended.'" />'; } } else { if ($play && empty($scoid)) { $scoid = $sco->id; } $incomplete = true; if ($sco->scormtype == 'sco') { $statusicon = '<img src="'.$OUTPUT->pix_url('notattempted', 'scorm').'" alt="'.get_string('notattempted','scorm').'" title="'.get_string('notattempted','scorm').'" />'; } else { $statusicon = '<img src="'.$OUTPUT->pix_url('asset', 'scorm').'" alt="'.get_string('asset','scorm').'" title="'.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 .= '<span>'.$statusicon.' '.format_string($sco->title).'</span>'; } 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.' <a href="'.$url.'">'.format_string($sco->title).'</a>'.$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 .= '<a title="'.$link.'">'.$statusicon.' '.format_string($sco->title).' '.$score.'</a>'; } else { $result->toc .= '<span>'.$statusicon.' '.format_string($sco->title).'</span>'; } } $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 .= '<span>'.$statusicon.' '.format_string($sco->title).'</span>'; } else { $result->toc .= $statusicon.' '.format_string($sco->title)."\n"; } } } else { $result->toc .= ' '.format_string($sco->title); } if (($nextsco === false) || $nextsco->parent == $sco->parent) { $result->toc .= "</li>\n"; } } if (($nextsco !== false) && ($nextid == 0) && ($findnext)) { if (!empty($nextsco->launch)) { $nextid = $nextsco->id; } } $prevsco = $sco; } for ($i=0;$i<$level;$i++) { $result->toc .= "\t\t</ul></li>\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 .= '</ul>'; // NEW IMS TOC if ($tocheader) { $result->toc .= '</div></div></div>'; $result->toc .= '<div id="scorm_navpanel"></div>'; } $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"); return $result; }
function scorm_get_parent($sco) { global $DB; if ($sco->parent != '/') { if ($parent = $DB->get_record('scorm_scoes', array('scorm' => $sco->scorm, 'identifier' => $sco->parent))) { return scorm_get_sco($parent->id); } } return null; }
function JLMS_LoadSCOSCORM($option) { global $JLMS_DB, $my, $Itemid; $JLMS_CONFIG =& JLMSFactory::getConfig(); $id = intval(mosGetParam($_REQUEST, 'id', 0)); $delayseconds = 20; // Delay time before sco launch, used to give time to browser to define API $delayseconds_nojs = 2; // if API were defined earlier than timer is passed - SCO will be launched if ($id) { $query = "SELECT * FROM #__lms_n_scorm WHERE id = {$id}"; $JLMS_DB->SetQuery($query); $scorm = $JLMS_DB->LoadObject(); if (is_object($scorm)) { $scoid = intval(mosGetParam($_REQUEST, 'scoid', 0)); if (!empty($scoid)) { // // Direct SCO request // if ($sco = scorm_get_sco($scoid)) { // (DEN) check if this $scoid from our SCORM !!!! if ($sco->launch == '') { // Search for the next launchable sco $query = "SELECT * FROM #__lms_n_scorm_scoes WHERE scorm = {$scorm->id} AND launch <> '' AND id > {$sco->id} ORDER BY id ASC"; $JLMS_DB->SetQuery($query); $scoes = $JLMS_DB->LoadObjectList(); //if ($scoes = get_records_select('scorm_scoes','scorm='.$scorm->id." AND launch<>'' AND id>".$sco->id,'id ASC')) { if (!empty($scoes)) { $sco = current($scoes); } } } } // // If no sco was found get the first of SCORM package // if (!isset($sco)) { $query = "SELECT * FROM #__lms_n_scorm_scoes WHERE scorm = {$scorm->id} AND launch <> '' ORDER BY id ASC"; $JLMS_DB->SetQuery($query); $scoes = $JLMS_DB->LoadObjectList(); //$scoes = get_records_select('scorm_scoes','scorm='.$scorm->id." AND launch<>''",'id ASC'); $sco = current($scoes); } if (!empty($sco)) { if ($sco->scormtype == 'asset') { $attempt = scorm_get_last_attempt($scorm->id, $my->id); $element = $scorm->version == 'scorm_13' ? 'cmi.completion_status' : 'cmi.core.lesson_status'; $value = 'completed'; $result = scorm_insert_track($my->id, $scorm->id, $sco->id, $attempt, $element, $value); } } // // Forge SCO URL // $connector = ''; $version = substr($scorm->version, 0, 4); if (isset($sco->parameters) && !empty($sco->parameters) || $version == 'AICC') { /** * 06.10.2007 (DEN) "''." - is added for compatibility with Joomla compatibility :)) library compat.php50x.php (on line 105 in PHP 4.4.7 there was a notice) */ if (stripos('' . $sco->launch, '?') !== false) { $connector = '&'; } else { $connector = '?'; } if (isset($sco->parameters) && !empty($sco->parameters) && $sco->parameters[0] == '?') { $sco->parameters = substr($sco->parameters, 1); } } if ($version == 'AICC') { if (isset($sco->parameters) && !empty($sco->parameters)) { $sco->parameters = '&' . $sco->parameters; } //$launcher = $sco->launch.$connector.'aicc_sid='.$my->id.'&aicc_url='.$CFG->wwwroot.'/mod/scorm/aicc.php'.$sco->parameters; $launcher = $sco->launch . $connector . 'aicc_sid=' . $my->id . '&aicc_url=' . $JLMS_CONFIG->get('live_site') . "/index.php?option={$option}&Itemid={$Itemid}&task=aicc_task&course_id={$course_id}" . $sco->parameters; // (DEN) check this URL /\ !!!!!!!!! } else { if (isset($sco->parameters) && !empty($sco->parameters)) { $launcher = $sco->launch . $connector . $sco->parameters; } else { $launcher = $sco->launch; } } $query = "SELECT * FROM #__lms_scorm_packages WHERE id = {$scorm->scorm_package}"; $JLMS_DB->SetQuery($query); $scorm_ref = $JLMS_DB->LoadObject(); //$reference = $CFG->dataroot.'/'.$courseid.'/'.$reference; //$row->reference = _JOOMLMS_SCORM_FOLDER_PATH . "/" . $scorm_ref->package_srv_name; $reference_folder = $JLMS_CONFIG->get('live_site') . "/" . _JOOMLMS_SCORM_PLAYER . "/" . $scorm_ref->folder_srv_name; //$reference_folder = _JOOMLMS_SCORM_FOLDER_PATH . "/" . $scorm_ref->folder_srv_name; // (DEN) we don't use external links nor repositry (but maybe...maybe...) /*if (scorm_external_link($sco->launch)) { // Remote learning activity $result = $launcher; } else if ($scorm->reference[0] == '#') { // Repository require_once($repositoryconfigfile); $result = $CFG->repositorywebroot.substr($scorm->reference,1).'/'.$sco->launch; } else {*/ if (true) { // (DEN) we don't use external packages /*if ((basename($scorm->reference) == 'imsmanifest.xml') && scorm_external_link($scorm->reference)) { // Remote manifest $result = dirname($scorm->reference).'/'.$launcher; } else {*/ if (true) { // Moodle internal package/manifest or remote (auto-imported) package //if (basename($scorm->reference) == 'imsmanifest.xml') { if (basename($reference_folder) == 'imsmanifest.xml') { //$basedir = dirname($scorm->reference); $basedir = dirname($reference_folder); } else { $basedir = $reference_folder; //$CFG->moddata.'/scorm/'.$scorm->id; } /*if ($CFG->slasharguments) { $result = $CFG->wwwroot.'/file.php/'.$scorm->course.'/'.$basedir.'/'.$launcher; } else { $result = $CFG->wwwroot.'/file.php?file=/'.$scorm->course.'/'.$basedir.'/'.$launcher; }*/ $result = $reference_folder . '/' . $launcher; // determine the name of the API variable, which are we looking for $LMS_api = $scorm->version == 'scorm_12' || $scorm->version == 'SCORM_1.2' || empty($scorm->version) ? 'API' : 'API_1484_11'; if (isset($sco->scormtype) && strtolower($sco->scormtype) == 'asset') { $delayseconds = 2; // if resource is 'asset' - we don't need SCORM API } ?> <html> <head> <title>LoadSCO</title> <script type="text/javascript"> //<![CDATA[ var delaySeconds = <?php echo $delayseconds; ?> function findscormAPI(win) { var findAPITries = 0; while ((win.<?php echo $LMS_api; ?> == null) && (win.parent != null) && (win.parent != win)) { findAPITries++; if (findAPITries > 7) { // we don't have more than 7 nested window objects.... return null; } win = win.parent; } return win.<?php echo $LMS_api; ?> ; } function getscormAPI() { var theAPI = findscormAPI(window); if ((theAPI == null) && (window.opener != null) && (typeof(window.opener) != "undefined")) { theAPI = findscormAPI(window.opener); } if (theAPI == null) { return null; } return theAPI; } function try_redirect() { if (getscormAPI() == null) { delaySeconds = delaySeconds - 1; if (delaySeconds < 0) { setTimeout('do_window_redirect();',1000); } else { setTimeout('try_redirect();',1000); } } else { setTimeout('do_window_redirect();',1000); } } function do_window_redirect() { document.location = "<?php echo $result; ?> "; } //]]> </script> <noscript> <meta http-equiv="refresh" content="<?php echo $delayseconds_nojs; ?> ;url=<?php echo $result; ?> " /> </noscript> </head> <body onload="try_redirect();"> <br /><br /><center><img src="<?php echo $JLMS_CONFIG->get('live_site'); ?> /components/com_joomla_lms/lms_images/loading.gif" height="32" width="32" border="0" alt="loading" /></center> </body> </html> <?php } } } } die; }
function scorm_get_toc($user, $scorm, $liststyle, $currentorg = '', $scoid = '', $mode = 'normal', $attempt = '', $play = false) { global $CFG; $strexpand = get_string('expcoll', 'scorm'); $modestr = ''; if ($mode == 'browse') { $modestr = '&mode=' . $mode; } $scormpixdir = $CFG->modpixpath . '/scorm/pix'; $result = new stdClass(); $result->toc = "<ul id='s0' class='{$liststyle}'>\n"; $tocmenus = array(); $result->prerequisites = true; $incomplete = false; // // Get the current organization infos // $organizationsql = ''; if (!empty($currentorg)) { if (($organizationtitle = get_field('scorm_scoes', 'title', 'scorm', $scorm->id, 'identifier', $currentorg)) != '') { $result->toc .= "\t<li>{$organizationtitle}</li>\n"; $tocmenus[] = $organizationtitle; } $organizationsql = "AND organization='{$currentorg}'"; } // // If not specified retrieve the last attempt number // if (empty($attempt)) { $attempt = scorm_get_last_attempt($scorm->id, $user->id); } $result->attemptleft = $scorm->maxattempt - $attempt; if ($scoes = get_records_select('scorm_scoes', "scorm='{$scorm->id}' {$organizationsql} order by id ASC")) { // // 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->status == '') { $usertrack->status = 'notattempted'; } $usertracks[$sco->identifier] = $usertrack; } } } $level = 0; $sublist = 1; $previd = 0; $nextid = 0; $findnext = false; $parents[$level] = '/'; foreach ($scoes as $sco) { $isvisible = false; $sco->title = stripslashes($sco->title); if ($optionaldatas = scorm_get_sco($sco->id, SCO_DATA)) { if (!isset($optionaldatas->isvisible) || isset($optionaldatas->isvisible) && $optionaldatas->isvisible == 'true') { $isvisible = true; } } else { $isvisible = true; } if ($parents[$level] != $sco->parent) { if ($newlevel = array_search($sco->parent, $parents)) { for ($i = 0; $i < $level - $newlevel; $i++) { $result->toc .= "\t\t</ul></li>\n"; } $level = $newlevel; } else { $i = $level; $closelist = ''; while ($i > 0 && $parents[$level] != $sco->parent) { $closelist .= "\t\t</ul></li>\n"; $i--; } if ($i == 0 && $sco->parent != $currentorg) { $style = ''; if (isset($_COOKIE['hide:SCORMitem' . $sco->id])) { $style = ' style="display: none;"'; } $result->toc .= "\t\t<li><ul id='s{$sublist}' class='{$liststyle}'{$style}>\n"; $level++; } else { $result->toc .= $closelist; $level = $i; } $parents[$level] = $sco->parent; } } if ($isvisible) { $result->toc .= "\t\t<li>"; } $nextsco = next($scoes); $nextisvisible = false; if ($nextsco !== false && ($optionaldatas = scorm_get_sco($nextsco->id, SCO_DATA))) { if (!isset($optionaldatas->isvisible) || isset($optionaldatas->isvisible) && $optionaldatas->isvisible == 'true') { $nextisvisible = true; } } if ($nextisvisible && $nextsco !== false && $sco->parent != $nextsco->parent && ($level == 0 || $level > 0 && $nextsco->parent == $sco->identifier)) { $sublist++; $icon = 'minus'; if (isset($_COOKIE['hide:SCORMitem' . $nextsco->id])) { $icon = 'plus'; } $result->toc .= '<a href="javascript:expandCollide(\'img' . $sublist . '\',' . $sublist . ',' . $nextsco->id . ');"><img id="img' . $sublist . '" src="' . $scormpixdir . '/' . $icon . '.gif" alt="' . $strexpand . '" title="' . $strexpand . '"/></a>'; // $result->toc .= '<a href="#" onclick="elementToggleHide(\''.$sublist.'\',true);"><img id="img'.$sublist.'" src="'.$scormpixdir.'/'.$icon.'.gif" alt="'.$strexpand.'" title="'.$strexpand.'"/></a>'; } else { if ($isvisible) { $result->toc .= '<img src="' . $scormpixdir . '/spacer.gif" />'; } } if (empty($sco->title)) { $sco->title = $sco->identifier; } if (!empty($sco->launch)) { if ($isvisible) { $startbold = ''; $endbold = ''; $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 = '<img src="' . $scormpixdir . '/' . $usertrack->status . '.gif" alt="' . $strstatus . '" title="' . $strstatus . '" />'; } else { $statusicon = '<img src="' . $scormpixdir . '/assetc.gif" alt="' . get_string('assetlaunched', 'scorm') . '" title="' . get_string('assetlaunched', 'scorm') . '" />'; } if ($usertrack->status == 'notattempted' || $usertrack->status == 'incomplete' || $usertrack->status == 'browsed') { $incomplete = true; if ($play && empty($scoid)) { $scoid = $sco->id; } } if ($usertrack->score_raw != '') { $score = '(' . get_string('score', 'scorm') . ': ' . $usertrack->score_raw . ')'; } $strsuspended = get_string('suspended', 'scorm'); if (isset($usertrack->{'cmi.core.exit'}) && $usertrack->{'cmi.core.exit'} == 'suspend') { $statusicon = '<img src="' . $scormpixdir . '/suspend.gif" alt="' . $strstatus . ' - ' . $strsuspended . '" title="' . $strstatus . ' - ' . $strsuspended . '" />'; } } else { if ($play && empty($scoid)) { $scoid = $sco->id; } $incomplete = true; if ($sco->scormtype == 'sco') { $statusicon = '<img src="' . $scormpixdir . '/notattempted.gif" alt="' . get_string('notattempted', 'scorm') . '" title="' . get_string('notattempted', 'scorm') . '" />'; } else { $statusicon = '<img src="' . $scormpixdir . '/asset.gif" alt="' . get_string('asset', 'scorm') . '" title="' . get_string('asset', 'scorm') . '" />'; } } if ($sco->id == $scoid) { $scodata = scorm_get_sco($sco->id, SCO_DATA); $startbold = '<b>'; $endbold = '</b>'; $findnext = true; $shownext = isset($scodata->next) ? $scodata->next : 0; $showprev = isset($scodata->previous) ? $scodata->previous : 0; } if ($nextid == 0 && scorm_count_launchable($scorm->id, $currentorg) > 1 && $nextsco !== false && !$findnext) { if (!empty($sco->launch)) { $previd = $sco->id; } } if (empty($sco->prerequisites) || scorm_eval_prerequisites($sco->prerequisites, $usertracks)) { if ($sco->id == $scoid) { $result->prerequisites = true; } $url = $CFG->wwwroot . '/mod/scorm/player.php?a=' . $scorm->id . '&currentorg=' . $currentorg . $modestr . '&scoid=' . $sco->id; $result->toc .= $statusicon . ' ' . $startbold . '<a href="' . $url . '">' . format_string($sco->title) . '</a>' . $score . $endbold . "</li>\n"; $tocmenus[$sco->id] = scorm_repeater('−', $level) . '>' . format_string($sco->title); } else { if ($sco->id == $scoid) { $result->prerequisites = false; } $result->toc .= $statusicon . ' ' . format_string($sco->title) . "</li>\n"; } } } else { $result->toc .= ' ' . format_string($sco->title) . "</li>\n"; } if ($nextsco !== false && $nextid == 0 && $findnext) { if (!empty($nextsco->launch)) { $nextid = $nextsco->id; } } } for ($i = 0; $i < $level; $i++) { $result->toc .= "\t\t</ul></li>\n"; } if ($play) { // it is possible that scoid is still not set, in this case we dont 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 .= "\t</ul>\n"; if ($scorm->hidetoc == 0) { $result->toc .= ' <script type="text/javascript"> //<![CDATA[ function expandCollide(which,list,item) { var nn=document.ids?true:false var w3c=document.getElementById?true:false var beg=nn?"document.ids.":w3c?"document.getElementById(":"document.all."; var mid=w3c?").style":".style"; which = which.substring(0,(which.length)); if (eval(beg+list+mid+".display") != "none") { document.getElementById(which).src = "' . $scormpixdir . '/plus.gif"; eval(beg+list+mid+".display=\'none\';"); new cookie("hide:SCORMitem" + item, 1, 356, "/").set(); } else { document.getElementById(which).src = "' . $scormpixdir . '/minus.gif"; eval(beg+list+mid+".display=\'block\';"); new cookie("hide:SCORMitem" + item, 1, -1, "/").set(); } } //]]> </script>' . "\n"; } $url = $CFG->wwwroot . '/mod/scorm/player.php?a=' . $scorm->id . '&currentorg=' . $currentorg . $modestr . '&scoid='; $result->tocmenu = popup_form($url, $tocmenus, "tocmenu", $sco->id, '', '', '', true); return $result; }
/** * Return a SCO object and the SCO launch URL * * @param stdClass $scorm SCORM object * @param int $scoid The SCO id in database * @param stdClass $context context object * @return array the SCO object and URL * @since Moodle 3.1 */ function scorm_get_sco_and_launch_url($scorm, $scoid, $context) { global $CFG, $DB; if (!empty($scoid)) { // Direct SCO request. if ($sco = scorm_get_sco($scoid)) { if ($sco->launch == '') { // Search for the next launchable sco. if ($scoes = $DB->get_records_select( 'scorm_scoes', 'scorm = ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true).' AND id > ?', array($scorm->id, $sco->id), 'sortorder, id')) { $sco = current($scoes); } } } } // If no sco was found get the first of SCORM package. if (!isset($sco)) { $scoes = $DB->get_records_select( 'scorm_scoes', 'scorm = ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true), array($scorm->id), 'sortorder, id' ); $sco = current($scoes); } $connector = ''; $version = substr($scorm->version, 0, 4); if ((isset($sco->parameters) && (!empty($sco->parameters))) || ($version == 'AICC')) { if (stripos($sco->launch, '?') !== false) { $connector = '&'; } else { $connector = '?'; } if ((isset($sco->parameters) && (!empty($sco->parameters))) && ($sco->parameters[0] == '?')) { $sco->parameters = substr($sco->parameters, 1); } } if ($version == 'AICC') { require_once("$CFG->dirroot/mod/scorm/datamodels/aicclib.php"); $aiccsid = scorm_aicc_get_hacp_session($scorm->id); if (empty($aiccsid)) { $aiccsid = sesskey(); } $scoparams = ''; if (isset($sco->parameters) && (!empty($sco->parameters))) { $scoparams = '&'. $sco->parameters; } $launcher = $sco->launch.$connector.'aicc_sid='.$aiccsid.'&aicc_url='.$CFG->wwwroot.'/mod/scorm/aicc.php'.$scoparams; } else { if (isset($sco->parameters) && (!empty($sco->parameters))) { $launcher = $sco->launch.$connector.$sco->parameters; } else { $launcher = $sco->launch; } } if (scorm_external_link($sco->launch)) { // TODO: does this happen? $scolaunchurl = $launcher; } else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL) { // Remote learning activity. $scolaunchurl = dirname($scorm->reference).'/'.$launcher; } else if ($scorm->scormtype === SCORM_TYPE_LOCAL && strtolower($scorm->reference) == 'imsmanifest.xml') { // This SCORM content sits in a repository that allows relative links. $scolaunchurl = "$CFG->wwwroot/pluginfile.php/$context->id/mod_scorm/imsmanifest/$scorm->revision/$launcher"; } else if ($scorm->scormtype === SCORM_TYPE_LOCAL or $scorm->scormtype === SCORM_TYPE_LOCALSYNC) { // Note: do not convert this to use moodle_url(). // SCORM does not work without slasharguments and moodle_url() encodes querystring vars. $scolaunchurl = "$CFG->wwwroot/pluginfile.php/$context->id/mod_scorm/content/$scorm->revision/$launcher"; } return array($sco, $scolaunchurl); }
function scorm_randomize_children_process($scoid, $userid) { $sco = scorm_get_sco($scoid); if (!scorm_is_leaf($sco)) { if (!scorm_seq_is('suspended', $scoid, $userid) && !scorm_seq_is('active', $scoid, $userid)) { $r = get_record('scorm_scoes_track', 'scoid', $scoid, 'userid', $userid, 'element', 'randomizationtiming'); switch ($r->value) { case 'never': break; case 'oneachnewattempt': case 'once': if (!scorm_seq_is('activityprogressstatus', $scoid, $userid)) { if (scorm_seq_is('randomizechildren', $scoid, $userid)) { $childlist = array(); $res = scorm_get_available_children($sco); $i = sizeof($res) - 1; $children = $res->value; while ($i >= 0) { $pos = array_rand($children); array_push($childlist, $children[$pos]); array_splice($children, $pos, 1); $i--; } $clist = serialize($childlist); scorm_seq_set('availablechildren', $scoid, $userid, false); scorm_seq_set('availablechildren', $scoid, $userid, $clist); } } break; } } } }
function scorm_get_toc($user, $scorm, $liststyle, $currentorg = '', $scoid = '', $mode = 'normal', $attempt = '', $play = false, $tocheader = false) { global $CFG, $DB, $PAGE, $OUTPUT; $strexpand = get_string('expcoll', 'scorm'); $modestr = ''; if ($mode == 'browse') { $modestr = '&mode=' . $mode; } $result = new stdClass(); //$result->toc = "<ul id='s0' class='$liststyle'>\n"; if ($tocheader) { $result->toc = '<div id="scorm_layout">'; $result->toc .= '<div id="scorm_toc">'; $result->toc .= '<div id="scorm_tree">'; } $result->toc .= '<ul>'; $tocmenus = array(); $result->prerequisites = true; $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<li>{$organizationtitle}</li>\n"; } $tocmenus[] = $organizationtitle; } } // // If not specified retrieve the last attempt number // if (empty($attempt)) { $attempt = scorm_get_last_attempt($scorm->id, $user->id); } $result->attemptleft = $scorm->maxattempt - $attempt; if ($scoes = scorm_get_scoes($scorm->id, $currentorg)) { // // Retrieve user tracking data for each learning object // $usertracks = array(); foreach ($scoes as $sco) { if (!empty($sco->launch)) { if (empty($scoid)) { $scoid = $sco->id; } if ($usertrack = scorm_get_tracks($sco->id, $user->id, $attempt)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } $usertracks[$sco->identifier] = $usertrack; } } } $level = 0; $sublist = 1; $previd = 0; $nextid = 0; $findnext = false; $parents[$level] = '/'; 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) { if ($newlevel = array_search($sco->parent, $parents)) { for ($i = 0; $i < $level - $newlevel; $i++) { $result->toc .= "\t\t</li></ul></li>\n"; } $level = $newlevel; } else { $i = $level; $closelist = ''; while ($i > 0 && $parents[$level] != $sco->parent) { $closelist .= "\t\t</li></ul></li>\n"; $i--; } if ($i == 0 && $sco->parent != $currentorg) { $style = ''; if (isset($_COOKIE['hide:SCORMitem' . $sco->id])) { $style = ' style="display: none;"'; } //$result->toc .= "\t\t<li><ul id='s$sublist' class='$liststyle'$style>\n"; $result->toc .= "\t\t<ul>\n"; $level++; } else { $result->toc .= $closelist; $level = $i; } $parents[$level] = $sco->parent; } } if ($isvisible) { $result->toc .= "\t\t<li>"; } if (isset($scoes[$pos + 1])) { $nextsco = $scoes[$pos + 1]; } else { $nextsco = false; } $nextisvisible = false; if (!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++; $icon = 'minus'; if (isset($_COOKIE['hide:SCORMitem' . $nextsco->id])) { $icon = 'plus'; } //$result->toc .= '<a href="javascript:expandCollide(\'img'.$sublist.'\',\'s'.$sublist.'\','.$nextsco->id.');"><img id="img'.$sublist.'" src="'.$OUTPUT->pix_url($icon, 'scorm').'" alt="'.$strexpand.'" title="'.$strexpand.'"/></a>'; } else { if ($isvisible) { //$result->toc .= '<img src="'.$OUTPUT->pix_url('spacer', 'scorm').'" alt="" />'; } } if (empty($sco->title)) { $sco->title = $sco->identifier; } if (!empty($sco->launch)) { if ($isvisible) { $startbold = ''; $endbold = ''; $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 = '<img src="' . $OUTPUT->pix_url($usertrack->status, 'scorm') . '" alt="' . $strstatus . '" title="' . $strstatus . '" />'; } else { $statusicon = '<img src="' . $OUTPUT->pix_url('assetc', 'scorm') . '" alt="' . get_string('assetlaunched', 'scorm') . '" title="' . get_string('assetlaunched', 'scorm') . '" />'; } if ($usertrack->status == 'notattempted' || $usertrack->status == 'incomplete' || $usertrack->status == 'browsed') { $incomplete = true; if ($play && empty($scoid)) { $scoid = $sco->id; } } if ($usertrack->score_raw != '') { $score = '(' . get_string('score', 'scorm') . ': ' . $usertrack->score_raw . ')'; } $strsuspended = get_string('suspended', 'scorm'); if ($incomplete && isset($usertrack->{'cmi.core.exit'}) && $usertrack->{'cmi.core.exit'} == 'suspend') { $statusicon = '<img src="' . $OUTPUT->pix_url('suspend', 'scorm') . '" alt="' . $strstatus . ' - ' . $strsuspended . '" title="' . $strstatus . ' - ' . $strsuspended . '" />'; } } else { if ($play && empty($scoid)) { $scoid = $sco->id; } $incomplete = true; if ($sco->scormtype == 'sco') { $statusicon = '<img src="' . $OUTPUT->pix_url('notattempted', 'scorm') . '" alt="' . get_string('notattempted', 'scorm') . '" title="' . get_string('notattempted', 'scorm') . '" />'; } else { $statusicon = '<img src="' . $OUTPUT->pix_url('asset', 'scorm') . '" alt="' . get_string('asset', 'scorm') . '" title="' . get_string('asset', 'scorm') . '" />'; } } if ($sco->id == $scoid) { $startbold = '<b>'; $endbold = '</b>'; $findnext = true; $shownext = isset($sco->next) ? $sco->next : 0; $showprev = isset($sco->previous) ? $sco->previous : 0; } if ($nextid == 0 && scorm_count_launchable($scorm->id, $currentorg) > 1 && $nextsco !== false && !$findnext) { if (!empty($sco->launch)) { $previd = $sco->id; } } if (empty($sco->prerequisites) || scorm_eval_prerequisites($sco->prerequisites, $usertracks)) { if ($sco->id == $scoid) { $result->prerequisites = true; } $url = $CFG->wwwroot . '/mod/scorm/player.php?a=' . $scorm->id . '&currentorg=' . $currentorg . $modestr . '&scoid=' . $sco->id; $thisscoidstr = '&scoid=' . $sco->id; //$link = $CFG->wwwroot.'/mod/scorm/loadSCO.php?a='.$scorm->id.$thisscoidstr.$modestr; $link = 'a=' . $scorm->id . $thisscoidstr . '¤torg=' . $currentorg . $modestr . '&attempt=' . $attempt; //$result->toc .= $statusicon.' '.$startbold.'<a href="'.$url.'">'.format_string($sco->title).'</a>'.$score.$endbold."</li>\n"; //$result->toc .= '<a title="'.$link.'">'.$statusicon.' '.format_string($sco->title).' '.$score.'</a>'; if ($sco->launch) { $result->toc .= '<a title="' . $link . '">' . $statusicon . ' ' . format_string($sco->title) . ' ' . $score . '</a>'; } else { $result->toc .= '<span>' . $statusicon . ' ' . format_string($sco->title) . '</span>'; } $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 .= '<span>' . $statusicon . ' ' . format_string($sco->title) . '</span>'; } else { $result->toc .= $statusicon . ' ' . format_string($sco->title) . "\n"; } } if ($nextsco === false || $nextsco->parent == $sco->parent) { $result->toc .= '</li>'; } } } else { $result->toc .= ' ' . format_string($sco->title) . "</li>\n"; } if ($nextsco !== false && $nextid == 0 && $findnext) { if (!empty($nextsco->launch)) { $nextid = $nextsco->id; } } } for ($i = 0; $i < $level; $i++) { $result->toc .= "\t\t</ul></li>\n"; } if ($play) { $sco = scorm_get_sco($scoid); $sco->previd = $previd; $sco->nextid = $nextid; $result->sco = $sco; $result->incomplete = $incomplete; } else { $result->incomplete = $incomplete; } } $result->toc .= '</ul>'; // NEW IMS TOC if ($tocheader) { $result->toc .= '</div></div></div>'; $result->toc .= '<div id="scorm_navpanel"></div>'; } if ($scorm->hidetoc == 0) { $result->toc .= html_writer::script(js_writer::set_variable('scormdata', array('plusicon' => $OUTPUT->pix_url('plus', 'scorm'), 'minusicon' => $OUTPUT->pix_url('minus', 'scorm')))); $result->toc .= html_writer::script('', $CFG->wwwroot . '/lib/cookies.js'); $result->toc .= html_writer::script('', $CFG->wwwroot . '/mod/scorm/datamodels/scorm_datamodels.js'); } $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"); return $result; }
/** * Sets up $userdata array and default values for AICC package. * * @param stdClass $userdata an empty stdClass variable that should be set up with user values * @param object $scorm package record * @param string $scoid SCO Id * @param string $attempt attempt number for the user * @param string $mode scorm display mode type * @return array The default values that should be used for AICC package */ function get_scorm_default(&$userdata, $scorm, $scoid, $attempt, $mode) { global $USER; $aiccuserid = get_config('scorm', 'aiccuserid'); if (!empty($aiccuserid)) { $userdata->student_id = $USER->id; } else { $userdata->student_id = $USER->username; } $userdata->student_name = $USER->lastname . ', ' . $USER->firstname; if ($usertrack = scorm_get_tracks($scoid, $USER->id, $attempt)) { foreach ($usertrack as $key => $value) { $userdata->{$key} = $value; } } else { $userdata->status = ''; $userdata->score_raw = ''; } if ($scodatas = scorm_get_sco($scoid, SCO_DATA)) { foreach ($scodatas as $key => $value) { $userdata->{$key} = $value; } } else { print_error('cannotfindsco', 'scorm'); } if (!($sco = scorm_get_sco($scoid))) { print_error('cannotfindsco', 'scorm'); } $userdata->mode = 'normal'; if (!empty($mode)) { $userdata->mode = $mode; } if ($userdata->mode == 'normal') { $userdata->credit = 'credit'; } else { $userdata->credit = 'no-credit'; } if (isset($userdata->status)) { if ($userdata->status == '') { $userdata->entry = 'ab-initio'; } else { if (isset($userdata->{'cmi.core.exit'}) && $userdata->{'cmi.core.exit'} == 'suspend') { $userdata->entry = 'resume'; } else { $userdata->entry = ''; } } } $def = array(); $def['cmi.core.student_id'] = $userdata->student_id; $def['cmi.core.student_name'] = $userdata->student_name; $def['cmi.core.credit'] = $userdata->credit; $def['cmi.core.entry'] = $userdata->entry; $def['cmi.launch_data'] = scorm_isset($userdata, 'datafromlms'); $def['cmi.core.lesson_mode'] = $userdata->mode; $def['cmi.student_data.attempt_number'] = scorm_isset($userdata, 'cmi.student_data.attempt_number'); $def['cmi.student_data.mastery_score'] = scorm_isset($userdata, 'mastery_score'); $def['cmi.student_data.max_time_allowed'] = scorm_isset($userdata, 'max_time_allowed'); $def['cmi.student_data.time_limit_action'] = scorm_isset($userdata, 'time_limit_action'); $def['cmi.student_data.tries_during_lesson'] = scorm_isset($userdata, 'cmi.student_data.tries_during_lesson'); $def['cmi.core.lesson_location'] = scorm_isset($userdata, 'cmi.core.lesson_location'); $def['cmi.core.lesson_status'] = scorm_isset($userdata, 'cmi.core.lesson_status'); $def['cmi.core.exit'] = scorm_isset($userdata, 'cmi.core.exit'); $def['cmi.core.score.raw'] = scorm_isset($userdata, 'cmi.core.score.raw'); $def['cmi.core.score.max'] = scorm_isset($userdata, 'cmi.core.score.max'); $def['cmi.core.score.min'] = scorm_isset($userdata, 'cmi.core.score.min'); $def['cmi.core.total_time'] = scorm_isset($userdata, 'cmi.core.total_time', '00:00:00'); $def['cmi.suspend_data'] = scorm_isset($userdata, 'cmi.suspend_data'); $def['cmi.comments'] = scorm_isset($userdata, 'cmi.comments'); return $def; }
function scorm_seq_set($what, $scoid, $userid, $attempt = 0, $value = 'true') { /// set passed activity to active or not if ($value == false) { delete_record('scorm_scoes_track', 'scoid', $scoid, 'userid', $userid, 'element', $what); } else { $sco = scorm_get_sco($scoid); scorm_insert_track($userid, $sco->scorm, $sco->id, 0, $what, $value); } }
$scorm = $DB->get_record("scorm", array("id" => $cm->instance), '*', MUST_EXIST); } else { if (!empty($a)) { $scorm = $DB->get_record("scorm", array("id" => $a), '*', MUST_EXIST); $course = $DB->get_record("course", array("id" => $scorm->course), '*', MUST_EXIST); $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id, false, MUST_EXIST); } 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', context_module::instance($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; } } }
} else { $userdata->status = ''; $userdata->score_raw = ''; } $userdata->student_id = addslashes($USER->username); $userdata->student_name = addslashes($USER->lastname . ', ' . $USER->firstname); $userdata->mode = 'normal'; if (isset($mode)) { $userdata->mode = $mode; } if ($userdata->mode == 'normal') { $userdata->credit = 'credit'; } else { $userdata->credit = 'no-credit'; } if ($scodatas = scorm_get_sco($scoid, SCO_DATA)) { foreach ($scodatas as $key => $value) { $userdata->{$key} = $value; } } else { error('Sco not found'); } $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe if (file_exists($CFG->dirroot . '/mod/scorm/datamodels/' . $scorm->version . '.js.php')) { include_once $CFG->dirroot . '/mod/scorm/datamodels/' . $scorm->version . '.js.php'; } else { include_once $CFG->dirroot . '/mod/scorm/datamodels/scorm_12.js.php'; } ?>
$PAGE->add_body_class('forcejavascript'); } require_login($course, false, $cm); $context = context_course::instance($course->id); $contextmodule = context_module::instance($cm->id); $launch = false; // Does this automatically trigger a launch based on skipview. if (!empty($scorm->popup)) { $orgidentifier = ''; $scoid = 0; if ($scorm->skipview >= SCORM_SKIPVIEW_FIRST && has_capability('mod/scorm:skipview', $contextmodule) && !has_capability('mod/scorm:viewreport', $contextmodule)) { // Don't skip users with the capability to view reports. // do we launch immediately and redirect the parent back ? if ($scorm->skipview == SCORM_SKIPVIEW_ALWAYS || !scorm_has_tracks($scorm->id, $USER->id)) { $orgidentifier = ''; if ($sco = scorm_get_sco($scorm->launch, SCO_ONLY)) { if ($sco->organization == '' && $sco->launch == '') { $orgidentifier = $sco->identifier; } else { $orgidentifier = $sco->organization; } $scoid = $sco->id; } $launch = true; } } // Redirect back to the section with one section per page ? $courseformat = course_get_format($course)->get_course(); $sectionid = ''; if (isset($courseformat->coursedisplay) && $courseformat->coursedisplay == COURSE_DISPLAY_MULTIPAGE) { $sectionid = $cm->sectionnum;
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_last_attempt($scorm->id, $user->id); } $result = new stdClass(); $organizationsco = null; if ($tocheader) { $result->toc = html_writer::start_div('yui3-g-r', array('id' => 'scorm_layout')); $result->toc .= html_writer::start_div('yui3-u-1-5', array('id' => 'scorm_toc')); $result->toc .= html_writer::div('', '', array('id' => 'scorm_toc_title')); $result->toc .= html_writer::start_div('', array('id' => 'scorm_tree')); } 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)) { // If this is a normal package with an org sco and child scos get the first child. if (!empty($scoes['scoes'][0]->children)) { $result->sco = $scoes['scoes'][0]->children[0]; } else { // This package only has one sco - it may be a simple external AICC package. $result->sco = $scoes['scoes'][0]; } } 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 != 'normal') { $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 .= html_writer::end_div() . html_writer::end_div(); $result->toc .= html_writer::start_div('', array('id' => 'scorm_toc_toggle')); $result->toc .= html_writer::tag('button', '', array('id' => 'scorm_toc_toggle_btn')) . html_writer::end_div(); $result->toc .= html_writer::start_div('', array('id' => 'scorm_content')); $result->toc .= html_writer::div('', '', array('id' => 'scorm_navpanel')); $result->toc .= html_writer::end_div() . html_writer::end_div(); } return $result; }
/** * Retrieves SCO tracking data for the given user id and attempt number * * @param int $scoid the sco id * @param int $userid the user id * @param int $attempt the attempt number * @return array warnings and the scoes data * @since Moodle 3.0 */ public static function get_scorm_sco_tracks($scoid, $userid, $attempt = 0) { global $USER, $DB; $params = self::validate_parameters(self::get_scorm_sco_tracks_parameters(), array('scoid' => $scoid, 'userid' => $userid, 'attempt' => $attempt)); $tracks = array(); $warnings = array(); $sco = scorm_get_sco($params['scoid'], SCO_ONLY); if (!$sco) { throw new moodle_exception('cannotfindsco', 'scorm'); } $scorm = $DB->get_record('scorm', array('id' => $sco->scorm), '*', MUST_EXIST); $cm = get_coursemodule_from_instance('scorm', $scorm->id); $context = context_module::instance($cm->id); self::validate_context($context); $user = core_user::get_user($params['userid'], '*', MUST_EXIST); core_user::require_active_user($user); // Extra checks so only users with permissions can view other users attempts. if ($USER->id != $user->id) { require_capability('mod/scorm:viewreport', $context); } scorm_require_available($scorm, true, $context); if (empty($params['attempt'])) { $params['attempt'] = scorm_get_last_attempt($scorm->id, $user->id); } $attempted = false; if ($scormtracks = scorm_get_tracks($sco->id, $params['userid'], $params['attempt'])) { // Check if attempted. if ($scormtracks->status != '') { $attempted = true; foreach ($scormtracks as $element => $value) { $tracks[] = array('element' => $element, 'value' => $value); } } } if (!$attempted) { $warnings[] = array('item' => 'attempt', 'itemid' => $params['attempt'], 'warningcode' => 'notattempted', 'message' => get_string('notattempted', 'scorm')); } $result = array(); $result['data']['attempt'] = $params['attempt']; $result['data']['tracks'] = $tracks; $result['warnings'] = $warnings; return $result; }
function scorm_get_toc($user, $scorm, $liststyle, $currentorg = '', $scoid = '', $mode = 'normal', $attempt = '', $play = false) { global $CFG, $DB, $PAGE, $OUTPUT; $strexpand = get_string('expcoll', 'scorm'); $modestr = ''; if ($mode == 'browse') { $modestr = '&mode=' . $mode; } $result = new stdClass(); $result->toc = "<ul id='s0' class='{$liststyle}'>\n"; $tocmenus = array(); $result->prerequisites = true; $incomplete = false; // // Get the current organization infos // if (!empty($currentorg)) { if (($organizationtitle = $DB->get_field('scorm_scoes', 'title', array('scorm' => $scorm->id, 'identifier' => $currentorg))) != '') { $result->toc .= "\t<li>{$organizationtitle}</li>\n"; $tocmenus[] = $organizationtitle; } } // // If not specified retrieve the last attempt number // if (empty($attempt)) { $attempt = scorm_get_last_attempt($scorm->id, $user->id); } $result->attemptleft = $scorm->maxattempt - $attempt; $conditions['scorm'] = $scorm->id; if ($scoes = scorm_get_scoes($scorm->id, $currentorg)) { // // 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->status == '') { $usertrack->status = 'notattempted'; } $usertracks[$sco->identifier] = $usertrack; } } } $level = 0; $sublist = 1; $previd = 0; $nextid = 0; $findnext = false; $parents[$level] = '/'; 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) { if ($newlevel = array_search($sco->parent, $parents)) { for ($i = 0; $i < $level - $newlevel; $i++) { $result->toc .= "\t\t</ul></li>\n"; } $level = $newlevel; } else { $i = $level; $closelist = ''; while ($i > 0 && $parents[$level] != $sco->parent) { $closelist .= "\t\t</ul></li>\n"; $i--; } if ($i == 0 && $sco->parent != $currentorg) { $style = ''; if (isset($_COOKIE['hide:SCORMitem' . $sco->id])) { $style = ' style="display: none;"'; } $result->toc .= "\t\t<li><ul id='s{$sublist}' class='{$liststyle}'{$style}>\n"; $level++; } else { $result->toc .= $closelist; $level = $i; } $parents[$level] = $sco->parent; } } if ($isvisible) { $result->toc .= "\t\t<li>"; } 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++; $icon = 'minus'; if (isset($_COOKIE['hide:SCORMitem' . $nextsco->id])) { $icon = 'plus'; } $result->toc .= '<a href="javascript:expandCollide(\'img' . $sublist . '\',\'s' . $sublist . '\',' . $nextsco->id . ');"><img id="img' . $sublist . '" src="' . $OUTPUT->mod_icon_url('pix/' . $icon, 'scorm') . '" alt="' . $strexpand . '" title="' . $strexpand . '"/></a>'; } else { if ($isvisible) { $result->toc .= '<img src="' . $OUTPUT->mod_icon_url('pix/spacer', 'scorm') . '" alt="" />'; } } if (empty($sco->title)) { $sco->title = $sco->identifier; } if (!empty($sco->launch)) { if ($isvisible) { $startbold = ''; $endbold = ''; $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 = '<img src="' . $OUTPUT->mod_icon_url('pix/' . $usertrack->status, 'scorm') . '" alt="' . $strstatus . '" title="' . $strstatus . '" />'; } else { $statusicon = '<img src="' . $OUTPUT->mod_icon_url('pix/assetc/', 'scorm') . '" alt="' . get_string('assetlaunched', 'scorm') . '" title="' . get_string('assetlaunched', 'scorm') . '" />'; } if ($usertrack->status == 'notattempted' || $usertrack->status == 'incomplete' || $usertrack->status == 'browsed') { $incomplete = true; if ($play && empty($scoid)) { $scoid = $sco->id; } } if ($usertrack->score_raw != '') { $score = '(' . get_string('score', 'scorm') . ': ' . $usertrack->score_raw . ')'; } $strsuspended = get_string('suspended', 'scorm'); if (isset($usertrack->{'cmi.core.exit'}) && $usertrack->{'cmi.core.exit'} == 'suspend') { if ($usertrack->status != 'completed') { $statusicon = '<img src="' . $OUTPUT->mod_icon_url('pix/suspend', 'scorm') . '" alt="' . $strstatus . ' - ' . $strsuspended . '" title="' . $strstatus . ' - ' . $strsuspended . '" />'; } } } else { if ($play && empty($scoid)) { $scoid = $sco->id; } $incomplete = true; if ($sco->scormtype == 'sco') { $statusicon = '<img src="' . $OUTPUT->mod_icon_url('pix/notattempted', 'scorm') . '" alt="' . get_string('notattempted', 'scorm') . '" title="' . get_string('notattempted', 'scorm') . '" />'; } else { $statusicon = '<img src="' . $OUTPUT->mod_icon_url('pix/asset', 'scorm') . '" alt="' . get_string('asset', 'scorm') . '" title="' . get_string('asset', 'scorm') . '" />'; } } if ($sco->id == $scoid) { $startbold = '<b>'; $endbold = '</b>'; $findnext = true; $shownext = isset($sco->next) ? $sco->next : 0; $showprev = isset($sco->previous) ? $sco->previous : 0; } if ($nextid == 0 && scorm_count_launchable($scorm->id, $currentorg) > 1 && $nextsco !== false && !$findnext) { if (!empty($sco->launch)) { $previd = $sco->id; } } if (empty($sco->prerequisites) || scorm_eval_prerequisites($sco->prerequisites, $usertracks)) { if ($sco->id == $scoid) { $result->prerequisites = true; } $url = $CFG->wwwroot . '/mod/scorm/player.php?a=' . $scorm->id . '&currentorg=' . $currentorg . $modestr . '&scoid=' . $sco->id; $result->toc .= $statusicon . ' ' . $startbold . '<a href="' . $url . '">' . format_string($sco->title) . '</a>' . $score . $endbold . "</li>\n"; $tocmenus[$sco->id] = scorm_repeater('−', $level) . '>' . format_string($sco->title); } else { if ($sco->id == $scoid) { $result->prerequisites = false; } $result->toc .= $statusicon . ' ' . format_string($sco->title) . "</li>\n"; } } } else { $result->toc .= ' ' . format_string($sco->title) . "</li>\n"; } if ($nextsco !== false && $nextid == 0 && $findnext) { if (!empty($nextsco->launch)) { $nextid = $nextsco->id; } } } for ($i = 0; $i < $level; $i++) { $result->toc .= "\t\t</ul></li>\n"; } if ($play) { // it is possible that scoid is still not set, in this case we dont 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 .= "\t</ul>\n"; if ($scorm->hidetoc == 0) { $PAGE->requires->data_for_js('scormdata', array('plusicon' => $OUTPUT->mod_icon_url('pix/plus', 'scorm'), 'minusicon' => $OUTPUT->mod_icon_url('pix/minus', 'scorm'))); $PAGE->requires->js('mod/scorm/datamodels/scorm_datamodels.js'); } $url = $CFG->wwwroot . '/mod/scorm/player.php?a=' . $scorm->id . '¤torg=' . $currentorg . $modestr; $select = html_select::make_popup_form($url, 'scoid', $tocmenus, "tocmenu", $sco->id); $select->nothinglabel = false; $result->tocmenu = $OUTPUT->select($select); return $result; }
function scorm_get_parent($sco) { if ($sco->parent != '/') { if ($parent = get_record('scorm_scoes', 'scorm', $sco->scorm, 'identifier', $sco->parent)) { return scorm_get_sco($parent->id); } } return null; }
/** * Trigger the course module viewed event. * * @param int $scormid the SCORM instance id * @param int $scoid the SCO id * @return array of warnings and status result * @since Moodle 3.1 * @throws moodle_exception */ public static function launch_sco($scormid, $scoid = 0) { global $DB; $params = self::validate_parameters(self::launch_sco_parameters(), array('scormid' => $scormid, 'scoid' => $scoid)); $warnings = array(); // Request and permission validation. $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST); list($course, $cm) = get_course_and_cm_from_instance($scorm, 'scorm'); $context = context_module::instance($cm->id); self::validate_context($context); // If the SCORM is not open this function will throw exceptions. scorm_require_available($scorm); if (!empty($params['scoid']) and !($sco = scorm_get_sco($params['scoid'], SCO_ONLY))) { throw new moodle_exception('cannotfindsco', 'scorm'); } list($sco, $scolaunchurl) = scorm_get_sco_and_launch_url($scorm, $params['scoid'], $context); // Trigger the SCO launched event. scorm_launch_sco($scorm, $sco, $cm, $context, $scolaunchurl); $result = array(); $result['status'] = true; $result['warnings'] = $warnings; return $result; }
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': // I think I can use this condition instead equivalent to OR. if (array_search(false, $childrenbag) === false && array_search('unknown', $childrenbag) === false) { $change = true; } break; case 'any': // I think I can use this condition instead equivalent to OR. if (array_search(true, $childrenbag) !== false) { $change = true; } break; case 'none': // I think I can use this condition instead equivalent to OR. if (array_search(true, $childrenbag) === false && array_search('unknown', $childrenbag) === false) { $change = true; } break; case 'atleastcount': // I think I can use this condition instead equivalent to OR. foreach ($childrenbag as $itm) { $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 / count($childrenbag) >= $rolluprule->minimumcount) { $change = true; } } break; } if ($change == true) { return true; } } } return false; }
/** * Sets up $userdata array and default values for SCORM 1.3 . * * @param stdClass $userdata an empty stdClass variable that should be set up with user values * @param object $scorm package record * @param string $scoid SCO Id * @param string $attempt attempt number for the user * @param string $mode scorm display mode type * @return array The default values that should be used for SCORM 1.3 package */ function get_scorm_default(&$userdata, $scorm, $scoid, $attempt, $mode) { global $DB, $USER; $userdata->student_id = $USER->username; $userdata->student_name = $USER->lastname . ', ' . $USER->firstname; if ($usertrack = scorm_get_tracks($scoid, $USER->id, $attempt)) { // According to SCORM 2004(RTE V1, 4.2.8), only cmi.exit==suspend should allow previous datamodel elements on re-launch. if (isset($usertrack->{'cmi.exit'}) && $usertrack->{'cmi.exit'} == 'suspend') { foreach ($usertrack as $key => $value) { $userdata->{$key} = $value; } } else { $userdata->status = ''; $userdata->score_raw = ''; } } else { $userdata->status = ''; $userdata->score_raw = ''; } if ($scodatas = scorm_get_sco($scoid, SCO_DATA)) { foreach ($scodatas as $key => $value) { $userdata->{$key} = $value; } } else { print_error('cannotfindsco', 'scorm'); } if (!($sco = scorm_get_sco($scoid))) { print_error('cannotfindsco', 'scorm'); } if (isset($userdata->status)) { if (!isset($userdata->{'cmi.exit'}) || $userdata->{'cmi.exit'} == 'time-out' || $userdata->{'cmi.exit'} == 'normal') { $userdata->entry = 'ab-initio'; } else { if (isset($userdata->{'cmi.exit'}) && ($userdata->{'cmi.exit'} == 'suspend' || $userdata->{'cmi.exit'} == 'logout')) { $userdata->entry = 'resume'; } else { $userdata->entry = ''; } } } $userdata->mode = 'normal'; if (!empty($mode)) { $userdata->mode = $mode; } if ($userdata->mode == 'normal') { $userdata->credit = 'credit'; } else { $userdata->credit = 'no-credit'; } $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++; } } $def = array(); $def['cmi.learner_id'] = $userdata->student_id; $def['cmi.learner_name'] = $userdata->student_name; $def['cmi.mode'] = $userdata->mode; $def['cmi.entry'] = $userdata->entry; $def['cmi.exit'] = scorm_isset($userdata, 'cmi.exit'); $def['cmi.credit'] = scorm_isset($userdata, 'credit'); $def['cmi.completion_status'] = scorm_isset($userdata, 'cmi.completion_status', 'unknown'); $def['cmi.completion_threshold'] = scorm_isset($userdata, 'threshold'); $def['cmi.learner_preference.audio_level'] = scorm_isset($userdata, 'cmi.learner_preference.audio_level', 1); $def['cmi.learner_preference.language'] = scorm_isset($userdata, 'cmi.learner_preference.language'); $def['cmi.learner_preference.delivery_speed'] = scorm_isset($userdata, 'cmi.learner_preference.delivery_speed'); $def['cmi.learner_preference.audio_captioning'] = scorm_isset($userdata, 'cmi.learner_preference.audio_captioning', 0); $def['cmi.location'] = scorm_isset($userdata, 'cmi.location'); $def['cmi.max_time_allowed'] = scorm_isset($userdata, 'attemptAbsoluteDurationLimit'); $def['cmi.progress_measure'] = scorm_isset($userdata, 'cmi.progress_measure'); $def['cmi.scaled_passing_score'] = scorm_isset($userdata, 'cmi.scaled_passing_score'); $def['cmi.score.scaled'] = scorm_isset($userdata, 'cmi.score.scaled'); $def['cmi.score.raw'] = scorm_isset($userdata, 'cmi.score.raw'); $def['cmi.score.min'] = scorm_isset($userdata, 'cmi.score.min'); $def['cmi.score.max'] = scorm_isset($userdata, 'cmi.score.max'); $def['cmi.success_status'] = scorm_isset($userdata, 'cmi.success_status', 'unknown'); $def['cmi.suspend_data'] = scorm_isset($userdata, 'cmi.suspend_data'); $def['cmi.time_limit_action'] = scorm_isset($userdata, 'timelimitaction'); $def['cmi.total_time'] = scorm_isset($userdata, 'cmi.total_time', 'PT0H0M0S'); return $def; }
function scorm_view_display($user, $scorm, $action, $cm, $boxwidth = '') { global $CFG; if ($scorm->updatefreq == UPDATE_EVERYTIME) { require_once $CFG->dirroot . '/mod/scorm/lib.php'; $scorm->instance = $scorm->id; scorm_update_instance($scorm); } $organization = optional_param('organization', '', PARAM_INT); print_simple_box_start('center', $boxwidth); ?> <div class="structurehead"><?php print_string('contents', 'scorm'); ?> </div> <?php if (empty($organization)) { $organization = $scorm->launch; } if ($orgs = get_records_select_menu('scorm_scoes', "scorm='{$scorm->id}' AND organization='' AND launch=''", 'id', 'id,title')) { if (count($orgs) > 1) { ?> <div class='scorm-center'> <?php print_string('organizations', 'scorm'); ?> <form id='changeorg' method='post' action='<?php echo $action; ?> '> <?php choose_from_menu($orgs, 'organization', "{$organization}", '', 'submit()'); ?> </form> </div> <?php } } $orgidentifier = ''; if ($sco = scorm_get_sco($organization, SCO_ONLY)) { if ($sco->organization == '' && $sco->launch == '') { $orgidentifier = $sco->identifier; } else { $orgidentifier = $sco->organization; } } /* $orgidentifier = ''; if ($org = get_record('scorm_scoes','id',$organization)) { if (($org->organization == '') && ($org->launch == '')) { $orgidentifier = $org->identifier; } else { $orgidentifier = $org->organization; } }*/ $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe if (!file_exists($CFG->dirroot . '/mod/scorm/datamodels/' . $scorm->version . 'lib.php')) { $scorm->version = 'scorm_12'; } require_once $CFG->dirroot . '/mod/scorm/datamodels/' . $scorm->version . 'lib.php'; $result = scorm_get_toc($user, $scorm, 'structlist', $orgidentifier); $incomplete = $result->incomplete; echo $result->toc; print_simple_box_end(); ?> <div class="scorm-center"> <form id="theform" method="post" action="<?php echo $CFG->wwwroot; ?> /mod/scorm/player.php"> <?php if ($scorm->hidebrowse == 0) { print_string('mode', 'scorm'); echo ': <input type="radio" id="b" name="mode" value="browse" /><label for="b">' . get_string('browse', 'scorm') . '</label>' . "\n"; echo '<input type="radio" id="n" name="mode" value="normal" checked="checked" /><label for="n">' . get_string('normal', 'scorm') . "</label>\n"; } else { echo '<input type="hidden" name="mode" value="normal" />' . "\n"; } if ($incomplete === false && ($result->attemptleft > 0 || $scorm->maxattempt == 0)) { ?> <br /> <input type="checkbox" id="a" name="newattempt" /> <label for="a"><?php print_string('newattempt', 'scorm'); ?> </label> <?php } ?> <br /> <input type="hidden" name="scoid"/> <input type="hidden" name="id" value="<?php echo $cm->id; ?> "/> <input type="hidden" name="currentorg" value="<?php echo $orgidentifier; ?> " /> <input type="submit" value="<?php print_string('enter', 'scorm'); ?> " /> </form> </div> <?php }
function scorm_view_display ($user, $scorm, $action, $cm) { global $CFG, $DB, $PAGE, $OUTPUT; if ($scorm->updatefreq == UPDATE_EVERYTIME) { scorm_parse($scorm, false); } $organization = optional_param('organization', '', PARAM_INT); if($scorm->displaycoursestructure == 1) { echo $OUTPUT->box_start('generalbox boxaligncenter toc'); ?> <div class="structurehead"><?php print_string('contents','scorm') ?></div> <?php } if (empty($organization)) { $organization = $scorm->launch; } if ($orgs = $DB->get_records_select_menu('scorm_scoes', 'scorm = ? AND '. $DB->sql_isempty('scorm_scoes', 'launch', false, true).' AND '. $DB->sql_isempty('scorm_scoes', 'organization', false, false), array($scorm->id),'id','id,title')) { if (count($orgs) > 1) { $select = new single_select(new moodle_url($action), 'organization', $orgs, $organization, null); $select->label = get_string('organizations','scorm'); $select->class = 'scorm-center'; echo $OUTPUT->render($select); } } $orgidentifier = ''; if ($sco = scorm_get_sco($organization, SCO_ONLY)) { if (($sco->organization == '') && ($sco->launch == '')) { $orgidentifier = $sco->identifier; } else { $orgidentifier = $sco->organization; } } $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe if (!file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php')) { $scorm->version = 'scorm_12'; } require_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php'); $result = scorm_get_toc($user,$scorm,$cm->id,TOCFULLURL,$orgidentifier); $incomplete = $result->incomplete; // do we want the TOC to be displayed? if($scorm->displaycoursestructure == 1) { echo $result->toc; echo $OUTPUT->box_end(); } // is this the first attempt ? $attemptcount = scorm_get_attempt_count($user->id, $scorm); // do not give the player launch FORM if the SCORM object is locked after the final attempt if ($scorm->lastattemptlock == 0 || $result->attemptleft > 0) { ?> <div class="scorm-center"> <form id="theform" method="post" action="<?php echo $CFG->wwwroot ?>/mod/scorm/player.php"> <?php if ($scorm->hidebrowse == 0) { print_string('mode','scorm'); echo ': <input type="radio" id="b" name="mode" value="browse" /><label for="b">'.get_string('browse','scorm').'</label>'."\n"; echo '<input type="radio" id="n" name="mode" value="normal" checked="checked" /><label for="n">'.get_string('normal','scorm')."</label>\n"; } else { echo '<input type="hidden" name="mode" value="normal" />'."\n"; } if ($scorm->forcenewattempt == 1) { if ($incomplete === false) { echo '<input type="hidden" name="newattempt" value="on" />'."\n"; } } elseif (!empty($attemptcount) && ($incomplete === false) && (($result->attemptleft > 0)||($scorm->maxattempt == 0))) { ?> <br /> <input type="checkbox" id="a" name="newattempt" /> <label for="a"><?php print_string('newattempt','scorm') ?></label> <?php } ?> <br /> <input type="hidden" name="scoid"/> <input type="hidden" name="cm" value="<?php echo $cm->id ?>"/> <input type="hidden" name="currentorg" value="<?php echo $orgidentifier ?>" /> <input type="submit" value="<?php print_string('enter','scorm') ?>" /> </form> </div> <?php } }
if (!empty($mode)) { $userdata->mode = $mode; } if ($userdata->mode == 'normal') { $userdata->credit = 'credit'; } else { $userdata->credit = 'no-credit'; } if ($scodatas = scorm_get_sco($scoid, SCO_DATA)) { foreach ($scodatas as $key => $value) { $userdata->$key = addslashes_js($value); } } else { print_error('cannotfindsco', 'scorm'); } if (!$sco = scorm_get_sco($scoid)) { print_error('cannotfindsco', 'scorm'); } if (scorm_version_check($scorm->version, SCORM_13)) { $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++; } } }
/** * Retrieves SCO tracking data for the given user id and attempt number * * @param int $scoid the sco id * @param int $userid the user id * @param int $attempt the attempt number * @return array warnings and the scoes data * @since Moodle 3.0 */ public static function get_scorm_sco_tracks($scoid, $userid, $attempt = 0) { global $USER, $DB; $params = self::validate_parameters(self::get_scorm_sco_tracks_parameters(), array('scoid' => $scoid, 'userid' => $userid, 'attempt' => $attempt)); $tracks = array(); $warnings = array(); $sco = scorm_get_sco($params['scoid'], SCO_ONLY); if (!$sco) { throw new moodle_exception('cannotfindsco', 'scorm'); } $scorm = $DB->get_record('scorm', array('id' => $sco->scorm), '*', MUST_EXIST); $cm = get_coursemodule_from_instance('scorm', $scorm->id); $context = context_module::instance($cm->id); self::validate_context($context); // Validate the user obtaining the context, it will fail if the user doesn't exists or have been deleted. context_user::instance($params['userid']); // Extra checks so only users with permissions can view other users attempts. if ($USER->id != $params['userid']) { require_capability('mod/scorm:viewreport', $context); } scorm_require_available($scorm, true, $context); if (empty($params['attempt'])) { $params['attempt'] = scorm_get_last_attempt($scorm->id, $params['userid']); } if ($scormtracks = scorm_get_tracks($sco->id, $params['userid'], $params['attempt'])) { foreach ($scormtracks as $element => $value) { $tracks[] = array( 'element' => $element, 'value' => $value, ); } } $result = array(); $result['data']['attempt'] = $params['attempt']; $result['data']['tracks'] = $tracks; $result['warnings'] = $warnings; return $result; }
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_last_attempt($scorm->id, $user->id); } $result = new stdClass(); $organizationsco = null; if ($tocheader) { $result->toc = "<div id=\"scorm_layout\" class=\"yui3-g-r\">\n"; $result->toc .= "<div id=\"scorm_toc\" class=\"yui3-u-1-5\">\n"; $result->toc .= "<div id=\"scorm_toc_title\"></div>\n"; $result->toc .= "<div id=\"scorm_tree\">\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[0]; } 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 != 'normal') { $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 .= "</div></div>\n"; $result->toc .= "<div id=\"scorm_toc_toggle\">\n"; $result->toc .= "<button id=\"scorm_toc_toggle_btn\"></button></div>\n"; $result->toc .= "<div id=\"scorm_content\">"; $result->toc .= "<div id=\"scorm_navpanel\"></div>\n"; $result->toc .= "</div></div>\n"; } return $result; }
function scorm_tcapi_store_statement($params, $statementObject) { global $CFG, $USER, $DB, $SESSION; if (isset($params['actor']) && isset($params['actor']->moodle_user)) $userid = $params['actor']->moodle_user; else $userid = $USER->id; if (isset($params['moodle_mod_id'])) $scoid = $params['moodle_mod_id']; else throw new invalid_parameter_exception('Module id not provided.'); require_once($CFG->dirroot.'/mod/scorm/locallib.php'); if (($sco = scorm_get_sco($scoid)) && ($attempt = scorm_get_last_attempt($sco->scorm, $userid))) { $usertrack = scorm_get_tracks($scoid, $userid, $attempt); // if the activity is considered complete, only update the time if it doesn't yet exist $attempt_complete = ($usertrack && (($usertrack->status == 'completed') || ($usertrack->status == 'passed') || ($usertrack->status == 'failed'))); $statement = $statementObject->statement; $statementRow = $statementObject->statementRow; // check that the incoming statement refers to the sco identifier if (isset($statement->activity)) { $sco_activity = $statement->activity; // TODO: Add support for interaction tracks for child results reporting. //if (!empty($statement->activity->grouping_id) && ($lrs_activity = $DB->get_record_select('tcapi_activity','id = ?',array($statement->activity->grouping_id)))) //$sco_activity = $lrs_activity; if ($sco->identifier == $sco_activity->activity_id) { // check for existing cmi.core.lesson_status // set default to 'incomplete' // check statement->verb and set cmi.core.lesson_status as appropriate $cmiCoreLessonStatus = (empty($usertrack->status) || $usertrack->status == 'notattempted') ? 'incomplete' : $usertrack->status; if (in_array(strtolower($statementRow->verb),array('completed','passed','mastered','failed'))) { $cmiCoreLessonStatus = strtolower($statementRow->verb); // Indicates activity status is complete $complStatus = ($cmiCoreLessonStatus !== 'failed') ? 'completed' : 'incomplete'; if (!$attempt_complete) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.completion_status', $complStatus); // Create/update track for cmi.core.lesson_status if (!$attempt_complete && in_array($cmiCoreLessonStatus,array('passed','failed','completed','incomplete'))) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.lesson_status', $cmiCoreLessonStatus); if (!$attempt_complete && in_array($cmiCoreLessonStatus,array('passed','failed'))) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.success_status', $cmiCoreLessonStatus); elseif (!isset($usertrack->{'cmi.success_status'})) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.success_status', 'unknown'); // check if any result was reported if (isset($statementObject->resultRow)) { $result = $statementObject->resultRow; // if a duration was reported, add to any existing total_time if (isset($result->duration)) { if ($usertrack->total_time == '00:00:00') $total_time = $result->duration; elseif (!$attempt_complete) $total_time = scorm_tcapi_add_time($result->duration, $usertrack->total_time); if (isset($total_time)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.total_time', $total_time); } if (isset($result->score) && !$attempt_complete) { $score = json_decode($result->score); if (isset($score->raw)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.raw', $score->raw); if (isset($score->min)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.min', $score->min); if (isset($score->max)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.max', $score->max); // if scaled is provided but no raw, calculate the raw as we need it for SCORM grades // try to use the min/max if available. if not, use 0/100 if (isset($score->scaled)) { if (!isset($score->raw)) { $scoremin = (isset($score->min)) ? $score->min : 0; $scoremax = (isset($score->max)) ? $score->max : 100; $score->raw = ($score->scaled*($scoremax-$scoremin))+$scoremin; scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.raw', $score->raw); if (!isset($score->min)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.min', $scoremin); if (!isset($score->max)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.max', $scoremax); } scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.score.scaled', $score->scaled); } } } } if ($attempt_complete) return $statementObject->statementId; // set cmi.core.exit to suspend if status is incomplete, else remove the track entry if ($cmiCoreLessonStatus == 'incomplete') scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.exit', 'suspend'); elseif ($track = $DB->get_record('scorm_scoes_track', array('userid'=>$userid, 'scormid'=>$sco->scorm, 'scoid'=>$scoid, 'attempt'=>$attempt, 'element'=>'cmi.core.exit'))) $DB->delete_records_select('scorm_scoes_track', 'id = ?', array($track->id)); } } } else throw new invalid_parameter_exception('Parameters invalid or Scorm/Sco not found.'); return $statementObject->statementId; }