diff --git a/Changelog.md b/Changelog.md
index 922bfa4ea..7a934236a 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -98,7 +98,7 @@ diaspora.yml file**. The existing settings from 0.4.x and before will not work a
* Display photos on the profile page as thumbnails [#5521](https://github.com/diaspora/diaspora/pull/5521)
* Unify not connected pages (sign in, sign up, forgot password) [#5391](https://github.com/diaspora/diaspora/pull/5391)
* Port remaining stream pages to Bootstrap [#5715](https://github.com/diaspora/diaspora/pull/5715)
-* Partial Backbone port of the notification dropdown [#5707](https://github.com/diaspora/diaspora/pull/5707)
+* Port notification dropdown to Backbone [#5707](https://github.com/diaspora/diaspora/pull/5707) [#5761](https://github.com/diaspora/diaspora/pull/5761)
* Add rounded corners for avatars [#5733](https://github.com/diaspora/diaspora/pull/5733)
* Move registration form to a partial [#5764](https://github.com/diaspora/diaspora/pull/5764)
* Add tests for liking and unliking posts [#5741](https://github.com/diaspora/diaspora/pull/5741)
diff --git a/app/assets/javascripts/app/views/header_view.js b/app/assets/javascripts/app/views/header_view.js
index a309942e7..814ef3a87 100644
--- a/app/assets/javascripts/app/views/header_view.js
+++ b/app/assets/javascripts/app/views/header_view.js
@@ -2,44 +2,47 @@
app.views.Header = app.views.Base.extend({
- templateName : "header",
+ templateName: "header",
- className : "dark-header",
+ className: "dark-header",
- events : {
- "click ul.dropdown li:first-child" : "toggleDropdown",
+ events: {
+ "click ul.dropdown li:first-child": "toggleUserDropdown",
"focusin #q": "toggleSearchActive",
"focusout #q": "toggleSearchActive"
},
- initialize : function() {
- $(document.body).click($.proxy(this.hideDropdown, this));
+ initialize: function(){
+ $(document.body).click($.proxy(this.hideUserDropdown, this));
+
return this;
},
postRenderTemplate: function(){
new app.views.Notifications({ el: '#notification_dropdown' });
+ new app.views.NotificationDropdown({ el: '#notification_badge' });
+ new app.views.Search({ el: '#header-search-form' });
},
- menuElement : function() { return this.$("ul.dropdown"); },
+ menuElement: function(){ return this.$("ul.dropdown"); },
- toggleDropdown : function(evt) {
+ toggleUserDropdown: function(evt){
if(evt){ evt.preventDefault(); }
this.menuElement().toggleClass("active");
- if($.browser.msie) {
+ if($.browser.msie){
this.$("header").toggleClass('ie-user-menu-active');
}
},
- hideDropdown : function(evt) {
- if(this.menuElement().hasClass("active") && !$(evt.target).parents("#user_menu").length) {
+ hideUserDropdown: function(evt){
+ if(this.menuElement().hasClass("active") && !$(evt.target).parents("#user_menu").length){
this.menuElement().removeClass("active");
}
},
- toggleSearchActive: function(ev) {
+ toggleSearchActive: function(ev){
// jQuery produces two events for focus/blur (for bubbling)
// don't rely on which event arrives first, by allowing for both variants
var is_active = (_.indexOf(['focus','focusin'], ev.type) !== -1);
@@ -48,4 +51,3 @@ app.views.Header = app.views.Base.extend({
}
});
// @license-end
-
diff --git a/app/assets/javascripts/app/views/notification_dropdown_view.js b/app/assets/javascripts/app/views/notification_dropdown_view.js
new file mode 100644
index 000000000..a2c7525db
--- /dev/null
+++ b/app/assets/javascripts/app/views/notification_dropdown_view.js
@@ -0,0 +1,118 @@
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
+
+app.views.NotificationDropdown = app.views.Base.extend({
+ events:{
+ "click #notifications-badge": "toggleDropdown"
+ },
+
+ initialize: function(){
+ $(document.body).click($.proxy(this.hideDropdown, 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');
+ },
+
+ toggleDropdown: function(evt){
+ evt.preventDefault();
+ evt.stopPropagation();
+ if(this.dropdownShowing()){ this.hideDropdown(evt); }
+ else{ this.showDropdown(); }
+ },
+
+ dropdownShowing: function(){
+ return this.dropdown.css('display') === 'block';
+ },
+
+ showDropdown: function(){
+ this.resetParams();
+ this.ajaxLoader.show();
+ this.badge.addClass('active');
+ this.dropdown.css('display', 'block');
+ this.dropdownNotifications.addClass('loading');
+ this.getNotifications();
+ },
+
+ hideDropdown: function(evt){
+ var inDropdown = $(evt.target).parents().is(this.dropdown);
+ var inHovercard = $.contains(app.hovercard.el, evt.target);
+ if(!inDropdown && !inHovercard && this.dropdownShowing()){
+ this.badge.removeClass('active');
+ this.dropdown.css('display', 'none');
+ this.dropdownNotifications.perfectScrollbar('destroy');
+ }
+ },
+
+ dropdownScroll: function(){
+ var isLoading = ($('.loading').length === 1);
+ if (this.isBottom() && this.hasMoreNotifs && !isLoading){
+ this.dropdownNotifications.addClass('loading');
+ this.getNotifications();
+ }
+ },
+
+ 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_path(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('img').fadeTo(200, 0, function(){
+ self.ajaxLoader.hide(300, function(){
+ self.ajaxLoader.find('img').css('opacity', 1);
+ });
+ });
+ },
+
+ 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').tooltip('destroy').tooltip();
+ }
+ });
+ });
+
+ this.hideAjaxLoader();
+
+ app.helpers.timeago(this.dropdownNotifications);
+
+ this.dropdownNotifications.perfectScrollbar('destroy').perfectScrollbar();
+ this.dropdownNotifications.removeClass('loading');
+ this.dropdownNotifications.scroll(function(){
+ self.dropdownScroll();
+ });
+ }
+});
+// @license-end
diff --git a/app/assets/javascripts/app/views/search_view.js b/app/assets/javascripts/app/views/search_view.js
new file mode 100644
index 000000000..3453a969e
--- /dev/null
+++ b/app/assets/javascripts/app/views/search_view.js
@@ -0,0 +1,70 @@
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
+app.views.Search = app.views.Base.extend({
+ initialize: function(){
+ this.searchFormAction = this.$el.attr('action');
+ this.searchInput = this.$('input[type="search"]');
+ this.searchInputName = this.$('input[type="search"]').attr('name');
+ this.searchInputHandle = this.$('input[type="search"]').attr('handle');
+ this.options = {
+ cacheLength: 15,
+ delay: 800,
+ extraParams: {limit: 4},
+ formatItem: this.formatItem,
+ formatResult: this.formatResult,
+ max: 5,
+ minChars: 2,
+ onSelect: this.selectItemCallback,
+ parse: this.parse,
+ scroll: false,
+ context: this
+ };
+
+ var self = this;
+ this.searchInput.autocomplete(self.searchFormAction + '.json',
+ $.extend(self.options, { element: self.searchInput }));
+ },
+
+ formatItem: function(row){
+ if(typeof row.search !== 'undefined') { return Diaspora.I18n.t('search_for', row); }
+ else {
+ var item = '';
+ if (row.avatar) { item += ''; }
+ item += row.name;
+ if (row.handle) { item += '