Update browse page to new layout and add sorting

openid
Marcin Kulik 11 years ago
parent 249117f80a
commit 100273f5bf

@ -1,5 +1,4 @@
class AsciicastsController < ApplicationController
PER_PAGE = 15
before_filter :load_resource, :only => [:show, :raw, :edit, :update, :destroy]
before_filter :ensure_authenticated!, :only => [:edit, :update, :destroy]
@ -8,23 +7,11 @@ class AsciicastsController < ApplicationController
respond_to :html, :json, :js
def index
@asciicasts = PaginatingDecorator.new(
Asciicast.newest_paginated(params[:page], PER_PAGE)
)
asciicasts = AsciicastList.new(params[:category], params[:order])
@category_name = "All asciicasts"
@current_category = :all
end
def popular
@asciicasts = PaginatingDecorator.new(
Asciicast.popular_paginated(params[:page], PER_PAGE)
)
@category_name = "Popular asciicasts"
@current_category = :popular
render :index
render locals: {
asciicast_list: AsciicastListDecorator.new(asciicasts, params[:page])
}
end
def show

@ -0,0 +1,23 @@
class AsciicastListDecorator < ApplicationDecorator
PER_PAGE = 12
attr_reader :page, :per_page
delegate_all
def initialize(model, page, per_page = nil)
super(model)
@page = page
@per_page = per_page || PER_PAGE
end
def category_name
"#{category.to_s.capitalize} asciicasts"
end
def items
PaginatingDecorator.new(model.items.paginate(page, per_page))
end
end

@ -1,5 +1,6 @@
class Asciicast < ActiveRecord::Base
MAX_DELAY = 5.0
ORDER_MODES = { recency: 'created_at', popularity: 'views_count' }
mount_uploader :stdin_data, StdinDataUploader
mount_uploader :stdin_timing, StdinTimingUploader
@ -30,6 +31,20 @@ class Asciicast < ActiveRecord::Base
Digest::MD5.hexdigest timestamps.join('/')
end
def self.paginate(page, per_page)
page(page).per(per_page)
end
def self.for_category_ordered(category, order)
collection = all
if category == :featured
collection = collection.featured
end
collection.order("#{ORDER_MODES[order]} DESC")
end
def stdout
@stdout ||= BufferedStdout.new(stdout_data.decompressed_path,
stdout_timing.decompressed_path).lazy

@ -0,0 +1,15 @@
class AsciicastList
attr_reader :category, :order, :repository
def initialize(category, order, repository = Asciicast)
@category = (category || :all).to_sym
@order = (order || :recency).to_sym
@repository = repository
end
def items
repository.for_category_ordered(category, order)
end
end

@ -1,9 +1,30 @@
section.supplimental
.wrapper
.main
h1 = @category_name
= render :partial => 'asciicasts/previews', :locals => { :asciicasts => @asciicasts }
= paginate @asciicasts
.asciicasts-list-page
.container
.row
.col-md-3
= render 'shared/browse_categories', current_category: asciicast_list.category
.extras
= render :partial => 'shared/browse_categories'
.col-md-9
.row
.col-md-6
h2 = asciicast_list.category_name
.col-md-6.text-right
.sorting
span Sort by
.btn-group.text-left
button.btn.btn-default.dropdown-toggle[type="button" data-toggle="dropdown"]
| #{asciicast_list.order}
span.caret
ul.dropdown-menu[role="menu"]
li
a href="?order=recency"
| recency
li
a href="?order=popularity"
| popularity
.row.asciicast-list
.col-md-12
= render 'asciicasts/previews', asciicasts: asciicast_list.items, per_row: 2
= paginate asciicast_list.items

@ -0,0 +1,3 @@
<li>
<%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote %>
</li>

@ -0,0 +1,3 @@
<li class="disabled">
<%= link_to raw(t 'views.pagination.truncate'), '#' %>
</li>

@ -0,0 +1,3 @@
<li>
<%= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} %>
</li>

@ -0,0 +1,3 @@
<li>
<%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote %>
</li>

@ -0,0 +1,3 @@
<li class="<%= 'active' if page.current? %>">
<%= link_to page, page.current? ? '#' : url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} %>
</li>

