/** A data model that represents a category @class Category @extends Discourse.Model @namespace Discourse @module Discourse **/ Discourse.Category = Discourse.Model.extend({ init: function() { this._super(); this.set("availableGroups", Em.A(this.get("available_groups"))); this.set("permissions", Em.A(_.map(this.group_permissions, function(elem){ return { group_name: elem.group_name, permission: Discourse.PermissionType.create({id: elem.permission_type}) }; }))); }, availablePermissions: function(){ return [ Discourse.PermissionType.create({id: Discourse.PermissionType.FULL}), Discourse.PermissionType.create({id: Discourse.PermissionType.CREATE_POST}), Discourse.PermissionType.create({id: Discourse.PermissionType.READONLY}) ]; }.property(), searchContext: function() { return ({ type: 'category', id: this.get('id'), category: this }); }.property('id'), url: function() { return Discourse.getURL("/category/") + Discourse.Category.slugFor(this); }.property('name'), unreadUrl: function() { return this.get('url') + '/l/unread'; }.property('url'), newUrl: function() { return this.get('url') + '/l/new'; }.property('url'), style: function() { return "background-color: #" + this.get('category.color') + "; color: #" + this.get('category.text_color') + ";"; }.property('color', 'text_color'), moreTopics: function() { return this.get('topic_count') > Discourse.SiteSettings.category_featured_topics; }.property('topic_count'), save: function() { var url = "/categories"; if (this.get('id')) { url = "/categories/" + this.get('id'); } return Discourse.ajax(url, { data: { name: this.get('name'), color: this.get('color'), text_color: this.get('text_color'), secure: this.get('secure'), permissions: this.get('permissionsForUpdate'), auto_close_hours: this.get('auto_close_hours'), position: this.get('position'), email_in: this.get('email_in'), email_in_allow_strangers: this.get('email_in_allow_strangers'), parent_category_id: this.get('parent_category_id') }, type: this.get('id') ? 'PUT' : 'POST' }); }, permissionsForUpdate: function(){ var rval = {}; _.each(this.get("permissions"),function(p){ rval[p.group_name] = p.permission.id; }); return rval; }.property("permissions"), destroy: function() { return Discourse.ajax("/categories/" + (this.get('slug') || this.get('id')), { type: 'DELETE' }); }, addPermission: function(permission){ this.get("permissions").addObject(permission); this.get("availableGroups").removeObject(permission.group_name); }, removePermission: function(permission){ this.get("permissions").removeObject(permission); this.get("availableGroups").addObject(permission.group_name); }, // note, this is used in a data attribute, data attributes get downcased // to avoid confusion later on using this naming here. description_text: function(){ return $("
" + this.get("description") + "
").text(); }.property("description"), permissions: function(){ return Em.A([ {group_name: "everyone", permission: Discourse.PermissionType.create({id: 1})}, {group_name: "admins", permission: Discourse.PermissionType.create({id: 2}) }, {group_name: "crap", permission: Discourse.PermissionType.create({id: 3}) } ]); }.property(), latestTopic: function(){ var topics = this.get('topics'); if (topics && topics.length) { return topics[0]; } }.property("topics"), featuredTopics: function() { var topics = this.get('topics'); if (topics && topics.length) { return topics.slice(0, Discourse.SiteSettings.category_featured_topics || 2); } }.property('topics'), topicTrackingState: function(){ return Discourse.TopicTrackingState.current(); }.property(), unreadTopics: function(){ return this.get('topicTrackingState').countUnread(this.get('name')); }.property('topicTrackingState.messageCount'), newTopics: function(){ return this.get('topicTrackingState').countNew(this.get('name')); }.property('topicTrackingState.messageCount'), topicStatsTitle: function() { var string = I18n.t('categories.topic_stats'); _.each(this.get('topicCountStats'), function(stat) { string += ' ' + I18n.t('categories.topic_stat_sentence', {count: stat.value, unit: stat.unit}); }, this); return string; }.property('post_count'), postStatsTitle: function() { var string = I18n.t('categories.post_stats'); _.each(this.get('postCountStats'), function(stat) { string += ' ' + I18n.t('categories.post_stat_sentence', {count: stat.value, unit: stat.unit}); }, this); return string; }.property('post_count'), topicCountStats: function() { return this.countStats('topics'); }.property('posts_year', 'posts_month', 'posts_week', 'posts_day'), postCountStats: function() { return this.countStats('posts'); }.property('posts_year', 'posts_month', 'posts_week', 'posts_day'), countStats: function(prefix) { var stats = [], val; _.each(['day', 'week', 'month', 'year'], function(unit) { val = this.get(prefix + '_' + unit); if (val > 0) stats.pushObject({value: val, unit: I18n.t(unit)}); if (stats.length === 2) return false; }, this); return stats; }, isUncategorizedCategory: function() { return this.get('id') === Discourse.Site.currentProp("uncategorized_category_id"); }.property('id') }); Discourse.Category.reopenClass({ slugFor: function(category) { if (!category) return ""; 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('sortedCategories'); }, findSingleBySlug: function(slug) { return Discourse.Category.list().find(function(c) { return Discourse.Category.slugFor(c) === slug; }); }, // TODO: optimise, slow for no real reason findById: function(id){ return Discourse.Category.list().findBy('id', id); }, findByIds: function(ids){ var categories = []; _.each(ids, function(id){ var found = Discourse.Category.findById(id); if(found){ categories.push(found); } }); return categories; }, findBySlug: function(slug, parentSlug) { var categories = Discourse.Category.list(), category; 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); }); } } else { category = Discourse.Category.findSingleBySlug(slug); // If we have a parent category, we need to enforce it if (category && 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); }); } });