Skip to content

Commit

Permalink
Support for "no subcategories"
Browse files Browse the repository at this point in the history
  • Loading branch information
eviltrout committed Dec 16, 2013
1 parent ccd0f9c commit acf262b
Show file tree
Hide file tree
Showing 14 changed files with 98 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@ Discourse.CategoryDropComponent = Ember.Component.extend({
}.property('expanded'),

allCategoriesUrl: function() {
return this.get('category.parentCategory.url') || "/";
}.property('category'),
if (this.get('subCategory')) {
return this.get('parentCategory.url') || "/";
} else {
return "/";
}
}.property('parentCategory.url', 'subCategory'),

noCategoriesUrl: function() {
return this.get('parentCategory.url') + "/none";
}.property('parentCategory.url'),

allCategoriesLabel: function() {
if (this.get('subCategory')) {
return I18n.t('categories.only_category', {categoryName: this.get('parentCategory.name')});
return I18n.t('categories.all_subcategories', {categoryName: this.get('parentCategory.name')});
}
return I18n.t('categories.all');
}.property('category'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ Discourse.ListController = Discourse.Controller.extend({
@method load
@param {String} filterMode the filter we want to load
@param {Object} params for additional filtering
@returns {Ember.Deferred} the promise that will resolve to the list of items.
**/
load: function(filterMode) {
load: function(filterMode, params) {
var self = this;
this.set('loading', true);

Expand Down Expand Up @@ -74,13 +75,15 @@ Discourse.ListController = Discourse.Controller.extend({
current = Discourse.NavItem.create({ name: filterMode });
}

return Discourse.TopicList.list(current).then(function(items) {
params = params || {};
return Discourse.TopicList.list(current, params).then(function(items) {
self.setProperties({
loading: false,
filterMode: filterMode,
draft: items.draft,
draft_key: items.draft_key,
draft_sequence: items.draft_sequence
draft_sequence: items.draft_sequence,
noSubcategories: params.no_subcategories
});
if(trackingState) {
trackingState.sync(items, filterMode);
Expand Down
2 changes: 2 additions & 0 deletions app/assets/javascripts/discourse/models/category.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ Discourse.Category.reopenClass({
if (parentSlug) {
var parentCategory = Discourse.Category.findSingleBySlug(parentSlug);
if (parentCategory) {
if (slug === 'none') { return parentCategory; }

category = categories.find(function(item) {
return item && item.get('parentCategory') === parentCategory && Discourse.Category.slugFor(item) === (parentSlug + "/" + slug);
});
Expand Down
9 changes: 6 additions & 3 deletions app/assets/javascripts/discourse/models/topic_list.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
**/

function finderFor(filter, params) {

return function() {
var url = Discourse.getURL("/") + filter + ".json";

Expand Down Expand Up @@ -185,9 +186,10 @@ Discourse.TopicList.reopenClass({
@method list
@param {Object} The menu item to filter to
@param {Object} Any additional params
@returns {Promise} a promise that resolves to the list of topics
**/
list: function(menuItem) {
list: function(menuItem, params) {
var filter = menuItem.get('name'),
session = Discourse.Session.current(),
list = session.get('topicList');
Expand All @@ -197,11 +199,12 @@ Discourse.TopicList.reopenClass({
return Ember.RSVP.resolve(list);
}
session.setProperties({topicList: null, topicListScrollPos: null});
return Discourse.TopicList.find(filter, {exclude_category: menuItem.get('excludeCategory')});

var findParams = {exclude_category: menuItem.get('excludeCategory')};
return Discourse.TopicList.find(filter, _.extend(findParams, params || {}));
},

find: function(filter, params) {

return PreloadStore.getAndRemove("topic_list", finderFor(filter, params)).then(function(result) {
var topicList = Discourse.TopicList.create({
inserted: Em.A(),
Expand Down
2 changes: 2 additions & 0 deletions app/assets/javascripts/discourse/routes/application_routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ Discourse.Route.buildRoutes(function() {
this.route('categories', { path: '/categories' });
this.route('category', { path: '/category/:slug' });
this.route('category', { path: '/category/:slug/more' });
this.route('categoryNone', { path: '/category/:slug/none' });
this.route('categoryNone', { path: '/category/:slug/none/more' });
this.route('category', { path: '/category/:parentSlug/:slug' });
this.route('category', { path: '/category/:parentSlug/:slug/more' });
});
Expand Down
21 changes: 14 additions & 7 deletions app/assets/javascripts/discourse/routes/list_category_route.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
@module Discourse
**/
Discourse.ListCategoryRoute = Discourse.FilteredListRoute.extend({

model: function(params) {
return Discourse.Category.findBySlug(Em.get(params, 'slug'), Em.get(params, 'parentSlug'));
},
Expand All @@ -24,11 +23,16 @@ Discourse.ListCategoryRoute = Discourse.FilteredListRoute.extend({
var listController = this.controllerFor('list'),
categorySlug = Discourse.Category.slugFor(category),
self = this,
filter = this.filter || "latest",
url = "category/" + categorySlug + "/l/" + filter;
filter = this.get('filter') || "latest",
url = "category/" + categorySlug + "/l/" + filter,
params = {};

if (this.get('noSubcategories')) {
params.no_subcategories = true;
}

listController.setProperties({ filterMode: url, category: null });
listController.load(url).then(function(topicList) {
listController.load(url, params).then(function(topicList) {
listController.setProperties({
canCreateTopic: topicList.get('can_create_topic'),
category: category
Expand All @@ -52,13 +56,16 @@ Discourse.ListCategoryRoute = Discourse.FilteredListRoute.extend({
// Clear the search context
this.controllerFor('search').set('searchContext', null);
}


});

Discourse.ListCategoryNoneRoute = Discourse.ListCategoryRoute.extend({
noSubcategories: true
});

Discourse.ListController.filters.forEach(function(filter) {
Discourse["List" + (filter.capitalize()) + "CategoryRoute"] = Discourse.ListCategoryRoute.extend({ filter: filter });
Discourse["List" + (filter.capitalize()) + "CategoryRoute"] = Discourse.ListCategoryRoute.extend({
filter: filter
});
});


Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<li>
{{category-drop category=firstCategory categories=parentCategories}}
{{category-drop category=firstCategory categories=parentCategories}}
</li>

{{#if childCategories}}
<li>
{{category-drop category=secondCategory parentCategory=firstCategory categories=childCategories subCategory="true"}}
{{category-drop category=secondCategory parentCategory=firstCategory categories=childCategories subCategory="true" noSubcategories=noSubcategories}}
</li>
{{/if}}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
{{#if category}}
<a href="#" {{action expand}} class="badge-category" {{bindAttr style="badgeStyle"}}>{{category.name}}</a>
{{else}}
<a href='#' {{action expand}} class='badge-category home' {{bindAttr style="badgeStyle"}}>{{allCategoriesLabel}}</i></a>
{{#if noSubcategories}}
<a href='#' {{action expand}} class='badge-category home' {{bindAttr style="badgeStyle"}}>{{i18n categories.no_subcategory}}</i></a>
{{else}}
<a href='#' {{action expand}} class='badge-category home' {{bindAttr style="badgeStyle"}}>{{allCategoriesLabel}}</i></a>
{{/if}}

{{/if}}

{{#if categories}}
<a href='#' {{action expand}} class='badge-category category-dropdown-button' {{bindAttr style="badgeStyle"}}><i {{bindAttr class="iconClass"}}></i></a>
<section {{bindAttr class="expanded::hidden :category-dropdown-menu"}} class='chooser'>
<div class='cat'><a {{bindAttr href=allCategoriesUrl}} class='badge-category home'>{{allCategoriesLabel}}</a></div>
{{#if subCategory}}
<div class='cat'><a {{bindAttr href=noCategoriesUrl}} class='badge-category home'>{{i18n categories.no_subcategory}}</a></div>
{{/if}}
{{#each categories}}<div class='cat'>{{categoryLink this allowUncategorized=true}}</div>{{/each}}
</section>
{{/if}}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class='list-controls'>
<div class="container">

{{bread-crumbs category=category categories=categories}}
{{bread-crumbs category=category categories=categories noSubcategories=noSubcategories}}

<ul class="nav nav-pills" id='category-filter'>
{{each availableNavItems itemViewClass="Discourse.NavItemView"}}
Expand Down
25 changes: 18 additions & 7 deletions app/controllers/list_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ class ListController < ApplicationController
end

def category
list_opts = build_topic_list_options
query = TopicQuery.new(current_user, list_opts)
list = query.list_latest
list.more_topics_url = construct_url_with(:latest, list_opts)
respond(list)
category_response
end

def category_none
category_response(no_subcategories: true)
end

def category_feed
Expand All @@ -74,6 +74,15 @@ def popular_redirect

protected

def category_response(extra_opts=nil)
list_opts = build_topic_list_options
list_opts.merge!(extra_opts) if extra_opts
query = TopicQuery.new(current_user, list_opts)
list = query.list_latest
list.more_topics_url = construct_url_with(:latest, list_opts)
respond(list)
end

def respond(list)

list.draft_key = Draft::NEW_TOPIC
Expand Down Expand Up @@ -128,14 +137,16 @@ def build_topic_list_options
menu_item = menu_items.select { |item| item.query_should_exclude_category?(action_name, params[:format]) }.first

# exclude_category = 1. from params / 2. parsed from top menu / 3. nil
return {
result = {
page: params[:page],
topic_ids: param_to_integer_list(:topic_ids),
exclude_category: (params[:exclude_category] || menu_item.try(:filter)),
category: params[:category],
sort_order: params[:sort_order],
sort_descending: params[:sort_descending]
sort_descending: params[:sort_descending],
}
result[:no_subcategories] = true if params[:no_subcategories] == 'true'
result
end

def list_target_user
Expand Down
3 changes: 2 additions & 1 deletion config/locales/client.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ en:

categories:
all: "all categories"
only_category: "only {{categoryName}}"
all_subcategories: "all subcategories"
no_subcategory: "no subcategory"
category: "Category"
posts: "Posts"
topics: "Topics"
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@

get 'category/:category.rss' => 'list#category_feed', format: :rss, as: 'category_feed'
get 'category/:category' => 'list#category', as: 'category_list'
get 'category/:category/none' => 'list#category_none', as: 'category_list_none'
get 'category/:category/more' => 'list#category', as: 'category_list_more'

# We've renamed popular to latest. If people access it we want a permanent redirect.
Expand Down
16 changes: 10 additions & 6 deletions lib/topic_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class TopicQuery
visible
category
sort_order
no_subcategories
sort_descending).map(&:to_sym)

# Maps `sort_order` to a columns in `topics`
Expand All @@ -31,7 +32,6 @@ class TopicQuery

def initialize(user=nil, options={})
options.assert_valid_keys(VALID_OPTIONS)

@options = options
@user = user
end
Expand Down Expand Up @@ -209,12 +209,16 @@ def default_results(options={})
category_id = nil
if options[:category].present?
category_id = options[:category].to_i
if category_id == 0
result = result.where('categories.slug = ?', options[:category])
else
result = result.where('categories.id = ?', category_id)
category_id = Category.where(slug: options[:category]).pluck(:id).first if category_id == 0

if category_id
if options[:no_subcategories]
result = result.where('categories.id = ?', category_id)
else
result = result.where('categories.id = ? or categories.parent_category_id = ?', category_id, category_id)
end
result = result.references(:categories)
end
result = result.references(:categories)
end

result = apply_ordering(result, options)
Expand Down
15 changes: 14 additions & 1 deletion spec/components/topic_query_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

context 'category filter' do
let(:category) { Fabricate(:category) }

let(:diff_category) { Fabricate(:category) }

it "returns topics in the category when we filter to it" do
Expand All @@ -50,9 +51,21 @@
TopicQuery.new(moderator, category: category.slug).list_latest.topics.size.should == 1
TopicQuery.new(moderator, category: "#{category.id}-category").list_latest.topics.size.should == 1
TopicQuery.new(moderator, category: diff_category.slug).list_latest.topics.size.should == 1
TopicQuery.new(moderator, category: 'made up slug').list_latest.topics.size.should == 0

# Defaults to no category filter when slug does not exist
TopicQuery.new(moderator, category: 'made up slug').list_latest.topics.size.should == 2
end

context 'subcategories' do
let!(:subcategory) { Fabricate(:category, parent_category_id: category.id)}

it "works with subcategories" do
TopicQuery.new(moderator, category: category.id).list_latest.topics.size.should == 2
TopicQuery.new(moderator, category: subcategory.id).list_latest.topics.size.should == 1
TopicQuery.new(moderator, category: category.id, no_subcategories: true).list_latest.topics.size.should == 1
end

end


end
Expand Down

0 comments on commit acf262b

Please sign in to comment.