Skip to content

Commit

Permalink
Merge branch 'next-minor' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
svbergerem committed Nov 18, 2016
2 parents 73d3529 + af331bf commit 8cd2605
Show file tree
Hide file tree
Showing 20 changed files with 864 additions and 293 deletions.
2 changes: 2 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
* Add a dark color theme [#7152](https://github.com/diaspora/diaspora/pull/7152)
* Added setting for custom changelog URL [#7166](https://github.com/diaspora/diaspora/pull/7166)
* Show more information of recipients on conversation creation [#7129](https://github.com/diaspora/diaspora/pull/7129)
* Update notifications every 5 minutes and when opening the notification dropdown [#6952](https://github.com/diaspora/diaspora/pull/6952)
* Show browser notifications when receiving new unread notifications [#6952](https://github.com/diaspora/diaspora/pull/6952)

# 0.6.1.0

Expand Down
1 change: 1 addition & 0 deletions app/assets/javascripts/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ var app = {

setupHeader: function() {
if(app.currentUser.authenticated()) {
app.notificationsCollection = new app.collections.Notifications();
app.header = new app.views.Header();
$("header").prepend(app.header.el);
app.header.render();
Expand Down
118 changes: 118 additions & 0 deletions app/assets/javascripts/app/collections/notifications.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
app.collections.Notifications = Backbone.Collection.extend({
model: app.models.Notification,
// URL parameter
/* eslint-disable camelcase */
url: Routes.notifications({per_page: 10, page: 1}),
/* eslint-enable camelcase */
page: 2,
perPage: 5,
unreadCount: 0,
unreadCountByType: {},
timeout: 300000, // 5 minutes

initialize: function() {
this.pollNotifications();

setTimeout(function() {
setInterval(this.pollNotifications.bind(this), this.timeout);
}.bind(this), this.timeout);

Diaspora.BrowserNotification.requestPermission();
},

pollNotifications: function() {
var unreadCountBefore = this.unreadCount;
this.fetch();

this.once("finishedLoading", function() {
if (unreadCountBefore < this.unreadCount) {
Diaspora.BrowserNotification.spawnNotification(
Diaspora.I18n.t("notifications.new_notifications", {count: this.unreadCount}));
}
}, this);
},

fetch: function(options) {
options = options || {};
options.remove = false;
options.merge = true;
options.parse = true;
Backbone.Collection.prototype.fetch.apply(this, [options]);
},

fetchMore: function() {
var hasMoreNotifications = (this.page * this.perPage) <= this.length;
// There are more notifications to load on the current page
if (hasMoreNotifications) {
this.page++;
// URL parameter
/* eslint-disable camelcase */
var route = Routes.notifications({per_page: this.perPage, page: this.page});
/* eslint-enable camelcase */
this.fetch({url: route, pushBack: true});
}
},

/**
* Adds new models to the collection at the end or at the beginning of the collection and
* then fires an event for each model of the collection. It will fire a different event
* based on whether the models were added at the end (typically when the scroll triggers to load more
* notifications) or at the beginning (new notifications have been added to the front of the list).
*/
set: function(items, options) {
options = options || {};
options.at = options.pushBack ? this.length : 0;

// Retreive back the new created models
var models = [];
var accu = function(model) { models.push(model); };
this.on("add", accu);
Backbone.Collection.prototype.set.apply(this, [items, options]);
this.off("add", accu);

if (options.pushBack) {
models.forEach(function(model) { this.trigger("pushBack", model); }.bind(this));
} else {
// Fires events in the reverse order so that the first event is prepended in first position
models.reverse();
models.forEach(function(model) { this.trigger("pushFront", model); }.bind(this));
}
this.trigger("finishedLoading");
},

parse: function(response) {
this.unreadCount = response.unread_count;
this.unreadCountByType = response.unread_count_by_type;

return _.map(response.notification_list, function(item) {
/* eslint-disable new-cap */
var model = new this.model(item);
/* eslint-enable new-cap */
model.on("change:unread", this.onChangedUnreadStatus.bind(this));
return model;
}.bind(this));
},

setAllRead: function() {
this.forEach(function(model) { model.setRead(); });
},

setRead: function(guid) {
this.find(function(model) { return model.guid === guid; }).setRead();
},

setUnread: function(guid) {
this.find(function(model) { return model.guid === guid; }).setUnread();
},

onChangedUnreadStatus: function(model) {
if (model.get("unread") === true) {
this.unreadCount++;
this.unreadCountByType[model.get("type")]++;
} else {
this.unreadCount = Math.max(this.unreadCount - 1, 0);
this.unreadCountByType[model.get("type")] = Math.max(this.unreadCountByType[model.get("type")] - 1, 0);
}
this.trigger("update");
}
});
69 changes: 69 additions & 0 deletions app/assets/javascripts/app/models/notification.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
app.models.Notification = Backbone.Model.extend({
constructor: function(attributes, options) {
options = options || {};
options.parse = true;
Backbone.Model.apply(this, [attributes, options]);
this.guid = this.get("id");
},

/**
* Flattens the notification object returned by the server.
*
* The server returns an object that looks like:
*
* {
* "reshared": {
* "id": 45,
* "target_type": "Post",
* "target_id": 11,
* "recipient_id": 1,
* "unread": true,
* "created_at": "2015-10-27T19:56:30.000Z",
* "updated_at": "2015-10-27T19:56:30.000Z",
* "note_html": <html/>
* },
* "type": "reshared"
* }
*
* The returned object looks like:
*
* {
* "type": "reshared",
* "id": 45,
* "target_type": "Post",
* "target_id": 11,
* "recipient_id": 1,
* "unread": true,
* "created_at": "2015-10-27T19:56:30.000Z",
* "updated_at": "2015-10-27T19:56:30.000Z",
* "note_html": <html/>,
* }
*/
parse: function(response) {
var result = {type: response.type};
result = $.extend(result, response[result.type]);
return result;
},

setRead: function() {
this.setUnreadStatus(false);
},

setUnread: function() {
this.setUnreadStatus(true);
},

setUnreadStatus: function(state) {
if (this.get("unread") !== state) {
$.ajax({
url: Routes.notification(this.guid),
/* eslint-disable camelcase */
data: {set_unread: state},
/* eslint-enable camelcase */
type: "PUT",
context: this,
success: function() { this.set("unread", state); }
});
}
}
});
2 changes: 1 addition & 1 deletion app/assets/javascripts/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ app.Router = Backbone.Router.extend({
notifications: function() {
this._loadContacts();
this.renderAspectMembershipDropdowns($(document));
new app.views.Notifications({el: "#notifications_container"});
new app.views.Notifications({el: "#notifications_container", collection: app.notificationsCollection});
},

peopleSearch: function() {
Expand Down
10 changes: 5 additions & 5 deletions app/assets/javascripts/app/views/header_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ app.views.Header = app.views.Base.extend({
});
},

postRenderTemplate: function(){
new app.views.Notifications({ el: "#notification-dropdown" });
this.notificationDropdown = new app.views.NotificationDropdown({ el: "#notification-dropdown" });
new app.views.Search({ el: "#header-search-form" });
postRenderTemplate: function() {
new app.views.Notifications({el: "#notification-dropdown", collection: app.notificationsCollection});
new app.views.NotificationDropdown({el: "#notification-dropdown", collection: app.notificationsCollection});
new app.views.Search({el: "#header-search-form"});
},

menuElement: function(){ return this.$("ul.dropdown"); },
menuElement: function() { return this.$("ul.dropdown"); }
});
// @license-end
71 changes: 24 additions & 47 deletions app/assets/javascripts/app/views/notification_dropdown_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@ app.views.NotificationDropdown = app.views.Base.extend({
},

initialize: function(){
$(document.body).click($.proxy(this.hideDropdown, this));
$(document.body).click(this.hideDropdown.bind(this));

this.notifications = [];
this.perPage = 5;
this.hasMoreNotifs = true;
this.badge = this.$el;
this.dropdown = $("#notification-dropdown");
this.dropdownNotifications = this.dropdown.find(".notifications");
this.ajaxLoader = this.dropdown.find(".ajax-loader");
this.perfectScrollbarInitialized = false;
this.dropdownNotifications.scroll(this.dropdownScroll.bind(this));
this.bindCollectionEvents();
},

bindCollectionEvents: function() {
this.collection.on("pushFront", this.onPushFront.bind(this));
this.collection.on("pushBack", this.onPushBack.bind(this));
this.collection.on("finishedLoading", this.finishLoading.bind(this));
},

toggleDropdown: function(evt){
Expand All @@ -31,12 +36,11 @@ app.views.NotificationDropdown = app.views.Base.extend({
},

showDropdown: function(){
this.resetParams();
this.ajaxLoader.show();
this.dropdown.addClass("dropdown-open");
this.updateScrollbar();
this.dropdownNotifications.addClass("loading");
this.getNotifications();
this.collection.fetch();
},

hideDropdown: function(evt){
Expand All @@ -50,40 +54,18 @@ app.views.NotificationDropdown = app.views.Base.extend({

dropdownScroll: function(){
var isLoading = ($(".loading").length === 1);
if (this.isBottom() && this.hasMoreNotifs && !isLoading){
if (this.isBottom() && !isLoading) {
this.dropdownNotifications.addClass("loading");
this.getNotifications();
this.collection.fetchMore();
}
},

getParams: function(){
if(this.notifications.length === 0){ return{ per_page: 10, page: 1 }; }
else{ return{ per_page: this.perPage, page: this.nextPage }; }
},

resetParams: function(){
this.notifications.length = 0;
this.hasMoreNotifs = true;
delete this.nextPage;
},

isBottom: function(){
var bottom = this.dropdownNotifications.prop("scrollHeight") - this.dropdownNotifications.height();
var currentPosition = this.dropdownNotifications.scrollTop();
return currentPosition + 50 >= bottom;
},

getNotifications: function(){
var self = this;
$.getJSON(Routes.notifications(this.getParams()), function(notifications){
$.each(notifications, function(){ self.notifications.push(this); });
self.hasMoreNotifs = notifications.length >= self.perPage;
if(self.nextPage){ self.nextPage++; }
else { self.nextPage = 3; }
self.renderNotifications();
});
},

hideAjaxLoader: function(){
var self = this;
this.ajaxLoader.find(".spinner").fadeTo(200, 0, function(){
Expand All @@ -93,28 +75,23 @@ app.views.NotificationDropdown = app.views.Base.extend({
});
},

renderNotifications: function(){
var self = this;
this.dropdownNotifications.find(".media.stream-element").remove();
$.each(self.notifications, function(index, notifications){
$.each(notifications, function(index, notification){
if($.inArray(notification, notifications) === -1){
var node = self.dropdownNotifications.append(notification.note_html);
$(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip();
$(node).find(self.avatars.selector).error(self.avatars.fallback);
}
});
});
onPushBack: function(notification) {
var node = this.dropdownNotifications.append(notification.get("note_html"));
$(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip();
$(node).find(this.avatars.selector).error(this.avatars.fallback);
},

this.hideAjaxLoader();
onPushFront: function(notification) {
var node = this.dropdownNotifications.prepend(notification.get("note_html"));
$(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip();
$(node).find(this.avatars.selector).error(this.avatars.fallback);
},

finishLoading: function() {
app.helpers.timeago(this.dropdownNotifications);

this.updateScrollbar();
this.hideAjaxLoader();
this.dropdownNotifications.removeClass("loading");
this.dropdownNotifications.scroll(function(){
self.dropdownScroll();
});
},

updateScrollbar: function() {
Expand Down
Loading

0 comments on commit 8cd2605

Please sign in to comment.