FEATURE: Subcategory list on parent subcategory page.

This commit is contained in:
Robin Ward 2014-07-02 15:10:39 -04:00
parent 4592916026
commit 462dcadd01
13 changed files with 119 additions and 43 deletions

View File

@ -29,12 +29,13 @@ export default Ember.Component.extend({
}.property('category', 'parentCategory'), }.property('category', 'parentCategory'),
childCategories: function() { childCategories: function() {
if (this.get('hideSubcategories')) { return []; }
var firstCategory = this.get('firstCategory'); var firstCategory = this.get('firstCategory');
if (!firstCategory) { return; } if (!firstCategory) { return []; }
return this.get('categories').filter(function (c) { return this.get('categories').filter(function (c) {
return c.get('parentCategory') === firstCategory; return c.get('parentCategory') === firstCategory;
}); });
}.property('firstCategory') }.property('firstCategory', 'hideSubcategories')
}); });

View File

@ -0,0 +1,21 @@
export default Em.Component.extend({
tagName: 'h3',
render: function(buffer) {
var category = this.get('category'),
logoUrl = category.get('logo_url');
if (category.get('read_restricted')) {
buffer.push("<i class='fa fa-group'></i> ");
}
buffer.push("<a href='" + Discourse.getURL('/category/') + Discourse.Category.slugFor(category) + "'>");
if (Em.isEmpty(logoUrl)) {
buffer.push(Handlebars.Utils.escapeExpression(category.get('name')));
} else {
buffer.push("<img src='" + logoUrl + "' class='category-logo'>");
}
buffer.push("</a>");
}
});

View File

@ -1,3 +1,3 @@
import NavigationDefaultController from 'discourse/controllers/navigation/default'; import NavigationDefaultController from 'discourse/controllers/navigation/default';
export default NavigationDefaultController.extend({}); export default NavigationDefaultController.extend();

View File

@ -1,7 +1,12 @@
import NavigationDefaultController from 'discourse/controllers/navigation/default'; import NavigationDefaultController from 'discourse/controllers/navigation/default';
export default NavigationDefaultController.extend({ export default NavigationDefaultController.extend({
subcategoryListSetting: Discourse.computed.setting('show_subcategory_list'),
showingParentCategory: Em.computed.none('category.parentCategory'),
showingSubcategoryList: Em.computed.and('subcategoryListSetting', 'showingParentCategory'),
navItems: function() { navItems: function() {
if (this.get('showingSubcategoryList')) { return []; }
return Discourse.NavItem.buildList(this.get('category'), { noSubcategories: this.get('noSubcategories') }); return Discourse.NavItem.buildList(this.get('category'), { noSubcategories: this.get('noSubcategories') });
}.property('category', 'noSubcategories') }.property('category', 'noSubcategories')
}); });

View File

