Merge branch 'MDL-68286-master' of git://github.com/andrewnicols/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 7 Apr 2020 22:37:02 +0000 (00:37 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 7 Apr 2020 22:37:02 +0000 (00:37 +0200)
13 files changed:
lib/table/amd/build/dynamic.min.js
lib/table/amd/build/dynamic.min.js.map
lib/table/amd/build/local/dynamic/repository.min.js
lib/table/amd/build/local/dynamic/repository.min.js.map
lib/table/amd/build/local/dynamic/selectors.min.js
lib/table/amd/build/local/dynamic/selectors.min.js.map
lib/table/amd/src/dynamic.js
lib/table/amd/src/local/dynamic/repository.js
lib/table/amd/src/local/dynamic/selectors.js
lib/table/classes/external/dynamic/fetch.php
lib/tablelib.php
lib/templates/initials_bar.mustache
lib/tests/tablelib_test.php

index d00b78f..2a30ca5 100644 (file)
Binary files a/lib/table/amd/build/dynamic.min.js and b/lib/table/amd/build/dynamic.min.js differ
index 2d81312..a6d77b2 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 d07cd46..849507d 100644 (file)
Binary files a/lib/table/amd/build/local/dynamic/repository.min.js and b/lib/table/amd/build/local/dynamic/repository.min.js differ
index 7629807..88acdf0 100644 (file)
Binary files a/lib/table/amd/build/local/dynamic/repository.min.js.map and b/lib/table/amd/build/local/dynamic/repository.min.js.map differ
index e45e5ff..7e047e0 100644 (file)
Binary files a/lib/table/amd/build/local/dynamic/selectors.min.js and b/lib/table/amd/build/local/dynamic/selectors.min.js differ
index 6af6cf1..525cf30 100644 (file)
Binary files a/lib/table/amd/build/local/dynamic/selectors.min.js.map and b/lib/table/amd/build/local/dynamic/selectors.min.js.map differ
index d3b9d06..4cddc4d 100644 (file)
@@ -38,7 +38,7 @@ const checkTableIsDynamic = tableRoot => {
         throw new Error("The table specified is not a dynamic table and cannot be updated");
     }
 
