Skip to content

Commit

Permalink
MDL-78527 core_completion: Improving core completion styling
Browse files Browse the repository at this point in the history
  • Loading branch information
Amaia Anabitarte committed Sep 12, 2023
1 parent f367759 commit 85d0756
Show file tree
Hide file tree
Showing 14 changed files with 233 additions and 71 deletions.
52 changes: 45 additions & 7 deletions completion/classes/edit_base_form.php
Expand Up @@ -99,18 +99,23 @@ abstract protected function get_module_form();
*
* @return array
*/
protected function add_completion_rules() {
protected function add_custom_completion(string $function): array {
$modnames = array_keys($this->get_module_names());

if (count($modnames) != 1 || !plugin_supports('mod', $modnames[0], FEATURE_COMPLETION_HAS_RULES, false)) {
return [];
return [false, []];
}

$component = "mod_{$modnames[0]}";
$itemnames = \core_grades\component_gradeitems::get_itemname_mapping_for_component($component);
$hascustomrules = count($itemnames) > 1;

try {
// Add completion rules from the module form to this form.
$moduleform = $this->get_module_form();
$moduleform->_form = $this->_form;
if ($customcompletionelements = $moduleform->add_completion_rules()) {
$this->hascustomrules = true;
if ($customcompletionelements = $moduleform->{$function}()) {
$hascustomrules = true;
foreach ($customcompletionelements as $customcompletionelement) {
// Instead of checking for the suffix at the end of the element name, we need to check for its presence
// because some modules, like SCORM, are adding things at the end.
Expand All @@ -123,16 +128,35 @@ protected function add_completion_rules() {
$moduleform->_form->removeElement($customcompletionelement);
}
}

}
return $customcompletionelements;
return [$hascustomrules, $customcompletionelements];
} catch (Exception $e) {
debugging('Could not add custom completion rule of module ' . $modnames[0] .
' to this form, this has to be fixed by the developer', DEBUG_DEVELOPER);
return [];
return [$hascustomrules, $customcompletionelements];
}
}

/**
* If all selected modules are of the same module type, adds custom completion rules from this module type
*
* @return array
*/
protected function add_completion_rules() {
list($hascustomrules, $customcompletionelements) = $this->add_custom_completion('add_completion_rules');
if (!$this->hascustomrules && $hascustomrules) {
$this->hascustomrules = true;
}

$component = "mod_{$this->get_module_name()}";
$itemnames = \core_grades\component_gradeitems::get_itemname_mapping_for_component($component);
if (count($itemnames) > 1) {
$customcompletionelements[] = 'completiongradeitemnumber';
}

return $customcompletionelements;
}

/**
* Checks if at least one of the custom completion rules is enabled
*
Expand All @@ -147,6 +171,20 @@ protected function completion_rule_enabled($data) {
return false;
}

/**
* If all selected modules are of the same module type, adds custom completion rules from this module type
*
* @return array
*/
public function add_completiongrade_rules(): array {
list($hascustomrules, $customcompletionelements) = $this->add_custom_completion('add_completiongrade_rules');
if (!$this->hascustomrules && $hascustomrules) {
$this->hascustomrules = true;
}

return $customcompletionelements;
}

/**
* Returns list of modules that have automatic completion rules that are not shown on this form
* (because they are not present in at least one other selected module).
Expand Down
172 changes: 126 additions & 46 deletions completion/classes/form/form_trait.php
Expand Up @@ -142,35 +142,50 @@ protected function add_completion_elements(

$completionel = 'completion' . $suffix;
$mform->addElement(
'select',
'radio',
$completionel,
get_string('completion', 'completion'),
[
COMPLETION_TRACKING_NONE => get_string('completion_none', 'completion'),
COMPLETION_TRACKING_MANUAL => get_string('completion_manual', 'completion'),
]
'',
get_string('completion_none', 'completion'),
COMPLETION_TRACKING_NONE,
['class' => 'left-indented']
);
$mform->setDefault($completionel, $trackingdefault);
$mform->addHelpButton($completionel, 'completion', 'completion');
$mform->addElement(
'radio',
$completionel,
'',
get_string('completion_manual', 'completion'),
COMPLETION_TRACKING_MANUAL,
['class' => 'left-indented']
);

$allconditionsel = 'allconditions' . $suffix;
$allconditions = $mform->createElement(
'static',
$allconditionsel,
'',
get_string('allconditions', 'completion'));

$conditionsgroupel = 'conditionsgroup' . $suffix;
$mform->addGroup([$allconditions], $conditionsgroupel, '', null, false);
$mform->hideIf($conditionsgroupel, $completionel, 'ne', COMPLETION_TRACKING_AUTOMATIC);

$mform->setType($completionel, PARAM_INT);
$mform->setDefault($completionel, COMPLETION_TRACKING_NONE);

// Automatic completion once you view it.
$autocompletionpossible = false;
if ($supportviews) {
$completionviewel = 'completionview' . $suffix;
$mform->addElement('checkbox', $completionviewel, get_string('completionview', 'completion'),
get_string('completionview_desc', 'completion'));
$mform->addElement(
'checkbox',
$completionviewel,
'',
get_string('completionview_desc', 'completion')
);
$mform->hideIf($completionviewel, $completionel, 'ne', COMPLETION_TRACKING_AUTOMATIC);
// Check by default if automatic completion tracking is set.
if ($trackingdefault == COMPLETION_TRACKING_AUTOMATIC) {
$mform->setDefault($completionviewel, 1);
}
$autocompletionpossible = true;
}

// If the activity supports grading, the grade elements must be added.
if ($supportgrades) {
$autocompletionpossible = true;
$this->add_completiongrade_elements($modname, $rating);
}

// Automatic completion according to module-specific rules.
Expand All @@ -183,14 +198,26 @@ protected function add_completion_elements(
foreach ($customcompletionelements as $element) {
$mform->hideIf($element, $completionel, 'ne', COMPLETION_TRACKING_AUTOMATIC);
}
$autocompletionpossible = $autocompletionpossible || count($customcompletionelements) > 0;
}

// If the activity supports grading, the grade elements must be added.
if ($supportgrades) {
$this->add_completiongrade_elements($modname, $rating);
}

$autocompletionpossible = $supportviews || $supportgrades || (count($customcompletionelements) > 0);

// Automatic option only appears if possible.
if ($autocompletionpossible) {
$mform->getElement($completionel)->addOption(
$automatic = $mform->createElement(
'radio',
$completionel,
'',
get_string('completion_automatic', 'completion'),
COMPLETION_TRACKING_AUTOMATIC);
COMPLETION_TRACKING_AUTOMATIC,
['class' => 'left-indented']
);
$mform->insertElementBefore($automatic, $conditionsgroupel);
}

// Completion expected at particular date? (For progress tracking).
Expand All @@ -201,7 +228,7 @@ protected function add_completion_elements(
['optional' => true]);
$a = get_string('pluginname', $modname);
$mform->addHelpButton($completionexpectedel, 'completionexpected', 'completion', '', false, $a);
$mform->hideIf($completionexpectedel, 'completion', 'eq', COMPLETION_TRACKING_NONE);
$mform->hideIf($completionexpectedel, $completionel, 'eq', COMPLETION_TRACKING_NONE);
}
}

Expand All @@ -224,27 +251,42 @@ protected function add_completiongrade_elements(
$completionelementexists = $mform->elementExists($completionel);
$component = "mod_{$modname}";
$itemnames = component_gradeitems::get_itemname_mapping_for_component($component);

$indentation = ['parentclass' => 'ml-2'];
$receiveagradeel = 'receiveagrade' . $suffix;
$completionusegradeel = 'completionusegrade' . $suffix;
$completionpassgradeel = 'completionpassgrade' . $suffix;

if (count($itemnames) === 1) {
// Only one gradeitem in this activity.
// We use the completionusegrade field here.
$completionusegradeel = 'completionusegrade' . $suffix;
$mform->addElement(
'checkbox',
$completionusegradeel,
get_string('completionusegrade', 'completion'),
'',
get_string('completionusegrade_desc', 'completion')
);
$mform->addHelpButton($completionusegradeel, 'completionusegrade', 'completion');

// Complete if the user has reached any grade.
$mform->addElement(
'radio',
$completionpassgradeel,
null,
get_string('completionanygrade_desc', 'completion'),
0,
$indentation
);

// Complete if the user has reached the pass grade.
$completionpassgradeel = 'completionpassgrade' . $suffix;
$mform->addElement(
'checkbox',
$completionpassgradeel, null,
get_string('completionpassgrade_desc', 'completion')
'radio',
$completionpassgradeel,
null,
get_string('completionpassgrade_desc', 'completion'),
1,
$indentation
);
$mform->disabledIf($completionpassgradeel, $completionusegradeel, 'notchecked');
$mform->addHelpButton($completionpassgradeel, 'completionpassgrade', 'completion');
$mform->hideIf($completionpassgradeel, $completionusegradeel, 'notchecked');

if ($completionelementexists) {
$mform->hideIf($completionpassgradeel, $completionel, 'ne', COMPLETION_TRACKING_AUTOMATIC);
Expand All @@ -254,51 +296,89 @@ protected function add_completiongrade_elements(
// The disabledIf logic differs between ratings and other grade items due to different field types.
if ($rating) {
// If using the rating system, there is no grade unless ratings are enabled.
$mform->disabledIf($completionusegradeel, 'assessed', 'eq', 0);
$mform->disabledIf($completionusegradeel, 'assessed', 'eq', 0);
$mform->hideIf($completionusegradeel, 'assessed', 'eq', 0);
$mform->hideIf($completionusegradeel, 'assessed', 'eq', 0);
} else {
// All other field types use the '$gradefieldname' field's modgrade_type.
$itemnumbers = array_keys($itemnames);
$itemnumber = array_shift($itemnumbers);
$gradefieldname = component_gradeitems::get_field_name_for_itemnumber($component, $itemnumber, 'grade');
$mform->disabledIf($completionusegradeel, "{$gradefieldname}[modgrade_type]", 'eq', 'none');
$mform->disabledIf($completionusegradeel, "{$gradefieldname}[modgrade_type]", 'eq', 'none');
$mform->hideIf($completionusegradeel, "{$gradefieldname}[modgrade_type]", 'eq', 'none');
$mform->hideIf($completionusegradeel, "{$gradefieldname}[modgrade_type]", 'eq', 'none');
}
} else if (count($itemnames) > 1) {
// There are multiple grade items in this activity.
// Show them all.
$options = [
'' => get_string('activitygradenotrequired', 'completion'),
];
$options = [];
foreach ($itemnames as $itemnumber => $itemname) {
$options[$itemnumber] = get_string("grade_{$itemname}_name", $component);
}

$group = [$mform->createElement(
'checkbox',
$completionusegradeel,
null,
get_string('completionusegrade_desc', 'completion')
)];
$completiongradeitemnumberel = 'completiongradeitemnumber' . $suffix;
$mform->addElement(
$group[] =& $mform->createElement(
'select',
$completiongradeitemnumberel,
get_string('completionusegrade', 'completion'),
'',
$options
);
$receiveagradegroupel = 'receiveagradegroup' . $suffix;
$mform->addGroup($group, $receiveagradegroupel, '', [' '], false);
if ($completionelementexists) {
$mform->hideIf($completionusegradeel, $completionel, 'ne', COMPLETION_TRACKING_AUTOMATIC);
$mform->hideIf($receiveagradegroupel, $completionel, 'ne', COMPLETION_TRACKING_AUTOMATIC);
}
$mform->hideIf($completiongradeitemnumberel, $completionusegradeel, 'notchecked');

// Complete if the user has reached any grade.
$mform->addElement(
'radio',
$completionpassgradeel,
null,
get_string('completionanygrade_desc', 'completion'),
0,
$indentation
);
// Complete if the user has reached the pass grade.
$completionpassgradeel = 'completionpassgrade' . $suffix;
$mform->addElement(
'checkbox',
$completionpassgradeel, null,
get_string('completionpassgrade_desc', 'completion')
'radio',
$completionpassgradeel,
null,
get_string('completionpassgrade_desc', 'completion'),
1,
$indentation
);
$mform->disabledIf($completionpassgradeel, $completiongradeitemnumberel, 'eq', '');
$mform->addHelpButton($completionpassgradeel, 'completionpassgrade', 'completion');
$mform->hideIf($completionpassgradeel, $completionusegradeel, 'notchecked');

if ($completionelementexists) {
$mform->hideIf($completiongradeitemnumberel, $completionel, 'ne', COMPLETION_TRACKING_AUTOMATIC);
$mform->hideIf($completionpassgradeel, $completionel, 'ne', COMPLETION_TRACKING_AUTOMATIC);
}
}

$customgradingelements = $this->add_completiongrade_rules();
if (property_exists($this, '_customcompletionelements')) {
$this->_customcompletionelements = array_merge($this->_customcompletionelements, $customgradingelements);
}
if ($completionelementexists) {
foreach ($customgradingelements as $customgradingelement) {
$mform->hideIf($customgradingelement, $completionel, 'ne', COMPLETION_TRACKING_AUTOMATIC);
}
}
}

/**
* Add completion grading elements to the form and return the list of element ids.
*
* @return array Array of string IDs of added items, empty array if none
*/
abstract public function add_completiongrade_rules(): array;

/**
* Perform some extra validation for completion settings.
*
Expand Down
3 changes: 3 additions & 0 deletions completion/classes/manager.php
Expand Up @@ -519,6 +519,9 @@ public function apply_default_completion($data, $updatecustomrules, string $suff
if (!array_key_exists('completionpassgrade', $data)) {
$data['completionpassgrade'] = 0;
}
if ($data['completionusegrade'] == 0) {
$data['completionpassgrade'] = 0;
}

if ($updatecustomrules) {
$customdata = array_diff_key($data, $defaults);
Expand Down
5 changes: 4 additions & 1 deletion course/modlib.php
Expand Up @@ -464,7 +464,10 @@ function set_moduleinfo_defaults($moduleinfo) {
}

// Convert the 'use grade' checkbox into a grade-item number: 0 if checked, null if not.
if (isset($moduleinfo->completionusegrade) && $moduleinfo->completionusegrade) {
if (isset($moduleinfo->completionusegrade) &&
$moduleinfo->completionusegrade &&
!isset($moduleinfo->completiongradeitemnumber
)) {
$moduleinfo->completiongradeitemnumber = 0;
} else if (!isset($moduleinfo->completiongradeitemnumber)) {
// If there is no gradeitemnumber set, make sure to disable completionpassgrade.
Expand Down

0 comments on commit 85d0756

Please sign in to comment.