Update existing notifications in dropdown on fetch
When fetching notifications this merges existing notifications and changes their appearance in the dropdown if the html or the unread status changed. This doesn't update all notifications in the dropdown but only those that are returned by the server. Related to #7247.
This commit is contained in:
parent
ade9b97215
commit
abe7ef3d18
6 changed files with 57 additions and 10 deletions
|
|
@ -84,7 +84,8 @@ app.collections.Notifications = Backbone.Collection.extend({
|
||||||
/* eslint-disable new-cap */
|
/* eslint-disable new-cap */
|
||||||
var model = new this.model(item);
|
var model = new this.model(item);
|
||||||
/* eslint-enable new-cap */
|
/* eslint-enable new-cap */
|
||||||
model.on("change:unread", this.onChangedUnreadStatus.bind(this));
|
model.on("userChangedUnreadStatus", this.onChangedUnreadStatus.bind(this));
|
||||||
|
model.on("change:unread", function() { this.trigger("update"); }.bind(this));
|
||||||
return model;
|
return model;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@ app.models.Notification = Backbone.Model.extend({
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
parse: function(response) {
|
parse: function(response) {
|
||||||
|
if (response.id) {
|
||||||
|
// already correct format
|
||||||
|
return response;
|
||||||
|
}
|
||||||
var result = {type: response.type};
|
var result = {type: response.type};
|
||||||
result = $.extend(result, response[result.type]);
|
result = $.extend(result, response[result.type]);
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -62,7 +66,10 @@ app.models.Notification = Backbone.Model.extend({
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
context: this,
|
context: this,
|
||||||
success: function() { this.set("unread", state); }
|
success: function() {
|
||||||
|
this.set("unread", state);
|
||||||
|
this.trigger("userChangedUnreadStatus", this);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ app.views.NotificationDropdown = app.views.Base.extend({
|
||||||
this.collection.on("pushFront", this.onPushFront.bind(this));
|
this.collection.on("pushFront", this.onPushFront.bind(this));
|
||||||
this.collection.on("pushBack", this.onPushBack.bind(this));
|
this.collection.on("pushBack", this.onPushBack.bind(this));
|
||||||
this.collection.on("finishedLoading", this.finishLoading.bind(this));
|
this.collection.on("finishedLoading", this.finishLoading.bind(this));
|
||||||
|
this.collection.on("change:note_html", this.onNotificationChange.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleDropdown: function(evt){
|
toggleDropdown: function(evt){
|
||||||
|
|
@ -87,6 +88,13 @@ app.views.NotificationDropdown = app.views.Base.extend({
|
||||||
$(node).find(this.avatars.selector).error(this.avatars.fallback);
|
$(node).find(this.avatars.selector).error(this.avatars.fallback);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onNotificationChange: function(notification) {
|
||||||
|
var node = this.dropdownNotifications.find("[data-guid=" + notification.get("id") + "]");
|
||||||
|
$(node).replaceWith(notification.get("note_html"));
|
||||||
|
$(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip();
|
||||||
|
$(node).find(this.avatars.selector).error(this.avatars.fallback);
|
||||||
|
},
|
||||||
|
|
||||||
finishLoading: function() {
|
finishLoading: function() {
|
||||||
app.helpers.timeago(this.dropdownNotifications);
|
app.helpers.timeago(this.dropdownNotifications);
|
||||||
this.updateScrollbar();
|
this.updateScrollbar();
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ describe("app.collections.Notifications", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("correctly binds the change:unread event", function() {
|
it("correctly binds the change:unread event", function() {
|
||||||
spyOn(app.collections.Notifications.prototype, "onChangedUnreadStatus");
|
spyOn(this.target, "trigger");
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
var parsed = this.target.parse({
|
var parsed = this.target.parse({
|
||||||
|
|
@ -216,8 +216,24 @@ describe("app.collections.Notifications", function() {
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
|
|
||||||
parsed[0].set("unread", true);
|
parsed[0].set("unread", true);
|
||||||
|
expect(this.target.trigger).toHaveBeenCalledWith("update");
|
||||||
|
});
|
||||||
|
|
||||||
expect(app.collections.Notifications.prototype.onChangedUnreadStatus).toHaveBeenCalled();
|
it("correctly binds the userChangedUnreadStatus event", function() {
|
||||||
|
spyOn(this.target, "onChangedUnreadStatus");
|
||||||
|
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
var parsed = this.target.parse({
|
||||||
|
unread_count: 15,
|
||||||
|
unread_count_by_type: {reshared: 6},
|
||||||
|
notification_list: [{"reshared": {id: 1}, "type": "reshared"}]
|
||||||
|
});
|
||||||
|
/* eslint-enable camelcase */
|
||||||
|
|
||||||
|
parsed[0].set("unread", true);
|
||||||
|
parsed[0].trigger("userChangedUnreadStatus", parsed[0]);
|
||||||
|
|
||||||
|
expect(this.target.onChangedUnreadStatus).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ describe("app.models.Notification", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("parse", function() {
|
describe("parse", function() {
|
||||||
it("correctly parses the object", function() {
|
beforeEach(function() {
|
||||||
var parsed = this.model.parse({
|
this.response = {
|
||||||
"reshared": {
|
"reshared": {
|
||||||
"id": 45,
|
"id": 45,
|
||||||
"target_type": "Post",
|
"target_type": "Post",
|
||||||
|
|
@ -31,9 +31,8 @@ describe("app.models.Notification", function() {
|
||||||
"note_html": "<html/>"
|
"note_html": "<html/>"
|
||||||
},
|
},
|
||||||
"type": "reshared"
|
"type": "reshared"
|
||||||
});
|
};
|
||||||
|
this.parsedResponse = {
|
||||||
expect(parsed).toEqual({
|
|
||||||
"type": "reshared",
|
"type": "reshared",
|
||||||
"id": 45,
|
"id": 45,
|
||||||
"target_type": "Post",
|
"target_type": "Post",
|
||||||
|
|
@ -43,7 +42,17 @@ describe("app.models.Notification", function() {
|
||||||
"created_at": "2015-10-27T19:56:30.000Z",
|
"created_at": "2015-10-27T19:56:30.000Z",
|
||||||
"updated_at": "2015-10-27T19:56:30.000Z",
|
"updated_at": "2015-10-27T19:56:30.000Z",
|
||||||
"note_html": "<html/>"
|
"note_html": "<html/>"
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("correctly parses the object", function() {
|
||||||
|
var parsed = this.model.parse(this.response);
|
||||||
|
expect(parsed).toEqual(this.parsedResponse);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("correctly parses the object twice", function() {
|
||||||
|
var parsed = this.model.parse(this.parsedResponse);
|
||||||
|
expect(parsed).toEqual(this.parsedResponse);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -67,6 +76,7 @@ describe("app.models.Notification", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.target = new app.models.Notification({"reshared": {id: 16}, "type": "reshared"});
|
this.target = new app.models.Notification({"reshared": {id: 16}, "type": "reshared"});
|
||||||
spyOn(app.models.Notification.prototype, "set").and.callThrough();
|
spyOn(app.models.Notification.prototype, "set").and.callThrough();
|
||||||
|
spyOn(app.models.Notification.prototype, "trigger");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls calls ajax with correct parameters and sets 'unread' attribute", function() {
|
it("calls calls ajax with correct parameters and sets 'unread' attribute", function() {
|
||||||
|
|
@ -80,6 +90,7 @@ describe("app.models.Notification", function() {
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
expect(call.method).toEqual("PUT");
|
expect(call.method).toEqual("PUT");
|
||||||
expect(app.models.Notification.prototype.set).toHaveBeenCalledWith("unread", true);
|
expect(app.models.Notification.prototype.set).toHaveBeenCalledWith("unread", true);
|
||||||
|
expect(app.models.Notification.prototype.trigger).toHaveBeenCalledWith("userChangedUnreadStatus", this.target);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,11 @@ describe("app.views.NotificationDropdown", function() {
|
||||||
this.view.collection.off("pushFront");
|
this.view.collection.off("pushFront");
|
||||||
this.view.collection.off("pushBack");
|
this.view.collection.off("pushBack");
|
||||||
this.view.collection.off("finishedLoading");
|
this.view.collection.off("finishedLoading");
|
||||||
|
this.view.collection.off("change:note_html");
|
||||||
spyOn(this.view, "onPushFront");
|
spyOn(this.view, "onPushFront");
|
||||||
spyOn(this.view, "onPushBack");
|
spyOn(this.view, "onPushBack");
|
||||||
spyOn(this.view, "finishLoading");
|
spyOn(this.view, "finishLoading");
|
||||||
|
spyOn(this.view, "onNotificationChange");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("binds collection events", function() {
|
it("binds collection events", function() {
|
||||||
|
|
@ -26,10 +28,12 @@ describe("app.views.NotificationDropdown", function() {
|
||||||
this.collection.trigger("pushFront");
|
this.collection.trigger("pushFront");
|
||||||
this.collection.trigger("pushBack");
|
this.collection.trigger("pushBack");
|
||||||
this.collection.trigger("finishedLoading");
|
this.collection.trigger("finishedLoading");
|
||||||
|
this.collection.trigger("change:note_html");
|
||||||
|
|
||||||
expect(this.view.onPushFront).toHaveBeenCalled();
|
expect(this.view.onPushFront).toHaveBeenCalled();
|
||||||
expect(this.view.onPushBack).toHaveBeenCalled();
|
expect(this.view.onPushBack).toHaveBeenCalled();
|
||||||
expect(this.view.finishLoading).toHaveBeenCalled();
|
expect(this.view.finishLoading).toHaveBeenCalled();
|
||||||
|
expect(this.view.onNotificationChange).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue