MDL-68612 user: Set the initial filter on page load
authorAndrew Nicols <andrew@nicols.co.uk>
Fri, 22 May 2020 10:59:41 +0000 (18:59 +0800)
committerMichael Hawkins <michaelh@moodle.com>
Wed, 3 Jun 2020 06:29:22 +0000 (14:29 +0800)
12 files changed:
lib/table/amd/build/dynamic.min.js
lib/table/amd/build/dynamic.min.js.map
lib/table/amd/src/dynamic.js
user/amd/build/local/participantsfilter/filter.min.js
user/amd/build/local/participantsfilter/filter.min.js.map
user/amd/build/local/participantsfilter/filtertypes/keyword.min.js
user/amd/build/local/participantsfilter/filtertypes/keyword.min.js.map
user/amd/build/participantsfilter.min.js
user/amd/build/participantsfilter.min.js.map
user/amd/src/local/participantsfilter/filter.js
user/amd/src/local/participantsfilter/filtertypes/keyword.js
user/amd/src/participantsfilter.js

index f4b2bdc..da081b3 100644 (file)
Binary files a/lib/table/amd/build/dynamic.min.js and b/lib/table/amd/build/dynamic.min.js differ
index 822e013..1609714 100644 (file)
Binary files a/lib/table/amd/build/dynamic.min.js.map and b/lib/table/amd/build/dynamic.min.js.map differ
index 235dd5e..10abe96 100644 (file)
@@ -158,6 +158,18 @@ export const updateTable = (tableRoot, {
     }
 };
 
+/**
+ * Get the table dataset for the specified tableRoot, ensuring that the provided table is a dynamic table.
+ *
+ * @param {HTMLElement} tableRoot
+ * @returns {DOMStringMap}
+ */
+const getTableData = tableRoot => {
+    checkTableIsDynamic(tableRoot);
+
+    return tableRoot.dataset;
+};
+
 /**
  * Update the specified table using the new filters.
  *
@@ -169,6 +181,18 @@ export const updateTable = (tableRoot, {
 export const setFilters = (tableRoot, filters, refreshContent = true) =>
     updateTable(tableRoot, {filters}, refreshContent);
 
+/**
+ * Get the filter data for the specified table.
+ *
+ * @param {HTMLElement} tableRoot
+ * @returns {Object}
+ */
+export const getFilters = tableRoot => {
+    checkTableIsDynamic(tableRoot);
+
+    return getFiltersetFromTable(tableRoot);
+};
+
 /**
  * Update the sort order.
  *
@@ -192,6 +216,14 @@ export const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true
 export const setPageNumber = (tableRoot, pageNumber, refreshContent = true) =>
     updateTable(tableRoot, {pageNumber}, refreshContent);
 
+/**
+ * Get the current page number.
+ *
+ * @param {HTMLElement} tableRoot
+ * @returns {Number}
+ */
+export const getPageNumber = tableRoot => getTableData(tableRoot).tablePageNumber;
+
 /**
  * Set the page size.
  *
@@ -203,6 +235,14 @@ export const setPageNumber = (tableRoot, pageNumber, refreshContent = true) =>
 export const setPageSize = (tableRoot, pageSize, refreshContent = true) =>
     updateTable(tableRoot, {pageSize, pageNumber: 0}, refreshContent);
 
+/**
+ * Get the current page size.
+ *
+ * @param {HTMLElement} tableRoot
+ * @returns {Number}
+ */
+export const getPageSize = tableRoot => getTableData(tableRoot).tablePageSize;
+
 /**
  * Update the first initial to show.
  *
@@ -214,6 +254,14 @@ export const setPageSize = (tableRoot, pageSize, refreshContent = true) =>
 export const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) =>
     updateTable(tableRoot, {firstInitial}, refreshContent);
 
+/**
+ * Get the current first initial filter.
+ *
+ * @param {HTMLElement} tableRoot
+ * @returns {String}
+ */
+export const getFirstInitial = tableRoot => getTableData(tableRoot).tableFirstInitial;
+
 /**
  * Update the last initial to show.
  *
@@ -225,6 +273,14 @@ export const setFirstInitial = (tableRoot, firstInitial, refreshContent = true)
 export const setLastInitial = (tableRoot, lastInitial, refreshContent = true) =>
     updateTable(tableRoot, {lastInitial}, refreshContent);
 
+/**
+ * Get the current last initial filter.
+ *
+ * @param {HTMLElement} tableRoot
+ * @returns {String}
+ */
+export const getLastInitial = tableRoot => getTableData(tableRoot).tableLastInitial;
+
 /**
  * Hide a column in the participants table.
  *
index 3ef1d57..0f13ff2 100644 (file)
Binary files a/user/amd/build/local/participantsfilter/filter.min.js and b/user/amd/build/local/participantsfilter/filter.min.js differ
index e694bbf..1cc0896 100644 (file)
Binary files a/user/amd/build/local/participantsfilter/filter.min.js.map and b/user/amd/build/local/participantsfilter/filter.min.js.map differ
index 4e178f8..b9b0dda 100644 (file)
Binary files a/user/amd/build/local/participantsfilter/filtertypes/keyword.min.js and b/user/amd/build/local/participantsfilter/filtertypes/keyword.min.js differ
index 0c000b7..9a66bfa 100644 (file)
Binary files a/user/amd/build/local/participantsfilter/filtertypes/keyword.min.js.map and b/user/amd/build/local/participantsfilter/filtertypes/keyword.min.js.map differ
index 8e225bf..1176f2b 100644 (file)
Binary files a/user/amd/build/participantsfilter.min.js and b/user/amd/build/participantsfilter.min.js differ
index b9cf663..b4c9f89 100644 (file)
Binary files a/user/amd/build/participantsfilter.min.js.map and b/user/amd/build/participantsfilter.min.js.map differ
index 7895ca0..6670c2e 100644 (file)
@@ -44,12 +44,13 @@ export default class {
      *
      * @param {String} filterType The type of filter that this relates to
      * @param {HTMLElement} rootNode The root node for the participants filterset
+     * @param {Array} initialValues The initial values for the selector
      */
