Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

{"version":3,"file":"notification_popover_controller.min.js","sources":["../src/notification_popover_controller.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Controls the notification popover in the nav bar.\n *\n * See template: message_popup/notification_popover\n *\n * @module     message_popup/notification_popover_controller\n * @class      notification_popover_controller\n * @copyright  2016 Ryan Wyllie <ryan@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/ajax', 'core/templates', 'core/str', 'core/url',\n            'core/notification', 'core/custom_interaction_events', 'core/popover_region_controller',\n            'message_popup/notification_repository', 'message_popup/notification_area_events'],\n        function($, Ajax, Templates, Str, URL, DebugNotification, CustomEvents,\n            PopoverController, NotificationRepo, NotificationAreaEvents) {\n\n    var SELECTORS = {\n        MARK_ALL_READ_BUTTON: '[data-action=\"mark-all-read\"]',\n        ALL_NOTIFICATIONS_CONTAINER: '[data-region=\"all-notifications\"]',\n        NOTIFICATION: '[data-region=\"notification-content-item-container\"]',\n        UNREAD_NOTIFICATION: '[data-region=\"notification-content-item-container\"].unread',\n        NOTIFICATION_LINK: '[data-action=\"content-item-link\"]',\n        EMPTY_MESSAGE: '[data-region=\"empty-message\"]',\n        COUNT_CONTAINER: '[data-region=\"count-container\"]',\n    };\n\n    /**\n     * Constructor for the NotificationPopoverController.\n     * Extends PopoverRegionController.\n     *\n     * @param {object} element jQuery object root element of the popover\n     */\n    var NotificationPopoverController = function(element) {\n        // Initialise base class.\n        PopoverController.call(this, element);\n\n        this.markAllReadButton = this.root.find(SELECTORS.MARK_ALL_READ_BUTTON);\n        this.unreadCount = 0;\n        this.lastQueried = 0;\n        this.userId = this.root.attr('data-userid');\n        this.container = this.root.find(SELECTORS.ALL_NOTIFICATIONS_CONTAINER);\n        this.limit = 20;\n        this.offset = 0;\n        this.loadedAll = false;\n        this.initialLoad = false;\n\n        // Let's find out how many unread notifications there are.\n        this.unreadCount = this.root.find(SELECTORS.COUNT_CONTAINER).html();\n    };\n\n    /**\n     * Clone the parent prototype.\n     */\n    NotificationPopoverController.prototype = Object.create(PopoverController.prototype);\n\n    /**\n     * Make sure the constructor is set correctly.\n     */\n    NotificationPopoverController.prototype.constructor = NotificationPopoverController;\n\n    /**\n     * Set the correct aria label on the menu toggle button to be read out by screen\n     * readers. The message will indicate the state of the unread notifications.\n     *\n     * @method updateButtonAriaLabel\n     */\n    NotificationPopoverController.prototype.updateButtonAriaLabel = function() {\n        if (this.isMenuOpen()) {\n            Str.get_string('hidenotificationwindow', 'message').done(function(string) {\n                this.menuToggle.attr('aria-label', string);\n            }.bind(this));\n        } else {\n            if (this.unreadCount) {\n                Str.get_string('shownotificationwindowwithcount', 'message', this.unreadCount).done(function(string) {\n                    this.menuToggle.attr('aria-label', string);\n                }.bind(this));\n            } else {\n                Str.get_string('shownotificationwindownonew', 'message').done(function(string) {\n                    this.menuToggle.attr('aria-label', string);\n                }.bind(this));\n            }\n        }\n    };\n\n    /**\n     * Return the jQuery element with the content. This will return either\n     * the unread notification container or the all notification container\n     * depending on which is currently visible.\n     *\n     * @method getContent\n     * @return {object} jQuery object currently visible content contianer\n     */\n    NotificationPopoverController.prototype.getContent = function() {\n        return this.container;\n    };\n\n    /**\n     * Get the offset value for the current state of the popover in order\n     * to sent to the backend to correctly paginate the notifications.\n     *\n     * @method getOffset\n     * @return {int} current offset\n     */\n    NotificationPopoverController.prototype.getOffset = function() {\n        return this.offset;\n    };\n\n    /**\n     * Increment the offset for the current state, if required.\n     *\n     * @method incrementOffset\n     */\n    NotificationPopoverController.prototype.incrementOffset = function() {\n        this.offset += this.limit;\n    };\n\n    /**\n     * Check if the first load of notification has been triggered for the current\n     * state of the popover.\n     *\n     * @method hasDoneInitialLoad\n     * @return {bool} true if first notification loaded, false otherwise\n     */\n    NotificationPopoverController.prototype.hasDoneInitialLoad = function() {\n        return this.initialLoad;\n    };\n\n    /**\n     * Check if we've loaded all of the notifications for the current popover\n     * state.\n     *\n     * @method hasLoadedAllContent\n     * @return {bool} true if all notifications loaded, false otherwise\n     */\n    NotificationPopoverController.prototype.hasLoadedAllContent = function() {\n        return this.loadedAll;\n    };\n\n    /**\n     * Set the state of the loaded all content property for the current state\n     * of the popover.\n     *\n     * @method setLoadedAllContent\n     * @param {bool} val True if all content is loaded, false otherwise\n     */\n    NotificationPopoverController.prototype.setLoadedAllContent = function(val) {\n        this.loadedAll = val;\n    };\n\n    /**\n     * Show the unread notification count badge on the menu toggle if there\n     * are unread notifications, otherwise hide it.\n     *\n     * @method renderUnreadCount\n     */\n    NotificationPopoverController.prototype.renderUnreadCount = function() {\n        var element = this.root.find(SELECTORS.COUNT_CONTAINER);\n\n        if (this.unreadCount) {\n            element.text(this.unreadCount);\n            element.removeClass('hidden');\n        } else {\n            element.addClass('hidden');\n        }\n    };\n\n    /**\n     * Hide the unread notification count badge on the menu toggle.\n     *\n     * @method hideUnreadCount\n     */\n    NotificationPopoverController.prototype.hideUnreadCount = function() {\n        this.root.find(SELECTORS.COUNT_CONTAINER).addClass('hidden');\n    };\n\n    /**\n     * Find the notification element for the given id.\n     *\n     * @param {int} id\n     * @method getNotificationElement\n     * @return {object|null} The notification element\n     */\n    NotificationPopoverController.prototype.getNotificationElement = function(id) {\n        var element = this.root.find(SELECTORS.NOTIFICATION + '[data-id=\"' + id + '\"]');\n        return element.length == 1 ? element : null;\n    };\n\n    /**\n     * Render the notification data with the appropriate template and add it to the DOM.\n     *\n     * @method renderNotifications\n     * @param {array} notifications Notification data\n     * @param {object} container jQuery object the container to append the rendered notifications\n     * @return {object} jQuery promise that is resolved when all notifications have been\n     *                  rendered and added to the DOM\n     */\n    NotificationPopoverController.prototype.renderNotifications = function(notifications, container) {\n        var promises = [];\n\n        $.each(notifications, function(index, notification) {\n            // Determine what the offset was when loading this notification.\n            var offset = this.getOffset() - this.limit;\n            // Update the view more url to contain the offset to allow the notifications\n            // page to load to the correct position in the list of notifications.\n            notification.viewmoreurl = URL.relativeUrl('/message/output/popup/notifications.php', {\n                notificationid: notification.id,\n                offset: offset,\n            });\n\n            // Link to mark read page before loading the actual link.\n            var notificationurlparams = {\n                notificationid: notification.id\n            };\n\n            notification.contexturl = URL.relativeUrl('message/output/popup/mark_notification_read.php', notificationurlparams);\n\n            var promise = Templates.render('message_popup/notification_content_item', notification)\n            .then(function(html, js) {\n                return {html: html, js: js};\n            });\n            promises.push(promise);\n        }.bind(this));\n\n        return $.when.apply($, promises).then(function() {\n            // Each of the promises in the when will pass its results as an argument to the function.\n            // The order of the arguments will be the order that the promises are passed to when()\n            // i.e. the first promise's results will be in the first argument.\n            $.each(arguments, function(index, argument) {\n                container.append(argument.html);\n                Templates.runTemplateJS(argument.js);\n            });\n            return;\n        });\n    };\n\n    /**\n     * Send a request for more notifications from the server, if we aren't already\n     * loading some and haven't already loaded all of them.\n     *\n     * Takes into account the current mode of the popover and will request only\n     * unread notifications if required.\n     *\n     * All notifications are marked as read by the server when they are returned.\n     *\n     * @method loadMoreNotifications\n     * @return {object} jQuery promise that is resolved when notifications have been\n     *                        retrieved and added to the DOM\n     */\n    NotificationPopoverController.prototype.loadMoreNotifications = function() {\n        if (this.isLoading || this.hasLoadedAllContent()) {\n            return $.Deferred().resolve();\n        }\n\n        this.startLoading();\n        var request = {\n            limit: this.limit,\n            offset: this.getOffset(),\n            useridto: this.userId,\n        };\n\n        var container = this.getContent();\n        return NotificationRepo.query(request).then(function(result) {\n            var notifications = result.notifications;\n            this.unreadCount = result.unreadcount;\n            this.lastQueried = Math.floor(new Date().getTime() / 1000);\n            this.setLoadedAllContent(!notifications.length || notifications.length < this.limit);\n            this.initialLoad = true;\n            this.updateButtonAriaLabel();\n\n            if (notifications.length) {\n                this.incrementOffset();\n                return this.renderNotifications(notifications, container);\n            }\n\n            return false;\n        }.bind(this))\n        .always(function() {\n            this.stopLoading();\n        }.bind(this));\n    };\n\n    /**\n     * Send a request to the server to mark all unread notifications as read and update\n     * the unread count and unread notification elements appropriately.\n     *\n     * @return {Promise}\n     * @method markAllAsRead\n     */\n    NotificationPopoverController.prototype.markAllAsRead = function() {\n        this.markAllReadButton.addClass('loading');\n\n        var request = {\n            useridto: this.userId,\n            timecreatedto: this.lastQueried,\n        };\n\n        return NotificationRepo.markAllAsRead(request)\n            .then(function() {\n                this.unreadCount = 0;\n                this.root.find(SELECTORS.UNREAD_NOTIFICATION).removeClass('unread');\n            }.bind(this))\n            .always(function() {\n                this.markAllReadButton.removeClass('loading');\n            }.bind(this));\n    };\n\n    /**\n     * Add all of the required event listeners for this notification popover.\n     *\n     * @method registerEventListeners\n     */\n    NotificationPopoverController.prototype.registerEventListeners = function() {\n        CustomEvents.define(this.root, [\n            CustomEvents.events.activate,\n        ]);\n\n        // Mark all notifications read if the user activates the mark all as read button.\n        this.root.on(CustomEvents.events.activate, SELECTORS.MARK_ALL_READ_BUTTON, function(e, data) {\n            this.markAllAsRead();\n            e.stopPropagation();\n            data.originalEvent.preventDefault();\n        }.bind(this));\n\n        // Mark individual notification read if the user activates it.\n        this.root.on(CustomEvents.events.activate, SELECTORS.NOTIFICATION_LINK, function(e) {\n            var element = $(e.target).closest(SELECTORS.NOTIFICATION);\n\n            if (element.hasClass('unread')) {\n                this.unreadCount--;\n                element.removeClass('unread');\n            }\n\n            e.stopPropagation();\n        }.bind(this));\n\n        // Update the notification information when the menu is opened.\n        this.root.on(this.events().menuOpened, function() {\n            this.hideUnreadCount();\n            this.updateButtonAriaLabel();\n\n            if (!this.hasDoneInitialLoad()) {\n                this.loadMoreNotifications();\n            }\n        }.bind(this));\n\n        // Update the unread notification count when the menu is closed.\n        this.root.on(this.events().menuClosed, function() {\n            this.renderUnreadCount();\n            this.updateButtonAriaLabel();\n        }.bind(this));\n\n        // Set aria attributes when popover is loading.\n        this.root.on(this.events().startLoading, function() {\n            this.getContent().attr('aria-busy', 'true');\n        }.bind(this));\n\n        // Set aria attributes when popover is finished loading.\n        this.root.on(this.events().stopLoading, function() {\n            this.getContent().attr('aria-busy', 'false');\n        }.bind(this));\n\n        // Load more notifications if the user has scrolled to the end of content\n        // item list.\n        this.getContentContainer().on(CustomEvents.events.scrollBottom, function() {\n            if (!this.isLoading && !this.hasLoadedAllContent()) {\n                this.loadMoreNotifications();\n            }\n        }.bind(this));\n\n        // Stop mouse scroll from propagating to the window element and\n        // scrolling the page.\n        CustomEvents.define(this.getContentContainer(), [\n            CustomEvents.events.scrollLock\n        ]);\n\n        // Listen for when a notification is shown in the notifications page and mark\n        // it as read, if it's unread.\n        $(document).on(NotificationAreaEvents.notificationShown, function(e, notification) {\n            if (!notification.read) {\n                var element = this.getNotificationElement(notification.id);\n\n                if (element) {\n                    element.removeClass('unread');\n                }\n\n                this.unreadCount--;\n                this.renderUnreadCount();\n            }\n        }.bind(this));\n    };\n\n    return NotificationPopoverController;\n});\n"],"names":["define","$","Ajax","Templates","Str","URL","DebugNotification","CustomEvents","PopoverController","NotificationRepo","NotificationAreaEvents","SELECTORS","NotificationPopoverController","element","call","this","markAllReadButton","root","find","unreadCount","lastQueried","userId","attr","container","limit","offset","loadedAll","initialLoad","html","prototype","Object","create","constructor","updateButtonAriaLabel","isMenuOpen","get_string","done","string","menuToggle","bind","getContent","getOffset","incrementOffset","hasDoneInitialLoad","hasLoadedAllContent","setLoadedAllContent","val","renderUnreadCount","text","removeClass","addClass","hideUnreadCount","getNotificationElement","id","length","renderNotifications","notifications","promises","each","index","notification","viewmoreurl","relativeUrl","notificationid","notificationurlparams","contexturl","promise","render","then","js","push","when","apply","arguments","argument","append","runTemplateJS","loadMoreNotifications","isLoading","Deferred","resolve","startLoading","request","useridto","query","result","unreadcount","Math","floor","Date","getTime","always","stopLoading","markAllAsRead","timecreatedto","registerEventListeners","events","activate","on","e","data","stopPropagation","originalEvent","preventDefault","target","closest","hasClass","menuOpened","menuClosed","getContentContainer","scrollBottom","scrollLock","document","notificationShown","read"],"mappings":"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"}