/** * Get the data for the report. * * @param int $scoid The sco ID. * @param array $allowedlist The list of user IDs allowed to be displayed. * @return array of data indexed per bar. */ protected function get_data($scoid, $allowedlist = []) { global $DB; $data = array_fill(0, self::BANDS, 0); if (empty($allowedlist)) { return $data; } list($usql, $params) = $DB->get_in_or_equal($allowedlist); $params[] = $scoid; // Construct the SQL. $sql = "SELECT DISTINCT " . $DB->sql_concat('st.userid', '\'#\'', 'COALESCE(st.attempt, 0)') . " AS uniqueid,\n st.userid AS userid,\n st.scormid AS scormid,\n st.attempt AS attempt,\n st.scoid AS scoid\n FROM {scorm_scoes_track} st\n WHERE st.userid {$usql} AND st.scoid = ?"; $attempts = $DB->get_records_sql($sql, $params); $usergrades = []; foreach ($attempts as $attempt) { if ($trackdata = scorm_get_tracks($scoid, $attempt->userid, $attempt->attempt)) { if (isset($trackdata->score_raw)) { $score = $trackdata->score_raw; if (empty($trackdata->score_min)) { $minmark = 0; } else { $minmark = $trackdata->score_min; } // TODO MDL-55004: Get this value from elsewhere? if (empty($trackdata->score_max)) { $maxmark = 100; } else { $maxmark = $trackdata->score_max; } $range = $maxmark - $minmark; if (empty($range)) { continue; } $percent = round($score * 100 / $range, 2); if (empty($usergrades[$attempt->userid]) || !isset($usergrades[$attempt->userid]) || $percent > $usergrades[$attempt->userid] || $usergrades[$attempt->userid] === '*') { $usergrades[$attempt->userid] = $percent; } unset($percent); } else { // User has made an attempt but either SCO was not able to record the score or something else is broken in SCO. if (!isset($usergrades[$attempt->userid])) { $usergrades[$attempt->userid] = '*'; } } } } // Recording all users who attempted the SCO, but resulting data was invalid. foreach ($usergrades as $userpercent) { if ($userpercent === '*') { $data[0]++; } else { $gradeband = floor($userpercent / self::BANDWIDTH); if ($gradeband != self::BANDS - 1) { $gradeband++; } $data[$gradeband]++; } } return $data; }
function scorm_simple_play($scorm, $user, $context) { $result = false; if ($scorm->updatefreq == UPDATE_EVERYTIME) { if (strpos($scorm->version, 'AICC') !== false) { $scorm->pkgtype = 'AICC'; } else { $scorm->pkgtype = 'SCORM'; } scorm_parse($scorm); } if (has_capability('mod/scorm:viewreport', $context)) { //if this user can view reports, don't skipview so they can see links to reports. return $result; } $scoes = get_records_select('scorm_scoes', 'scorm=' . $scorm->id . ' AND launch<>\'' . sql_empty() . '\'', 'id', 'id'); if ($scoes) { if ($scorm->skipview >= 1) { $sco = current($scoes); if (scorm_get_tracks($sco->id, $user->id) === false) { header('Location: player.php?a=' . $scorm->id . '&scoid=' . $sco->id); $result = true; } else { if ($scorm->skipview == 2) { header('Location: player.php?a=' . $scorm->id . '&scoid=' . $sco->id); $result = true; } } } } return $result; }
$course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST); $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/loaddatamodel.php', array('scoid'=>$scoid, 'id'=>$cm->id)); require_login($course, false, $cm); $userdata = new stdClass(); if ($usertrack = scorm_get_tracks($scoid, $USER->id, $attempt)) { // According to SCORM 2004 spec(RTE V1, 4.2.8), only cmi.exit==suspend should allow previous datamodel elements on re-launch. if (!scorm_version_check($scorm->version, SCORM_13) || (isset($usertrack->{'cmi.exit'}) && ($usertrack->{'cmi.exit'} == 'suspend'))) { foreach ($usertrack as $key => $value) { $userdata->$key = addslashes_js($value); } } else { $userdata->status = ''; $userdata->score_raw = ''; } } else { $userdata->status = ''; $userdata->score_raw = ''; } $userdata->student_id = addslashes_js($USER->username);
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; 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 (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 .= "\t\t" . '<li><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 .= "\t\t" . '<li><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; } if ($sco->scormtype == 'sco') { $statusicon = '<img src="' . $OUTPUT->mod_icon_url('pix/notattempted', 'scorm') . '" alt="' . get_string('notattempted', 'scorm') . '" title="' . get_string('notattempted', 'scorm') . '" />'; $incomplete = true; } 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->prev) ? $sco->prev : 0; } if ($nextid == 0 && scorm_count_launchable($scorm->id, $currentorg) > 1 && $nextsco !== false && !$findnext) { if (!empty($sco->launch)) { $previd = $sco->id; } } require_once 'sequencinglib.php'; if (scorm_seq_evaluate($sco->id, $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 .= ' ' . 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) { $sco = $DB->get_record('scorm_scoes', array('id' => $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_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_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; }
/** * Print a detailed representation of what a user has done with * a given particular instance of this module, for user activity reports. * * @global stdClass * @global object * @param object $course * @param object $user * @param object $mod * @param object $scorm * @return boolean */ function scorm_user_complete($course, $user, $mod, $scorm) { global $CFG, $DB, $OUTPUT; require_once("$CFG->libdir/gradelib.php"); $liststyle = 'structlist'; $now = time(); $firstmodify = $now; $lastmodify = 0; $sometoreport = false; $report = ''; // First Access and Last Access dates for SCOs. require_once($CFG->dirroot.'/mod/scorm/locallib.php'); $timetracks = scorm_get_sco_runtime($scorm->id, false, $user->id); $firstmodify = $timetracks->start; $lastmodify = $timetracks->finish; $grades = grade_get_grades($course->id, 'mod', 'scorm', $scorm->id, $user->id); if (!empty($grades->items[0]->grades)) { $grade = reset($grades->items[0]->grades); echo $OUTPUT->container(get_string('grade').': '.$grade->str_long_grade); if ($grade->str_feedback) { echo $OUTPUT->container(get_string('feedback').': '.$grade->str_feedback); } } if ($orgs = $DB->get_records_select('scorm_scoes', 'scorm = ? AND '. $DB->sql_isempty('scorm_scoes', 'launch', false, true).' AND '. $DB->sql_isempty('scorm_scoes', 'organization', false, false), array($scorm->id), 'sortorder, id', 'id, identifier, title')) { if (count($orgs) <= 1) { unset($orgs); $orgs = array(); $org = new stdClass(); $org->identifier = ''; $orgs[] = $org; } $report .= html_writer::start_div('mod-scorm'); foreach ($orgs as $org) { $conditions = array(); $currentorg = ''; if (!empty($org->identifier)) { $report .= html_writer::div($org->title, 'orgtitle'); $currentorg = $org->identifier; $conditions['organization'] = $currentorg; } $report .= html_writer::start_tag('ul', array('id' => '0', 'class' => $liststyle)); $conditions['scorm'] = $scorm->id; if ($scoes = $DB->get_records('scorm_scoes', $conditions, "sortorder, id")) { // Drop keys so that we can access array sequentially. $scoes = array_values($scoes); $level = 0; $sublist = 1; $parents[$level] = '/'; foreach ($scoes as $pos => $sco) { if ($parents[$level] != $sco->parent) { if ($level > 0 && $parents[$level - 1] == $sco->parent) { $report .= html_writer::end_tag('ul').html_writer::end_tag('li'); $level--; } else { $i = $level; $closelist = ''; while (($i > 0) && ($parents[$level] != $sco->parent)) { $closelist .= html_writer::end_tag('ul').html_writer::end_tag('li'); $i--; } if (($i == 0) && ($sco->parent != $currentorg)) { $report .= html_writer::start_tag('li'); $report .= html_writer::start_tag('ul', array('id' => $sublist, 'class' => $liststyle)); $level++; } else { $report .= $closelist; $level = $i; } $parents[$level] = $sco->parent; } } $report .= html_writer::start_tag('li'); if (isset($scoes[$pos + 1])) { $nextsco = $scoes[$pos + 1]; } else { $nextsco = false; } if (($nextsco !== false) && ($sco->parent != $nextsco->parent) && (($level == 0) || (($level > 0) && ($nextsco->parent == $sco->identifier)))) { $sublist++; } else { $report .= $OUTPUT->spacer(array("height" => "12", "width" => "13")); } if ($sco->launch) { $score = ''; $totaltime = ''; if ($usertrack = scorm_get_tracks($sco->id, $user->id)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } $strstatus = get_string($usertrack->status, 'scorm'); $report .= html_writer::img($OUTPUT->pix_url($usertrack->status, 'scorm'), $strstatus, array('title' => $strstatus)); } else { if ($sco->scormtype == 'sco') { $report .= html_writer::img($OUTPUT->pix_url('notattempted', 'scorm'), get_string('notattempted', 'scorm'), array('title' => get_string('notattempted', 'scorm'))); } else { $report .= html_writer::img($OUTPUT->pix_url('asset', 'scorm'), get_string('asset', 'scorm'), array('title' => get_string('asset', 'scorm'))); } } $report .= " $sco->title $score$totaltime".html_writer::end_tag('li'); if ($usertrack !== false) { $sometoreport = true; $report .= html_writer::start_tag('li').html_writer::start_tag('ul', array('class' => $liststyle)); foreach ($usertrack as $element => $value) { if (substr($element, 0, 3) == 'cmi') { $report .= html_writer::tag('li', $element.' => '.s($value)); } } $report .= html_writer::end_tag('ul').html_writer::end_tag('li'); } } else { $report .= " $sco->title".html_writer::end_tag('li'); } } for ($i = 0; $i < $level; $i++) { $report .= html_writer::end_tag('ul').html_writer::end_tag('li'); } } $report .= html_writer::end_tag('ul').html_writer::empty_tag('br'); } $report .= html_writer::end_div(); } if ($sometoreport) { if ($firstmodify < $now) { $timeago = format_time($now - $firstmodify); echo get_string('firstaccess', 'scorm').': '.userdate($firstmodify).' ('.$timeago.")".html_writer::empty_tag('br'); } if ($lastmodify > 0) { $timeago = format_time($now - $lastmodify); echo get_string('lastaccess', 'scorm').': '.userdate($lastmodify).' ('.$timeago.")".html_writer::empty_tag('br'); } echo get_string('report', 'scorm').":".html_writer::empty_tag('br'); echo $report; } else { print_string('noactivity', 'scorm'); } return true; }
function scorm_simple_play($scorm, $user) { $result = false; $scoes = get_records_select('scorm_scoes', 'scorm=' . $scorm->id . ' AND launch<>\'\''); if (count($scoes) == 1) { if ($scorm->skipview >= 1) { $sco = current($scoes); if (scorm_get_tracks($sco->id, $user->id) === false) { header('Location: player.php?a=' . $scorm->id . '&scoid=' . $sco->id); $result = true; } else { if ($scorm->skipview == 2) { header('Location: player.php?a=' . $scorm->id . '&scoid=' . $sco->id); $result = true; } } } } return $result; }
/** * 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; }
$row[] = userdate($timetracks->start, get_string("strftimedatetime", "langconfig")); } else { $row[] = userdate($timetracks->start); } if ($download == 'ODS' || $download == 'Excel') { $row[] = userdate($timetracks->finish, get_string('strftimedatetime', 'langconfig')); } else { $row[] = userdate($timetracks->finish); } $row[] = scorm_grade_user_attempt($scorm, $scouser->userid, $scouser->attempt); } // print out all scores of attempt if ($scoes) { foreach ($scoes as $sco) { if ($sco->launch != '') { if ($trackdata = scorm_get_tracks($sco->id, $scouser->userid, $scouser->attempt)) { if ($trackdata->status == '') { $trackdata->status = 'notattempted'; } $strstatus = get_string($trackdata->status, 'scorm'); // if raw score exists, print it if ($trackdata->score_raw != '') { $score = $trackdata->score_raw; // add max score if it exists if ($scorm->version == 'SCORM_1.3') { $maxkey = 'cmi.score.max'; } else { $maxkey = 'cmi.core.score.max'; } if (isset($trackdata->{$maxkey})) { $score .= '/' . $trackdata->{$maxkey};
/** * 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_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; }
/** * Print a detailed representation of what a user has done with * a given particular instance of this module, for user activity reports. * * @global stdClass * @global object * @param object $course * @param object $user * @param object $mod * @param object $scorm * @return boolean */ function scorm_user_complete($course, $user, $mod, $scorm) { global $CFG, $DB, $OUTPUT; $liststyle = 'structlist'; $now = time(); $firstmodify = $now; $lastmodify = 0; $sometoreport = false; $report = ''; if ($orgs = $DB->get_records('scorm_scoes', array('scorm' => $scorm->id, 'organization' => '', 'launch' => ''), 'id', 'id,identifier,title')) { if (count($orgs) <= 1) { unset($orgs); $orgs[]->identifier = ''; } $report .= '<div class="mod-scorm">' . "\n"; foreach ($orgs as $org) { $conditions = array(); $currentorg = ''; if (!empty($org->identifier)) { $report .= '<div class="orgtitle">' . $org->title . '</div>'; $currentorg = $org->identifier; $conditions['organization'] = $currentorg; } $report .= "<ul id='0' class='{$liststyle}'>"; $conditions['scorm'] = $scorm->id; if ($scoes = $DB->get_records('scorm_scoes', $conditions, "id ASC")) { // drop keys so that we can access array sequentially $scoes = array_values($scoes); $level = 0; $sublist = 1; $parents[$level] = '/'; foreach ($scoes as $pos => $sco) { if ($parents[$level] != $sco->parent) { if ($level > 0 && $parents[$level - 1] == $sco->parent) { $report .= "\t\t</ul></li>\n"; $level--; } else { $i = $level; $closelist = ''; while ($i > 0 && $parents[$level] != $sco->parent) { $closelist .= "\t\t</ul></li>\n"; $i--; } if ($i == 0 && $sco->parent != $currentorg) { $report .= "\t\t<li><ul id='{$sublist}' class='{$liststyle}'>\n"; $level++; } else { $report .= $closelist; $level = $i; } $parents[$level] = $sco->parent; } } $report .= "\t\t<li>"; if (isset($scoes[$pos + 1])) { $nextsco = $scoes[$pos + 1]; } else { $nextsco = false; } if ($nextsco !== false && $sco->parent != $nextsco->parent && ($level == 0 || $level > 0 && $nextsco->parent == $sco->identifier)) { $sublist++; } else { $report .= '<img src="' . $OUTPUT->mod_icon_url('pix/spacer', 'scorm') . '" alt="" />'; } if ($sco->launch) { require_once 'locallib.php'; $score = ''; $totaltime = ''; if ($usertrack = scorm_get_tracks($sco->id, $user->id)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } $strstatus = get_string($usertrack->status, 'scorm'); $report .= "<img src='" . $OUTPUT->mod_icon_url('pix/' . $usertrack->status, 'scorm') . "' alt='{$strstatus}' title='{$strstatus}' />"; if ($usertrack->timemodified != 0) { if ($usertrack->timemodified > $lastmodify) { $lastmodify = $usertrack->timemodified; } if ($usertrack->timemodified < $firstmodify) { $firstmodify = $usertrack->timemodified; } } } else { if ($sco->scormtype == 'sco') { $report .= '<img src="' . $OUTPUT->mod_icon_url('pix/notattempted', 'scorm') . '" alt="' . get_string('notattempted', 'scorm') . '" title="' . get_string('notattempted', 'scorm') . '" />'; } else { $report .= '<img src="' . $OUTPUT->mod_icon_url('pix/asset', 'scorm') . '" alt="' . get_string('asset', 'scorm') . '" title="' . get_string('asset', 'scorm') . '" />'; } } $report .= " {$sco->title} {$score}{$totaltime}</li>\n"; if ($usertrack !== false) { $sometoreport = true; $report .= "\t\t\t<li><ul class='{$liststyle}'>\n"; foreach ($usertrack as $element => $value) { if (substr($element, 0, 3) == 'cmi') { $report .= '<li>' . $element . ' => ' . $value . '</li>'; } } $report .= "\t\t\t</ul></li>\n"; } } else { $report .= " {$sco->title}</li>\n"; } } for ($i = 0; $i < $level; $i++) { $report .= "\t\t</ul></li>\n"; } } $report .= "\t</ul><br />\n"; } $report .= "</div>\n"; } if ($sometoreport) { if ($firstmodify < $now) { $timeago = format_time($now - $firstmodify); echo get_string('firstaccess', 'scorm') . ': ' . userdate($firstmodify) . ' (' . $timeago . ")<br />\n"; } if ($lastmodify > 0) { $timeago = format_time($now - $lastmodify); echo get_string('lastaccess', 'scorm') . ': ' . userdate($lastmodify) . ' (' . $timeago . ")<br />\n"; } echo get_string('report', 'scorm') . ":<br />\n"; echo $report; } else { print_string('noactivity', 'scorm'); } return true; }
/** * displays the full report * @param \stdClass $scorm full SCORM object * @param \stdClass $cm - full course_module object * @param \stdClass $course - full course object * @param string $download - type of download being requested */ public function display($scorm, $cm, $course, $download) { global $CFG, $DB, $OUTPUT, $PAGE; $contextmodule = \context_module::instance($cm->id); $action = optional_param('action', '', PARAM_ALPHA); $attemptids = optional_param_array('attemptid', array(), PARAM_RAW); $attemptsmode = optional_param('attemptsmode', SCORM_REPORT_ATTEMPTS_ALL_STUDENTS, PARAM_INT); $PAGE->set_url(new \moodle_url($PAGE->url, array('attemptsmode' => $attemptsmode))); if ($action == 'delete' && has_capability('mod/scorm:deleteresponses', $contextmodule) && confirm_sesskey()) { if (scorm_delete_responses($attemptids, $scorm)) { // Delete responses. echo $OUTPUT->notification(get_string('scormresponsedeleted', 'scorm'), 'notifysuccess'); } } // Find out current groups mode. $currentgroup = groups_get_activity_group($cm, true); // Detailed report. $mform = new \mod_scorm_report_objectives_settings($PAGE->url, compact('currentgroup')); if ($fromform = $mform->get_data()) { $pagesize = $fromform->pagesize; $showobjectivescore = $fromform->objectivescore; set_user_preference('scorm_report_pagesize', $pagesize); set_user_preference('scorm_report_objectives_score', $showobjectivescore); } else { $pagesize = get_user_preferences('scorm_report_pagesize', 0); $showobjectivescore = get_user_preferences('scorm_report_objectives_score', 0); } if ($pagesize < 1) { $pagesize = SCORM_REPORT_DEFAULT_PAGE_SIZE; } // Select group menu. $displayoptions = array(); $displayoptions['attemptsmode'] = $attemptsmode; $displayoptions['objectivescore'] = $showobjectivescore; $mform->set_data($displayoptions + array('pagesize' => $pagesize)); if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used. if (!$download) { groups_print_activity_menu($cm, new \moodle_url($PAGE->url, $displayoptions)); } } $formattextoptions = array('context' => \context_course::instance($course->id)); // We only want to show the checkbox to delete attempts // if the user has permissions and if the report mode is showing attempts. $candelete = has_capability('mod/scorm:deleteresponses', $contextmodule) && $attemptsmode != SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO; // Select the students. $nostudents = false; if (empty($currentgroup)) { // All users who can attempt scoes. if (!($students = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id', '', '', '', '', '', false))) { echo $OUTPUT->notification(get_string('nostudentsyet')); $nostudents = true; $allowedlist = ''; } else { $allowedlist = array_keys($students); } unset($students); } else { // All users who can attempt scoes and who are in the currently selected group. $groupstudents = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id', '', '', '', $currentgroup, '', false); if (!$groupstudents) { echo $OUTPUT->notification(get_string('nostudentsingroup')); $nostudents = true; $groupstudents = array(); } $allowedlist = array_keys($groupstudents); unset($groupstudents); } if (!$nostudents) { // Now check if asked download of data. $coursecontext = \context_course::instance($course->id); if ($download) { $filename = clean_filename("{$course->shortname} " . format_string($scorm->name, true, $formattextoptions)); } // Define table columns. $columns = array(); $headers = array(); if (!$download && $candelete) { $columns[] = 'checkbox'; $headers[] = null; } if (!$download && $CFG->grade_report_showuserimage) { $columns[] = 'picture'; $headers[] = ''; } $columns[] = 'fullname'; $headers[] = get_string('name'); $extrafields = get_extra_user_fields($coursecontext); foreach ($extrafields as $field) { $columns[] = $field; $headers[] = get_user_field_name($field); } $columns[] = 'attempt'; $headers[] = get_string('attempt', 'scorm'); $columns[] = 'start'; $headers[] = get_string('started', 'scorm'); $columns[] = 'finish'; $headers[] = get_string('last', 'scorm'); $columns[] = 'score'; $headers[] = get_string('score', 'scorm'); $scoes = $DB->get_records('scorm_scoes', array("scorm" => $scorm->id), 'sortorder, id'); foreach ($scoes as $sco) { if ($sco->launch != '') { $columns[] = 'scograde' . $sco->id; $headers[] = format_string($sco->title, '', $formattextoptions); } } $params = array(); list($usql, $params) = $DB->get_in_or_equal($allowedlist, SQL_PARAMS_NAMED); // Construct the SQL. $select = 'SELECT DISTINCT ' . $DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)') . ' AS uniqueid, '; $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' . \user_picture::fields('u', array('idnumber'), 'userid') . get_extra_user_fields_sql($coursecontext, 'u', '', array('email', 'idnumber')) . ' '; // This part is the same for all cases - join users and scorm_scoes_track tables. $from = 'FROM {user} u '; $from .= 'LEFT JOIN {scorm_scoes_track} st ON st.userid = u.id AND st.scormid = ' . $scorm->id; switch ($attemptsmode) { case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH: // Show only students with attempts. $where = ' WHERE u.id ' . $usql . ' AND st.userid IS NOT NULL'; break; case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO: // Show only students without attempts. $where = ' WHERE u.id ' . $usql . ' AND st.userid IS NULL'; break; case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS: // Show all students with or without attempts. $where = ' WHERE u.id ' . $usql . ' AND (st.userid IS NOT NULL OR st.userid IS NULL)'; break; } $countsql = 'SELECT COUNT(DISTINCT(' . $DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)') . ')) AS nbresults, '; $countsql .= 'COUNT(DISTINCT(' . $DB->sql_concat('u.id', '\'#\'', 'st.attempt') . ')) AS nbattempts, '; $countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers '; $countsql .= $from . $where; $nbmaincolumns = count($columns); // Get number of main columns used. $objectives = get_scorm_objectives($scorm->id); $nosort = array(); foreach ($objectives as $scoid => $sco) { foreach ($sco as $id => $objectivename) { $colid = $scoid . 'objectivestatus' . $id; $columns[] = $colid; $nosort[] = $colid; if (!$displayoptions['objectivescore']) { // Display the objective name only. $headers[] = $objectivename; } else { // Display the objective status header with a "status" suffix to avoid confusion. $headers[] = $objectivename . ' ' . get_string('status', 'scormreport_objectives'); // Now print objective score headers. $colid = $scoid . 'objectivescore' . $id; $columns[] = $colid; $nosort[] = $colid; $headers[] = $objectivename . ' ' . get_string('score', 'scormreport_objectives'); } } } $emptycell = ''; // Used when an empty cell is being printed - in html we add a space. if (!$download) { $emptycell = ' '; $table = new \flexible_table('mod-scorm-report'); $table->define_columns($columns); $table->define_headers($headers); $table->define_baseurl($PAGE->url); $table->sortable(true); $table->collapsible(true); // This is done to prevent redundant data, when a user has multiple attempts. $table->column_suppress('picture'); $table->column_suppress('fullname'); foreach ($extrafields as $field) { $table->column_suppress($field); } foreach ($nosort as $field) { $table->no_sorting($field); } $table->no_sorting('start'); $table->no_sorting('finish'); $table->no_sorting('score'); $table->no_sorting('checkbox'); $table->no_sorting('picture'); foreach ($scoes as $sco) { if ($sco->launch != '') { $table->no_sorting('scograde' . $sco->id); } } $table->column_class('picture', 'picture'); $table->column_class('fullname', 'bold'); $table->column_class('score', 'bold'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'generaltable generalbox'); // Start working -- this is necessary as soon as the niceties are over. $table->setup(); } else { if ($download == 'ODS') { require_once "{$CFG->libdir}/odslib.class.php"; $filename .= ".ods"; // Creating a workbook. $workbook = new \MoodleODSWorkbook("-"); // Sending HTTP headers. $workbook->send($filename); // Creating the first worksheet. $sheettitle = get_string('report', 'scorm'); $myxls = $workbook->add_worksheet($sheettitle); // Format types. $format = $workbook->add_format(); $format->set_bold(0); $formatbc = $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb = $workbook->add_format(); $formatb->set_bold(1); $formaty = $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc = $workbook->add_format(); $formatc->set_align('center'); $formatr = $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg = $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); // Here starts workshhet headers. $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else { if ($download == 'Excel') { require_once "{$CFG->libdir}/excellib.class.php"; $filename .= ".xls"; // Creating a workbook. $workbook = new \MoodleExcelWorkbook("-"); // Sending HTTP headers. $workbook->send($filename); // Creating the first worksheet. $sheettitle = get_string('report', 'scorm'); $myxls = $workbook->add_worksheet($sheettitle); // Format types. $format = $workbook->add_format(); $format->set_bold(0); $formatbc = $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb = $workbook->add_format(); $formatb->set_bold(1); $formaty = $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc = $workbook->add_format(); $formatc->set_align('center'); $formatr = $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg = $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else { if ($download == 'CSV') { $csvexport = new \csv_export_writer("tab"); $csvexport->set_filename($filename, ".txt"); $csvexport->add_data($headers); } } } } if (!$download) { $sort = $table->get_sql_sort(); } else { $sort = ''; } // Fix some wired sorting. if (empty($sort)) { $sort = ' ORDER BY uniqueid'; } else { $sort = ' ORDER BY ' . $sort; } if (!$download) { // Add extra limits due to initials bar. list($twhere, $tparams) = $table->get_sql_where(); if ($twhere) { $where .= ' AND ' . $twhere; // Initial bar. $params = array_merge($params, $tparams); } if (!empty($countsql)) { $count = $DB->get_record_sql($countsql, $params); $totalinitials = $count->nbresults; if ($twhere) { $countsql .= ' AND ' . $twhere; } $count = $DB->get_record_sql($countsql, $params); $total = $count->nbresults; } $table->pagesize($pagesize, $total); echo \html_writer::start_div('scormattemptcounts'); if ($count->nbresults == $count->nbattempts) { echo get_string('reportcountattempts', 'scorm', $count); } else { if ($count->nbattempts > 0) { echo get_string('reportcountallattempts', 'scorm', $count); } else { echo $count->nbusers . ' ' . get_string('users'); } } echo \html_writer::end_div(); } // Fetch the attempts. if (!$download) { $attempts = $DB->get_records_sql($select . $from . $where . $sort, $params, $table->get_page_start(), $table->get_page_size()); echo \html_writer::start_div('', array('id' => 'scormtablecontainer')); if ($candelete) { // Start form. $strreallydel = addslashes_js(get_string('deleteattemptcheck', 'scorm')); echo \html_writer::start_tag('form', array('id' => 'attemptsform', 'method' => 'post', 'action' => $PAGE->url->out(false), 'onsubmit' => 'return confirm("' . $strreallydel . '");')); echo \html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'delete')); echo \html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())); echo \html_writer::start_div('', array('style' => 'display: none;')); echo \html_writer::input_hidden_params($PAGE->url); echo \html_writer::end_div(); echo \html_writer::start_div(); } $table->initialbars($totalinitials > 20); // Build table rows. } else { $attempts = $DB->get_records_sql($select . $from . $where . $sort, $params); } if ($attempts) { foreach ($attempts as $scouser) { $row = array(); if (!empty($scouser->attempt)) { $timetracks = scorm_get_sco_runtime($scorm->id, false, $scouser->userid, $scouser->attempt); } else { $timetracks = ''; } if (in_array('checkbox', $columns)) { if ($candelete && !empty($timetracks->start)) { $row[] = \html_writer::checkbox('attemptid[]', $scouser->userid . ':' . $scouser->attempt, false); } else { if ($candelete) { $row[] = ''; } } } if (in_array('picture', $columns)) { $user = new \stdClass(); $additionalfields = explode(',', \user_picture::fields()); $user = username_load_fields_from_object($user, $scouser, null, $additionalfields); $user->id = $scouser->userid; $row[] = $OUTPUT->user_picture($user, array('courseid' => $course->id)); } if (!$download) { $url = new \moodle_url('/user/view.php', array('id' => $scouser->userid, 'course' => $course->id)); $row[] = \html_writer::link($url, fullname($scouser)); } else { $row[] = fullname($scouser); } foreach ($extrafields as $field) { $row[] = s($scouser->{$field}); } if (empty($timetracks->start)) { $row[] = '-'; $row[] = '-'; $row[] = '-'; $row[] = '-'; } else { if (!$download) { $url = new \moodle_url('/mod/scorm/report/userreport.php', array('id' => $cm->id, 'user' => $scouser->userid, 'attempt' => $scouser->attempt)); $row[] = \html_writer::link($url, $scouser->attempt); } else { $row[] = $scouser->attempt; } if ($download == 'ODS' || $download == 'Excel') { $row[] = userdate($timetracks->start, get_string("strftimedatetime", "langconfig")); } else { $row[] = userdate($timetracks->start); } if ($download == 'ODS' || $download == 'Excel') { $row[] = userdate($timetracks->finish, get_string('strftimedatetime', 'langconfig')); } else { $row[] = userdate($timetracks->finish); } $row[] = scorm_grade_user_attempt($scorm, $scouser->userid, $scouser->attempt); } // Print out all scores of attempt. foreach ($scoes as $sco) { if ($sco->launch != '') { if ($trackdata = scorm_get_tracks($sco->id, $scouser->userid, $scouser->attempt)) { if ($trackdata->status == '') { $trackdata->status = 'notattempted'; } $strstatus = get_string($trackdata->status, 'scorm'); if ($trackdata->score_raw != '') { // If raw score exists, print it. $score = $trackdata->score_raw; // Add max score if it exists. if (isset($trackdata->score_max)) { $score .= '/' . $trackdata->score_max; } } else { // ...else print out status. $score = $strstatus; } if (!$download) { $url = new \moodle_url('/mod/scorm/report/userreporttracks.php', array('id' => $cm->id, 'scoid' => $sco->id, 'user' => $scouser->userid, 'attempt' => $scouser->attempt)); $row[] = \html_writer::img($OUTPUT->pix_url($trackdata->status, 'scorm'), $strstatus, array('title' => $strstatus)) . \html_writer::empty_tag('br') . \html_writer::link($url, $score, array('title' => get_string('details', 'scorm'))); } else { $row[] = $score; } // Iterate over tracks and match objective id against values. $scorm2004 = false; if (scorm_version_check($scorm->version, SCORM_13)) { $scorm2004 = true; $objectiveprefix = "cmi.objectives."; } else { $objectiveprefix = "cmi.objectives_"; } $keywords = array(".id", $objectiveprefix); $objectivestatus = array(); $objectivescore = array(); foreach ($trackdata as $name => $value) { if (strpos($name, $objectiveprefix) === 0 && strrpos($name, '.id') !== false) { $num = trim(str_ireplace($keywords, '', $name)); if (is_numeric($num)) { if ($scorm2004) { $element = $objectiveprefix . $num . '.completion_status'; } else { $element = $objectiveprefix . $num . '.status'; } if (isset($trackdata->{$element})) { $objectivestatus[$value] = $trackdata->{$element}; } else { $objectivestatus[$value] = ''; } if ($displayoptions['objectivescore']) { $element = $objectiveprefix . $num . '.score.raw'; if (isset($trackdata->{$element})) { $objectivescore[$value] = $trackdata->{$element}; } else { $objectivescore[$value] = ''; } } } } } // Interaction data. if (!empty($objectives[$trackdata->scoid])) { foreach ($objectives[$trackdata->scoid] as $name) { if (isset($objectivestatus[$name])) { $row[] = s($objectivestatus[$name]); } else { $row[] = $emptycell; } if ($displayoptions['objectivescore']) { if (isset($objectivescore[$name])) { $row[] = s($objectivescore[$name]); } else { $row[] = $emptycell; } } } } // End of interaction data. } else { // If we don't have track data, we haven't attempted yet. $strstatus = get_string('notattempted', 'scorm'); if (!$download) { $row[] = \html_writer::img($OUTPUT->pix_url('notattempted', 'scorm'), $strstatus, array('title' => $strstatus)) . \html_writer::empty_tag('br') . $strstatus; } else { $row[] = $strstatus; } // Complete the empty cells. for ($i = 0; $i < count($columns) - $nbmaincolumns; $i++) { $row[] = $emptycell; } } } } if (!$download) { $table->add_data($row); } else { if ($download == 'Excel' or $download == 'ODS') { $colnum = 0; foreach ($row as $item) { $myxls->write($rownum, $colnum, $item, $format); $colnum++; } $rownum++; } else { if ($download == 'CSV') { $csvexport->add_data($row); } } } } if (!$download) { $table->finish_output(); if ($candelete) { echo \html_writer::start_tag('table', array('id' => 'commands')); echo \html_writer::start_tag('tr') . \html_writer::start_tag('td'); echo \html_writer::link('javascript:select_all_in(\'DIV\', null, \'scormtablecontainer\');', get_string('selectall', 'scorm')) . ' / '; echo \html_writer::link('javascript:deselect_all_in(\'DIV\', null, \'scormtablecontainer\');', get_string('selectnone', 'scorm')); echo ' '; echo \html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('deleteselected', 'scorm'), 'class' => 'btn btn-secondary')); echo \html_writer::end_tag('td') . \html_writer::end_tag('tr') . \html_writer::end_tag('table'); // Close form. echo \html_writer::end_tag('div'); echo \html_writer::end_tag('form'); } echo \html_writer::end_div(); if (!empty($attempts)) { echo \html_writer::start_tag('table', array('class' => 'boxaligncenter')) . \html_writer::start_tag('tr'); echo \html_writer::start_tag('td'); echo $OUTPUT->single_button(new \moodle_url($PAGE->url, array('download' => 'ODS') + $displayoptions), get_string('downloadods'), 'post', ['class' => 'm-t-1']); echo \html_writer::end_tag('td'); echo \html_writer::start_tag('td'); echo $OUTPUT->single_button(new \moodle_url($PAGE->url, array('download' => 'Excel') + $displayoptions), get_string('downloadexcel'), 'post', ['class' => 'm-t-1']); echo \html_writer::end_tag('td'); echo \html_writer::start_tag('td'); echo $OUTPUT->single_button(new \moodle_url($PAGE->url, array('download' => 'CSV') + $displayoptions), get_string('downloadtext'), 'post', ['class' => 'm-t-1']); echo \html_writer::end_tag('td'); echo \html_writer::start_tag('td'); echo \html_writer::end_tag('td'); echo \html_writer::end_tag('tr') . \html_writer::end_tag('table'); } } } else { if ($candelete && !$download) { echo \html_writer::end_div(); echo \html_writer::end_tag('form'); $table->finish_output(); } echo \html_writer::end_div(); } // Show preferences form irrespective of attempts are there to report or not. if (!$download) { $mform->set_data(compact('detailedrep', 'pagesize', 'attemptsmode')); $mform->display(); } if ($download == 'Excel' or $download == 'ODS') { $workbook->close(); exit; } else { if ($download == 'CSV') { $csvexport->download_file(); exit; } } } else { echo $OUTPUT->notification(get_string('noactivity', 'scorm')); } }
function scorm_simple_play($scorm,$user, $context) { global $DB; $result = false; if ($scorm->updatefreq == UPDATE_EVERYTIME) { scorm_parse($scorm, false); } if (has_capability('mod/scorm:viewreport', $context)) { //if this user can view reports, don't skipview so they can see links to reports. return $result; } $scoes = $DB->get_records_select('scorm_scoes', 'scorm = ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true), array($scorm->id), 'id', 'id'); if ($scoes) { if ($scorm->skipview >= 1) { $sco = current($scoes); if (scorm_get_tracks($sco->id,$user->id) === false) { header('Location: player.php?a='.$scorm->id.'&scoid='.$sco->id); $result = true; } else if ($scorm->skipview == 2) { header('Location: player.php?a='.$scorm->id.'&scoid='.$sco->id); $result = true; } } } return $result; }
function JLMS_APISCORM($option) { global $JLMS_DB, $my, $Itemid; $id = intval(mosGetParam($_REQUEST, 'id', 0)); $course_id = intval(mosGetParam($_REQUEST, 'course_id', 0)); $skip_resume = intval(mosGetParam($_REQUEST, 'skip_resume', 0)); 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)); $attempt = intval(mosGetParam($_REQUEST, 'attempt', 0)); $mode = strval(mosGetParam($_REQUEST, 'mode', '')); $track_attempt = $attempt; if ($track_attempt > 1) { global $JLMS_CONFIG; $course_params = $JLMS_CONFIG->get('course_params'); $params = new JLMSParameters($course_params); if ($params->get('track_type', 0) == 1) { //by the best attaempt $track_attempt--; } } if ($skip_resume) { $userdata->status = ''; $userdata->score_raw = ''; } else { if ($usertrack = scorm_get_tracks($scoid, $my->id, $track_attempt)) { if (isset($usertrack->{'cmi.exit'}) && $usertrack->{'cmi.exit'} != 'time-out' || $scorm->version != "SCORM_1.3") { $userdata = $usertrack; } else { $userdata->status = ''; $userdata->score_raw = ''; } } else { $userdata->status = ''; $userdata->score_raw = ''; } } $userdata->student_id = addslashes($my->username); $userdata->student_name = addslashes($my->name); $userdata->mode = 'normal'; if ($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 { // (DEN) //error('Sco not found'); //echo 'SCO not found'; } //$scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe $scorm->version = strtolower(preg_replace('/[^a-zA-Z0-9_-]/i', '', $scorm->version)); if (file_exists(_JOOMLMS_FRONT_HOME . '/includes/n_scorm/datamodels/' . $scorm->version . '.js.php')) { include_once _JOOMLMS_FRONT_HOME . '/includes/n_scorm/datamodels/' . $scorm->version . '.js.php'; } else { include_once _JOOMLMS_FRONT_HOME . '/includes/n_scorm/datamodels/scorm_12.js.php'; } /*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'); }*/ ?> var errorCode = "0"; function underscore(str) { str = str.replace(/.N/g,"."); return str.replace(/\./g,"__"); } <?php } } exit; }
/** * 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; }
/** * displays the full report * @param stdClass $scorm full SCORM object * @param stdClass $cm - full course_module object * @param stdClass $course - full course object * @param string $download - type of download being requested */ function display($scorm, $cm, $course, $download) { global $CFG, $DB, $OUTPUT, $PAGE; $contextmodule = get_context_instance(CONTEXT_MODULE, $cm->id); $action = optional_param('action', '', PARAM_ALPHA); $attemptids = optional_param_array('attemptid', array(), PARAM_RAW); $attemptsmode = optional_param('attemptsmode', SCORM_REPORT_ATTEMPTS_ALL_STUDENTS, PARAM_INT); $PAGE->set_url(new moodle_url($PAGE->url, array('attemptsmode' => $attemptsmode))); if ($action == 'delete' && has_capability('mod/scorm:deleteresponses', $contextmodule) && confirm_sesskey()) { if (scorm_delete_responses($attemptids, $scorm)) { //delete responses. add_to_log($course->id, 'scorm', 'delete attempts', 'report.php?id=' . $cm->id, implode(",", $attemptids), $cm->id); echo $OUTPUT->notification(get_string('scormresponsedeleted', 'scorm'), 'notifysuccess'); } } // find out current groups mode $currentgroup = groups_get_activity_group($cm, true); // detailed report $mform = new mod_scorm_report_interactions_settings($PAGE->url, compact('currentgroup')); if ($fromform = $mform->get_data()) { $pagesize = $fromform->pagesize; $includeqtext = $fromform->qtext; $includeresp = $fromform->resp; $includeright = $fromform->right; set_user_preference('scorm_report_pagesize', $pagesize); set_user_preference('scorm_report_interactions_qtext', $includeqtext); set_user_preference('scorm_report_interactions_resp', $includeresp); set_user_preference('scorm_report_interactions_right', $includeright); } else { $pagesize = get_user_preferences('scorm_report_pagesize', 0); $includeqtext = get_user_preferences('scorm_report_interactions_qtext', 0); $includeresp = get_user_preferences('scorm_report_interactions_resp', 1); $includeright = get_user_preferences('scorm_report_interactions_right', 0); } if ($pagesize < 1) { $pagesize = SCORM_REPORT_DEFAULT_PAGE_SIZE; } // select group menu $displayoptions = array(); $displayoptions['attemptsmode'] = $attemptsmode; $displayoptions['qtext'] = $includeqtext; $displayoptions['resp'] = $includeresp; $displayoptions['right'] = $includeright; $mform->set_data($displayoptions + array('pagesize' => $pagesize)); if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used if (!$download) { groups_print_activity_menu($cm, new moodle_url($PAGE->url, $displayoptions)); } } $formattextoptions = array('context' => get_context_instance(CONTEXT_COURSE, $course->id)); // We only want to show the checkbox to delete attempts // if the user has permissions and if the report mode is showing attempts. $candelete = has_capability('mod/scorm:deleteresponses', $contextmodule) && ($attemptsmode != SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO); // select the students $nostudents = false; if (empty($currentgroup)) { // all users who can attempt scoes if (!$students = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', '', '', '', '', '', '', false)) { echo $OUTPUT->notification(get_string('nostudentsyet')); $nostudents = true; $allowedlist = ''; } else { $allowedlist = array_keys($students); } } else { // all users who can attempt scoes and who are in the currently selected group if (!$groupstudents = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', '', '', '', '', $currentgroup, '', false)) { echo $OUTPUT->notification(get_string('nostudentsingroup')); $nostudents = true; $groupstudents = array(); } $allowedlist = array_keys($groupstudents); } if ( !$nostudents ) { // Now check if asked download of data $coursecontext = context_course::instance($course->id); if ($download) { $filename = clean_filename("$course->shortname ".format_string($scorm->name, true,$formattextoptions)); } // Define table columns $columns = array(); $headers = array(); if (!$download && $candelete) { $columns[] = 'checkbox'; $headers[] = null; } if (!$download && $CFG->grade_report_showuserimage) { $columns[] = 'picture'; $headers[] = ''; } $columns[] = 'fullname'; $headers[] = get_string('name'); $extrafields = get_extra_user_fields($coursecontext); foreach ($extrafields as $field) { $columns[] = $field; $headers[] = get_user_field_name($field); } $columns[] = 'attempt'; $headers[] = get_string('attempt', 'scorm'); $columns[] = 'start'; $headers[] = get_string('started', 'scorm'); $columns[] = 'finish'; $headers[] = get_string('last', 'scorm'); $columns[] = 'score'; $headers[] = get_string('score', 'scorm'); $scoes = $DB->get_records('scorm_scoes', array("scorm"=>$scorm->id), 'id'); foreach ($scoes as $sco) { if ($sco->launch != '') { $columns[] = 'scograde'.$sco->id; $headers[] = format_string($sco->title,'',$formattextoptions); } } $params = array(); list($usql, $params) = $DB->get_in_or_equal($allowedlist, SQL_PARAMS_NAMED); // Construct the SQL $select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, '; $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' . 'u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, u.imagealt, u.email'. get_extra_user_fields_sql($coursecontext, 'u', '', array('idnumber')) . ' '; // This part is the same for all cases - join users and scorm_scoes_track tables $from = 'FROM {user} u '; $from .= 'LEFT JOIN {scorm_scoes_track} st ON st.userid = u.id AND st.scormid = '.$scorm->id; switch ($attemptsmode) { case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH: // Show only students with attempts $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NOT NULL'; break; case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO: // Show only students without attempts $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NULL'; break; case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS: // Show all students with or without attempts $where = ' WHERE u.id ' .$usql. ' AND (st.userid IS NOT NULL OR st.userid IS NULL)'; break; } $countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').')) AS nbresults, '; $countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'st.attempt').')) AS nbattempts, '; $countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers '; $countsql .= $from.$where; $attempts = $DB->get_records_sql($select.$from.$where, $params); $questioncount = get_scorm_question_count($scorm->id); for($id = 0; $id < $questioncount; $id++) { if ($displayoptions['qtext']) { $columns[] = 'question' . $id; $headers[] = get_string('questionx', 'scormreport_interactions', $id); } if ($displayoptions['resp']) { $columns[] = 'response' . $id; $headers[] = get_string('responsex', 'scormreport_interactions', $id); } if ($displayoptions['right']) { $columns[] = 'right' . $id; $headers[] = get_string('rightanswerx', 'scormreport_interactions', $id); } } if (!$download) { $table = new flexible_table('mod-scorm-report'); $table->define_columns($columns); $table->define_headers($headers); $table->define_baseurl($PAGE->url); $table->sortable(true); $table->collapsible(true); // This is done to prevent redundant data, when a user has multiple attempts $table->column_suppress('picture'); $table->column_suppress('fullname'); foreach ($extrafields as $field) { $table->column_suppress($field); } $table->no_sorting('start'); $table->no_sorting('finish'); $table->no_sorting('score'); foreach ($scoes as $sco) { if ($sco->launch != '') { $table->no_sorting('scograde'.$sco->id); } } $table->column_class('picture', 'picture'); $table->column_class('fullname', 'bold'); $table->column_class('score', 'bold'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'generaltable generalbox'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); } else if ($download == 'ODS') { require_once("$CFG->libdir/odslib.class.php"); $filename .= ".ods"; // Creating a workbook $workbook = new MoodleODSWorkbook("-"); // Sending HTTP headers $workbook->send($filename); // Creating the first worksheet $sheettitle = get_string('report', 'scorm'); $myxls =& $workbook->add_worksheet($sheettitle); // format types $format =& $workbook->add_format(); $format->set_bold(0); $formatbc =& $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb =& $workbook->add_format(); $formatb->set_bold(1); $formaty =& $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc =& $workbook->add_format(); $formatc->set_align('center'); $formatr =& $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg =& $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); // Here starts workshhet headers $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else if ($download =='Excel') { require_once("$CFG->libdir/excellib.class.php"); $filename .= ".xls"; // Creating a workbook $workbook = new MoodleExcelWorkbook("-"); // Sending HTTP headers $workbook->send($filename); // Creating the first worksheet $sheettitle = get_string('report', 'scorm'); $myxls =& $workbook->add_worksheet($sheettitle); // format types $format =& $workbook->add_format(); $format->set_bold(0); $formatbc =& $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb =& $workbook->add_format(); $formatb->set_bold(1); $formaty =& $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc =& $workbook->add_format(); $formatc->set_align('center'); $formatr =& $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg =& $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else if ($download == 'CSV') { $filename .= ".txt"; header("Content-Type: application/download\n"); header("Content-Disposition: attachment; filename=\"$filename\""); header("Expires: 0"); header("Cache-Control: must-revalidate,post-check=0,pre-check=0"); header("Pragma: public"); echo implode("\t", $headers)." \n"; } if (!$download) { $sort = $table->get_sql_sort(); } else { $sort = ''; } // Fix some wired sorting if (empty($sort)) { $sort = ' ORDER BY uniqueid'; } else { $sort = ' ORDER BY '.$sort; } if (!$download) { // Add extra limits due to initials bar list($twhere, $tparams) = $table->get_sql_where(); if ($twhere) { $where .= ' AND '.$twhere; //initial bar $params = array_merge($params, $tparams); } if (!empty($countsql)) { $count = $DB->get_record_sql($countsql,$params); $totalinitials = $count->nbresults; if ($twhere) { $countsql .= ' AND '.$twhere; } $count = $DB->get_record_sql($countsql, $params); $total = $count->nbresults; } $table->pagesize($pagesize, $total); echo '<div class="quizattemptcounts">'; if ( $count->nbresults == $count->nbattempts ) { echo get_string('reportcountattempts', 'scorm', $count); } else if ( $count->nbattempts>0 ) { echo get_string('reportcountallattempts', 'scorm', $count); } else { echo $count->nbusers.' '.get_string('users'); } echo '</div>'; } // Fetch the attempts if (!$download) { $attempts = $DB->get_records_sql($select.$from.$where.$sort, $params, $table->get_page_start(), $table->get_page_size()); echo '<div id="scormtablecontainer">'; if ($candelete) { // Start form $strreallydel = addslashes_js(get_string('deleteattemptcheck', 'scorm')); echo '<form id="attemptsform" method="post" action="' . $PAGE->url->out(false) . '" onsubmit="return confirm(\''.$strreallydel.'\');">'; echo '<input type="hidden" name="action" value="delete"/>'; echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />'; echo '<div style="display: none;">'; echo html_writer::input_hidden_params($PAGE->url); echo '</div>'; echo '<div>'; } $table->initialbars($totalinitials>20); // Build table rows } else { $attempts = $DB->get_records_sql($select.$from.$where.$sort, $params); } if ($attempts) { foreach ($attempts as $scouser) { $row = array(); if (!empty($scouser->attempt)) { $timetracks = scorm_get_sco_runtime($scorm->id, false, $scouser->userid, $scouser->attempt); } else { $timetracks = ''; } if (in_array('checkbox', $columns)) { if ($candelete && !empty($timetracks->start)) { $row[] = '<input type="checkbox" name="attemptid[]" value="'. $scouser->userid . ':' . $scouser->attempt . '" />'; } else if ($candelete) { $row[] = ''; } } if (in_array('picture', $columns)) { $user = (object)array( 'id'=>$scouser->userid, 'picture'=>$scouser->picture, 'imagealt'=>$scouser->imagealt, 'email'=>$scouser->email, 'firstname'=>$scouser->firstname, 'lastname'=>$scouser->lastname); $row[] = $OUTPUT->user_picture($user, array('courseid'=>$course->id)); } if (!$download) { $row[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$scouser->userid.'&course='.$course->id.'">'.fullname($scouser).'</a>'; } else { $row[] = fullname($scouser); } foreach ($extrafields as $field) { $row[] = s($scouser->{$field}); } if (empty($timetracks->start)) { $row[] = '-'; $row[] = '-'; $row[] = '-'; $row[] = '-'; } else { if (!$download) { $row[] = '<a href="userreport.php?a='.$scorm->id.'&user='******'&attempt='.$scouser->attempt.'">'.$scouser->attempt.'</a>'; } else { $row[] = $scouser->attempt; } if ($download =='ODS' || $download =='Excel' ) { $row[] = userdate($timetracks->start, get_string("strftimedatetime", "langconfig")); } else { $row[] = userdate($timetracks->start); } if ($download =='ODS' || $download =='Excel' ) { $row[] = userdate($timetracks->finish, get_string('strftimedatetime', 'langconfig')); } else { $row[] = userdate($timetracks->finish); } $row[] = scorm_grade_user_attempt($scorm, $scouser->userid, $scouser->attempt); } // print out all scores of attempt foreach ($scoes as $sco) { if ($sco->launch != '') { if ($trackdata = scorm_get_tracks($sco->id, $scouser->userid, $scouser->attempt)) { if ($trackdata->status == '') { $trackdata->status = 'notattempted'; } $strstatus = get_string($trackdata->status, 'scorm'); // if raw score exists, print it if ($trackdata->score_raw != '') { $score = $trackdata->score_raw; // add max score if it exists if ($scorm->version == 'SCORM_1.3') { $maxkey = 'cmi.score.max'; } else { $maxkey = 'cmi.core.score.max'; } if (isset($trackdata->$maxkey)) { $score .= '/'.$trackdata->$maxkey; } // else print out status } else { $score = $strstatus; } if (!$download) { $row[] = '<img src="'.$OUTPUT->pix_url($trackdata->status, 'scorm').'" alt="'.$strstatus.'" title="'.$strstatus.'" /><br/> <a href="userreport.php?b='.$sco->id.'&user='******'&attempt='.$scouser->attempt. '" title="'.get_string('details', 'scorm').'">'.$score.'</a>'; } else { $row[] = $score; } // interaction data $i=0; $element='cmi.interactions_'.$i.'.id'; while(isset($trackdata->$element)) { if ($displayoptions['qtext']) { $element='cmi.interactions_'.$i.'.id'; if (isset($trackdata->$element)) { $row[] = s($trackdata->$element); } else { $row[] = ' '; } } if ($displayoptions['resp']) { $element='cmi.interactions_'.$i.'.student_response'; if (isset($trackdata->$element)) { $row[] = s($trackdata->$element); } else { $row[] = ' '; } } if ($displayoptions['right']) { $j=0; $element = 'cmi.interactions_'.$i.'.correct_responses_'.$j.'.pattern'; $rightans = ''; if (isset($trackdata->$element)) { while(isset($trackdata->$element)) { if($j>0) { $rightans .= ','; } $rightans .= s($trackdata->$element); $j++; $element = 'cmi.interactions_'.$i.'.correct_responses_'.$j.'.pattern'; } $row[] = $rightans; } else { $row[] = ' '; } } $i++; $element = 'cmi.interactions_'.$i.'.id'; } //---end of interaction data*/ } else { // if we don't have track data, we haven't attempted yet $strstatus = get_string('notattempted', 'scorm'); if (!$download) { $row[] = '<img src="'.$OUTPUT->pix_url('notattempted', 'scorm').'" alt="'.$strstatus.'" title="'.$strstatus.'" /><br/>'.$strstatus; } else { $row[] = $strstatus; } } } } if (!$download) { $table->add_data($row); } else if ($download == 'Excel' or $download == 'ODS') { $colnum = 0; foreach ($row as $item) { $myxls->write($rownum, $colnum, $item, $format); $colnum++; } $rownum++; } else if ($download == 'CSV') { $text = implode("\t", $row); echo $text." \n"; } } if (!$download) { $table->finish_output(); if ($candelete) { echo '<table id="commands">'; echo '<tr><td>'; echo '<a href="javascript:select_all_in(\'DIV\', null, \'scormtablecontainer\');">'. get_string('selectall', 'scorm').'</a> / '; echo '<a href="javascript:deselect_all_in(\'DIV\', null, \'scormtablecontainer\');">'. get_string('selectnone', 'scorm').'</a> '; echo ' '; echo '<input type="submit" value="'.get_string('deleteselected', 'quiz_overview').'"/>'; echo '</td></tr></table>'; // Close form echo '</div>'; echo '</form>'; } echo '</div>'; if (!empty($attempts)) { echo '<table class="boxaligncenter"><tr>'; echo '<td>'; echo $OUTPUT->single_button(new moodle_url($PAGE->url, array('download'=>'ODS') + $displayoptions), get_string('downloadods')); echo "</td>\n"; echo '<td>'; echo $OUTPUT->single_button(new moodle_url($PAGE->url, array('download'=>'Excel') + $displayoptions), get_string('downloadexcel')); echo "</td>\n"; echo '<td>'; echo $OUTPUT->single_button(new moodle_url($PAGE->url, array('download'=>'CSV') + $displayoptions), get_string('downloadtext')); echo "</td>\n"; echo "<td>"; echo "</td>\n"; echo '</tr></table>'; } } } else { if ($candelete && !$download) { echo '</div>'; echo '</form>'; $table->finish_output(); } echo '</div>'; } // Show preferences form irrespective of attempts are there to report or not if (!$download) { $mform->set_data(compact('detailedrep', 'pagesize', 'attemptsmode')); $mform->display(); } if ($download == 'Excel' or $download == 'ODS') { $workbook->close(); exit; } else if ($download == 'CSV') { exit; } } else { echo $OUTPUT->notification(get_string('noactivity', 'scorm')); } }// function ends
/** * Print a detailed representation of what a user has done with * a given particular instance of this module, for user activity reports. * * @global stdClass * @global object * @param object $course * @param object $user * @param object $mod * @param object $scorm * @return boolean */ function scorm_user_complete($course, $user, $mod, $scorm) { global $CFG, $DB, $OUTPUT; require_once "{$CFG->libdir}/gradelib.php"; $liststyle = 'structlist'; $now = time(); $firstmodify = $now; $lastmodify = 0; $sometoreport = false; $report = ''; // First Access and Last Access dates for SCOs require_once $CFG->dirroot . '/mod/scorm/locallib.php'; $timetracks = scorm_get_sco_runtime($scorm->id, false, $user->id); $firstmodify = $timetracks->start; $lastmodify = $timetracks->finish; $grades = grade_get_grades($course->id, 'mod', 'scorm', $scorm->id, $user->id); if (!empty($grades->items[0]->grades)) { $grade = reset($grades->items[0]->grades); echo $OUTPUT->container(get_string('grade') . ': ' . $grade->str_long_grade); if ($grade->str_feedback) { echo $OUTPUT->container(get_string('feedback') . ': ' . $grade->str_feedback); } } if ($orgs = $DB->get_records_select('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,identifier,title')) { if (count($orgs) <= 1) { unset($orgs); $orgs[]->identifier = ''; } $report .= '<div class="mod-scorm">' . "\n"; foreach ($orgs as $org) { $conditions = array(); $currentorg = ''; if (!empty($org->identifier)) { $report .= '<div class="orgtitle">' . $org->title . '</div>'; $currentorg = $org->identifier; $conditions['organization'] = $currentorg; } $report .= "<ul id='0' class='{$liststyle}'>"; $conditions['scorm'] = $scorm->id; if ($scoes = $DB->get_records('scorm_scoes', $conditions, "id ASC")) { // drop keys so that we can access array sequentially $scoes = array_values($scoes); $level = 0; $sublist = 1; $parents[$level] = '/'; foreach ($scoes as $pos => $sco) { if ($parents[$level] != $sco->parent) { if ($level > 0 && $parents[$level - 1] == $sco->parent) { $report .= "\t\t</ul></li>\n"; $level--; } else { $i = $level; $closelist = ''; while ($i > 0 && $parents[$level] != $sco->parent) { $closelist .= "\t\t</ul></li>\n"; $i--; } if ($i == 0 && $sco->parent != $currentorg) { $report .= "\t\t<li><ul id='{$sublist}' class='{$liststyle}'>\n"; $level++; } else { $report .= $closelist; $level = $i; } $parents[$level] = $sco->parent; } } $report .= "\t\t<li>"; if (isset($scoes[$pos + 1])) { $nextsco = $scoes[$pos + 1]; } else { $nextsco = false; } if ($nextsco !== false && $sco->parent != $nextsco->parent && ($level == 0 || $level > 0 && $nextsco->parent == $sco->identifier)) { $sublist++; } else { $report .= '<img src="' . $OUTPUT->pix_url('spacer', 'scorm') . '" alt="" />'; } if ($sco->launch) { $score = ''; $totaltime = ''; if ($usertrack = scorm_get_tracks($sco->id, $user->id)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } $strstatus = get_string($usertrack->status, 'scorm'); $report .= "<img src='" . $OUTPUT->pix_url($usertrack->status, 'scorm') . "' alt='{$strstatus}' title='{$strstatus}' />"; } else { if ($sco->scormtype == 'sco') { $report .= '<img src="' . $OUTPUT->pix_url('notattempted', 'scorm') . '" alt="' . get_string('notattempted', 'scorm') . '" title="' . get_string('notattempted', 'scorm') . '" />'; } else { $report .= '<img src="' . $OUTPUT->pix_url('asset', 'scorm') . '" alt="' . get_string('asset', 'scorm') . '" title="' . get_string('asset', 'scorm') . '" />'; } } $report .= " {$sco->title} {$score}{$totaltime}</li>\n"; if ($usertrack !== false) { $sometoreport = true; $report .= "\t\t\t<li><ul class='{$liststyle}'>\n"; foreach ($usertrack as $element => $value) { if (substr($element, 0, 3) == 'cmi') { $report .= '<li>' . $element . ' => ' . s($value) . '</li>'; } } $report .= "\t\t\t</ul></li>\n"; } } else { $report .= " {$sco->title}</li>\n"; } } for ($i = 0; $i < $level; $i++) { $report .= "\t\t</ul></li>\n"; } } $report .= "\t</ul><br />\n"; } $report .= "</div>\n"; } if ($sometoreport) { if ($firstmodify < $now) { $timeago = format_time($now - $firstmodify); echo get_string('firstaccess', 'scorm') . ': ' . userdate($firstmodify) . ' (' . $timeago . ")<br />\n"; } if ($lastmodify > 0) { $timeago = format_time($now - $lastmodify); echo get_string('lastaccess', 'scorm') . ': ' . userdate($lastmodify) . ' (' . $timeago . ")<br />\n"; } echo get_string('report', 'scorm') . ":<br />\n"; echo $report; } else { print_string('noactivity', 'scorm'); } return true; }
/** * Print a detailed representation of what a user has done with * a given particular instance of this module, for user activity reports. * * @param int $course Course id * @param int $user User id * @param int $mod * @param int $scorm The scorm id * @return boolean */ function scorm_user_complete($course, $user, $mod, $scorm) { global $CFG; $liststyle = 'structlist'; $scormpixdir = $CFG->modpixpath . '/scorm/pix'; $now = time(); $firstmodify = $now; $lastmodify = 0; $sometoreport = false; $report = ''; if ($orgs = get_records_select('scorm_scoes', "scorm='{$scorm->id}' AND organization='' AND launch=''", 'id', 'id,identifier,title')) { if (count($orgs) <= 1) { unset($orgs); $orgs[]->identifier = ''; } $report .= '<div class="mod-scorm">' . "\n"; foreach ($orgs as $org) { $organizationsql = ''; $currentorg = ''; if (!empty($org->identifier)) { $report .= '<div class="orgtitle">' . $org->title . '</div>'; $currentorg = $org->identifier; $organizationsql = "AND organization='{$currentorg}'"; } $report .= "<ul id='0' class='{$liststyle}'>"; if ($scoes = get_records_select('scorm_scoes', "scorm='{$scorm->id}' {$organizationsql} order by id ASC")) { $level = 0; $sublist = 1; $parents[$level] = '/'; foreach ($scoes as $sco) { if ($parents[$level] != $sco->parent) { if ($level > 0 && $parents[$level - 1] == $sco->parent) { $report .= "\t\t</ul></li>\n"; $level--; } else { $i = $level; $closelist = ''; while ($i > 0 && $parents[$level] != $sco->parent) { $closelist .= "\t\t</ul></li>\n"; $i--; } if ($i == 0 && $sco->parent != $currentorg) { $report .= "\t\t<li><ul id='{$sublist}' class='{$liststyle}'>\n"; $level++; } else { $report .= $closelist; $level = $i; } $parents[$level] = $sco->parent; } } $report .= "\t\t<li>"; $nextsco = next($scoes); if ($nextsco !== false && $sco->parent != $nextsco->parent && ($level == 0 || $level > 0 && $nextsco->parent == $sco->identifier)) { $sublist++; } else { $report .= '<img src="' . $scormpixdir . '/spacer.gif" alt="" />'; } if ($sco->launch) { require_once 'locallib.php'; $score = ''; $totaltime = ''; if ($usertrack = scorm_get_tracks($sco->id, $user->id)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } $strstatus = get_string($usertrack->status, 'scorm'); $report .= "<img src='" . $scormpixdir . '/' . $usertrack->status . ".gif' alt='{$strstatus}' title='{$strstatus}' />"; if ($usertrack->timemodified != 0) { if ($usertrack->timemodified > $lastmodify) { $lastmodify = $usertrack->timemodified; } if ($usertrack->timemodified < $firstmodify) { $firstmodify = $usertrack->timemodified; } } } else { if ($sco->scormtype == 'sco') { $report .= '<img src="' . $scormpixdir . '/' . 'notattempted.gif" alt="' . get_string('notattempted', 'scorm') . '" title="' . get_string('notattempted', 'scorm') . '" />'; } else { $report .= '<img src="' . $scormpixdir . '/' . 'asset.gif" alt="' . get_string('asset', 'scorm') . '" title="' . get_string('asset', 'scorm') . '" />'; } } $report .= " {$sco->title} {$score}{$totaltime}</li>\n"; if ($usertrack !== false) { $sometoreport = true; $report .= "\t\t\t<li><ul class='{$liststyle}'>\n"; foreach ($usertrack as $element => $value) { if (substr($element, 0, 3) == 'cmi') { $report .= '<li>' . $element . ' => ' . $value . '</li>'; } } $report .= "\t\t\t</ul></li>\n"; } } else { $report .= " {$sco->title}</li>\n"; } } for ($i = 0; $i < $level; $i++) { $report .= "\t\t</ul></li>\n"; } } $report .= "\t</ul><br />\n"; } $report .= "</div>\n"; } if ($sometoreport) { if ($firstmodify < $now) { $timeago = format_time($now - $firstmodify); echo get_string('firstaccess', 'scorm') . ': ' . userdate($firstmodify) . ' (' . $timeago . ")<br />\n"; } if ($lastmodify > 0) { $timeago = format_time($now - $lastmodify); echo get_string('lastaccess', 'scorm') . ': ' . userdate($lastmodify) . ' (' . $timeago . ")<br />\n"; } echo get_string('report', 'scorm') . ":<br />\n"; echo $report; } else { print_string('noactivity', 'scorm'); } return true; }
function scorm_get_toc($user, $scorm, $liststyle, $currentorg = '', $scoid = '', $mode = 'normal', $attempt = '', $play = false) { global $CFG, $DB; $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 // 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; 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 (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 .= "\t\t" . '<li><a href="javascript:expandCollide(\'img' . $sublist . '\',\'s' . $sublist . '\',' . $nextsco->id . ');">' . '<img id="img' . $sublist . '" src="' . $scormpixdir . '/' . $icon . '.gif" alt="' . $strexpand . '" title="' . $strexpand . '"/></a>'; } else { if ($isvisible) { $result->toc .= "\t\t" . '<li><img src="' . $scormpixdir . '/spacer.gif" 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="' . $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') { if ($usertrack->status != 'completed') { $statusicon = '<img src="' . $scormpixdir . '/suspend.gif" alt="' . $strstatus . ' - ' . $strsuspended . '" title="' . $strstatus . ' - ' . $strsuspended . '" />'; } } } else { if ($play && empty($scoid)) { $scoid = $sco->id; } if ($sco->scormtype == 'sco') { $statusicon = '<img src="' . $scormpixdir . '/notattempted.gif" alt="' . get_string('notattempted', 'scorm') . '" title="' . get_string('notattempted', 'scorm') . '" />'; $incomplete = true; } else { $statusicon = '<img src="' . $scormpixdir . '/asset.gif" 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->prev) ? $sco->prev : 0; } if ($nextid == 0 && scorm_count_launchable($scorm->id, $currentorg) > 1 && $nextsco !== false && !$findnext) { if (!empty($sco->launch)) { $previd = $sco->id; } } require_once 'sequencinglib.php'; if (scorm_seq_evaluate($sco->id, $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 .= ' ' . 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) { $sco = $DB->get_record('scorm_scoes', array('id' => $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 el = document.ids ? document.ids[list] : document.getElementById ? document.getElementById(list) : document.all[list]; which = which.substring(0,(which.length)); var el2 = document.ids ? document.ids[which] : document.getElementById ? document.getElementById(which) : document.all[which]; if (el.style.display != "none") { el2.src = "' . $scormpixdir . '/plus.gif"; el.style.display=\'none\'; new cookie("hide:SCORMitem" + item, 1, 356, "/").set(); } else { el2.src = "' . $scormpixdir . '/minus.gif"; el.style.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; }
function scorm_simple_play($scorm, $user) { $result = false; if ($scorm->updatefreq == UPDATE_EVERYTIME) { scorm_parse($scorm); } $scoes = get_records_select('scorm_scoes', 'scorm=' . $scorm->id . ' AND launch<>\'' . sql_empty() . '\''); if ($scoes) { if ($scorm->skipview >= 1) { $sco = current($scoes); if (scorm_get_tracks($sco->id, $user->id) === false) { header('Location: player.php?a=' . $scorm->id . '&scoid=' . $sco->id); $result = true; } else { if ($scorm->skipview == 2) { header('Location: player.php?a=' . $scorm->id . '&scoid=' . $sco->id); $result = true; } } } } return $result; }
print_error('cannotcallscript'); } $aiccrequest = "MOODLE scoid: {$scoid}" . "\r\nMOODLE mode: {$mode}" . "\r\nMOODLE status: {$status}" . "\r\nMOODLE attempt: {$attempt}" . "\r\nAICC sessionid: {$sessionid}" . "\r\nAICC command: {$command}" . "\r\nAICC aiccdata:\r\n{$aiccdata}"; scorm_debug_log_write("aicc", "HACP Request:\r\n{$aiccrequest}", $scoid); ob_start(); if ($scorm = $DB->get_record('scorm', array('id' => $sco->scorm))) { switch ($command) { case 'getparam': if ($status == 'Not Initialized') { $scormsession->scormstatus = 'Running'; $status = 'Running'; } if ($status != 'Running') { echo "error=101\r\nerror_text=Terminated\r\n"; } else { if ($usertrack = scorm_get_tracks($scoid, $aiccuser->id, $attempt)) { $userdata = $usertrack; } else { $userdata->status = ''; $userdata->score_raw = ''; } $aiccuserid = get_config('scorm', 'aiccuserid'); if (!empty($aiccuserid)) { $userdata->student_id = $aiccuser->id; } else { $userdata->student_id = $aiccuser->username; } $userdata->student_name = $aiccuser->lastname . ', ' . $aiccuser->firstname; $userdata->mode = $mode; if ($userdata->mode == 'normal') { $userdata->credit = 'credit';
$row[] = $score; $row[] = $detailslink; } else { $row = array(format_string($sco->title), ' ', ' ', ' ', ' '); } $table->data[] = $row; } echo html_writer::table($table); } if (!empty($b)) { echo $OUTPUT->box_start('generalbox boxaligncenter'); echo $OUTPUT->heading('<a href="'.$CFG->wwwroot.'/mod/scorm/player.php?a='.$scorm->id.'&mode=browse&scoid='.$selsco->id.'" target="_new">'.format_string($selsco->title).'</a>'); echo '<div class="mdl-align">'."\n"; $scoreview = ''; if ($trackdata = scorm_get_tracks($selsco->id, $user, $attempt)) { if ($trackdata->score_raw != '') { $scoreview = get_string('score', 'scorm').': '.$trackdata->score_raw; } if ($trackdata->status == '') { $trackdata->status = 'notattempted'; } } else { $trackdata->status = 'notattempted'; $trackdata->total_time = ''; } $strstatus = get_string($trackdata->status, 'scorm'); echo '<img src="'.$OUTPUT->pix_url($trackdata->status, 'scorm').'" alt="'.$strstatus.'" title="'. $strstatus.'" /> '.scorm_format_duration($trackdata->total_time).'<br />'.$scoreview.'<br />'; echo '</div>'."\n"; echo '<hr /><h2>'.get_string('details', 'scorm').'</h2>';
/** * 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; }
$scorm->version = 'scorm_12'; } require_once $CFG->dirroot . '/mod/scorm/datamodels/' . $scorm->version . 'lib.php'; $attempt = scorm_get_last_attempt($scorm->id, $USER->id); if ($newattempt == 'on' && ($attempt < $scorm->maxattempt || $scorm->maxattempt == 0)) { $attempt++; $mode = 'normal'; } $attemptstr = '&attempt=' . $attempt; $result = scorm_get_toc($USER, $scorm, 'structurelist', $currentorg, $scoid, $mode, $attempt, true); $sco = $result->sco; if ($mode == 'browse' && $scorm->hidebrowse == 1) { $mode = 'normal'; } if ($mode != 'browse') { if ($trackdata = scorm_get_tracks($sco->id, $USER->id, $attempt)) { if ($trackdata->status == 'completed' || $trackdata->status == 'passed' || $trackdata->status == 'failed') { $mode = 'review'; } else { $mode = 'normal'; } } else { $mode = 'normal'; } } add_to_log($course->id, 'scorm', 'view', "player.php?id={$cm->id}&scoid={$sco->id}", "{$scorm->id}", $cm->id); $scoidstr = '&scoid=' . $sco->id; $scoidpop = '&scoid=' . $sco->id; $modestr = '&mode=' . $mode; if ($mode == 'browse') { $modepop = '&mode=' . $mode;
$graphdata[$i] = 0; } // Do this only if we have students to report. if (!empty($allowedlist)) { list($usql, $params) = $DB->get_in_or_equal($allowedlist); $params[] = $scoid; // Construct the SQL. $select = 'SELECT DISTINCT '.$DB->sql_concat('st.userid', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, '; $select .= 'st.userid AS userid, st.scormid AS scormid, st.attempt AS attempt, st.scoid AS scoid '; $from = 'FROM {scorm_scoes_track} st '; $where = ' WHERE st.userid ' .$usql. ' and st.scoid = ?'; $attempts = $DB->get_records_sql($select.$from.$where, $params); foreach ($attempts as $attempt) { if ($trackdata = scorm_get_tracks($scoid, $attempt->userid, $attempt->attempt)) { if (isset($trackdata->score_raw)) { $score = $trackdata->score_raw; if (empty($trackdata->score_min)) { $minmark = 0; } else { $minmark = $trackdata->score_min; } if (empty($trackdata->score_max)) { $maxmark = 100; } else { $maxmark = $trackdata->score_max; } $range = ($maxmark - $minmark); if (empty($range)) { continue;
function scorm_get_toc_object($user, $scorm, $currentorg = '', $scoid = '', $mode = 'normal', $attempt = '', $play = false, $organizationsco = null) { global $CFG, $DB, $PAGE, $OUTPUT; $modestr = ''; if ($mode != 'normal') { $modestr = '&mode=' . $mode; } $result = array(); $incomplete = false; if (!empty($organizationsco)) { $result[0] = $organizationsco; $result[0]->isvisible = true; $result[0]->statusicon = ''; $result[0]->url = ''; } 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; } } } foreach ($scoes as $sco) { if (!isset($sco->isvisible)) { $sco->isvisible = true; } if (empty($sco->title)) { $sco->title = $sco->identifier; } if (scorm_version_check($scorm->version, SCORM_13)) { $sco->prereq = true; } else { $sco->prereq = empty($sco->prerequisites) || scorm_eval_prerequisites($sco->prerequisites, $usertracks); } if ($sco->isvisible) { if (!empty($sco->launch)) { 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('asset', '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; } } $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 (empty($statusicon)) { $sco->statusicon = '<img src="' . $OUTPUT->pix_url('notattempted', 'scorm') . '" alt="' . get_string('notattempted', 'scorm') . '" title="' . 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, $currentorg); // Be safe, prevent warnings from showing up while returning array if (!isset($scoid)) { $scoid = ''; } return array('scoes' => $result, 'usertracks' => $usertracks, 'scoid' => $scoid); }
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; }