diff --git a/app/assets/javascripts/admin/components/screened_ip_address_form_component.js b/app/assets/javascripts/admin/components/screened_ip_address_form_component.js new file mode 100644 index 00000000000..dbae5a9aac9 --- /dev/null +++ b/app/assets/javascripts/admin/components/screened_ip_address_form_component.js @@ -0,0 +1,64 @@ +/** + A form to create an IP address that will be blocked or whitelisted. + Example usage: + + {{screened-ip-address-form action="recordAdded"}} + + where action is a callback on the controller or route that will get called after + the new record is successfully saved. It is called with the new ScreenedIpAddress record + as an argument. + + @class ScreenedIpAddressFormComponent + @extends Ember.Component + @namespace Discourse + @module Discourse +**/ +Discourse.ScreenedIpAddressFormComponent = Ember.Component.extend({ + classNames: ['screened-ip-address-form'], + formSubmitted: false, + actionName: 'block', + + actionNames: function() { + return [ + {id: 'block', name: I18n.t('admin.logs.screened_ips.actions.block')}, + {id: 'do_nothing', name: I18n.t('admin.logs.screened_ips.actions.do_nothing')} + ]; + }.property(), + + actions: { + submit: function() { + if (!this.get('formSubmitted')) { + var self = this; + this.set('formSubmitted', true); + var screenedIpAddress = Discourse.ScreenedIpAddress.create({ip_address: this.get('ip_address'), action_name: this.get('actionName')}); + screenedIpAddress.save().then(function(result) { + self.set('ip_address', ''); + self.set('formSubmitted', false); + self.sendAction('action', Discourse.ScreenedIpAddress.create(result.screened_ip_address)); + Em.run.schedule('afterRender', function() { self.$('.ip-address-input').focus(); }); + }, function(e) { + self.set('formSubmitted', false); + var msg; + if (e.responseJSON && e.responseJSON.errors) { + msg = I18n.t("generic_error_with_reason", {error: e.responseJSON.errors.join('. ')}); + } else { + msg = I18n.t("generic_error"); + } + bootbox.alert(msg, function() { self.$('.ip-address-input').focus(); }); + }); + } + } + }, + + didInsertElement: function(e) { + var self = this; + this._super(); + Em.run.schedule('afterRender', function() { + self.$('.ip-address-input').keydown(function(e) { + if (e.keyCode === 13) { // enter key + self.send('submit'); + } + }); + }); + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin_logs_screened_ip_addresses_controller.js b/app/assets/javascripts/admin/controllers/admin_logs_screened_ip_addresses_controller.js index 303b7fb3434..bbf06d69921 100644 --- a/app/assets/javascripts/admin/controllers/admin_logs_screened_ip_addresses_controller.js +++ b/app/assets/javascripts/admin/controllers/admin_logs_screened_ip_addresses_controller.js @@ -18,6 +18,12 @@ Discourse.AdminLogsScreenedIpAddressesController = Ember.ArrayController.extend( self.set('content', result); self.set('loading', false); }); + }, + + actions: { + recordAdded: function(arg) { + this.get("content").unshiftObject(arg); + } } }); @@ -27,12 +33,12 @@ Discourse.AdminLogsScreenedIpAddressController = Ember.ObjectController.extend({ actions: { allow: function(record) { - record.set('action', 'do_nothing'); + record.set('action_name', 'do_nothing'); this.send('save', record); }, block: function(record) { - record.set('action', 'block'); + record.set('action_name', 'block'); this.send('save', record); }, diff --git a/app/assets/javascripts/admin/models/screened_ip_address.js b/app/assets/javascripts/admin/models/screened_ip_address.js index 5a635214d1e..b209d7f6205 100644 --- a/app/assets/javascripts/admin/models/screened_ip_address.js +++ b/app/assets/javascripts/admin/models/screened_ip_address.js @@ -9,20 +9,20 @@ **/ Discourse.ScreenedIpAddress = Discourse.Model.extend({ actionName: function() { - return I18n.t("admin.logs.screened_ips.actions." + this.get('action')); - }.property('action'), + return I18n.t("admin.logs.screened_ips.actions." + this.get('action_name')); + }.property('action_name'), isBlocked: function() { - return (this.get('action') === 'block'); - }.property('action'), + return (this.get('action_name') === 'block'); + }.property('action_name'), actionIcon: function() { - if (this.get('action') === 'block') { + if (this.get('action_name') === 'block') { return this.get('blockIcon'); } else { return this.get('doNothingIcon'); } - }.property('action'), + }.property('action_name'), blockIcon: function() { return 'icon-ban-circle'; @@ -33,9 +33,9 @@ Discourse.ScreenedIpAddress = Discourse.Model.extend({ }.property(), save: function() { - return Discourse.ajax("/admin/logs/screened_ip_addresses/" + this.get('id') + ".json", { - type: 'PUT', - data: {ip_address: this.get('ip_address'), action_name: this.get('action')} + return Discourse.ajax("/admin/logs/screened_ip_addresses" + (this.id ? '/' + this.id : '') + ".json", { + type: this.id ? 'PUT' : 'POST', + data: {ip_address: this.get('ip_address'), action_name: this.get('action_name')} }); }, diff --git a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.js.handlebars b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.js.handlebars index b929daf340c..920306ae7e6 100644 --- a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.js.handlebars +++ b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.js.handlebars @@ -1,5 +1,8 @@

{{i18n admin.logs.screened_ips.description}}

+{{screened-ip-address-form action="recordAdded"}} +
+ {{#if loading}}
{{i18n loading}}
{{else}} diff --git a/app/assets/javascripts/application.js.erb b/app/assets/javascripts/application.js.erb index d81c2f245c8..eabbd1ea23a 100644 --- a/app/assets/javascripts/application.js.erb +++ b/app/assets/javascripts/application.js.erb @@ -7,7 +7,7 @@ //= require ./env // probe framework first -//= require ./discourse/components/probes.js +//= require ./discourse/lib/probes.js // Externals we need to load first diff --git a/app/assets/javascripts/discourse/components/breadcrumbs_component.js b/app/assets/javascripts/discourse/components/breadcrumbs_component.js index b60c811f372..1f4d900942e 100644 --- a/app/assets/javascripts/discourse/components/breadcrumbs_component.js +++ b/app/assets/javascripts/discourse/components/breadcrumbs_component.js @@ -1,5 +1,22 @@ Discourse.DiscourseBreadcrumbsComponent = Ember.Component.extend({ classNames: ['category-breadcrumb'], tagName: 'ol', - parentCategory: Em.computed.alias('category.parentCategory') + parentCategory: Em.computed.alias('category.parentCategory'), + + parentCategories: Em.computed.filter('categories', function(c) { + return !c.get('parentCategory'); + }), + + targetCategory: function() { + // Note we can't use Em.computed.or here because it returns a boolean not the object + return this.get('parentCategory') || this.get('category'); + }.property('parentCategory', 'category'), + + childCategories: function() { + var self = this; + return this.get('categories').filter(function (c) { + return c.get('parentCategory') === self.get('targetCategory'); + }); + }.property('targetCategory') + }); diff --git a/app/assets/javascripts/discourse/components/categorydrop_component.js b/app/assets/javascripts/discourse/components/categorydrop_component.js new file mode 100644 index 00000000000..0eb45d09951 --- /dev/null +++ b/app/assets/javascripts/discourse/components/categorydrop_component.js @@ -0,0 +1,54 @@ +Discourse.DiscourseCategorydropComponent = Ember.Component.extend({ + classNameBindings: ['category::no-category', 'categories:has-drop'], + tagName: 'li', + + iconClass: function() { + if (this.get('expanded')) { return "icon icon-caret-down"; } + return "icon icon-caret-right"; + }.property('expanded'), + + badgeStyle: function() { + var category = this.get('category'); + if (category) { + return Discourse.HTML.categoryStyle(category); + } else { + return "background-color: #eee; color: #333"; + } + }.property('category'), + + actions: { + expand: function() { + if (this.get('expanded')) { + this.close(); + return; + } + + if (this.get('categories')) { + this.set('expanded', true); + } + var self = this, + $dropdown = this.$()[0]; + + $('html').on('click.category-drop', function(e) { + var $target = $(e.target), + closest = $target.closest($dropdown); + + return ($(e.currentTarget).hasClass('badge-category') || (closest.length && closest[0] === $dropdown)) ? true : self.close(); + }); + } + }, + + categoryChanged: function() { + this.close(); + }.observes('category', 'parentCategory'), + + close: function() { + $('html').off('click.category-drop'); + this.set('expanded', false); + }, + + willDestroyElement: function() { + $('html').off('click.category-drop'); + } + +}); diff --git a/app/assets/javascripts/discourse/controllers/edit_category_controller.js b/app/assets/javascripts/discourse/controllers/edit_category_controller.js index 0686254af13..6be805503a9 100644 --- a/app/assets/javascripts/discourse/controllers/edit_category_controller.js +++ b/app/assets/javascripts/discourse/controllers/edit_category_controller.js @@ -13,6 +13,12 @@ Discourse.EditCategoryController = Discourse.ObjectController.extend(Discourse.M settingsSelected: Ember.computed.equal('selectedTab', 'settings'), foregroundColors: ['FFFFFF', '000000'], + parentCategories: function() { + return Discourse.Category.list().filter(function (c) { + return !c.get('parentCategory'); + }); + }.property(), + onShow: function() { this.changeSize(); this.titleChanged(); @@ -122,17 +128,27 @@ Discourse.EditCategoryController = Discourse.ObjectController.extend(Discourse.M }, 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); + model.set('parentCategory', parentCategory); + var newSlug = Discourse.Category.slugFor(this.get('model')); + this.get('model').save().then(function(result) { // success - categoryController.send('closeModal'); - Discourse.URL.redirectTo("/category/" + Discourse.Category.slugFor(result.category)); - }, function(errors) { - // errors - if(errors.length === 0) errors.push(I18n.t("category.creation_error")); - categoryController.displayErrors(errors); - categoryController.set('saving', false); + self.send('closeModal'); + Discourse.URL.redirectTo("/category/" + newSlug); + }, function(error) { + + if (error && error.responseText) { + self.flash($.parseJSON(error.responseText).errors[0]); + } else { + self.flash(I18n.t('generic_error')); + } + + self.set('saving', false); }); }, @@ -147,8 +163,14 @@ Discourse.EditCategoryController = Discourse.ObjectController.extend(Discourse.M // success self.send('closeModal'); Discourse.URL.redirectTo("/categories"); - }, function(jqXHR){ - // error + }, function(error){ + + if (error && error.responseText) { + self.flash($.parseJSON(error.responseText).errors[0]); + } else { + self.flash(I18n.t('generic_error')); + } + self.send('showModal'); self.displayErrors([I18n.t("category.delete_error")]); self.set('deleting', false); diff --git a/app/assets/javascripts/discourse/controllers/list_controller.js b/app/assets/javascripts/discourse/controllers/list_controller.js index edf9765fdeb..45f02dc7115 100644 --- a/app/assets/javascripts/discourse/controllers/list_controller.js +++ b/app/assets/javascripts/discourse/controllers/list_controller.js @@ -7,32 +7,34 @@ @module Discourse **/ Discourse.ListController = Discourse.Controller.extend({ - categoryBinding: 'topicList.category', + categoryBinding: "topicList.category", canCreateCategory: false, canCreateTopic: false, - needs: ['composer', 'modal', 'listTopics'], + needs: ["composer", "modal", "listTopics"], availableNavItems: function() { var loggedOn = !!Discourse.User.current(); + var category = this.get("category"); return Discourse.SiteSettings.top_menu.split("|").map(function(i) { return Discourse.NavItem.fromText(i, { - loggedOn: loggedOn + loggedOn: loggedOn, + category: category }); }).filter(function(i) { - return i !== null; + return i !== null && !(category && i.get("name").indexOf("categor") === 0); }); - }.property(), + }.property("category"), createTopicText: function() { - if (this.get('category.name')) { + if (this.get("category.name")) { return I18n.t("topic.create_in", { - categoryName: this.get('category.name') + categoryName: this.get("category.name") }); } else { return I18n.t("topic.create"); } - }.property('category.name'), + }.property("category.name"), /** Refresh our current topic list @@ -132,7 +134,11 @@ Discourse.ListController = Discourse.Controller.extend({ } else { return false; } - }.property('category') + }.property('category'), + + categories: function() { + return Discourse.Category.list(); + }.property() }); diff --git a/app/assets/javascripts/discourse/controllers/static_controller.js b/app/assets/javascripts/discourse/controllers/static_controller.js index 9cf97a139aa..e02d6fee20a 100644 --- a/app/assets/javascripts/discourse/controllers/static_controller.js +++ b/app/assets/javascripts/discourse/controllers/static_controller.js @@ -7,8 +7,15 @@ @module Discourse **/ Discourse.StaticController = Discourse.Controller.extend({ + needs: ['header'], + path: null, + + showLoginButton: function() { + return this.get('path') === '/login'; + }.property('path'), loadPath: function(path) { + this.set('path', path); var staticController = this; this.set('content', null); diff --git a/app/assets/javascripts/discourse/helpers/application_helpers.js b/app/assets/javascripts/discourse/helpers/application_helpers.js index e1c58b29d19..adb570eb276 100644 --- a/app/assets/javascripts/discourse/helpers/application_helpers.js +++ b/app/assets/javascripts/discourse/helpers/application_helpers.js @@ -29,12 +29,32 @@ Handlebars.registerHelper('shorten', function(property, options) { @for Handlebars **/ Handlebars.registerHelper('topicLink', function(property, options) { - var title, topic; - topic = Ember.Handlebars.get(this, property, options); - title = topic.get('fancy_title') || topic.get('title'); - return "" + title + ""; + var topic = Ember.Handlebars.get(this, property, options), + title = topic.get('fancy_title') || topic.get('title'); + return "" + title + ""; }); + +/** + Produces a link to a category given a category object and helper options + + @method categoryLinkHTML + @param {Discourse.Category} category to link to + @param {Object} options standard from handlebars +**/ +function categoryLinkHTML(category, options) { + var categoryOptions = {}; + if (options.hash) { + if (options.hash.allowUncategorized) { + categoryOptions.allowUncategorized = true; + } + if (options.hash.categories) { + categoryOptions.categories = Em.Handlebars.get(this, options.hash.categories, options); + } + } + return new Handlebars.SafeString(Discourse.HTML.categoryLink(category, categoryOptions)); +} + /** Produces a link to a category @@ -42,21 +62,16 @@ Handlebars.registerHelper('topicLink', function(property, options) { @for Handlebars **/ Handlebars.registerHelper('categoryLink', function(property, options) { - var allowUncategorized = options.hash && options.hash.allowUncategorized; - var category = Ember.Handlebars.get(this, property, options); - return new Handlebars.SafeString(Discourse.Utilities.categoryLink(category, allowUncategorized)); + return categoryLinkHTML(Ember.Handlebars.get(this, property, options), options); }); - /** Produces a bound link to a category @method boundCategoryLink @for Handlebars **/ -Ember.Handlebars.registerBoundHelper('boundCategoryLink', function(category) { - return new Handlebars.SafeString(Discourse.Utilities.categoryLink(category)); -}); +Ember.Handlebars.registerBoundHelper('boundCategoryLink', categoryLinkHTML); /** Produces a link to a route with support for i18n on the title diff --git a/app/assets/javascripts/discourse/components/autocomplete.js b/app/assets/javascripts/discourse/lib/autocomplete.js similarity index 100% rename from app/assets/javascripts/discourse/components/autocomplete.js rename to app/assets/javascripts/discourse/lib/autocomplete.js diff --git a/app/assets/javascripts/discourse/components/caret_position.js b/app/assets/javascripts/discourse/lib/caret_position.js similarity index 100% rename from app/assets/javascripts/discourse/components/caret_position.js rename to app/assets/javascripts/discourse/lib/caret_position.js diff --git a/app/assets/javascripts/discourse/components/click_track.js b/app/assets/javascripts/discourse/lib/click_track.js similarity index 100% rename from app/assets/javascripts/discourse/components/click_track.js rename to app/assets/javascripts/discourse/lib/click_track.js diff --git a/app/assets/javascripts/discourse/components/computed.js b/app/assets/javascripts/discourse/lib/computed.js similarity index 100% rename from app/assets/javascripts/discourse/components/computed.js rename to app/assets/javascripts/discourse/lib/computed.js diff --git a/app/assets/javascripts/discourse/components/debounce.js b/app/assets/javascripts/discourse/lib/debounce.js similarity index 100% rename from app/assets/javascripts/discourse/components/debounce.js rename to app/assets/javascripts/discourse/lib/debounce.js diff --git a/app/assets/javascripts/discourse/components/development.js b/app/assets/javascripts/discourse/lib/development.js similarity index 100% rename from app/assets/javascripts/discourse/components/development.js rename to app/assets/javascripts/discourse/lib/development.js diff --git a/app/assets/javascripts/discourse/components/div_resizer.js b/app/assets/javascripts/discourse/lib/div_resizer.js similarity index 100% rename from app/assets/javascripts/discourse/components/div_resizer.js rename to app/assets/javascripts/discourse/lib/div_resizer.js diff --git a/app/assets/javascripts/discourse/components/eyeline.js b/app/assets/javascripts/discourse/lib/eyeline.js similarity index 100% rename from app/assets/javascripts/discourse/components/eyeline.js rename to app/assets/javascripts/discourse/lib/eyeline.js diff --git a/app/assets/javascripts/discourse/components/formatter.js b/app/assets/javascripts/discourse/lib/formatter.js similarity index 100% rename from app/assets/javascripts/discourse/components/formatter.js rename to app/assets/javascripts/discourse/lib/formatter.js diff --git a/app/assets/javascripts/discourse/lib/html.js b/app/assets/javascripts/discourse/lib/html.js new file mode 100644 index 00000000000..e204d998370 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/html.js @@ -0,0 +1,60 @@ +/** + Helpers to build HTML strings such as rich links to categories and topics. + + @class HTML + @namespace Discourse + @module Discourse +**/ +Discourse.HTML = { + + /** + Returns the CSS styles for a category + + @method categoryStyle + @param {Discourse.Category} category the category whose link we want + **/ + categoryStyle: function(category) { + var color = Em.get(category, 'color'), + textColor = Em.get(category, 'text_color'); + + if (!color && !textColor) { return; } + + // Add the custom style if we need to + var style = ""; + if (color) { style += "background-color: #" + color + "; "; } + if (textColor) { style += "color: #" + textColor + "; "; } + return style; + }, + + /** + Create a badge-like category link + + @method categoryLink + @param {Discourse.Category} category the category whose link we want + @param {Object} opts The options for the category link + @param {Boolean} opts.allowUncategorized Whether we allow rendering of the uncategorized category + @returns {String} the html category badge + **/ + categoryLink: function(category, opts) { + opts = opts || {}; + + if ((!category) || + (!opts.allowUncategorized && Em.get(category, 'id') === Discourse.Site.currentProp("uncategorized_category_id"))) return ""; + + var name = Em.get(category, 'name'), + description = Em.get(category, 'description'), + html = ""; + + return html; + } + +}; \ No newline at end of file diff --git a/app/assets/javascripts/discourse/components/key_value_store.js b/app/assets/javascripts/discourse/lib/key_value_store.js similarity index 100% rename from app/assets/javascripts/discourse/components/key_value_store.js rename to app/assets/javascripts/discourse/lib/key_value_store.js diff --git a/app/assets/javascripts/discourse/components/lightbox.js b/app/assets/javascripts/discourse/lib/lightbox.js similarity index 100% rename from app/assets/javascripts/discourse/components/lightbox.js rename to app/assets/javascripts/discourse/lib/lightbox.js diff --git a/app/assets/javascripts/discourse/components/markdown.js b/app/assets/javascripts/discourse/lib/markdown.js similarity index 100% rename from app/assets/javascripts/discourse/components/markdown.js rename to app/assets/javascripts/discourse/lib/markdown.js diff --git a/app/assets/javascripts/discourse/components/mention.js b/app/assets/javascripts/discourse/lib/mention.js similarity index 100% rename from app/assets/javascripts/discourse/components/mention.js rename to app/assets/javascripts/discourse/lib/mention.js diff --git a/app/assets/javascripts/discourse/components/message_bus.js b/app/assets/javascripts/discourse/lib/message_bus.js similarity index 100% rename from app/assets/javascripts/discourse/components/message_bus.js rename to app/assets/javascripts/discourse/lib/message_bus.js diff --git a/app/assets/javascripts/discourse/components/mobile.js b/app/assets/javascripts/discourse/lib/mobile.js similarity index 100% rename from app/assets/javascripts/discourse/components/mobile.js rename to app/assets/javascripts/discourse/lib/mobile.js diff --git a/app/assets/javascripts/discourse/components/onebox.js b/app/assets/javascripts/discourse/lib/onebox.js similarity index 100% rename from app/assets/javascripts/discourse/components/onebox.js rename to app/assets/javascripts/discourse/lib/onebox.js diff --git a/app/assets/javascripts/discourse/components/probes.js b/app/assets/javascripts/discourse/lib/probes.js similarity index 100% rename from app/assets/javascripts/discourse/components/probes.js rename to app/assets/javascripts/discourse/lib/probes.js diff --git a/app/assets/javascripts/discourse/components/quote.js b/app/assets/javascripts/discourse/lib/quote.js similarity index 100% rename from app/assets/javascripts/discourse/components/quote.js rename to app/assets/javascripts/discourse/lib/quote.js diff --git a/app/assets/javascripts/discourse/components/screen_track.js b/app/assets/javascripts/discourse/lib/screen_track.js similarity index 100% rename from app/assets/javascripts/discourse/components/screen_track.js rename to app/assets/javascripts/discourse/lib/screen_track.js diff --git a/app/assets/javascripts/discourse/components/search.js b/app/assets/javascripts/discourse/lib/search.js similarity index 100% rename from app/assets/javascripts/discourse/components/search.js rename to app/assets/javascripts/discourse/lib/search.js diff --git a/app/assets/javascripts/discourse/components/syntax_highlighting.js b/app/assets/javascripts/discourse/lib/syntax_highlighting.js similarity index 100% rename from app/assets/javascripts/discourse/components/syntax_highlighting.js rename to app/assets/javascripts/discourse/lib/syntax_highlighting.js diff --git a/app/assets/javascripts/discourse/components/transition_helper.js b/app/assets/javascripts/discourse/lib/transition_helper.js similarity index 100% rename from app/assets/javascripts/discourse/components/transition_helper.js rename to app/assets/javascripts/discourse/lib/transition_helper.js diff --git a/app/assets/javascripts/discourse/components/url.js b/app/assets/javascripts/discourse/lib/url.js similarity index 100% rename from app/assets/javascripts/discourse/components/url.js rename to app/assets/javascripts/discourse/lib/url.js diff --git a/app/assets/javascripts/discourse/components/user_search.js b/app/assets/javascripts/discourse/lib/user_search.js similarity index 100% rename from app/assets/javascripts/discourse/components/user_search.js rename to app/assets/javascripts/discourse/lib/user_search.js diff --git a/app/assets/javascripts/discourse/components/utilities.js b/app/assets/javascripts/discourse/lib/utilities.js similarity index 91% rename from app/assets/javascripts/discourse/components/utilities.js rename to app/assets/javascripts/discourse/lib/utilities.js index eef2ed1e23e..e2e3060945b 100644 --- a/app/assets/javascripts/discourse/components/utilities.js +++ b/app/assets/javascripts/discourse/lib/utilities.js @@ -33,29 +33,6 @@ Discourse.Utilities = { } }, - /** - 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, allowUncategorized) { - if (!category) return ""; - if (!allowUncategorized && Em.get(category, 'id') === Discourse.Site.currentProp("uncategorized_category_id")) return ""; - - var color = Em.get(category, 'color'), - textColor = Em.get(category, 'text_color'), - name = Em.get(category, 'name'), - description = Em.get(category, 'description'), - html = "" + name + ""; - }, - avatarUrl: function(template, size) { if (!template) { return ""; } var rawSize = Discourse.Utilities.getRawSize(Discourse.Utilities.translateSize(size)); diff --git a/app/assets/javascripts/discourse/models/category.js b/app/assets/javascripts/discourse/models/category.js index cf32f9d93ff..dc75876c55c 100644 --- a/app/assets/javascripts/discourse/models/category.js +++ b/app/assets/javascripts/discourse/models/category.js @@ -34,6 +34,13 @@ Discourse.Category = Discourse.Model.extend({ return Discourse.getURL("/category/") + (this.get('slug')); }.property('name'), + unreadUrl: function() { + return this.get('url') + '/unread'; + }.property('url'), + + newUrl: function() { + return this.get('url') + '/new'; + }.property('url'), style: function() { return "background-color: #" + (this.get('category.color')) + "; color: #" + (this.get('category.text_color')) + ";"; @@ -58,7 +65,8 @@ Discourse.Category = Discourse.Model.extend({ secure: this.get('secure'), permissions: this.get('permissionsForUpdate'), 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' }); diff --git a/app/assets/javascripts/discourse/models/nav_item.js b/app/assets/javascripts/discourse/models/nav_item.js index c4df6c42dc9..0a58954beb8 100644 --- a/app/assets/javascripts/discourse/models/nav_item.js +++ b/app/assets/javascripts/discourse/models/nav_item.js @@ -31,18 +31,32 @@ Discourse.NavItem = Discourse.Model.extend({ // href from this item href: function() { + return Discourse.getURL("/") + this.get('filterMode'); + }.property('filterMode'), + + // href from this item + filterMode: function() { var name = this.get('name'); if( name.split('/')[0] === 'category' ) { - return Discourse.getURL("/") + 'category/' + this.get('categorySlug'); + return 'category/' + this.get('categorySlug'); } else { - return Discourse.getURL("/") + name.replace(' ', '-'); + var mode = ""; + var category = this.get("category"); + if(category){ + mode += "category/"; + + var parentSlug = category.get('parentCategory.slug'); + if (parentSlug) { mode += parentSlug + "/"; } + mode += category.get("slug") + "/l/"; + } + return mode + name.replace(' ', '-'); } }.property('name'), count: function() { var state = this.get('topicTrackingState'); if (state) { - return state.lookupCount(this.get('name')); + return state.lookupCount(this.get('name'), this.get('category')); } }.property('topicTrackingState.messageCount'), @@ -71,7 +85,8 @@ Discourse.NavItem.reopenClass({ opts = { name: name, hasIcon: name === "unread" || name === "favorited", - filters: split.splice(1) + filters: split.splice(1), + category: opts.category }; return Discourse.NavItem.create(opts); diff --git a/app/assets/javascripts/discourse/models/topic_list.js b/app/assets/javascripts/discourse/models/topic_list.js index 97b6ea4ab73..f27400cddf6 100644 --- a/app/assets/javascripts/discourse/models/topic_list.js +++ b/app/assets/javascripts/discourse/models/topic_list.js @@ -146,7 +146,6 @@ Discourse.TopicList.reopenClass({ return Ember.RSVP.resolve(list); } session.setProperties({topicList: null, topicListScrollPos: null}); - return Discourse.TopicList.find(filter, menuItem.get('excludeCategory')); } }); diff --git a/app/assets/javascripts/discourse/models/topic_tracking_state.js b/app/assets/javascripts/discourse/models/topic_tracking_state.js index 882d0dd6af3..90584c7839a 100644 --- a/app/assets/javascripts/discourse/models/topic_tracking_state.js +++ b/app/assets/javascripts/discourse/models/topic_tracking_state.js @@ -159,15 +159,16 @@ Discourse.TopicTrackingState = Discourse.Model.extend({ return count; }, - lookupCount: function(name){ + lookupCount: function(name, category){ + var categoryName = Em.get(category, "name"); if(name==="new") { - return this.countNew(); + return this.countNew(categoryName); } else if(name==="unread") { - return this.countUnread(); + return this.countUnread(categoryName); } else { - var category = name.split("/")[1]; - if(category) { - return this.countCategory(category); + categoryName = name.split("/")[1]; + if(categoryName) { + return this.countCategory(categoryName); } } }, diff --git a/app/assets/javascripts/discourse/routes/application_routes.js b/app/assets/javascripts/discourse/routes/application_routes.js index 1d7f4db2eef..139b863591c 100644 --- a/app/assets/javascripts/discourse/routes/application_routes.js +++ b/app/assets/javascripts/discourse/routes/application_routes.js @@ -26,8 +26,10 @@ Discourse.Route.buildRoutes(function() { Discourse.ListController.filters.forEach(function(filter) { router.route(filter, { path: "/" + filter }); router.route(filter, { path: "/" + filter + "/more" }); - router.route(filter + "Category", { path: "/category/:slug/" + filter }); - router.route(filter + "Category", { path: "/category/:slug/" + filter + "/more" }); + router.route(filter + "Category", { path: "/category/:slug/l/" + filter }); + router.route(filter + "Category", { path: "/category/:slug/l/" + filter + "/more" }); + router.route(filter + "Category", { path: "/category/:parentSlug/:slug/l/" + filter }); + router.route(filter + "Category", { path: "/category/:parentSlug/:slug/l/" + filter + "/more" }); }); diff --git a/app/assets/javascripts/discourse/routes/list_category_route.js b/app/assets/javascripts/discourse/routes/list_category_route.js index cef425dff8e..c9257a99551 100644 --- a/app/assets/javascripts/discourse/routes/list_category_route.js +++ b/app/assets/javascripts/discourse/routes/list_category_route.js @@ -22,11 +22,13 @@ Discourse.ListCategoryRoute = Discourse.FilteredListRoute.extend({ } var listController = this.controllerFor('list'), - urlId = Discourse.Category.slugFor(category), - self = this; + categorySlug = Discourse.Category.slugFor(category), + self = this, + filter = this.filter || "latest", + url = "category/" + categorySlug + "/l/" + filter; - listController.set('filterMode', "category/" + urlId); - listController.load("category/" + urlId).then(function(topicList) { + listController.set('filterMode', url); + listController.load(url).then(function(topicList) { listController.setProperties({ canCreateTopic: topicList.get('can_create_topic'), category: category diff --git a/app/assets/javascripts/discourse/templates/components/discourse-breadcrumbs.js.handlebars b/app/assets/javascripts/discourse/templates/components/discourse-breadcrumbs.js.handlebars index e076c749ffb..a67132bf284 100644 --- a/app/assets/javascripts/discourse/templates/components/discourse-breadcrumbs.js.handlebars +++ b/app/assets/javascripts/discourse/templates/components/discourse-breadcrumbs.js.handlebars @@ -1,17 +1,12 @@
  • - {{title}} - +{{discourse-categorydrop parentCategory=category categories=parentCategories}} +
  • +
  • + {{discourse-categorydrop parentCategory=category category=targetCategory categories=childCategories}}
  • - {{#if parentCategory}}
  • - {{discourse-categorydrop category=parentCategory categories=categories}} -
  • -{{/if}} - -{{#if category}} -
  • - {{discourse-categorydrop category=category}} + {{boundCategoryLink category}}
  • {{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/discourse-categorydrop.js.handlebars b/app/assets/javascripts/discourse/templates/components/discourse-categorydrop.js.handlebars index 35ba8bcf4a8..c7431539092 100644 --- a/app/assets/javascripts/discourse/templates/components/discourse-categorydrop.js.handlebars +++ b/app/assets/javascripts/discourse/templates/components/discourse-categorydrop.js.handlebars @@ -1,4 +1,12 @@ -{{categoryLink category}} +{{#if category}} + {{boundCategoryLink category allowUncategorized=true}} +{{else}} + +{{/if}} + {{#if categories}} - -{{/if}} \ No newline at end of file + +
    + {{#each categories}}
    {{categoryLink this allowUncategorized=true}}
    {{/each}} +
    +{{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/screened-ip-address-form.handlebars b/app/assets/javascripts/discourse/templates/components/screened-ip-address-form.handlebars new file mode 100644 index 00000000000..04ee5701372 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/screened-ip-address-form.handlebars @@ -0,0 +1,4 @@ +{{i18n admin.logs.screened_ips.form.label}} +{{textField value=ip_address disabled=formSubmitted class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.ip_address" autocorrect="off" autocapitalize="off"}} +{{combobox content=actionNames value=actionName}} + diff --git a/app/assets/javascripts/discourse/templates/header.js.handlebars b/app/assets/javascripts/discourse/templates/header.js.handlebars index c3790dde11c..f5cc6a7422c 100644 --- a/app/assets/javascripts/discourse/templates/header.js.handlebars +++ b/app/assets/javascripts/discourse/templates/header.js.handlebars @@ -144,7 +144,7 @@ {{#each categories}}
  • - {{categoryLink this}} + {{categoryLink this allowUncategorized=true}} {{unbound topic_count}}
  • {{/each}} diff --git a/app/assets/javascripts/discourse/templates/list.js.handlebars b/app/assets/javascripts/discourse/templates/list.js.handlebars index 2f5a9f32d2b..ab0c79b242f 100644 --- a/app/assets/javascripts/discourse/templates/list.js.handlebars +++ b/app/assets/javascripts/discourse/templates/list.js.handlebars @@ -1,5 +1,10 @@ -
    +
    + + {{#if category}} + {{discourse-breadcrumbs category=category categories=categories}} + {{/if}} + diff --git a/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars b/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars index 81d25ea5e7a..a1f65f4cfe8 100644 --- a/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars +++ b/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars @@ -41,9 +41,11 @@ {{/if}} +{{#unless controller.category}} {{categoryLink category}} +{{/unless}} {{#each posters}} diff --git a/app/assets/javascripts/discourse/templates/list/topics.js.handlebars b/app/assets/javascripts/discourse/templates/list/topics.js.handlebars index c5d8ad3faf8..9753fda8580 100644 --- a/app/assets/javascripts/discourse/templates/list/topics.js.handlebars +++ b/app/assets/javascripts/discourse/templates/list/topics.js.handlebars @@ -10,10 +10,6 @@ {{/if}} - {{#if category}} - {{discourse-breadcrumbs title=Discourse.SiteSettings.title category=category categories=categories}} - {{/if}} - @@ -23,7 +19,9 @@ + {{#unless category}} + {{/unless}} diff --git a/app/assets/javascripts/discourse/templates/list/wide_categories.js.handlebars b/app/assets/javascripts/discourse/templates/list/wide_categories.js.handlebars index 444d63133ec..d76e8549591 100644 --- a/app/assets/javascripts/discourse/templates/list/wide_categories.js.handlebars +++ b/app/assets/javascripts/discourse/templates/list/wide_categories.js.handlebars @@ -22,10 +22,10 @@ {{/if}} {{categoryLink this allowUncategorized=true}} {{#if unreadTopics}} - {{unbound unreadTopics}} + {{unbound unreadTopics}} {{/if}} {{#if newTopics}} - {{unbound newTopics}} + {{unbound newTopics}} {{/if}}
    {{i18n topic.title}} {{i18n category_title}}{{i18n top_contributors}} {{i18n posts}}