| 1 | efrain | 1 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 2 | //
 | 
        
           |  |  | 3 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 4 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 5 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 6 | // (at your option) any later version.
 | 
        
           |  |  | 7 | //
 | 
        
           |  |  | 8 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 11 | // GNU General Public License for more details.
 | 
        
           |  |  | 12 | //
 | 
        
           |  |  | 13 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 14 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 15 |   | 
        
           |  |  | 16 | /**
 | 
        
           |  |  | 17 |  * Controls the notification popover in the nav bar.
 | 
        
           |  |  | 18 |  *
 | 
        
           |  |  | 19 |  * See template: message_popup/notification_popover
 | 
        
           |  |  | 20 |  *
 | 
        
           |  |  | 21 |  * @module     message_popup/notification_popover_controller
 | 
        
           |  |  | 22 |  * @class      notification_popover_controller
 | 
        
           |  |  | 23 |  * @copyright  2016 Ryan Wyllie <ryan@moodle.com>
 | 
        
           |  |  | 24 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 25 |  */
 | 
        
           |  |  | 26 | define(['jquery', 'core/ajax', 'core/templates', 'core/str', 'core/url',
 | 
        
           |  |  | 27 |             'core/notification', 'core/custom_interaction_events', 'core/popover_region_controller',
 | 
        
           |  |  | 28 |             'message_popup/notification_repository', 'message_popup/notification_area_events'],
 | 
        
           |  |  | 29 |         function($, Ajax, Templates, Str, URL, DebugNotification, CustomEvents,
 | 
        
           |  |  | 30 |             PopoverController, NotificationRepo, NotificationAreaEvents) {
 | 
        
           |  |  | 31 |   | 
        
           |  |  | 32 |     var SELECTORS = {
 | 
        
           |  |  | 33 |         MARK_ALL_READ_BUTTON: '[data-action="mark-all-read"]',
 | 
        
           |  |  | 34 |         ALL_NOTIFICATIONS_CONTAINER: '[data-region="all-notifications"]',
 | 
        
           |  |  | 35 |         NOTIFICATION: '[data-region="notification-content-item-container"]',
 | 
        
           |  |  | 36 |         UNREAD_NOTIFICATION: '[data-region="notification-content-item-container"].unread',
 | 
        
           |  |  | 37 |         NOTIFICATION_LINK: '[data-action="content-item-link"]',
 | 
        
           |  |  | 38 |         EMPTY_MESSAGE: '[data-region="empty-message"]',
 | 
        
           |  |  | 39 |         COUNT_CONTAINER: '[data-region="count-container"]',
 | 
        
           |  |  | 40 |     };
 | 
        
           |  |  | 41 |   | 
        
           |  |  | 42 |     /**
 | 
        
           |  |  | 43 |      * Constructor for the NotificationPopoverController.
 | 
        
           |  |  | 44 |      * Extends PopoverRegionController.
 | 
        
           |  |  | 45 |      *
 | 
        
           |  |  | 46 |      * @param {object} element jQuery object root element of the popover
 | 
        
           |  |  | 47 |      */
 | 
        
           |  |  | 48 |     var NotificationPopoverController = function(element) {
 | 
        
           |  |  | 49 |         // Initialise base class.
 | 
        
           |  |  | 50 |         PopoverController.call(this, element);
 | 
        
           |  |  | 51 |   | 
        
           |  |  | 52 |         this.markAllReadButton = this.root.find(SELECTORS.MARK_ALL_READ_BUTTON);
 | 
        
           |  |  | 53 |         this.unreadCount = 0;
 | 
        
           |  |  | 54 |         this.lastQueried = 0;
 | 
        
           |  |  | 55 |         this.userId = this.root.attr('data-userid');
 | 
        
           |  |  | 56 |         this.container = this.root.find(SELECTORS.ALL_NOTIFICATIONS_CONTAINER);
 | 
        
           |  |  | 57 |         this.limit = 20;
 | 
        
           |  |  | 58 |         this.offset = 0;
 | 
        
           |  |  | 59 |         this.loadedAll = false;
 | 
        
           |  |  | 60 |         this.initialLoad = false;
 | 
        
           |  |  | 61 |   | 
        
           |  |  | 62 |         // Let's find out how many unread notifications there are.
 | 
        
           |  |  | 63 |         this.unreadCount = this.root.find(SELECTORS.COUNT_CONTAINER).html();
 | 
        
           |  |  | 64 |     };
 | 
        
           |  |  | 65 |   | 
        
           |  |  | 66 |     /**
 | 
        
           |  |  | 67 |      * Clone the parent prototype.
 | 
        
           |  |  | 68 |      */
 | 
        
           |  |  | 69 |     NotificationPopoverController.prototype = Object.create(PopoverController.prototype);
 | 
        
           |  |  | 70 |   | 
        
           |  |  | 71 |     /**
 | 
        
           |  |  | 72 |      * Make sure the constructor is set correctly.
 | 
        
           |  |  | 73 |      */
 | 
        
           |  |  | 74 |     NotificationPopoverController.prototype.constructor = NotificationPopoverController;
 | 
        
           |  |  | 75 |   | 
        
           |  |  | 76 |     /**
 | 
        
           |  |  | 77 |      * Set the correct aria label on the menu toggle button to be read out by screen
 | 
        
           |  |  | 78 |      * readers. The message will indicate the state of the unread notifications.
 | 
        
           |  |  | 79 |      *
 | 
        
           |  |  | 80 |      * @method updateButtonAriaLabel
 | 
        
           |  |  | 81 |      */
 | 
        
           |  |  | 82 |     NotificationPopoverController.prototype.updateButtonAriaLabel = function() {
 | 
        
           |  |  | 83 |         if (this.isMenuOpen()) {
 | 
        
           |  |  | 84 |             Str.get_string('hidenotificationwindow', 'message').done(function(string) {
 | 
        
           |  |  | 85 |                 this.menuToggle.attr('aria-label', string);
 | 
        
           |  |  | 86 |             }.bind(this));
 | 
        
           |  |  | 87 |         } else {
 | 
        
           |  |  | 88 |             if (this.unreadCount) {
 | 
        
           |  |  | 89 |                 Str.get_string('shownotificationwindowwithcount', 'message', this.unreadCount).done(function(string) {
 | 
        
           |  |  | 90 |                     this.menuToggle.attr('aria-label', string);
 | 
        
           |  |  | 91 |                 }.bind(this));
 | 
        
           |  |  | 92 |             } else {
 | 
        
           |  |  | 93 |                 Str.get_string('shownotificationwindownonew', 'message').done(function(string) {
 | 
        
           |  |  | 94 |                     this.menuToggle.attr('aria-label', string);
 | 
        
           |  |  | 95 |                 }.bind(this));
 | 
        
           |  |  | 96 |             }
 | 
        
           |  |  | 97 |         }
 | 
        
           |  |  | 98 |     };
 | 
        
           |  |  | 99 |   | 
        
           |  |  | 100 |     /**
 | 
        
           |  |  | 101 |      * Return the jQuery element with the content. This will return either
 | 
        
           |  |  | 102 |      * the unread notification container or the all notification container
 | 
        
           |  |  | 103 |      * depending on which is currently visible.
 | 
        
           |  |  | 104 |      *
 | 
        
           |  |  | 105 |      * @method getContent
 | 
        
           |  |  | 106 |      * @return {object} jQuery object currently visible content contianer
 | 
        
           |  |  | 107 |      */
 | 
        
           |  |  | 108 |     NotificationPopoverController.prototype.getContent = function() {
 | 
        
           |  |  | 109 |         return this.container;
 | 
        
           |  |  | 110 |     };
 | 
        
           |  |  | 111 |   | 
        
           |  |  | 112 |     /**
 | 
        
           |  |  | 113 |      * Get the offset value for the current state of the popover in order
 | 
        
           |  |  | 114 |      * to sent to the backend to correctly paginate the notifications.
 | 
        
           |  |  | 115 |      *
 | 
        
           |  |  | 116 |      * @method getOffset
 | 
        
           |  |  | 117 |      * @return {int} current offset
 | 
        
           |  |  | 118 |      */
 | 
        
           |  |  | 119 |     NotificationPopoverController.prototype.getOffset = function() {
 | 
        
           |  |  | 120 |         return this.offset;
 | 
        
           |  |  | 121 |     };
 | 
        
           |  |  | 122 |   | 
        
           |  |  | 123 |     /**
 | 
        
           |  |  | 124 |      * Increment the offset for the current state, if required.
 | 
        
           |  |  | 125 |      *
 | 
        
           |  |  | 126 |      * @method incrementOffset
 | 
        
           |  |  | 127 |      */
 | 
        
           |  |  | 128 |     NotificationPopoverController.prototype.incrementOffset = function() {
 | 
        
           |  |  | 129 |         this.offset += this.limit;
 | 
        
           |  |  | 130 |     };
 | 
        
           |  |  | 131 |   | 
        
           |  |  | 132 |     /**
 | 
        
           |  |  | 133 |      * Check if the first load of notification has been triggered for the current
 | 
        
           |  |  | 134 |      * state of the popover.
 | 
        
           |  |  | 135 |      *
 | 
        
           |  |  | 136 |      * @method hasDoneInitialLoad
 | 
        
           |  |  | 137 |      * @return {bool} true if first notification loaded, false otherwise
 | 
        
           |  |  | 138 |      */
 | 
        
           |  |  | 139 |     NotificationPopoverController.prototype.hasDoneInitialLoad = function() {
 | 
        
           |  |  | 140 |         return this.initialLoad;
 | 
        
           |  |  | 141 |     };
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 |     /**
 | 
        
           |  |  | 144 |      * Check if we've loaded all of the notifications for the current popover
 | 
        
           |  |  | 145 |      * state.
 | 
        
           |  |  | 146 |      *
 | 
        
           |  |  | 147 |      * @method hasLoadedAllContent
 | 
        
           |  |  | 148 |      * @return {bool} true if all notifications loaded, false otherwise
 | 
        
           |  |  | 149 |      */
 | 
        
           |  |  | 150 |     NotificationPopoverController.prototype.hasLoadedAllContent = function() {
 | 
        
           |  |  | 151 |         return this.loadedAll;
 | 
        
           |  |  | 152 |     };
 | 
        
           |  |  | 153 |   | 
        
           |  |  | 154 |     /**
 | 
        
           |  |  | 155 |      * Set the state of the loaded all content property for the current state
 | 
        
           |  |  | 156 |      * of the popover.
 | 
        
           |  |  | 157 |      *
 | 
        
           |  |  | 158 |      * @method setLoadedAllContent
 | 
        
           |  |  | 159 |      * @param {bool} val True if all content is loaded, false otherwise
 | 
        
           |  |  | 160 |      */
 | 
        
           |  |  | 161 |     NotificationPopoverController.prototype.setLoadedAllContent = function(val) {
 | 
        
           |  |  | 162 |         this.loadedAll = val;
 | 
        
           |  |  | 163 |     };
 | 
        
           |  |  | 164 |   | 
        
           |  |  | 165 |     /**
 | 
        
           |  |  | 166 |      * Show the unread notification count badge on the menu toggle if there
 | 
        
           |  |  | 167 |      * are unread notifications, otherwise hide it.
 | 
        
           |  |  | 168 |      *
 | 
        
           |  |  | 169 |      * @method renderUnreadCount
 | 
        
           |  |  | 170 |      */
 | 
        
           |  |  | 171 |     NotificationPopoverController.prototype.renderUnreadCount = function() {
 | 
        
           |  |  | 172 |         var element = this.root.find(SELECTORS.COUNT_CONTAINER);
 | 
        
           |  |  | 173 |   | 
        
           |  |  | 174 |         if (this.unreadCount) {
 | 
        
           |  |  | 175 |             element.text(this.unreadCount);
 | 
        
           |  |  | 176 |             element.removeClass('hidden');
 | 
        
           |  |  | 177 |         } else {
 | 
        
           |  |  | 178 |             element.addClass('hidden');
 | 
        
           |  |  | 179 |         }
 | 
        
           |  |  | 180 |     };
 | 
        
           |  |  | 181 |   | 
        
           |  |  | 182 |     /**
 | 
        
           |  |  | 183 |      * Hide the unread notification count badge on the menu toggle.
 | 
        
           |  |  | 184 |      *
 | 
        
           |  |  | 185 |      * @method hideUnreadCount
 | 
        
           |  |  | 186 |      */
 | 
        
           |  |  | 187 |     NotificationPopoverController.prototype.hideUnreadCount = function() {
 | 
        
           |  |  | 188 |         this.root.find(SELECTORS.COUNT_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 189 |     };
 | 
        
           |  |  | 190 |   | 
        
           |  |  | 191 |     /**
 | 
        
           |  |  | 192 |      * Find the notification element for the given id.
 | 
        
           |  |  | 193 |      *
 | 
        
           |  |  | 194 |      * @param {int} id
 | 
        
           |  |  | 195 |      * @method getNotificationElement
 | 
        
           |  |  | 196 |      * @return {object|null} The notification element
 | 
        
           |  |  | 197 |      */
 | 
        
           |  |  | 198 |     NotificationPopoverController.prototype.getNotificationElement = function(id) {
 | 
        
           |  |  | 199 |         var element = this.root.find(SELECTORS.NOTIFICATION + '[data-id="' + id + '"]');
 | 
        
           |  |  | 200 |         return element.length == 1 ? element : null;
 | 
        
           |  |  | 201 |     };
 | 
        
           |  |  | 202 |   | 
        
           |  |  | 203 |     /**
 | 
        
           |  |  | 204 |      * Render the notification data with the appropriate template and add it to the DOM.
 | 
        
           |  |  | 205 |      *
 | 
        
           |  |  | 206 |      * @method renderNotifications
 | 
        
           |  |  | 207 |      * @param {array} notifications Notification data
 | 
        
           |  |  | 208 |      * @param {object} container jQuery object the container to append the rendered notifications
 | 
        
           |  |  | 209 |      * @return {object} jQuery promise that is resolved when all notifications have been
 | 
        
           |  |  | 210 |      *                  rendered and added to the DOM
 | 
        
           |  |  | 211 |      */
 | 
        
           |  |  | 212 |     NotificationPopoverController.prototype.renderNotifications = function(notifications, container) {
 | 
        
           |  |  | 213 |         var promises = [];
 | 
        
           |  |  | 214 |   | 
        
           |  |  | 215 |         $.each(notifications, function(index, notification) {
 | 
        
           |  |  | 216 |             // Determine what the offset was when loading this notification.
 | 
        
           |  |  | 217 |             var offset = this.getOffset() - this.limit;
 | 
        
           |  |  | 218 |             // Update the view more url to contain the offset to allow the notifications
 | 
        
           |  |  | 219 |             // page to load to the correct position in the list of notifications.
 | 
        
           |  |  | 220 |             notification.viewmoreurl = URL.relativeUrl('/message/output/popup/notifications.php', {
 | 
        
           |  |  | 221 |                 notificationid: notification.id,
 | 
        
           |  |  | 222 |                 offset: offset,
 | 
        
           |  |  | 223 |             });
 | 
        
           |  |  | 224 |   | 
        
           |  |  | 225 |             // Link to mark read page before loading the actual link.
 | 
        
           |  |  | 226 |             var notificationurlparams = {
 | 
        
           |  |  | 227 |                 notificationid: notification.id
 | 
        
           |  |  | 228 |             };
 | 
        
           |  |  | 229 |   | 
        
           |  |  | 230 |             notification.contexturl = URL.relativeUrl('message/output/popup/mark_notification_read.php', notificationurlparams);
 | 
        
           |  |  | 231 |   | 
        
           |  |  | 232 |             var promise = Templates.render('message_popup/notification_content_item', notification)
 | 
        
           |  |  | 233 |             .then(function(html, js) {
 | 
        
           |  |  | 234 |                 return {html: html, js: js};
 | 
        
           |  |  | 235 |             });
 | 
        
           |  |  | 236 |             promises.push(promise);
 | 
        
           |  |  | 237 |         }.bind(this));
 | 
        
           |  |  | 238 |   | 
        
           |  |  | 239 |         return $.when.apply($, promises).then(function() {
 | 
        
           |  |  | 240 |             // Each of the promises in the when will pass its results as an argument to the function.
 | 
        
           |  |  | 241 |             // The order of the arguments will be the order that the promises are passed to when()
 | 
        
           |  |  | 242 |             // i.e. the first promise's results will be in the first argument.
 | 
        
           |  |  | 243 |             $.each(arguments, function(index, argument) {
 | 
        
           |  |  | 244 |                 container.append(argument.html);
 | 
        
           |  |  | 245 |                 Templates.runTemplateJS(argument.js);
 | 
        
           |  |  | 246 |             });
 | 
        
           |  |  | 247 |             return;
 | 
        
           |  |  | 248 |         });
 | 
        
           |  |  | 249 |     };
 | 
        
           |  |  | 250 |   | 
        
           |  |  | 251 |     /**
 | 
        
           |  |  | 252 |      * Send a request for more notifications from the server, if we aren't already
 | 
        
           |  |  | 253 |      * loading some and haven't already loaded all of them.
 | 
        
           |  |  | 254 |      *
 | 
        
           |  |  | 255 |      * Takes into account the current mode of the popover and will request only
 | 
        
           |  |  | 256 |      * unread notifications if required.
 | 
        
           |  |  | 257 |      *
 | 
        
           |  |  | 258 |      * All notifications are marked as read by the server when they are returned.
 | 
        
           |  |  | 259 |      *
 | 
        
           |  |  | 260 |      * @method loadMoreNotifications
 | 
        
           |  |  | 261 |      * @return {object} jQuery promise that is resolved when notifications have been
 | 
        
           |  |  | 262 |      *                        retrieved and added to the DOM
 | 
        
           |  |  | 263 |      */
 | 
        
           |  |  | 264 |     NotificationPopoverController.prototype.loadMoreNotifications = function() {
 | 
        
           |  |  | 265 |         if (this.isLoading || this.hasLoadedAllContent()) {
 | 
        
           |  |  | 266 |             return $.Deferred().resolve();
 | 
        
           |  |  | 267 |         }
 | 
        
           |  |  | 268 |   | 
        
           |  |  | 269 |         this.startLoading();
 | 
        
           |  |  | 270 |         var request = {
 | 
        
           |  |  | 271 |             limit: this.limit,
 | 
        
           |  |  | 272 |             offset: this.getOffset(),
 | 
        
           |  |  | 273 |             useridto: this.userId,
 | 
        
           |  |  | 274 |         };
 | 
        
           |  |  | 275 |   | 
        
           |  |  | 276 |         var container = this.getContent();
 | 
        
           |  |  | 277 |         return NotificationRepo.query(request).then(function(result) {
 | 
        
           |  |  | 278 |             var notifications = result.notifications;
 | 
        
           |  |  | 279 |             this.unreadCount = result.unreadcount;
 | 
        
           |  |  | 280 |             this.lastQueried = Math.floor(new Date().getTime() / 1000);
 | 
        
           |  |  | 281 |             this.setLoadedAllContent(!notifications.length || notifications.length < this.limit);
 | 
        
           |  |  | 282 |             this.initialLoad = true;
 | 
        
           |  |  | 283 |             this.updateButtonAriaLabel();
 | 
        
           |  |  | 284 |   | 
        
           |  |  | 285 |             if (notifications.length) {
 | 
        
           |  |  | 286 |                 this.incrementOffset();
 | 
        
           |  |  | 287 |                 return this.renderNotifications(notifications, container);
 | 
        
           |  |  | 288 |             }
 | 
        
           |  |  | 289 |   | 
        
           |  |  | 290 |             return false;
 | 
        
           |  |  | 291 |         }.bind(this))
 | 
        
           |  |  | 292 |         .always(function() {
 | 
        
           |  |  | 293 |             this.stopLoading();
 | 
        
           |  |  | 294 |         }.bind(this));
 | 
        
           |  |  | 295 |     };
 | 
        
           |  |  | 296 |   | 
        
           |  |  | 297 |     /**
 | 
        
           |  |  | 298 |      * Send a request to the server to mark all unread notifications as read and update
 | 
        
           |  |  | 299 |      * the unread count and unread notification elements appropriately.
 | 
        
           |  |  | 300 |      *
 | 
        
           |  |  | 301 |      * @return {Promise}
 | 
        
           |  |  | 302 |      * @method markAllAsRead
 | 
        
           |  |  | 303 |      */
 | 
        
           |  |  | 304 |     NotificationPopoverController.prototype.markAllAsRead = function() {
 | 
        
           |  |  | 305 |         this.markAllReadButton.addClass('loading');
 | 
        
           |  |  | 306 |   | 
        
           |  |  | 307 |         var request = {
 | 
        
           |  |  | 308 |             useridto: this.userId,
 | 
        
           |  |  | 309 |             timecreatedto: this.lastQueried,
 | 
        
           |  |  | 310 |         };
 | 
        
           |  |  | 311 |   | 
        
           |  |  | 312 |         return NotificationRepo.markAllAsRead(request)
 | 
        
           |  |  | 313 |             .then(function() {
 | 
        
           |  |  | 314 |                 this.unreadCount = 0;
 | 
        
           |  |  | 315 |                 this.root.find(SELECTORS.UNREAD_NOTIFICATION).removeClass('unread');
 | 
        
           |  |  | 316 |             }.bind(this))
 | 
        
           |  |  | 317 |             .always(function() {
 | 
        
           |  |  | 318 |                 this.markAllReadButton.removeClass('loading');
 | 
        
           |  |  | 319 |             }.bind(this));
 | 
        
           |  |  | 320 |     };
 | 
        
           |  |  | 321 |   | 
        
           |  |  | 322 |     /**
 | 
        
           |  |  | 323 |      * Add all of the required event listeners for this notification popover.
 | 
        
           |  |  | 324 |      *
 | 
        
           |  |  | 325 |      * @method registerEventListeners
 | 
        
           |  |  | 326 |      */
 | 
        
           |  |  | 327 |     NotificationPopoverController.prototype.registerEventListeners = function() {
 | 
        
           |  |  | 328 |         CustomEvents.define(this.root, [
 | 
        
           |  |  | 329 |             CustomEvents.events.activate,
 | 
        
           |  |  | 330 |         ]);
 | 
        
           |  |  | 331 |   | 
        
           |  |  | 332 |         // Mark all notifications read if the user activates the mark all as read button.
 | 
        
           |  |  | 333 |         this.root.on(CustomEvents.events.activate, SELECTORS.MARK_ALL_READ_BUTTON, function(e, data) {
 | 
        
           |  |  | 334 |             this.markAllAsRead();
 | 
        
           |  |  | 335 |             e.stopPropagation();
 | 
        
           |  |  | 336 |             data.originalEvent.preventDefault();
 | 
        
           |  |  | 337 |         }.bind(this));
 | 
        
           |  |  | 338 |   | 
        
           |  |  | 339 |         // Mark individual notification read if the user activates it.
 | 
        
           |  |  | 340 |         this.root.on(CustomEvents.events.activate, SELECTORS.NOTIFICATION_LINK, function(e) {
 | 
        
           |  |  | 341 |             var element = $(e.target).closest(SELECTORS.NOTIFICATION);
 | 
        
           |  |  | 342 |   | 
        
           |  |  | 343 |             if (element.hasClass('unread')) {
 | 
        
           |  |  | 344 |                 this.unreadCount--;
 | 
        
           |  |  | 345 |                 element.removeClass('unread');
 | 
        
           |  |  | 346 |             }
 | 
        
           |  |  | 347 |   | 
        
           |  |  | 348 |             e.stopPropagation();
 | 
        
           |  |  | 349 |         }.bind(this));
 | 
        
           |  |  | 350 |   | 
        
           |  |  | 351 |         // Update the notification information when the menu is opened.
 | 
        
           |  |  | 352 |         this.root.on(this.events().menuOpened, function() {
 | 
        
           |  |  | 353 |             this.hideUnreadCount();
 | 
        
           |  |  | 354 |             this.updateButtonAriaLabel();
 | 
        
           |  |  | 355 |   | 
        
           |  |  | 356 |             if (!this.hasDoneInitialLoad()) {
 | 
        
           |  |  | 357 |                 this.loadMoreNotifications();
 | 
        
           |  |  | 358 |             }
 | 
        
           |  |  | 359 |         }.bind(this));
 | 
        
           |  |  | 360 |   | 
        
           |  |  | 361 |         // Update the unread notification count when the menu is closed.
 | 
        
           |  |  | 362 |         this.root.on(this.events().menuClosed, function() {
 | 
        
           |  |  | 363 |             this.renderUnreadCount();
 | 
        
           |  |  | 364 |             this.updateButtonAriaLabel();
 | 
        
           |  |  | 365 |         }.bind(this));
 | 
        
           |  |  | 366 |   | 
        
           |  |  | 367 |         // Set aria attributes when popover is loading.
 | 
        
           |  |  | 368 |         this.root.on(this.events().startLoading, function() {
 | 
        
           |  |  | 369 |             this.getContent().attr('aria-busy', 'true');
 | 
        
           |  |  | 370 |         }.bind(this));
 | 
        
           |  |  | 371 |   | 
        
           |  |  | 372 |         // Set aria attributes when popover is finished loading.
 | 
        
           |  |  | 373 |         this.root.on(this.events().stopLoading, function() {
 | 
        
           |  |  | 374 |             this.getContent().attr('aria-busy', 'false');
 | 
        
           |  |  | 375 |         }.bind(this));
 | 
        
           |  |  | 376 |   | 
        
           |  |  | 377 |         // Load more notifications if the user has scrolled to the end of content
 | 
        
           |  |  | 378 |         // item list.
 | 
        
           |  |  | 379 |         this.getContentContainer().on(CustomEvents.events.scrollBottom, function() {
 | 
        
           |  |  | 380 |             if (!this.isLoading && !this.hasLoadedAllContent()) {
 | 
        
           |  |  | 381 |                 this.loadMoreNotifications();
 | 
        
           |  |  | 382 |             }
 | 
        
           |  |  | 383 |         }.bind(this));
 | 
        
           |  |  | 384 |   | 
        
           |  |  | 385 |         // Stop mouse scroll from propagating to the window element and
 | 
        
           |  |  | 386 |         // scrolling the page.
 | 
        
           |  |  | 387 |         CustomEvents.define(this.getContentContainer(), [
 | 
        
           |  |  | 388 |             CustomEvents.events.scrollLock
 | 
        
           |  |  | 389 |         ]);
 | 
        
           |  |  | 390 |   | 
        
           |  |  | 391 |         // Listen for when a notification is shown in the notifications page and mark
 | 
        
           |  |  | 392 |         // it as read, if it's unread.
 | 
        
           |  |  | 393 |         $(document).on(NotificationAreaEvents.notificationShown, function(e, notification) {
 | 
        
           |  |  | 394 |             if (!notification.read) {
 | 
        
           |  |  | 395 |                 var element = this.getNotificationElement(notification.id);
 | 
        
           |  |  | 396 |   | 
        
           |  |  | 397 |                 if (element) {
 | 
        
           |  |  | 398 |                     element.removeClass('unread');
 | 
        
           |  |  | 399 |                 }
 | 
        
           |  |  | 400 |   | 
        
           |  |  | 401 |                 this.unreadCount--;
 | 
        
           |  |  | 402 |                 this.renderUnreadCount();
 | 
        
           |  |  | 403 |             }
 | 
        
           |  |  | 404 |         }.bind(this));
 | 
        
           |  |  | 405 |     };
 | 
        
           |  |  | 406 |   | 
        
           |  |  | 407 |     return NotificationPopoverController;
 | 
        
           |  |  | 408 | });
 |