@ -0,0 +1,15 @@
<%= paginator.render do -%>
<ul class="pagination">
<%= first_page_tag unless current_page.first? %>
<%= prev_page_tag unless current_page.first? %>
<% each_page do |page| -%>
<% if page.left_outer? || page.right_outer? || page.inside_window? -%>
<%= page_tag page %>
<% elsif !page.was_truncated? -%>
<%= gap_tag %>
<% end -%>
<% end -%>
<%= next_page_tag unless current_page.last? %>
<%= last_page_tag unless current_page.last? %>
</ul>
<% end -%>

@ -0,0 +1,3 @@
<li>
<%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote %>
</li>

@ -1,17 +0,0 @@
<h1>Browse</h1>
<ul class="delimited">
<li>
<%= link_to_category 'All', browse_path, :all %>
</li>
<li>
<%= link_to_category 'Popular', popular_path, :popular %>
</li>
<% if current_user -%>
<li>
<%= link_to 'Mine', profile_path(current_user) %>
</li>
<% end -%>
</ul>

@ -0,0 +1,5 @@
h2 Browse
= category_links current_category do |categories|
= categories.link_to 'All', browse_path, :all
= categories.link_to 'Featured', category_path(:featured), :featured

@ -1,7 +1,7 @@
Asciinema::Application.routes.draw do
get "/browse" => "asciicasts#index", :as => :browse
get "/browse/popular" => "asciicasts#popular", :as => :popular
get "/browse/:category" => "asciicasts#index", :as => :category
resources :asciicasts, :path => 'a' do
member do

@ -11,49 +11,33 @@ shared_examples_for 'non-owner user trying to modify' do
end
describe AsciicastsController do
let(:user) { stub_model(User, :nickname => 'nick') }
let(:asciicast) { stub_model(Asciicast, :id => 666) }
subject { response }
describe '#index' do
let(:asciicasts) { [double('asciicast')] }
let(:page) { double('page').to_s }
let(:asciicast_list) { double('asciicast_list') }
let(:decorated_asciicast_list) { double('decorated_asciicast_list') }
before do
Asciicast.should_receive(:newest_paginated).
with(page, an_instance_of(Fixnum)).and_return(asciicasts)
allow(controller).to receive(:render)
PaginatingDecorator.should_receive(:new).with(asciicasts).
and_return(asciicasts)
allow(AsciicastList).to receive(:new).
with('featured', 'recency') { asciicast_list }
allow(AsciicastListDecorator).to receive(:new).
with(asciicast_list, '2') { decorated_asciicast_list }
get :index, :page => page
get :index, category: 'featured', order: 'recency', page: '2'
end
it { should be_success }
specify { assigns(:asciicasts).should == asciicasts }
specify { assigns(:category_name).should =~ /^All/ }
specify { assigns(:current_category).should == :all }
end
describe '#popular' do
let(:asciicasts) { [double('asciicast')] }
let(:page) { double('page').to_s }
before do
Asciicast.should_receive(:popular_paginated).
with(page, an_instance_of(Fixnum)).and_return(asciicasts)
PaginatingDecorator.should_receive(:new).with(asciicasts).
and_return(asciicasts)
get :popular, :page => page
it 'renders template with asciicast_list' do
expect(controller).to have_received(:render).
with(locals: { asciicast_list: decorated_asciicast_list })
end
it { should be_success }
specify { assigns(:asciicasts).should == asciicasts }
specify { assigns(:category_name).should =~ /^Popular/ }
specify { assigns(:current_category).should == :popular }
end
describe '#show' do

@ -0,0 +1,34 @@
require 'spec_helper'
describe AsciicastListDecorator do
let(:decorator) { described_class.new(list, 3, 10) }
let(:list) { double('list', category: :foo, items: items) }
let(:items) { double('items', paginate: paginated) }
let(:paginated) { [Asciicast.new] }
describe '#category_name' do
subject { decorator.category_name }
it { should eq('Foo asciicasts') }
end
describe '#items' do
subject { decorator.items }
it 'returns the items paginated' do
expect(subject).to eq(paginated)
expect(items).to have_received(:paginate).with(3, 10)
end
it 'wraps the paginated items in a PaginatingDecorator' do
paginating_decorator = double('paginating_decorator')
allow(PaginatingDecorator).to receive(:new).
with(paginated) { paginating_decorator }
expect(subject).to be(paginating_decorator)
end
end
end

