diff --git a/lib/form/form.js b/lib/form/form.js
index 38e518bef44..4fc331fdf22 100644
--- a/lib/form/form.js
+++ b/lib/form/form.js
@@ -69,8 +69,10 @@ if (typeof M.form.dependencyManager === 'undefined') {
names[i] = new Y.NodeList();
for (var condition in conditions) {
for (var value in conditions[condition]) {
- for (var ei in conditions[condition][value]) {
- names[conditions[condition][value][ei]] = new Y.NodeList();
+ for (var hide in conditions[condition][value]) {
+ for (var ei in conditions[condition][value][hide]) {
+ names[conditions[condition][value][hide][ei]] = new Y.NodeList();
+ }
}
}
}
@@ -83,6 +85,13 @@ if (typeof M.form.dependencyManager === 'undefined') {
names[name].push(node);
}
});
+ // Locate any groups with the given name.
+ this.get('form').all('.fitem').each(function(node) {
+ var name = node.getData('groupname');
+ if (name && ({}).hasOwnProperty.call(names, name)) {
+ names[name].push(node);
+ }
+ });
this._nameCollections = names;
},
@@ -118,7 +127,7 @@ if (typeof M.form.dependencyManager === 'undefined') {
var dependencies = this.get('dependencies'),
tohide = {},
tolock = {},
- condition, value, lock, hide,
+ condition, value, isHide, lock, hide,
checkfunction, result, elements;
if (!({}).hasOwnProperty.call(dependencies, dependon)) {
return true;
@@ -126,26 +135,28 @@ if (typeof M.form.dependencyManager === 'undefined') {
elements = this.elementsByName(dependon);
for (condition in dependencies[dependon]) {
for (value in dependencies[dependon][condition]) {
- checkfunction = '_dependency' + condition[0].toUpperCase() + condition.slice(1);
- if (Y.Lang.isFunction(this[checkfunction])) {
- result = this[checkfunction].apply(this, [elements, value, e]);
- } else {
- result = this._dependencyDefault(elements, value, e);
- }
- lock = result.lock || false;
- hide = result.hide || false;
- for (var ei in dependencies[dependon][condition][value]) {
- var eltolock = dependencies[dependon][condition][value][ei];
- if (({}).hasOwnProperty.call(tohide, eltolock)) {
- tohide[eltolock] = tohide[eltolock] || hide;
+ for (isHide in dependencies[dependon][condition][value]) {
+ checkfunction = '_dependency' + condition[0].toUpperCase() + condition.slice(1);
+ if (Y.Lang.isFunction(this[checkfunction])) {
+ result = this[checkfunction].apply(this, [elements, value, (isHide === "1"), e]);
} else {
- tohide[eltolock] = hide;
+ result = this._dependencyDefault(elements, value, (isHide === "1"), e);
}
+ lock = result.lock || false;
+ hide = result.hide || false;
+ for (var ei in dependencies[dependon][condition][value][isHide]) {
+ var eltolock = dependencies[dependon][condition][value][isHide][ei];
+ if (({}).hasOwnProperty.call(tohide, eltolock)) {
+ tohide[eltolock] = tohide[eltolock] || hide;
+ } else {
+ tohide[eltolock] = hide;
+ }
- if (({}).hasOwnProperty.call(tolock, eltolock)) {
- tolock[eltolock] = tolock[eltolock] || lock;
- } else {
- tolock[eltolock] = lock;
+ if (({}).hasOwnProperty.call(tolock, eltolock)) {
+ tolock[eltolock] = tolock[eltolock] || lock;
+ } else {
+ tolock[eltolock] = lock;
+ }
}
}
}
@@ -260,8 +271,13 @@ if (typeof M.form.dependencyManager === 'undefined') {
_hideElement: function(name, hidden) {
var els = this.elementsByName(name);
els.each(function(node) {
- var e = node.ancestor('.fitem');
+ var e = node.ancestor('.fitem', true);
if (e) {
+ if (hidden) {
+ e.setAttribute('hidden', 'hidden');
+ } else {
+ e.removeAttribute('hidden');
+ }
e.setStyles({
display: (hidden) ? 'none' : ''
});
@@ -291,7 +307,7 @@ if (typeof M.form.dependencyManager === 'undefined') {
return false;
},
- _dependencyNotchecked: function(elements, value) {
+ _dependencyNotchecked: function(elements, value, isHide) {
var lock = false;
elements.each(function() {
if (this.getAttribute('type').toLowerCase() == 'hidden' &&
@@ -306,10 +322,10 @@ if (typeof M.form.dependencyManager === 'undefined') {
});
return {
lock: lock,
- hide: false
+ hide: isHide ? lock : false
};
},
- _dependencyChecked: function(elements, value) {
+ _dependencyChecked: function(elements, value, isHide) {
var lock = false;
elements.each(function() {
if (this.getAttribute('type').toLowerCase() == 'hidden' &&
@@ -324,20 +340,20 @@ if (typeof M.form.dependencyManager === 'undefined') {
});
return {
lock: lock,
- hide: false
+ hide: isHide ? lock : false
};
},
- _dependencyNoitemselected: function(elements, value) {
+ _dependencyNoitemselected: function(elements, value, isHide) {
var lock = false;
elements.each(function() {
lock = lock || this.get('selectedIndex') == -1;
});
return {
lock: lock,
- hide: false
+ hide: isHide ? lock : false
};
},
- _dependencyEq: function(elements, value) {
+ _dependencyEq: function(elements, value, isHide) {
var lock = false;
var hiddenVal = false;
var options, v, selected, values;
@@ -391,7 +407,7 @@ if (typeof M.form.dependencyManager === 'undefined') {
});
return {
lock: lock,
- hide: false
+ hide: isHide ? lock : false
};
},
/**
@@ -402,7 +418,7 @@ if (typeof M.form.dependencyManager === 'undefined') {
* @returns {{lock: boolean, hide: boolean}}
* @private
*/
- _dependencyIn: function(elements, values) {
+ _dependencyIn: function(elements, values, isHide) {
// A pipe (|) is used as a value separator
// when multiple values have to be passed on at the same time.
values = values.split('|');
@@ -458,7 +474,7 @@ if (typeof M.form.dependencyManager === 'undefined') {
});
return {
lock: lock,
- hide: false
+ hide: isHide ? lock : false
};
},
_dependencyHide: function(elements, value) {
@@ -467,7 +483,7 @@ if (typeof M.form.dependencyManager === 'undefined') {
hide: true
};
},
- _dependencyDefault: function(elements, value, ev) {
+ _dependencyDefault: function(elements, value, isHide) {
var lock = false,
hiddenVal = false,
values
@@ -521,7 +537,7 @@ if (typeof M.form.dependencyManager === 'undefined') {
});
return {
lock: lock,
- hide: false
+ hide: isHide ? lock : false
};
}
}, {
diff --git a/lib/form/group.php b/lib/form/group.php
index da9359ddbea..f4f241fd045 100644
--- a/lib/form/group.php
+++ b/lib/form/group.php
@@ -213,6 +213,7 @@ class MoodleQuickForm_group extends HTML_QuickForm_group implements templatable
$i++;
}
+ $context['groupname'] = $name;
$context['elements'] = $elements;
return $context;
}
diff --git a/lib/form/templates/element-template.mustache b/lib/form/templates/element-template.mustache
index 9463064f2e9..cc1195ad53c 100644
--- a/lib/form/templates/element-template.mustache
+++ b/lib/form/templates/element-template.mustache
@@ -46,7 +46,7 @@
}
}}
-
+
{{{ helpbutton }}}
diff --git a/lib/form/tests/behat/hideif.feature b/lib/form/tests/behat/hideif.feature
new file mode 100644
index 00000000000..04027bacd1b
--- /dev/null
+++ b/lib/form/tests/behat/hideif.feature
@@ -0,0 +1,29 @@
+@core @javascript @core_form
+Feature: hideIf functionality in forms
+ For forms including hideIf functions
+ As a user
+ If I trigger the hideIf condition then the form elements will be hidden
+
+ Background:
+ Given the following "courses" exist:
+ | fullname | shortname |
+ | Course 1 | C1 |
+ And I log in as "admin"
+ And I am on "Course 1" course homepage
+ And I turn editing mode on
+
+ Scenario: When 'eq' hideIf conditions are not met, the relevant elements are shown
+ When I add a "Assignment" to section "1"
+ And I expand all fieldsets
+ And I set the field "Students submit in groups" to "Yes"
+ Then I should see "Require group to make submission"
+ And I should see "Require all group members submit"
+ And I should see "Grouping for student groups"
+
+ Scenario: When 'eq' hideIf conditions are met, the relevant elements are hidden
+ When I add a "Assignment" to section "1"
+ And I expand all fieldsets
+ And I set the field "Students submit in groups" to "No"
+ Then I should not see "Require group to make submission"
+ And I should not see "Require all group members to submit"
+ And I should not see "Grouping for student groups"
diff --git a/lib/formslib.php b/lib/formslib.php
index 965b0a4f51a..66527b655b3 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -1412,6 +1412,11 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
/** @var array dependent state for the element/'s */
var $_dependencies = array();
+ /**
+ * @var array elements that will become hidden based on another element
+ */
+ protected $_hideifs = array();
+
/** @var array Array of buttons that if pressed do not result in the processing of the form. */
var $_noSubmitButtons=array();
@@ -1460,6 +1465,16 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
*/
protected $clientvalidation = false;
+ /**
+ * Is this a 'disableIf' dependency ?
+ */
+ const DEP_DISABLE = 0;
+
+ /**
+ * Is this a 'hideIf' dependency?
+ */
+ const DEP_HIDE = 1;
+
/**
* Class constructor - same parameters as HTML_QuickForm_DHTMLRulesTableless
*
@@ -2426,8 +2441,7 @@ require(["core/event", "jquery"], function(Event, $) {
foreach ($conditions as $condition=>$values) {
$result[$dependentOn][$condition] = array();
foreach ($values as $value=>$dependents) {
- $result[$dependentOn][$condition][$value] = array();
- $i = 0;
+ $result[$dependentOn][$condition][$value][self::DEP_DISABLE] = array();
foreach ($dependents as $dependent) {
$elements = $this->_getElNamesRecursive($dependent);
if (empty($elements)) {
@@ -2438,7 +2452,29 @@ require(["core/event", "jquery"], function(Event, $) {
if ($element == $dependentOn) {
continue;
}
- $result[$dependentOn][$condition][$value][] = $element;
+ $result[$dependentOn][$condition][$value][self::DEP_DISABLE][] = $element;
+ }
+ }
+ }
+ }
+ }
+ foreach ($this->_hideifs as $dependenton => $conditions) {
+ $result[$dependenton] = array();
+ foreach ($conditions as $condition => $values) {
+ $result[$dependenton][$condition] = array();
+ foreach ($values as $value => $dependents) {
+ $result[$dependenton][$condition][$value][self::DEP_HIDE] = array();
+ foreach ($dependents as $dependent) {
+ $elements = $this->_getElNamesRecursive($dependent);
+ if (!in_array($dependent, $elements)) {
+ // Always want to hide the main element, even if it contains sub-elements as well.
+ $elements[] = $dependent;
+ }
+ foreach ($elements as $element) {
+ if ($element == $dependenton) {
+ continue;
+ }
+ $result[$dependenton][$condition][$value][self::DEP_HIDE][] = $element;
}
}
}
@@ -2533,6 +2569,40 @@ require(["core/event", "jquery"], function(Event, $) {
$this->_dependencies[$dependentOn][$condition][$value][] = $elementName;
}
+ /**
+ * Adds a dependency for $elementName which will be hidden if $condition is met.
+ * If $condition = 'notchecked' (default) then the condition is that the $dependentOn element
+ * is not checked. If $condition = 'checked' then the condition is that the $dependentOn element
+ * is checked. If $condition is something else (like "eq" for equals) then it is checked to see if the value
+ * of the $dependentOn element is $condition (such as equal) to $value.
+ *
+ * When working with multiple selects, the dependentOn has to be the real name of the select, meaning that
+ * it will most likely end up with '[]'. Also, the value should be an array of required values, or a string
+ * containing the values separated by pipes: array('red', 'blue') or 'red|blue'.
+ *
+ * @param string $elementname the name of the element which will be hidden
+ * @param string $dependenton the name of the element whose state will be checked for condition
+ * @param string $condition the condition to check
+ * @param mixed $value used in conjunction with condition.
+ */
+ public function hideIf($elementname, $dependenton, $condition = 'notchecked', $value = '1') {
+ // Multiple selects allow for a multiple selection, we transform the array to string here as
+ // an array cannot be used as a key in an associative array.
+ if (is_array($value)) {
+ $value = implode('|', $value);
+ }
+ if (!array_key_exists($dependenton, $this->_hideifs)) {
+ $this->_hideifs[$dependenton] = array();
+ }
+ if (!array_key_exists($condition, $this->_hideifs[$dependenton])) {
+ $this->_hideifs[$dependenton][$condition] = array();
+ }
+ if (!array_key_exists($value, $this->_hideifs[$dependenton][$condition])) {
+ $this->_hideifs[$dependenton][$condition][$value] = array();
+ }
+ $this->_hideifs[$dependenton][$condition][$value][] = $elementname;
+ }
+
/**
* Registers button as no submit button
*
diff --git a/mod/assign/mod_form.php b/mod/assign/mod_form.php
index 7f88c0738de..ffb9a159402 100644
--- a/mod/assign/mod_form.php
+++ b/mod/assign/mod_form.php
@@ -148,12 +148,12 @@ class mod_assign_mod_form extends moodleform_mod {
'preventsubmissionnotingroup',
'assign');
$mform->setType('preventsubmissionnotingroup', PARAM_BOOL);
- $mform->disabledIf('preventsubmissionnotingroup', 'teamsubmission', 'eq', 0);
+ $mform->hideIf('preventsubmissionnotingroup', 'teamsubmission', 'eq', 0);
$name = get_string('requireallteammemberssubmit', 'assign');
$mform->addElement('selectyesno', 'requireallteammemberssubmit', $name);
$mform->addHelpButton('requireallteammemberssubmit', 'requireallteammemberssubmit', 'assign');
- $mform->disabledIf('requireallteammemberssubmit', 'teamsubmission', 'eq', 0);
+ $mform->hideIf('requireallteammemberssubmit', 'teamsubmission', 'eq', 0);
$mform->disabledIf('requireallteammemberssubmit', 'submissiondrafts', 'eq', 0);
$groupings = groups_get_all_groupings($assignment->get_course()->id);
@@ -166,7 +166,7 @@ class mod_assign_mod_form extends moodleform_mod {
$name = get_string('teamsubmissiongroupingid', 'assign');
$mform->addElement('select', 'teamsubmissiongroupingid', $name, $options);
$mform->addHelpButton('teamsubmissiongroupingid', 'teamsubmissiongroupingid', 'assign');
- $mform->disabledIf('teamsubmissiongroupingid', 'teamsubmission', 'eq', 0);
+ $mform->hideIf('teamsubmissiongroupingid', 'teamsubmission', 'eq', 0);
if ($assignment->has_submissions_or_grades()) {
$mform->freeze('teamsubmissiongroupingid');
}
diff --git a/theme/boost/templates/core_form/element-template-inline.mustache b/theme/boost/templates/core_form/element-template-inline.mustache
index 88593fccdcb..95f1fa79c87 100644
--- a/theme/boost/templates/core_form/element-template-inline.mustache
+++ b/theme/boost/templates/core_form/element-template-inline.mustache
@@ -1,4 +1,4 @@
-