admino 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95d1dd4a6bc98fcad84bb9d2269ac8104bdc4beb
4
- data.tar.gz: c5a3bf57e8c8c22abb5f3f26a45e324c8204415a
3
+ metadata.gz: e3846d45b87e8e04505a972b8deabf753e7518ed
4
+ data.tar.gz: f5a5177a520c3e14ce1828f0158e983ae230f93e
5
5
  SHA512:
6
- metadata.gz: 222f144346d9e0c3666f7eb682c716599bd883376265d7ad10bb257805d39e8d0cdcade04fd7ac3cf73d2ca9f5bedb888ac4b534db6df5c0e03aff2c535f9ca5
7
- data.tar.gz: 8a1117eb95c79108304c0d27e02578843f9a3bb985718202d1401d5b44cd8c44c263d83bfa5a1cc67dbb1a15d90cbc66a45e30921b1487d0619ebea5bb557bc2
6
+ metadata.gz: c063c612bd312def34cccd381533613f7c13aa2ad27470065ebe1ec90671ad3abf71a49893a7986e9c1dae0aa757c5dc0f2b59285f863d610a331173a4f25fb7
7
+ data.tar.gz: dc64e3c91e279a3c631bdd1cdd7503d17b6945e8b6b3ccbc39566d9246b3007108ec09e3ba5e0588d01d4b2b2004e6ad5d1e578b340906b1812b7ee902d38707
@@ -1,3 +1,7 @@
1
+ # v0.0.2
2
+
3
+ * Support to sortings
4
+
1
5
  # v0.0.1
2
6
 
3
7
  * First release
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Admino
2
2
 
