rmg/magic_grid

View on GitHub
lib/magic_grid/definition.rb

Summary

Maintainability
A
3 hrs
Test Coverage
require 'magic_grid/logger'
require 'magic_grid/collection'
require 'magic_grid/column'
require 'magic_grid/order'
require 'active_support/core_ext'

module MagicGrid
  class Definition
    attr_reader :columns, :options, :params

    def magic_collection
      @collection
    end

    def collection
      @collection.collection
    end

    DEFAULTS = {
      :class                 => [],
      :top_pager             => false,
      :bottom_pager          => true,
      :remote                => false,
      :min_search_length     => 3,
      :id                    => false,
      :searcher              => false,
      :needs_searcher        => false,
      :live_search           => false,
      :listeners             => {},
      :collapse_empty_header => false,
      :collapse_empty_footer => false,
      :default_ajax_handler  => true,
      :default_order         => :asc,
      :search_button         => false,
      :searcher_size         => nil,
      :title                 => nil,
    }

    def self.runtime_defaults
      # run these lazily to catch any late I18n path changes
      DEFAULTS.merge(Collection::DEFAULTS).merge(
        :if_empty         => I18n.t("magic_grid.no_results").capitalize, # "No results found."
        :searcher_label   => I18n.t("magic_grid.search.label").capitalize + ': ', # "Search: "
        :searcher_tooltip => I18n.t("magic_grid.search.tooltip"), # "type.. + <return>"
        :searcher_button  => I18n.t("magic_grid.search.button").capitalize # "Search"
      )
    end

    def self.normalize_columns_options(cols_or_opts, opts)
      case cols_or_opts
      when Hash
        options = runtime_defaults.merge(cols_or_opts.reject {|k| k == :cols})
        columns = cols_or_opts.fetch(:cols, [])
      when Array
        options = runtime_defaults.merge opts
        columns = cols_or_opts
      else
        raise "I have no idea what that is, but it's not a columns list or options hash"
      end
      [options, columns]
    end

    def initialize(cols_or_opts, collection = nil, controller = nil, opts = {})
      @options, @columns = *self.class.normalize_columns_options(cols_or_opts, opts)
      @params = controller && controller.params || {}

      @collection = Collection.create_or_reuse collection, options

      @columns = Column.columns_for_collection(magic_collection,
                                               columns,
                                               options[:searchable])
      columns.each do |col|
        if col.sortable?
          if col.id == current_sort_col
            col.order = current_order
          else
            col.order = Order::Unordered
          end
        else
          col.order = Order::Unsortable
        end
      end

      apply_collection_params
    end

    def apply_collection_params
      magic_collection.apply_sort(columns[current_sort_col], current_order.to_sql)

      magic_collection.apply_filter filters
      magic_collection.apply_pagination(current_page)
      magic_collection.apply_search current_search

      magic_collection.per_page = options[:per_page]
      magic_collection.apply_filter_callback options[:listener_handler]
      magic_collection.enable_post_filter options[:collection_post_filter]
      magic_collection.add_post_filter_callback options[:post_filter]
    end

    def filters
      @filters ||= begin
        filter_keys = options[:listeners].values
        params.slice(*filter_keys).reject {|k,v| v.to_s.empty? }
      end
    end

    def current_sort_col
      @current_sort_col ||= begin
        given = param(:col, -1).to_i
        if given >= 0 and given <= columns.count
          given
        else
          options[:default_col].to_i
        end
      end
    end

    def default_order
      @default_order ||= Order.from_param(options[:default_order])
    end

    def current_order
      @current_order ||= Order.from_param(param(:order, default_order.to_param))
    end

    def current_search
      param(:q, "")
    end

    def magic_id
      options[:id] || (Column.hash_string(columns) + magic_collection.hash_string)
    end

    def searchable?
      magic_collection.searchable?
    end

    def needs_searcher?
      options[:needs_searcher] or (searchable? and not options[:searcher])
    end

    def searcher
      if needs_searcher?
        param_key(:searcher)
      else
        options[:searcher]
      end
    end

    def has_title?
      options[:title] || false
    end

    def title
      options[:title]
    end

    def param_key(key)
      "#{magic_id}_#{key}".to_sym
    end

    def param(key, default=nil)
      params.fetch(param_key(key), default)
    end

    def base_params
      params.merge :magic_grid_id => magic_id
    end

    def current_page
      [param(:page, 1).to_i, 1].max
    end
  end
end