Skip to content

Commit

Permalink
MDL-11501 Scorm New attempts and reviewing. Changes to help customis…
Browse files Browse the repository at this point in the history
…e player/package interactions.
  • Loading branch information
piers committed Sep 16, 2008
1 parent ad1cfbb commit 6381fa5
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 13 deletions.
4 changes: 4 additions & 0 deletions lang/en_utf8/help/scorm/displayattemptstatus.html
@@ -0,0 +1,4 @@
<h1>Display Attempt Status</h1>

<p>Display attempt status controls whether the status of SCORM attempts by a student are displayed on the SCORM outline page. </p>
<p>The status displays attempts, the scores, and grade passed to the Gradebook</P>
3 changes: 3 additions & 0 deletions lang/en_utf8/help/scorm/displaycoursestructure.html
@@ -0,0 +1,3 @@
<h1>Display Course Structure</h1>

<p>Display course structure controls whether the SCORM table of contents gets displayed on the SCORM outline page. </p>
4 changes: 4 additions & 0 deletions lang/en_utf8/help/scorm/forcecompleted.html
@@ -0,0 +1,4 @@
<h1>Force Completed</h1>

<p>Force completed will ensure that the status of the current attempt is forced to "completed" if cmi.core.score.raw has been issued, and as such is only relevant for SCORM 1.2 packages. </p>
<p>This is usefull if the SCORM package does not handle revisiting an attempt correctly, in review or browse mode, or otherwise incorrectly issues the completion status.</p>
3 changes: 3 additions & 0 deletions lang/en_utf8/help/scorm/forcenewattempt.html
@@ -0,0 +1,3 @@
<h1>Force New Attempt</h1>

<p>Force new attempt will make every visit to a SCORM package a new attempt. </p>
4 changes: 4 additions & 0 deletions lang/en_utf8/help/scorm/lastattemptlock.html
@@ -0,0 +1,4 @@
<h1>Lock After Final Attempt</h1>