3
+ [![Build Status](https://travis-ci.org/cantierecreativo/admino.png?branch=v0.0.1)](https://travis-ci.org/cantierecreativo/admino)
4
+ [![Coverage Status](https://coveralls.io/repos/cantierecreativo/admino/badge.png?branch=master)](https://coveralls.io/r/cantierecreativo/admino?branch=master)
5
+
3
6
  TODO: Write a gem description
4
7
 
5
8
  ## Installation
@@ -27,3 +30,4 @@ TODO: Write usage instructions here
27
30
  3. Commit your changes (`git commit -am 'Add some feature'`)
28
31
  4. Push to the branch (`git push origin my-new-feature`)
29
32
  5. Create new Pull Request
33
+
@@ -4,6 +4,8 @@ require 'admino/query/configuration'
4
4
  require 'admino/query/field'
5
5
  require 'admino/query/group'
6
6
  require 'admino/query/group_presenter'
7
+ require 'admino/query/sorting'
8
+ require 'admino/query/sorting_presenter'
7
9
 
8
10
  module Admino
9
11
  module Query
@@ -15,6 +15,7 @@ module Admino
15
15
  attr_reader :params
16
16
  attr_reader :groups
17
17
  attr_reader :fields
18
+ attr_reader :sorting
18
19
 
19
20
  def self.i18n_scope
20
21
  :query
@@ -26,6 +27,7 @@ module Admino
26
27
 
27
28
  init_groups
28
29
  init_fields
30
+ init_sorting
29
31
  end
30
32
 
31
33
  def scope(starting_scope = nil)
@@ -37,7 +39,10 @@ module Admino
37
39
 
38
40
  scope_builder = starting_scope
39
41
 
40
- (fields + groups).each do |field|
42
+ scope_augmenters = fields + groups
43
+ scope_augmenters << sorting if sorting
44
+
45
+ scope_augmenters.each do |field|
41
46
  scope_builder = field.augment_scope(scope_builder)
42
47
  end
43
48
 
@@ -88,6 +93,12 @@ module Admino
88
93
  @fields[config.name] = Field.new(config, params)
89
94
  end
90
95
  end
96
+
97
+ def init_sorting
98
+ if config.sorting
99
+ @sorting = Sorting.new(config.sorting, params)
100
+ end
101
+ end
91
102
  end
92
103
  end
93
104
  end
@@ -4,6 +4,7 @@ module Admino
4
4
  module Query
5
5
  class BasePresenter < Showcase::Presenter
6
6
  presents_collection :groups
7
+ presents :sorting
7
8
 
8
9
  def form(options = {}, &block)
9
10
  h.form_for(
@@ -27,8 +27,29 @@ module Admino
27
27
  end
28
28
  end
29
29
 
30
+ class Sorting
31
+ attr_reader :scopes
32
+ attr_reader :default_scope
33
+ attr_reader :default_direction
34
+
35
+ def initialize(scopes, options = {})
36
+ options.symbolize_keys!
37
+ options.assert_valid_keys(:default_scope, :default_direction)
38
+
39
+ @scopes = scopes.map(&:to_sym)
40
+ @default_scope = if options[:default_scope]
41
+ options[:default_scope].to_sym
42
+ end
43
+
44
+ @default_direction = if options[:default_direction]
45
+ options[:default_direction].to_sym
46
+ end
47
+ end
48
+ end
49
+
30
50
  attr_reader :fields
31
51
  attr_reader :groups
52
+ attr_reader :sorting
32
53
  attr_accessor :starting_scope_callable
33
54
  attr_accessor :ending_scope_callable
34
55
 
@@ -48,6 +69,10 @@ module Admino
48
69
  self.groups << group
49
70
  end
50
71
  end
72
+
73
+ def add_sorting_scopes(scopes, options = {})
74
+ @sorting = Sorting.new(scopes, options)
75
+ end
51
76
  end
52
77
  end
53
78
  end
@@ -17,6 +17,11 @@ module Admino
17
17
  config.add_group(name, scopes)
18
18
  end
19
19
 
20
+ def sorting(*args)
21
+ options = args.extract_options!
22
+ config.add_sorting_scopes(args, options)
23
+ end
24
+
20
25
  def starting_scope(&block)
21
26
  config.starting_scope_callable = block
22
27
  end
@@ -15,14 +15,14 @@ module Admino
15
15
  end
16
16
 
17
17
  def augment_scope(scope)
18
- if current_scope
19
- scope.send(current_scope)
18
+ if active_scope
19
+ scope.send(active_scope)
20
20
  else
21
21
  scope
22
22
  end
23
23
  end
24
24
 
25
- def current_scope
25
+ def active_scope
26
26
  if param_value && available_scopes.include?(param_value.to_sym)
27
27
  param_value.to_sym
28
28
  else
@@ -31,7 +31,7 @@ module Admino
31
31
  end
32
32
 
33
33
  def is_scope_active?(scope)
34
- current_scope == scope
34
+ active_scope == scope
35
35
  end
36
36
 
37
37
  def param_value
@@ -0,0 +1,74 @@
1
+ require 'coercible'
2
+ require 'active_support/hash_with_indifferent_access'
3
+ require 'active_support/core_ext/hash'
4
+
5
+ module Admino
6
+ module Query
7
+ class Sorting
8
+ attr_reader :params
9
+ attr_reader :config
10
+
11
+ def initialize(config, params)
12
+ @config = config
13
+ @params = ActiveSupport::HashWithIndifferentAccess.new(params)
14
+ end
15
+
16
+ def augment_scope(scope)
17
+ if active_scope
18
+ scope.send(active_scope, ascending? ? :asc : :desc)
19
+ else
20
+ scope
21
+ end
22
+ end
23
+
24
+ def is_scope_active?(scope)
25
+ active_scope == scope
26
+ end
27
+
28
+ def ascending?
29
+ if params[:sort_order] == 'desc'
30
+ false
31
+ elsif params[:sort_order].blank? && active_scope == default_scope
32
+ default_direction_is_ascending?
33
+ else
34
+ true
35
+ end
36
+ end
37
+
38
+ def active_scope
39
+ if param_value && available_scopes.include?(param_value.to_sym)
40
+ param_value.to_sym
41
+ elsif default_scope
42
+ default_scope
43
+ else
44
+ nil
45
+ end
46
+ end
47
+
48
+ def default_scope
49
+ config.default_scope
50
+ end
51
+
52
+ def default_direction_is_ascending?
53
+ config.default_direction != :desc
54
+ end
55
+
56
+ def param_value
57
+ params.fetch(param_name, nil)
58
+ end
59
+
60
+ def param_name
61
+ :sorting
62
+ end
63
+
64
+ def available_scopes
65
+ config.scopes
66
+ end
67
+
68
+ def scope_name
69
+ config.name
70
+ end
71
+ end
72
+ end
73
+ end
74
+
@@ -0,0 +1,41 @@
1
+ require 'showcase'
2
+
3
+ module Admino
4
+ module Query
5
+ class SortingPresenter < Showcase::Presenter
6
+ def scope_link(scope, label, *args)
7
+ options = args.extract_options!
8
+
9
+ desc_class = options.delete(:desc_class) { 'is-desc' }
10
+ asc_class = options.delete(:asc_class) { 'is-asc' }
11
+
12
+ options = Showcase::Helpers::HtmlOptions.new(options)
13
+
14
+ if is_scope_active?(scope)
15
+ options.add_class!(ascending? ? asc_class : desc_class)
16
+ end
17
+
18
+ h.link_to label, scope_path(scope), options.to_h
19
+ end
20
+
21
+ def scope_path(scope)
22
+ h.request.path + "?" + scope_params(scope).to_query
23
+ end
24
+
25
+ def scope_params(scope)
26
+ params = ActiveSupport::HashWithIndifferentAccess.new(h.request.query_parameters)
27
+
28
+ if is_scope_active?(scope)
29
+ params.merge!(sorting: scope.to_s, sort_order: ascending? ? 'desc' : 'asc')
30
+ elsif default_scope == scope
31
+ params.merge!(sorting: scope.to_s, sort_order: default_direction.to_s)
32
+ else
33
+ params.merge!(sorting: scope.to_s, sort_order: 'asc')
34
+ end
35
+
36
+ params
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -5,9 +5,11 @@ module Admino
5
5
  module Table
6
6
  class HeadRow < Row
7
7
  attr_reader :resource_klass
8
+ attr_reader :query
8
9
 
9
- def initialize(resource_klass, view_context)
10
+ def initialize(resource_klass, query, view_context)
10
11
  @resource_klass = resource_klass
12
+ @query = query
11
13
  @columns = ""
12
14
 
13
15
  super(view_context)
@@ -38,6 +40,14 @@ module Admino
38
40
  default_options = column_html_options(attribute_name)
39
41
  html_options = Showcase::Helpers::HtmlOptions.new(default_options)
40
42
  html_options.merge_attrs!(options)
43
+ html_options = html_options.to_h
44
+
45
+ sorting_scope = html_options.delete(:sorting)
46
+ if sorting_scope
47
+ raise ArgumentError, 'query object is required' unless query
48
+ sorting_html_options = html_options.delete(:sorting_html_options) { {} }
49
+ label = query.sorting.scope_link(sorting_scope, label, sorting_html_options)
50
+ end
41
51
 
42
52
  @columns << h.content_tag(:th, label.to_s, html_options.to_h)
43
53
  end
@@ -6,6 +6,7 @@ module Admino
6
6
  module Table
7
7
  class Presenter < Showcase::Presenter
8
8
  attr_reader :collection_klass
9
+ attr_reader :query
9
10
 
10
11
  def self.tag_helper(name, tag, options = {})
11
12
  default_options_method = :"#{name}_html_options"
@@ -28,8 +29,13 @@ module Admino
28
29
  tag_helper :tbody, :tbody
29
30
  tag_helper :tbody_tr, :tr, params: %w(resource index)
30
31
 
31
- def initialize(collection, klass, context)
32
- @collection_klass = klass
32
+ def initialize(*args)
33
+ context = args.pop
34
+ collection = args.shift
35
+
36
+ @collection_klass = args.shift
37
+ @query = args.shift
38
+
33
39
  super(collection, context)
34
40
  end
35
41
 
@@ -37,7 +43,7 @@ module Admino
37
43
  table_tag(options) do
38
44
  thead_tag do
39
45
  thead_tr_tag do
40
- row = head_row(collection_klass, view_context)
46
+ row = head_row(collection_klass, query, view_context)
41
47
  h.capture(row, nil, &block) if block_given?
42
48
  row.to_html
43
49
  end
@@ -64,8 +70,8 @@ module Admino
64
70
  @collection ||= present_collection(object)
65
71
  end
66
72
 
67
- def head_row(collection_klass, view_context)
68
- HeadRow.new(collection_klass, view_context)
73
+ def head_row(collection_klass, query, view_context)
74
+ HeadRow.new(collection_klass, query, view_context)
69
75
  end
70
76
 
71
77
  def resource_row(resource, view_context)
@@ -1,3 +1,4 @@
1
1
  module Admino
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
4
+
@@ -50,6 +50,23 @@ module Admino
50
50
  end
51
51
  end
52
52
 
53
+ context 'with a declared sorting' do
54
+ let(:config) { Configuration.new }
55
+ let(:sorting_config) do
56
+ config.add_sorting_scopes([:by_title, :by_date])
57
+ end
58
+
59
+ before do
60
+ sorting_config
61
+ end
62
+
63
+ it 'returns a configured Sorting' do
64
+ sorting = query.sorting
65
+ expect(sorting.config).to eq sorting_config
66
+ expect(sorting.params).to eq params
67
+ end
68
+ end
69
+
53
70
  describe '#scope' do
54
71
  let(:config) { Configuration.new }
55
72
  let(:result) { query.scope(starting_scope) }
@@ -18,6 +18,13 @@ module Admino
18
18
  expect(group.scopes).to eq [:one, :two]
19
19
  end
20
20
 
21
+ it 'allows #sortings declaration' do
22
+ sorting = config.sorting
23
+ expect(sorting.scopes).to eq [:by_title, :by_date]
24
+ expect(sorting.default_scope).to eq :by_title
25
+ expect(sorting.default_direction).to eq :desc
26
+ end
27
+
21
28
  it 'allows #starting_scope block declaration' do
22
29
  expect(config.starting_scope_callable.call).to eq 'start'
23
30
  end
@@ -26,29 +26,33 @@ module Admino
26
26
  end
27
27
 
28
28
  describe '#scope_link' do
29
+ subject { presenter.scope_link(:foo) }
30
+
29
31
  before do
30
- group.stub(:is_scope_active?).with(:foo).and_return(true)
32
+ group.stub(:is_scope_active?).with(:foo).and_return(false)
31
33
  end
32
34
 
33
35
  context 'active CSS class' do
36
+ before do
37
+ group.stub(:is_scope_active?).with(:foo).and_return(true)
38
+ end
39
+
34
40
  it 'adds an is-active class' do
35
- expect(presenter.scope_link(:foo)).to have_tag(:a, with: { class: 'is-active' })
41
+ should have_tag(:a, with: { class: 'is-active' })
36
42
  end
37
43
 
38
44
  context 'if an :active_class option is specified' do
45
+ subject { presenter.scope_link(:foo, active_class: 'active') }
46
+
39
47
  it 'adds it' do
40
- expect(presenter.scope_link(:foo, active_class: 'active')).to have_tag(:a, with: { class: 'active' })
48
+ should have_tag(:a, with: { class: 'active' })
41
49
  end
42
50
  end
51
+ end
43
52
 
44
- context 'else' do
45
- before do
46
- group.stub(:is_scope_active?).with(:foo).and_return(false)
47
- end
48
-
49
- it 'does not add it' do
50
- expect(presenter.scope_link(:foo)).not_to have_tag(:a, with: { class: 'is-active' })
51
- end
53
+ context 'else' do
54
+ it 'does not add it' do
55
+ should_not have_tag(:a, with: { class: 'is-active' })
52
56
  end
53
57
  end
54
58
 
@@ -58,12 +62,14 @@ module Admino
58
62
  end
59
63
 
60
64
  it 'uses #scope_name method' do
61
- expect(presenter.scope_link(:foo)).to have_tag(:a, text: 'scope_name')
65
+ should have_tag(:a, text: 'scope_name')
62
66
  end
63
67
 
64
68
  context 'if a second parameter is supplied' do
69
+ subject { presenter.scope_link(:foo, 'test', active_class: 'active') }
70
+
65
71
  it 'uses it' do
66
- expect(presenter.scope_link(:foo, 'test')).to have_tag(:a, text: 'test')
72
+ should have_tag(:a, text: 'test')
67
73
  end
68
74
  end
69
75
  end
@@ -74,7 +80,7 @@ module Admino
74
80
  end
75
81
 
76
82
  it 'uses #scope_path method' do
77
- expect(presenter.scope_link(:foo)).to have_tag(:a, href: 'URL')
83
+ should have_tag(:a, href: 'URL')
78
84
  end
79
85
  end
80
86
  end
@@ -7,28 +7,28 @@ module Admino
7
7
  let(:config) { Configuration::Group.new(:foo, [:bar]) }
8
8
  let(:params) { {} }
9
9
 
10
- describe '#current_scope' do
10
+ describe '#active_scope' do
11
11
  context 'with no param' do
12
12
  let(:params) { {} }
13
13
 
14
- it 'returns the param value for the field' do
15
- expect(group.current_scope).to be_nil
14
+ it 'returns nil' do
15
+ expect(group.active_scope).to be_nil
16
16
  end
17
17
  end
18
18
 
19
19
  context 'with an invalid value' do
20
20
  let(:params) { { 'foo' => 'qux' } }
21
21
 
22
- it 'returns the param value for the field' do
23
- expect(group.current_scope).to be_nil
22
+ it 'returns nil' do
23
+ expect(group.active_scope).to be_nil
24
24
  end
25
25
  end
26
26
 
27
27
  context 'with a valid value' do
28
28
  let(:params) { { 'foo' => 'bar' } }
29
29
 
30
- it 'returns nil' do
31
- expect(group.current_scope).to eq :bar
30
+ it 'returns the scope name' do
31
+ expect(group.active_scope).to eq :bar
32
32
  end
33
33
  end
34
34
  end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+
3
+ module Admino
4
+ module Query
5
+ describe SortingPresenter do
6
+ subject(:presenter) { SortingPresenter.new(sorting, view) }
7
+ let(:view) { RailsViewContext.new }
8
+ let(:sorting) { double('Sorting', default_scope: 'by_name') }
9
+ let(:request_object) do
10
+ double(
11
+ 'ActionDispatch::Request',
12
+ query_parameters: { 'sorting' => 'by_date' },
13
+ path: '/'
14
+ )
15
+ end
16
+
17
+ before do
18
+ view.stub(:request).and_return(request_object)
19
+ end
20
+
21
+ describe '#scope_link' do
22
+ subject { presenter.scope_link(:by_title, 'Titolo') }
23
+
24
+ before do
25
+ sorting.stub(:is_scope_active?).with(:by_title).and_return(false)
26
+ end
27
+
28
+ context 'scope is active' do
29
+ before do
30
+ sorting.stub(:is_scope_active?).with(:by_title).and_return(true)
31
+ end
32
+
33
+ context 'ascending' do
34
+ before do
35
+ sorting.stub(:ascending?).and_return(true)
36
+ end
37
+
38
+ it 'adds an is-asc class' do
39
+ should have_tag(:a, with: { class: 'is-asc' })
40
+ end
41
+
42
+ context 'if an :asc_class option is specified' do
43
+ subject { presenter.scope_link(:by_title, 'Titolo', asc_class: 'asc') }
44
+
45
+ it 'adds it' do
46
+ should have_tag(:a, with: { class: 'asc' })
47
+ end
48
+ end
49
+ end
50
+
51
+ context 'descendent' do
52
+ before do
53
+ sorting.stub(:ascending?).and_return(false)
54
+ end
55
+
56
+ it 'adds an is-desc class' do
57
+ should have_tag(:a, with: { class: 'is-desc' })
58
+ end
59
+
60
+ context 'if a :desc_class option is specified' do
61
+ subject { presenter.scope_link(:by_title, 'Titolo', desc_class: 'desc') }
62
+
63
+ it 'adds it' do
64
+ should have_tag(:a, with: { class: 'desc' })
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'else' do
71
+ it 'does not add it' do
72
+ should_not have_tag(:a, with: { class: 'is-asc' })
73
+ end
74
+ end
75
+
76
+ context 'label' do
77
+ it 'uses the provided argument' do
78
+ should have_tag(:a, text: 'Titolo')
79
+ end
80
+ end
81
+
82
+ context 'URL' do
83
+ before do
84
+ presenter.stub(:scope_path).with(:by_title).and_return('URL')
85
+ end
86
+
87
+ it 'uses #scope_path method' do
88
+ should have_tag(:a, href: 'URL')
89
+ end
90
+ end
91
+ end
92
+
93
+ describe '#scope_params' do
94
+ subject { presenter.scope_params(:by_title) }
95
+
96
+ before do
97
+ sorting.stub(:is_scope_active?).with(:by_title).and_return(false)
98
+ end
99
+
100
+ it 'sets the sorting param as the scope' do
101
+ subject[:sorting] == 'by_title'
102
+ end
103
+
104
+ context 'scope is active' do
105
+ before do
106
+ sorting.stub(:is_scope_active?).with(:by_title).and_return(true)
107
+ end
108
+
109
+ context 'is currently ascending' do
110
+ before do
111
+ sorting.stub(:ascending?).and_return(true)
112
+ end
113
+
114
+ it 'sets the sorting order to descending' do
115
+ subject[:sort_order] == 'desc'
116
+ end
117
+ end
118
+
119
+ context 'is currently descending' do
120
+ before do
121
+ sorting.stub(:ascending?).and_return(false)
122
+ end
123
+
124
+ it 'sets the sorting order to ascending' do
125
+ subject[:sort_order] == 'asc'
126
+ end
127
+ end
128
+ end
129
+
130
+ context 'scope is the default one' do
131
+ let(:sorting) { double('Sorting', default_scope: 'by_title') }
132
+
133
+ context 'default scope is ascending' do
134
+ before do
135
+ sorting.stub(:default_direction).and_return(:asc)
136
+ end
137
+
138
+ it 'sets the sorting order to ascending' do
139
+ subject[:sort_order] == 'asc'
140
+ end
141
+ end
142
+
143
+ context 'default scope is descending' do
144
+ before do
145
+ sorting.stub(:default_direction).and_return(:desc)
146
+ end
147
+
148
+ it 'sets the sorting order to descending' do
149
+ subject[:sort_order] == 'desc'
150
+ end
151
+ end
152
+ end
153
+
154
+ context 'else' do
155
+ before do
156
+ sorting.stub(:is_scope_active?).with(:by_title).and_return(false)
157
+ end
158
+
159
+ it 'sets the sorting order to ascending' do
160
+ subject[:sort_order] == 'asc'
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+
@@ -0,0 +1,129 @@
1
+ require 'spec_helper'
2
+
3
+ module Admino
4
+ module Query
5
+ describe Sorting do
6
+ subject(:sorting) { Sorting.new(config, params) }
7
+ let(:config) do
8
+ Configuration::Sorting.new(sorting_scopes, options)
9
+ end
10
+ let(:sorting_scopes) { [:by_title, :by_date] }
11
+ let(:options) { {} }
12
+ let(:params) { {} }
13
+
14
+ describe '#active_scope' do
15
+ context 'with no param' do
16
+ let(:params) { {} }
17
+
18
+ it 'returns false' do
19
+ expect(sorting.active_scope).to be_nil
20
+ end
21
+
22
+ context 'if a default scope is configured' do
23
+ let(:options) { { default_scope: :by_date } }
24
+
25
+ it 'returns it' do
26
+ expect(sorting.active_scope).to eq :by_date
27
+ end
28
+ end
29
+ end
30
+
31
+ context 'with an invalid value' do
32
+ let(:params) { { 'sorting' => 'foo' } }
33
+
34
+ it 'returns false' do
35
+ expect(sorting.active_scope).to be_nil
36
+ end
37
+ end
38
+
39
+ context 'with a valid value' do
40
+ let(:params) { { 'sorting' => 'by_title' } }
41
+
42
+ it 'returns the scope name' do
43
+ expect(sorting.active_scope).to eq :by_title
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '#ascending?' do
49
+ context 'with no param' do
50
+ let(:params) { {} }
51
+
52
+ it 'returns true' do
53
+ expect(sorting).to be_ascending
54
+ end
55
+ end
56
+
57
+ context 'with invalid value' do
58
+ let(:params) { { 'sort_order' => 'foo' } }
59
+
60
+ it 'returns true' do
61
+ expect(sorting).to be_ascending
62
+ end
63
+ end
64
+
65
+ context 'with "asc" value' do
66
+ let(:params) { { 'sort_order' => 'asc' } }
67
+
68
+ it 'returns nil' do
69
+ expect(sorting).to be_ascending
70
+ end
71
+ end
72
+
73
+ context 'with "desc" value' do
74
+ let(:params) { { 'sort_order' => 'desc' } }
75
+
76
+ it 'returns the param value for the field' do
77
+ expect(sorting).not_to be_ascending
78
+ end
79
+ end
80
+
81
+ context 'if a default scope and direction are set and default scope is current' do
82
+ let(:options) { { default_scope: :by_date, default_direction: :desc } }
83
+ let(:params) { { 'sorting' => 'by_date', 'sort_order' => 'desc' } }
84
+
85
+ it 'returns it' do
86
+ expect(sorting).not_to be_ascending
87
+ end
88
+ end
89
+ end
90
+
91
+ describe '#augment_scope' do
92
+ let(:result) { sorting.augment_scope(scope) }
93
+ let(:scope) { ScopeMock.new('original') }
94
+
95
+ context 'if the field has a value' do
96
+ let(:params) { { 'sorting' => 'by_title', 'sort_order' => 'desc' } }
97
+
98
+ it 'returns the original scope chained with the current scope' do
99
+ expect(result.chain).to eq [:by_title, [:desc]]
100
+ end
101
+ end
102
+
103
+ context 'else' do
104
+ it 'returns the original scope' do
105
+ expect(result).to eq scope
106
+ end
107
+ end
108
+
109
+ context 'if a default scope is configured' do
110
+ let(:options) { { default_scope: :by_date } }
111
+ let(:params) { {} }
112
+
113
+ it 'returns the original scope chained with the default scope' do
114
+ expect(result.chain).to eq [:by_date, [:asc]]
115
+ end
116
+
117
+ context 'if a default direction is configured' do
118
+ let(:options) { { default_scope: :by_date, default_direction: :desc } }
119
+
120
+ it 'returns the original scope chained with the default scope and default direction' do
121
+ expect(result.chain).to eq [:by_date, [:desc]]
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+
@@ -3,9 +3,10 @@ require 'spec_helper'
3
3
  module Admino
4
4
  module Table
5
5
  describe HeadRow do
6
- subject(:row) { HeadRow.new(klass, view) }
7
- let(:view) { RailsViewContext.new }
6
+ subject(:row) { HeadRow.new(klass, query, view) }
8
7
  let(:klass) { Post }
8
+ let(:query) { nil }
9
+ let(:view) { RailsViewContext.new }
9
10
 
10
11
  it 'takes a class and a view context' do
11
12
  expect(row.resource_klass).to eq klass
@@ -50,6 +51,30 @@ module Admino
50
51
  end
51
52
  end
52
53
 
54
+ context 'sorting' do
55
+ context 'if no query object is present' do
56
+ it 'raises an ArgumentError' do
57
+ expect { row.column(:title, sorting: :by_title) }.to raise_error ArgumentError
58
+ end
59
+ end
60
+
61
+ context 'else' do
62
+ let(:query) { double('Query', sorting: sorting) }
63
+ let(:sorting) { double('Sorting') }
64
+
65
+ before do
66
+ sorting.stub(:scope_link).with(:by_title, 'Title', {}).
67
+ and_return('Link')
68
+ end
69
+
70
+ before { row.column(:title, sorting: :by_title) }
71
+
72
+ it 'generates a sorting scope link' do
73
+ should have_tag(:th, text: 'Link')
74
+ end
75
+ end
76
+ end
77
+
53
78
  context 'role' do
54
79
  before { row.column(:author_name) }
55
80
 
@@ -4,8 +4,9 @@ require 'ostruct'
4
4
  module Admino
5
5
  module Table
6
6
  describe Presenter do
7
- subject(:presenter) { presenter_klass.new(collection, Post, view) }
7
+ subject(:presenter) { presenter_klass.new(collection, Post, query, view) }
8
8
  let(:presenter_klass) { Presenter }
9
+ let(:query) { double('Query') }
9
10
  let(:view) { RailsViewContext.new }
10
11
 
11
12
  let(:collection) { [ first_post, second_post ] }
@@ -21,7 +22,7 @@ module Admino
21
22
  PostPresenter.stub(:new).with(first_post, view).and_return(first_post_presenter)
22
23
  PostPresenter.stub(:new).with(second_post, view).and_return(second_post_presenter)
23
24
 
24
- HeadRow.stub(:new).with(Post, view).and_return(head_row)
25
+ HeadRow.stub(:new).with(Post, query, view).and_return(head_row)
25
26
  ResourceRow.stub(:new).with(first_post_presenter, view).and_return(resource_row)
26
27
  ResourceRow.stub(:new).with(second_post_presenter, view).and_return(resource_row)
27
28
  end
@@ -37,6 +37,10 @@ class TestQuery < Admino::Query::Base
37
37
 
38
38
  group :bar, [:one, :two]
39
39
 
40
+ sorting :by_title, :by_date,
41
+ default_scope: :by_title,
42
+ default_direction: :desc
43
+
40
44
  starting_scope { 'start' }
41
45
  ending_scope { 'end' }
42
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: admino
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefano Verna
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-16 00:00:00.000000000 Z
11
+ date: 2014-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: showcase
@@ -188,6 +188,8 @@ files:
188
188
  - lib/admino/query/field.rb
189
189
  - lib/admino/query/group.rb
190
190
  - lib/admino/query/group_presenter.rb
191
+ - lib/admino/query/sorting.rb
192
+ - lib/admino/query/sorting_presenter.rb
191
193
  - lib/admino/table.rb
192
194
  - lib/admino/table/head_row.rb
193
195
  - lib/admino/table/presenter.rb
@@ -200,6 +202,8 @@ files:
200
202
  - spec/admino/query/field_spec.rb
201
203
  - spec/admino/query/group_presenter_spec.rb
202
204
  - spec/admino/query/group_spec.rb
205
+ - spec/admino/query/sorting_presenter_spec.rb
206
+ - spec/admino/query/sorting_spec.rb
203
207
  - spec/admino/table/head_row_spec.rb
204
208
  - spec/admino/table/presenter_spec.rb
205
209
  - spec/admino/table/resource_row_spec.rb
@@ -236,6 +240,8 @@ test_files:
236
240
  - spec/admino/query/field_spec.rb
237
241
  - spec/admino/query/group_presenter_spec.rb
238
242
  - spec/admino/query/group_spec.rb
243
+ - spec/admino/query/sorting_presenter_spec.rb
244
+ - spec/admino/query/sorting_spec.rb
239
245
  - spec/admino/table/head_row_spec.rb
240
246
  - spec/admino/table/presenter_spec.rb
241
247
  - spec/admino/table/resource_row_spec.rb