tabulatr2 0.9.4 → 0.9.6
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 +4 -4
- data/CHANGELOG.md +29 -0
- data/Gemfile +1 -2
- data/README.md +155 -95
- data/app/assets/javascripts/tabulatr/_storage.js +41 -0
- data/app/assets/javascripts/tabulatr/_tabulatr.js +598 -0
- data/app/assets/javascripts/tabulatr/application.js +3 -553
- data/app/assets/stylesheets/tabulatr/application.css.scss +21 -12
- data/app/assets/stylesheets/tabulatr.css +1 -0
- data/app/views/tabulatr/_tabulatr_actual_table.html.slim +18 -18
- data/app/views/tabulatr/_tabulatr_filter_dialog.html.slim +1 -1
- data/app/views/tabulatr/_tabulatr_fuzzy_search_field.html.slim +1 -1
- data/app/views/tabulatr/_tabulatr_static_table.html.slim +3 -3
- data/app/views/tabulatr/_tabulatr_table.html.slim +17 -12
- data/lib/tabulatr/data/data.rb +7 -9
- data/lib/tabulatr/data/dsl.rb +36 -21
- data/lib/tabulatr/data/filtering.rb +41 -13
- data/lib/tabulatr/data/formatting.rb +7 -20
- data/lib/tabulatr/data/pagination.rb +1 -2
- data/lib/tabulatr/data/proxy.rb +2 -0
- data/lib/tabulatr/data/sorting.rb +24 -13
- data/lib/tabulatr/engine.rb +1 -0
- data/lib/tabulatr/generators/tabulatr/templates/tabulatr.yml +2 -2
- data/lib/tabulatr/json_builder.rb +23 -25
- data/lib/tabulatr/rails/action_controller.rb +4 -0
- data/lib/tabulatr/rails/action_view.rb +3 -2
- data/lib/tabulatr/renderer/checkbox.rb +3 -1
- data/lib/tabulatr/renderer/column.rb +47 -5
- data/lib/tabulatr/renderer/columns_from_block.rb +24 -6
- data/lib/tabulatr/renderer/renderer.rb +26 -17
- data/lib/tabulatr/utility/unexpected_search_result_error.rb +9 -0
- data/lib/tabulatr/utility/utility.rb +4 -0
- data/lib/tabulatr/version.rb +1 -1
- data/spec/dummy/app/controllers/products_controller.rb +9 -0
- data/spec/dummy/app/views/products/local_storage.html.slim +4 -0
- data/spec/dummy/app/views/products/simple_index.html.erb +1 -1
- data/spec/dummy/app/views/products/stupid_array.html.erb +1 -1
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/locales/tabulatr.yml +2 -2
- data/spec/dummy/config/routes.rb +1 -0
- data/spec/features/tabulatrs_spec.rb +27 -27
- data/spec/lib/tabulatr/data/data_spec.rb +12 -16
- data/spec/lib/tabulatr/data/filtering_spec.rb +48 -7
- data/spec/lib/tabulatr/data/formatting_spec.rb +32 -0
- data/spec/lib/tabulatr/data/sorting_spec.rb +81 -0
- data/spec/lib/tabulatr/json_builder_spec.rb +23 -9
- data/spec/lib/tabulatr/renderer/checkbox_spec.rb +14 -0
- data/spec/lib/tabulatr/renderer/renderer_spec.rb +20 -8
- data/tabulatr.gemspec +4 -3
- metadata +45 -9
- data/lib/tabulatr/data/column_name_builder.rb +0 -86
| @@ -23,19 +23,30 @@ | |
| 23 23 |  | 
| 24 24 | 
             
            class Tabulatr::Renderer
         | 
| 25 25 | 
             
              class ColumnsFromBlock
         | 
| 26 | 
            -
                attr_accessor :columns, :klass
         | 
| 26 | 
            +
                attr_accessor :columns, :klass, :table_data
         | 
| 27 27 |  | 
| 28 | 
            -
                def initialize(klass)
         | 
| 28 | 
            +
                def initialize(klass, table_data_object)
         | 
| 29 29 | 
             
                  @klass = klass
         | 
| 30 | 
            +
                  @table_data = table_data_object
         | 
| 30 31 | 
             
                  @columns ||= []
         | 
| 31 32 | 
             
                end
         | 
| 32 33 |  | 
| 33 34 | 
             
                def column(name, opts={}, &block)
         | 
| 34 | 
            -
                   | 
| 35 | 
            +
                  if table_data
         | 
| 36 | 
            +
                    @columns << fetch_column_from_table_data(klass.table_name.to_sym, name, opts, &block)
         | 
| 37 | 
            +
                  else
         | 
| 38 | 
            +
                    @columns << Column.from(opts.merge(klass: klass, table_name: klass.table_name.to_sym, name: name), &block)
         | 
| 39 | 
            +
                  end
         | 
| 35 40 | 
             
                end
         | 
| 36 41 |  | 
| 37 42 | 
             
                def association(table_name, name, opts={}, &block)
         | 
| 38 | 
            -
                   | 
| 43 | 
            +
                  if table_data
         | 
| 44 | 
            +
                    @columns << fetch_column_from_table_data(table_name, name, opts, &block)
         | 
| 45 | 
            +
                  else
         | 