@ -77,6 +77,10 @@ Discourse.Resolver = Ember.DefaultResolver.extend({
return this.customResolve(parsedName) || this._super(parsedName); return this.customResolve(parsedName) || this._super(parsedName);
}, },
resolveRoute: function(parsedName) {
return this.customResolve(parsedName) || this._super(parsedName);
},
/** /**
Attaches a view and wires up the container properly Attaches a view and wires up the container properly

View File

@ -3,6 +3,7 @@ import buildTopicRoute from 'discourse/routes/build-topic-route';
export default { export default {
name: 'dynamic-route-builders', name: 'dynamic-route-builders',
after: 'register-discourse-location',
initialize: function(container, app) { initialize: function(container, app) {
app.DiscoveryCategoryRoute = buildCategoryRoute('latest'); app.DiscoveryCategoryRoute = buildCategoryRoute('latest');

View File

@ -7,7 +7,6 @@
@module Discourse @module Discourse
**/ **/
Discourse.CategoryList = Ember.ArrayProxy.extend({ Discourse.CategoryList = Ember.ArrayProxy.extend({
init: function() { init: function() {
this.content = []; this.content = [];
this._super(); this._super();
@ -22,7 +21,6 @@ Discourse.CategoryList = Ember.ArrayProxy.extend({
}); });
Discourse.CategoryList.reopenClass({ Discourse.CategoryList.reopenClass({
categoriesFrom: function(result) { categoriesFrom: function(result) {
var categories = Discourse.CategoryList.create(), var categories = Discourse.CategoryList.create(),
users = Discourse.Model.extractByKey(result.featured_users, Discourse.User), users = Discourse.Model.extractByKey(result.featured_users, Discourse.User),
@ -55,6 +53,15 @@ Discourse.CategoryList.reopenClass({
return categories; return categories;
}, },
listForParent: function(category) {
var self = this;
return Discourse.ajax('/categories.json?parent_category_id=' + category.get('id')).then(function(result) {
return Discourse.CategoryList.create({
categories: self.categoriesFrom(result)
});
});
},
list: function() { list: function() {
var self = this; var self = this;

View File

@ -1,8 +1,8 @@
// A helper function to create a category route with parameters // A helper function to create a category route with parameters
export default function(filter, params) { export default function(filter, params) {
return Discourse.Route.extend({ return Discourse.Route.extend({
model: function(params) { model: function(modelParams) {
return Discourse.Category.findBySlug(params.slug, params.parentSlug); return Discourse.Category.findBySlug(modelParams.slug, modelParams.parentSlug);
}, },
afterModel: function(model, transaction) { afterModel: function(model, transaction) {
@ -11,21 +11,44 @@ export default function(filter, params) {
return; return;
} }
var self = this,
noSubcategories = params && !!params.no_subcategories,
filterMode = "category/" + Discourse.Category.slugFor(model) + (noSubcategories ? "/none" : "") + "/l/" + filter,
listFilter = "category/" + Discourse.Category.slugFor(model) + "/l/" + filter;
this.controllerFor('search').set('searchContext', model.get('searchContext')); this.controllerFor('search').set('searchContext', model.get('searchContext'));
this._setupNavigation(model);
return Em.RSVP.all([this._createSubcategoryList(model),
this._retrieveTopicList(model, transaction)]);
},
var opts = { category: model, filterMode: filterMode }; _setupNavigation: function(model) {
opts.noSubcategories = params && params.no_subcategories; var noSubcategories = params && !!params.no_subcategories,
opts.canEditCategory = Discourse.User.currentProp('staff'); filterMode = "category/" + Discourse.Category.slugFor(model) + (noSubcategories ? "/none" : "") + "/l/" + filter;
opts.canChangeCategoryNotificationLevel = Discourse.User.current(); this.controllerFor('navigation/category').setProperties({
this.controllerFor('navigation/category').setProperties(opts); category: model,
filterMode: filterMode,
noSubcategories: params && params.no_subcategories,
canEditCategory: Discourse.User.currentProp('staff'),
canChangeCategoryNotificationLevel: Discourse.User.current()
});
},
_createSubcategoryList: function(model) {
this._categoryList = null;
if (Em.isNone(model.get('parentCategory')) && Discourse.SiteSettings.show_subcategory_list) {
var self = this;
return Discourse.CategoryList.listForParent(model).then(function(list) {
console.log('loaded list');
self._categoryList = list;
});
}
// If we're not loading a subcategory list just resolve
return Em.RSVP.resolve();
},
_retrieveTopicList: function(model, transaction) {
var queryParams = transaction.queryParams,
listFilter = "category/" + Discourse.Category.slugFor(model) + "/l/" + filter,
self = this;
var queryParams = transaction.queryParams;
params = params || {}; params = params || {};
if (queryParams && queryParams.order) { params.order = queryParams.order; } if (queryParams && queryParams.order) { params.order = queryParams.order; }
@ -67,6 +90,10 @@ export default function(filter, params) {
renderTemplate: function() { renderTemplate: function() {
this.render('navigation/category', { outlet: 'navigation-bar' }); this.render('navigation/category', { outlet: 'navigation-bar' });
if (this._categoryList) {
this.render('discovery/categories', { outlet: 'header-list-container', model: this._categoryList });
}
this.render('discovery/topics', { controller: 'discovery/topics', outlet: 'list-container' }); this.render('discovery/topics', { controller: 'discovery/topics', outlet: 'list-container' });
}, },

View File

@ -14,7 +14,16 @@
<div class='spinner'>{{i18n loading}}</div> <div class='spinner'>{{i18n loading}}</div>
</div> </div>
<div {{bind-attr class=":container :list-container loadingSpinner:hidden"}}> <div {{bind-attr class=":container :list-container loadingSpinner:hidden"}}>
<div class="row">
<div class="full-width">
<div id='header-list-area'>
{{outlet header-list-container}}
</div>
</div>
</div>
<div class="row"> <div class="row">
<div class="full-width"> <div class="full-width">
<div id='list-area'> <div id='list-area'>

View File

@ -20,16 +20,7 @@
<div> <div>
<div class="pull-left"> <div class="pull-left">
{{#if controller.ordering}}<i class="fa fa-bars"></i>{{/if}} {{#if controller.ordering}}<i class="fa fa-bars"></i>{{/if}}
<h3> {{category-title-link category=this}}
{{#if read_restricted}}<i class='fa fa-group'></i>{{/if}}
{{#link-to 'discovery.parentCategory' this}}
{{#if logo_url}}
<img src="{{unbound logo_url}}" class='category-logo'>
{{else}}
{{unbound name}}
{{/if}}
{{/link-to}}
</h3>
{{#if unreadTopics}} {{#if unreadTopics}}
<a href={{unbound unreadUrl}} class='badge new-posts badge-notification' title='{{i18n topic.unread_topics count="unreadTopics"}}'>{{unbound unreadTopics}}</a> <a href={{unbound unreadUrl}} class='badge new-posts badge-notification' title='{{i18n topic.unread_topics count="unreadTopics"}}'>{{unbound unreadTopics}}</a>
{{/if}} {{/if}}

View File

@ -1,4 +1,7 @@
{{bread-crumbs categories=categories category=category noSubcategories=noSubcategories}} {{bread-crumbs categories=categories
category=category
noSubcategories=noSubcategories
hideSubcategories=showingSubcategoryList}}
<ul class="nav nav-pills" id='navigation-bar'> <ul class="nav nav-pills" id='navigation-bar'>
{{#each navItem in navItems}} {{#each navItem in navItems}}

View File

@ -11,8 +11,9 @@ class CategoriesController < ApplicationController
options = {} options = {}
options[:latest_posts] = params[:latest_posts] || SiteSetting.category_featured_topics options[:latest_posts] = params[:latest_posts] || SiteSetting.category_featured_topics
options[:parent_category_id] = params[:parent_category_id]
@list = CategoryList.new(guardian,options) @list = CategoryList.new(guardian, options)
@list.draft_key = Draft::NEW_TOPIC @list.draft_key = Draft::NEW_TOPIC
@list.draft_sequence = DraftSequence.current(current_user, Draft::NEW_TOPIC) @list.draft_sequence = DraftSequence.current(current_user, Draft::NEW_TOPIC)
@list.draft = Draft.get(current_user, @list.draft_key, @list.draft_sequence) if current_user @list.draft = Draft.get(current_user, @list.draft_key, @list.draft_sequence) if current_user

View File

@ -58,6 +58,10 @@ class CategoryList
.includes(:featured_users, subcategories: [:topic_only_relative_url]) .includes(:featured_users, subcategories: [:topic_only_relative_url])
.secured(@guardian) .secured(@guardian)
if @options[:parent_category_id].present?
@categories = @categories.where('categories.parent_category_id = ?', @options[:parent_category_id].to_i)
end
if SiteSetting.fixed_category_positions if SiteSetting.fixed_category_positions
@categories = @categories.order('position ASC').order('id ASC') @categories = @categories.order('position ASC').order('id ASC')
else else
@ -72,21 +76,23 @@ class CategoryList
end end
@categories = @categories.to_a @categories = @categories.to_a
subcategories = {} if @options[:parent_category_id].blank?
to_delete = Set.new subcategories = {}
@categories.each do |c| to_delete = Set.new
if c.parent_category_id.present?
subcategories[c.parent_category_id] ||= []
subcategories[c.parent_category_id] << c.id
to_delete << c
end
end
if subcategories.present?
@categories.each do |c| @categories.each do |c|
c.subcategory_ids = subcategories[c.id] if c.parent_category_id.present?
subcategories[c.parent_category_id] ||= []
subcategories[c.parent_category_id] << c.id
to_delete << c
end
end
if subcategories.present?
@categories.each do |c|
c.subcategory_ids = subcategories[c.id]
end
@categories.delete_if {|c| to_delete.include?(c) }
end end
@categories.delete_if {|c| to_delete.include?(c) }
end end
if latest_post_only? if latest_post_only?