-    constructor(filterType, rootNode) {
+    constructor(filterType, rootNode, initialValues) {
         this.filterType = filterType;
         this.rootNode = rootNode;
 
-        this.addValueSelector();
+        this.addValueSelector(initialValues);
     }
 
     /**
@@ -79,8 +80,10 @@ export default class {
 
     /**
      * Add the value selector to the filter row.
+     *
+     * @param {Array} initialValues
      */
-    async addValueSelector() {
+    async addValueSelector(initialValues = []) {
         const filterValueNode = this.getFilterValueNode();
 
         // Copy the data in place.
@@ -88,6 +91,21 @@ export default class {
 
         const dataSource = filterValueNode.querySelector('select');
 
+        // If there are any initial values then attempt to apply them.
+        initialValues.forEach(filterValue => {
+            let selectedOption = dataSource.querySelector(`option[value="${filterValue}"]`);
+            if (selectedOption) {
+                selectedOption.selected = true;
+            } else if (!this.showSuggestions) {
+                selectedOption = document.createElement('option');
+                selectedOption.value = filterValue;
+                selectedOption.innerHTML = filterValue;
+                selectedOption.selected = true;
+
+                dataSource.append(selectedOption);
+            }
+        });
+
         Autocomplete.enhance(
             // The source select element.
             dataSource,
index c7b7872..a1aa479 100644 (file)
@@ -25,10 +25,6 @@ import Filter from '../filter';
 import {get_string as getString} from 'core/str';
 
 export default class extends Filter {
-    constructor(filterType, filterSet) {
-        super(filterType, filterSet);
-    }
-
     /**
      * For keywords the final value is an Array of strings.
      *
index 2214b8f..718e5ab 100644 (file)
@@ -106,8 +106,10 @@ export const init = participantsRegionId => {
      *
      * @param {HTMLElement} filterRow
      * @param {String} filterType
+     * @param {Array} initialFilterValues The initially selected values for the filter
+     * @returns {Filter}
      */
-    const addFilter = async(filterRow, filterType) => {
+    const addFilter = async(filterRow, filterType, initialFilterValues) => {
         // Name the filter on the filter row.
         filterRow.dataset.filterType = filterType;
 
@@ -118,14 +120,17 @@ export const init = participantsRegionId => {
         if (filterDataNode.dataset.filterTypeClass) {
             Filter = await import(filterDataNode.dataset.filterTypeClass);
         }
-        activeFilters[filterType] = new Filter(filterType, filterSet);
+        activeFilters[filterType] = new Filter(filterType, filterSet, initialFilterValues);
 
         // Disable the select.
         const typeField = filterRow.querySelector(Selectors.filter.fields.type);
+        typeField.value = filterType;
         typeField.disabled = 'disabled';
 
         // Update the list of available filter types.
         updateFiltersOptions();
+
+        return activeFilters[filterType];
     };
 
     /**
@@ -248,15 +253,28 @@ export const init = participantsRegionId => {
 
     /**
      * Remove all filters.
+     *
+     * @returns {Promise}
      */
-    const removeAllFilters = async() => {
+    const removeAllFilters = () => {
         const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);
-        filters.forEach((filterRow) => {
-            removeOrReplaceFilterRow(filterRow);
-        });
+        filters.forEach(filterRow => removeOrReplaceFilterRow(filterRow));
 
         // Refresh the table.
-        updateTableFromFilter();
+        return updateTableFromFilter();
+    };
+
+    /**
+     * Remove any empty filters.
+     */
+    const removeEmptyFilters = () => {
+        const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);
+        filters.forEach(filterRow => {
+            const filterType = filterRow.querySelector(Selectors.filter.fields.type);
+            if (!filterType.value) {
+                removeOrReplaceFilterRow(filterRow);
+            }
+        });
     };
 
     /**
@@ -298,6 +316,49 @@ export const init = participantsRegionId => {
         }
     };
 
+    /**
+     * Set the current filter options based on a provided configuration.
+     *
+     * @param {Object} config
+     * @param {Number} config.jointype
+     * @param {Object} config.filters
+     */
+    const setFilterFromConfig = config => {
+        const filterConfig = Object.entries(config.filters);
+
+        if (!filterConfig.length) {
+            // There are no filters to set from.
+            return;
+        }
+
+        // Set the main join type.
+        filterSet.querySelector(Selectors.filterset.fields.join).value = config.jointype;
+
+        const filterPromises = filterConfig.map(([filterType, filterData]) => {
+            if (filterType === 'courseid') {
+                // The courseid is a special case.
+                return Promise.resolve();
+            }
+
+            const filterValues = filterData.values;
+
+            if (!filterValues.length) {
+                // There are no values for this filter.
+                // Skip it.
+                return Promise.resolve();
+            }
+
+            return addFilterRow().then(([filterRow]) => addFilter(filterRow, filterType, filterValues));
+        });
+
+        Promise.all(filterPromises).then(() => {
+            return removeEmptyFilters();
+        })
+        .then(updateFiltersOptions)
+        .then(updateTableFromFilter)
+        .catch();
+    };
+
     /**
      * Update the Dynamic table based upon the current filter.
      *
@@ -383,4 +444,11 @@ export const init = participantsRegionId => {
     filterSet.querySelector(Selectors.filterset.fields.join).addEventListener('change', e => {
         filterSet.dataset.filterverb = e.target.value;
     });
+
+    const tableRoot = DynamicTable.getTableFromId(filterSet.dataset.tableRegion);
+    const initialFilters = DynamicTable.getFilters(tableRoot);
+    if (initialFilters) {
+        // Apply the initial filter configuration.
+        setFilterFromConfig(initialFilters);
+    }
 };