Merge pull request #5761 from AugierLe42e/port-notifications-backbone-part2
Port notifications to backbone part. 2
This commit is contained in:
commit
c3bf9dd831
13 changed files with 332 additions and 259 deletions
|
|
@ -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)
|
* 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)
|
* 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)
|
* 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)
|
* 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)
|
* 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)
|
* Add tests for liking and unliking posts [#5741](https://github.com/diaspora/diaspora/pull/5741)
|
||||||
|
|
|
||||||
|
|
@ -2,44 +2,47 @@
|
||||||
|
|
||||||
app.views.Header = app.views.Base.extend({
|
app.views.Header = app.views.Base.extend({
|
||||||
|
|
||||||
templateName : "header",
|
templateName: "header",
|
||||||
|
|
||||||
className : "dark-header",
|
className: "dark-header",
|
||||||
|
|
||||||
events : {
|
events: {
|
||||||
"click ul.dropdown li:first-child" : "toggleDropdown",
|
"click ul.dropdown li:first-child": "toggleUserDropdown",
|
||||||
"focusin #q": "toggleSearchActive",
|
"focusin #q": "toggleSearchActive",
|
||||||
"focusout #q": "toggleSearchActive"
|
"focusout #q": "toggleSearchActive"
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize : function() {
|
initialize: function(){
|
||||||
$(document.body).click($.proxy(this.hideDropdown, this));
|
$(document.body).click($.proxy(this.hideUserDropdown, this));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
postRenderTemplate: function(){
|
postRenderTemplate: function(){
|
||||||
new app.views.Notifications({ el: '#notification_dropdown' });
|
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(); }
|
if(evt){ evt.preventDefault(); }
|
||||||
|
|
||||||
this.menuElement().toggleClass("active");
|
this.menuElement().toggleClass("active");
|
||||||
|
|
||||||
if($.browser.msie) {
|
if($.browser.msie){
|
||||||
this.$("header").toggleClass('ie-user-menu-active');
|
this.$("header").toggleClass('ie-user-menu-active');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
hideDropdown : function(evt) {
|
hideUserDropdown: function(evt){
|
||||||
if(this.menuElement().hasClass("active") && !$(evt.target).parents("#user_menu").length) {
|
if(this.menuElement().hasClass("active") && !$(evt.target).parents("#user_menu").length){
|
||||||
this.menuElement().removeClass("active");
|
this.menuElement().removeClass("active");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleSearchActive: function(ev) {
|
toggleSearchActive: function(ev){
|
||||||
// jQuery produces two events for focus/blur (for bubbling)
|
// jQuery produces two events for focus/blur (for bubbling)
|
||||||
// don't rely on which event arrives first, by allowing for both variants
|
// don't rely on which event arrives first, by allowing for both variants
|
||||||
var is_active = (_.indexOf(['focus','focusin'], ev.type) !== -1);
|
var is_active = (_.indexOf(['focus','focusin'], ev.type) !== -1);
|
||||||
|
|
@ -48,4 +51,3 @@ app.views.Header = app.views.Base.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// @license-end
|
// @license-end
|
||||||
|
|
||||||
|
|
|
||||||
118
app/assets/javascripts/app/views/notification_dropdown_view.js
Normal file
118
app/assets/javascripts/app/views/notification_dropdown_view.js
Normal file
|
|
@ -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
|
||||||
70
app/assets/javascripts/app/views/search_view.js
Normal file
70
app/assets/javascripts/app/views/search_view.js
Normal file
|
|
@ -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 += '<img src="' + row.avatar + '" class="avatar"/>'; }
|
||||||
|
item += row.name;
|
||||||
|
if (row.handle) { item += '<div class="search_handle">' + row.handle + '</div>'; }
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
formatResult: function(row){ return Handlebars.Utils.escapeExpression(row.name); },
|
||||||
|
|
||||||
|
parse: function(data) {
|
||||||
|
var self = this.context;
|
||||||
|
|
||||||
|
var results = data.map(function(person){
|
||||||
|
person.name = self.formatResult(person);
|
||||||
|
return {data : person, value : person.name};
|
||||||
|
});
|
||||||
|
|
||||||
|
results.push({
|
||||||
|
data: {
|
||||||
|
name: self.searchInput.val(),
|
||||||
|
url: self.searchFormAction + '?' + self.searchInputName + '=' + self.searchInput.val(),
|
||||||
|
search: true
|
||||||
|
},
|
||||||
|
value: self.searchInput.val()
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
},
|
||||||
|
|
||||||
|
selectItemCallback: function(evt, data, formatted){
|
||||||
|
if(data.search === true){
|
||||||
|
window.location = this.searchFormAction + '?' + this.searchInputName + '=' + data.name;
|
||||||
|
}
|
||||||
|
else{ // The actual result
|
||||||
|
this.options.element.val(formatted);
|
||||||
|
window.location = data.url ? data.url : '/tags/' + data.name.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// @license-ends
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var Header = function() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.subscribe("widget/ready", function(evt, header) {
|
|
||||||
self.notifications = self.instantiate("Notifications",
|
|
||||||
header.find("#notification_badge .badge_count"),
|
|
||||||
header.find("#notification_dropdown")
|
|
||||||
);
|
|
||||||
|
|
||||||
self.notificationsDropdown = self.instantiate("NotificationsDropdown",
|
|
||||||
header.find("#notification_badge"),
|
|
||||||
header.find("#notification_dropdown")
|
|
||||||
);
|
|
||||||
|
|
||||||
self.search = self.instantiate("Search", header.find(".search_form"));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Diaspora.Widgets.Header = Header;
|
|
||||||
})();
|
|
||||||
// @license-end
|
|
||||||
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var NotificationDropdown = function() {
|
|
||||||
var self = this;
|
|
||||||
var currentPage = 2;
|
|
||||||
var notificationsLoaded = 10;
|
|
||||||
|
|
||||||
this.subscribe("widget/ready",function(evt, badge, dropdown) {
|
|
||||||
$.extend(self, {
|
|
||||||
badge: badge,
|
|
||||||
badgeLink: badge.find("a"),
|
|
||||||
documentBody: $(document.body),
|
|
||||||
dropdown: dropdown,
|
|
||||||
dropdownNotifications: dropdown.find(".notifications"),
|
|
||||||
ajaxLoader: dropdown.find(".ajax_loader")
|
|
||||||
});
|
|
||||||
|
|
||||||
if( ! $.browser.msie ) {
|
|
||||||
self.badge.on('click', self.badgeLink, function(evt){
|
|
||||||
evt.preventDefault();
|
|
||||||
evt.stopPropagation();
|
|
||||||
if (self.dropdownShowing()){
|
|
||||||
self.hideDropdown();
|
|
||||||
} else {
|
|
||||||
self.showDropdown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
self.documentBody.click(function(evt) {
|
|
||||||
var inDropdown = $(evt.target).parents().is(self.dropdown);
|
|
||||||
var inHovercard = $.contains(app.hovercard.el, evt.target);
|
|
||||||
|
|
||||||
if(!inDropdown && !inHovercard && self.dropdownShowing()) {
|
|
||||||
self.badgeLink.click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
this.dropdownShowing = function() {
|
|
||||||
return this.dropdown.css("display") === "block";
|
|
||||||
};
|
|
||||||
|
|
||||||
this.showDropdown = function() {
|
|
||||||
self.ajaxLoader.show();
|
|
||||||
self.badge.addClass("active");
|
|
||||||
self.dropdown.css("display", "block");
|
|
||||||
self.dropdownNotifications.addClass("loading");
|
|
||||||
self.getNotifications();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
this.hideDropdown = function() {
|
|
||||||
self.badge.removeClass("active");
|
|
||||||
self.dropdown.css("display", "none");
|
|
||||||
self.dropdownNotifications.perfectScrollbar('destroy');
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getMoreNotifications = function(page) {
|
|
||||||
$.getJSON("/notifications?per_page=5&page=" + page, function(notifications) {
|
|
||||||
for(var i = 0; i < notifications.length; ++i)
|
|
||||||
self.notifications.push(notifications[i]);
|
|
||||||
notificationsLoaded += 5;
|
|
||||||
self.renderNotifications();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.hideAjaxLoader = function(){
|
|
||||||
self.ajaxLoader.find('img').fadeTo(200, 0, function(){
|
|
||||||
self.ajaxLoader.hide(300, function(){
|
|
||||||
self.ajaxLoader.find('img').css('opacity', 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getNotifications = function() {
|
|
||||||
$.getJSON("/notifications?per_page="+notificationsLoaded, function(notifications) {
|
|
||||||
self.notifications = notifications;
|
|
||||||
self.renderNotifications();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.renderNotifications = function() {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
self.hideAjaxLoader();
|
|
||||||
|
|
||||||
app.helpers.timeago(self.dropdownNotifications);
|
|
||||||
|
|
||||||
self.dropdownNotifications.perfectScrollbar('destroy').perfectScrollbar();
|
|
||||||
var isLoading = false;
|
|
||||||
self.dropdownNotifications.removeClass("loading");
|
|
||||||
//Infinite Scrolling
|
|
||||||
self.dropdownNotifications.scroll(function() {
|
|
||||||
var bottom = self.dropdownNotifications.prop('scrollHeight') - self.dropdownNotifications.height();
|
|
||||||
var currentPosition = self.dropdownNotifications.scrollTop();
|
|
||||||
isLoading = ($('.loading').length === 1);
|
|
||||||
if (currentPosition + 50 >= bottom && notificationsLoaded <= self.notifications.length && !isLoading) {
|
|
||||||
self.dropdownNotifications.addClass("loading");
|
|
||||||
self.getMoreNotifications(++currentPage);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Diaspora.Widgets.NotificationsDropdown = NotificationDropdown;
|
|
||||||
})();
|
|
||||||
// @license-end
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var Search = function() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.subscribe("widget/ready", function(evt, searchForm) {
|
|
||||||
$.extend(self, {
|
|
||||||
searchForm: searchForm,
|
|
||||||
searchFormAction: searchForm.attr("action"),
|
|
||||||
searchInput: searchForm.find("input[type='search']"),
|
|
||||||
searchInputName: searchForm.find("input[type='search']").attr("name"),
|
|
||||||
searchInputHandle: searchForm.find("input[type='search']").attr("handle"),
|
|
||||||
options: {
|
|
||||||
cacheLength : 15,
|
|
||||||
delay : 800,
|
|
||||||
extraParams : {limit : 4},
|
|
||||||
formatItem : self.formatItem,
|
|
||||||
formatResult : self.formatResult,
|
|
||||||
max : 5,
|
|
||||||
minChars : 2,
|
|
||||||
onSelect: self.selectItemCallback,
|
|
||||||
parse : self.parse,
|
|
||||||
scroll : false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.searchInput.autocomplete(self.searchFormAction + ".json", $.extend(self.options, {
|
|
||||||
element: self.searchInput
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.formatItem = function(row) {
|
|
||||||
if (typeof row.search !== "undefined") {
|
|
||||||
return Diaspora.I18n.t("search_for", row);
|
|
||||||
} else {
|
|
||||||
var item = "";
|
|
||||||
if (row.avatar) {
|
|
||||||
item += "<img src='"+ row.avatar +"' class='avatar'/>";
|
|
||||||
}
|
|
||||||
item += row.name;
|
|
||||||
if (row.handle) {
|
|
||||||
item += "<div class='search_handle'>" + row.handle + "</div>";
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.formatResult = function(row) {
|
|
||||||
return Handlebars.Utils.escapeExpression(row.name);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.parse = function(data) {
|
|
||||||
var results = data.map(function(person){
|
|
||||||
person['name'] = Handlebars.Utils.escapeExpression(person['name']);
|
|
||||||
return {data : person, value : person['name']};
|
|
||||||
});
|
|
||||||
|
|
||||||
results.push({
|
|
||||||
data: {
|
|
||||||
name: self.searchInput.val(),
|
|
||||||
url: self.searchFormAction + "?" + self.searchInputName + "=" + self.searchInput.val(),
|
|
||||||
search: true
|
|
||||||
},
|
|
||||||
value: self.searchInput.val()
|
|
||||||
});
|
|
||||||
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.selectItemCallback = function(evt, data, formatted) {
|
|
||||||
if (data['search'] === true) { // The placeholder "search for" result
|
|
||||||
window.location = self.searchFormAction + '?' + self.searchInputName + '=' + data['name'];
|
|
||||||
} else { // The actual result
|
|
||||||
self.options.element.val(formatted);
|
|
||||||
window.location = data['url'] ? data['url'] : "/tags/" + data['name'].substring(1); // we don't want the #-character
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Diaspora.Widgets.Search = Search;
|
|
||||||
})();
|
|
||||||
// @license-end
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
<div id="nav_badges">
|
<div id="nav_badges">
|
||||||
<div class="badge badge-inverse" id="notification_badge">
|
<div class="badge badge-inverse" id="notification_badge">
|
||||||
<div class="icons-notifications_grey" >
|
<div class="icons-notifications_grey" >
|
||||||
<a href="/notifications" title="{{t "header.notifications"}}" class="badge_link" >
|
<a id="notifications-badge" href="/notifications" title="{{t "header.notifications"}}" class="badge_link" >
|
||||||
<div class="badge_count {{#unless current_user.notifications_count}} hidden {{/unless}}">
|
<div class="badge_count {{#unless current_user.notifications_count}} hidden {{/unless}}">
|
||||||
{{current_user.notifications_count}}
|
{{current_user.notifications_count}}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -87,7 +87,7 @@
|
||||||
|
|
||||||
|
|
||||||
<div id="global_search">
|
<div id="global_search">
|
||||||
<form accept-charset="UTF-8" action="/search" class="search_form" method="get">
|
<form id="header-search-form" accept-charset="UTF-8" action="/search" class="search_form" method="get">
|
||||||
<input name="utf8" type="hidden" value="✓">
|
<input name="utf8" type="hidden" value="✓">
|
||||||
<input id="q" name="q" placeholder="{{t "header.search"}}" results="5" type="search" autocomplete="off" class="ac_input">
|
<input id="q" name="q" placeholder="{{t "header.search"}}" results="5" type="search" autocomplete="off" class="ac_input">
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -54,20 +54,20 @@ describe("app.views.Header", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#toggleDropdown", function() {
|
describe("#toggleUserDropdown", function() {
|
||||||
it("adds the class 'active'", function() {
|
it("adds the class 'active'", function() {
|
||||||
expect(this.view.$(".dropdown")).not.toHaveClass("active");
|
expect(this.view.$(".dropdown")).not.toHaveClass("active");
|
||||||
this.view.toggleDropdown($.Event());
|
this.view.toggleUserDropdown($.Event());
|
||||||
expect(this.view.$(".dropdown")).toHaveClass("active");
|
expect(this.view.$(".dropdown")).toHaveClass("active");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#hideDropdown", function() {
|
describe("#hideUserDropdown", function() {
|
||||||
it("removes the class 'active' if the user clicks anywhere that isn't the menu element", function() {
|
it("removes the class 'active' if the user clicks anywhere that isn't the menu element", function() {
|
||||||
this.view.toggleDropdown($.Event());
|
this.view.toggleUserDropdown($.Event());
|
||||||
expect(this.view.$(".dropdown")).toHaveClass("active");
|
expect(this.view.$(".dropdown")).toHaveClass("active");
|
||||||
|
|
||||||
this.view.hideDropdown($.Event());
|
this.view.hideUserDropdown($.Event());
|
||||||
expect(this.view.$(".dropdown")).not.toHaveClass("active");
|
expect(this.view.$(".dropdown")).not.toHaveClass("active");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
107
spec/javascripts/app/views/notification_dropdown_view_spec.js
Normal file
107
spec/javascripts/app/views/notification_dropdown_view_spec.js
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
describe('app.views.NotificationDropdown', function() {
|
||||||
|
beforeEach(function (){
|
||||||
|
spec.loadFixture('notifications');
|
||||||
|
this.header = new app.views.Header();
|
||||||
|
$("header").prepend(this.header.el);
|
||||||
|
this.header.render();
|
||||||
|
this.view = new app.views.NotificationDropdown({el: '#notification_badge'});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('showDropdown', function(){
|
||||||
|
it('Calls resetParam()', function(){
|
||||||
|
spyOn(this.view, 'resetParams');
|
||||||
|
this.view.showDropdown();
|
||||||
|
expect(this.view.resetParams).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
it('Changes CSS', function(){
|
||||||
|
this.view.showDropdown();
|
||||||
|
expect($('#notification_dropdown').css('display')).toBe('block');
|
||||||
|
});
|
||||||
|
it('Calls getNotifications()', function(){
|
||||||
|
spyOn(this.view, 'getNotifications');
|
||||||
|
this.view.showDropdown();
|
||||||
|
expect(this.view.getNotifications).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('dropdownScroll', function(){
|
||||||
|
it('Calls getNotifications if is at the bottom and has more notifications to load', function(){
|
||||||
|
this.view.isBottom = function(){ return true; };
|
||||||
|
this.view.hasMoreNotifs = true;
|
||||||
|
spyOn(this.view, 'getNotifications');
|
||||||
|
this.view.dropdownScroll();
|
||||||
|
expect(this.view.getNotifications).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doesn't call getNotifications if is not at the bottom", function(){
|
||||||
|
this.view.isBottom = function(){ return false; };
|
||||||
|
this.view.hasMoreNotifs = true;
|
||||||
|
spyOn(this.view, 'getNotifications');
|
||||||
|
this.view.dropdownScroll();
|
||||||
|
expect(this.view.getNotifications).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doesn't call getNotifications if is not at the bottom", function(){
|
||||||
|
this.view.isBottom = function(){ return true; };
|
||||||
|
this.view.hasMoreNotifs = false;
|
||||||
|
spyOn(this.view, 'getNotifications');
|
||||||
|
this.view.dropdownScroll();
|
||||||
|
expect(this.view.getNotifications).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('getNotifications', function(){
|
||||||
|
it('Has more notifications', function(){
|
||||||
|
var response = ['', '', '', '', ''];
|
||||||
|
spyOn($, 'getJSON').and.callFake(function(url, callback){ callback(response); });
|
||||||
|
this.view.getNotifications();
|
||||||
|
expect(this.view.hasMoreNotifs).toBe(true);
|
||||||
|
});
|
||||||
|
it('Has no more notifications', function(){
|
||||||
|
spyOn($, 'getJSON').and.callFake(function(url, callback){ callback([]); });
|
||||||
|
this.view.getNotifications();
|
||||||
|
expect(this.view.hasMoreNotifs).toBe(false);
|
||||||
|
});
|
||||||
|
it('Correctly sets the next page', function(){
|
||||||
|
spyOn($, 'getJSON').and.callFake(function(url, callback){ callback([]); });
|
||||||
|
expect(typeof this.view.nextPage).toBe('undefined');
|
||||||
|
this.view.getNotifications();
|
||||||
|
expect(this.view.nextPage).toBe(3);
|
||||||
|
});
|
||||||
|
it('Increase the page count', function(){
|
||||||
|
var response = ['', '', '', '', ''];
|
||||||
|
spyOn($, 'getJSON').and.callFake(function(url, callback){ callback(response); });
|
||||||
|
this.view.getNotifications();
|
||||||
|
expect(this.view.nextPage).toBe(3);
|
||||||
|
this.view.getNotifications();
|
||||||
|
expect(this.view.nextPage).toBe(4);
|
||||||
|
});
|
||||||
|
it('Calls renderNotifications()', function(){
|
||||||
|
spyOn($, 'getJSON').and.callFake(function(url, callback){ callback([]); });
|
||||||
|
spyOn(this.view, 'renderNotifications');
|
||||||
|
this.view.getNotifications();
|
||||||
|
expect(this.view.renderNotifications).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
it('Adds the notifications to this.notifications', function(){
|
||||||
|
var response = ['', '', '', '', ''];
|
||||||
|
this.view.notifications.length = 0;
|
||||||
|
spyOn($, 'getJSON').and.callFake(function(url, callback){ callback(response); });
|
||||||
|
this.view.getNotifications();
|
||||||
|
expect(this.view.notifications).toEqual(response);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('renderNotifications', function(){
|
||||||
|
it('Removes the previous notifications', function(){
|
||||||
|
this.view.dropdownNotifications.append('<div class="media stream_element">Notification</div>');
|
||||||
|
expect(this.view.dropdownNotifications.find('.media.stream_element').length).toBe(1);
|
||||||
|
this.view.renderNotifications();
|
||||||
|
expect(this.view.dropdownNotifications.find('.media.stream_element').length).toBe(0);
|
||||||
|
});
|
||||||
|
it('Calls hideAjaxLoader()', function(){
|
||||||
|
spyOn(this.view, 'hideAjaxLoader');
|
||||||
|
this.view.renderNotifications();
|
||||||
|
expect(this.view.hideAjaxLoader).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
14
spec/javascripts/app/views/search_view_spec.js
Normal file
14
spec/javascripts/app/views/search_view_spec.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
describe("app.views.Search", function() {
|
||||||
|
beforeEach(function(){
|
||||||
|
spec.content().html('<form action="#" id="search_people_form"></form>');
|
||||||
|
this.view = new app.views.Search({ el: '#search_people_form' });
|
||||||
|
});
|
||||||
|
describe("parse", function() {
|
||||||
|
it("escapes a persons name", function() {
|
||||||
|
var person = { 'name': '</script><script>alert("xss");</script' };
|
||||||
|
this.view.context = this.view;
|
||||||
|
var result = this.view.parse([$.extend({}, person)]);
|
||||||
|
expect(result[0].data.name).not.toEqual(person.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
describe("Diaspora.Widgets.Search", function() {
|
|
||||||
describe("parse", function() {
|
|
||||||
it("escapes a persons name", function() {
|
|
||||||
$("#jasmine_content").html('<form action="#" id="searchForm"></form>');
|
|
||||||
|
|
||||||
var search = Diaspora.BaseWidget.instantiate("Search", $("#jasmine_content > #searchForm"));
|
|
||||||
var person = {"name": "</script><script>alert('xss');</script"};
|
|
||||||
var result = search.parse([$.extend({}, person)]);
|
|
||||||
expect(result[0].data.name).not.toEqual(person.name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Loading…
Reference in a new issue