MDL-80386 core_question: Add "show all" button to filters.

This adds the "Show All" button to the question bank filters
to allow users to select all questions easily.

It also adds new behat tests to test the functionality.
This commit is contained in:
Conn Warwicker
2025-03-11 18:13:23 +00:00
committed by Tim Hunt
parent 4df87b3130
commit 532ef50ed6
8 changed files with 134 additions and 12 deletions
+6 -2
View File
@@ -36,7 +36,8 @@
}
]
}
]
],
"showallbutton": false
}
}}
@@ -52,7 +53,10 @@
<button type="button" class="btn btn-link text-reset" data-filteraction="add">
{{#pix}}t/add{{/pix}}<span class="pl-3">{{#str}}addcondition{{/str}}</span>
</button>
<button data-filteraction="reset" type="button" class="btn btn-secondary ml-auto mr-2">{{#str}}clearfilters{{/str}}</button>
{{#showallbutton}}
<button data-filteraction="showall" data-perpage="{{ perpage }}" data-status="0" type="button" class="btn btn-light ml-auto mr-2">{{#str}}showall{{/str}}</button>
{{/showallbutton}}
<button data-filteraction="reset" type="button" class="btn btn-secondary {{^showallbutton}}ml-auto{{/showallbutton}} mr-2">{{#str}}clearfilters{{/str}}</button>
<button data-filteraction="apply" type="button" class="btn btn-primary">{{#str}}applyfilters{{/str}}</button>
</div>
@@ -83,10 +83,10 @@ class custom_view extends \core_question\local\bank\view {
}
$this->init_columns($this->wanted_columns(), $this->heading_column());
$this->pagesize = self::DEFAULT_PAGE_SIZE;
parent::__construct($contexts, $pageurl, $course, $cm, $params, $extraparams);
[$this->quiz, ] = get_module_from_cmid($cm->id);
$this->set_quiz_has_attempts(quiz_has_attempts($this->quiz->id));
$this->pagesize = self::DEFAULT_PAGE_SIZE;
}
/**
+2 -2
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+37 -3
View File
@@ -26,6 +26,8 @@ import Notification from 'core/notification';
import Selectors from 'core/datafilter/selectors';
import Templates from 'core/templates';
import Fragment from 'core/fragment';
import {getString} from 'core/str';
import {addIconToContainerRemoveOnCompletion} from 'core/loadingicon';
/**
* Initialise the question bank filter on the element with the given id.
@@ -42,7 +44,7 @@ import Fragment from 'core/fragment';
* @param {Object} pagevars JSON-encoded parameters from passed from the view, including filters and jointype.
* @param {Object} extraparams JSON-encoded additional parameters specific to this view class, used for re-rendering the view.
*/
export const init = (
export const init = async(
filterRegionId,
defaultcourseid,
defaultcategoryid,
@@ -66,10 +68,19 @@ export const init = (
MENU_ACTIONS: '.menu-action',
EDIT_SWITCH: '.editmode-switch-form input[name=setmode]',
EDIT_SWITCH_URL: '.editmode-switch-form input[name=pageurl]',
SHOW_ALL_LINK: '[data-filteraction="showall"]',
};
const filterSet = document.querySelector(`#${filterRegionId}`);
const [
showAllText,
showPerPageText,
] = await Promise.all([
getString('showall', 'core', ''),
getString('showperpage', 'core', extraparams.defaultqperpage),
]);
const viewData = {
extraparams: JSON.stringify(extraparams),
cmid,
@@ -115,10 +126,15 @@ export const init = (
// Load questions for first page.
viewData.filter = JSON.stringify(filterdata);
viewData.sortdata = JSON.stringify(sortData);
const questionscontainer = document.querySelector(SELECTORS.QUESTION_CONTAINER_ID);
// Clear the contents of the element, then append the loading icon.
questionscontainer.innerHTML = '';
addIconToContainerRemoveOnCompletion(questionscontainer, pendingPromise);
Fragment.loadFragment(component, callback, contextId, viewData)
// Render questions for first page and pagination.
.then((questionhtml, jsfooter) => {
const questionscontainer = document.querySelector(SELECTORS.QUESTION_CONTAINER_ID);
if (questionhtml === undefined) {
questionhtml = '';
}
@@ -180,10 +196,11 @@ export const init = (
};
// Add listeners for the sorting, paging and clear actions.
document.addEventListener('click', e => {
document.querySelector('.questionbankwindow').addEventListener('click', e => {
const sortableLink = e.target.closest(SELECTORS.SORT_LINK);
const paginationLink = e.target.closest(SELECTORS.PAGINATION_LINK);
const clearLink = e.target.closest(Selectors.filterset.actions.resetFilters);
const showallLink = e.target.closest(SELECTORS.SHOW_ALL_LINK);
if (sortableLink) {
e.preventDefault();
const oldSort = sortData;
@@ -209,6 +226,23 @@ export const init = (
if (clearLink) {
cleanUrlParams();
}
if (showallLink) {
e.preventDefault();
// Toggle between showing all and going back to the original qperpage.
if (Number(showallLink.dataset.status) === 0) {
viewData.qperpage = extraparams.maxqperpage;
showallLink.dataset.status = 1;
showallLink.innerText = showPerPageText;
} else {
viewData.qperpage = extraparams.defaultqperpage;
showallLink.dataset.status = 0;
showallLink.innerText = showAllText;
}
viewData.qpage = 0;
coreFilter.updateTableFromFilter();
}
});
// Run apply filter at page load.
+11 -3
View File
@@ -235,6 +235,10 @@ class view {
$this->cm = $cm;
$this->extraparams = $extraparams;
// Add the default qperpage to extra params array so we can switch back and forth between it and "all".
$this->extraparams['defaultqperpage'] = $this->pagesize;
$this->extraparams['maxqperpage'] = MAXIMUM_QUESTIONS_PER_PAGE;
// Default filter condition.
if (!isset($params['filter']) && isset($params['cat'])) {
$params['filter'] = [];
@@ -811,15 +815,18 @@ class view {
*/
protected function load_page_questions(): \moodle_recordset {
global $DB;
// Load the questions based on the page we are on.
$questions = $DB->get_recordset_sql($this->loadsql, $this->sqlparams,
(int)$this->pagevars['qpage'] * (int)$this->pagevars['qperpage'], $this->pagevars['qperpage']);
(int)$this->pagevars['qpage'] * (int)$this->pagevars['qperpage'], (int)$this->pagevars['qperpage']);
if (!$questions->valid()) {
$questions->close();
// No questions on this page. Reset to the nearest page that contains questions.
$this->pagevars['qpage'] = max(0,
ceil($this->totalcount / $this->pagevars['qperpage']) - 1);
ceil($this->totalcount / (int)$this->pagevars['qperpage']) - 1);
$questions = $DB->get_recordset_sql($this->loadsql, $this->sqlparams,
$this->pagevars['qpage'] * (int) $this->pagevars['qperpage'], $this->pagevars['qperpage']);
(int)$this->pagevars['qpage'] * (int)$this->pagevars['qperpage'], (int)$this->pagevars['qperpage']);
}
return $questions;
}
@@ -1155,6 +1162,7 @@ class view {
// We probably do not want to raise it to unlimited, so randomly picking 5 minutes.
// Note: We do not call this in the loop because quiz ob_ captures this function (see raise() PHP doc).
\core_php_time_limit::raise(300);
raise_memory_limit(MEMORY_EXTRA);
[$categoryid, $contextid] = category_condition::validate_category_param($this->pagevars['cat']);
$catcontext = \context::instance_by_id($contextid);
@@ -137,6 +137,7 @@ class question_bank_filter_ui extends datafilter {
'cmid' => $this->cmid ?? 0,
'pagevars' => json_encode($this->pagevars),
'extraparams' => json_encode($this->extraparams),
'showallbutton' => true,
];
}
}
@@ -0,0 +1,75 @@
@core @core_question @qbank_filter @javascript
Feature: A teacher can show all of the questions on the question bank and override pagination
In order to see all the questions in the question bank
As a teacher
I must be able to toggle between show all and show paginated
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "question categories" exist:
| contextlevel | reference | questioncategory | name |
| Course | C1 | Top | Test Category |
Given 201 "questions" exist with the following data:
| questioncategory | Test Category |
| qtype | truefalse |
| name | Question #[count] |
| questiontext | True or false? |
Scenario: Use "Show All" button on the question bank when there are no questions
Given I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
When I apply question bank filter "Category" with value "Default for C1"
Then I should not see "Question #"
And I click on "Show all" "button"
Then I should not see "Question #"
And I click on "Show 100 per page" "button"
Then I should not see "Question #"
Scenario: Question bank shows paginated questions by default
Given I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
When I apply question bank filter "Category" with value "Top for Course 1"
Then I should see "100" occurrences of "Question #" in the "div#questionscontainer" "css_element"
And I should see "1" in the ".pagination" "css_element"
And I should see "2" in the ".pagination" "css_element"
And I should see "3" in the ".pagination" "css_element"
Scenario: Toggle "Show all" shows all questions
Given I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
When I apply question bank filter "Category" with value "Top for Course 1"
And I click on "Show all" "button"
Then I should see "201" occurrences of "Question #" in the "div#questionscontainer" "css_element"
And ".pagination" "css_element" should not exist
And I should see "Show 100 per page"
Scenario: Toggle "Show all" back to paginated shows paginated questions
Given I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
When I apply question bank filter "Category" with value "Top for Course 1"
And I click on "Show all" "button"
And I click on "Show 100 per page" "button"
Then I should see "100" occurrences of "Question #" in the "div#questionscontainer" "css_element"
And I should see "1" in the ".pagination" "css_element"
And I should see "2" in the ".pagination" "css_element"
And I should see "3" in the ".pagination" "css_element"
And I should see "Show all"
Scenario: Show all questions on the question bank when adding questions to a quiz
Given I am on the "Test quiz" "mod_quiz > Edit" page logged in as "teacher1"
When I open the "last" add to quiz menu
And I follow "from question bank"
And I apply question bank filter "Category" with value "Top for Course 1"
Then I should see "20" occurrences of "Question #" in the "div#questionscontainer" "css_element"
When I click on "Show all" "button"
Then I should see "201" occurrences of "Question #" in the "div#questionscontainer" "css_element"
When I click on "Select all" "checkbox"
And I click on "Add selected questions to the quiz" "button"
Then I should see "Questions: 201"