@ -2,25 +2,26 @@ require 'spec_helper'
feature "Asciicast lists" do
let!(:asciicast) { create(:asciicast) }
let!(:asciicast) { create(:asciicast, title: 'foo bar') }
let!(:featured_asciicast) { create(:asciicast, title: 'qux', featured: true) }
scenario 'Visiting all' do
visit browse_path
expect(page).to have_content(/All Asciicasts/i)
expect_browse_links
expect(page).to have_link("bashing")
expect(page).to have_selector('.supplimental .play-button')
expect(page).to have_link("foo bar")
expect(page).to have_selector('.asciicast-list .play-button')
end
scenario 'Visiting popular' do
scenario 'Visiting featured' do
visit asciicast_path(asciicast)
visit popular_path
visit category_path(:featured)
expect(page).to have_content(/Popular Asciicasts/i)
expect(page).to have_content(/Featured Asciicasts/i)
expect_browse_links
expect(page).to have_link("bashing")
expect(page).to have_selector('.supplimental .play-button')
expect(page).to have_link("qux")
expect(page).to have_selector('.asciicast-list .play-button')
end
end

@ -0,0 +1,63 @@
require 'spec_helper'
describe AsciicastList do
let(:list) { described_class.new(category, order, repository) }
let(:category) { 'featured' }
let(:order) { 'recency' }
let(:repository) { double('repository') }
describe '#category' do
subject { list.category }
context "when it was passed as a string" do
let(:category) { 'thecat' }
it { should eq(:thecat) }
end
context "when it was passed as nil" do
let(:category) { nil }
it { should eq(:all) }
end
end
describe '#order' do
subject { list.order }
context "when it was passed as a string" do
let(:order) { 'thecat' }
it { should eq(:thecat) }
end
context "when it was passed as nil" do
let(:order) { nil }
it { should eq(:recency) }
end
end
describe '#items' do
subject { list.items }
let(:category) { 'foo' }
let(:order) { 'bar' }
let(:asciicasts) { [Asciicast.new] }
before do
allow(repository).to receive(:for_category_ordered) { asciicasts }
subject
end
it { should eq(asciicasts) }
it 'calls for_category_ordered on repository with proper args' do
expect(repository).to have_received(:for_category_ordered).
with(:foo, :bar)
end
end
end

@ -3,6 +3,55 @@ require 'tempfile'
describe Asciicast do
describe '.for_category_ordered' do
subject { described_class.for_category_ordered(category, order) }
let!(:asciicast_1) { create(:asciicast, created_at: 2.hours.ago,
views_count: 10,
featured: false) }
let!(:asciicast_2) { create(:asciicast, created_at: 1.hour.ago,
views_count: 20,
featured: true) }
let!(:asciicast_3) { create(:asciicast, created_at: 4.hours.ago,
views_count: 30,
featured: false) }
let!(:asciicast_4) { create(:asciicast, created_at: 3.hours.ago,
views_count: 40,
featured: true) }
context "when category is :all" do
let(:category) { :all }
context "and order is :recency" do
let(:order) { :recency }
it { should eq([asciicast_2, asciicast_1, asciicast_4, asciicast_3]) }
end
context "and order is :popularity" do
let(:order) { :popularity }
it { should eq([asciicast_4, asciicast_3, asciicast_2, asciicast_1]) }
end
end
context "when category is :featured" do
let(:category) { :featured }
context "and order is :recency" do
let(:order) { :recency }
it { should eq([asciicast_2, asciicast_4]) }
end
context "and order is :popularity" do
let(:order) { :popularity }
it { should eq([asciicast_4, asciicast_2]) }
end
end
end
let(:asciicast) { described_class.new }
describe '#stdout' do

@ -3,7 +3,7 @@ module Asciinema
def expect_browse_links
expect(page).to have_link('All')
expect(page).to have_link('Popular')
expect(page).to have_link('Featured')
end
def expect_doc_links

Loading…
Cancel
Save