MDL-63793 block_myoverview: Persist the user's paging limit preference
authorPeter <peter@moodle.com>
Tue, 30 Oct 2018 05:42:14 +0000 (13:42 +0800)
committerPeter <peter@moodle.com>
Mon, 19 Nov 2018 01:43:00 +0000 (09:43 +0800)
* providers for paging preferences
* Moved the user pref persistence to the factory
* Added client defined namespace in config
* Define custom client events in the client instead of passing to the
  factory

14 files changed:
blocks/myoverview/amd/build/view.min.js
blocks/myoverview/amd/src/view.js
blocks/myoverview/block_myoverview.php
blocks/myoverview/classes/output/main.php
blocks/myoverview/classes/privacy/provider.php
blocks/myoverview/lang/en/block_myoverview.php
blocks/myoverview/lib.php
blocks/myoverview/templates/courses-view.mustache
blocks/myoverview/tests/behat/block_myoverview_pagelimit_persistence.feature [new file with mode: 0644]
blocks/myoverview/tests/privacy_test.php
lib/amd/build/paged_content.min.js
lib/amd/build/paged_content_factory.min.js
lib/amd/src/paged_content.js
lib/amd/src/paged_content_factory.js

index 0212118..dbce038 100644 (file)
Binary files a/blocks/myoverview/amd/build/view.min.js and b/blocks/myoverview/amd/build/view.min.js differ
index 62f44a8..f9d0e1d 100644 (file)
@@ -31,7 +31,8 @@ define(
     'core/notification',
     'core/templates',
     'core_course/events',
-    'block_myoverview/selectors'
+    'block_myoverview/selectors',
+    'core/paged_content_events',
 ],
 function(
     $,
@@ -42,7 +43,8 @@ function(
     Notification,
     Templates,
     CourseEvents,
-    Selectors
+    Selectors,
+    PagedContentEvents
 ) {
 
     var SELECTORS = {
@@ -75,6 +77,8 @@ function(
 
     var lastLimit = 0;
 
+    var namespace = null;
+
     /**
      * Get filter values from DOM.
      *
@@ -95,6 +99,7 @@ function(
     var DEFAULT_PAGED_CONTENT_CONFIG = {
         ignoreControlWhileLoading: true,
         controlPlacementBottom: true,
+        persistentLimitKey: 'block_myoverview_user_paging_preference'
     };
 
     /**
@@ -377,17 +382,58 @@ function(
         }
     };
 
+    /**
+     * Return the callback to be passed to the subscribe event
+     *
+     * @param {Number} limit The paged limit that is passed through the event
+     */
+    var setLimit = function(limit) {
+        this.find(Selectors.courseView.region).attr('data-paging', limit);
+    };
+
     /**
      * Intialise the paged list and cards views on page load.
+     * Returns an array of paged contents that we would like to handle here
+     *
+     * @param {object} root The root element for the courses view
+     * @param {string} namespace The namespace for all the events attached
+     */
+    var registerPagedEventHandlers = function(root, namespace) {
+        var event = namespace + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT;
+        PubSub.subscribe(event, setLimit.bind(root));
+    };
+
+    /**
+     * Intialise the courses list and cards views on page load.
      *
      * @param {object} root The root element for the courses view.
      * @param {object} content The content element for the courses view.
      */
     var initializePagedContent = function(root) {
+        namespace = "block_myoverview_" + root.attr('id') + "_" + Math.random();
+
+        var itemsPerPage = NUMCOURSES_PERPAGE;
+        var pagingLimit = parseInt(root.find(Selectors.courseView.region).attr('data-paging'), 10);
+        if (pagingLimit) {
+            itemsPerPage = NUMCOURSES_PERPAGE.map(function(value) {
+                var active = false;
+                if (value == pagingLimit) {
+                    active = true;
+                }
+
+                return {
+                    value: value,
+                    active: active
+                };
+            });
+        }
+
         var filters = getFilterValues(root);
+        var config = $.extend({}, DEFAULT_PAGED_CONTENT_CONFIG);
+        config.eventNamespace = namespace;
 
         var pagedContentPromise = PagedContentFactory.createWithLimit(
-            NUMCOURSES_PERPAGE,
+            itemsPerPage,
             function(pagesData, actions) {
                 var promises = [];
 
@@ -471,10 +517,11 @@ function(
 
                 return promises;
             },
-            DEFAULT_PAGED_CONTENT_CONFIG
+            config
         );
 
         pagedContentPromise.then(function(html, js) {
+            registerPagedEventHandlers(root, namespace);
             return Templates.replaceNodeContents(root.find(Selectors.courseView.region), html, js);
         }).catch(Notification.exception);
     };
@@ -556,12 +603,12 @@ function(
         lastPage = 0;
         courseOffset = 0;
 
+        initializePagedContent(root);
+
         if (!root.attr('data-init')) {
             registerEventListeners(root);
             root.attr('data-init', true);
         }
-
-        initializePagedContent(root);
     };
 
     /**
index cbd2f9d..85c208e 100644 (file)
@@ -52,8 +52,9 @@ class block_myoverview extends block_base {
         $group = get_user_preferences('block_myoverview_user_grouping_preference');
         $sort = get_user_preferences('block_myoverview_user_sort_preference');
         $view = get_user_preferences('block_myoverview_user_view_preference');
+        $paging = get_user_preferences('block_myoverview_user_paging_preference');
 
-        $renderable = new \block_myoverview\output\main($group, $sort, $view);
+        $renderable = new \block_myoverview\output\main($group, $sort, $view, $paging);
         $renderer = $this->page->get_renderer('block_myoverview');
 
         $this->content = new stdClass();
index 7cd6d1e..eb28dce 100644 (file)
@@ -59,6 +59,13 @@ class main implements renderable, templatable {
      */
     private $view;
 
+    /**
+     * Store the paging preference
+     *
+     * @var string String matching the paging constants defined in myoverview/lib.php
+     */
+    private $paging;
+
     /**
      * main constructor.
      * Initialize the user preferences
@@ -67,10 +74,11 @@ class main implements renderable, templatable {
      * @param string $sort Sort user preference
      * @param string $view Display user preference
      */
-    public function __construct($grouping, $sort, $view) {
+    public function __construct($grouping, $sort, $view, $paging) {
         $this->grouping = $grouping ? $grouping : BLOCK_MYOVERVIEW_GROUPING_ALL;
         $this->sort = $sort ? $sort : BLOCK_MYOVERVIEW_SORTING_TITLE;
         $this->view = $view ? $view : BLOCK_MYOVERVIEW_VIEW_CARD;
+        $this->paging = $paging ? $paging : BLOCK_MYOVERVIEW_PAGING_12;
     }
 
     /**
@@ -101,7 +109,8 @@ class main implements renderable, templatable {
             'nocoursesimg' => $nocoursesurl,
             'grouping' => $this->grouping,
             'sort' => $this->sort == BLOCK_MYOVERVIEW_SORTING_TITLE ? 'fullname' : 'ul.timeaccess desc',
-            'view' => $this->view
+            'view' => $this->view,
+            'paging' => $this->paging
         ];
 
         $preferences = $this->get_preferences_as_booleans();
index be95345..729bbce 100644 (file)
@@ -49,6 +49,8 @@ class provider implements \core_privacy\local\metadata\provider, user_preference
         $collection->add_user_preference('block_myoverview_user_view_preference', 'privacy:metadata:overviewviewpreference');
         $collection->add_user_preference('block_myoverview_user_grouping_preference',
             'privacy:metadata:overviewgroupingpreference');
+        $collection->add_user_preference('block_myoverview_user_paging_preference',
+            'privacy:metadata:overviewpagingpreference');
         return $collection;
     }
     /**
@@ -94,5 +96,13 @@ class provider implements \core_privacy\local\metadata\provider, user_preference
                 );
             }
         }
+
+        $preference = get_user_preferences('block_myoverview_user_paging_preference', null, $userid);
+        if (isset($preference)) {
+            \core_privacy\local\request\writer::export_user_preference('block_myoverview',
+                'block_myoverview_user_paging_preference',
+                $preference,
+                get_string('privacy:metadata:overviewpagingpreference', 'block_myoverview'));
+        }
     }
 }
\ No newline at end of file
index 7a7e2e2..3bd0631 100644 (file)
@@ -60,6 +60,7 @@ $string['pluginname'] = 'Course overview';
 $string['privacy:metadata:overviewsortpreference'] = 'The Course overview block sort preference.';
 $string['privacy:metadata:overviewviewpreference'] = 'The Course overview block view preference.';
 $string['privacy:metadata:overviewgroupingpreference'] = 'The Course overview block grouping preference.';
+$string['privacy:metadata:overviewpagingpreference'] = 'The Course overview block paging preference.';
 $string['removefromfavourites'] = 'Unstar this course';
 $string['summary'] = 'Summary';
 $string['title'] = 'Title';
index 3244e4c..ed7334a 100644 (file)
@@ -48,6 +48,13 @@ define('BLOCK_MYOVERVIEW_VIEW_CARD', 'cards');
 define('BLOCK_MYOVERVIEW_VIEW_LIST', 'list');
 define('BLOCK_MYOVERVIEW_VIEW_SUMMARY', 'summary');
 
+/**
+ * Constants for the user paging preferences
+ */
+define('BLOCK_MYOVERVIEW_PAGING_12', 12);
+define('BLOCK_MYOVERVIEW_PAGING_24', 24);
+define('BLOCK_MYOVERVIEW_PAGING_48', 48);
+
 /**
  * Get the current user preferences that are available
  *
@@ -95,5 +102,16 @@ function block_myoverview_user_preferences() {
         'default' => 'none'
     );
 
+    $preferences['block_myoverview_user_paging_preference'] = array(
+        'null' => NULL_NOT_ALLOWED,
+        'default' => BLOCK_MYOVERVIEW_PAGING_12,
+        'type' => PARAM_INT,
+        'choices' => array(
+            BLOCK_MYOVERVIEW_PAGING_12,
+            BLOCK_MYOVERVIEW_PAGING_24,
+            BLOCK_MYOVERVIEW_PAGING_48
+        )
+    );
+
     return $preferences;
 }
index c5be1e8..d58425c 100644 (file)
@@ -33,6 +33,7 @@
     data-grouping="{{grouping}}"
     data-sort="{{sort}}"
     data-prev-display="{{view}}"
+    data-paging="{{paging}}"
     data-nocoursesimg="{{nocoursesimg}}">
     <div data-region="course-view-content">
         <div data-region="courses-loading-placeholder">
diff --git a/blocks/myoverview/tests/behat/block_myoverview_pagelimit_persistence.feature b/blocks/myoverview/tests/behat/block_myoverview_pagelimit_persistence.feature
new file mode 100644 (file)
index 0000000..4135c0a
--- /dev/null
@@ -0,0 +1,57 @@
+@block @block_myoverview @javascript
+Feature: The my overview block allows users to persistence of their page limits
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | idnumber |
+      | student1 | Student   | X        | student1@example.com | S1       |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1        | 0        |
+      | Course 2 | C2        | 0        |
+      | Course 3 | C3        | 0        |
+      | Course 4 | C4        | 0        |
+      | Course 5 | C5        | 0        |
+      | Course 6 | C6        | 0        |
+      | Course 7 | C7        | 0        |
+      | Course 8 | C8        | 0        |
+      | Course 9 | C9        | 0        |
+      | Course 10 | C10        | 0        |
+      | Course 11 | C11        | 0        |
+      | Course 12 | C12        | 0        |
+      | Course 13 | C13        | 0        |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | student1 | C1 | student |
+      | student1 | C2 | student |
+      | student1 | C3 | student |
+      | student1 | C4 | student |
+      | student1 | C5 | student |
+      | student1 | C6 | student |
+      | student1 | C7 | student |
+      | student1 | C8 | student |
+      | student1 | C9 | student |
+      | student1 | C10 | student |
+      | student1 | C11 | student |
+      | student1 | C12 | student |
+      | student1 | C13 | student |
+
+  Scenario: Toggle the page limit between page reloads
+    Given I log in as "student1"
+    When I click on "Show 12 items per page" "button" in the "Course overview" "block"
+    And I click on "24" "link"
+    Then I should see "Course 9"
+    And I reload the page
+    Then I should see "Course 9"
+    And I should see "24" in the "[data-action='limit-toggle']" "css_element"
+    And I log out
+
+  Scenario: Toggle the page limit between grouping changes
+    Given I log in as "student1"
+    When I click on "Show 12 items per page" "button" in the "Course overview" "block"
+    And I click on "24" "link"
+    And I click on "All" "button" in the "Course overview" "block"
+    And I click on "In progress" "link" in the "Course overview" "block"
+    Then I should see "Course 9"
+    And I should see "24" in the "[data-action='limit-toggle']" "css_element"
+    And I log out
index 2ccd331..5b5b488 100644 (file)
@@ -50,14 +50,17 @@ class block_myoverview_privacy_testcase extends \core_privacy\tests\provider_tes
      *
      * @dataProvider user_preference_provider
      */
-    public function test_export_user_preferences($type, $value) {
+    public function test_export_user_preferences($type, $value, $expected) {
         $this->resetAfterTest();
         $user = $this->getDataGenerator()->create_user();
         set_user_preference($type, $value, $user);
         provider::export_user_preferences($user->id);
         $writer = writer::with_context(\context_system::instance());
         $blockpreferences = $writer->get_user_preferences('block_myoverview');
-        $this->assertEquals(get_string($value, 'block_myoverview'), $blockpreferences->{$type}->value);
+        if (!$expected) {
+            $expected = get_string($value, 'block_myoverview');
+        }
+        $this->assertEquals($expected, $blockpreferences->{$type}->value);
     }
 
     /**
@@ -67,15 +70,16 @@ class block_myoverview_privacy_testcase extends \core_privacy\tests\provider_tes
      */
     public function user_preference_provider() {
         return array(
-            array('block_myoverview_user_sort_preference', 'lastaccessed'),
-            array('block_myoverview_user_sort_preference', 'title'),
-            array('block_myoverview_user_grouping_preference', 'all'),
-            array('block_myoverview_user_grouping_preference', 'inprogress'),
-            array('block_myoverview_user_grouping_preference', 'future'),
-            array('block_myoverview_user_grouping_preference', 'past'),
-            array('block_myoverview_user_view_preference', 'card'),
-            array('block_myoverview_user_view_preference', 'list'),
-            array('block_myoverview_user_view_preference', 'summary')
+            array('block_myoverview_user_sort_preference', 'lastaccessed', ''),
+            array('block_myoverview_user_sort_preference', 'title', ''),
+            array('block_myoverview_user_grouping_preference', 'all', ''),
+            array('block_myoverview_user_grouping_preference', 'inprogress', ''),
+            array('block_myoverview_user_grouping_preference', 'future', ''),
+            array('block_myoverview_user_grouping_preference', 'past', ''),
+            array('block_myoverview_user_view_preference', 'card', ''),
+            array('block_myoverview_user_view_preference', 'list', ''),
+            array('block_myoverview_user_view_preference', 'summary', ''),
+            array('block_myoverview_user_paging_preference', 12, 12)
         );
     }
 
index 860f755..626b4e3 100644 (file)
Binary files a/lib/amd/build/paged_content.min.js and b/lib/amd/build/paged_content.min.js differ
index a7caeac..938b442 100644 (file)
Binary files a/lib/amd/build/paged_content_factory.min.js and b/lib/amd/build/paged_content_factory.min.js differ
index 9067ca5..282be2c 100644 (file)
@@ -44,8 +44,10 @@ function(
      * @param {function} renderPagesContentCallback (optional) A callback function to render a
      *                                              content page. See core/paged_content_pages for
      *                                              more defails.
+     * @param {string} namespaceOverride (optional) Provide a unique namespace override. If none provided defaults
+     *                                      to generate html's id
      */
-    var init = function(root, renderPagesContentCallback) {
+    var init = function(root, renderPagesContentCallback, namespaceOverride) {
         root = $(root);
         var pagesContainer = root.find(Pages.rootSelector);
         var pagingBarContainer = root.find(PagingBar.rootSelector);
@@ -53,6 +55,11 @@ function(
         var pagingBarLimitSelectorContainer = root.find(PagingBarLimitSelector.rootSelector);
         var id = root.attr('id');
 
+        // Set the id to the custom namespace provided
+        if (namespaceOverride) {
+            id = namespaceOverride;
+        }
+
         Pages.init(pagesContainer, id, renderPagesContentCallback);
 
         if (pagingBarContainer.length) {
index c8eb0a6..82671cf 100644 (file)
@@ -27,7 +27,8 @@ define(
     'core/notification',
     'core/paged_content',
     'core/paged_content_events',
-    'core/pubsub'
+    'core/pubsub',
+    'core/ajax'
 ],
 function(
     $,
@@ -35,7 +36,8 @@ function(
     Notification,
     PagedContent,
     PagedContentEvents,
-    PubSub
+    PubSub,
+    Ajax
 ) {
     var TEMPLATES = {
         PAGED_CONTENT: 'core/paged_content'
@@ -425,10 +427,18 @@ function(
         Templates.render(TEMPLATES.PAGED_CONTENT, templateContext)
             .then(function(html, js) {
                 html = $(html);
+                var id = html.attr('id');
+
+                // Set the id to the custom namespace provided
+                if (config.hasOwnProperty('eventNamespace')) {
+                    id = config.eventNamespace;
+                }
 
                 var container = html;
 
-                PagedContent.init(container, renderPagesContentCallback);
+                PagedContent.init(container, renderPagesContentCallback, id);
+
+                registerEvents(id, config);
 
                 deferred.resolve(html, js);
                 return;
@@ -494,6 +504,47 @@ function(
         PubSub.publish(id + PagedContentEvents.ALL_ITEMS_LOADED, lastPageNumber);
     };
 
+    /**
+     * Generate the callback handler for the page limit persistence functionality
+     *
+     * @param {String} persistentLimitKey
+     * @return {callback}
+     */
+    var generateLimitHandler = function(persistentLimitKey) {
+        var callback = function(limit) {
+            var args = {
+                preferences: [
+                    {
+                        type: persistentLimitKey,
+                        value: limit
+                    }
+                ]
+            };
+
+            var request = {
+                methodname: 'core_user_update_user_preferences',
+                args: args
+            };
+
+            Ajax.call([request]);
+        };
+
+        return callback;
+    };
+
+    /**
+     * Set up any events based on config key values
+     *
+     * @param {string} namespace The namespace for this component
+     * @param {object} config Config options passed to the factory
+     */
+    var registerEvents = function(namespace, config) {
+        if (config.hasOwnProperty('persistentLimitKey')) {
+            PubSub.subscribe(namespace + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT,
+                generateLimitHandler(config.persistentLimitKey));
+        }
+    };
+
     return {
         create: create,
         createWithLimit: createWithLimit,