diff --git a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 index 879c2d37daa..26ac79cd02b 100644 --- a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 +++ b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 @@ -20,6 +20,7 @@ export default { app.DiscoveryCategoryNoneRoute = buildCategoryRoute("default", { no_subcategories: true }); + app.DiscoveryCategoryWithIDRoute = buildCategoryRoute("default"); const site = Site.current(); site.get("filters").forEach(filter => { diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 index 36c3e3a6e55..dc8cdf92f63 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -22,44 +22,55 @@ export default function() { this.route("topicBySlugOrId", { path: "/t/:slugOrId", resetNamespace: true }); this.route("discovery", { path: "/", resetNamespace: true }, function() { + // legacy route + this.route("topParentCategory", { path: "/c/:slug/l/top" }); + // top this.route("top"); - this.route("topParentCategory", { path: "/c/:slug/l/top" }); - this.route("topCategoryNone", { path: "/c/:slug/none/l/top" }); - this.route("topCategory", { path: "/c/:parentSlug/:slug/l/top" }); + this.route("topCategoryNone", { + path: "/c/*categorySlugPathWithID/none/l/top" + }); + this.route("topCategory", { path: "/c/*categorySlugPathWithID/l/top" }); // top by periods Site.currentProp("periods").forEach(period => { const top = "top" + period.capitalize(); - this.route(top, { path: "/top/" + period }); + + // legacy route this.route(top + "ParentCategory", { path: "/c/:slug/l/top/" + period }); + + this.route(top, { path: "/top/" + period }); this.route(top + "CategoryNone", { - path: "/c/:slug/none/l/top/" + period + path: "/c/*categorySlugPathWithID/none/l/top/" + period }); this.route(top + "Category", { - path: "/c/:parentSlug/:slug/l/top/" + period + path: "/c/*categorySlugPathWithID/l/top/" + period }); }); // filters Site.currentProp("filters").forEach(filter => { - this.route(filter, { path: "/" + filter }); + // legacy route this.route(filter + "ParentCategory", { path: "/c/:slug/l/" + filter }); + + this.route(filter, { path: "/" + filter }); this.route(filter + "CategoryNone", { - path: "/c/:slug/none/l/" + filter + path: "/c/*categorySlugPathWithID/none/l/" + filter }); this.route(filter + "Category", { - path: "/c/:parentSlug/:slug/l/" + filter + path: "/c/*categorySlugPathWithID/l/" + filter }); }); this.route("categories"); - // default filter for a category + // legacy routes this.route("parentCategory", { path: "/c/:slug" }); - this.route("categoryNone", { path: "/c/:slug/none" }); - this.route("category", { path: "/c/:parentSlug/:slug" }); this.route("categoryWithID", { path: "/c/:parentSlug/:slug/:id" }); + + // default filter for a category + this.route("categoryNone", { path: "/c/*categorySlugPathWithID/none" }); + this.route("category", { path: "/c/*categorySlugPathWithID" }); }); this.route("groups", { resetNamespace: true, path: "/g" }, function() { diff --git a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 b/app/assets/javascripts/discourse/routes/build-category-route.js.es6 index d360c11eb05..c7cb74613c3 100644 --- a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-category-route.js.es6 @@ -16,11 +16,46 @@ export default (filterArg, params) => { return DiscourseRoute.extend({ queryParams, + serialize(modelParams) { + if (!modelParams.categorySlugPathWithID) { + modelParams.categorySlugPathWithID = [ + modelParams.parentSlug, + modelParams.slug, + modelParams.id + ] + .filter(x => x) + .join("/"); + } + + return modelParams; + }, + model(modelParams) { - const category = Category.findBySlug( - modelParams.slug, - modelParams.parentSlug - ); + modelParams = this.serialize(modelParams); + + const parts = modelParams.categorySlugPathWithID.split("/"); + let category = null; + + if (parts.length > 0 && parts[parts.length - 1].match(/^\d+$/)) { + const id = parseInt(parts.pop(), 10); + + category = Category.findByID(id); + } else { + const [slug, parentSlug] = [...parts].reverse(); + + category = Category.findBySlug(slug, parentSlug); + + if ( + !category && + parts.length > 0 && + parts[parts.length - 1].match(/^\d+-/) + ) { + const id = parseInt(parts.pop(), 10); + + category = Category.findByID(id); + } + } + if (category) { return { category }; } diff --git a/app/assets/javascripts/discourse/routes/discovery-category-with-id.js.es6 b/app/assets/javascripts/discourse/routes/discovery-category-with-id.js.es6 deleted file mode 100644 index e5ed07790ef..00000000000 --- a/app/assets/javascripts/discourse/routes/discovery-category-with-id.js.es6 +++ /dev/null @@ -1,7 +0,0 @@ -import Category from "discourse/models/category"; - -export default Discourse.DiscoveryCategoryRoute.extend({ - model(params) { - return { category: Category.findById(params.id) }; - } -});