Routes and support for sub-categories

This commit is contained in:
Robin Ward
2013-10-23 14:40:39 -04:00
parent 49a11e51df
commit 541620c115
15 changed files with 206 additions and 92 deletions

View File

@@ -33,22 +33,26 @@ Discourse.Utilities = {
}
},
// Create a badge like category link
/**
Create a badge-like category link
@method categoryLink
@param {Discourse.Category} category the category whose link we want
@returns {String} the html category badge
**/
categoryLink: function(category) {
if (!category) return "";
var color = Em.get(category, 'color');
var textColor = Em.get(category, 'text_color');
var name = Em.get(category, 'name');
var description = Em.get(category, 'description');
// Build the HTML link
var result = "<a href=\"" + Discourse.getURL("/category/") + Discourse.Category.slugFor(category) + "\" class=\"badge-category\" ";
var color = Em.get(category, 'color'),
textColor = Em.get(category, 'text_color'),
name = Em.get(category, 'name'),
description = Em.get(category, 'description'),
html = "<a href=\"" + Discourse.getURL("/category/") + Discourse.Category.slugFor(category) + "\" class=\"badge-category\" ";
// Add description if we have it
if (description) result += "title=\"" + Handlebars.Utils.escapeExpression(description) + "\" ";
if (description) html += "title=\"" + Handlebars.Utils.escapeExpression(description) + "\" ";
return result + "style=\"background-color: #" + color + "; color: #" + textColor + ";\">" + name + "</a>";
return html + "style=\"background-color: #" + color + "; color: #" + textColor + ";\">" + name + "</a>";
},
avatarUrl: function(template, size) {

View File

@@ -132,18 +132,56 @@ Discourse.Category.reopenClass({
slugFor: function(category) {
if (!category) return "";
var id = Em.get(category, 'id');
var slug = Em.get(category, 'slug');
if (!slug || slug.trim().length === 0) return "" + id + "-category";
return slug;
var parentCategory = Em.get(category, 'parentCategory'),
result = "";
if (parentCategory) {
result = Discourse.Category.slugFor(parentCategory) + "/";
}
var id = Em.get(category, 'id'),
slug = Em.get(category, 'slug');
if (!slug || slug.trim().length === 0) return result + id + "-category";
return result + slug;
},
list: function() {
return Discourse.Site.currentProp('categories');
},
findBySlugOrId: function(slugOrId) {
// TODO: all our routing around categories need a rethink
findBySlug: function(slug, parentSlug) {
var uncategorized = Discourse.Category.uncategorizedInstance();
if (slug === uncategorized.get('slug')) return uncategorized;
var categories = Discourse.Category.list(),
category;
if (parentSlug) {
var parentCategory = categories.findBy('slug', parentSlug);
if (parentCategory) {
category = categories.find(function(item) {
return item && item.get('parentCategory') === parentCategory && item.get('slug') === slug;
});
}
} else {
category = categories.findBy('slug', slug);
// If we have a parent category, we need to enforce it
if (category.get('parentCategory')) return;
}
// In case the slug didn't work, try to find it by id instead.
if (!category) {
category = categories.findBy('id', parseInt(slug, 10));
}
return category;
},
reloadBySlugOrId: function(slugOrId) {
return Discourse.ajax("/category/" + slugOrId + "/show.json").then(function (result) {
return Discourse.Category.create(result.category);
});

View File

@@ -24,18 +24,23 @@ Discourse.CategoryList = Ember.ArrayProxy.extend({
Discourse.CategoryList.reopenClass({
categoriesFrom: function(result) {
var categories = Discourse.CategoryList.create();
var users = Discourse.Model.extractByKey(result.featured_users, Discourse.User);
var categories = Discourse.CategoryList.create(),
users = Discourse.Model.extractByKey(result.featured_users, Discourse.User),
list = Discourse.Category.list();
result.category_list.categories.forEach(function(c) {
if (c.parent_category_id) {
c.parentCategory = list.findBy('id', c.parent_category_id);
}
_.each(result.category_list.categories,function(c) {
if (c.featured_user_ids) {
c.featured_users = _.map(c.featured_user_ids,function(u) {
c.featured_users = c.featured_user_ids.map(function(u) {
return users[u];
});
}
if (c.topics) {
c.topics = _.map(c.topics,function(t) {
c.topics = c.topics.map(function(t) {
return Discourse.Topic.create(t);
});
}
@@ -58,8 +63,9 @@ Discourse.CategoryList.reopenClass({
},
list: function(filter) {
var self = this;
var finder = null;
var self = this,
finder = null;
if (filter === 'categories') {
finder = PreloadStore.getAndRemove("categories_list", function() {
return Discourse.ajax("/categories.json");

View File

@@ -48,7 +48,7 @@ Discourse.Site.reopenClass(Discourse.Singleton, {
var result = this._super(obj);
if (result.categories) {
var byId = {}
var byId = {};
result.categories = _.map(result.categories, function(c) {
byId[c.id] = Discourse.Category.create(c);
return byId[c.id];
@@ -59,7 +59,7 @@ Discourse.Site.reopenClass(Discourse.Singleton, {
if (c.get('parent_category_id')) {
c.set('parentCategory', byId[c.get('parent_category_id')]);
}
})
});
}
if (result.trust_levels) {

View File

@@ -83,9 +83,9 @@ Discourse.TopicList = Discourse.Model.extend({
Discourse.TopicList.reopenClass({
loadTopics: function(topic_ids, filter) {
var defer = new Ember.Deferred();
var defer = new Ember.Deferred(),
url = Discourse.getURL("/") + filter + "?topic_ids=" + topic_ids.join(",");
var url = Discourse.getURL("/") + filter + "?topic_ids=" + topic_ids.join(",");
Discourse.ajax({url: url}).then(function (result) {
if (result) {
// the new topics loaded from the server
@@ -107,37 +107,45 @@ Discourse.TopicList.reopenClass({
return defer;
},
/**
Stitch together side loaded topic data
@method topicsFrom
@param {Object} JSON object with topic data
@returns {Array} the list of topics
**/
topicsFrom: function(result) {
// Stitch together our side loaded data
var categories, topics, users;
categories = this.extractByKey(result.categories, Discourse.Category);
users = this.extractByKey(result.users, Discourse.User);
topics = Em.A();
var categories = Discourse.Category.list(),
users = this.extractByKey(result.users, Discourse.User),
topics = Em.A();
_.each(result.topic_list.topics,function(ft) {
ft.category = categories[ft.category_id];
_.each(ft.posters,function(p) {
return result.topic_list.topics.map(function (t) {
t.category = categories.findBy('id', t.category_id);
t.posters.forEach(function(p) {
p.user = users[p.user_id];
});
topics.pushObject(Discourse.Topic.create(ft));
return Discourse.Topic.create(t);
});
return topics;
},
/**
Lists topics on a given menu item
@method list
@param {Object} The menu item to filter to
@returns {Promise} a promise that resolves to the list of topics
**/
list: function(menuItem) {
var filter = menuItem.get('name');
var filter = menuItem.get('name'),
session = Discourse.Session.current(),
list = session.get('topicList');
var session = Discourse.Session.current();
var list = session.get('topicList');
if (list) {
if ((list.get('filter') === filter) && window.location.pathname.indexOf('more') > 0) {
list.set('loaded', true);
return Ember.RSVP.resolve(list);
}
if (list && (list.get('filter') === filter) && window.location.pathname.indexOf('more') > 0) {
list.set('loaded', true);
return Ember.RSVP.resolve(list);
}
session.set('topicList', null);
session.set('topicListScrollPos', null);
session.setProperties({topicList: null, topicListScrollPos: null});
return Discourse.TopicList.find(filter, menuItem.get('excludeCategory'));
}

View File

@@ -68,7 +68,7 @@ Discourse.ApplicationRoute = Em.Route.extend({
Discourse.Route.showModal(router, 'editCategory', category);
router.controllerFor('editCategory').set('selectedTab', 'general');
} else {
Discourse.Category.findBySlugOrId(category.get('slug') || category.get('id')).then(function (c) {
Discourse.Category.reloadBySlugOrId(category.get('slug') || category.get('id')).then(function (c) {
Discourse.Site.current().updateCategory(c);
Discourse.Route.showModal(router, 'editCategory', c);
router.controllerFor('editCategory').set('selectedTab', 'general');

View File

@@ -29,13 +29,14 @@ Discourse.Route.buildRoutes(function() {
});
// the homepage is the first item of the 'top_menu' site setting
var settings = Discourse.SiteSettings;
var homepage = settings.top_menu.split("|")[0].split(",")[0];
var homepage = Discourse.SiteSettings.top_menu.split("|")[0].split(",")[0];
this.route(homepage, { path: '/' });
this.route('categories', { path: '/categories' });
this.route('category', { path: '/category/:slug/more' });
this.route('category', { path: '/category/:slug' });
this.route('category', { path: '/category/:slug/more' });
this.route('category', { path: '/category/:parentSlug/:slug' });
this.route('category', { path: '/category/:parentSlug/:slug/more' });
});
// User routes

View File

@@ -9,21 +9,7 @@
Discourse.ListCategoryRoute = Discourse.FilteredListRoute.extend({
model: function(params) {
var categories = Discourse.Category.list();
var slug = Em.get(params, 'slug');
var uncategorized = Discourse.Category.uncategorizedInstance();
if (slug === uncategorized.get('slug')) return uncategorized;
var category = categories.findProperty('slug', Em.get(params, 'slug'));
// In case the slug didn't work, try to find it by id instead.
if (!category) {
category = categories.findProperty('id', parseInt(slug, 10));
}
return category;
return Discourse.Category.findBySlug(Em.get(params, 'slug'), Em.get(params, 'parentSlug'));
},
setupController: function(controller, category) {
@@ -35,16 +21,18 @@ Discourse.ListCategoryRoute = Discourse.FilteredListRoute.extend({
}
}
var listController = this.controllerFor('list');
var urlId = Discourse.Category.slugFor(category);
listController.set('filterMode', "category/" + urlId);
var listController = this.controllerFor('list'),
urlId = Discourse.Category.slugFor(category),
self = this;
var router = this;
listController.set('filterMode', "category/" + urlId);
listController.load("category/" + urlId).then(function(topicList) {
listController.set('canCreateTopic', topicList.get('can_create_topic'));
listController.set('category', category);
router.controllerFor('listTopics').set('content', topicList);
router.controllerFor('listTopics').set('category', category);
listController.setProperties({
canCreateTopic: topicList.get('can_create_topic'),
category: category
});
self.controllerFor('listTopics').set('content', topicList);
self.controllerFor('listTopics').set('category', category);
});
},

View File

@@ -62,7 +62,12 @@ class ListController < ApplicationController
@description = @category.description
end
list.more_topics_url = url_for(category_list_path(params[:category], page: next_page, format: "json"))
if params[:parent_category].present?
list.more_topics_url = url_for(category_list_parent_path(params[:parent_category], params[:category], page: next_page, format: "json"))
else
list.more_topics_url = url_for(category_list_path(params[:category], page: next_page, format: "json"))
end
respond(list)
end
@@ -118,7 +123,18 @@ class ListController < ApplicationController
def set_category
slug = params.fetch(:category)
@category = Category.where("slug = ?", slug).includes(:featured_users).first || Category.where("id = ?", slug.to_i).includes(:featured_users).first
parent_slug = params[:parent_category]
parent_category_id = nil
if parent_slug.present?
parent_category_id = Category.where(slug: parent_slug).pluck(:id).first ||
Category.where(id: parent_slug.to_i).pluck(:id).first
raise Discourse::NotFound.new if parent_category_id.blank?
end
@category = Category.where(slug: slug, parent_category_id: parent_category_id).includes(:featured_users).first ||
Category.where(id: slug.to_i, parent_category_id: parent_category_id).includes(:featured_users).first
end
def request_is_for_uncategorized?

View File

@@ -13,4 +13,8 @@ class BasicCategorySerializer < ApplicationSerializer
:permission,
:parent_category_id
def include_parent_category_id?
parent_category_id
end
end

View File

@@ -1,16 +1,9 @@
class CategoryDetailedSerializer < ApplicationSerializer
class CategoryDetailedSerializer < BasicCategorySerializer
attributes :id,
:name,
:color,
:text_color,
:slug,
:topic_count,
:post_count,
attributes :post_count,
:topics_week,
:topics_month,
:topics_year,
:description,
:description_excerpt,
:is_uncategorized

View File

@@ -6,9 +6,9 @@ class TopicListItemSerializer < ListableTopicSerializer
:has_best_of,
:archetype,
:rank_details,
:last_poster_username
:last_poster_username,
:category_id
has_one :category, serializer: BasicCategorySerializer
has_many :posters, serializer: TopicPosterSerializer, embed: :objects
def starred