MDL-68463 user: Update select/show [count] links dynamically
authorAndrew Nicols <andrew@nicols.co.uk>
Fri, 24 Apr 2020 04:33:36 +0000 (12:33 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Mon, 18 May 2020 12:03:38 +0000 (20:03 +0800)
lang/en/moodle.php
lang/en/user.php
lib/tablelib.php
user/amd/build/participants.min.js
user/amd/build/participants.min.js.map
user/amd/src/participants.js
user/index.php
user/tests/behat/filter_participants_showall.feature

index 4885cc4..484eb52 100644 (file)
@@ -1523,7 +1523,6 @@ $string['parentcategory'] = 'Parent category';
 $string['parentcoursenotfound'] = 'Parent course not found!';
 $string['parentfolder'] = 'Parent folder';
 $string['participants'] = 'Participants';
-$string['participantscount'] = 'Number of participants: {$a}';
 $string['participantslist'] = 'Participants list';
 $string['participationratio'] = 'Participation ratio';
 $string['participationreport'] = 'Participation report';
@@ -2290,3 +2289,6 @@ $string['messagedselectedcountusersfailed'] = 'A problem occurred and {$a} messa
 $string['messagedselecteduserfailed'] = 'The message was not sent to user {$a->fullname}.';
 $string['previewhtml'] = 'HTML format preview';
 $string['sitemessage'] = 'Message users';
+
+// Deprecated since Moodle 3.9.
+$string['participantscount'] = 'Number of participants: {$a}';
index 6160014..e010e09 100644 (file)
@@ -22,6 +22,7 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['countparticipantsfound'] = '{$a} participants found';
 $string['privacy:courserequestpath'] = 'Requested courses';
 $string['privacy:descriptionpath'] = 'Profile description';
 $string['privacy:devicespath'] = 'User devices';
index 2c46b2f..997a965 100644 (file)
@@ -1658,6 +1658,7 @@ class flexible_table {
                 'data-table-page-number' => $this->currpage + 1,
                 'data-table-page-size' => $this->pagesize,
                 'data-table-hidden-columns' => json_encode(array_keys($this->prefs['collapse'])),
+                'data-table-total-rows' => $this->totalrows,
             ]);
         }
 
index f433003..1d61489 100644 (file)
Binary files a/user/amd/build/participants.min.js and b/user/amd/build/participants.min.js differ
index d24dd4a..97fd5a5 100644 (file)
Binary files a/user/amd/build/participants.min.js.map and b/user/amd/build/participants.min.js.map differ
index eba586a..a5e2704 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+import * as DynamicTable from 'core_table/dynamic';
+import * as Str from 'core/str';
+import CheckboxToggleAll from 'core/checkbox-toggleall';
+import CustomEvents from 'core/custom_interaction_events';
 import DynamicTableSelectors from 'core_table/local/dynamic/selectors';
 import ModalEvents from 'core/modal_events';
 import Notification from 'core/notification';
-import CustomEvents from 'core/custom_interaction_events';
+import jQuery from 'jquery';
 import {showAddNote, showSendMessage} from 'core_user/local/participants/bulkactions';
 
 const Selectors = {
     bulkActionSelect: "#formactionid",
-    bulkUserCheckBoxes: "input.usercheckbox",
-    bulkUserSelectedCheckBoxes: "input.usercheckbox:checked",
-    checkAllButton: "#checkall",
+    bulkUserSelectedCheckBoxes: "input[data-togglegroup='participants-table']:checked",
+    checkCountButton: "#checkall",
+    showCountText: '[data-region="participant-count"]',
+    showCountToggle: '[data-action="showcount"]',
     stateHelpIcon: '[data-region="state-help-icon"]',
     tableForm: uniqueId => `form[data-table-unique-id="${uniqueId}"]`,
 };
