Support for "no subcategories"

This commit is contained in:
Robin Ward 2013-12-13 17:18:28 -05:00
parent ccd0f9c371
commit acf262b631
14 changed files with 98 additions and 35 deletions

View File

@ -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'),

View File

@ -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);
@ -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);

View File

@ -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);
});

View File

@ -8,6 +8,7 @@
**/
function finderFor(filter, params) {
return function() {
var url = Discourse.getURL("/") + filter + ".json";
@ -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');
@ -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(),

View File

@ -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' });
});

View File

@ -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'));
},
@ -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
@ -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
});
});

View File

@ -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}}

View File

@ -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}}

View File

@ -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"}}

View File

@ -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
@ -74,6 +74,15 @@ class ListController < ApplicationController
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
@ -128,14 +137,16 @@ class ListController < ApplicationController
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

View File

@ -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"

View File

@ -200,6 +200,7 @@ Discourse::Application.routes.draw do
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.

View File

@ -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`
@ -31,7 +32,6 @@ class TopicQuery
def initialize(user=nil, options={})
options.assert_valid_keys(VALID_OPTIONS)
@options = options
@user = user
end
@ -209,12 +209,16 @@ class TopicQuery
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)

View File

@ -41,6 +41,7 @@ describe TopicQuery do
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
@ -50,9 +51,21 @@ describe TopicQuery do
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