MDL-63817 block_timeline: Persist page limits when sorting by dates
authorPeter <peter@moodle.com>
Fri, 2 Nov 2018 06:45:38 +0000 (14:45 +0800)
committerPeter <peter@moodle.com>
Mon, 19 Nov 2018 06:52:56 +0000 (14:52 +0800)
* Included privacy provider for new pref with unit test
* JS changes

12 files changed:
blocks/timeline/amd/build/event_list.min.js
blocks/timeline/amd/build/view_dates.min.js
blocks/timeline/amd/src/event_list.js
blocks/timeline/amd/src/view_dates.js
blocks/timeline/block_timeline.php
blocks/timeline/classes/output/main.php
blocks/timeline/classes/privacy/provider.php
blocks/timeline/lang/en/block_timeline.php
blocks/timeline/lib.php
blocks/timeline/templates/view.mustache
blocks/timeline/tests/behat/block_timeline_pagelimit_persistence.feature [new file with mode: 0644]
blocks/timeline/tests/privacy_test.php

index cd209c5..025c596 100644 (file)
Binary files a/blocks/timeline/amd/build/event_list.min.js and b/blocks/timeline/amd/build/event_list.min.js differ
index b29cb60..dc99182 100644 (file)
Binary files a/blocks/timeline/amd/build/view_dates.min.js and b/blocks/timeline/amd/build/view_dates.min.js differ
index dfd1517..b6d2a43 100644 (file)
@@ -300,6 +300,7 @@ function(
      * @param {Number} daysOffset How many days (from midnight) to offset the results from
      * @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to
      * @param {string} paginationAriaLabel String to set as the aria label for the pagination bar.
+     * @param {object} additionalConfig Additional config options to pass to pagedContentFactory
      * @return {object} jQuery promise.
      */
     var createPagedContent = function(
@@ -310,7 +311,8 @@ function(
         courseId,
         daysOffset,
         daysLimit,
-        paginationAriaLabel
+        paginationAriaLabel,
+        additionalConfig
     ) {
         // Remember the last event id we loaded on each page because we can't
         // use the offset value since the backend can skip events if the user doesn't
@@ -318,7 +320,7 @@ function(
         // based on the last seen event id.
         var lastIds = {'1': 0};
         var hasContent = false;
-        var config = $.extend({}, DEFAULT_PAGED_CONTENT_CONFIG);
+        var config = $.extend({}, DEFAULT_PAGED_CONTENT_CONFIG, additionalConfig);
 
         return Str.get_string(
                 'ariaeventlistpagelimit',
@@ -396,8 +398,9 @@ function(
      * @param {int|array} pageLimit A single limit or list of limits as options for the paged content
      * @param {object} preloadedPages An object of preloaded page data. Page number as key, data promise as value.
      * @param {string} paginationAriaLabel String to set as the aria label for the pagination bar.
+     * @param {object} additionalConfig Additional config options to pass to pagedContentFactory
      */
-    var init = function(root, pageLimit, preloadedPages, paginationAriaLabel) {
+    var init = function(root, pageLimit, preloadedPages, paginationAriaLabel, additionalConfig) {
         root = $(root);
 
         // Create a promise that will be resolved once the first set of page
@@ -425,7 +428,8 @@ function(
         }
 
         // Created the paged content element.
-        createPagedContent(pageLimit, preloadedPages, midnight, firstLoad, courseId, daysOffset, daysLimit, paginationAriaLabel)
+        return createPagedContent(pageLimit, preloadedPages, midnight, firstLoad, courseId, daysOffset, daysLimit,
+                paginationAriaLabel, additionalConfig)
             .then(function(html, js) {
                 html = $(html);
                 // Hide the content for now.
index b18d21a..f411c47 100644 (file)
@@ -25,18 +25,64 @@ define(
 [
     'jquery',
     'core/str',
-    'block_timeline/event_list'
+    'block_timeline/event_list',
+    'core/pubsub',
+    'core/paged_content_events'
 ],
 function(
     $,
     Str,
-    EventList
+    EventList,
+    PubSub,
+    PagedContentEvents
 ) {
 
     var SELECTORS = {
         EVENT_LIST_CONTAINER: '[data-region="event-list-container"]',
     };
 
+    var DEFAULT_PAGE_LIMIT = [5, 10, 25];
+
+    /**
+     * Generate a paged content array of limits taking into account user preferences
+     *
+     * @param {object} root The root element for the timeline dates view.
+     * @return {array} Array of limit objects
+     */
+    var getPagingLimits = function(root) {
+        var limitPref = parseInt(root.data('limit'), 10);
+        var isDefaultSet = false;
+        var limits = DEFAULT_PAGE_LIMIT.map(function(value) {
+            if (limitPref == value) {
+                isDefaultSet = true;
+            }
+
+            return {
+                value: value,
+                active: limitPref == value
+            };
+        });
+
+        if (!isDefaultSet) {
+            limits[0].active = true;
+        }
+
+        return limits;
+    };
+
+    /**
+     * Setup the listeners for the timeline block
+     *
+     * @param {string} root view dates container
+     * @param {string} namespace The namespace for the paged content
+     */
+    var registerEventListeners = function(root, namespace) {
+        var event = namespace + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT;
+        PubSub.subscribe(event, function(limit) {
+            $(root).data('limit', limit);
+        });
+    };
+
     /**
      * Initialise the event list and being loading the events.
      *
@@ -44,14 +90,22 @@ function(
      */
     var load = function(root) {
         var eventListContainer = root.find(SELECTORS.EVENT_LIST_CONTAINER);
+        var namespace = $(eventListContainer).attr('id') + "user_block_timeline" + Math.random();
+        registerEventListeners(root, namespace);
+
+        var limits = getPagingLimits(root);
+        var config = {
+            persistentLimitKey: "block_timeline_user_limit_preference",
+            eventNamespace: namespace
+        };
         Str.get_string('ariaeventlistpaginationnavdates', 'block_timeline')
             .then(function(string) {
-                EventList.init(eventListContainer, [5, 10, 25], {}, string);
+                EventList.init(eventListContainer, limits, {}, string, config);
                 return string;
             })
             .catch(function() {
                 // Ignore if we can't load the string. Still init the event list.
-                EventList.init(eventListContainer, [5, 10, 25]);
+                EventList.init(eventListContainer, limits, {}, "", config);
             });
     };
 
@@ -65,7 +119,7 @@ function(
         root = $(root);
         if (root.hasClass('active')) {
             load(root);
-            root.attr('data-seen', true);
+            root.data('seen', true);
         }
     };
 
@@ -79,7 +133,7 @@ function(
         root.removeAttr('data-seen');
         if (root.hasClass('active')) {
             load(root);
-            root.attr('data-seen', true);
+            root.data('seen', true);
         }
     };
 
@@ -89,9 +143,9 @@ function(
      * @param {object} root The root element for the timeline courses view.
      */
     var shown = function(root) {
-        if (!root.attr('data-seen')) {
+        if (!root.data('seen')) {
             load(root);
-            root.attr('data-seen', true);
+            root.data('seen', true);
         }
     };
 
index 03e7230..ad7aaa2 100644 (file)
@@ -52,8 +52,9 @@ class block_timeline extends block_base {
 
         $sort = get_user_preferences('block_timeline_user_sort_preference');
         $filter = get_user_preferences('block_timeline_user_filter_preference');
+        $limit = get_user_preferences('block_timeline_user_limit_preference');
 
-        $renderable = new \block_timeline\output\main($sort, $filter);
+        $renderable = new \block_timeline\output\main($sort, $filter, $limit);
         $renderer = $this->page->get_renderer('block_timeline');
 
         $this->content = (object) [
index 218eb46..bb741b4 100644 (file)
@@ -54,15 +54,22 @@ class main implements renderable, templatable {
      */
     public $order;
 
+    /**
+     * @var string The current limit preference
+     */
+    public $limit;
+
     /**
      * main constructor.
      *
      * @param string $order Constant sort value from ../timeline/lib.php
-     * @param string $filter Constant sort value from ../timeline/lib.php
+     * @param string $filter Constant filter value from ../timeline/lib.php
+     * @param string $limit Constant limit value from ../timeline/lib.php
      */
-    public function __construct($order, $filter) {
+    public function __construct($order, $filter, $limit) {
         $this->order = $order ? $order : BLOCK_TIMELINE_SORT_BY_DATES;
         $this->filter = $filter ? $filter : BLOCK_TIMELINE_FILTER_BY_7_DAYS;
+        $this->limit = $limit ? $limit : BLOCK_TIMELINE_LIMIT_DEFAULT;
     }
 
     /**
@@ -165,6 +172,7 @@ class main implements renderable, templatable {
             'hasdaysoffset' => true,
             'hasdayslimit' => $offsets['dayslimit'] !== false ,
             'nodayslimit' => $offsets['dayslimit'] === false ,
+            'limit' => $this->limit
         ];
         return array_merge($contextvariables, $filters, $offsets);
     }
index 3be0998..ed1df85 100644 (file)
@@ -44,6 +44,7 @@ class provider implements \core_privacy\local\metadata\provider, \core_privacy\l
     public static function get_metadata(collection $collection) : collection {
         $collection->add_user_preference('block_timeline_user_sort_preference', 'privacy:metadata:timelinesortpreference');
         $collection->add_user_preference('block_timeline_user_filter_preference', 'privacy:metadata:timelinefilterpreference');
+        $collection->add_user_preference('block_timeline_user_limit_preference', 'privacy:metadata:timelinelimitpreference');
         return $collection;
     }
 
@@ -68,5 +69,13 @@ class provider implements \core_privacy\local\metadata\provider, \core_privacy\l
                     get_string('privacy:metadata:timelinefilterpreference', 'block_timeline')
             );
         }
+
+        $preference = get_user_preferences('block_timeline_user_limit_preference', null, $userid);
+        if (isset($preference)) {
+            \core_privacy\local\request\writer::export_user_preference('block_timeline', 'block_timeline_user_limit_preference',
+                    $preference,
+                    get_string('privacy:metadata:timelinelimitpreference', 'block_timeline')
+            );
+        }
     }
 }
index 12dae0d..b45d3ff 100644 (file)
@@ -49,3 +49,4 @@ $string['timeline'] = 'Timeline';
 $string['viewcourse'] = 'View course';
 $string['privacy:metadata:timelinesortpreference'] = 'The user sort preference for the timeline block.';
 $string['privacy:metadata:timelinefilterpreference'] = 'The user day filter preference for the timeline block.';
+$string['privacy:metadata:timelinelimitpreference'] = 'The user page limit preference for the timeline block.';
index 26e8783..adf9083 100644 (file)
@@ -38,6 +38,7 @@ define('BLOCK_TIMELINE_FILTER_BY_7_DAYS', 'next7days');
 define('BLOCK_TIMELINE_FILTER_BY_30_DAYS', 'next30days');
 define('BLOCK_TIMELINE_FILTER_BY_3_MONTHS', 'next3months');
 define('BLOCK_TIMELINE_FILTER_BY_6_MONTHS', 'next6months');
+define('BLOCK_TIMELINE_LIMIT_DEFAULT', 2);
 
 /**
  * Returns the name of the user preferences as well as the details this plugin uses.
@@ -66,5 +67,11 @@ function block_timeline_user_preferences() {
         )
     );
 
+    $preferences['block_timeline_user_limit_preference'] = array(
+        'null' => NULL_NOT_ALLOWED,
+        'default' => BLOCK_TIMELINE_LIMIT_DEFAULT,
+        'type' => PARAM_INT
+    );
+
     return $preferences;
 }
index acb5f78..ce96132 100644 (file)
         "next3months": false,
         "next6months": false,
         "daysoffset": -14,
-        "dayslimit": false
+        "dayslimit": false,
+        "limit": 0
     }
 }}
 <div data-region="timeline-view">
     <div class="tab-content">
-        <div class="tab-pane {{#sorttimelinedates}}active show{{/sorttimelinedates}} fade" data-region="view-dates" id="view_dates_{{uniqid}}">
+        <div class="tab-pane {{#sorttimelinedates}}active show{{/sorttimelinedates}} fade" data-limit="{{limit}}" data-region="view-dates" id="view_dates_{{uniqid}}">
             {{> block_timeline/view-dates }}
         </div>
         <div
diff --git a/blocks/timeline/tests/behat/block_timeline_pagelimit_persistence.feature b/blocks/timeline/tests/behat/block_timeline_pagelimit_persistence.feature
new file mode 100644 (file)
index 0000000..76518f5
--- /dev/null
@@ -0,0 +1,63 @@
+@block @block_timeline @javascript
+Feature: The timeline block allows user persistence of their page limits
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | idnumber |
+      | student1 | Student   | 1        | student1@example.com | S1       |
+    And the following "courses" exist:
+      | fullname | shortname | category | startdate                   | enddate         |
+      | Course 1 | C1        | 0        | ##1 month ago##             | ##15 days ago## |
+      | Course 2 | C2        | 0        | ##yesterday##               | ##tomorrow## |
+      | Course 3 | C3        | 0        | ##first day of next month## | ##last day of next month## |
+      | Course 4 | C4        | 0        | ##first day of next month## | ##last day of next month## |
+      | Course 5 | C5        | 0        | ##first day of next month## | ##last day of next month## |
+      | Course 6 | C6        | 0        | ##first day of next month## | ##last day of next month## |
+    And the following "activities" exist:
+      | activity | course | idnumber  | name            | intro                   | timeopen      | timeclose     |
+      | choice   | C2     | choice1   | Test choice 1   | Test choice description | ##yesterday## | ##tomorrow##  |
+      | choice   | C1     | choice2   | Test choice 2   | Test choice description | ##1 month ago## | ##15 days ago##  |
+      | choice   | C3     | choice3   | Test choice 3   | Test choice description | ##first day of +5 months## | ##last day of +5 months##  |
+      | feedback | C2     | feedback1 | Test feedback 1 | Test feedback description | ##yesterday## | ##tomorrow##  |
+      | feedback | C1     | feedback2 | Test feedback 2 | Test feedback description | ##first day of +10 months## | ##last day of +10 months##  |
+      | feedback | C3     | feedback3 | Test feedback 3 | Test feedback description | ##first day of +5 months## | ##last day of +5 months## |
+    And the following "activities" exist:
+      | activity | course | idnumber  | name            | intro                   | timeopen      | duedate     |
+      | assign   | C1     | assign1   | Test assign 1   | Test assign description | ##1 month ago## | ##yesterday##  |
+    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 |
+
+  Scenario: Toggle the page limit 5 - 25
+    Given I log in as "student1"
+    And I click on "Next 30 days" "button" in the "Timeline" "block"
+    And I click on "All" "link" in the "Timeline" "block"
+    And I click on "Sort" "button" in the "Timeline" "block"
+    And I click on "Sort by dates" "link" in the "Timeline" "block"
+    When I click on "5" "button" in the "Timeline" "block"
+    And I click on "25" "link"
+    Then I should see "Test feedback 2" in the "Timeline" "block"
+    And I reload the page
+    Then I should see "Test feedback 2" in the "Timeline" "block"
+    And I log out
+
+  Scenario: Toggle the page limit 25 - 5
+    Given I log in as "student1"
+    And I click on "Next 30 days" "button" in the "Timeline" "block"
+    And I click on "All" "link" in the "Timeline" "block"
+    And I click on "Sort" "button" in the "Timeline" "block"
+    And I click on "Sort by dates" "link" in the "Timeline" "block"
+    When I click on "5" "button" in the "Timeline" "block"
+    And I click on "25" "link"
+    And I should see "Test feedback 2" in the "Timeline" "block"
+    And I click on "25" "button" in the "Timeline" "block"
+    And I click on "5" "link" in the ".dropdown-menu.show" "css_element"
+    Then I should not see "Test feedback 2" in the "Timeline" "block"
+    And I reload the page
+    And I should not see "Test feedback 2" in the "Timeline" "block"
+    And I log out
index 0aacf3e..787a346 100644 (file)
@@ -49,62 +49,39 @@ class block_timeline_privacy_testcase extends \core_privacy\tests\provider_testc
     }
 
     /**
-     * Test that the preference courses is exported properly.
+     * Test the export_user_preferences given different inputs
+     *
+     * @param string $type The name of the user preference to get/set
+     * @param string $value The value you are storing
+     * @param string $expected The expected value override
+     *
+     * @dataProvider user_preference_provider
      */
-    public function test_export_user_preferences_date_sort_preference() {
+    public function test_export_user_preferences($type, $value, $expected) {
         $this->resetAfterTest();
-
-        $user = $this->getDataGenerator()->create_user();
-        set_user_preference('block_timeline_user_sort_preference', 'sortbydates', $user);
-
-        provider::export_user_preferences($user->id);
-        $writer = writer::with_context(\context_system::instance());
-        $blockpreferences = $writer->get_user_preferences('block_timeline');
-        $this->assertEquals('Sort by dates', $blockpreferences->block_timeline_user_sort_preference->value);
-    }
-
-    /**
-     * Test that the preference timeline is exported properly.
-     */
-    public function test_export_user_preferences_course_sort_preference() {
-        $this->resetAfterTest();
-
         $user = $this->getDataGenerator()->create_user();
-        set_user_preference('block_timeline_user_sort_preference', 'sortbycourses', $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_timeline');
-        $this->assertEquals('Sort by courses', $blockpreferences->block_timeline_user_sort_preference->value);
+        if (!$expected) {
+            $expected = get_string($value, 'block_timeline');
+        }
+        $this->assertEquals($expected, $blockpreferences->{$type}->value);
     }
 
     /**
-     * Test that the preference timeline is exported properly.
+     * Create an array of valid user preferences for the timeline block.
+     *
+     * @return array Array of valid user preferences.
      */
-    public function test_export_user_preferences_7day_filter_preference() {
-        $this->resetAfterTest();
-
-        $user = $this->getDataGenerator()->create_user();
-        set_user_preference('block_timeline_user_filter_preference', 'next7days', $user);
-
-        provider::export_user_preferences($user->id);
-        $writer = writer::with_context(\context_system::instance());
-        $blockpreferences = $writer->get_user_preferences('block_timeline');
-        $this->assertEquals('Next 7 days', $blockpreferences->block_timeline_user_filter_preference->value);
-    }
-
-    /**
-     * Test that the preference timeline is exported properly.
-     */
-    public function test_export_user_preferences_all_filter_preference() {
-        $this->resetAfterTest();
-
-        $user = $this->getDataGenerator()->create_user();
-        set_user_preference('block_timeline_user_filter_preference', 'all', $user);
-
-        provider::export_user_preferences($user->id);
-        $writer = writer::with_context(\context_system::instance());
-        $blockpreferences = $writer->get_user_preferences('block_timeline');
-        $this->assertEquals('All', $blockpreferences->block_timeline_user_filter_preference->value);
+    public function user_preference_provider() {
+        return array(
+            array('block_timeline_user_sort_preference', 'sortbydates', ''),
+            array('block_timeline_user_sort_preference', 'sortbycourses', ''),
+            array('block_timeline_user_sort_preference', 'next7days', ''),
+            array('block_timeline_user_sort_preference', 'all', ''),
+            array('block_timeline_user_limit_preference', 5, 5),
+        );
     }
 }