MDL-59515 messages: Order of popup messages should be predictable

Before this change the messages in the message popup would be loaded
onto a page in a random order, based on the speed at which the user's
browser was able to render each template.

This causes the messages to be attached to the page sequentially, after
they have all been rendered asynchronously.
This commit is contained in:
Neill Magill
2017-07-14 15:50:48 +01:00
parent 16a68a2f76
commit a5fbe27d8e
6 changed files with 46 additions and 21 deletions
@@ -1 +1 @@
define(["jquery","core/ajax","core/templates","core/str","core/notification","core/custom_interaction_events","core/popover_region_controller","core_message/message_repository","core/url"],function(a,b,c,d,e,f,g,h,i){var j={MARK_ALL_READ_BUTTON:'[data-action="mark-all-read"]',CONTENT:'[data-region="messages"]',CONTENT_ITEM_CONTAINER:'[data-region="message-content-item-container"]',EMPTY_MESSAGE:'[data-region="empty-message"]',COUNT_CONTAINER:'[data-region="count-container"]'},k=function(a){g.call(this,a),this.markAllReadButton=this.root.find(j.MARK_ALL_READ_BUTTON),this.content=this.root.find(j.CONTENT),this.userId=this.root.attr("data-userid"),this.limit=20,this.offset=0,this.loadedAll=!1,this.initialLoad=!1,this.loadUnreadMessageCount()};return k.prototype=Object.create(g.prototype),k.prototype.constructor=k,k.prototype.getContent=function(){return this.content},k.prototype.incrementOffset=function(){this.offset+=this.limit},k.prototype.updateButtonAriaLabel=function(){this.isMenuOpen()?d.get_string("hidemessagewindow","message").done(function(a){this.menuToggle.attr("aria-label",a)}.bind(this)):this.unreadCount?d.get_string("showmessagewindowwithcount","message",this.unreadCount).done(function(a){this.menuToggle.attr("aria-label",a)}.bind(this)):d.get_string("showmessagewindownonew","message").done(function(a){this.menuToggle.attr("aria-label",a)}.bind(this))},k.prototype.renderUnreadCount=function(){var a=this.root.find(j.COUNT_CONTAINER);this.unreadCount?(a.text(this.unreadCount),a.removeClass("hidden")):a.addClass("hidden")},k.prototype.hideUnreadCount=function(){this.root.find(j.COUNT_CONTAINER).addClass("hidden")},k.prototype.loadUnreadMessageCount=function(){h.countUnreadConversations({useridto:this.userId}).then(function(a){this.unreadCount=a,this.renderUnreadCount(),this.updateButtonAriaLabel()}.bind(this))["catch"](e.exception)},k.prototype.renderMessages=function(b,d){var e=[];return a.each(b,function(a,b){b.contexturl=i.relativeUrl("/message/index.php",{user:this.userId,id:b.userid}),b.profileurl=i.relativeUrl("/user/profile.php",{id:b.userid});var f=c.render("message_popup/message_content_item",b).then(function(a,b){d.append(a),c.runTemplateJS(b)});e.push(f)}.bind(this)),a.when.apply(a,e)},k.prototype.loadMoreMessages=function(){if(this.isLoading||this.loadedAll)return a.Deferred().resolve();this.startLoading();var b={userid:this.userId,limit:this.limit,offset:this.offset},c=this.getContent();return h.query(b).then(function(a){var b=a.contacts;return this.loadedAll=!b.length||b.length<this.limit,this.initialLoad=!0,this.updateButtonAriaLabel(),!!b.length&&(this.incrementOffset(),this.renderMessages(b,c))}.bind(this)).always(function(){this.stopLoading()}.bind(this))},k.prototype.markAllAsRead=function(){return this.markAllReadButton.hasClass("loading")?a.Deferred().resolve():(this.markAllReadButton.addClass("loading"),h.markAllAsRead({useridto:this.userId}).then(function(){this.unreadCount=0,this.hideUnreadCount(),this.getContent().find(j.CONTENT_ITEM_CONTAINER).removeClass("unread")}.bind(this)).always(function(){this.markAllReadButton.removeClass("loading")}.bind(this)))},k.prototype.registerEventListeners=function(){f.define(this.root,[f.events.keyboardActivate]),this.root.on(this.events().menuOpened,function(){this.hideUnreadCount(),this.updateButtonAriaLabel(),this.initialLoad||this.loadMoreMessages()}.bind(this)),this.root.on(this.events().menuClosed,function(){this.renderUnreadCount(),this.updateButtonAriaLabel()}.bind(this)),this.root.on(f.events.scrollBottom,function(){this.loadMoreMessages()}.bind(this)),this.root.on(f.events.activate,j.MARK_ALL_READ_BUTTON,function(a,b){this.markAllAsRead(),a.stopPropagation(),b.originalEvent.preventDefault()}.bind(this)),f.define(this.getContentContainer(),[f.events.scrollLock]),a(document).on("messagearea:conversationselected",function(){this.unreadCount--,this.renderUnreadCount()}.bind(this))},k});
define(["jquery","core/ajax","core/templates","core/str","core/notification","core/custom_interaction_events","core/popover_region_controller","core_message/message_repository","core/url"],function(a,b,c,d,e,f,g,h,i){var j={MARK_ALL_READ_BUTTON:'[data-action="mark-all-read"]',CONTENT:'[data-region="messages"]',CONTENT_ITEM_CONTAINER:'[data-region="message-content-item-container"]',EMPTY_MESSAGE:'[data-region="empty-message"]',COUNT_CONTAINER:'[data-region="count-container"]'},k=function(a){g.call(this,a),this.markAllReadButton=this.root.find(j.MARK_ALL_READ_BUTTON),this.content=this.root.find(j.CONTENT),this.userId=this.root.attr("data-userid"),this.limit=20,this.offset=0,this.loadedAll=!1,this.initialLoad=!1,this.loadUnreadMessageCount()};return k.prototype=Object.create(g.prototype),k.prototype.constructor=k,k.prototype.getContent=function(){return this.content},k.prototype.incrementOffset=function(){this.offset+=this.limit},k.prototype.updateButtonAriaLabel=function(){this.isMenuOpen()?d.get_string("hidemessagewindow","message").done(function(a){this.menuToggle.attr("aria-label",a)}.bind(this)):this.unreadCount?d.get_string("showmessagewindowwithcount","message",this.unreadCount).done(function(a){this.menuToggle.attr("aria-label",a)}.bind(this)):d.get_string("showmessagewindownonew","message").done(function(a){this.menuToggle.attr("aria-label",a)}.bind(this))},k.prototype.renderUnreadCount=function(){var a=this.root.find(j.COUNT_CONTAINER);this.unreadCount?(a.text(this.unreadCount),a.removeClass("hidden")):a.addClass("hidden")},k.prototype.hideUnreadCount=function(){this.root.find(j.COUNT_CONTAINER).addClass("hidden")},k.prototype.loadUnreadMessageCount=function(){h.countUnreadConversations({useridto:this.userId}).then(function(a){this.unreadCount=a,this.renderUnreadCount(),this.updateButtonAriaLabel()}.bind(this))["catch"](e.exception)},k.prototype.renderMessages=function(b,d){var e=[];return a.each(b,function(a,b){b.contexturl=i.relativeUrl("/message/index.php",{user:this.userId,id:b.userid}),b.profileurl=i.relativeUrl("/user/profile.php",{id:b.userid});var d=c.render("message_popup/message_content_item",b);e.push(d)}.bind(this)),a.when.apply(a,e).then(function(){a.each(arguments,function(a,b){d.append(b[0]),c.runTemplateJS(b[1])})})},k.prototype.loadMoreMessages=function(){if(this.isLoading||this.loadedAll)return a.Deferred().resolve();this.startLoading();var b={userid:this.userId,limit:this.limit,offset:this.offset},c=this.getContent();return h.query(b).then(function(a){var b=a.contacts;return this.loadedAll=!b.length||b.length<this.limit,this.initialLoad=!0,this.updateButtonAriaLabel(),!!b.length&&(this.incrementOffset(),this.renderMessages(b,c))}.bind(this)).always(function(){this.stopLoading()}.bind(this))},k.prototype.markAllAsRead=function(){return this.markAllReadButton.hasClass("loading")?a.Deferred().resolve():(this.markAllReadButton.addClass("loading"),h.markAllAsRead({useridto:this.userId}).then(function(){this.unreadCount=0,this.hideUnreadCount(),this.getContent().find(j.CONTENT_ITEM_CONTAINER).removeClass("unread")}.bind(this)).always(function(){this.markAllReadButton.removeClass("loading")}.bind(this)))},k.prototype.registerEventListeners=function(){f.define(this.root,[f.events.keyboardActivate]),this.root.on(this.events().menuOpened,function(){this.hideUnreadCount(),this.updateButtonAriaLabel(),this.initialLoad||this.loadMoreMessages()}.bind(this)),this.root.on(this.events().menuClosed,function(){this.renderUnreadCount(),this.updateButtonAriaLabel()}.bind(this)),this.root.on(f.events.scrollBottom,function(){this.loadMoreMessages()}.bind(this)),this.root.on(f.events.activate,j.MARK_ALL_READ_BUTTON,function(a,b){this.markAllAsRead(),a.stopPropagation(),b.originalEvent.preventDefault()}.bind(this)),f.define(this.getContentContainer(),[f.events.scrollLock]),a(document).on("messagearea:conversationselected",function(){this.unreadCount--,this.renderUnreadCount()}.bind(this))},k});
@@ -1 +1 @@
define(["jquery","core/templates","core/notification","core/custom_interaction_events","message_popup/notification_repository","message_popup/notification_area_events"],function(a,b,c,d,e,f){var g={CONTAINER:'[data-region="notification-area"]',CONTENT:'[data-region="content"]',NOTIFICATION:'[data-region="notification-content-item-container"]',CAN_RECEIVE_FOCUS:'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]'},h={NOTIFICATION:"message_popup/notification_content_item"},i=function(b,c){this.root=a(b),this.container=this.root.closest(g.CONTAINER),this.userId=c,this.content=this.root.find(g.CONTENT),this.offset=0,this.limit=20,this.initialLoad=!1,this.isLoading=!1,this.loadedAll=!1,this.notifications={},this.registerEventListeners()};return i.prototype.getRoot=function(){return this.root},i.prototype.getContainer=function(){return this.container},i.prototype.getUserId=function(){return this.userId},i.prototype.getContent=function(){return this.content},i.prototype.getOffset=function(){return this.offset},i.prototype.getLimit=function(){return this.limit},i.prototype.setOffset=function(a){this.offset=a},i.prototype.setLimit=function(a){this.limit=a},i.prototype.incrementOffset=function(){this.offset+=this.limit},i.prototype.startLoading=function(){this.isLoading=!0,this.getRoot().addClass("loading")},i.prototype.stopLoading=function(){this.isLoading=!1,this.getRoot().removeClass("loading")},i.prototype.hasDoneInitialLoad=function(){return this.initialLoad},i.prototype.hasLoadedAllContent=function(){return this.loadedAll},i.prototype.setLoadedAllContent=function(a){this.loadedAll=a},i.prototype.setCacheNotification=function(a){this.notifications[a.id]=a},i.prototype.getCacheNotification=function(a){return this.notifications[a]},i.prototype.getNotificationElement=function(a){var b=this.getRoot().find(g.NOTIFICATION+'[data-id="'+a+'"]');return 1==b.length?b:null},i.prototype.scrollNotificationIntoView=function(a){var b=a.position(),c=this.getRoot(),d=b.top-c.scrollTop();if(d>c.innerHeight()){var e=a.outerHeight();e=4*e;var f=b.top-e;c.scrollTop(f)}},i.prototype.showNotification=function(b){if("object"!=typeof b&&(b=this.getNotificationElement(b)),b&&b.length){this.getRoot().find(g.NOTIFICATION).removeClass("selected"),b.addClass("selected").find(g.CAN_RECEIVE_FOCUS).focus();var c=b.attr("data-id"),d=this.getCacheNotification(c);this.scrollNotificationIntoView(b),this.getContainer().trigger(f.showNotification,[a.extend({},d)])}},i.prototype.markNotificationAsRead=function(a){return e.markAsRead(a.attr("data-id")).done(function(){a.removeClass("unread")})},i.prototype.renderNotifications=function(c){var d=[],e=this.getContent();return a.each(c,function(a,c){var f=c.contexturl;delete c.contexturl;var g=b.render(h.NOTIFICATION,c).then(function(a,d){e.append(a),b.runTemplateJS(d),c.contexturl=f,this.setCacheNotification(c)}.bind(this));d.push(g)}.bind(this)),a.when.apply(a,d)},i.prototype.loadMoreNotifications=function(){if(this.isLoading||this.hasLoadedAllContent())return a.Deferred().resolve();this.startLoading();var b={limit:this.getLimit(),offset:this.getOffset(),useridto:this.getUserId()};this.initialLoad||(b.limit=this.getOffset()+this.getLimit(),b.offset=0);var c=e.query(b).then(function(a){var b=a.notifications;return this.unreadCount=a.unreadcount,this.setLoadedAllContent(!b.length||b.length<this.getLimit()),this.initialLoad=!0,!!b.length&&(this.incrementOffset(),this.renderNotifications(b))}.bind(this)).always(function(){this.stopLoading()}.bind(this));return c},i.prototype.registerEventListeners=function(){d.define(this.getRoot(),[d.events.activate,d.events.scrollBottom,d.events.scrollLock,d.events.up,d.events.down]),this.getRoot().on(d.events.scrollBottom,function(){this.loadMoreNotifications()}.bind(this)),this.getRoot().on(d.events.activate,g.NOTIFICATION,function(b){var c=a(b.target).closest(g.NOTIFICATION);this.showNotification(c)}.bind(this)),this.getRoot().on(d.events.up,g.NOTIFICATION,function(b,c){var d=a(b.target).closest(g.NOTIFICATION);this.showNotification(d.prev()),c.originalEvent.preventDefault()}.bind(this)),this.getRoot().on(d.events.down,g.NOTIFICATION,function(b,c){var d=a(b.target).closest(g.NOTIFICATION);this.showNotification(d.next()),c.originalEvent.preventDefault()}.bind(this)),this.getContainer().on(f.notificationShown,function(a,b){if(!b.read){var c=this.getNotificationElement(b.id);c&&this.markNotificationAsRead(c);var d=this.getCacheNotification(b.id);d&&(d.read=!0)}}.bind(this))},i});
define(["jquery","core/templates","core/notification","core/custom_interaction_events","message_popup/notification_repository","message_popup/notification_area_events"],function(a,b,c,d,e,f){var g={CONTAINER:'[data-region="notification-area"]',CONTENT:'[data-region="content"]',NOTIFICATION:'[data-region="notification-content-item-container"]',CAN_RECEIVE_FOCUS:'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]'},h={NOTIFICATION:"message_popup/notification_content_item"},i=function(b,c){this.root=a(b),this.container=this.root.closest(g.CONTAINER),this.userId=c,this.content=this.root.find(g.CONTENT),this.offset=0,this.limit=20,this.initialLoad=!1,this.isLoading=!1,this.loadedAll=!1,this.notifications={},this.registerEventListeners()};return i.prototype.getRoot=function(){return this.root},i.prototype.getContainer=function(){return this.container},i.prototype.getUserId=function(){return this.userId},i.prototype.getContent=function(){return this.content},i.prototype.getOffset=function(){return this.offset},i.prototype.getLimit=function(){return this.limit},i.prototype.setOffset=function(a){this.offset=a},i.prototype.setLimit=function(a){this.limit=a},i.prototype.incrementOffset=function(){this.offset+=this.limit},i.prototype.startLoading=function(){this.isLoading=!0,this.getRoot().addClass("loading")},i.prototype.stopLoading=function(){this.isLoading=!1,this.getRoot().removeClass("loading")},i.prototype.hasDoneInitialLoad=function(){return this.initialLoad},i.prototype.hasLoadedAllContent=function(){return this.loadedAll},i.prototype.setLoadedAllContent=function(a){this.loadedAll=a},i.prototype.setCacheNotification=function(a){this.notifications[a.id]=a},i.prototype.getCacheNotification=function(a){return this.notifications[a]},i.prototype.getNotificationElement=function(a){var b=this.getRoot().find(g.NOTIFICATION+'[data-id="'+a+'"]');return 1==b.length?b:null},i.prototype.scrollNotificationIntoView=function(a){var b=a.position(),c=this.getRoot(),d=b.top-c.scrollTop();if(d>c.innerHeight()){var e=a.outerHeight();e=4*e;var f=b.top-e;c.scrollTop(f)}},i.prototype.showNotification=function(b){if("object"!=typeof b&&(b=this.getNotificationElement(b)),b&&b.length){this.getRoot().find(g.NOTIFICATION).removeClass("selected"),b.addClass("selected").find(g.CAN_RECEIVE_FOCUS).focus();var c=b.attr("data-id"),d=this.getCacheNotification(c);this.scrollNotificationIntoView(b),this.getContainer().trigger(f.showNotification,[a.extend({},d)])}},i.prototype.markNotificationAsRead=function(a){return e.markAsRead(a.attr("data-id")).done(function(){a.removeClass("unread")})},i.prototype.renderNotifications=function(c){var d=[],e=this.getContent();return a.each(c,function(a,c){var e=c.contexturl;delete c.contexturl;var f=b.render(h.NOTIFICATION,c).then(function(a,b){return c.contexturl=e,this.setCacheNotification(c),[a,b]}.bind(this));d.push(f)}.bind(this)),a.when.apply(a,d).then(function(){a.each(arguments,function(a,c){e.append(c[0]),b.runTemplateJS(c[1])})})},i.prototype.loadMoreNotifications=function(){if(this.isLoading||this.hasLoadedAllContent())return a.Deferred().resolve();this.startLoading();var b={limit:this.getLimit(),offset:this.getOffset(),useridto:this.getUserId()};this.initialLoad||(b.limit=this.getOffset()+this.getLimit(),b.offset=0);var c=e.query(b).then(function(a){var b=a.notifications;return this.unreadCount=a.unreadcount,this.setLoadedAllContent(!b.length||b.length<this.getLimit()),this.initialLoad=!0,!!b.length&&(this.incrementOffset(),this.renderNotifications(b))}.bind(this)).always(function(){this.stopLoading()}.bind(this));return c},i.prototype.registerEventListeners=function(){d.define(this.getRoot(),[d.events.activate,d.events.scrollBottom,d.events.scrollLock,d.events.up,d.events.down]),this.getRoot().on(d.events.scrollBottom,function(){this.loadMoreNotifications()}.bind(this)),this.getRoot().on(d.events.activate,g.NOTIFICATION,function(b){var c=a(b.target).closest(g.NOTIFICATION);this.showNotification(c)}.bind(this)),this.getRoot().on(d.events.up,g.NOTIFICATION,function(b,c){var d=a(b.target).closest(g.NOTIFICATION);this.showNotification(d.prev()),c.originalEvent.preventDefault()}.bind(this)),this.getRoot().on(d.events.down,g.NOTIFICATION,function(b,c){var d=a(b.target).closest(g.NOTIFICATION);this.showNotification(d.next()),c.originalEvent.preventDefault()}.bind(this)),this.getContainer().on(f.notificationShown,function(a,b){if(!b.read){var c=this.getNotificationElement(b.id);c&&this.markNotificationAsRead(c);var d=this.getCacheNotification(b.id);d&&(d.read=!0)}}.bind(this))},i});
File diff suppressed because one or more lines are too long
@@ -176,16 +176,23 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str',
id: message.userid,
});
var promise = Templates.render('message_popup/message_content_item', message)
.then(function(html, js) {
container.append(html);
Templates.runTemplateJS(js);
return;
});
var promise = Templates.render('message_popup/message_content_item', message);
promises.push(promise);
}.bind(this));
return $.when.apply($, promises);
return $.when.apply($, promises).then(function() {
// Each of the promises in the when will pass its results as an argument to the function.
// The order of the arguments will be the order that the promises are passed to when()
// i.e. the first promise's results will be in the first argument.
$.each(arguments, function(index, argument) {
// The promises will return an array containing two values.
// The first value is the html that should be attached to the page.
// The second will be any JavaScript that needs to be run.
container.append(argument[0]);
Templates.runTemplateJS(argument[1]);
});
return;
});
};
/**
@@ -317,17 +317,28 @@ define(['jquery', 'core/templates', 'core/notification', 'core/custom_interactio
var promise = Templates.render(TEMPLATES.NOTIFICATION, notification)
.then(function(html, js) {
container.append(html);
Templates.runTemplateJS(js);
// Restore it for the cache.
notification.contexturl = contextUrl;
this.setCacheNotification(notification);
return;
// Pass the Rendered content out.
return [html, js];
}.bind(this));
promises.push(promise);
}.bind(this));
return $.when.apply($, promises);
return $.when.apply($, promises).then(function() {
// Each of the promises in the when will pass its results as an argument to the function.
// The order of the arguments will be the order that the promises are passed to when()
// i.e. the first promise's results will be in the first argument.
$.each(arguments, function(index, argument) {
// The promises will return an array containing two values.
// The first value is the html that should be attached to the page.
// The second will be any JavaScript that needs to be run.
container.append(argument[0]);
Templates.runTemplateJS(argument[1]);
});
return;
});
};
/**
@@ -237,16 +237,23 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str', 'core/url',
offset: offset,
});
var promise = Templates.render('message_popup/notification_content_item', notification)
.then(function(html, js) {
container.append(html);
Templates.runTemplateJS(js);
return;
});
var promise = Templates.render('message_popup/notification_content_item', notification);
promises.push(promise);
}.bind(this));
return $.when.apply($, promises);
return $.when.apply($, promises).then(function() {
// Each of the promises in the when will pass its results as an argument to the function.
// The order of the arguments will be the order that the promises are passed to when()
// i.e. the first promise's results will be in the first argument.
$.each(arguments, function(index, argument) {
// The promises will return an array containing two values.
// The first value is the html that should be attached to the page.
// The second will be any JavaScript that needs to be run.
container.append(argument[0]);
Templates.runTemplateJS(argument[1]);
});
return;
});
};
/**