| 46 | 
            +
                    assoc_klass = klass.reflect_on_association(table_name.to_sym)
         | 
| 47 | 
            +
                    @columns << Association.from(opts.merge(klass: assoc_klass.try(:klass),
         | 
| 48 | 
            +
                      name: name, table_name: table_name), &block)
         | 
| 49 | 
            +
                  end
         | 
| 39 50 | 
             
                end
         | 
| 40 51 |  | 
| 41 52 | 
             
                def checkbox(opts={})
         | 
| @@ -46,11 +57,18 @@ class Tabulatr::Renderer | |
| 46 57 | 
             
                  @columns << Action.from(opts.merge(klass: klass, filter: false, sortable: false), &block)
         | 
| 47 58 | 
             
                end
         | 
| 48 59 |  | 
| 49 | 
            -
                def self.process(klass, &block)
         | 
| 50 | 
            -
                  i = self.new(klass)
         | 
| 60 | 
            +
                def self.process(klass, table_data_object = nil, &block)
         | 
| 61 | 
            +
                  i = self.new(klass, table_data_object)
         | 
| 51 62 | 
             
                  yield(i)
         | 
| 52 63 | 
             
                  c = i.columns
         | 
| 53 64 | 
             
                  c
         | 
| 54 65 | 
             
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                private
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def fetch_column_from_table_data table_name, name, opts={}, &block
         | 
| 70 | 
            +
                  column = table_data.table_columns.find{|tc| tc.table_name == table_name && tc.name == name}
         | 
| 71 | 
            +
                  column.update_options(opts, &block)
         | 
| 72 | 
            +
                end
         | 
| 55 73 | 
             
              end
         | 
| 56 74 | 
             
            end
         | 
| @@ -32,7 +32,10 @@ class Tabulatr::Renderer | |
| 32 32 | 
             
                  batch_actions: false,  # :name => value hash of batch action stuff
         | 
| 33 33 | 
             
                  footer_content: false, # if given, add a <%= content_for <footer_content> %> before the </table>
         | 
| 34 34 | 
             
                  path: '#',             # where to send the AJAX-requests to
         | 
| 35 | 
            -
                  order_by: nil | 
| 35 | 
            +
                  order_by: nil,         # default order
         | 
| 36 | 
            +
                  html_class: '',
         | 
| 37 | 
            +
                  pagination_position: :top,
         | 
| 38 | 
            +
                  persistent: true)
         | 
| 36 39 | 
             
                @klass = klass
         | 
| 37 40 | 
             
                @view = view
         | 
| 38 41 | 
             
                @table_options = {
         | 
| @@ -44,21 +47,27 @@ class Tabulatr::Renderer | |
| 44 47 | 
             
                  batch_actions: batch_actions,
         | 
| 45 48 | 
             
                  footer_content: footer_content,
         | 
| 46 49 | 
             
                  path: path,
         | 
| 47 | 
            -
                  order_by: order_by
         | 
| 50 | 
            +
                  order_by: order_by,
         | 
| 51 | 
            +
                  html_class: 'table tabulatr_table '.concat(html_class),
         | 
| 52 | 
            +
                  pagination_position: pagination_position,
         | 
| 53 | 
            +
                  persistent: paginate ? persistent : false
         | 
| 48 54 | 
             
                }
         | 
| 49 55 | 
             
                @classname = @klass.name.underscore
         | 
| 50 56 | 
             
              end
         | 
| 51 57 |  | 
| 52 | 
            -
              def build_table(columns, &block)
         | 
| 53 | 
            -
                 | 
| 58 | 
            +
              def build_table(columns, tabulatr_data_class, &block)
         | 
| 59 | 
            +
                if tabulatr_data_class.present?
         | 
| 60 | 
            +
                  tdc = tabulatr_data_class.constantize.new(@klass)
         | 
| 61 | 
            +
                else
         | 
| 62 | 
            +
                  tdc = "#{@klass.name}TabulatrData".constantize.new(@klass)
         | 
| 63 | 
            +
                end
         | 
| 54 64 | 
             
                if block_given?
         | 
| 55 | 
            -
                  @columns = ColumnsFromBlock.process @klass, &block
         | 
| 65 | 
            +
                  @columns = ColumnsFromBlock.process @klass, tdc, &block
         | 
| 56 66 | 
             
                elsif columns.any?
         | 
| 57 67 | 
             
                  @columns = get_requested_columns(tdc.table_columns, columns)
         | 
| 58 68 | 
             
                else
         | 
| 59 69 | 
             
                  @columns = tdc.table_columns
         | 
| 60 70 | 
             
                end
         | 
| 61 | 
            -
             | 
| 62 71 | 
             
                @view.render(partial: '/tabulatr/tabulatr_table', locals: {
         | 
| 63 72 | 
             
                  columns: @columns,
         | 
| 64 73 | 
             
                  table_options: @table_options,
         | 
| @@ -66,7 +75,7 @@ class Tabulatr::Renderer | |
| 66 75 | 
             
                  classname: @classname,
         | 
| 67 76 | 
             
                  tabulatr_data: tdc,
         | 
| 68 77 | 
             
                  table_id: generate_id,
         | 
| 69 | 
            -
                  formatted_name: formatted_name
         | 
| 78 | 
            +
                  formatted_name: Tabulatr::Utility.formatted_name(@klass.name)
         | 
| 70 79 | 
             
                })
         | 
| 71 80 | 
             
              end
         | 
| 72 81 |  | 
| @@ -83,11 +92,7 @@ class Tabulatr::Renderer | |
| 83 92 | 
             
              end
         | 
| 84 93 |  | 
| 85 94 | 
             
              def generate_id
         | 
| 86 | 
            -
                "#{formatted_name}_table_#{ | 
| 87 | 
            -
              end
         | 
| 88 | 
            -
             | 
| 89 | 
            -
              def formatted_name
         | 
| 90 | 
            -
                "#{@klass.to_s.gsub(/::/, '--').downcase}"
         | 
| 95 | 
            +
                "#{Tabulatr::Utility.formatted_name(@klass.name)}_table_#{@view.controller.controller_name}_#{@view.controller.action_name}_#{@view.instance_variable_get(:@_tabulatr_table_index)}"
         | 
| 91 96 | 
             
              end
         | 
| 92 97 |  | 
| 93 98 | 
             
              def self.build_static_table(records, view, toptions={}, &block)
         | 
| @@ -96,16 +101,21 @@ class Tabulatr::Renderer | |
| 96 101 | 
             
                new(klass, view, toptions).build_static_table(records, &block)
         | 
| 97 102 | 
             
              end
         | 
| 98 103 |  | 
| 99 | 
            -
              def self.build_table(klass, view, toptions={}, columns, &block)
         | 
| 100 | 
            -
                new(klass, view, toptions).build_table(columns, &block)
         | 
| 104 | 
            +
              def self.build_table(klass, view, toptions={}, columns, tabulatr_data_class, &block)
         | 
| 105 | 
            +
                new(klass, view, toptions).build_table(columns, tabulatr_data_class, &block)
         | 
| 101 106 | 
             
              end
         | 
| 102 107 |  | 
| 103 108 | 
             
              private
         | 
| 104 109 |  | 
| 105 110 | 
             
              def get_requested_columns(available_columns, requested_columns)
         | 
| 111 | 
            +
                main_table_name = @klass.table_name.to_sym
         | 
| 106 112 | 
             
                requested_columns.collect do |r|
         | 
| 107 | 
            -
                   | 
| 108 | 
            -
             | 
| 113 | 
            +
                  if r.is_a?(Hash) && r.count == 1
         | 
| 114 | 
            +
                    r = "#{r.keys.first}:#{r.values.first}"
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
                  result = available_columns.find{|column| column.full_name.to_sym == r.to_sym }
         | 
| 117 | 
            +
                  result = available_columns.find{|column| column.name.to_sym == r.to_sym && column.table_name == main_table_name} if result.nil?
         | 
| 118 | 
            +
                  result
         | 
| 109 119 | 
             
                end.flatten
         | 
| 110 120 | 
             
              end
         | 
| 111 121 |  | 
| @@ -116,4 +126,3 @@ require_relative './association' | |
| 116 126 | 
             
            require_relative './action'
         | 
| 117 127 | 
             
            require_relative './checkbox'
         | 
| 118 128 | 
             
            require_relative './columns_from_block'
         | 
| 119 | 
            -
             | 
    
        data/lib/tabulatr/version.rb
    CHANGED
    
    
| @@ -5,7 +5,7 @@ en: | |
| 5 5 | 
             
                batch_actions: 'Batch actions'
         | 
| 6 6 | 
             
                count: 'Showing: %{current} of total %{total}. %{per_page} items per page.'
         | 
| 7 7 | 
             
                apply_filters: 'Apply'
         | 
| 8 | 
            -
                search: 'Search'
         | 
| 8 | 
            +
                search: 'Search...'
         | 
| 9 9 | 
             
                date_filter:
         | 
| 10 10 | 
             
                  none: ''
         | 
| 11 11 | 
             
                  today: "Today"
         | 
| @@ -27,7 +27,7 @@ de: | |
| 27 27 | 
             
                batch_actions: 'Batch-Aktionen'
         | 
| 28 28 | 
             
                count: 'Zeige %{current} von insgesamt %{total}. %{per_page} pro Seite.'
         | 
| 29 29 | 
             
                apply_filters: 'Anwenden'
         | 
| 30 | 
            -
                search: 'Suche'
         | 
| 30 | 
            +
                search: 'Suche...'
         | 
| 31 31 | 
             
                date_filter:
         | 
| 32 32 | 
             
                  none: ''
         | 
| 33 33 | 
             
                  today: "Heute"
         | 
    
        data/spec/dummy/config/routes.rb
    CHANGED
    
    
| @@ -100,7 +100,7 @@ describe "Tabulatr" do | |
| 100 100 | 
             
                      Product.create!(:title => "test #{i}")
         | 
| 101 101 | 
             
                    end
         | 
| 102 102 | 
             
                    visit one_item_per_page_with_pagination_products_path
         | 
| 103 | 
            -
                    page.all('.pagination li a').count.should eq 5
         | 
| 103 | 
            +
                    page.all('.pagination li a[data-page]').count.should eq 5
         | 
| 104 104 | 
             
                  end
         | 
| 105 105 |  | 
| 106 106 | 
             
                  it 'shows some pages when there are 20', js: true do
         | 
| @@ -108,7 +108,7 @@ describe "Tabulatr" do | |
| 108 108 | 
             
                      Product.create!
         | 
| 109 109 | 
             
                    end
         | 
| 110 110 | 
             
                    visit one_item_per_page_with_pagination_products_path
         | 
| 111 | 
            -
                    pages = page.all('.pagination li a').map{|a| a['data-page'].to_i}
         | 
| 111 | 
            +
                    pages = page.all('.pagination li a[data-page]').map{|a| a['data-page'].to_i}
         | 
| 112 112 | 
             
                    pages.should eq [1,2,3,10,20]
         | 
| 113 113 | 
             
                  end
         | 
| 114 114 | 
             
                end
         | 
| @@ -136,21 +136,21 @@ describe "Tabulatr" do | |
| 136 136 | 
             
                  expect(find('.dropdown-menu').visible?)
         | 
| 137 137 | 
             
                  find(".tabulatr-filter-menu-wrapper a.btn").trigger('click')
         | 
| 138 138 | 
             
                  within(".tabulatr_filter_form") do
         | 
| 139 | 
            -
                    fill_in("product_filter[title][like]", with: "ore")
         | 
| 139 | 
            +
                    fill_in("product_filter[products:title][like]", with: "ore")
         | 
| 140 140 | 
             
                    expect{find('#title_like').visible?}.to be_true
         | 
| 141 141 | 
             
                    find_button("Apply").trigger('click')
         | 
| 142 142 | 
             
                  end
         | 
| 143 | 
            -
                  expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'lorem')
         | 
| 144 | 
            -
                  expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'labore')
         | 
| 145 | 
            -
                  expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'dolore')
         | 
| 143 | 
            +
                  expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'lorem')
         | 
| 144 | 
            +
                  expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'labore')
         | 
| 145 | 
            +
                  expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'dolore')
         | 
| 146 146 |  | 
| 147 147 | 
             
                  within(".tabulatr_filter_form") do
         | 
| 148 | 
            -
                    fill_in("product_filter[title][like]", :with => "loreem")
         | 
| 148 | 
            +
                    fill_in("product_filter[products:title][like]", :with => "loreem")
         | 
| 149 149 | 
             
                    find_button("Apply").trigger('click')
         | 
| 150 150 | 
             
                  end
         | 
| 151 | 
            -
                  expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'lorem')
         | 
| 152 | 
            -
                  expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'labore')
         | 
| 153 | 
            -
                  expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'dolore')
         | 
| 151 | 
            +
                  expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'lorem')
         | 
| 152 | 
            +
                  expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'labore')
         | 
| 153 | 
            +
                  expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'dolore')
         | 
| 154 154 | 
             
                end
         | 
| 155 155 |  | 
| 156 156 | 
             
                it "filters", js: true do
         | 
| @@ -178,15 +178,15 @@ describe "Tabulatr" do | |
| 178 178 | 
             
                  end
         | 
| 179 179 | 
             
                  find(".tabulatr-filter-menu-wrapper a.btn").trigger('click')
         | 
| 180 180 | 
             
                  within('.tabulatr_filter_form') do
         | 
| 181 | 
            -
                    fill_in("product_filter[price][from]", :with => 4)
         | 
| 182 | 
            -
                    fill_in("product_filter[price][to]", :with => 10)
         | 
| 181 | 
            +
                    fill_in("product_filter[products:price][from]", :with => 4)
         | 
| 182 | 
            +
                    fill_in("product_filter[products:price][to]", :with => 10)
         | 
| 183 183 | 
             
                    find_button("Apply").trigger('click')
         | 
| 184 184 | 
             
                  end
         | 
| 185 185 | 
             
                  page.find(".tabulatr_table tbody tr[data-id='#{Product.first.id}']").should have_content('foo')
         | 
| 186 186 | 
             
                  page.has_no_css?(".tabulatr_table tbody tr[data-id='#{Product.last.id}']")
         | 
| 187 187 | 
             
                  within('.tabulatr_filter_form') do
         | 
| 188 | 
            -
                    fill_in("product_filter[price][from]", :with => 12)
         | 
| 189 | 
            -
                    fill_in("product_filter[price][to]", :with => 19)
         | 
| 188 | 
            +
                    fill_in("product_filter[products:price][from]", :with => 12)
         | 
| 189 | 
            +
                    fill_in("product_filter[products:price][to]", :with => 19)
         | 
| 190 190 | 
             
                    find_button("Apply").trigger('click')
         | 
| 191 191 | 
             
                  end
         | 
| 192 192 | 
             
                  page.should have_selector(".tabulatr_table tbody tr[data-id='#{Product.last.id}']")
         | 
| @@ -203,19 +203,19 @@ describe "Tabulatr" do | |
| 203 203 | 
             
                  expect(find('.dropdown-menu').visible?)
         | 
| 204 204 | 
             
                  find(".tabulatr-filter-menu-wrapper a.btn").trigger('click')
         | 
| 205 205 | 
             
                  within(".tabulatr_filter_form") do
         | 
| 206 | 
            -
                    fill_in("product_filter[title][like]", with: "foo")
         | 
| 207 | 
            -
                    expect(find('#title_like').visible?)
         | 
