Support for "no subcategories"
This commit is contained in:
parent
ccd0f9c371
commit
acf262b631
|
@ -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'),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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' });
|
||||
});
|
||||
|
|
|
@ -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
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue