diff --git a/message/amd/src/message_popover_controller.js b/message/amd/src/message_popover_controller.js index 032ffbbea09..e804addea35 100644 --- a/message/amd/src/message_popover_controller.js +++ b/message/amd/src/message_popover_controller.js @@ -27,9 +27,9 @@ */ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates', 'core/str', 'core/notification', 'core/custom_interaction_events', 'core/mdl_popover_controller', - 'core_message/message_repository'], + 'core_message/message_repository', 'core/url'], function($, bootstrap, ajax, templates, str, debugNotification, customEvents, - PopoverController, messageRepo) { + PopoverController, messageRepo, URL) { var SELECTORS = { MARK_ALL_READ_BUTTON: '.mark-all-read-button', @@ -38,6 +38,7 @@ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates' CONTENT: '.messages', CONTENT_ITEM_CONTAINER: '.content-item-container', EMPTY_MESSAGE: '.empty-message', + LINK_URL: '[data-link-url]', }; /** @@ -112,6 +113,26 @@ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates' } }; + /** + * Navigate the browser to the link URL for the item, if it has one. + * + * @method navigateToLinkURL + * @param {jQuery} item The link element + * @param {bool} item Should the URL be opened in a new tab or not. + */ + MessagePopoverController.prototype.navigateToLinkURL = function(item, newTab) { + var url = item.attr('data-link-url'); + newTab = newTab || false; + + if (url) { + if (newTab) { + window.open(url, '_blank'); + } else { + window.location.assign(url); + } + } + }; + /** * Show the unread notification count badge on the menu toggle if there * are unread notifications, otherwise hide it. @@ -167,6 +188,15 @@ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates' if (messages.length) { $.each(messages, function(index, message) { + message.contexturl = URL.relativeUrl('/message/index.php', { + user: this.userId, + id: message.userid, + }, true); + + message.profileurl = URL.relativeUrl('/user/profile.php', { + id: message.userid, + }); + var promise = templates.render('message/message_content_item', message); promise.then(function(html, js) { container.append(html); @@ -240,6 +270,10 @@ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates' * @method registerEventListeners */ MessagePopoverController.prototype.registerEventListeners = function() { + customEvents.define(this.root, [ + customEvents.events.keyboardActivate, + ]); + // Update the notification information when the menu is opened. this.root.on(this.events().menuOpened, function() { this.hideUnreadCount(); @@ -255,6 +289,31 @@ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates' this.renderUnreadCount(); this.updateButtonAriaLabel(); }.bind(this)); + + // Load more messages when we scroll to the bottom of the open menu. + this.root.on(customEvents.events.scrollBottom, function() { + this.loadMoreMessages(); + }.bind(this)); + + // Follow the link URL if the user activates it. + this.root.on('click', SELECTORS.LINK_URL, function(e) { + var linkItem = $(e.target).closest(SELECTORS.LINK_URL); + // Open link in a new tab if the user ctrl + click or command + click. + if (e.ctrlKey || e.metaKey) { + this.navigateToLinkURL(linkItem, true); + } else { + this.navigateToLinkURL(linkItem, false); + } + e.stopPropagation(); + e.preventDefault(); + }.bind(this)); + + // Follow the link URL if the user activates it. + this.root.on(customEvents.events.keyboardActivate, SELECTORS.LINK_URL, function(e) { + var linkItem = $(e.target).closest(SELECTORS.LINK_URL); + this.navigateToLinkURL(linkItem, false); + e.stopPropagation(); + }.bind(this)); }; return MessagePopoverController; diff --git a/message/amd/src/message_repository.js b/message/amd/src/message_repository.js index 9a593e74322..7a50691a46b 100644 --- a/message/amd/src/message_repository.js +++ b/message/amd/src/message_repository.js @@ -19,21 +19,23 @@ * @module core_message/message_repository * @class message_repository * @package message - * @copyright 2015 Ryan Wyllie + * @copyright 2016 Ryan Wyllie * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since 3.2 */ define(['jquery', 'core/ajax', 'core/notification'], function($, ajax, notification) { var query = function(args) { - /* + // Normalise the arguments to use limit/offset rather than limitnum/limitfrom. if (typeof args.limit === 'undefined') { - args.limit = 20; + args.limit = 0; } if (typeof args.offset === 'undefined') { args.offset = 0; } - */ + + args.limitfrom = args.offset; + args.limitnum = args.limit; delete args.limit; delete args.offset; diff --git a/message/amd/src/notification_popover_controller.js b/message/amd/src/notification_popover_controller.js index 575a4a76f4e..4ade9f15cb1 100644 --- a/message/amd/src/notification_popover_controller.js +++ b/message/amd/src/notification_popover_controller.js @@ -44,6 +44,7 @@ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates' EMPTY_MESSAGE: '.empty-message', CONTENT_BODY_SHORT: '.content-body-short', CONTENT_BODY_FULL: '.content-body-full', + LINK_URL: '[data-link-url]', }; var PROCESSOR_NAME = 'popup'; @@ -501,16 +502,22 @@ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates' }; /** - * Navigate the browser to the content URL for the content item, if it has one. + * Navigate the browser to the link URL for the item, if it has one. * - * @method navigateToContextURL - * @param item jQuery object representing the content item + * @method navigateToLinkURL + * @param {jQuery} item The link element + * @param {bool} item Should the URL be opened in a new tab or not. */ - NotificationPopoverController.prototype.navigateToContextURL = function(item) { - var url = item.attr('data-context-url'); + NotificationPopoverController.prototype.navigateToLinkURL = function(item, newTab) { + var url = item.attr('data-link-url'); + newTab = newTab || false; if (url) { - window.location.assign(url); + if (newTab) { + window.open(url, '_blank'); + } else { + window.location.assign(url); + } } }; @@ -602,6 +609,7 @@ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates' NotificationPopoverController.prototype.registerEventListeners = function() { customEvents.define(this.root, [ customEvents.events.activate, + customEvents.events.keyboardActivate, customEvents.events.next, customEvents.events.previous, customEvents.events.asterix, @@ -674,10 +682,23 @@ define(['jquery', 'theme_bootstrapbase/bootstrap', 'core/ajax', 'core/templates' e.stopPropagation(); }.bind(this)); - // Follow the context URL if the user activates the content item. - this.root.on(customEvents.events.activate, SELECTORS.CONTENT_ITEM_CONTAINER, function(e) { - var contentItem = $(e.target).closest(SELECTORS.CONTENT_ITEM_CONTAINER); - this.navigateToContextURL(contentItem); + // Follow the link URL if the user activates it. + this.root.on('click', SELECTORS.LINK_URL, function(e) { + var linkItem = $(e.target).closest(SELECTORS.LINK_URL); + // Open link in a new tab if the user ctrl + click or command + click. + if (e.ctrlKey || e.metaKey) { + this.navigateToLinkURL(linkItem, true); + } else { + this.navigateToLinkURL(linkItem, false); + } + e.stopPropagation(); + e.preventDefault(); + }.bind(this)); + + // Follow the link URL if the user activates it. + this.root.on(customEvents.events.keyboardActivate, SELECTORS.LINK_URL, function(e) { + var linkItem = $(e.target).closest(SELECTORS.LINK_URL); + this.navigateToLinkURL(linkItem, false); e.stopPropagation(); }.bind(this)); diff --git a/message/templates/message_content_item.mustache b/message/templates/message_content_item.mustache index bffb42237ee..c5d1e0e1277 100644 --- a/message/templates/message_content_item.mustache +++ b/message/templates/message_content_item.mustache @@ -34,18 +34,25 @@ } }} - diff --git a/message/templates/notification_content_item.mustache b/message/templates/notification_content_item.mustache index 2634601b866..6a160e6cfe2 100644 --- a/message/templates/notification_content_item.mustache +++ b/message/templates/notification_content_item.mustache @@ -38,16 +38,14 @@ role="listitem" aria-expanded="false" aria-label="{{subject}}" - tabindex="0" - {{#contexturl}}data-context-url="{{{.}}}"{{/contexturl}}> + tabindex="0"> + {{#contexturl}} + + {{/contexturl}}
@@ -92,4 +90,7 @@
+ {{#contexturl}} + + {{/contexturl}}
diff --git a/theme/bootstrapbase/less/moodle/popover.less b/theme/bootstrapbase/less/moodle/popover.less index dcd1bbc27af..3862d55eee2 100644 --- a/theme/bootstrapbase/less/moodle/popover.less +++ b/theme/bootstrapbase/less/moodle/popover.less @@ -83,6 +83,21 @@ } } + [data-link-url] { + cursor: pointer; + color: @linkColor; + + &:hover, + &:active { + outline: 0; + } + &:hover, + &:focus { + color: @linkColorHover; + text-decoration: underline; + } + } + &.collapsed { .mdl-popover-container { height: 0; @@ -307,8 +322,14 @@ opacity: 0.8; } - &[data-context-url] { - cursor: pointer; + .content-item-link { + color: inherit; + text-decoration: none; + + &:hover { + color: inherit; + text-decoration: none; + } } .content-item { @@ -568,29 +589,44 @@ box-sizing: border-box; padding: 5px; height: 85px; + cursor: pointer; &:hover { opacity: 0.8; } - &[data-context-url] { - cursor: pointer; + .content-item-link { + color: inherit; + text-decoration: none; + + &:hover { + color: inherit; + text-decoration: none; + } } .content-item { height: 100%; width: 100%; - img { + .profile-image-container { + height: 100%; + width: 20%; display: inline-block; - vertical-align: middle; + + img { + height: 100%; + display: inline-block; + vertical-align: middle; + border-radius: 50%; + } } .content-item-body { display: inline-block; box-sizing: border-box; vertical-align: middle; - width: ~"calc(100% - 68px)"; + width: 75%; height: 100%; h3 { @@ -608,6 +644,9 @@ &:last-child { border-bottom: none; } + &.unread { + background-color: #effaff; + } } } &.loading { diff --git a/theme/bootstrapbase/style/moodle.css b/theme/bootstrapbase/style/moodle.css index 58d2d16240a..6704ace6c82 100644 --- a/theme/bootstrapbase/style/moodle.css +++ b/theme/bootstrapbase/style/moodle.css @@ -7107,6 +7107,19 @@ body.path-question-type .mform fieldset.hidden { .mdl-popover .mdl-popover-container .mdl-popover-content-container.loading .empty-message { display: none; } +.mdl-popover [data-link-url] { + cursor: pointer; + color: #0070a8; +} +.mdl-popover [data-link-url]:hover, +.mdl-popover [data-link-url]:active { + outline: 0; +} +.mdl-popover [data-link-url]:hover, +.mdl-popover [data-link-url]:focus { + color: #003d5c; + text-decoration: underline; +} .mdl-popover.collapsed .mdl-popover-container { height: 0; overflow: hidden; @@ -7286,8 +7299,13 @@ body.path-question-type .mform fieldset.hidden { .mdl-popover-notifications.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container:hover { opacity: 0.8; } -.mdl-popover-notifications.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container[data-context-url] { - cursor: pointer; +.mdl-popover-notifications.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item-link { + color: inherit; + text-decoration: none; +} +.mdl-popover-notifications.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item-link:hover { + color: inherit; + text-decoration: none; } .mdl-popover-notifications.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item { width: calc(100% - 45px); @@ -7474,26 +7492,39 @@ body.path-question-type .mform fieldset.hidden { box-sizing: border-box; padding: 5px; height: 85px; + cursor: pointer; } .mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container:hover { opacity: 0.8; } -.mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container[data-context-url] { - cursor: pointer; +.mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item-link { + color: inherit; + text-decoration: none; +} +.mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item-link:hover { + color: inherit; + text-decoration: none; } .mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item { height: 100%; width: 100%; } -.mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item img { +.mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item .profile-image-container { + height: 100%; + width: 20%; + display: inline-block; +} +.mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item .profile-image-container img { + height: 100%; display: inline-block; vertical-align: middle; + border-radius: 50%; } .mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item .content-item-body { display: inline-block; box-sizing: border-box; vertical-align: middle; - width: calc(100% - 68px); + width: 75%; height: 100%; } .mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container .content-item .content-item-body h3 { @@ -7508,6 +7539,9 @@ body.path-question-type .mform fieldset.hidden { .mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container:last-child { border-bottom: none; } +.mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container .mdl-popover-content .content-item-container.unread { + background-color: #effaff; +} .mdl-popover-messages.mdl-popover .mdl-popover-container .mdl-popover-content-container.loading .mdl-popover-content .messages:empty + .empty-message { display: none; }