| 206 | 
            +
                    fill_in("product_filter[products:title][like]", with: "foo")
         | 
| 207 | 
            +
                    # expect(find('#products--title_like').visible?)
         | 
| 208 208 | 
             
                    find_button("Apply").trigger('click')
         | 
| 209 209 | 
             
                  end
         | 
| 210 210 | 
             
                  # expect(page).to have_content('foo')
         | 
| 211 211 | 
             
                  # expect(page).to have_no_content('bar')
         | 
| 212 | 
            -
                  expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'bar')
         | 
| 213 | 
            -
                  expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'foo')
         | 
| 214 | 
            -
                  find("a[data-hide-table-filter='title']").trigger('click')
         | 
| 212 | 
            +
                  expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'bar')
         | 
| 213 | 
            +
                  expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'foo')
         | 
| 214 | 
            +
                  find("a[data-hide-table-filter='products:title']").trigger('click')
         | 
| 215 215 | 
             
                  # expect(page).to have_content('foo')
         | 
| 216 216 | 
             
                  # expect(page).to have_content('bar')
         | 
| 217 | 
            -
                  expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'bar')
         | 
| 218 | 
            -
                  expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'foo')
         | 
| 217 | 
            +
                  expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'bar')
         | 
| 218 | 
            +
                  expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'foo')
         | 
| 219 219 | 
             
                end
         | 
| 220 220 | 
             
              end
         | 
| 221 221 |  | 
| @@ -231,14 +231,14 @@ describe "Tabulatr" do | |
| 231 231 | 
             
                    page.should have_content names[l-i]
         | 
| 232 232 | 
             
                  end
         | 
| 233 233 | 
             
                  within('.tabulatr_table thead') do
         | 
| 234 | 
            -
                    find('th[data-tabulatr-column-name=title]').click
         | 
| 234 | 
            +
                    find('th[data-tabulatr-column-name="products:title"]').click
         | 
| 235 235 | 
             
                  end
         | 
| 236 236 | 
             
                  snames = names.sort
         | 
| 237 237 | 
             
                  (1..10).each do |i|
         | 
| 238 238 | 
             
                    page.should have_content snames[i-1]
         | 
| 239 239 | 
             
                  end
         | 
| 240 240 | 
             
                  within('.tabulatr_table thead') do
         | 
| 241 | 
            -
                    find('th[data-tabulatr-column-name=title]').click
         | 
| 241 | 
            +
                    find('th[data-tabulatr-column-name="products:title"]').click
         | 
| 242 242 | 
             
                  end
         | 
| 243 243 | 
             
                  (1..10).each do |i|
         | 
| 244 244 | 
             
                    page.should have_content snames[-i]
         | 
| @@ -303,10 +303,10 @@ describe "Tabulatr" do | |
| 303 303 | 
             
                it 'applys the given style' do
         | 
| 304 304 | 
             
                  p = Product.create!(:title => names[0], :active => true, :price => 10.0)
         | 
| 305 305 | 
             
                  visit with_styling_products_path
         | 
| 306 | 
            -
                  cell   = find(".tabulatr_table tbody td[data-tabulatr-column-name='title']")
         | 
| 307 | 
            -
                  header = find(".tabulatr_table thead th[data-tabulatr-column-name='title']")
         | 
| 308 | 
            -
                  cell_without_style   = find(".tabulatr_table tbody td[data-tabulatr-column-name='price']")
         | 
| 309 | 
            -
                  header_without_style = find(".tabulatr_table thead th[data-tabulatr-column-name='price']")
         | 
| 306 | 
            +
                  cell   = find(".tabulatr_table tbody td[data-tabulatr-column-name='products:title']")
         | 
| 307 | 
            +
                  header = find(".tabulatr_table thead th[data-tabulatr-column-name='products:title']")
         | 
| 308 | 
            +
                  cell_without_style   = find(".tabulatr_table tbody td[data-tabulatr-column-name='products:price']")
         | 
| 309 | 
            +
                  header_without_style = find(".tabulatr_table thead th[data-tabulatr-column-name='products:price']")
         | 
| 310 310 | 
             
                  expect(cell[:style]).to eql 'text-align:left;width:60px;vertical-align:top;white-space:nowrap;background-color:green'
         | 
| 311 311 | 
             
                  expect(header[:style]).to eql 'text-align:left;width:60px;vertical-align:top;white-space:nowrap;color:orange'
         | 
| 312 312 | 
             
                  expect(cell_without_style[:style]).to be_empty
         | 
| @@ -3,8 +3,15 @@ require 'spec_helper' | |
| 3 3 | 
             
            describe Tabulatr::Data do
         | 
| 4 4 |  | 
| 5 5 | 
             
              before do
         | 
| 6 | 
            -
                Tabulatr:: | 
| 7 | 
            -
             | 
| 6 | 
            +
                column = Tabulatr::Renderer::Column.from(
         | 
| 7 | 
            +
                    name: :title,
         | 
| 8 | 
            +
                    klass: Product,
         | 
| 9 | 
            +
                    table_name: :products,
         | 
| 10 | 
            +
                    sort_sql: "products.title",
         | 
| 11 | 
            +
                    filter_sql: "products.title",
         | 
| 12 | 
            +
                    output: ->(record){record.send(:title)}
         | 
| 13 | 
            +
                )
         | 
