diff --git a/app/assets/javascripts/discourse/models/category.js b/app/assets/javascripts/discourse/models/category.js index a6383f8ca21..ffa3c56af06 100644 --- a/app/assets/javascripts/discourse/models/category.js +++ b/app/assets/javascripts/discourse/models/category.js @@ -157,6 +157,22 @@ Discourse.Category = Discourse.Model.extend({ return this.countStats('topics'); }.property('posts_year', 'posts_month', 'posts_week', 'posts_day'), + notification_level: function () { + return this.get('notification_level'); + }.property('notification_level'), + + setNotification: function (notification_level) { + //console.log("inside category.js"); + var url = "/category/" + this.get('id')+"/notifications"; + this.set('notification_level', notification_level) + return Discourse.ajax(url, { + data: { + notification_level: notification_level + }, + type: 'POST' + }); + }, + postCountStats: function() { return this.countStats('posts'); }.property('posts_year', 'posts_month', 'posts_week', 'posts_day'), @@ -178,6 +194,13 @@ Discourse.Category = Discourse.Model.extend({ Discourse.Category.reopenClass({ + NotificationLevel: { + WATCHING: 3, + TRACKING: 2, + REGULAR: 1, + MUTED: 0 + }, + slugFor: function(category) { if (!category) return ""; diff --git a/app/assets/javascripts/discourse/templates/navigation/category.js.handlebars b/app/assets/javascripts/discourse/templates/navigation/category.js.handlebars index de0ec0ffecb..9081893e9b2 100644 --- a/app/assets/javascripts/discourse/templates/navigation/category.js.handlebars +++ b/app/assets/javascripts/discourse/templates/navigation/category.js.handlebars @@ -7,6 +7,8 @@ {{customHTML "extraNavItem"}} +{{view Discourse.CategoryNotificationsButton categoryBinding="model" category=category}} + {{#if canCreateTopic}} {{/if}} diff --git a/app/assets/javascripts/discourse/views/buttons/category_notification_dropdown_view.js b/app/assets/javascripts/discourse/views/buttons/category_notification_dropdown_view.js new file mode 100644 index 00000000000..f9cd8f96326 --- /dev/null +++ b/app/assets/javascripts/discourse/views/buttons/category_notification_dropdown_view.js @@ -0,0 +1,50 @@ +/** + This view handles rendering of a button with an associated drop down + + @class CategoryNotificationDropdownButtonView + @extends Discourse.View + @namespace Discourse + @module Discourse +**/ +Discourse.CategoryNotificationDropdownButtonView = Discourse.View.extend({ + classNameBindings: [':btn-group', 'hidden'], + shouldRerender: Discourse.View.renderIfChanged('text', 'text'), + + didInsertElement: function() { + // If there's a click handler, call it + if (this.clicked) { + var dropDownButtonView = this; + this.$('ul li').on('click.dropdown-button', function(e) { + e.preventDefault(); + dropDownButtonView.clicked($(e.currentTarget).data('id')); + return false; + }); + } + }, + + willDestroyElement: function() { + this.$('ul li').off('click.dropdown-button'); + }, + + render: function(buffer) { + buffer.push(""); + + buffer.push(""); + + } +}); diff --git a/app/assets/javascripts/discourse/views/buttons/category_notifications_button.js b/app/assets/javascripts/discourse/views/buttons/category_notifications_button.js new file mode 100644 index 00000000000..cffdb3a2f62 --- /dev/null +++ b/app/assets/javascripts/discourse/views/buttons/category_notifications_button.js @@ -0,0 +1,65 @@ +/** + A button to display notification options for categories. + + @class NotificationsButton + @extends Discourse.DropdownButtonView + @namespace Discourse + @module Discourse +**/ +Discourse.CategoryNotificationsButton = Discourse.CategoryNotificationDropdownButtonView.extend({ + classNames: ['notification-options'], + //title: I18n.t('category.notifications.title'), + //longDescriptionBinding: 'topic.details.notificationReasonText', + //topic: Em.computed.alias('controller.model'), + category: Em.computed.alias('controller.model'), + hidden: Em.computed.alias('topic.deleted'), + + dropDownContent: function() { + var contents = []; + + _.each([ + ['WATCHING', 'watching'], + ['TRACKING', 'tracking'], + ['REGULAR', 'regular'], + ['MUTED', 'muted'] + ], function(pair) { + + if (pair[1] === 'regular') { return; } + + contents.push([ + Discourse.Category.NotificationLevel[pair[0]], + 'category.notifications.' + pair[1] + ]); + }); + + return contents; + }.property(), + + // displayed Button + text: function() { + var key = (function() { + switch (this.get('category.notification_level')) { + case Discourse.Category.NotificationLevel.WATCHING: return 'watching'; + case Discourse.Category.NotificationLevel.TRACKING: return 'tracking'; + case Discourse.Category.NotificationLevel.MUTED: return 'muted'; + default: return 'regular'; + } + }).call(this); + + var icon = (function() { + switch (key) { + case 'watching': return ' '; + case 'tracking': return ' '; + case 'muted': return ' '; + default: return ''; + } + })(); + return icon + (I18n.t("category.notifications." + key + ".title")) + ""; + }.property('category.notification_level'), + + clicked: function(id) { + return this.get('category').setNotification(id); + } + +}); + diff --git a/app/assets/stylesheets/desktop/category-notification.scss b/app/assets/stylesheets/desktop/category-notification.scss new file mode 100644 index 00000000000..f3e7e857003 --- /dev/null +++ b/app/assets/stylesheets/desktop/category-notification.scss @@ -0,0 +1,38 @@ +@import "common/foundation/variables"; +@import "common/foundation/mixins"; +@import "common/foundation/helpers"; + +.notification-dropdown-menu { + position: absolute; + z-index: 100; + display: none; + width: 550px; + padding: 4px 0; + margin: 1px 0 0; + list-style: none; + background-color: $primary_background_color; + border: 1px solid $primary_border_color; + box-shadow: 0 1px 5px rgba($primary_shadow_color, .4); + background-clip: padding-box; + span {font-size: 12px;} +.title {font-weight: bold; display: block; font-size: 14px;} +} +.notification-dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: $primary_text_color; +} +.notification-dropdown-menu li > a:hover, +.notification-dropdown-menu .active > a, +.notification-dropdown-menu .active > a:hover { + color: $tertiary_text_color; + text-decoration: none; + background-color: $emphasis_text_color; +} +.open > .notification-dropdown-menu { + display: block; + clear: both; +} \ No newline at end of file diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 025f03adf65..08864536706 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -72,6 +72,14 @@ class CategoriesController < ApplicationController } end + def set_notifications + category_id = params[:category_id].to_i + notification_level = params[:notification_level].to_i + + CategoryUser.set_notification_level_for_category(current_user, notification_level , category_id) + render json: success_json + end + def destroy guardian.ensure_can_delete!(@category) @category.destroy diff --git a/app/models/category.rb b/app/models/category.rb index 980aea83991..867f91d09c7 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -66,7 +66,7 @@ class Category < ActiveRecord::Base # permission is just used by serialization # we may consider wrapping this in another spot - attr_accessor :displayable_topics, :permission, :subcategory_ids + attr_accessor :displayable_topics, :permission, :subcategory_ids, :notification_level def self.scoped_to_permissions(guardian, permission_types) diff --git a/app/models/category_user.rb b/app/models/category_user.rb index abbef8fbf20..e445c2ccef5 100644 --- a/app/models/category_user.rb +++ b/app/models/category_user.rb @@ -6,6 +6,10 @@ class CategoryUser < ActiveRecord::Base self.where(user: user, notification_level: notification_levels[level]) end + def self.lookup_by_category(user, category) + self.where(user: user, category: category) + end + # same for now def self.notification_levels TopicUser.notification_levels @@ -35,6 +39,20 @@ class CategoryUser < ActiveRecord::Base end end + def self.set_notification_level_for_category(user, level, category_id) + record = CategoryUser.where(user: user, category_id: category_id).first + # oder CategoryUser.where(user: user, category_id: category_id).destroy_all + # und danach mir create anlegen. + + if record.present? + record.notification_level = level + record.save! + else + CategoryUser.create!(user: user, category_id: category_id, notification_level: level) + end + end + + def self.auto_mute_new_topic(topic) apply_default_to_topic( topic, diff --git a/app/models/site.rb b/app/models/site.rb index 84716f87a80..c48790c9799 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -45,6 +45,11 @@ class Site by_id = {} categories.each do |category| + # nur wenn user gesetzt ist + #unless guardian.anonymous? + category.notification_level = CategoryUser.lookup_by_category(@guardian.user, category).pluck(:notification_level)[0] + #end + category.permission = CategoryGroup.permission_types[:full] if allowed_topic_create.include?(category.id) by_id[category.id] = category end diff --git a/app/serializers/basic_category_serializer.rb b/app/serializers/basic_category_serializer.rb index 8fca40e980e..e1cf751631b 100644 --- a/app/serializers/basic_category_serializer.rb +++ b/app/serializers/basic_category_serializer.rb @@ -11,10 +11,10 @@ class BasicCategorySerializer < ApplicationSerializer :topic_url, :read_restricted, :permission, - :parent_category_id + :parent_category_id, + :notification_level def include_parent_category_id? parent_category_id end - end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index fdc4385440a..fa289a1a83d 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1142,6 +1142,21 @@ en: default_position: "Default Position" position_disabled: 'Categories will be displayed in order of activity. To control the order of categories in lists, enable the "fixed category positions" setting.' parent: "Parent Category" + notifications: + title: '' + reasons: + watching: + title: "Watching" + description: "You will automatically watch all new topics in these categories. You will be notified of all new posts and topics, plus the count of unread and new posts will also appear next to the topic's listing." + tracking: + title: "Tracking" + description: "You will automatically track all new topics in these categories. The count of unread and new posts will appear next to the topic's listing." + regular: + title: "Regular" + description: "You will be notified only if someone mentions your @name or replies to your post." + muted: + title: "Muted" + description: "You will not be notified of anything about new topics in these categories, and they will not appear on your unread tab." flagging: title: 'Why are you privately flagging this post?' diff --git a/config/routes.rb b/config/routes.rb index 5d61d0704ef..f0321c619b9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -278,6 +278,7 @@ Discourse::Application.routes.draw do get "category/:category" => "list#category_latest" get "category/:category/none" => "list#category_none_latest" get "category/:parent_category/:category" => "list#parent_category_category_latest" + post "category/:category_id/notifications" => "categories#set_notifications" get "top" => "list#top" get "category/:category/l/top" => "list#category_top", as: "category_top"