Merge pull request from ZogStriP/selecting-default-landing-tab

FIX: allows the selection of the default landing tab
This commit is contained in:
Robin Ward 2013-03-28 08:27:05 -07:00
commit 08267f5171
8 changed files with 81 additions and 88 deletions
app
assets/javascripts/discourse
controllers
models
config
lib
spec/controllers

View file

@ -14,7 +14,7 @@ Discourse.ListController = Discourse.Controller.extend({
canCreateTopic: false, canCreateTopic: false,
needs: ['composer', 'modal', 'listTopics'], needs: ['composer', 'modal', 'listTopics'],
availableNavItems: (function() { availableNavItems: function() {
var hasCategories, loggedOn, summary; var hasCategories, loggedOn, summary;
summary = this.get('filterSummary'); summary = this.get('filterSummary');
loggedOn = !!Discourse.get('currentUser'); loggedOn = !!Discourse.get('currentUser');
@ -28,7 +28,7 @@ Discourse.ListController = Discourse.Controller.extend({
}).filter(function(i) { }).filter(function(i) {
return i !== null; return i !== null;
}); });
}).property('filterSummary'), }.property('filterSummary'),
/** /**
Load a list based on a filter Load a list based on a filter
@ -63,26 +63,23 @@ Discourse.ListController = Discourse.Controller.extend({
}, },
// Put in the appropriate page title based on our view // Put in the appropriate page title based on our view
updateTitle: (function() { updateTitle: function() {
if (this.get('filterMode') === 'categories') { if (this.get('filterMode') === 'categories') {
return Discourse.set('title', Em.String.i18n('categories_list')); return Discourse.set('title', Em.String.i18n('categories_list'));
} else { } else {
if (this.present('category')) { if (this.present('category')) {
return Discourse.set('title', "" + (this.get('category.name').capitalize()) + " " + (Em.String.i18n('topic.list'))); return Discourse.set('title', this.get('category.name').capitalize() + " " + Em.String.i18n('topic.list'));
} else { } else {
return Discourse.set('title', Em.String.i18n('topic.list')); return Discourse.set('title', Em.String.i18n('topic.list'));
} }
} }
}).observes('filterMode', 'category'), }.observes('filterMode', 'category'),
// Create topic button // Create topic button
createTopic: function() { createTopic: function() {
var topicList; var topicList = this.get('controllers.listTopics.content');
topicList = this.get('controllers.listTopics.content'); if (!topicList) return;
if (!topicList) { this.get('controllers.composer').open({
return;
}
return this.get('controllers.composer').open({
categoryName: this.get('category.name'), categoryName: this.get('category.name'),
action: Discourse.Composer.CREATE_TOPIC, action: Discourse.Composer.CREATE_TOPIC,
draftKey: topicList.get('draft_key'), draftKey: topicList.get('draft_key'),
@ -100,5 +97,3 @@ Discourse.ListController = Discourse.Controller.extend({
Discourse.ListController.reopenClass({ Discourse.ListController.reopenClass({
filters: ['latest', 'hot', 'favorited', 'read', 'unread', 'new', 'posted'] filters: ['latest', 'hot', 'favorited', 'read', 'unread', 'new', 'posted']
}); });

View file

@ -6,47 +6,35 @@
@namespace Discourse @namespace Discourse
@module Discourse @module Discourse
**/ **/
var validNavNames = ['read', 'latest', 'hot', 'categories', 'favorited', 'category', 'unread', 'new', 'posted']; var validNavNames = ['latest', 'hot', 'categories', 'category', 'favorited', 'unread', 'new', 'read', 'posted'];
var validAnon = ['latest', 'hot', 'category', 'categories']; var validAnon = ['latest', 'hot', 'categories', 'category'];
Discourse.NavItem = Discourse.Model.extend({ Discourse.NavItem = Discourse.Model.extend({
categoryName: (function() { categoryName: function() {
var split; var split = this.get('name').split('/');
split = this.get('name').split('/'); return split[0] === 'category' ? split[1] : null;
if (split[0] === 'category') { }.property('name'),
return split[1];
} else {
return null;
}
}).property(),
href: (function() {
/* href from this item
*/
var name; // href from this item
name = this.get('name'); href: function() {
if (name === 'category') { var name = this.get('name'),
return Discourse.getURL("/") + name + "/" + (this.get('categoryName')); href = Discourse.getURL("/") + name;
} else { if (name === 'category') href += "/" + this.get('categoryName');
return Discourse.getURL("/") + name; return href;
} }.property('name')
}).property()
}); });
Discourse.NavItem.reopenClass({ Discourse.NavItem.reopenClass({
// create a nav item from the text, will return null if there is not valid nav item for this particular text // create a nav item from the text, will return null if there is not valid nav item for this particular text
fromText: function(text, opts) { fromText: function(text, opts) {
var countSummary, hasCategories, loggedOn, name, split, testName; var countSummary = opts.countSummary,
countSummary = opts.countSummary; split = text.split(","),
loggedOn = opts.loggedOn; name = split[0],
hasCategories = opts.hasCategories; testName = name.split("/")[0];
split = text.split(",");
name = split[0];
testName = name.split("/")[0];
if (!loggedOn && !validAnon.contains(testName)) return null; if (!opts.loggedOn && !validAnon.contains(testName)) return null;
if (!hasCategories && testName === "categories") return null; if (!opts.hasCategories && testName === "categories") return null;
if (!validNavNames.contains(testName)) return null; if (!validNavNames.contains(testName)) return null;
opts = { opts = {
@ -54,14 +42,10 @@ Discourse.NavItem.reopenClass({
hasIcon: name === "unread" || name === "favorited", hasIcon: name === "unread" || name === "favorited",
filters: split.splice(1) filters: split.splice(1)
}; };
if (countSummary) {
if (countSummary && countSummary[name]) { if (countSummary && countSummary[name]) opts.count = countSummary[name];
opts.count = countSummary[name];
}
}
return Discourse.NavItem.create(opts); return Discourse.NavItem.create(opts);
} }
}); });

View file

@ -19,22 +19,20 @@ Discourse.Route.buildRoutes(function() {
router.route(p, { path: "/" + p }); router.route(p, { path: "/" + p });
}); });
this.route('faq', { path: '/faq' });
this.route('tos', { path: '/tos' });
this.route('privacy', { path: '/privacy' });
// List routes // List routes
this.resource('list', { path: '/' }, function() { this.resource('list', { path: '/' }, function() {
router = this; router = this;
// Generate routes for all our filters // Generate routes for all our filters
Discourse.ListController.filters.forEach(function(r) { Discourse.ListController.filters.forEach(function(filter) {
router.route(r, { path: "/" + r }); router.route(filter, { path: "/" + filter });
router.route(r, { path: "/" + r + "/more" }); router.route(filter, { path: "/" + filter + "/more" });
}); });
this.route('latest', { path: '/' }); // the homepage is the first item of the 'top_menu' site setting
this.route('hot', { path: '/hot' }); var homepage = PreloadStore.get('siteSettings').top_menu.split("|")[0];
this.route(homepage, { path: '/' });
this.route('categories', { path: '/categories' }); this.route('categories', { path: '/categories' });
this.route('category', { path: '/category/:slug/more' }); this.route('category', { path: '/category/:slug/more' });
this.route('category', { path: '/category/:slug' }); this.route('category', { path: '/category/:slug' });
@ -51,5 +49,3 @@ Discourse.Route.buildRoutes(function() {
this.route('invited', { path: 'invited' }); this.route('invited', { path: 'invited' });
}); });
}); });

