diff --git a/mod/scorm/classes/external.php b/mod/scorm/classes/external.php index a3907f47ce3..3045fa33f86 100644 --- a/mod/scorm/classes/external.php +++ b/mod/scorm/classes/external.php @@ -782,7 +782,7 @@ class mod_scorm_external extends external_api { 'maxattempt' => new external_value(PARAM_INT, 'Maximum number of attemtps', VALUE_OPTIONAL), 'forcecompleted' => new external_value(PARAM_BOOL, 'Status current attempt is forced to "completed"', VALUE_OPTIONAL), - 'forcenewattempt' => new external_value(PARAM_BOOL, 'Hides the "Start new attempt" checkbox', + 'forcenewattempt' => new external_value(PARAM_INT, 'Controls re-entry behaviour', VALUE_OPTIONAL), 'lastattemptlock' => new external_value(PARAM_BOOL, 'Prevents to launch new attempts once finished', VALUE_OPTIONAL), diff --git a/mod/scorm/lang/en/scorm.php b/mod/scorm/lang/en/scorm.php index c6ad22ff722..acbed2cbcaa 100644 --- a/mod/scorm/lang/en/scorm.php +++ b/mod/scorm/lang/en/scorm.php @@ -150,11 +150,14 @@ $string['floating'] = 'Floating'; $string['forcecompleted'] = 'Force completed'; $string['forcecompleted_help'] = 'If enabled, the status of the current attempt is forced to "completed". (Only applicable to SCORM 1.2 packages.)'; $string['forcecompleteddesc'] = 'This preference sets the default value for the force completed setting'; -$string['forcenewattempt'] = 'Force new attempt'; -$string['forcenewattempt_help'] = 'This setting hides the "Start new attempt" checkbox and prevents review mode. +$string['forcenewattempts'] = 'Force new attempt'; +$string['forcenewattempts_help'] = 'There are 3 options: -SCORM allows a student to return to the same attempt at any point and a new attempt is not possible unless the previous attempt has been set as "completed", "passed" or "failed". If the SCORM package does not do this, the student will always re-enter the same attempt.'; -$string['forcenewattemptdesc'] = 'This setting hides the "Start new attempt" checkbox and prevents review mode. SCORM allows a student to return to the same attempt at any point and a new attempt is not possible unless the previous attempt has been set as "completed", "passed" or "failed". If the SCORM package does not do this, the student will always re-enter the same attempt.'; +* No - If a previous attempt is completed, passed or failed, the student will be provided with the option to enter in review mode or start a new attempt. +* When previous attempt completed, passed or failed - This relies on the SCORM package setting the status of \'completed\', \'passed\' or \'failed\'. +* Always - Each re-entry to the SCORM activity will generate a new attempt and the student will not be returned to the same point they reached in their previous attempt.'; +$string['forceattemptalways'] = 'Always'; +$string['forceattemptoncomplete'] = 'When previous attempt completed, passed or failed'; $string['forcejavascript'] = 'Force users to enable JavaScript'; $string['forcejavascript_desc'] = 'If enabled (recommended) this prevents access to SCORM objects when JavaScript is not supported/enabled in a users browser. If disabled the user may view the SCORM but API communication will fail and no grade information will be saved.'; $string['forcejavascriptmessage'] = 'JavaScript is required to view this object, please enable JavaScript in your browser and try again.'; diff --git a/mod/scorm/lib.php b/mod/scorm/lib.php index 6543851bfb0..ee88c55e982 100644 --- a/mod/scorm/lib.php +++ b/mod/scorm/lib.php @@ -1450,6 +1450,14 @@ function scorm_check_mode($scorm, &$newattempt, &$attempt, $userid, &$mode) { return; } } + + if ($scorm->forcenewattempt == SCORM_FORCEATTEMPT_ALWAYS) { + // This SCORM is configured to force a new attempt on every re-entry. + $attempt++; + $newattempt = 'on'; + $mode = 'normal'; + return; + } // Check if the scorm module is incomplete (used to validate user request to start a new attempt). $incomplete = true; diff --git a/mod/scorm/locallib.php b/mod/scorm/locallib.php index 58fbc8aa548..27e4b945bed 100644 --- a/mod/scorm/locallib.php +++ b/mod/scorm/locallib.php @@ -51,6 +51,10 @@ define('LASTATTEMPT', '3'); define('TOCJSLINK', 1); define('TOCFULLURL', 2); +define('SCORM_FORCEATTEMPT_NO', 0); +define('SCORM_FORCEATTEMPT_ONCOMPLETE', 1); +define('SCORM_FORCEATTEMPT_ALWAYS', 2); + // Local Library of functions for module scorm. /** @@ -196,6 +200,17 @@ function scorm_get_attemptstatus_array() { SCORM_DISPLAY_ATTEMPTSTATUS_ENTRY => get_string('attemptstatusentry', 'scorm')); } +/** + * Returns an array of the force attempt options + * + * @return array an array of attempt options + */ +function scorm_get_forceattempt_array() { + return array(SCORM_FORCEATTEMPT_NO => get_string('no'), + SCORM_FORCEATTEMPT_ONCOMPLETE => get_string('forceattemptoncomplete', 'scorm'), + SCORM_FORCEATTEMPT_ALWAYS => get_string('forceattemptalways', 'scorm')); +} + /** * Extracts scrom package, sets up all variables. * Called whenever scorm changes @@ -931,8 +946,8 @@ function scorm_print_launch ($user, $scorm, $action, $cm) { $result = scorm_get_toc($user, $scorm, $cm->id, TOCFULLURL, $orgidentifier); $incomplete = $result->incomplete; - // Get latest incomplete sco to launch first. - if (!empty($result->sco->id)) { + // Get latest incomplete sco to launch first if force new attempt isn't set to always. + if (!empty($result->sco->id) && $scorm->forcenewattempt != SCORM_FORCEATTEMPT_ALWAYS) { $launchsco = $result->sco->id; } else { // Use launch defined by SCORM package. @@ -969,8 +984,9 @@ function scorm_print_launch ($user, $scorm, $action, $cm) { } else { echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'mode', 'value' => 'normal')); } - if ($scorm->forcenewattempt == 1) { - if ($incomplete === false) { + if (!empty($scorm->forcenewattempt)) { + if ($scorm->forcenewattempt == SCORM_FORCEATTEMPT_ALWAYS || + ($scorm->forcenewattempt == SCORM_FORCEATTEMPT_ONCOMPLETE && $incomplete === false)) { echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'newattempt', 'value' => 'on')); } } else if (!empty($attemptcount) && ($incomplete === false) && (($result->attemptleft > 0)||($scorm->maxattempt == 0))) { @@ -1023,19 +1039,18 @@ function scorm_simple_play($scorm, $user, $context, $cmid) { $result = scorm_get_toc($user, $scorm, $cmid, TOCFULLURL, $orgidentifier); $url = new moodle_url('/mod/scorm/player.php', array('a' => $scorm->id, 'currentorg' => $orgidentifier)); - // Set last incomplete sco to launch first. - if (!empty($result->sco->id)) { + // Set last incomplete sco to launch first if forcenewattempt not set to always. + if (!empty($result->sco->id) && $scorm->forcenewattempt != SCORM_FORCEATTEMPT_ALWAYS) { $url->param('scoid', $result->sco->id); } else { $url->param('scoid', $sco->id); } if ($scorm->skipview == SCORM_SKIPVIEW_ALWAYS || !scorm_has_tracks($scorm->id, $user->id)) { - if (!empty($scorm->forcenewattempt)) { + if ($scorm->forcenewattempt == SCORM_FORCEATTEMPT_ALWAYS || + ($result->incomplete === false && $scorm->forcenewattempt == SCORM_FORCEATTEMPT_ONCOMPLETE)) { - if ($result->incomplete === false) { - $url->param('newattempt', 'on'); - } + $url->param('newattempt', 'on'); } redirect($url); } diff --git a/mod/scorm/mod_form.php b/mod/scorm/mod_form.php index 82d650a1bda..a84fbb09ef2 100644 --- a/mod/scorm/mod_form.php +++ b/mod/scorm/mod_form.php @@ -228,8 +228,9 @@ class mod_scorm_mod_form extends moodleform_mod { $mform->setDefault('whatgrade', $cfgscorm->whatgrade); // Force new attempt. - $mform->addElement('selectyesno', 'forcenewattempt', get_string('forcenewattempt', 'scorm')); - $mform->addHelpButton('forcenewattempt', 'forcenewattempt', 'scorm'); + $newattemptselect = scorm_get_forceattempt_array(); + $mform->addElement('select', 'forcenewattempt', get_string('forcenewattempts', 'scorm'), $newattemptselect); + $mform->addHelpButton('forcenewattempt', 'forcenewattempts', 'scorm'); $mform->setDefault('forcenewattempt', $cfgscorm->forcenewattempt); // Last attempt lock - lock the enter button after the last available attempt has been made. diff --git a/mod/scorm/settings.php b/mod/scorm/settings.php index 28965085bd4..ec7c8c58c2c 100644 --- a/mod/scorm/settings.php +++ b/mod/scorm/settings.php @@ -108,8 +108,9 @@ if ($ADMIN->fulltree) { $settings->add(new admin_setting_configselect('scorm/forcecompleted', get_string('forcecompleted', 'scorm'), get_string('forcecompleteddesc', 'scorm'), 0, $yesno)); + $forceattempts = scorm_get_forceattempt_array(); $settings->add(new admin_setting_configselect('scorm/forcenewattempt', - get_string('forcenewattempt', 'scorm'), get_string('forcenewattemptdesc', 'scorm'), 0, $yesno)); + get_string('forcenewattempts', 'scorm'), get_string('forcenewattempts_help', 'scorm'), 0, $forceattempts)); $settings->add(new admin_setting_configselect('scorm/autocommit', get_string('autocommit', 'scorm'), get_string('autocommitdesc', 'scorm'), 0, $yesno)); diff --git a/mod/scorm/tests/behat/multisco_review_mode.feature b/mod/scorm/tests/behat/multisco_review_mode.feature index 69a5c8348df..2c922ddc0d8 100644 --- a/mod/scorm/tests/behat/multisco_review_mode.feature +++ b/mod/scorm/tests/behat/multisco_review_mode.feature @@ -1,8 +1,6 @@ @mod @mod_scorm @_file_upload @_switch_iframe Feature: Scorm multi-sco review mode. - In order to let students access a scorm package - As a teacher - I need to add scorm activity to a course + Check review mode and attempt handling. Background: Given the following "users" exist: | username | firstname | lastname | email | @@ -28,6 +26,7 @@ Feature: Scorm multi-sco review mode. And I set the following fields to these values: | Name | Basic Multi-sco SCORM package | | Description | Description | + | Force new attempt | No | And I set the field "Completed" to "1" And I upload "mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12.zip" file to "Package file" filemanager And I click on "Save and display" "button" @@ -64,6 +63,7 @@ Feature: Scorm multi-sco review mode. | Description | Description | | Completion tracking | Show activity as complete when conditions are met | | Require all scos to return completion status | 1 | + | Force new attempt | No | And I set the field "Completed" to "1" And I upload "mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12.zip" file to "Package file" filemanager And I click on "Save and display" "button" @@ -170,3 +170,217 @@ Feature: Scorm multi-sco review mode. And I should see "Normal" And I press "Enter" Then I should see "Review mode" + + @javascript + Scenario: Test force completed set to Always. + When I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I add a "SCORM package" to section "1" + And I set the following fields to these values: + | Name | Basic Multi-sco SCORM package | + | Description | Description | + | Force new attempt | Always | + And I upload "mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip" file to "Package file" filemanager + And I click on "Save and display" "button" + And I should see "Basic Multi-sco SCORM package" + And I log out + And I log in as "student1" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + And I should see "Normal" + And I press "Enter" + And I switch to "scorm_object" iframe + And I should see "Play of the game" + And I switch to the main frame + And I follow "Exit activity" + And I wait until the page is ready + And I should see "Basic Multi-sco SCORM package" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + And I should see "Normal" + And I should not see "Start a new attempt" + And I press "Enter" + Then I should not see "Review mode" + And I switch to "scorm_object" iframe + And I should see "Play of the game" + + @javascript + Scenario: Test force completed set to when previous complete/passed/failed. + When I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I add a "SCORM package" to section "1" + And I set the following fields to these values: + | Name | Basic Multi-sco SCORM package | + | Description | Description | + | Force new attempt | When previous attempt completed, passed or failed | + And I upload "mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip" file to "Package file" filemanager + And I click on "Save and display" "button" + And I should see "Basic Multi-sco SCORM package" + And I log out + And I log in as "student1" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + And I should see "Normal" + And I press "Enter" + And I switch to "scorm_object" iframe + And I should see "Play of the game" + And I switch to the main frame + And I follow "Exit activity" + And I wait until the page is ready + And I should see "Basic Multi-sco SCORM package" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + And I should see "Normal" + And I should not see "Start a new attempt" + And I press "Enter" + And I should not see "Review mode" + And I switch to "scorm_object" iframe + And I should see "Par" + + And I switch to the main frame + And I click on "Keeping Score" "list_item" + And I switch to "scorm_object" iframe + And I should see "Scoring" + + And I switch to the main frame + And I click on "Other Scoring Systems" "list_item" + And I switch to "scorm_object" iframe + And I should see "Other Scoring Systems" + + And I switch to the main frame + And I click on "The Rules of Golf" "list_item" + And I switch to "scorm_object" iframe + And I should see "The Rules of Golf" + + And I switch to the main frame + And I click on "Playing Golf Quiz" "list_item" + And I switch to "scorm_object" iframe + And I should see "Knowledge Check" + + And I switch to the main frame + And I click on "How to Have Fun Playing Golf" "list_item" + And I switch to "scorm_object" iframe + And I should see "How to Have Fun Golfing" + + And I switch to the main frame + And I click on "How to Make Friends Playing Golf" "list_item" + And I switch to "scorm_object" iframe + And I should see "How to Make Friends on the Golf Course" + + And I switch to the main frame + And I click on "Having Fun Quiz" "list_item" + And I switch to "scorm_object" iframe + And I should see "Knowledge Check" + And I switch to the main frame + And I follow "Exit activity" + And I wait until the page is ready + And I should see "Basic Multi-sco SCORM package" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + And I should see "Normal" + And I press "Enter" + Then I should not see "Review mode" + And I switch to "scorm_object" iframe + And I should see "Play of the game" + + @javascript + Scenario: Test force completed set to Always and student skipview + When I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I add a "SCORM package" to section "1" + And I set the following fields to these values: + | Name | Basic Multi-sco SCORM package | + | Description | Description | + | Force new attempt | Always | + | Student skip content structure page | Always | + And I upload "mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip" file to "Package file" filemanager + And I click on "Save and display" "button" + And I should see "Basic Multi-sco SCORM package" + And I log out + And I log in as "student1" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + And I switch to "scorm_object" iframe + And I should see "Play of the game" + And I switch to the main frame + And I follow "Exit activity" + And I wait until the page is ready + And I should see "Basic Multi-sco SCORM package" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + Then I should not see "Review mode" + And I switch to "scorm_object" iframe + And I should see "Play of the game" + + @javascript + Scenario: Test force completed set to when previous complete/passed/failed. + When I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I add a "SCORM package" to section "1" + And I set the following fields to these values: + | Name | Basic Multi-sco SCORM package | + | Description | Description | + | Force new attempt | When previous attempt completed, passed or failed | + | Student skip content structure page | Always | + And I upload "mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip" file to "Package file" filemanager + And I click on "Save and display" "button" + And I should see "Basic Multi-sco SCORM package" + And I log out + And I log in as "student1" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + And I switch to "scorm_object" iframe + And I should see "Play of the game" + And I switch to the main frame + And I follow "Exit activity" + And I wait until the page is ready + And I should see "Basic Multi-sco SCORM package" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + And I should not see "Review mode" + And I switch to "scorm_object" iframe + And I should see "Par" + + And I switch to the main frame + And I click on "Keeping Score" "list_item" + And I switch to "scorm_object" iframe + And I should see "Scoring" + + And I switch to the main frame + And I click on "Other Scoring Systems" "list_item" + And I switch to "scorm_object" iframe + And I should see "Other Scoring Systems" + + And I switch to the main frame + And I click on "The Rules of Golf" "list_item" + And I switch to "scorm_object" iframe + And I should see "The Rules of Golf" + + And I switch to the main frame + And I click on "Playing Golf Quiz" "list_item" + And I switch to "scorm_object" iframe + And I should see "Knowledge Check" + + And I switch to the main frame + And I click on "How to Have Fun Playing Golf" "list_item" + And I switch to "scorm_object" iframe + And I should see "How to Have Fun Golfing" + + And I switch to the main frame + And I click on "How to Make Friends Playing Golf" "list_item" + And I switch to "scorm_object" iframe + And I should see "How to Make Friends on the Golf Course" + + And I switch to the main frame + And I click on "Having Fun Quiz" "list_item" + And I switch to "scorm_object" iframe + And I should see "Knowledge Check" + And I switch to the main frame + And I follow "Exit activity" + And I wait until the page is ready + And I should see "Basic Multi-sco SCORM package" + And I am on "Course 1" course homepage + And I follow "Basic Multi-sco SCORM package" + Then I should not see "Review mode" + And I switch to "scorm_object" iframe + And I should see "Play of the game" \ No newline at end of file diff --git a/mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip b/mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip new file mode 100644 index 00000000000..a83fe62e5dc Binary files /dev/null and b/mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip differ diff --git a/mod/scorm/tests/packages/readme_moodle.txt b/mod/scorm/tests/packages/readme_moodle.txt index 49898592c06..725a9f08c9b 100644 --- a/mod/scorm/tests/packages/readme_moodle.txt +++ b/mod/scorm/tests/packages/readme_moodle.txt @@ -7,6 +7,7 @@ Sample Packages downloaded from http://scorm.com/scorm-explained/technical-scorm * singlesco_scorm12.zip - Single SCO content packaging example. SCORM 1.2. * RuntimeMinimumCalls_SCORM12.zip - Multi-SCO packaging example. SCORM 1.2. * RuntimeBasicCalls_SCORM20043rdEdition.zip - Multi-SCO packaging example. SCORM 2004 3rd edition. +* RuntimeMinimumCalls_SCORM12-mini.zip - modified 2 SCO version of RuntimeMinimumCalls_SCORM12.zip These packages were downloaded from http://scorm.com/ website, the website disclaimer states that *Content on this site is licensed under a Creative diff --git a/mod/scorm/upgrade.txt b/mod/scorm/upgrade.txt index 9fe5309d114..f6b7d58b38a 100644 --- a/mod/scorm/upgrade.txt +++ b/mod/scorm/upgrade.txt @@ -1,5 +1,9 @@ This files describes API changes in the mod_scorm code. +=== 3.5 === +* In get_scorms_by_courses() external/ws function, the force new attempt setting is no longer a boolean - now accepts 3 values: + No (0), On complete (1) and the new Always (2). See MDL-32585 for more details. + === 3.3.2 === * scorm_refresh_events() Now takes two additional parameters to refine the update to a specific instance. This function