-    if (!tableRoot.matches(Selectors.table.region)) {
+    if (!tableRoot.matches(Selectors.main.region)) {
         // The table is not a dynamic table.
         throw new Error("The table specified is not a dynamic table and cannot be updated");
     }
@@ -73,6 +73,8 @@ export const refreshTableContent = tableRoot => {
             sortOrder: tableRoot.dataset.tableSortOrder,
             joinType: filterset.jointype,
             filters: filterset.filters,
+            firstinitial: tableRoot.dataset.tableFirstInitial,
+            lastinitial: tableRoot.dataset.tableLastInitial,
         }
     )
     .then(data => {
@@ -88,6 +90,8 @@ export const updateTable = (tableRoot, {
     sortBy = null,
     sortOrder = null,
     filters = null,
+    firstInitial = null,
+    lastInitial = null,
 } = {}, refreshContent = true) => {
     checkTableIsDynamic(tableRoot);
 
@@ -97,6 +101,15 @@ export const updateTable = (tableRoot, {
         tableRoot.dataset.tableSortOrder = sortOrder;
     }
 
+    // Update initials.
+    if (firstInitial !== null) {
+        tableRoot.dataset.tableFirstInitial = firstInitial;
+    }
+
+    if (lastInitial !== null) {
+        tableRoot.dataset.tableLastInitial = lastInitial;
+    }
+
     // Update filters.
     if (filters) {
         tableRoot.dataset.tableFilters = JSON.stringify(filters);
@@ -133,6 +146,28 @@ export const setFilters = (tableRoot, filters, refreshContent = true) =>
 export const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true) =>
     updateTable(tableRoot, {sortBy, sortOrder}, refreshContent);
 
+/**
+ * Update the first initial to show.
+ *
+ * @param {HTMLElement} tableRoot
+ * @param {String} firstInitial
+ * @param {Bool} refreshContent
+ * @returns {Promise}
+ */
+export const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) =>
+    updateTable(tableRoot, {firstInitial}, refreshContent);
+
+/**
+ * Update the last initial to show.
+ *
+ * @param {HTMLElement} tableRoot
+ * @param {String} lastInitial
+ * @param {Bool} refreshContent
+ * @returns {Promise}
+ */
+export const setLastInitial = (tableRoot, lastInitial, refreshContent = true) =>
+    updateTable(tableRoot, {lastInitial}, refreshContent);
+
 /**
  * Set up listeners to handle table updates.
  */
@@ -144,7 +179,7 @@ export const init = () => {
     watching = true;
 
     document.addEventListener('click', e => {
-        const tableRoot = e.target.closest(Selectors.table.region);
+        const tableRoot = e.target.closest(Selectors.main.region);
 
         if (!tableRoot) {
             return;
@@ -156,5 +191,19 @@ export const init = () => {
 
             setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder);
         }
+
+        const firstInitialLink = e.target.closest(Selectors.initialsBar.links.firstInitial);
+        if (firstInitialLink !== null) {
+            e.preventDefault();
+
+            setFirstInitial(tableRoot, firstInitialLink.dataset.initial);
+        }
+
+        const lastInitialLink = e.target.closest(Selectors.initialsBar.links.lastInitial);
+        if (lastInitialLink !== null) {
+            e.preventDefault();
+
+            setLastInitial(tableRoot, lastInitialLink.dataset.initial);
+        }
     });
 };
index 4fe7219..6743775 100644 (file)
@@ -30,6 +30,9 @@ import {call as fetchMany} from 'core/ajax';
  * @method fetch
  * @param {String} handler The name of the handler
  * @param {String} uniqueid The unique id of the table
+ * @param {Object} filters The filters to apply when searching
+ * @param {String} firstinitial The first name initial to filter on
+ * @param {String} lastinitial The last name initial to filter on
  * @param {Number} params parameters to request table
  * @return {Promise} Resolved with requested table view
  */
@@ -37,7 +40,9 @@ export const fetch = (handler, uniqueid, {
         sortBy = null,
         sortOrder = null,
         joinType = null,
-        filters = {}
+        filters = {},
+        firstinitial = null,
+        lastinitial = null,
     } = {}
 ) => {
     return fetchMany([{
@@ -49,6 +54,8 @@ export const fetch = (handler, uniqueid, {
             sortorder: sortOrder,
             jointype: joinType,
             filters,
+            firstinitial,
+            lastinitial,
         },
     }])[0];
 };
index 68a0a3b..6803571 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 export default {
-    table: {
+    main: {
         region: '[data-region="core_table/dynamic"]',
+    },
+    table: {
         links: {
             sortableColumn: 'a[data-sortable="1"]',
         },
     },
+    initialsBar: {
+        links: {
+            firstInitial: '.firstinitial [data-initial]',
+            lastInitial: '.lastinitial [data-initial]',
+        },
+    },
 };
index 8cef49c..b029ff5 100644 (file)
@@ -86,6 +86,18 @@ class fetch extends external_api {
                 VALUE_OPTIONAL
             ),
             'jointype' => new external_value(PARAM_INT, 'Type of join to join all filters together', VALUE_REQUIRED),
+            'firstinitial' => new external_value(
+                PARAM_ALPHANUMEXT,
+                'The first initial to sort filter on',
+                VALUE_REQUIRED,
+                null
+            ),
+            'lastinitial' => new external_value(
+                PARAM_ALPHANUMEXT,
+                'The last initial to sort filter on',
+                VALUE_REQUIRED,
+                null
+            ),
         ]);
     }
 
@@ -98,11 +110,21 @@ class fetch extends external_api {
      * @param string $sortorder The sort order.
      * @param array $filters The filters that will be applied in the request.
      * @param string $jointype The join type.
+     * @param string $firstinitial The first name initial to filter on
+     * @param string $lastinitial The last name initial to filter on
      *
      * @return array
      */
-    public static function execute(string $handler, string $uniqueid, string $sortby, string $sortorder,
-            array $filters = [], string $jointype = null) {
+    public static function execute(
+        string $handler,
+        string $uniqueid,
+        string $sortby,
+        string $sortorder,
+        ?array $filters = null,
+        ?string $jointype = null,
+        ?string $firstinitial = null,
+        ?string $lastinitial = null
+    ) {
 
         global $PAGE;
 
@@ -117,6 +139,8 @@ class fetch extends external_api {
             'sortorder' => $sortorder,
             'filters' => $filters,
             'jointype' => $jointype,
+            'firstinitial' => $firstinitial,
+            'lastinitial' => $lastinitial,
         ] = self::validate_parameters(self::execute_parameters(), [
             'handler' => $handler,
             'uniqueid' => $uniqueid,
@@ -124,6 +148,8 @@ class fetch extends external_api {
             'sortorder' => $sortorder,
             'filters' => $filters,
             'jointype' => $jointype,
+            'firstinitial' => $firstinitial,
+            'lastinitial' => $lastinitial,
         ]);
 
         $filterset = new \core_user\table\participants_filterset();
@@ -139,6 +165,14 @@ class fetch extends external_api {
         $instance->set_filterset($filterset);
         $instance->set_sorting($sortby, $sortorder);
 
+        if ($firstinitial !== null) {
+            $instance->set_first_initial($firstinitial);
+        }
+
+        if ($lastinitial !== null) {
+            $instance->set_last_initial($lastinitial);
+        }
+
         $context = $instance->get_context();
 
         self::validate_context($context);
index e5f5b03..a3c9298 100644 (file)
@@ -95,6 +95,12 @@ class flexible_table {
      */
     protected $sortorder;
 
+    /** @var string The manually set first name initial preference */
+    protected $ifirst;
+
+    /** @var string The manually set last name initial preference */
+    protected $ilast;
+
     var $use_pages      = false;
     var $use_initials   = false;
 
@@ -525,16 +531,7 @@ class flexible_table {
         }
 
         $this->set_sorting_preferences();
-
-        $ilast = optional_param($this->request[TABLE_VAR_ILAST], null, PARAM_RAW);
-        if (!is_null($ilast) && ($ilast ==='' || strpos(get_string('alphabet', 'langconfig'), $ilast) !== false)) {
-            $this->prefs['i_last'] = $ilast;
-        }
-
-        $ifirst = optional_param($this->request[TABLE_VAR_IFIRST], null, PARAM_RAW);
-        if (!is_null($ifirst) && ($ifirst === '' || strpos(get_string('alphabet', 'langconfig'), $ifirst) !== false)) {
-            $this->prefs['i_first'] = $ifirst;
-        }
+        $this->set_initials_preferences();
 
         // Save user preferences if they have changed.
         if ($this->prefs != $oldprefs) {
@@ -1002,12 +999,18 @@ class flexible_table {
     function print_nothing_to_display() {
         global $OUTPUT;
 
+        // Render the dynamic table header.
+        echo $this->get_dynamic_table_html_start();
+
         // Render button to allow user to reset table preferences.
         echo $this->render_reset_button();
 
         $this->print_initials_bar();
 
         echo $OUTPUT->heading(get_string('nothingtodisplay'));
+
+        // Render the dynamic table footer.
+        echo $this->get_dynamic_table_html_end();
     }
 
     /**
@@ -1172,12 +1175,8 @@ class flexible_table {
                 echo $OUTPUT->render($pagingbar);
             }
 
-            // Dynamic Table content.
-            if (is_a($this, \core_table\dynamic::class)) {
-                echo html_writer::end_tag('div');
-
-                $PAGE->requires->js_call_amd('core_table/dynamic', 'init');
-            }
+            // Render the dynamic table footer.
+            echo $this->get_dynamic_table_html_end();
         }
     }
 
@@ -1353,6 +1352,31 @@ class flexible_table {
         }
     }
 
+    /**
+     * Fill in the preferences for the initials bar.
+     */
+    protected function set_initials_preferences(): void {
+        $ifirst = $this->ifirst;
+        $ilast = $this->ilast;
+
+        if ($ifirst === null) {
+            $ifirst = optional_param($this->request[TABLE_VAR_IFIRST], null, PARAM_RAW);
+        }
+
+        if ($ilast === null) {
+            $ilast = optional_param($this->request[TABLE_VAR_ILAST], null, PARAM_RAW);
+        }
+
+        if (!is_null($ifirst) && ($ifirst === '' || strpos(get_string('alphabet', 'langconfig'), $ifirst) !== false)) {
+            $this->prefs['i_first'] = $ifirst;
+        }
+
+        if (!is_null($ilast) && ($ilast === '' || strpos(get_string('alphabet', 'langconfig'), $ilast) !== false)) {
+            $this->prefs['i_last'] = $ilast;
+        }
+
+    }
+
     /**
      * Set the preferred table sorting attributes.
      *
@@ -1364,6 +1388,24 @@ class flexible_table {
         $this->sortorder = $sortorder;
     }
 
+    /**
+     * Set the preferred first name initial in an initials bar.
+     *
+     * @param string $initial The character to set
+     */
+    public function set_first_initial(string $initial): void {
+        $this->ifirst = $initial;
+    }
+
+    /**
+     * Set the preferred last name initial in an initials bar.
+     *
+     * @param string $initial The character to set
+     */
+    public function set_last_initial(string $initial): void {
+        $this->ilast = $initial;
+    }
+
     /**
      * Generate the HTML for the sort icon. This is a helper method used by {@link sort_link()}.
      * @param bool $isprimary whether an icon is needed (it is only needed for the primary sort column.)
@@ -1446,23 +1488,55 @@ class flexible_table {
     }
 
     /**
-     * This function is not part of the public api.
+     * Get the dynamic table start wrapper.
+     * If this is not a dynamic table, then an empty string is returned making this safe to blindly call.
+     *
+     * @return string
      */
-    function start_html() {
-        global $OUTPUT;
-
+    protected function get_dynamic_table_html_start(): string {
         if (is_a($this, \core_table\dynamic::class)) {
             $sortdata = $this->get_sort_order();
-            echo html_writer::start_tag('div', [
+            return html_writer::start_tag('div', [
                 'data-region' => 'core_table/dynamic',
                 'data-table-handler' => get_class($this),
                 'data-table-uniqueid' => $this->uniqueid,
                 'data-table-filters' => json_encode($this->get_filterset()),
                 'data-table-sort-by' => $sortdata['sortby'],
                 'data-table-sort-order' => $sortdata['sortorder'],
+                'data-table-first-initial' => $this->prefs['i_first'],
+                'data-table-last-initial' => $this->prefs['i_last'],
             ]);
         }
 
+        return '';
+    }
+
+    /**
+     * Get the dynamic table end wrapper.
+     * If this is not a dynamic table, then an empty string is returned making this safe to blindly call.
+     *
+     * @return string
+     */
+    protected function get_dynamic_table_html_end(): string {
+        global $PAGE;
+
+        if (is_a($this, \core_table\dynamic::class)) {
+            $PAGE->requires->js_call_amd('core_table/dynamic', 'init');
+            return html_writer::end_tag('div');
+        }
+
+        return '';
+    }
+
+    /**
+     * This function is not part of the public api.
+     */
+    function start_html() {
+        global $OUTPUT;
+
+        // Render the dynamic table header.
+        echo $this->get_dynamic_table_html_start();
+
         // Render button to allow user to reset table preferences.
         echo $this->render_reset_button();
 
index 7f02e93..ab87624 100644 (file)
         <ul class="pagination pagination-sm">
         {{#current}}
             <li class="initialbarall page-item">
-                <a class="page-link" href="{{url}}">{{all}}</a>
+                <a data-initial="" class="page-link" href="{{url}}">{{all}}</a>
             </li>
         {{/current}}
         {{^current}}
             <li class="initialbarall page-item active">
-                <a class="page-link">{{all}}</a>
+                <a data-initial="" class="page-link">{{all}}</a>
             </li>
         {{/current}}
         </ul>
             <ul class="pagination pagination-sm">
                 {{#letter}}
                     {{#selected}}
-                        <li class="page-item active {{name}}"><span class="page-link">{{name}}</span></li>
+                        <li data-initial="{{name}}" class="page-item active {{name}}"><span class="page-link">{{name}}</span></li>
                     {{/selected}}
                     {{^selected}}
-                        <li class="page-item {{name}}"><a class="page-link" href="{{url}}">{{name}}</a></li>
+                        <li data-initial="{{name}}" class="page-item {{name}}"><a class="page-link" href="{{url}}">{{name}}</a></li>
                     {{/selected}}
                 {{/letter}}
             </ul>
index 25bf48a..0e41c87 100644 (file)
@@ -701,4 +701,91 @@ class core_tablelib_testcase extends advanced_testcase {
         $this->assertEquals("Col1,Col2,Col3\na,b,c\n", substr($output, 3));
     }
 
+    /**
+     * Test the initials functionality.
+     *
+     * @dataProvider initials_provider
+     * @param string|null $getvalue
+     * @param string|null $setvalue
+     * @param string|null $finalvalue
+     */
+    public function test_initials_first_set(?string $getvalue, ?string $setvalue, ?string $finalvalue): void {
+        global $_GET;
+
+        $this->resetAfterTest(true);
+
+        $table = new flexible_table('tablelib_test');
+
+        $user = $this->getDataGenerator()->create_user();
+
+        $table->define_columns(['fullname']);
+        $table->define_headers(['Fullname']);
+        $table->define_baseurl('/invalid.php');
+        $table->initialbars(true);
+
+        if ($getvalue !== null) {
+            $_GET['tifirst'] = $getvalue;
+        }
+
+        if ($setvalue !== null) {
+            $table->set_first_initial($setvalue);
+        }
+
+        $table->setup();
+
+        $this->assertEquals($finalvalue, $table->get_initial_first());
+    }
+
+    /**
+     * Test the initials functionality.
+     *
+     * @dataProvider initials_provider
+     * @param string|null $getvalue
+     * @param string|null $setvalue
+     * @param string|null $finalvalue
+     */
+    public function test_initials_last_set(?string $getvalue, ?string $setvalue, ?string $finalvalue): void {
+        global $_GET;
+
+        $this->resetAfterTest(true);
+
+        $table = new flexible_table('tablelib_test');
+
+        $user = $this->getDataGenerator()->create_user();
+
+        $table->define_columns(['fullname']);
+        $table->define_headers(['Fullname']);
+        $table->define_baseurl('/invalid.php');
+        $table->initialbars(true);
+
+        if ($getvalue !== null) {
+            $_GET['tilast'] = $getvalue;
+        }
+
+        if ($setvalue !== null) {
+            $table->set_last_initial($setvalue);
+        }
+
+        $table->setup();
+
+        $this->assertEquals($finalvalue, $table->get_initial_last());
+    }
+
+    /**
+     * Data for testing initials providers.
+     *
+     * @return array
+     */
+    public function initials_provider(): array {
+        return [
+            [null, null, null],
+            ['A', null, 'A'],
+            ['Z', null, 'Z'],
+            [null, 'A', 'A'],
+            [null, 'Z', 'Z'],
+            ['A', 'Z', 'Z'],
+            ['Z', 'A', 'A'],
+        ];
+    }
+
 }