<p>This enables the locking of the SCORM player after a student has used all of their allocated attempts.</p>
<p>The student will still be able to visit the course outline page and view the attempts status information (if enabled), but will not beable to select "Enter" to launch the player.</p>
10 changes: 10 additions & 0 deletions lang/en_utf8/scorm.php
Expand Up @@ -38,6 +38,8 @@
$string['directories'] = 'Show the directory links';
$string['display'] = 'Display package';
$string['domxml'] = 'DOMXML external library';
$string['displayattemptstatus'] = 'Display attempt status';
$string['displaycoursestructure'] = 'Display course structure';
$string['element'] = 'Element';
$string['entercourse'] = 'Enter course';
$string['enter'] = 'Enter';
Expand All @@ -56,9 +58,12 @@
$string['framewidth'] = 'This preference set the default width for stage frame or window';
$string['fullscreen'] = 'Fill the whole screen';
$string['general'] = 'General data';
$string['forcenewattempt'] = 'Force new attempt';
$string['forcecompleted'] = 'Force completed';
$string['gradeaverage'] = 'Average grade';
$string['gradehighest'] = 'Highest grade';
$string['grademethod'] = 'Grading method';
$string['gradereported'] = 'Grade reported';
$string['gradescoes'] = 'Learning Objects';
$string['gradesum'] = 'Sum grade';
$string['height'] = 'Height';
Expand All @@ -78,6 +83,7 @@
$string['last'] = 'Last accessed on';
$string['lastaccess'] = 'Last access';
$string['lastattempt'] = 'Last attempt';
$string['lastattemptlock'] = 'Lock after final attempt';
$string['location'] = 'Show the location bar';
$string['max'] = 'Max score';
$string['maximumattempts'] = 'Number of attempts';
Expand Down Expand Up @@ -176,4 +182,8 @@
$string['activitypleasewait'] = "Activity loading, please wait ....";
$string['scormloggingon'] = "API Logging is On";
$string['scormloggingoff'] = "API Logging is Off";
$string['noattemptsallowed'] = "Number of attempts allowed";
$string['noattemptsmade'] = "Number of attempts you have made";
$string['gradeforattempt'] = "Grade for attempt";
$string['exceededmaxattempts'] = "You have reached the maximum number of attempts.";
?>
2 changes: 1 addition & 1 deletion mod/scorm/datamodel.php
Expand Up @@ -43,7 +43,7 @@
$element = str_replace('__','.',$element);
if (substr($element,0,3) == 'cmi') {
$netelement = preg_replace('/\.N(\d+)\./',"\.\$1\.",$element);
$result = scorm_insert_track($USER->id, $scorm->id, $scoid, $attempt, $netelement, $value) && $result;
$result = scorm_insert_track($USER->id, $scorm->id, $scoid, $attempt, $element, $value, $scorm->forcecompleted) && $result;
}
if (substr($element,0,15) == 'adl.nav.request') {
// SCORM 2004 Sequencing Request
Expand Down
9 changes: 7 additions & 2 deletions mod/scorm/db/install.xml
Expand Up @@ -16,8 +16,13 @@
<FIELD NAME="maxgrade" TYPE="float" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="version" NEXT="grademethod"/>
<FIELD NAME="grademethod" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="maxgrade" NEXT="whatgrade"/>
<FIELD NAME="whatgrade" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="grademethod" NEXT="maxattempt"/>
<FIELD NAME="maxattempt" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" ENUM="false" PREVIOUS="whatgrade" NEXT="updatefreq"/>
<FIELD NAME="updatefreq" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Define when the package must be automatically update" PREVIOUS="maxattempt" NEXT="sha1hash"/>
<FIELD NAME="maxattempt" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" ENUM="false" PREVIOUS="whatgrade" NEXT="forcenewattempt"/>
<FIELD NAME="forcecompleted" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" ENUM="false" PREVIOUS="maxattempt" NEXT="forcenewattempt"/>
<FIELD NAME="forcenewattempt" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="forcecompleted" NEXT="lastattemptlock"/>
<FIELD NAME="lastattemptlock" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="forcenewattempt" NEXT="displayattemptstatus"/>
<FIELD NAME="displayattemptstatus" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" ENUM="false" PREVIOUS="lastattemptlock" NEXT="displaycoursestructure"/>
<FIELD NAME="displaycoursestructure" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" ENUM="false" PREVIOUS="displayattemptstatus" NEXT="updatefreq"/>
<FIELD NAME="updatefreq" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Define when the package must be automatically update" PREVIOUS="displaycoursestructure" NEXT="sha1hash"/>
<FIELD NAME="sha1hash" TYPE="char" LENGTH="40" NOTNULL="false" SEQUENCE="false" ENUM="false" COMMENT="pacakge content or ext path hash" PREVIOUS="updatefreq" NEXT="md5hash"/>
<FIELD NAME="md5hash" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" ENUM="false" COMMENT="MD5 Hash of package file" PREVIOUS="sha1hash" NEXT="revision"/>
<FIELD NAME="revision" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="revison number" PREVIOUS="md5hash" NEXT="launch"/>
Expand Down
30 changes: 30 additions & 0 deletions mod/scorm/db/upgrade.php
Expand Up @@ -234,6 +234,36 @@ function scorm_migrate_content_files($context, $base, $path) {
upgrade_mod_savepoint($result, 2008090304, 'scorm');
}


if ($result && $oldversion < 2008090305) {

/// Define new fields forcecompleted, forcenewattempt, displayattemptstatus, and displaycoursestructure to be added to scorm
$table = new xmldb_table('scorm');
$field = new xmldb_field('forcecompleted', XMLDB_TYPE_INTEGER, '1', null, null, null, null, null, '0', 'maxattempt');
if (!$dbman->field_exists($table,$field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('forcenewattempt', XMLDB_TYPE_INTEGER, '1', null, null, null, null, null, '0', 'forcecompleted');
if (!$dbman->field_exists($table,$field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('lastattemptlock', XMLDB_TYPE_INTEGER, '1', null, null, null, null, null, '0', 'forcenewattempt');
if (!$dbman->field_exists($table,$field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('displayattemptstatus', XMLDB_TYPE_INTEGER, '1', null, null, null, null, null, '1', 'lastattemptlock');
if (!$dbman->field_exists($table,$field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('displaycoursestructure', XMLDB_TYPE_INTEGER, '1', null, null, null, null, null, '1', 'displayattemptstatus');
if (!$dbman->field_exists($table,$field)) {
$dbman->add_field($table, $field);
}

/// scorm savepoint reached
upgrade_mod_savepoint($result, 2008090305, 'scorm');
}

return $result;
}

Expand Down
135 changes: 127 additions & 8 deletions mod/scorm/locallib.php
Expand Up @@ -238,10 +238,28 @@ function scorm_get_scoes($id,$organisation=false) {
}
}

function scorm_insert_track($userid,$scormid,$scoid,$attempt,$element,$value) {
function scorm_insert_track($userid,$scormid,$scoid,$attempt,$element,$value,$forcecompleted=false) {
global $DB;

$id = null;

if ($forcecompleted) {
//TODO - this could be broadened to encompass SCORM 2004 in future
if (($element == 'cmi.core.lesson_status') && ($value == 'incomplete')) {
if ($track = $DB->get_record_select('scorm_scoes_track','userid=? AND scormid=? AND scoid=? AND attempt=? AND element=\'cmi.core.score.raw\'', array($userid, $scormid, $scoid, $attempt))) {
$value = 'completed';
}
}
if ($element == 'cmi.core.score.raw') {
if ($tracktest = $DB->get_record_select('scorm_scoes_track','userid=? AND scormid=? AND scoid=? AND attempt=? AND element=\'cmi.core.lesson_status\'', array($userid, $scormid, $scoid, $attempt))) {
if ($tracktest->value == "incomplete") {
$tracktest->value = "completed";
$idtest = $DB->update_record('scorm_scoes_track',$tracktest);
}
}
}
}

if ($track = $DB->get_record('scorm_scoes_track',array('userid'=>$userid, 'scormid'=>$scormid, 'scoid'=>$scoid, 'attempt'=>$attempt, 'element'=>$element))) {
$track->value = $value;
$track->timemodified = time();
Expand Down Expand Up @@ -499,6 +517,8 @@ function scorm_get_last_attempt($scormid, $userid) {
} else {
return $lastattempt->a;
}
} else {
return false;
}
}

Expand Down Expand Up @@ -561,10 +581,12 @@ function scorm_view_display ($user, $scorm, $action, $cm, $boxwidth='') {

$organization = optional_param('organization', '', PARAM_INT);

print_simple_box_start('center',$boxwidth);
if($scorm->displaycoursestructure == 1) {
print_simple_box_start('center',$boxwidth);
?>
<div class="structurehead"><?php print_string('contents','scorm') ?></div>
<?php
}
if (empty($organization)) {
$organization = $scorm->launch;
}
Expand Down Expand Up @@ -607,9 +629,18 @@ function scorm_view_display ($user, $scorm, $action, $cm, $boxwidth='') {

$result = scorm_get_toc($user,$scorm,'structlist',$orgidentifier);
$incomplete = $result->incomplete;
echo $result->toc;
print_simple_box_end();

// do we want the TOC to be displayed?
if($scorm->displaycoursestructure == 1) {
echo $result->toc;
print_simple_box_end();
}

// is this the first attempt ?
$attemptcount = scorm_get_attempt_count($user, $scorm);

// do not give the player launch FORM if the SCORM object is locked after the final attempt
if ($scorm->lastattemptlock == 0 || $result->attemptleft > 0) {
?>
<div class="scorm-center">
<form id="theform" method="post" action="<?php echo $CFG->wwwroot ?>/mod/scorm/player.php">
Expand All @@ -621,11 +652,15 @@ function scorm_view_display ($user, $scorm, $action, $cm, $boxwidth='') {
} else {
echo '<input type="hidden" name="mode" value="normal" />'."\n";
}
if (($incomplete === false) && (($result->attemptleft > 0)||($scorm->maxattempt == 0))) {
if ($scorm->forcenewattempt == 1) {
if ($incomplete === false) {
echo '<input type="hidden" name="newattempt" value="on" />'."\n";
}
} elseif ($attemptcount != 0 && ($incomplete === false) && (($result->attemptleft > 0)||($scorm->maxattempt == 0))) {
?>
<br />
<input type="checkbox" id="a" name="newattempt" />
<label for="a"><?php print_string('newattempt','scorm') ?></label>
<br />
<input type="checkbox" id="a" name="newattempt" />
<label for="a"><?php print_string('newattempt','scorm') ?></label>
<?php
}
?>
Expand All @@ -637,6 +672,7 @@ function scorm_view_display ($user, $scorm, $action, $cm, $boxwidth='') {
</form>
</div>
<?php
}
}

function scorm_simple_play($scorm,$user) {
Expand Down Expand Up @@ -777,4 +813,87 @@ function scorm_element_cmp($a, $b) {
return 0; // equal to
}
}

/**
* Generate the user attempt status string
*
* @param object $user Current context user
* @param object $scorm a moodle scrom object - mdl_scorm
* @return string - Attempt status string
*/
function scorm_get_attempt_status($user, $scorm) {
global $DB;

$attempts = $DB->get_records_select('scorm_scoes_track',"element='cmi.core.score.raw' AND userid=? AND scormid=?", array($user->id, $scorm->id),'attempt','attempt AS attemptnumber, value AS grade');
if(empty($attempts)) {
$attemptcount = 0;
} else {
$attemptcount = count($attempts);
}

$result = '<p>'.get_string('noattemptsallowed', 'scorm').': ';
if ($scorm->maxattempt > 0) {
$result .= $scorm->maxattempt . '<BR>';
} else {
$result .= get_string('unlimited').'<BR>';
}
$result .= get_string('noattemptsmade', 'scorm').': ' . $attemptcount . '<BR>';

$gradereported = 0;
$gradesum = 0;
switch ($scorm->grademethod) {
case GRADEHIGHEST:
$grademethod = get_string('gradehighest', 'scorm');
break;
case GRADEAVERAGE:
$grademethod = get_string('gradeaverage', 'scorm');
break;
case GRADESUM:
$grademethod = get_string('gradesum', 'scorm');
break;
case GRADESCOES:
$grademethod = get_string('gradescoes', 'scorm');
break;
}

if(!empty($attempts)) {
foreach($attempts as $attempt) {
$gradereported = scorm_grade_user_attempt($scorm, $user->id, $attempt->attemptnumber);
$result .= get_string('gradeforattempt', 'scorm').' ' . $attempt->attemptnumber . ': ' . $attempt->grade .'%<BR>';
}
}

$result .= get_string('grademethod', 'scorm'). ': ' . $grademethod;
if(empty($attempts)) {
$result .= '<BR>' . get_string('gradereported','scorm') . ': ' . get_string('none') . '<BR>';
} else {
$result .= '<BR>' . get_string('gradereported','scorm') . ': ' . $gradereported . ($scorm->grademethod == GRADESCOES ? '' : '%') .'<BR>';
}
$result .= '</p>';
if ($attemptcount >= $scorm->maxattempt and $scorm->maxattempt > 0) {
$result .= '<p><font color="#cc0000">'.get_string('exceededmaxattempts','scorm').'</font></p>';
}
return $result;
}

/**
* Get SCORM attempt count
*
* @param object $user Current context user
* @param object $scorm a moodle scrom object - mdl_scorm
* @return int - no. of attempts so far
*/
function scorm_get_attempt_count($user, $scorm) {
global $DB;
$attemptcount = 0;
$element = 'cmi.core.score.raw';
if ($scorm->version == 'scorm1_3') {
$element = 'cmi.score.raw';
}
$attempts = $DB->get_records_select('scorm_scoes_track',"element=? AND userid=? AND scormid=?", array($element, $user->id, $scorm->id),'attempt','attempt AS attemptnumber, value AS grade');
if(!empty($attempts)) {
$attemptcount = count($attempts);
}
return $attemptcount;
}
?>
28 changes: 28 additions & 0 deletions mod/scorm/mod_form.php
Expand Up @@ -103,6 +103,34 @@ function definition() {
$mform->setHelpButton('maxattempt', array('maxattempt',get_string('maximumattempts', 'scorm'), 'scorm'));
$mform->setDefault('maxattempt', 1);

// Display attempt status
$mform->addElement('selectyesno', 'displayattemptstatus', get_string('displayattemptstatus', 'scorm'));
$mform->setHelpButton('displayattemptstatus', array('displayattemptstatus',get_string('displayattemptstatus', 'scorm'), 'scorm'));
$mform->setDefault('displayattemptstatus', 1);

// Display course structure
$mform->addElement('selectyesno', 'displaycoursestructure', get_string('displaycoursestructure', 'scorm'));
$mform->setHelpButton('displaycoursestructure', array('displaycoursestructure',get_string('displaycoursestructure', 'scorm'), 'scorm'));
$mform->setDefault('displaycoursestructure', 1);

// Force completed
$mform->addElement('selectyesno', 'forcecompleted', get_string('forcecompleted', 'scorm'));
$mform->setHelpButton('forcecompleted', array('forcecompleted',get_string('forcecompleted', 'scorm'), 'scorm'));
$mform->setDefault('forcecompleted', 0);
$mform->setAdvanced('forcecompleted');

// Force new attempt
$mform->addElement('selectyesno', 'forcenewattempt', get_string('forcenewattempt', 'scorm'));
$mform->setHelpButton('forcenewattempt', array('forcenewattempt',get_string('forcenewattempt', 'scorm'), 'scorm'));
$mform->setDefault('forcenewattempt', 0);
$mform->setAdvanced('forcenewattempt');

// Last attempt lock - lock the enter button after the last available attempt has been made
$mform->addElement('selectyesno', 'lastattemptlock', get_string('lastattemptlock', 'scorm'));
$mform->setHelpButton('lastattemptlock', array('lastattemptlock',get_string('lastattemptlock', 'scorm'), 'scorm'));
$mform->setDefault('lastattemptlock', 0);
$mform->setAdvanced('lastattemptlock');

// What Grade
$mform->addElement('select', 'whatgrade', get_string('whatgrade', 'scorm'), $SCORM_WHAT_GRADE);
$mform->disabledIf('whatgrade', 'maxattempt','eq',1);
Expand Down
2 changes: 1 addition & 1 deletion mod/scorm/version.php
Expand Up @@ -10,7 +10,7 @@
// catch up now, so until 27th October please only increment in very tiny steps
// in HEAD, until we get past that date..

$module->version = 2008090304; // The (date) version of this module
$module->version = 2008090305; // The (date) version of this module
$module->requires = 2008090108; // The version of Moodle that is required
$module->cron = 300; // How often should cron check this module (seconds)?
Expand Down
6 changes: 5 additions & 1 deletion mod/scorm/view.php
Expand Up @@ -82,7 +82,11 @@

// Print the main part of the page
print_heading(format_string($scorm->name));
print_box(format_text($scorm->summary), 'generalbox', 'intro');
$attemptstatus = '';
if($scorm->displayattemptstatus == 1) {
$attemptstatus = scorm_get_attempt_status($USER,$scorm);
}
print_simple_box(format_text($scorm->summary).$attemptstatus, 'center', '70%', '', 5, 'generalbox', 'intro');
scorm_view_display($USER, $scorm, 'view.php?id='.$cm->id, $cm);
print_footer($course);
?>

0 comments on commit 6381fa5

Please sign in to comment.