sorting_table_for 0.2.0 → 0.2.1
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.
- data/CHANGELOG.mdown +4 -0
- data/init.rb +0 -4
- data/lib/sorting_table_for.rb +3 -0
- data/lib/sorting_table_for/format_cell.rb +189 -0
- data/lib/sorting_table_for/format_line.rb +110 -0
- data/lib/sorting_table_for/i18n.rb +16 -9
- data/lib/sorting_table_for/model_scope.rb +76 -0
- data/lib/sorting_table_for/table_builder.rb +15 -306
- data/spec/db/schema.rb +1 -1
- data/spec/fixtures/{user.rb → sorting_table_for_user.rb} +2 -2
- data/spec/helpers/builder_spec.rb +8 -5
- data/spec/helpers/caption_spec.rb +7 -4
- data/spec/helpers/cell_value_spec.rb +7 -4
- data/spec/helpers/column_spec.rb +14 -11
- data/spec/helpers/footer_spec.rb +7 -4
- data/spec/helpers/header_spec.rb +33 -8
- data/spec/helpers/i18n_spec.rb +12 -7
- data/spec/locales/test.yml +11 -2
- data/spec/locales/test_rails3.yml +6 -4
- data/spec/model/sorting_table_model_scope_spec.rb +24 -18
- data/spec/spec_helper.rb +18 -0
- metadata +7 -15
- data/lib/model/sorting_table_model_scope.rb +0 -72
@@ -6,8 +6,7 @@ module SortingTableFor
|
|
6
6
|
|
7
7
|
class TableBuilder
|
8
8
|
|
9
|
-
include ::ActionView::Helpers
|
10
|
-
include ::ActionView::Helpers::NumberHelper
|
9
|
+
include ::ActionView::Helpers
|
11
10
|
|
12
11
|
class_inheritable_accessor :reserved_columns, :currency_columns,
|
13
12
|
:default_boolean, :show_total_entries,
|
@@ -31,7 +30,7 @@ module SortingTableFor
|
|
31
30
|
def initialize(collection, object_or_array, template, options, params)
|
32
31
|
@collection, @@object_or_array, @@template, @@options, @@params = collection, object_or_array, template, options, params
|
33
32
|
set_default_global_options
|
34
|
-
I18n.set_options(params, model_name(@collection.first),
|
33
|
+
I18n.set_options(params, model_name(@collection.first), @@options[:i18n])
|
35
34
|
@lines = []
|
36
35
|
end
|
37
36
|
|
@@ -135,7 +134,7 @@ module SortingTableFor
|
|
135
134
|
column_options, html_options = get_column_and_html_options( args.extract_options! )
|
136
135
|
if block_given?
|
137
136
|
@header_line = FormatLine.new(args, column_options, html_options, nil, :thead)
|
138
|
-
|
137
|
+
capture(&block)
|
139
138
|
else
|
140
139
|
@header_line = FormatLine.new(args, column_options, html_options, @collection.first, :thead)
|
141
140
|
end
|
@@ -184,7 +183,7 @@ module SortingTableFor
|
|
184
183
|
#
|
185
184
|
def header(*args, &block)
|
186
185
|
if block_given?
|
187
|
-
block =
|
186
|
+
block = capture(&block)
|
188
187
|
@header_line.add_cell(@collection.first, args, nil, block)
|
189
188
|
else
|
190
189
|
@header_line.add_cell(@collection.first, args)
|
@@ -392,7 +391,7 @@ module SortingTableFor
|
|
392
391
|
#
|
393
392
|
def column(*args, &block)
|
394
393
|
if block_given?
|
395
|
-
block =
|
394
|
+
block = capture(&block)
|
396
395
|
@lines.last.add_cell(@current_object, args, nil, block)
|
397
396
|
else
|
398
397
|
@lines.last.add_cell(@current_object, args)
|
@@ -451,7 +450,7 @@ module SortingTableFor
|
|
451
450
|
column_options, html_options = get_column_and_html_options( args.extract_options! )
|
452
451
|
if block_given?
|
453
452
|
@footer_line = FormatLine.new(args, column_options, html_options, nil, :tfoot)
|
454
|
-
|
453
|
+
capture(&block)
|
455
454
|
else
|
456
455
|
@footer_line = FormatLine.new(args, column_options, html_options, @collection.first, :tfoot) if !args.empty?
|
457
456
|
end
|
@@ -506,7 +505,7 @@ module SortingTableFor
|
|
506
505
|
#
|
507
506
|
def footer(*args, &block)
|
508
507
|
if block_given?
|
509
|
-
block =
|
508
|
+
block = capture(&block)
|
510
509
|
@footer_line.add_cell(@collection.first, args, nil, block)
|
511
510
|
else
|
512
511
|
@footer_line.add_cell(@collection.first, args)
|
@@ -557,7 +556,7 @@ module SortingTableFor
|
|
557
556
|
def caption(*args, &block)
|
558
557
|
@caption[:option], @caption[:html] = get_column_and_html_options( args.extract_options! )
|
559
558
|
if block_given?
|
560
|
-
@caption[:value] =
|
559
|
+
@caption[:value] = capture(&block)
|
561
560
|
else
|
562
561
|
@caption[:value] = (args.empty?) ? I18n.t(:table_caption) : args.first;
|
563
562
|
end
|
@@ -571,6 +570,11 @@ module SortingTableFor
|
|
571
570
|
object.present? ? object.class.name : object.to_s.classify
|
572
571
|
end
|
573
572
|
|
573
|
+
# Send method to ActionView
|
574
|
+
def method_missing(name, *args, &block)
|
575
|
+
@@template.send(name, *args, &block)
|
576
|
+
end
|
577
|
+
|
574
578
|
private
|
575
579
|
|
576
580
|
def render_caption
|
@@ -595,6 +599,7 @@ module SortingTableFor
|
|
595
599
|
def render_tbody
|
596
600
|
if @lines and @lines.size > 0
|
597
601
|
return Tools::html_safe(content_tag(:tbody, render_total_entries + Tools::html_safe(@lines.collect { |line| line.render_line }.join)))
|
602
|
+
return Tools::html_safe(content_tag(:tr, content_tag(:td, I18n.t(:total_entries, :scope => :sorting_table_for, :value => total_entries), {:colspan => max_cells}), { :class => 'total-entries' }))
|
598
603
|
end
|
599
604
|
''
|
600
605
|
end
|
@@ -624,7 +629,7 @@ module SortingTableFor
|
|
624
629
|
total_entries = @collection.total_entries rescue @collection.size
|
625
630
|
header_total_cells = @header_line ? @header_line.total_cells : 0
|
626
631
|
max_cells = (@lines.first.total_cells > header_total_cells) ? @lines.first.total_cells : header_total_cells
|
627
|
-
return Tools::html_safe(content_tag(:tr, content_tag(:td, I18n.t(:total_entries, :
|
632
|
+
return Tools::html_safe(content_tag(:tr, content_tag(:td, I18n.t(:total_entries, :value => total_entries), {:colspan => max_cells}), { :class => 'total-entries' }))
|
628
633
|
end
|
629
634
|
''
|
630
635
|
end
|
@@ -635,300 +640,4 @@ module SortingTableFor
|
|
635
640
|
end
|
636
641
|
|
637
642
|
end
|
638
|
-
|
639
|
-
class FormatLine < TableBuilder
|
640
|
-
|
641
|
-
def initialize(args, column_options = {}, html_options = {}, object = nil, type = nil)
|
642
|
-
@args, @column_options, @html_options, @object, @type = args, column_options, html_options, object, type
|
643
|
-
@cells = []
|
644
|
-
if object
|
645
|
-
@attributes = (args.empty?) ? (get_columns - TableBuilder.reserved_columns) : @args
|
646
|
-
create_cells
|
647
|
-
end
|
648
|
-
end
|
649
|
-
|
650
|
-
# Create a new cell with the class FormatCell
|
651
|
-
# Add the object in @cells
|
652
|
-
def add_cell(object, args, type = nil, block = nil)
|
653
|
-
@cells << FormatCell.new(object, args, type, block)
|
654
|
-
end
|
655
|
-
|
656
|
-
# Return a tr line based on the type (:thead, :tbody or :tfoot)
|
657
|
-
def render_line
|
658
|
-
if @type == :thead
|
659
|
-
return content_tag(:tr, Tools::html_safe(@cells.collect { |cell| cell.render_cell_thead }.join), @html_options)
|
660
|
-
elsif @type == :tfoot
|
661
|
-
return content_tag(:tr, Tools::html_safe(@cells.collect { |cell| cell.render_cell_tfoot }.join), @html_options)
|
662
|
-
else
|
663
|
-
content_tag(:tr, Tools::html_safe(@cells.collect { |cell| cell.render_cell_tbody }.join), @html_options.merge(:class => "#{@html_options[:class]} #{@@template.cycle(:odd, :even)}".strip))
|
664
|
-
end
|
665
|
-
end
|
666
|
-
|
667
|
-
# Return the number of cells in line
|
668
|
-
def total_cells
|
669
|
-
@cells.size
|
670
|
-
end
|
671
|
-
|
672
|
-
protected
|
673
|
-
|
674
|
-
# Return each column in the model's database table
|
675
|
-
def content_columns
|
676
|
-
model_name(@object).constantize.content_columns.collect { |c| c.name.to_sym }.compact rescue []
|
677
|
-
end
|
678
|
-
|
679
|
-
# Return true if the column is in the model's database table
|
680
|
-
def model_have_column?(column)
|
681
|
-
model_name(@object).constantize.content_columns.each do |model_column|
|
682
|
-
return true if model_column.name == column.to_s
|
683
|
-
end
|
684
|
-
false
|
685
|
-
end
|
686
|
-
|
687
|
-
# Return true if the column is in the model's database table
|
688
|
-
def can_sort_column?(column)
|
689
|
-
model_have_column?(column)
|
690
|
-
end
|
691
|
-
|
692
|
-
# Options only for cells
|
693
|
-
def only_cell_option?(key)
|
694
|
-
[:colspan].include? key
|
695
|
-
end
|
696
|
-
|
697
|
-
# Format ask to send options to cell
|
698
|
-
def format_options_to_cell(ask, options = @column_options)
|
699
|
-
options.each do |key, value|
|
700
|
-
if only_cell_option?(key)
|
701
|
-
if ask.is_a? Hash
|
702
|
-
ask.merge!(key => value)
|
703
|
-
else
|
704
|
-
ask = [ask] unless ask.is_a? Array
|
705
|
-
(ask.last.is_a? Hash and ask.last.has_key? :html) ? ask.last[:html].merge!(key => value) : ask << { :html => { key => value }}
|
706
|
-
end
|
707
|
-
end
|
708
|
-
end
|
709
|
-
ask
|
710
|
-
end
|
711
|
-
|
712
|
-
private
|
713
|
-
|
714
|
-
# Call after headers or columns with no attributes (table.headers)
|
715
|
-
# Create all the cells based on each column in the model's database table
|
716
|
-
# Create cell's actions based on option default_actions or on actions given (:actions => [:edit])
|
717
|
-
def create_cells
|
718
|
-
@attributes.each { |ask| add_cell(@object, format_options_to_cell(ask)) }
|
719
|
-
if @args.empty?
|
720
|
-
TableBuilder.default_actions.each { |action| add_cell(@object, action, :action) }
|
721
|
-
else
|
722
|
-
get_column_actions.each { |action| add_cell(@object, action, :action) }
|
723
|
-
end
|
724
|
-
end
|
725
|
-
|
726
|
-
# Return an Array of all actions given to headers or columns (:actions => [:edit, :delete])
|
727
|
-
def get_column_actions
|
728
|
-
if @column_options.has_key? :actions
|
729
|
-
if @column_options[:actions].is_a?(Array)
|
730
|
-
return @column_options[:actions]
|
731
|
-
else
|
732
|
-
return [ @column_options[:actions] ]
|
733
|
-
end
|
734
|
-
end
|
735
|
-
[]
|
736
|
-
end
|
737
|
-
|
738
|
-
# Return an Array of the columns based on options :only or :except
|
739
|
-
def get_columns
|
740
|
-
if @column_options.has_key? :only
|
741
|
-
return @column_options[:only] if @column_options[:only].is_a?(Array)
|
742
|
-
[ @column_options[:only] ]
|
743
|
-
elsif @column_options.has_key? :except
|
744
|
-
return content_columns - @column_options[:except] if @column_options[:except].is_a?(Array)
|
745
|
-
content_columns - [ @column_options[:except] ]
|
746
|
-
else
|
747
|
-
content_columns
|
748
|
-
end
|
749
|
-
end
|
750
|
-
|
751
|
-
end
|
752
|
-
|
753
|
-
class FormatCell < FormatLine
|
754
|
-
|
755
|
-
def initialize(object, args, type = nil, block = nil)
|
756
|
-
@object, @type, @block = object, type, block
|
757
|
-
if args.is_a? Array
|
758
|
-
@options, @html_options = get_cell_and_html_options( args.extract_options! )
|
759
|
-
@ask = args.first
|
760
|
-
if @ask.nil? and @options.has_key?(:action)
|
761
|
-
@type = :action
|
762
|
-
@ask = @options[:action]
|
763
|
-
end
|
764
|
-
else
|
765
|
-
@ask = args
|
766
|
-
end
|
767
|
-
set_default_options
|
768
|
-
@can_sort = true if @options and @options[:sort] and can_sort_column?(@ask)
|
769
|
-
end
|
770
|
-
|
771
|
-
# Return a td with the formated value or action for columns
|
772
|
-
def render_cell_tbody
|
773
|
-
if @type == :action
|
774
|
-
cell_value = action_link_to(@ask)
|
775
|
-
elsif @ask
|
776
|
-
cell_value = (@ask.is_a?(Symbol)) ? format_cell_value(@object[@ask], @ask) : format_cell_value(@ask)
|
777
|
-
else
|
778
|
-
cell_value = @block
|
779
|
-
end
|
780
|
-
cell_value = action_link_to(@options[:action], cell_value) if @type != :action and @options.has_key?(:action)
|
781
|
-
content_tag(:td, cell_value, @html_options)
|
782
|
-
end
|
783
|
-
|
784
|
-
# Return a td with the formated value or action for headers
|
785
|
-
def render_cell_thead
|
786
|
-
if @ask
|
787
|
-
cell_value = (@ask.is_a?(Symbol)) ? I18n.t(@ask, {}, :header) : @ask
|
788
|
-
else
|
789
|
-
cell_value = @block
|
790
|
-
end
|
791
|
-
if @can_sort and @options[:sort]
|
792
|
-
@html_options.merge!(:class => "#{@html_options[:class]} #{sorting_html_class}".strip)
|
793
|
-
content_tag(:th, sort_link_to(cell_value), @html_options)
|
794
|
-
else
|
795
|
-
content_tag(:th, cell_value, @html_options)
|
796
|
-
end
|
797
|
-
end
|
798
|
-
|
799
|
-
def render_cell_tfoot
|
800
|
-
if @ask
|
801
|
-
cell_value = (@ask.is_a?(Symbol)) ? I18n.t(@ask, {}, :footer) : @ask
|
802
|
-
else
|
803
|
-
cell_value = @block
|
804
|
-
end
|
805
|
-
cell_value = action_link_to(@options[:action], cell_value) if @type != :action and @options.has_key?(:action)
|
806
|
-
content_tag(:td, cell_value, @html_options)
|
807
|
-
end
|
808
|
-
|
809
|
-
private
|
810
|
-
|
811
|
-
# Return options and html options for a cell
|
812
|
-
def get_cell_and_html_options(options)
|
813
|
-
return options, options.delete(:html) || {}
|
814
|
-
end
|
815
|
-
|
816
|
-
# Set default options for cell
|
817
|
-
# Set an empty hash if no html options
|
818
|
-
# Set an empty hash if no options
|
819
|
-
# Set sort to true if no options sort
|
820
|
-
def set_default_options
|
821
|
-
@html_options = {} unless defined? @html_options
|
822
|
-
@options = {} unless defined? @options
|
823
|
-
@html_options = format_options_to_cell(@html_options, @options)
|
824
|
-
@options[:sort] = @@options[:sort] if !@options.has_key? :sort
|
825
|
-
end
|
826
|
-
|
827
|
-
# Create the link for actions
|
828
|
-
# Set the I18n translation or the given block for the link's name
|
829
|
-
def action_link_to(action, block = nil)
|
830
|
-
object_or_array = @@object_or_array.clone
|
831
|
-
object_or_array.push @object
|
832
|
-
return case action.to_sym
|
833
|
-
when :delete
|
834
|
-
create_link_to(block || I18n.t(:delete), object_or_array, @@options[:link_remote], :delete, I18n.t(:confirm_delete))
|
835
|
-
when :show
|
836
|
-
create_link_to(block || I18n.t(:show), object_or_array, @@options[:link_remote])
|
837
|
-
else
|
838
|
-
object_or_array.insert(0, action)
|
839
|
-
create_link_to(block || I18n.t(@ask), object_or_array, @@options[:link_remote])
|
840
|
-
end
|
841
|
-
end
|
842
|
-
|
843
|
-
# Create sorting link
|
844
|
-
def sort_link_to(name)
|
845
|
-
create_link_to(name, sort_url, @@options[:sort_remote])
|
846
|
-
end
|
847
|
-
|
848
|
-
# Create the link based on object
|
849
|
-
# Set an ajax link if option link_remote is set to true
|
850
|
-
# Compatible with rails 2 and 3.
|
851
|
-
def create_link_to(block, url, remote, method = nil, confirm = nil)
|
852
|
-
if remote and Tools::rails3?
|
853
|
-
return @@template.link_to(block, url, :method => method, :confirm => confirm, :remote => true)
|
854
|
-
elsif remote
|
855
|
-
method = :get if method.nil?
|
856
|
-
return @@template.link_to_remote(block, { :url => url, :method => method, :confirm => confirm })
|
857
|
-
end
|
858
|
-
@@template.link_to(block, url, :method => method, :confirm => confirm)
|
859
|
-
end
|
860
|
-
|
861
|
-
# Return a string with html class of sorting for headers
|
862
|
-
# The html class is based on option: SortingTableFor::TableBuilder.html_sorting_class
|
863
|
-
def sorting_html_class
|
864
|
-
return TableBuilder.html_sorting_class.first if current_sorting.nil?
|
865
|
-
return TableBuilder.html_sorting_class.second if current_sorting == :asc
|
866
|
-
TableBuilder.html_sorting_class.third
|
867
|
-
end
|
868
|
-
|
869
|
-
# Return an url for sorting
|
870
|
-
# Add the param sorting_table[name]=direction to the url
|
871
|
-
# Add the default direction: :asc
|
872
|
-
def sort_url
|
873
|
-
url_params = @@params.clone
|
874
|
-
if url_params.has_key? TableBuilder.params_sort_table
|
875
|
-
if url_params[TableBuilder.params_sort_table].has_key? @ask
|
876
|
-
url_params[TableBuilder.params_sort_table][@ask] = inverse_sorting
|
877
|
-
return @@template.url_for(url_params)
|
878
|
-
end
|
879
|
-
url_params[TableBuilder.params_sort_table].delete @ask
|
880
|
-
end
|
881
|
-
url_params[TableBuilder.params_sort_table] = { @ask => :asc }
|
882
|
-
@@template.url_for(url_params)
|
883
|
-
end
|
884
|
-
|
885
|
-
# Return a symbol of the current sorting (:asc, :desc, nil)
|
886
|
-
def current_sorting
|
887
|
-
if @@params.has_key? TableBuilder.params_sort_table and @@params[TableBuilder.params_sort_table].has_key? @ask
|
888
|
-
return @@params[TableBuilder.params_sort_table][@ask].to_sym
|
889
|
-
end
|
890
|
-
nil
|
891
|
-
end
|
892
|
-
|
893
|
-
# Return a symbol, the inverse of the current sorting
|
894
|
-
def inverse_sorting
|
895
|
-
return :asc if current_sorting.nil?
|
896
|
-
return :desc if current_sorting == :asc
|
897
|
-
:asc
|
898
|
-
end
|
899
|
-
|
900
|
-
# Return the formated cell's value
|
901
|
-
def format_cell_value(value, attribute = nil)
|
902
|
-
unless (ret_value = format_cell_value_as_ask(value)).nil?
|
903
|
-
return ret_value
|
904
|
-
end
|
905
|
-
format_cell_value_as_type(value, attribute)
|
906
|
-
end
|
907
|
-
|
908
|
-
# Format the value if option :as is set
|
909
|
-
def format_cell_value_as_ask(value)
|
910
|
-
return nil if !@options or @options.empty? or !@options.has_key?(:as)
|
911
|
-
return case @options[:as]
|
912
|
-
when :date then ::I18n.l(value.to_date, :format => @options[:format] || TableBuilder.i18n_default_format_date)
|
913
|
-
when :time then ::I18n.l(value.to_datetime, :format => @options[:format] || TableBuilder.i18n_default_format_date)
|
914
|
-
when :currency then number_to_currency(value)
|
915
|
-
else nil
|
916
|
-
end
|
917
|
-
end
|
918
|
-
|
919
|
-
# Format the value based on value's type
|
920
|
-
def format_cell_value_as_type(value, attribute)
|
921
|
-
if value.is_a?(Time) or value.is_a?(Date)
|
922
|
-
return ::I18n.l(value, :format => @options[:format] || TableBuilder.i18n_default_format_date)
|
923
|
-
elsif TableBuilder.currency_columns.include?(attribute)
|
924
|
-
return number_to_currency(value)
|
925
|
-
elsif value.is_a?(TrueClass)
|
926
|
-
return TableBuilder.default_boolean.first
|
927
|
-
elsif value.is_a?(FalseClass)
|
928
|
-
return TableBuilder.default_boolean.second
|
929
|
-
end
|
930
|
-
value
|
931
|
-
end
|
932
|
-
|
933
|
-
end
|
934
643
|
end
|
data/spec/db/schema.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class SortingTableForUser < ActiveRecord::Base
|
2
2
|
if ::SortingTableFor::Tools::rails3?
|
3
3
|
scope :good_position, :conditions => 'position > 3'
|
4
4
|
scope :set_limit, lambda { |limit| { :limit => limit } }
|
@@ -10,7 +10,7 @@ class User < ActiveRecord::Base
|
|
10
10
|
end
|
11
11
|
|
12
12
|
20.times do |n|
|
13
|
-
|
13
|
+
SortingTableForUser.create(
|
14
14
|
:username => "my_usename_#{n}",
|
15
15
|
:firstname => "my_firstname_#{n}",
|
16
16
|
:lastname => "my_lastname_#{n}",
|
@@ -1,16 +1,19 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
|
-
require File.expand_path(File.dirname(__FILE__) + '/../fixtures/
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/../fixtures/sorting_table_for_user')
|
5
5
|
|
6
6
|
include SortingTableForSpecHelper
|
7
7
|
|
8
8
|
describe SortingTableFor, :type => :helper do
|
9
9
|
|
10
|
+
before :all do
|
11
|
+
(SortingTableFor::Tools::rails3?) ? routes_rails3 : routes_rails2
|
12
|
+
end
|
13
|
+
|
10
14
|
before :each do
|
11
|
-
@users =
|
12
|
-
helper.stub!(:
|
13
|
-
helper.stub!(:params).and_return({ :controller => 'fakes', :action => 'index' })
|
15
|
+
@users = SortingTableForUser.all
|
16
|
+
helper.stub!(:params).and_return({ :controller => 'sorting_table_for_users', :action => 'index' })
|
14
17
|
helper.output_buffer = ''
|
15
18
|
end
|
16
19
|
|
@@ -42,7 +45,7 @@ describe SortingTableFor, :type => :helper do
|
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
45
|
-
it "should
|
48
|
+
it "should use i18n by default" do
|
46
49
|
helper.sorting_table_for(@users) do |table|
|
47
50
|
html = table.headers(:username)
|
48
51
|
html.should have_comp_tag("th:nth-child(1)", :text => 'Usernames')
|