| 14 | 
            +
                Tabulatr::Data.any_instance.stub(:table_columns).and_return([column])
         | 
| 8 15 | 
             
              end
         | 
| 9 16 |  | 
| 10 17 | 
             
              it 'prefilters the result' do
         | 
| @@ -17,24 +24,13 @@ describe Tabulatr::Data do | |
| 17 24 | 
             
              it 'uses default order' do
         | 
| 18 25 | 
             
                Product.create([{title: 'foo', price: 5}, {title: 'bar', price: 10}, {title: 'fuzz', price: 7}])
         | 
| 19 26 |  | 
| 20 | 
            -
                cols = {
         | 
| 21 | 
            -
                  title: {
         | 
| 22 | 
            -
                    name: 'title',
         | 
| 23 | 
            -
                    sort_sql: nil,
         | 
| 24 | 
            -
                    filter_sql: nil,
         | 
| 25 | 
            -
                    output: nil,
         | 
| 26 | 
            -
                    table_column: Tabulatr::Renderer::Column.from(name: 'title', klass: Product)
         | 
| 27 | 
            -
                  }
         | 
| 28 | 
            -
                }
         | 
| 29 | 
            -
                Tabulatr::Data.instance_variable_set('@columns', cols)
         | 
| 30 27 | 
             
                td = Tabulatr::Data.new(Product)
         | 
| 31 | 
            -
                 | 
| 32 | 
            -
                # raise mod_params.inspect
         | 
| 33 | 
            -
                records = td.data_for_table(HashWithIndifferentAccess.new(example_params.merge(product_sort: 'products.title DESC')))
         | 
| 28 | 
            +
                records = td.data_for_table(HashWithIndifferentAccess.new(example_params.merge(product_sort: 'title DESC')))
         | 
| 34 29 | 
             
                expect(records.count).to eql 3
         | 
| 35 30 | 
             
                titles = ['fuzz', 'foo', 'bar']
         | 
| 31 | 
            +
                # raise records.inspect
         | 
| 36 32 | 
             
                records.each_with_index do |r, ix|
         | 
| 37 | 
            -
                  expect(r[:title]).to eql titles[ix]
         | 
| 33 | 
            +
                  expect(r[:products][:title]).to eql titles[ix]
         | 
| 38 34 | 
             
                end
         | 
| 39 35 | 
             
              end
         | 
| 40 36 | 
             
            end
         | 
| @@ -21,40 +21,46 @@ describe Tabulatr::Data::Filtering do | |
| 21 21 | 
             
              end
         | 
| 22 22 | 
             
              describe '.apply_date_condition' do
         | 
| 23 23 | 
             
                it "filters for 'today'" do
         | 
| 24 | 
            -
                   | 
| 24 | 
            +
                  fake_obj = double(filter_sql: 'publish_at')
         | 
| 25 | 
            +
                  @dummy.apply_date_condition(fake_obj, {simple: 'today'})
         | 
| 25 26 | 
             
                  result = @dummy.instance_variable_get('@relation')
         | 
| 26 27 | 
             
                  expect(result.count).to be 1
         | 
| 27 28 | 
             
                  expect(result[0].id).to be @today.id
         | 
| 28 29 | 
             
                end
         | 
| 29 30 |  | 
| 30 31 | 
             
                it "filters for 'yesterday'" do
         | 
| 31 | 
            -
                   | 
| 32 | 
            +
                  fake_obj = double(filter_sql: 'publish_at')
         | 
| 33 | 
            +
                  @dummy.apply_date_condition(fake_obj, {simple: 'yesterday'})
         | 
| 32 34 | 
             
                  result = @dummy.instance_variable_get('@relation')
         | 
| 33 35 | 
             
                  expect(result.count).to be 1
         | 
| 34 36 | 
             
                  expect(result[0].id).to be @yesterday.id
         | 
| 35 37 | 
             
                end
         | 
| 36 38 |  | 
| 37 39 | 
             
                it "filters for 'this week'" do
         | 
| 38 | 
            -
                   | 
| 40 | 
            +
                  fake_obj = double(filter_sql: 'publish_at')
         | 
| 41 | 
            +
                  @dummy.apply_date_condition(fake_obj, {simple: 'this_week'})
         | 
| 39 42 | 
             
                  result = @dummy.instance_variable_get('@relation')
         | 
| 40 43 | 
             
                  expect(result.count).to be 4
         | 
| 41 44 | 
             
                  expect(result.map(&:id).sort).to eq [@yesterday.id, @today.id, @week_one.id, @week_two.id].sort
         | 
| 42 45 | 
             
                end
         | 
| 43 46 |  | 
| 44 47 | 
             
                it "filters for 'last 7 days'" do
         | 
| 45 | 
            -
                   | 
| 48 | 
            +
                  fake_obj = double(filter_sql: 'publish_at')
         | 
| 49 | 
            +
                  @dummy.apply_date_condition(fake_obj, {simple: 'last_7_days'})
         | 
| 46 50 | 
             
                  result = @dummy.instance_variable_get('@relation')
         | 
| 47 51 | 
             
                  expect(result.map(&:id).sort).to eq ([@last_seven_days.id, @yesterday.id, @today.id, @week_one.id].sort)
         | 
