]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-11501 Scorm New attempts and reviewing. Changes to help customise player/package...
authorpiers <piers>
Tue, 16 Sep 2008 20:32:50 +0000 (20:32 +0000)
committerpiers <piers>
Tue, 16 Sep 2008 20:32:50 +0000 (20:32 +0000)
13 files changed:
lang/en_utf8/help/scorm/displayattemptstatus.html [new file with mode: 0644]
lang/en_utf8/help/scorm/displaycoursestructure.html [new file with mode: 0644]
lang/en_utf8/help/scorm/forcecompleted.html [new file with mode: 0644]
lang/en_utf8/help/scorm/forcenewattempt.html [new file with mode: 0644]
lang/en_utf8/help/scorm/lastattemptlock.html [new file with mode: 0644]
lang/en_utf8/scorm.php
mod/scorm/datamodel.php
mod/scorm/db/install.xml
mod/scorm/db/upgrade.php
mod/scorm/locallib.php
mod/scorm/mod_form.php
mod/scorm/version.php
mod/scorm/view.php

diff --git a/lang/en_utf8/help/scorm/displayattemptstatus.html b/lang/en_utf8/help/scorm/displayattemptstatus.html
new file mode 100644 (file)
index 0000000..1bc89a7
--- /dev/null
@@ -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>
diff --git a/lang/en_utf8/help/scorm/displaycoursestructure.html b/lang/en_utf8/help/scorm/displaycoursestructure.html
new file mode 100644 (file)
index 0000000..0089ba7
--- /dev/null
@@ -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>
diff --git a/lang/en_utf8/help/scorm/forcecompleted.html b/lang/en_utf8/help/scorm/forcecompleted.html
new file mode 100644 (file)
index 0000000..465abc4
--- /dev/null
@@ -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>
diff --git a/lang/en_utf8/help/scorm/forcenewattempt.html b/lang/en_utf8/help/scorm/forcenewattempt.html
new file mode 100644 (file)
index 0000000..ddbeee5
--- /dev/null
@@ -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>
diff --git a/lang/en_utf8/help/scorm/lastattemptlock.html b/lang/en_utf8/help/scorm/lastattemptlock.html
new file mode 100644 (file)
index 0000000..b714b89
--- /dev/null
@@ -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>
index 8cf989ed517d1e249afbeae0d7f5481d892ea758..cd91df31b9eeaa42a1bea081ba58c6168bdea517 100644 (file)
@@ -38,6 +38,8 @@ $string['details'] = 'Track details';
 $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';
@@ -56,9 +58,12 @@ $string['frameheight'] = 'This preference set the default height for stage frame
 $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';
@@ -78,6 +83,7 @@ $string['invalidactivity'] = 'Scorm activity is incorrect';
 $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';
@@ -176,4 +182,8 @@ $string['activityloading'] = "You will be automatically redirected to the activi
 $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.";
 ?>
\ No newline at end of file
index 19d4905b15eeeaf0b99560469f25ea6d3412321b..a10875b7457bdf095d17dd89df8bfeebf583a4e3 100755 (executable)
@@ -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
index 12642de474d8cd1e8435aaed8e525981f85e742a..dabb226add780ba34057d7c8052ba70197ecc54a 100644 (file)
         <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"/>
index 9061b248e9c969336c5593d77bc996d69853b722..5e4611eb46da20e14b446816c77ede38155ec12a 100644 (file)
@@ -234,6 +234,36 @@ function xmldb_scorm_upgrade($oldversion) {
         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;
 }
 
index 7fecd22debd23396520699a93c95aa92ccea89ef..28a6ff0355460468d466498e94efc09c9efe6caf 100755 (executable)
@@ -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();
@@ -499,6 +517,8 @@ function scorm_get_last_attempt($scormid, $userid) {
         } else {
             return $lastattempt->a;
         }
+    } else {
+        return false;
     }
 }
 
@@ -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;
     }
@@ -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">
@@ -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
                   }
               ?>
@@ -637,6 +672,7 @@ function scorm_view_display ($user, $scorm, $action, $cm, $boxwidth='') {
               </form>
           </div>
 <?php
+    }
 }
 
 function scorm_simple_play($scorm,$user) {
@@ -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;
+}
 ?>
\ No newline at end of file
index 399edc375068c975782473c0d009e75803fd5139..4d1453dc6aa2abc1929e4c0a7a367afe3d767b0e 100644 (file)
@@ -103,6 +103,34 @@ class mod_scorm_mod_form extends moodleform_mod {
         $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);
index 3abb85dc7348f8308ceb0fa1fc515915cc62a309..febd804a2aebf4f483f8a314624772aebc0fb8b0 100755 (executable)
@@ -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)?
 
index 1cfc00d25ce253eda5903d57f7b0e224cd4cb8af..4ccdc3c579804b501ed4b62339b094016f08a662 100755 (executable)
 
     // 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);
 ?>