Can assign a parent category to a category.

This commit is contained in:
Robin Ward 2013-10-24 17:03:28 -04:00
parent ee2dd9d24c
commit 61468f6f27
10 changed files with 67 additions and 27 deletions

View File

@ -13,6 +13,12 @@ Discourse.EditCategoryController = Discourse.ObjectController.extend(Discourse.M
settingsSelected: Ember.computed.equal('selectedTab', 'settings'), settingsSelected: Ember.computed.equal('selectedTab', 'settings'),
foregroundColors: ['FFFFFF', '000000'], foregroundColors: ['FFFFFF', '000000'],
parentCategories: function() {
return Discourse.Category.list().filter(function (c) {
return !c.get('parentCategory');
});
}.property(),
onShow: function() { onShow: function() {
this.changeSize(); this.changeSize();
this.titleChanged(); this.titleChanged();
@ -122,17 +128,27 @@ Discourse.EditCategoryController = Discourse.ObjectController.extend(Discourse.M
}, },
saveCategory: function() { saveCategory: function() {
var categoryController = this; var self = this,
model = this.get('model'),
parentCategory = Discourse.Category.list().findBy('id', parseInt(model.get('parent_category_id'), 10));
this.set('saving', true); this.set('saving', true);
model.set('parentCategory', parentCategory);
var newSlug = Discourse.Category.slugFor(this.get('model'));
this.get('model').save().then(function(result) { this.get('model').save().then(function(result) {
// success // success
categoryController.send('closeModal'); self.send('closeModal');
Discourse.URL.redirectTo("/category/" + Discourse.Category.slugFor(result.category)); Discourse.URL.redirectTo("/category/" + newSlug);
}, function(errors) { }, function(error) {
// errors
if(errors.length === 0) errors.push(I18n.t("category.creation_error")); if (error && error.responseText) {
categoryController.displayErrors(errors); self.flash($.parseJSON(error.responseText).errors[0]);
categoryController.set('saving', false); } else {
self.flash(I18n.t('generic_error'));
}
self.set('saving', false);
}); });
}, },
@ -147,8 +163,14 @@ Discourse.EditCategoryController = Discourse.ObjectController.extend(Discourse.M
// success // success
self.send('closeModal'); self.send('closeModal');
Discourse.URL.redirectTo("/categories"); Discourse.URL.redirectTo("/categories");
}, function(jqXHR){ }, function(error){
// error
if (error && error.responseText) {
self.flash($.parseJSON(error.responseText).errors[0]);
} else {
self.flash(I18n.t('generic_error'));
}
self.send('showModal'); self.send('showModal');
self.displayErrors([I18n.t("category.delete_error")]); self.displayErrors([I18n.t("category.delete_error")]);
self.set('deleting', false); self.set('deleting', false);

View File

@ -58,7 +58,8 @@ Discourse.Category = Discourse.Model.extend({
secure: this.get('secure'), secure: this.get('secure'),
permissions: this.get('permissionsForUpdate'), permissions: this.get('permissionsForUpdate'),
auto_close_days: this.get('auto_close_days'), auto_close_days: this.get('auto_close_days'),
position: this.get('position') position: this.get('position'),
parent_category_id: this.get('parent_category_id')
}, },
type: this.get('id') ? 'PUT' : 'POST' type: this.get('id') ? 'PUT' : 'POST'
}); });

View File