@@ -52,7 +57,8 @@ export const init = ({
      * @private
      */
     const registerEventListeners = () => {
-        root.querySelector(Selectors.bulkActionSelect).addEventListener(CustomEvents.events.accessibleChange, e => {
+        CustomEvents.define(Selectors.bulkActionSelect, [CustomEvents.events.accessibleChange]);
+        jQuery(Selectors.bulkActionSelect).on(CustomEvents.events.accessibleChange, e => {
             const action = e.target.value;
             const tableRoot = getTableFromUniqueId(uniqueid);
             const checkboxes = tableRoot.querySelectorAll(Selectors.bulkUserSelectedCheckBoxes);
@@ -98,14 +104,112 @@ export const init = ({
         });
 
         root.addEventListener('click', e => {
-            const checkAllButton = e.target.closest(Selectors.checkAllButton);
-            if (checkAllButton) {
-                const showAllLink = checkAllButton.dataset.showalllink;
-                if (showAllLink) {
-                    window.location = showAllLink;
-                }
+            // Handle clicking of the "Show [all|count]" and "Select all" actions.
+            const showCountLink = root.querySelector(Selectors.showCountToggle);
+            const checkCountButton = root.querySelector(Selectors.checkCountButton);
+
+            const showCountLinkClicked = showCountLink && showCountLink.contains(e.target);
+            const checkCountButtonClicked = checkCountButton && checkCountButton.contains(e.target);
+
+            if (showCountLinkClicked || checkCountButtonClicked) {
+                e.preventDefault();
+
+                const tableRoot = getTableFromUniqueId(uniqueid);
+
+                DynamicTable.setPageSize(tableRoot, showCountLink.dataset.targetPageSize)
+                .then(tableRoot => {
+                    // Always update the toggle state.
+                    // This ensures that the bulk actions are disabled after changing the page size.
+                    CheckboxToggleAll.setGroupState(tableRoot, 'participants-table', checkCountButtonClicked);
+
+                    return tableRoot;
+                })
+                .catch(Notification.exception);
             }
         });
+
+        // When the content is refreshed, update the row counts in various places.
+        root.addEventListener(DynamicTable.Events.tableContentRefreshed, e => {
+            const showCountLink = root.querySelector(Selectors.showCountToggle);
+            const checkCountButton = root.querySelector(Selectors.checkCountButton);
+
+            const tableRoot = e.target;
+
+            const defaultPageSize = parseInt(root.dataset.tableDefaultPerPage, 10);
+            const currentPageSize = parseInt(tableRoot.dataset.tablePageSize, 10);
+            const totalRowCount = parseInt(tableRoot.dataset.tableTotalRows, 10);
+
+            CheckboxToggleAll.updateSlavesFromMasterState(tableRoot, 'participants-table');
+
+            const pageCountStrings = [
+                {
+                    key: 'countparticipantsfound',
+                    component: 'core_user',
+                    param: totalRowCount,
+                },
+            ];
+
+
+            if (totalRowCount <= defaultPageSize) {
+                // There are fewer than the default page count numbers of rows.
+                showCountLink.classList.add('hidden');
+                checkCountButton.classList.add('hidden');
+            } else if (totalRowCount <= currentPageSize) {
+                // The are fewer than the current page size.
+                pageCountStrings.push({
+                    key: 'showperpage',
+                    component: 'core',
+                    param: defaultPageSize,
+                });
+
+                pageCountStrings.push({
+                    key: 'selectalluserswithcount',
+                    component: 'core',
+                    param: defaultPageSize,
+                });
+
+                // Show the 'Show [x]' link.
+                showCountLink.classList.remove('hidden');
+                showCountLink.dataset.targetPageSize = defaultPageSize;
+
+                // The 'Check all [x]' button is only visible when there are values to set.
+                checkCountButton.classList.add('hidden');
+            } else {
+                pageCountStrings.push({
+                    key: 'showall',
+                    component: 'core',
+                    param: totalRowCount,
+                });
+
+                pageCountStrings.push({
+                    key: 'selectalluserswithcount',
+                    component: 'core',
+                    param: totalRowCount,
+                });
+
+                // Show both the 'Show [x]' link, and the 'Check all [x]' button.
+                showCountLink.classList.remove('hidden');
+                showCountLink.dataset.targetPageSize = totalRowCount;
+                checkCountButton.classList.remove('hidden');
+            }
+
+            Str.get_strings(pageCountStrings)
+            .then(([showingParticipantCountString, showCountString, selectCountString]) => {
+                const showingParticipantCount = root.querySelector(Selectors.showCountText);
+                showingParticipantCount.innerHTML = showingParticipantCountString;
+
+                if (showCountString) {
+                    showCountLink.innerHTML = showCountString;
+                }
+
+                if (selectCountString) {
+                    checkCountButton.value = selectCountString;
+                }
+
+                return;
+            })
+            .catch(Notification.exception);
+        });
     };
 
     const resetBulkAction = bulkActionSelect => {
index 4aa5fcb..b542c1a 100644 (file)
@@ -286,8 +286,6 @@ $participanttable->out($perpage, true);
 $participanttablehtml = ob_get_contents();
 ob_end_clean();
 
-echo html_writer::tag('p', get_string('participantscount', 'moodle', $participanttable->totalrows));
-
 if ($bulkoperations) {
     echo html_writer::start_tag('form', [
         'action' => 'action_redir.php',
@@ -295,45 +293,64 @@ if ($bulkoperations) {
         'id' => 'participantsform',
         'data-course-id' => $course->id,
         'data-table-unique-id' => $participanttable->uniqueid,
+        'data-table-default-per-page' => DEFAULT_PAGE_SIZE,
     ]);
     echo '<div>';
     echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
     echo '<input type="hidden" name="returnto" value="'.s($PAGE->url->out(false)).'" />';
 }
 
+echo html_writer::tag(
+    'p',
+    get_string('countparticipantsfound', 'core_user', $participanttable->totalrows),
+    [
+        'data-region' => 'participant-count',
+    ]
+);
+
 echo $participanttablehtml;
 
 $perpageurl = clone($baseurl);
 $perpageurl->remove_params('perpage');
 if ($perpage == SHOW_ALL_PAGE_SIZE && $participanttable->totalrows > DEFAULT_PAGE_SIZE) {
     $perpageurl->param('perpage', DEFAULT_PAGE_SIZE);
-    echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showperpage', '', DEFAULT_PAGE_SIZE)), array(), 'showall');
+    echo $OUTPUT->container(html_writer::link(
+        $perpageurl,
+        get_string('showperpage', '', DEFAULT_PAGE_SIZE),
+        [
+            'data-action' => 'showcount',
+            'data-target-page-size' => DEFAULT_PAGE_SIZE,
+        ]
+    ), [], 'showall');
 
 } else if ($participanttable->get_page_size() < $participanttable->totalrows) {
     $perpageurl->param('perpage', SHOW_ALL_PAGE_SIZE);
-    echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showall', '', $participanttable->totalrows)),
-        array(), 'showall');
+    echo $OUTPUT->container(html_writer::link(
+        $perpageurl,
+        get_string('showall', '', $participanttable->totalrows),
+        [
+            'data-action' => 'showcount',
+            'data-target-page-size' => SHOW_ALL_PAGE_SIZE,
+        ]
+    ),
+    [], 'showall');
 }
 
 if ($bulkoperations) {
     echo '<br /><div class="buttons"><div class="form-inline">';
 
-    if ($participanttable->get_page_size() < $participanttable->totalrows) {
-        $perpageurl = clone($baseurl);
-        $perpageurl->remove_params('perpage');
-        $perpageurl->param('perpage', SHOW_ALL_PAGE_SIZE);
-        $perpageurl->param('selectall', true);
-        $showalllink = $perpageurl;
-    } else {
-        $showalllink = false;
-    }
-
     echo html_writer::start_tag('div', array('class' => 'btn-group'));
+
     if ($participanttable->get_page_size() < $participanttable->totalrows) {
-        // Select all users, refresh page showing all users and mark them all selected.
+        // Select all users, refresh table showing all users and mark them all selected.
         $label = get_string('selectalluserswithcount', 'moodle', $participanttable->totalrows);
-        echo html_writer::empty_tag('input', array('type' => 'button', 'id' => 'checkall', 'class' => 'btn btn-secondary',
-                'value' => $label, 'data-showallink' => $showalllink));
+        echo html_writer::empty_tag('input', [
+            'type' => 'button',
+            'id' => 'checkall',
+            'class' => 'btn btn-secondary',
+            'value' => $label,
+            'data-target-page-size' => $participanttable->totalrows,
+        ]);
     }
     echo html_writer::end_tag('div');
     $displaylist = array();
index 6cec23e..d50851f 100644 (file)
@@ -86,7 +86,7 @@ Feature: Course participants can be filtered to display all the users
     And I click on "Role: Student" item in the autocomplete list
     And I click on "Show all 24" "link"
     Then I should see "Role: Student"
-    And I should see "Number of participants: 24" in the "//div[@class='userlist']" "xpath_element"
+    And I should see "24 participants found"
     And I should see "Show 20 per page"
 
   @javascript
@@ -101,7 +101,7 @@ Feature: Course participants can be filtered to display all the users
     And I click on "Show all 23" "link"
     Then I should see "Role: Student"
     And I should see "Status: Active"
-    And I should see "Number of participants: 23" in the "//div[@class='userlist']" "xpath_element"
+    And I should see "23 participants found"
     And I should see "Student 1"
     And I should not see "Student 24"
     And I should see "Show 20 per page"