View file

@ -1,12 +1,11 @@
class ListController < ApplicationController class ListController < ApplicationController
before_filter :ensure_logged_in, except: [:index, :hot, :category, :category_feed] before_filter :ensure_logged_in, except: [:latest, :hot, :category, :category_feed]
skip_before_filter :check_xhr skip_before_filter :check_xhr
# Create our filters # Create our filters
[:latest, :hot, :favorited, :read, :posted, :unread, :new].each do |filter| [:latest, :hot, :favorited, :read, :posted, :unread, :new].each do |filter|
define_method(filter) do define_method(filter) do
list_opts = {page: params[:page]} list_opts = {page: params[:page]}
# html format means we need to farm exclude from the site options # html format means we need to farm exclude from the site options
@ -14,7 +13,7 @@ class ListController < ApplicationController
#TODO objectify this stuff #TODO objectify this stuff
SiteSetting.top_menu.split('|').each do |f| SiteSetting.top_menu.split('|').each do |f|
s = f.split(",") s = f.split(",")
if s[0] == action_name || (action_name == "index" && s[0] == "latest") if s[0] == action_name || (action_name == "index" && s[0] == SiteSetting.homepage)
list_opts[:exclude_category] = s[1][1..-1] if s.length == 2 list_opts[:exclude_category] = s[1][1..-1] if s.length == 2
end end
end end
@ -27,7 +26,6 @@ class ListController < ApplicationController
respond(list) respond(list)
end end
end end
alias_method :index, :latest
def category def category

