diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index 507f8c0bf..52c5bd3f7 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -24,7 +24,7 @@ class NotificationsController < VannaController :conditions => conditions, :order => 'created_at desc', :include => [:target, {:actors => :profile}], - :limit => pager.per_page, + :limit => request.format == :json ? 5 : pager.per_page, :offset => pager.offset ) @@ -32,6 +32,7 @@ class NotificationsController < VannaController end notifications.each do |n| n[:actors] = n.actors + n[:translation] = object_link(n, n.actors.map { |a| person_link(a) }) n[:translation_key] = n.popup_translation_key n[:target] = n.translation_key == "notifications.mentioned" ? n.target.post : n.target end @@ -42,9 +43,14 @@ class NotificationsController < VannaController def read_all(opts=params) Notification.where(:recipient_id => current_user.id).update_all(:unread => false) end + post_process :html do def post_read_all(json) Response.new(:status => 302, :location => aspects_path) end end + + def controller + Object.new + end end diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 058124822..5c30f9ede 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -1,4 +1,8 @@ module NotificationsHelper + include ERB::Util + include ActionView::Helpers::TranslationHelper + include ActionView::Helpers::UrlHelper + include ApplicationHelper def object_link(note, actors) target_type = note.popup_translation_key actors_count = note.actors.count diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index 0bd36b062..55dd8ae51 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -43,6 +43,15 @@ .badge_count{:class => ("hidden" if @unread_message_count == 0)} = @unread_message_count + #notification_dropdown + .header + = link_to t('.view_all'), notifications_path, :id => "view_all_notifications" + %h4 + Recent notifications + .notifications + .ajax_loader + = image_tag("ajax-loader.gif") + %ul#user_menu.dropdown %li .right diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 0fe815845..064663a3e 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -94,8 +94,6 @@ .span-24.last{:style=> "#{yield(:break_the_mold)}"} = yield - .clearfix - =render :partial => 'notifications/overlay' /=render :partial => 'layouts/debug.haml' %footer diff --git a/app/views/notifications/_overlay.html.haml b/app/views/notifications/_overlay.html.haml deleted file mode 100644 index ea149e55b..000000000 --- a/app/views/notifications/_overlay.html.haml +++ /dev/null @@ -1,19 +0,0 @@ -.span-24.last#notifications_overlay - .stream.notifications - .day_group.span-24.last - .span-3 - .date - .day - .month - .span-8.notifications_for_day - .stream_element{:data=>{:guid => nil}} - .right - %span.from - = link_to("", "#", :class => "actor") - = link_to("", "#", :class => "object") - - %br - %time - = link_to("all of them", notifications_path) - %a.close{:href => "#" } - close \ No newline at end of file diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 9c7fb6229..b8b5076e9 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -292,6 +292,7 @@ en: login: "log in" code: "code" admin: "admin" + view_all: "View all" application: powered_by: "POWERED BY DIASPORA*" whats_new: "what's new?" diff --git a/features/notifications.feature b/features/notifications.feature index 7c94cb1ea..a5ad1fda3 100644 --- a/features/notifications.feature +++ b/features/notifications.feature @@ -14,8 +14,14 @@ Background: And I go to the destroy user session page -Scenario: someone shares with me - When I sign in as "alice@alice.alice" - And I follow "notifications" in the header + Scenario: someone shares with me + When I sign in as "alice@alice.alice" + And I follow "notifications" in the header Then I should see "started sharing with you" + + Scenario: notification popup + When I sign in as "alice@alice.alice" + And I click the notification badge + And I wait for the ajax to finish + Then the notification dropdown should be visible diff --git a/features/step_definitions/custom_web_steps.rb b/features/step_definitions/custom_web_steps.rb index d239eda9c..9856a7d26 100644 --- a/features/step_definitions/custom_web_steps.rb +++ b/features/step_definitions/custom_web_steps.rb @@ -194,3 +194,11 @@ end When /^I wait for (\d+) seconds$/ do |seconds| sleep seconds.to_i end + +When /^I click the notification badge$/ do + evaluate_script("$('#notification_badge a').click();"); +end + +Then /^the notification dropdown should be visible$/ do + evaluate_script("$('#notification_dropdown').css('display') === 'block'") +end diff --git a/public/javascripts/widgets/notifications-badge.js b/public/javascripts/widgets/notifications-badge.js index 23384aeaf..085923ef4 100644 --- a/public/javascripts/widgets/notifications-badge.js +++ b/public/javascripts/widgets/notifications-badge.js @@ -1,41 +1,92 @@ -$(function() { - $("#notification_badge a").live("_click", function(event){ - event.preventDefault(); - $.getJSON("/notifications", function(hash) { - $("#notifications_overlay").show(); - var notificationsElement = $("#notifications_overlay .notifications"); - var dayElementTemplate = $("#notifications_overlay .day_group").clone(); - dayElementTemplate.find(".notifications_for_day").empty(); - var streamElementTemplate = $("#notifications_overlay .stream_element").clone(); - notificationsElement.empty(); - $.each(hash["group_days"], function(day){ - var dayElement = dayElementTemplate.clone(); - var dayParts = day.split(" "); - dayElement.find(".month").text(dayParts[0]) - dayElement.find(".day").text(dayParts[1]) - var notificationsForDay = hash["group_days"][day], - notificationsForDayElement = dayElement.find('.notifications_for_day'); +(function() { + var NotificationDropdown = function() { + var self = this; - $.each(notificationsForDay, function(i, notificationHash) { - $.each(notificationHash, function(notificationType, notification) { - var actor = notification.actors[0]; - var streamElement = streamElementTemplate.clone().appendTo(notificationsForDayElement); - streamElement.find(".actor") - .text(actor.name) - .attr("href", notification.actors[0]["url"]); - streamElement.find('time').attr("datetime", notification["created_at"]); + this.start = function() { + this.badge = $("#notification_badge"); + this.badgeLink = this.badge.find("a"); + this.documentBody = $(document.body); + this.dropdown = $("#notification_dropdown"); + this.dropdownNotifications = this.dropdown.find(".notifications"); + this.ajaxLoader = this.dropdown.find(".ajax_loader"); + + this.badgeLink.toggle(function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + + self.ajaxLoader.show(); + self.badge.addClass("active"); + self.dropdown.css("display", "block"); + + self.getNotifications(function() { + self.renderNotifications(); }); - }); - notificationsElement.append(dayElement) + }, function(evt) { + evt.preventDefault(); + evt.stopPropagation(); - Diaspora.widgets.timeago.updateTimeAgo("time"); + self.badge.removeClass("active"); + self.dropdown.css("display", "none"); }); - }); - }); - $("#notifications_overlay").delegate('a.close', 'click', function() { - console.log("hi!"); - $('#notifications_overlay').hide(); - }); + this.dropdown.click(function(evt) { + evt.stopPropagation(); + }); -}); + this.documentBody.click(function(evt) { + if(self.dropdownShowing()) { + self.badgeLink.click(); + } + }); + }; + + + this.dropdownShowing = function() { + return this.dropdown.css("display") === "block"; + }; + + this.getNotifications = function(callback) { + $.getJSON("/notifications", function(notifications) { + self.notifications = notifications; + callback.apply(self, []); + }); + }; + + this.renderNotifications = function() { + self.dropdownNotifications.empty(); + + $.each(self.notifications.notifications, function(index, notifications) { + $.each(notifications, function(index, notification) { + var notificationElement = $("
") + .addClass("notification_element") + .html(notification.translation) + .prepend($("", { src: notification.actors[0].avatar })) + .append("
") + .append($("", { + "class": "timeago", + "title": notification.created_at + })) + .appendTo(self.dropdownNotifications); + + Diaspora.widgets.timeago.updateTimeAgo(".notification_element time.timeago"); + + if(notification.unread) { + notificationElement.addClass("unread"); + $.ajax({ + url: "/notifications/" + notification.id, + type: "PUT", + success: function() { + Diaspora.widgets.notifications.decrementCount(); + } + }); + } + }); + }); + + + self.ajaxLoader.hide(); + }; + }; + + Diaspora.widgets.add("notificationDropdown", NotificationDropdown); +})(); diff --git a/public/stylesheets/sass/application.sass b/public/stylesheets/sass/application.sass index 6d57883cf..0e5be741f 100644 --- a/public/stylesheets/sass/application.sass +++ b/public/stylesheets/sass/application.sass @@ -131,6 +131,7 @@ header :z-index 50 :padding 6px 0 :color #CCC + :height 26px :position fixed @@ -1548,10 +1549,13 @@ h3 span.current_gs_step :color #22AAE0 #nav_badges - :position relative + :position absolute :display inline-block - :top 3px :min-width 170px + :top 3px + :left 460px + :margin + :left 20px a:hover :text @@ -1559,17 +1563,16 @@ h3 span.current_gs_step .badge :position relative + :top 2px :display inline - :margin 0 15px - :right -5px + :margin 0 2px + :padding 8px 3px + :bottom 9px :font :weight bold :size smaller :width 28px - &:active - :top 1px - &:hover .badge_count :background @@ -1589,8 +1592,8 @@ h3 span.current_gs_step :z-index 3 :position absolute - :top -10px - :left 11px + :top -2px + :left 13px :padding 0 2px :bottom 1px :background @@ -2755,7 +2758,7 @@ ul#requested-scopes img :height 30px :width 30px - + .scope-description :display none @@ -2931,20 +2934,6 @@ ul.left_nav :height 30px :width 30px -#notifications_overlay - :display none - :position absolute - :border 4px solid black - :background - :color white - :width 700px - :padding 10px - :top 275.5px - :left 217.5px - a.close - :float right - :text-decoration none - #aspect_controls @include border-radius(2px) :background @@ -2988,3 +2977,72 @@ ul.left_nav .big_stream_photo :display block + +#view_all_notifications + :float right + :margin + :right 3px + :font + :weight bold + + +#notification_dropdown + @include box-shadow(0,0px,13px,rgba(20,20,20,0.5)) + :background white + :border solid #888 1px + :position absolute + :top 32px + :left 543px + :width 380px + :display none + + :color #444 + + a + :color $blue + + .header + :padding 10px + h4 + :padding + :bottom 0 + :margin + :bottom 0 + + .notification_element, + .header + :border + :bottom 1px solid #ddd + + .ajax_loader + :text-align center + :padding 15px + + .notification_element + :padding 10px + :min-height 30px + + img + :height 30px + :width 30px + :float left + :margin + :right 10px + + &.unread + :background + :color #eee + :color #000 + :font + :weight bold + +#notification_badge.active + :z-index 10 + :background + :color #fff + :border 1px solid #888 + :bottom none + :margin + :left 0px + :padding + :bottom 10px