Proyectos de Subversion Moodle

Rev

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

{"version":3,"file":"notification_area_control_area.min.js","sources":["../src/notification_area_control_area.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 area on the notification page.\n *\n * @module     message_popup/notification_area_control_area\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/templates', 'core/notification', 'core/custom_interaction_events',\n        'message_popup/notification_repository', 'message_popup/notification_area_events'],\n    function($, Templates, DebugNotification, CustomEvents, NotificationRepo, NotificationAreaEvents) {\n\n    var SELECTORS = {\n        CONTAINER: '[data-region=\"notification-area\"]',\n        CONTENT: '[data-region=\"content\"]',\n        NOTIFICATION: '[data-region=\"notification-content-item-container\"]',\n        CAN_RECEIVE_FOCUS: 'input:not([type=\"hidden\"]), a[href], button, textarea, select, [tabindex]',\n    };\n\n    var TEMPLATES = {\n        NOTIFICATION: 'message_popup/notification_content_item',\n    };\n\n    /**\n     * Constructor for ControlArea\n     *\n     * @class\n     * @param {object} root The root element for the content area\n     * @param {int} userId The user id of the current user\n     */\n    var ControlArea = function(root, userId) {\n        this.root = $(root);\n        this.container = this.root.closest(SELECTORS.CONTAINER);\n        this.userId = userId;\n        this.content = this.root.find(SELECTORS.CONTENT);\n        this.offset = 0;\n        this.limit = 20;\n        this.initialLoad = false;\n        this.isLoading = false;\n        this.loadedAll = false;\n        this.notifications = {};\n\n        this.registerEventListeners();\n    };\n\n    /**\n     * Get the root element.\n     *\n     * @method getRoot\n     * @return {object} jQuery element\n     */\n    ControlArea.prototype.getRoot = function() {\n        return this.root;\n    };\n\n    /**\n     * Get the container element (which the control area is within).\n     *\n     * @method getContainer\n     * @return {object} jQuery element\n     */\n    ControlArea.prototype.getContainer = function() {\n        return this.container;\n    };\n\n    /**\n     * Get the user id.\n     *\n     * @method getUserId\n     * @return {int}\n     */\n    ControlArea.prototype.getUserId = function() {\n        return this.userId;\n    };\n\n    /**\n     * Get the control area content element.\n     *\n     * @method getContent\n     * @return {object} jQuery element\n     */\n    ControlArea.prototype.getContent = function() {\n        return this.content;\n    };\n\n    /**\n     * Get the offset value for paginated loading of the\n     * notifications.\n     *\n     * @method getOffset\n     * @return {int}\n     */\n    ControlArea.prototype.getOffset = function() {\n        return this.offset;\n    };\n\n    /**\n     * Get the limit value for the paginated loading of the\n     * notifications.\n     *\n     * @method getLimit\n     * @return {int}\n     */\n    ControlArea.prototype.getLimit = function() {\n        return this.limit;\n    };\n\n    /**\n     * Set the offset value for the paginated loading of the\n     * notifications.\n     *\n     * @method setOffset\n     * @param {int} value The new offset value\n     */\n    ControlArea.prototype.setOffset = function(value) {\n        this.offset = value;\n    };\n\n    /**\n     * Set the limit value for the paginated loading of the\n     * notifications.\n     *\n     * @method setLimit\n     * @param {int} value The new limit value\n     */\n    ControlArea.prototype.setLimit = function(value) {\n        this.limit = value;\n    };\n\n    /**\n     * Increment the offset by the limit amount.\n     *\n     * @method incrementOffset\n     */\n    ControlArea.prototype.incrementOffset = function() {\n        this.offset += this.limit;\n    };\n\n    /**\n     * Flag the control area as loading.\n     *\n     * @method startLoading\n     */\n    ControlArea.prototype.startLoading = function() {\n        this.isLoading = true;\n        this.getRoot().addClass('loading');\n    };\n\n    /**\n     * Remove the loading flag from the control area.\n     *\n     * @method stopLoading\n     */\n    ControlArea.prototype.stopLoading = function() {\n        this.isLoading = false;\n        this.getRoot().removeClass('loading');\n    };\n\n    /**\n     * Check if the first load of notifications has been triggered.\n     *\n     * @method hasDoneInitialLoad\n     * @return {bool} true if first notification loaded, false otherwise\n     */\n    ControlArea.prototype.hasDoneInitialLoad = function() {\n        return this.initialLoad;\n    };\n\n    /**\n     * Check if all of the notifications have been loaded.\n     *\n     * @method hasLoadedAllContent\n     * @return {bool}\n     */\n    ControlArea.prototype.hasLoadedAllContent = function() {\n        return this.loadedAll;\n    };\n\n    /**\n     * Set the state of the loaded all content property.\n     *\n     * @method setLoadedAllContent\n     * @param {bool} val True if all content is loaded, false otherwise\n     */\n    ControlArea.prototype.setLoadedAllContent = function(val) {\n        this.loadedAll = val;\n    };\n\n    /**\n     * Save a notification in the cache.\n     *\n     * @method setCacheNotification\n     * @param {object} notification A notification returned by a webservice\n     */\n    ControlArea.prototype.setCacheNotification = function(notification) {\n        this.notifications[notification.id] = notification;\n    };\n\n    /**\n     * Retrieve a notification from the cache.\n     *\n     * @method getCacheNotification\n     * @param {int} id The id for the notification you wish to retrieve\n     * @return {object} A notification (as returned by a webservice)\n     */\n    ControlArea.prototype.getCacheNotification = function(id) {\n        return this.notifications[id];\n    };\n\n    /**\n     * Find the notification element in the control area for the given id.\n     *\n     * @method getNotificationElement\n     * @param {int} id The notification id\n     * @return {(object|null)} jQuery element or null\n     */\n    ControlArea.prototype.getNotificationElement = function(id) {\n        var element = this.getRoot().find(SELECTORS.NOTIFICATION + '[data-id=\"' + id + '\"]');\n        return element.length == 1 ? element : null;\n    };\n\n    /**\n     * Scroll the notification element into view within the control area, if it\n     * isn't already visible.\n     *\n     * @method scrollNotificationIntoView\n     * @param {object} notificationElement The jQuery notification element\n     */\n    ControlArea.prototype.scrollNotificationIntoView = function(notificationElement) {\n        var position = notificationElement.position();\n        var container = this.getRoot();\n        var relativeTop = position.top - container.scrollTop();\n\n        // If the element isn't in the view window.\n        if (relativeTop > container.innerHeight()) {\n            var height = notificationElement.outerHeight();\n            // Offset enough to make sure the notification will be in view.\n            height = height * 4;\n            var scrollTo = position.top - height;\n            container.scrollTop(scrollTo);\n        }\n    };\n\n    /**\n     * Show the full notification for the given notification element. The notification\n     * context is retrieved from the cache and send as data with an event to be\n     * rendered in the content area.\n     *\n     * @method showNotification\n     * @param {(int|object)} notificationElement The notification id or jQuery notification element\n     */\n    ControlArea.prototype.showNotification = function(notificationElement) {\n        if (typeof notificationElement !== 'object') {\n            // Assume it's an ID if it's not an object.\n            notificationElement = this.getNotificationElement(notificationElement);\n        }\n\n        if (notificationElement && notificationElement.length) {\n            this.getRoot().find(SELECTORS.NOTIFICATION).removeClass('selected');\n            notificationElement.addClass('selected').find(SELECTORS.CAN_RECEIVE_FOCUS).focus();\n            var notificationId = notificationElement.attr('data-id');\n            var notification = this.getCacheNotification(notificationId);\n            this.scrollNotificationIntoView(notificationElement);\n            // Create a new version of the notification to send with the notification so\n            // this copy isn't modified.\n            this.getContainer().trigger(NotificationAreaEvents.showNotification, [$.extend({}, notification)]);\n        }\n    };\n\n    /**\n     * Send a request to mark the notification as read in the server and remove the unread\n     * status from the element.\n     *\n     * @method markNotificationAsRead\n     * @param {object} notificationElement The jQuery notification element\n     * @return {object} jQuery promise\n     */\n    ControlArea.prototype.markNotificationAsRead = function(notificationElement) {\n        return NotificationRepo.markAsRead(notificationElement.attr('data-id')).done(function() {\n            notificationElement.removeClass('unread');\n        });\n    };\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 Array of notification data\n     * @return {object} jQuery promise that is resolved when all notifications have been\n     *                  rendered and added to the DOM\n     */\n    ControlArea.prototype.renderNotifications = function(notifications) {\n        var promises = [];\n        var container = this.getContent();\n\n        $.each(notifications, function(index, notification) {\n            // Need to remove the contexturl so the item isn't rendered\n            // as a link.\n            var contextUrl = notification.contexturl;\n            delete notification.contexturl;\n\n            var promise = Templates.render(TEMPLATES.NOTIFICATION, notification)\n            .then(function(html, js) {\n                // Restore it for the cache.\n                notification.contexturl = contextUrl;\n                this.setCacheNotification(notification);\n                // Pass the Rendered content out.\n                return {html: html, js: js};\n            }.bind(this));\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     * Load notifications from the server and render them.\n     *\n     * @method loadMoreNotifications\n     * @return {object} jQuery promise\n     */\n    ControlArea.prototype.loadMoreNotifications = function() {\n        if (this.isLoading || this.hasLoadedAllContent()) {\n            return $.Deferred().resolve();\n        }\n\n        this.startLoading();\n        var request = {\n            limit: this.getLimit(),\n            offset: this.getOffset(),\n            useridto: this.getUserId(),\n        };\n\n        if (!this.initialLoad) {\n            // If this is the first load we may have been given a non-zero offset,\n            // in which case we need to load all notifications preceeding that offset\n            // to make sure the full list is rendered.\n            request.limit = this.getOffset() + this.getLimit();\n            request.offset = 0;\n        }\n\n        var promise = NotificationRepo.query(request).then(function(result) {\n            var notifications = result.notifications;\n            this.unreadCount = result.unreadcount;\n            this.setLoadedAllContent(!notifications.length || notifications.length < this.getLimit());\n            this.initialLoad = true;\n\n            if (notifications.length) {\n                this.incrementOffset();\n                return this.renderNotifications(notifications);\n            }\n\n            return false;\n        }.bind(this))\n        .always(function() {\n            this.stopLoading();\n        }.bind(this));\n\n        return promise;\n    };\n\n    /**\n     * Create the event listeners for the control area.\n     *\n     * @method registerEventListeners\n     */\n    ControlArea.prototype.registerEventListeners = function() {\n        CustomEvents.define(this.getRoot(), [\n            CustomEvents.events.activate,\n            CustomEvents.events.scrollBottom,\n            CustomEvents.events.scrollLock,\n            CustomEvents.events.up,\n            CustomEvents.events.down,\n        ]);\n\n        this.getRoot().on(CustomEvents.events.scrollBottom, function() {\n            this.loadMoreNotifications();\n        }.bind(this));\n\n        this.getRoot().on(CustomEvents.events.activate, SELECTORS.NOTIFICATION, function(e) {\n            var notificationElement = $(e.target).closest(SELECTORS.NOTIFICATION);\n            this.showNotification(notificationElement);\n        }.bind(this));\n\n        // Show the previous notification in the list.\n        this.getRoot().on(CustomEvents.events.up, SELECTORS.NOTIFICATION, function(e, data) {\n            var notificationElement = $(e.target).closest(SELECTORS.NOTIFICATION);\n            this.showNotification(notificationElement.prev());\n\n            data.originalEvent.preventDefault();\n        }.bind(this));\n\n        // Show the next notification in the list.\n        this.getRoot().on(CustomEvents.events.down, SELECTORS.NOTIFICATION, function(e, data) {\n            var notificationElement = $(e.target).closest(SELECTORS.NOTIFICATION);\n            this.showNotification(notificationElement.next());\n\n            data.originalEvent.preventDefault();\n        }.bind(this));\n\n        this.getContainer().on(NotificationAreaEvents.notificationShown, function(e, notification) {\n            if (!notification.read) {\n                var element = this.getNotificationElement(notification.id);\n\n                if (element) {\n                    this.markNotificationAsRead(element);\n                }\n\n                var cachedNotification = this.getCacheNotification(notification.id);\n\n                if (cachedNotification) {\n                    cachedNotification.read = true;\n                }\n            }\n        }.bind(this));\n    };\n\n    return ControlArea;\n});\n"],"names":["define","$","Templates","DebugNotification","CustomEvents","NotificationRepo","NotificationAreaEvents","SELECTORS","TEMPLATES","ControlArea","root","userId","container","this","closest","content","find","offset","limit","initialLoad","isLoading","loadedAll","notifications","registerEventListeners","prototype","getRoot","getContainer","getUserId","getContent","getOffset","getLimit","setOffset","value","setLimit","incrementOffset","startLoading","addClass","stopLoading","removeClass","hasDoneInitialLoad","hasLoadedAllContent","setLoadedAllContent","val","setCacheNotification","notification","id","getCacheNotification","getNotificationElement","element","length","scrollNotificationIntoView","notificationElement","position","top","scrollTop","innerHeight","height","outerHeight","scrollTo","showNotification","focus","notificationId","attr","trigger","extend","markNotificationAsRead","markAsRead","done","renderNotifications","promises","each","index","contextUrl","contexturl","promise","render","then","html","js","bind","push","when","apply","arguments","argument","append","runTemplateJS","loadMoreNotifications","Deferred","resolve","request","useridto","query","result","unreadCount","unreadcount","always","events","activate","scrollBottom","scrollLock","up","down","on","e","target","data","prev","originalEvent","preventDefault","next","notificationShown","read","cachedNotification"],"mappings":"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"}