From 00117c18c3c7838d89be8e0cf18da1bb2f01bd17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 18 Jun 2014 20:04:10 +0200 Subject: [PATCH] FEATURE: dismissable banner topic --- .../components/discourse-banner.js.es6 | 25 ++++++++ .../javascripts/discourse/models/user.js | 8 +++ .../components/discourse-banner.js.handlebars | 9 +++ .../templates/discovery.js.handlebars | 1 + .../discourse/templates/topic.js.handlebars | 1 + .../common/components/banner.css.scss | 14 +++++ app/assets/stylesheets/desktop/modal.scss | 20 +++--- app/assets/stylesheets/mobile/modal.scss | 20 +++--- app/controllers/application_controller.rb | 12 +++- app/models/topic.rb | 14 +++++ app/serializers/current_user_serializer.rb | 7 ++- app/services/user_updater.rb | 3 +- config/locales/client.en.yml | 6 ++ ...dd_dismissed_banner_key_to_user_profile.rb | 5 ++ spec/models/topic_spec.rb | 63 ++++++++++--------- 15 files changed, 153 insertions(+), 55 deletions(-) create mode 100644 app/assets/javascripts/discourse/components/discourse-banner.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/components/discourse-banner.js.handlebars create mode 100644 app/assets/stylesheets/common/components/banner.css.scss create mode 100644 db/migrate/20140618163511_add_dismissed_banner_key_to_user_profile.rb diff --git a/app/assets/javascripts/discourse/components/discourse-banner.js.es6 b/app/assets/javascripts/discourse/components/discourse-banner.js.es6 new file mode 100644 index 00000000000..42da49aa90e --- /dev/null +++ b/app/assets/javascripts/discourse/components/discourse-banner.js.es6 @@ -0,0 +1,25 @@ +export default Ember.Component.extend({ + + visible: function () { + var bannerKey = this.get("banner.key"), + dismissedBannerKey = this.get("user.dismissed_banner_key") || + Discourse.KeyValueStore.get("dismissed_banner_key"); + + if (bannerKey) { bannerKey = parseInt(bannerKey, 10); } + if (dismissedBannerKey) { dismissedBannerKey = parseInt(dismissedBannerKey, 10); } + + return bannerKey && dismissedBannerKey !== bannerKey; + }.property("user.dismissed_banner_key", "banner.key"), + + actions: { + dismiss: function () { + if (this.get("user")) { + this.get("user").dismissBanner(this.get("banner.key")); + } else { + this.set("visible", false); + Discourse.KeyValueStore.set({ key: "dismissed_banner_key", value: this.get("banner.key") }); + } + } + } + +}); diff --git a/app/assets/javascripts/discourse/models/user.js b/app/assets/javascripts/discourse/models/user.js index e178c38f7b8..277dc379c6c 100644 --- a/app/assets/javascripts/discourse/models/user.js +++ b/app/assets/javascripts/discourse/models/user.js @@ -411,6 +411,14 @@ Discourse.User = Discourse.Model.extend({ } else { return Ember.RSVP.reject(I18n.t('user.delete_yourself_not_allowed')); } + }, + + dismissBanner: function (bannerKey) { + this.set("dismissed_banner_key", bannerKey); + Discourse.ajax("/users/" + this.get('username'), { + type: 'PUT', + data: { dismissed_banner_key: bannerKey } + }); } }); diff --git a/app/assets/javascripts/discourse/templates/components/discourse-banner.js.handlebars b/app/assets/javascripts/discourse/templates/components/discourse-banner.js.handlebars new file mode 100644 index 00000000000..ea8107c06e1 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/discourse-banner.js.handlebars @@ -0,0 +1,9 @@ +{{#if visible}} + +{{/if}} diff --git a/app/assets/javascripts/discourse/templates/discovery.js.handlebars b/app/assets/javascripts/discourse/templates/discovery.js.handlebars index 20fb4b0e98c..047b977a513 100644 --- a/app/assets/javascripts/discourse/templates/discovery.js.handlebars +++ b/app/assets/javascripts/discourse/templates/discovery.js.handlebars @@ -1,6 +1,7 @@
{{custom-html "top"}} {{Discourse.globalNotice}} + {{discourse-banner user=currentUser banner=Discourse.banner}}
diff --git a/app/assets/javascripts/discourse/templates/topic.js.handlebars b/app/assets/javascripts/discourse/templates/topic.js.handlebars index 8a7627a2d3a..d3c7c26dee2 100644 --- a/app/assets/javascripts/discourse/templates/topic.js.handlebars +++ b/app/assets/javascripts/discourse/templates/topic.js.handlebars @@ -1,6 +1,7 @@
{{custom-html "top"}} {{Discourse.globalNotice}} + {{discourse-banner user=currentUser banner=Discourse.banner}}
{{#if postStream.loaded}} diff --git a/app/assets/stylesheets/common/components/banner.css.scss b/app/assets/stylesheets/common/components/banner.css.scss new file mode 100644 index 00000000000..d7f50d8ff83 --- /dev/null +++ b/app/assets/stylesheets/common/components/banner.css.scss @@ -0,0 +1,14 @@ +// -------------------------------------------------- +// Banner +// -------------------------------------------------- + +#banner { + margin-bottom: 10px; + .close { + font-size: 25px !important; + margin-top: 0 !important; + } + .meta { + display: none; + } +} diff --git a/app/assets/stylesheets/desktop/modal.scss b/app/assets/stylesheets/desktop/modal.scss index 01c2f729ab1..3ac8fc3b633 100644 --- a/app/assets/stylesheets/desktop/modal.scss +++ b/app/assets/stylesheets/desktop/modal.scss @@ -63,16 +63,16 @@ animation: modal .25s; font-size: 20px; padding: 10px 15px 7px; } - .close { - float: right; - font-size: 20px; - margin: 10px 10px 0; - text-decoration: none; - color: scale-color($primary, $lightness: 35%); - cursor: pointer; - &:hover { - color: $primary; - } +} +.close { + float: right; + font-size: 20px; + margin: 10px 10px 0; + text-decoration: none; + color: scale-color($primary, $lightness: 35%); + cursor: pointer; + &:hover { + color: $primary; } } diff --git a/app/assets/stylesheets/mobile/modal.scss b/app/assets/stylesheets/mobile/modal.scss index bc6d084ed04..fa436db22e6 100644 --- a/app/assets/stylesheets/mobile/modal.scss +++ b/app/assets/stylesheets/mobile/modal.scss @@ -54,18 +54,16 @@ font-size: 15px; padding: 0 0 0 20px; } - .close { - float: right; - font-size: 24px; - padding: 15px; // more pixels to touch - margin: -15px 0 0 0; - text-decoration: none; - color: $primary; - cursor: pointer; - } } - - +.close { + float: right; + font-size: 24px; + padding: 15px; // more pixels to touch + margin: -15px 0 0 0; + text-decoration: none; + color: $primary; + cursor: pointer; +} #move-selected { p { diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2da42748a20..ea08909f7e3 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -234,6 +234,7 @@ class ApplicationController < ActionController::Base store_preloaded("site", Site.json_for(guardian)) store_preloaded("siteSettings", SiteSetting.client_settings_json) store_preloaded("customHTML", custom_html_json) + store_preloaded("banner", banner_json) end def preload_current_user_data @@ -259,16 +260,23 @@ class ApplicationController < ActionController::Base MultiJson.dump(data) end + def banner_json + topic = Topic.where(archetype: Archetype.banner).limit(1).first + banner = topic.present? ? topic.banner : {} + + MultiJson.dump(banner) + end + def render_json_error(obj) render json: MultiJson.dump(create_errors_json(obj)), status: 422 end def success_json - {success: 'OK'} + { success: 'OK' } end def failed_json - {failed: 'FAILED'} + { failed: 'FAILED' } end def json_result(obj, opts={}) diff --git a/app/models/topic.rb b/app/models/topic.rb index 0da1ad8a38a..23efb66a293 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -634,12 +634,26 @@ class Topic < ActiveRecord::Base self.archetype = Archetype.banner self.add_moderator_post(user, I18n.t("archetypes.banner.message.make")) self.save + + MessageBus.publish('/site/banner', banner) end def remove_banner!(user) self.archetype = Archetype.default self.add_moderator_post(user, I18n.t("archetypes.banner.message.remove")) self.save + + MessageBus.publish('/site/banner', nil) + end + + def banner + post = self.posts.order(:post_number).limit(1).first + + { + html: post.cooked, + url: self.url, + key: self.id + } end def self.starred_counts_per_day(sinceDaysAgo=30) diff --git a/app/serializers/current_user_serializer.rb b/app/serializers/current_user_serializer.rb index d8b78a06cf6..1cdb4df6c40 100644 --- a/app/serializers/current_user_serializer.rb +++ b/app/serializers/current_user_serializer.rb @@ -23,7 +23,8 @@ class CurrentUserSerializer < BasicUserSerializer :redirected_to_top_reason, :disable_jump_reply, :custom_fields, - :muted_category_ids + :muted_category_ids, + :dismissed_banner_key def include_site_flagged_posts_count? object.staff? @@ -100,4 +101,8 @@ class CurrentUserSerializer < BasicUserSerializer .pluck(:category_id) end + def dismissed_banner_key + object.user_profile.dismissed_banner_key + end + end diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index eeaeb1adae8..f1f7a24412e 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -19,7 +19,8 @@ class UserUpdater ] PROFILE_ATTR = [ - :location + :location, + :dismissed_banner_key ] def initialize(actor, user) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 6ebca8c8814..9be4a236d16 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -166,6 +166,12 @@ en: undo: "Undo" revert: "Revert" + banner: + close: "Dismiss this banner." + read_more: + title: "Click to go to the topic." + text: "Read more" + choose_topic: none_found: "No topics found." title: diff --git a/db/migrate/20140618163511_add_dismissed_banner_key_to_user_profile.rb b/db/migrate/20140618163511_add_dismissed_banner_key_to_user_profile.rb new file mode 100644 index 00000000000..f84c1f9a928 --- /dev/null +++ b/db/migrate/20140618163511_add_dismissed_banner_key_to_user_profile.rb @@ -0,0 +1,5 @@ +class AddDismissedBannerKeyToUserProfile < ActiveRecord::Migration + def change + add_column :user_profiles, :dismissed_banner_key, :integer, nullable: true + end +end diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index aea4dad51ca..273a553ba02 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -638,41 +638,44 @@ describe Topic do end end - describe "make_banner!" do + describe "banner" do + + let(:topic) { Fabricate(:topic) } + let(:user) { topic.user } + let(:banner) { { html: "

BANNER

", url: topic.url, key: topic.id } } + + before { topic.stubs(:banner).returns(banner) } + + describe "make_banner!" do + + it "changes the topic archetype to 'banner'" do + topic.expects(:add_moderator_post) + MessageBus.expects(:publish).with("/site/banner", banner) + topic.make_banner!(user) + topic.archetype.should == Archetype.banner + end + + it "ensures only one banner topic at all time" do + banner_topic = Fabricate(:banner_topic) + Topic.where(archetype: Archetype.banner).count.should == 1 + + topic.make_banner!(user) + Topic.where(archetype: Archetype.banner).count.should == 1 + end - before do - @topic = Fabricate(:topic) - @user = @topic.user end - it "changes the topic archetype to 'banner'" do - @topic.expects(:add_moderator_post) - @topic.make_banner!(@user) - @topic.archetype.should == Archetype.banner + describe "remove_banner!" do + + it "resets the topic archetype" do + topic.expects(:add_moderator_post) + MessageBus.expects(:publish).with("/site/banner", nil) + topic.remove_banner!(user) + topic.archetype.should == Archetype.default + end + end - it "ensures only one banner topic at all time" do - banner_topic = Fabricate(:banner_topic) - Topic.where(archetype: Archetype.banner).count.should == 1 - - @topic.make_banner!(@user) - Topic.where(archetype: Archetype.banner).count.should == 1 - end - - end - - describe "remove_banner!" do - - before do - @topic = Fabricate(:topic) - @user = @topic.user - end - - it "resets the topic archetype" do - @topic.expects(:add_moderator_post) - @topic.remove_banner!(@user) - @topic.archetype.should == Archetype.default - end end