diff --git a/availability/tests/behat/edit_availability.feature b/availability/tests/behat/edit_availability.feature index 3f2e3a2112c..82f36628e42 100644 --- a/availability/tests/behat/edit_availability.feature +++ b/availability/tests/behat/edit_availability.feature @@ -172,3 +172,62 @@ Feature: edit_availability And I should not see "None" in the "Restrict access" "fieldset" And "Restriction type" "select" should be visible And I should see "Date" in the "Restrict access" "fieldset" + + @javascript + Scenario: 'Add group/grouping access restriction' button unavailable + # Button does not exist when conditional access restrictions are turned off. + Given I log in as "admin" + And I follow "Course 1" + And I turn editing mode on + And I add a "Forum" to section "1" + When I expand all fieldsets + Then "Add group/grouping access restriction" "button" should not exist + + @javascript + Scenario: Use the 'Add group/grouping access restriction' button + # Button should initially be disabled. + Given I log in as "admin" + And I set the following administration settings values: + | Enable conditional access | 1 | + And the following "groupings" exist: + | name | course | idnumber | + | GX1 | C1 | GXI1 | + And I am on homepage + And I follow "Course 1" + And I turn editing mode on + And I add a "Forum" to section "1" + And I set the following fields to these values: + | Forum name | MyForum | + | Description | x | + When I expand all fieldsets + Then the "Add group/grouping access restriction" "button" should be disabled + + # Turn on separate groups. + And I set the field "Group mode" to "Separate groups" + And the "Add group/grouping access restriction" "button" should be enabled + + # Press the button and check it adds a restriction and disables itself. + And I should see "None" in the "Restrict access" "fieldset" + And I press "Add group/grouping access restriction" + And I should see "Group" in the "Restrict access" "fieldset" + And the "Add group/grouping access restriction" "button" should be disabled + + # Delete the restriction and check it is enabled again. + And I click on "Delete" "link" in the "Restrict access" "fieldset" + And the "Add group/grouping access restriction" "button" should be enabled + + # Try a grouping instead. + And I set the field "Grouping" to "GX1" + And I press "Add group/grouping access restriction" + And I should see "Grouping" in the "Restrict access" "fieldset" + + # Check the button still works after saving and editing. + And I press "Save and display" + And I navigate to "Edit settings" node in "Forum administration" + And I expand all fieldsets + And the "Add group/grouping access restriction" "button" should be disabled + And I should see "Grouping" in the "Restrict access" "fieldset" + + # And check it's still active if I delete the condition. + And I click on "Delete" "link" in the "Restrict access" "fieldset" + And the "Add group/grouping access restriction" "button" should be enabled diff --git a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js index 1af7df270f9..61b4781bad6 100644 --- a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js +++ b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js @@ -66,6 +66,14 @@ M.core_availability.form = { */ idCounter : 0, + /** + * The 'Restrict by group' button if present. + * + * @property restrictByGroup + * @type Y.Node + */ + restrictByGroup : null, + /** * Called to initialise the system when the page loads. This method will * also call the init method for each plugin. @@ -121,6 +129,22 @@ M.core_availability.form = { this.field.ancestor('form').on('submit', function() { this.mainDiv.all('input,textarea,select').set('disabled', true); }, this); + + // If the form has group mode and/or grouping options, there is a + // 'add restriction' button there. + this.restrictByGroup = Y.one('#restrictbygroup'); + if (this.restrictByGroup) { + this.restrictByGroup.on('click', this.addRestrictByGroup, this); + var groupmode = Y.one('#id_groupmode'); + var groupingid = Y.one('#id_groupingid'); + if (groupmode) { + groupmode.on('change', this.updateRestrictByGroup, this); + } + if (groupingid) { + groupingid.on('change', this.updateRestrictByGroup, this); + } + this.updateRestrictByGroup(); + } }, /** @@ -143,6 +167,75 @@ M.core_availability.form = { // Set into hidden form field, JS-encoded. this.field.set('value', Y.JSON.stringify(jsValue)); + + // Also update the restrict by group button if present. + this.updateRestrictByGroup(); + }, + + /** + * Updates the status of the 'restrict by group' button (enables or disables + * it) based on current availability restrictions and group/grouping settings. + */ + updateRestrictByGroup : function() { + if (!this.restrictByGroup) { + return; + } + + // If the root list is anything other than the default 'and' type, disable. + if (this.rootList.getValue().op !== '&') { + this.restrictByGroup.set('disabled', true); + return; + } + + // If there's already a group restriction, disable it. + var alreadyGot = this.rootList.hasItemOfType('group') || + this.rootList.hasItemOfType('grouping'); + if (alreadyGot) { + this.restrictByGroup.set('disabled', true); + return; + } + + // If the groupmode and grouping id aren't set, disable it. + var groupmode = Y.one('#id_groupmode'); + var groupingid = Y.one('#id_groupingid'); + if ((!groupmode || Number(groupmode.get('value')) === 0) && + (!groupingid || Number(groupingid.get('value')) === 0)) { + this.restrictByGroup.set('disabled', true); + return; + } + + this.restrictByGroup.set('disabled', false); + }, + + /** + * Called when the user clicks on the 'restrict by group' button. This is + * a special case that adds a group or grouping restriction. + * + * By default this restriction is not shown which makes it similar to the + * + * @param e Button click event + */ + addRestrictByGroup : function(e) { + // If you don't prevent default, it submits the form for some reason. + e.preventDefault(); + + // Add the condition. + var groupingid = Y.one('#id_groupingid'); + var newChild; + if (groupingid && Number(groupingid.get('value')) !== 0) { + // Add a grouping restriction if one is specified. + newChild = new M.core_availability.Item( + {type : 'grouping', id : Number(groupingid.get('value'))}, true); + } else { + // Otherwise just add a group restriction. + newChild = new M.core_availability.Item({type : 'group'}, true); + } + + // Refresh HTML. + this.rootList.addChild(newChild); + this.update(); + this.rootList.renumber(); + this.rootList.updateHtml(); } }; @@ -709,6 +802,31 @@ M.core_availability.List.prototype.fillErrors = function(errors) { } }; +/** + * Checks whether the list contains any items of the given type name. + * + * @method hasItemOfType + * @param {String} pluginType Required plugin type (name) + * @return {Boolean} True if there is one + */ +M.core_availability.List.prototype.hasItemOfType = function(pluginType) { + // Check each item. + for (var i = 0; i < this.children.length; i++) { + var child = this.children[i]; + if (child instanceof M.core_availability.List) { + // Recursive call. + if (child.hasItemOfType(pluginType)) { + return true; + } + } else { + if (child.pluginType === pluginType) { + return true; + } + } + } + return false; +}; + /** * Eye icon for this list (null if none). * diff --git a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js index 4733ed58a6a..92740e759da 100644 --- a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js +++ b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js @@ -1,3 +1,3 @@ -YUI.add("moodle-core_availability-form",function(e,t){M.core_availability=M.core_availability||{},M.core_availability.form={plugins:{},field:null,mainDiv:null,rootList:null,idCounter:0,init:function(t){for(var n in t){var r=t[n],i=M[r[0]].form;i.init.apply(i,r)}this.field=e.one("#id_availabilityconditionsjson"),this.field.setAttribute("aria-hidden","true"),this.mainDiv=e.Node.create('
'),this.field.insert(this.mainDiv,"after");var s=this.field.get("value"),o=null;if(s!=="")try{o=e.JSON.parse(s)}catch(u){this.field.set("value","")}this.rootList=new M.core_availability.List(o,!0),this.mainDiv.appendChild(this.rootList.node),this.update(),this.rootList.renumber(),this.mainDiv.setAttribute("aria-live","polite"),this.field.ancestor("form").on("submit",function(){this.mainDiv.all("input,textarea,select").set("disabled",!0)},this)},update:function(){var t=this.rootList.getValue(),n=[];this.rootList.fillErrors(n),n.length!==0&&(t.errors=n),this.field.set("value",e.JSON.stringify(t))}},M.core_availability.plugin={allowAdd:!1,init:function(e,t,n){var r=e.replace(/^availability_/,"");this.allowAdd=t,M.core_availability.form.plugins[r]=this,this.initInner.apply(this,n)},initInner:function(){},getNode:function(){throw"getNode not implemented"},fillValue:function(){throw"fillValue not implemented"},fillErrors:function(){},focusAfterAdd:function(e){var t=e.one("input:not([disabled]),select:not([disabled])");t.focus()}},M.core_availability.List=function(t,n,r){this.children=[],n!==undefined&&(this.root=n),this.node=e.Node.create('