View file

@ -190,4 +190,13 @@ class SiteSetting < ActiveRecord::Base
def self.post_length def self.post_length
min_post_length..max_post_length min_post_length..max_post_length
end end
def self.homepage
top_menu.split('|')[0]
end
def self.anonymous_homepage
top_menu.split('|').select{ |f| ['latest', 'hot', 'categories', 'category'].include? f }[0]
end
end end

View file

@ -1,6 +1,7 @@
require 'sidekiq/web' require 'sidekiq/web'
require_dependency 'admin_constraint' require_dependency 'admin_constraint'
require_dependency 'homepage_constraint'
# This used to be User#username_format, but that causes a preload of the User object # This used to be User#username_format, but that causes a preload of the User object
# and makes Guard not work properly. # and makes Guard not work properly.
@ -154,20 +155,10 @@ Discourse::Application.routes.draw do
get 'popular' => 'list#popular_redirect' get 'popular' => 'list#popular_redirect'
get 'popular/more' => 'list#popular_redirect' get 'popular/more' => 'list#popular_redirect'
get 'latest' => 'list#index' [:latest, :hot, :favorited, :read, :posted, :unread, :new].each do |filter|
get 'latest/more' => 'list#index' get "#{filter}" => "list##{filter}"
get 'hot' => 'list#hot' get "#{filter}/more" => "list##{filter}"
get 'hot/more' => 'list#hot' end
get 'favorited' => 'list#favorited'
get 'favorited/more' => 'list#favorited'
get 'read' => 'list#read'
get 'read/more' => 'list#read'
get 'unread' => 'list#unread'
get 'unread/more' => 'list#unread'
get 'new' => 'list#new'
get 'new/more' => 'list#new'
get 'posted' => 'list#posted'
get 'posted/more' => 'list#posted'
get 'search' => 'search#query' get 'search' => 'search#query'
@ -222,11 +213,12 @@ Discourse::Application.routes.draw do
post 'draft' => 'draft#update' post 'draft' => 'draft#update'
delete 'draft' => 'draft#destroy' delete 'draft' => 'draft#destroy'
get 'robots.txt' => 'robots_txt#index' get 'robots.txt' => 'robots_txt#index'
# You can have the root of your site routed with "root" [:latest, :hot, :unread, :new, :favorited, :read, :posted].each do |filter|
# just remember to delete public/index.html. root to: "list##{filter}", constraints: HomePageConstraint.new("#{filter}")
root to: 'list#index' end
# special case for categories
root to: "categories#index", constraints: HomePageConstraint.new("categories")
end end

View file

@ -0,0 +1,10 @@
class HomePageConstraint
def initialize(filter)
@filter = filter
end
def matches?(request)
homepage = request.session[:current_user_id].present? ? SiteSetting.homepage : SiteSetting.anonymous_homepage
homepage == @filter
end
end

View file

@ -8,12 +8,21 @@ describe ListController do
@post = Fabricate(:post, user: @user) @post = Fabricate(:post, user: @user)
end end
context 'index' do describe 'indexes' do
before do
xhr :get, :index [:latest, :hot].each do |filter|
context '#{filter}' do
before { xhr :get, filter }
it { should respond_with(:success) }
end
end
[:favorited, :read, :posted, :unread, :new].each do |filter|
context '#{filter}' do
it { expect { xhr :get, filter }.to raise_error(Discourse::NotLoggedIn) }
end
end end
it { should respond_with(:success) }
end end
context 'category' do context 'category' do