| 48 52 | 
             
                end
         | 
| 49 53 |  | 
| 50 54 | 
             
                it "filters for 'this month'" do
         | 
| 51 | 
            -
                   | 
| 55 | 
            +
                  fake_obj = double(filter_sql: 'publish_at')
         | 
| 56 | 
            +
                  @dummy.apply_date_condition(fake_obj, {simple: 'this_month'})
         | 
| 52 57 | 
             
                  result = @dummy.instance_variable_get('@relation')
         | 
| 53 58 | 
             
                  expect(result.map(&:id).sort).to eq ([@today.id, @week_two.id, @this_month.id])
         | 
| 54 59 | 
             
                end
         | 
| 55 60 |  | 
| 56 61 | 
             
                it "filters for 'last 30 days'" do
         | 
| 57 | 
            -
                   | 
| 62 | 
            +
                  fake_obj = double(filter_sql: 'publish_at')
         | 
| 63 | 
            +
                  @dummy.apply_date_condition(fake_obj, {simple: 'last_30_days'})
         | 
| 58 64 | 
             
                  result = @dummy.instance_variable_get('@relation')
         | 
| 59 65 | 
             
                  expect(result.map(&:id).sort).to eq ([
         | 
| 60 66 | 
             
                    @last_thirty_days.id, @yesterday.id, @last_seven_days.id, @today.id,
         | 
| @@ -62,11 +68,46 @@ describe Tabulatr::Data::Filtering do | |
| 62 68 | 
             
                end
         | 
| 63 69 |  | 
| 64 70 | 
             
                it "filters from 'start_date' to 'end_date'" do
         | 
| 65 | 
            -
                   | 
| 71 | 
            +
                  fake_obj = double(filter_sql: 'publish_at')
         | 
| 72 | 
            +
                  @dummy.apply_date_condition(fake_obj, {
         | 
| 66 73 | 
             
                    simple: 'from_to', from: '31.12.2013 15:00',
         | 
| 67 74 | 
             
                    to: '15.01.2014 00:00'})
         | 
| 68 75 | 
             
                  result = @dummy.instance_variable_get('@relation')
         | 
| 69 76 | 
             
                  expect(result.map(&:id)).to eq ([@yesterday.id, @today.id, @week_two.id].sort)
         | 
| 70 77 | 
             
                end
         | 
| 71 78 | 
             
              end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              describe '.apply_search' do
         | 
| 81 | 
            +
                it 'allows to alter the ActiveRecord::Relation' do
         | 
| 82 | 
            +
                  @dummy.instance_variable_set('@search',
         | 
| 83 | 
            +
                    ->(query, relation){ relation.joins(:vendor).where(%{vendors.name LIKE '%#{query}%'})})
         | 
| 84 | 
            +
                  expect{@dummy.apply_search('awesome vendor')}.to_not raise_error
         | 
| 85 | 
            +
                  sql =  @dummy.instance_variable_get('@relation').to_sql
         | 
| 86 | 
            +
                  expect(sql).to match(/INNER JOIN \"vendors\" ON \"vendors\".\"id\" = \"products\".\"vendor_id\"/)
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                it 'allows to provide only one argument' do
         | 
| 90 | 
            +
                  @dummy.instance_variable_set('@search', ->(query){ nil })
         | 
| 91 | 
            +
                  expect{@dummy.apply_search('awesome product')}.to_not raise_error
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                it 'allows to return a Hash' do
         | 
| 95 | 
            +
                  @dummy.instance_variable_set('@search', ->(query){ {title: query} })
         | 
| 96 | 
            +
                  expect{@dummy.apply_search('awesome product')}.to_not raise_error
         | 
| 97 | 
            +
                  sql =  @dummy.instance_variable_get('@relation').to_sql
         | 
| 98 | 
            +
                  expect(sql).to match(/WHERE \"products\".\"title\"/)
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                it 'allows to return an Array' do
         | 
| 102 | 
            +
                  @dummy.instance_variable_set('@search', ->(query){["title = ?", query]})
         | 
| 103 | 
            +
                  expect{@dummy.apply_search('awesome product')}.to_not raise_error
         | 
| 104 | 
            +
                  sql =  @dummy.instance_variable_get('@relation').to_sql
         | 
| 105 | 
            +
                  expect(sql).to match(/WHERE \(title = 'awesome product'\)/)
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                it 'can not be called without a block variable' do
         | 
| 109 | 
            +
                  @dummy.instance_variable_set('@search', ->{'hi'})
         | 
| 110 | 
            +
                  expect{@dummy.apply_search('test')}.to raise_error
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
              end
         | 
| 72 113 | 
             
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Tabulatr::Data::Formatting do
         | 
| 4 | 
            +
              class DummySpecClass
         | 
| 5 | 
            +
                include Tabulatr::Data::Formatting
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              before(:each) do
         | 
| 9 | 
            +
                @dummy = DummySpecClass.new
         | 
| 10 | 
            +
                @dummy.instance_variable_set('@relation', Product.all)
         | 
| 11 | 
            +
                column = Tabulatr::Renderer::Column.from(
         | 
| 12 | 
            +
                    name: :title,
         | 
| 13 | 
            +
                    klass: Product,
         | 
| 14 | 
            +
                    table_name: :products,
         | 
| 15 | 
            +
                    sort_sql: "products.title",
         | 
| 16 | 
            +
                    filter_sql: "products.title"
         | 
| 17 | 
            +
                )
         | 
| 18 | 
            +
                allow(@dummy).to receive(:table_columns).and_return([column])
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              describe '#apply_formats' do
         | 
| 22 | 
            +
                it 'applies given formatting block to a column' do
         | 
| 23 | 
            +
                  allow(@dummy).to receive(:format_row).and_return(nil)
         | 
| 24 | 
            +
                  p = Product.create!(title: 'title of product')
         | 
| 25 | 
            +
                  @dummy.table_columns.first.output = ->(record){record.title.upcase}
         | 
| 26 | 
            +
                  result = @dummy.apply_formats
         | 
| 27 | 
            +
                  expect(result.count).to be 1
         | 
| 28 | 
            +
                  expect(result.first[:products][:title]).to eql 'TITLE OF PRODUCT'
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            end
         | 
| @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Tabulatr::Data::Sorting do
         | 
| 4 | 
            +
              class DummySpecClass
         | 
| 5 | 
            +
                include Tabulatr::Data::Sorting
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              before(:each) do
         | 
| 9 | 
            +
                @dummy = DummySpecClass.new
         | 
| 10 | 
            +
                @dummy.instance_variable_set('@relation', Product.all)
         | 
| 11 | 
            +
                @dummy.instance_variable_set('@table_name', 'products')
         | 
| 12 | 
            +
                @dummy.instance_variable_set('@base', Product)
         | 
| 13 | 
            +
                column = Tabulatr::Renderer::Column.from(
         | 
| 14 | 
            +
                    name: :title,
         | 
| 15 | 
            +
                    klass: Product,
         | 
| 16 | 
            +
                    sort_sql: "products.title",
         | 
| 17 | 
            +
                    filter_sql: "products.title",
         | 
| 18 | 
            +
                    table_name: :products
         | 
| 19 | 
            +
                )
         | 
| 20 | 
            +
                allow(@dummy).to receive(:table_columns).and_return([column])
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              describe '.apply_sorting' do
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                context 'no sortparam' do
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  context 'with no default order given' do
         | 
| 28 | 
            +
                    it 'sorts by primary_key descending' do
         | 
| 29 | 
            +
                      @dummy.apply_sorting(nil)
         | 
| 30 | 
            +
                      expect(@dummy.instance_variable_get('@relation').to_sql)
         | 
| 31 | 
            +
                        .to match /ORDER BY products.id desc/
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                context 'sortparam given' do
         | 
| 37 | 
            +
                  context 'sort by column of main table' do
         | 
| 38 | 
            +
                    context 'sort by "title"' do
         | 
| 39 | 
            +
                      it 'uses the given sortparam' do
         | 
| 40 | 
            +
                        @dummy.apply_sorting('products.title desc')
         | 
| 41 | 
            +
                        expect(@dummy.instance_variable_get('@relation').to_sql)
         | 
| 42 | 
            +
                          .to match /ORDER BY products.title desc/
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  context 'sort by association column' do
         | 
| 48 | 
            +
                    it 'sorts by vendor.name' do
         | 
| 49 | 
            +
                      @dummy.instance_variable_set('@includes', [])
         | 
| 50 | 
            +
                      assoc = Tabulatr::Renderer::Association.from(
         | 
| 51 | 
            +
                          name: :name,
         | 
| 52 | 
            +
                          table_name: :vendor,
         | 
| 53 | 
            +
                          klass: Product,
         | 
| 54 | 
            +
                          sort_sql: "vendors.name",
         | 
| 55 | 
            +
                          filter_sql: "vendors.name"
         | 
| 56 | 
            +
                      )
         | 
| 57 | 
            +
                      allow(@dummy).to receive(:table_columns).and_return([assoc])
         | 
| 58 | 
            +
                      @dummy.apply_sorting('vendor:name desc')
         | 
| 59 | 
            +
                      expect(@dummy.instance_variable_get('@relation').to_sql)
         | 
| 60 | 
            +
                        .to match /ORDER BY vendors.name desc/
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  context 'sort by custom sql' do
         | 
| 65 | 
            +
                    it "sorts by products.title || '' || vendors.name" do
         | 
| 66 | 
            +
                      @dummy.instance_variable_set('@includes', [])
         | 
| 67 | 
            +
                      column = Tabulatr::Renderer::Column.from(
         | 
| 68 | 
            +
                          name: :custom_column,
         | 
| 69 | 
            +
                          klass: Product,
         | 
| 70 | 
            +
                          sort_sql: "products.title || '' || vendors.name",
         | 
| 71 | 
            +
                          filter_sql: "products.title"
         | 
| 72 | 
            +
                      )
         | 
| 73 | 
            +
                      allow(@dummy).to receive(:table_columns).and_return([column])
         | 
| 74 | 
            +
                      @dummy.apply_sorting('custom_column asc')
         | 
| 75 | 
            +
                      expect(@dummy.instance_variable_get('@relation').to_sql)
         | 
| 76 | 
            +
                        .to match /ORDER BY products.title \|\| '' \|\| vendors.name asc/
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
            end
         |