@ -21,6 +21,11 @@
{{textField value=name placeholderKey="category.name_placeholder" maxlength="50"}} {{textField value=name placeholderKey="category.name_placeholder" maxlength="50"}}
</section> </section>
<section class='field'>
<label>{{i18n category.parent}}</label>
{{categoryChooser valueAttribute="id" value=parent_category_id categories=parentCategories}}
</section>
{{#unless isUncategorized}} {{#unless isUncategorized}}
<section class='field'> <section class='field'>
<label>{{i18n category.description}}</label> <label>{{i18n category.description}}</label>

View File

@ -12,14 +12,16 @@ Discourse.CategoryChooserView = Discourse.ComboboxView.extend({
dataAttributes: ['name', 'color', 'text_color', 'description_text', 'topic_count'], dataAttributes: ['name', 'color', 'text_color', 'description_text', 'topic_count'],
valueBinding: Ember.Binding.oneWay('source'), valueBinding: Ember.Binding.oneWay('source'),
content: Em.computed.filter('categories', function(c) {
var uncategorized_id = Discourse.Site.currentProp("uncategorized_category_id");
return c.get('permission') === Discourse.PermissionType.FULL && c.get('id') !== uncategorized_id;
}),
init: function() { init: function() {
this._super(); this._super();
// TODO perhaps allow passing a param in to select if we need full or not if (!this.get('categories')) {
this.set('categories', Discourse.Category.list());
var uncategorized_id = Discourse.Site.currentProp("uncategorized_category_id"); }
this.set('content', _.filter(Discourse.Category.list(), function(c){
return c.permission === Discourse.PermissionType.FULL && c.id !== uncategorized_id;
}));
}, },
none: function() { none: function() {

View File

@ -27,12 +27,6 @@ Discourse.ModalBodyView = Discourse.View.extend({
} }
}, },
// Pass the errors to our errors view
displayErrors: function(errors, callback) {
this.set('parentView.parentView.modalErrorsView.errors', errors);
if (typeof callback === "function") callback();
},
flashMessageChanged: function() { flashMessageChanged: function() {
var flashMessage = this.get('controller.flashMessage'); var flashMessage = this.get('controller.flashMessage');
if (flashMessage) { if (flashMessage) {

View File

@ -164,6 +164,19 @@
border-bottom: 1px solid #bbb; border-bottom: 1px solid #bbb;
} }
.category-combobox {
width: 430px;
.chzn-drop {
left: -9000px;
width: 428px;
}
.chzn-search input {
width: 378px;
}
}
&.hidden { &.hidden {
display: none; display: none;
} }

View File

@ -90,7 +90,7 @@ class CategoriesController < ApplicationController
end end
end end
params.permit(*required_param_keys, :position, :hotness, :auto_close_days, :permissions => [*p.try(:keys)]) params.permit(*required_param_keys, :position, :hotness, :parent_category_id, :auto_close_days, :permissions => [*p.try(:keys)])
end end
end end

View File

@ -187,10 +187,10 @@ SQL
def parent_category_validator def parent_category_validator
if parent_category_id if parent_category_id
errors.add(:parent_category_id, "You can't link a category to itself") if parent_category_id == id errors.add(:parent_category_id, I18n.t("category.errors.self_parent")) if parent_category_id == id
grandfather_id = Category.where(id: parent_category_id).pluck(:parent_category_id).first grandfather_id = Category.where(id: parent_category_id).pluck(:parent_category_id).first
errors.add(:parent_category_id, "You can't have more than one level of subcategory") if grandfather_id errors.add(:base, I18n.t("category.errors.depth")) if grandfather_id
end end
end end

View File

@ -975,6 +975,7 @@ en:
add_permission: "Add Permission" add_permission: "Add Permission"
this_year: "this year" this_year: "this year"
position: "position" position: "position"
parent: "Parent Category"
flagging: flagging:
title: 'Why are you flagging this post?' title: 'Why are you flagging this post?'

View File

@ -159,7 +159,9 @@ en:
topic_prefix: "Category definition for %{category}" topic_prefix: "Category definition for %{category}"
replace_paragraph: "[Replace this first paragraph with a short description of your new category. This guidance will appear in the category selection area, so try to keep it below 200 characters.]" replace_paragraph: "[Replace this first paragraph with a short description of your new category. This guidance will appear in the category selection area, so try to keep it below 200 characters.]"
post_template: "%{replace_paragraph}\n\nUse the following paragraphs for a longer description, as well as to establish any category guidelines or rules.\n\nSome things to consider in any discussion replies below:\n\n- What is this category for? Why should people select this category for their topic?\n\n- How is this different than the other categories we already have?\n\n- Do we need this category?\n\n- Should we merge this with another category, or split it into more categories?\n" post_template: "%{replace_paragraph}\n\nUse the following paragraphs for a longer description, as well as to establish any category guidelines or rules.\n\nSome things to consider in any discussion replies below:\n\n- What is this category for? Why should people select this category for their topic?\n\n- How is this different than the other categories we already have?\n\n- Do we need this category?\n\n- Should we merge this with another category, or split it into more categories?\n"
errors:
self_parent: "A subcategory's parent cannot be itself."
depth: "You can't nest a subcategory under another."
trust_levels: trust_levels:
newuser: newuser:
title: "new user" title: "new user"