diff --git a/app/assets/javascripts/discourse/lib/html.js b/app/assets/javascripts/discourse/lib/html.js
index 9c4d8a15f34..8d2d19b9fe5 100644
--- a/app/assets/javascripts/discourse/lib/html.js
+++ b/app/assets/javascripts/discourse/lib/html.js
@@ -84,7 +84,7 @@ Discourse.HTML = {
) return "";
var name = Em.get(category, 'name'),
- description = Em.get(category, 'description'),
+ description = Em.get(category, 'description_text'),
restricted = Em.get(category, 'read_restricted'),
url = Discourse.getURL("/c/") + Discourse.Category.slugFor(category),
elem = (opts.link === false ? 'span' : 'a'),
@@ -101,7 +101,7 @@ Discourse.HTML = {
name = Handlebars.Utils.escapeExpression(name);
// Add description if we have it, without tags. Server has sanitized the description value.
- if (description) html += "title=\"" + $("
").html(description).text() + "\" ";
+ if (description) html += "title=\"" + Handlebars.Utils.escapeExpression(description) + "\" ";
if (!opts.onlyStripe) {
categoryStyle = Discourse.HTML.categoryStyle(category);
diff --git a/app/assets/javascripts/discourse/models/category.js b/app/assets/javascripts/discourse/models/category.js
index ca1bc73bcde..3f0732328fe 100644
--- a/app/assets/javascripts/discourse/models/category.js
+++ b/app/assets/javascripts/discourse/models/category.js
@@ -99,12 +99,6 @@ Discourse.Category = Discourse.Model.extend({
this.get("availableGroups").addObject(permission.group_name);
},
- // note, this is used in a data attribute, data attributes get downcased
- // to avoid confusion later on using this naming here.
- description_text: function(){
- return $("" + this.get("description") + "
").text();
- }.property("description"),
-
permissions: function(){
return Em.A([
{group_name: "everyone", permission: Discourse.PermissionType.create({id: 1})},
diff --git a/app/models/category.rb b/app/models/category.rb
index 0e2a55b26f9..a47ef4a68cd 100644
--- a/app/models/category.rb
+++ b/app/models/category.rb
@@ -181,6 +181,16 @@ SQL
topic_only_relative_url.try(:relative_url)
end
+ def description_text
+ return nil unless description
+
+ @@cache ||= LruRedux::ThreadSafeCache.new(100)
+ @@cache.getset(self.description) do
+ Nokogiri::HTML(self.description).text
+ end
+
+ end
+
def ensure_slug
if name.present?
self.name.strip!
diff --git a/app/serializers/basic_category_serializer.rb b/app/serializers/basic_category_serializer.rb
index e80ce8dc60a..75ef6488a46 100644
--- a/app/serializers/basic_category_serializer.rb
+++ b/app/serializers/basic_category_serializer.rb
@@ -8,6 +8,7 @@ class BasicCategorySerializer < ApplicationSerializer
:topic_count,
:post_count,
:description,
+ :description_text,
:topic_url,
:read_restricted,
:permission,
diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb
index 39fa1f9ca5c..192f498906c 100644
--- a/spec/models/category_spec.rb
+++ b/spec/models/category_spec.rb
@@ -19,14 +19,6 @@ describe Category do
c.errors[:name].should be_present
end
- it { should belong_to :topic }
- it { should belong_to :user }
-
- it { should have_many :topics }
- it { should have_many :category_featured_topics }
- it { should have_many :featured_topics }
- it { should belong_to :parent_category}
-
describe "last_updated_at" do
it "returns a number value of when the category was last updated" do
last = Category.last_updated_at
@@ -49,7 +41,7 @@ describe Category do
# NOTE we also have the uncategorized category ... hence the increased count
- default_category = Fabricate(:category)
+ _default_category = Fabricate(:category)
full_category = Fabricate(:category)
can_post_category = Fabricate(:category)
can_read_category = Fabricate(:category)
@@ -194,6 +186,15 @@ describe Category do
end
end
+ describe 'description_text' do
+ it 'correctly generates text description as needed' do
+ c = Category.new
+ c.description_text.should == nil
+ c.description = "<hello test."
+ c.description_text.should == "