lib/presentation/grid.rb in presenting-2.0.0 vs lib/presentation/grid.rb in presenting-2.0.1
- old
+ new
@@ -1,160 +1,162 @@
-module Presentation
- # TODO: ability to render a hash
- # TODO: custom css classes for rows and/or cells
- # TODO: document or complain for required options -- id and fields
- # TODO: make fields= accept an ActiveRecord::Base.columns array for a default field set
- class Grid < Base
- # The id for this presentation. Required.
- attr_accessor :id
-
- # The display title for this presentation. Will default based on the id.
- attr_writer :title
- def title
- @title ||= self.id.titleize
- end
-
- # Paradigm Example:
- # Grid.new(:fields => [
- # :email,
- # {"Full Name" => proc{|r| [r.first_name, r.last_name].join(' ')}},
- # {"Roles" => {:value => :roles, :type => :collection}}
- # ])
- #
- # Is equivalent to:
- # g = Grid.new
- # g.fields << :email
- # g.fields << {"Full Name" => proc{|r| [r.first_name, r.last_name].join(' ')},
- # g.fields << {"Roles" => {:value => :roles, :type => :collection}}
- def fields=(args)
- args.each do |field|
- self.fields << field
- end
- end
-
- def fields
- @fields ||= Presenting::FieldSet.new(Field, :name, :value)
- end
-
- def colspan
- @colspan ||= fields.size + (record_links.empty? ? 0 : 1)
- end
-
- def iname; :grid end
-
- class Field < Presenting::Attribute
- # Defines how this field sorts. This means two things:
- # 1. whether it sorts
- # 2. what name it uses to sort
- #
- # Examples:
- #
- # # The field is sortable and assumes the sort_name of "first_name".
- # # This is the default.
- # Field.new(:sortable => true, :name => "First Name")
- #
- # # The field is sortable and assumes the sort_name of "first".
- # Field.new(:sortable => 'first', :name => 'First Name')
- #
- # # The field is unsortable.
- # Field.new(:sortable => false)
- def sortable=(val)
- @sort_name = case val
- when TrueClass: self.id
- when FalseClass, NilClass: nil
- else val.to_s
- end
- end
-
- # if the field is sortable at all
- def sortable?
- self.sortable = Presenting::Defaults.grid_is_sortable unless defined? @sort_name
- !@sort_name.blank?
- end
-
- attr_reader :sort_name
-
- # is this field sorted in the given request?
- def is_sorted?(request)
- @is_sorted ||= if sortable? and sorting = request.query_parameters["sort"] and sorting[sort_name]
- sorting[sort_name].to_s.match(/desc/i) ? 'desc' : 'asc'
- else
- false
- end
- end
-
- # for the view -- modifies the current request such that it would sort this field.
- def sorted_url(request)
- if current_direction = is_sorted?(request)
- next_direction = current_direction == 'desc' ? 'asc' : 'desc'
- else
- next_direction = 'desc'
- end
- request.path + '?' + request.query_parameters.merge("sort" => {sort_name => next_direction}).to_param
- end
-
- ##
- ## Planned
- ##
-
- # TODO: discover "type" from data class (ActiveRecord) if available
- # TODO: decorate a Hash object so type is specifiable there as well
- # PLAN: type should determine how a field renders. custom types for custom renders. this should be the second option to present().
- # attr_accessor :type
-
- # PLAN: a field's description would appear in the header column, perhaps only visibly in a tooltip
- # attr_accessor :description
-
- # PLAN: any field may be linked. this would happen after :value and :type.
- # attr_accessor :link
- end
-
- # Links are an area where I almost made the mistake of too much configuration. Presentations are configured in the view,
- # and all of the view helpers are available. When I looked at the (simple) configuration I was building and realized that
- # I could just as easily take the result of link_to, well, I felt a little silly.
- #
- # Compare:
- #
- # @grid.links = [
- # {:name => 'Foo', :url => foo_path, :class => 'foo'}
- # ]
- #
- # vs:
- #
- # @grid.links = [
- # link_to('Foo', foo_path, :class => 'foo')
- # ]
- #
- # Not only is the second example (the supported example, by the way) shorter and cleaner, it encourages the developer
- # to stay in touch with the Rails internals and therefore discourages a configuration-heavy mindset.
- def links=(set)
- set.compact.each do |link|
- raise ArgumentError, "Links must be strings, such as the output of link_to()." unless link.is_a?(String)
- links << link
- end
- end
- def links
- @links ||= []
- end
-
- # Like links, except the link will appear for each record. This means that the link must be a block that accepts the
- # record as its argument. For example:
- #
- # @grid.record_links = [
- # proc{|record| link_to("Foo", foo_path(record), :class => 'foo') }
- # ]
- #
- def record_links=(set)
- set.compact.each do |link|
- raise ArgumentError, "Record links must be blocks that accept the record as an argument." unless link.respond_to?(:call) and link.arity == 1
- record_links << link
- end
- end
- def record_links
- @record_links ||= []
- end
-
- def paginate?
- defined? WillPaginate and (presentable.is_a? WillPaginate::Collection or presentable.respond_to?(:total_entries))
- end
- end
-end
+module Presentation
+ # TODO: ability to render a hash
+ # TODO: custom css classes for rows and/or cells
+ # TODO: document or complain for required options -- id and fields
+ # TODO: make fields= accept an ActiveRecord::Base.columns array for a default field set
+ class Grid < Base
+ # The id for this presentation. Required.
+ attr_accessor :id
+
+ # The display title for this presentation. Will default based on the id.
+ attr_writer :title
+ def title
+ @title ||= self.id.titleize
+ end
+
+ # Paradigm Example:
+ # Grid.new(:fields => [
+ # :email,
+ # {"Full Name" => proc{|r| [r.first_name, r.last_name].join(' ')}},
+ # {"Roles" => {:value => :roles, :type => :collection}}
+ # ])
+ #
+ # Is equivalent to:
+ # g = Grid.new
+ # g.fields << :email
+ # g.fields << {"Full Name" => proc{|r| [r.first_name, r.last_name].join(' ')},
+ # g.fields << {"Roles" => {:value => :roles, :type => :collection}}
+ def fields=(args)
+ args.each do |field|
+ self.fields << field
+ end
+ end
+
+ def fields
+ @fields ||= Presenting::FieldSet.new(Field, :name, :value)
+ end
+
+ def colspan
+ @colspan ||= fields.size + (record_links.empty? ? 0 : 1)
+ end
+
+ def iname; :grid end
+
+ class Field < Presenting::Attribute
+ # Defines how this field sorts. This means two things:
+ # 1. whether it sorts
+ # 2. what name it uses to sort
+ #
+ # Examples:
+ #
+ # # The field is sortable and assumes the sort_name of "first_name".
+ # # This is the default.
+ # Field.new(:sortable => true, :name => "First Name")
+ #
+ # # The field is sortable and assumes the sort_name of "first".
+ # Field.new(:sortable => 'first', :name => 'First Name')
+ #
+ # # The field is unsortable.
+ # Field.new(:sortable => false)
+ def sortable=(val)
+ @sort_name = case val
+ when TrueClass, FalseClass, NilClass
+ val
+ else
+ val.to_s
+ end
+ end
+
+ # if the field is sortable at all
+ def sortable?
+ self.sortable = Presenting::Defaults.grid_is_sortable unless defined? @sort_name
+ self.sortable = self.id if @sort_name == true
+ !@sort_name.blank?
+ end
+
+ attr_reader :sort_name
+
+ # is this field sorted in the given request?
+ def is_sorted?(request)
+ @is_sorted ||= if sortable? and sorting = request.query_parameters["sort"] and sorting[sort_name]
+ sorting[sort_name].to_s.match(/desc/i) ? 'desc' : 'asc'
+ else
+ false
+ end
+ end
+
+ # for the view -- modifies the current request such that it would sort this field.
+ def sorted_url(request)
+ if current_direction = is_sorted?(request)
+ next_direction = current_direction == 'desc' ? 'asc' : 'desc'
+ else
+ next_direction = 'desc'
+ end
+ request.path + '?' + request.query_parameters.merge("sort" => {sort_name => next_direction}).to_param
+ end
+
+ ##
+ ## Planned
+ ##
+
+ # TODO: discover "type" from data class (ActiveRecord) if available
+ # TODO: decorate a Hash object so type is specifiable there as well
+ # PLAN: type should determine how a field renders. custom types for custom renders. this should be the second option to present().
+ # attr_accessor :type
+
+ # PLAN: a field's description would appear in the header column, perhaps only visibly in a tooltip
+ # attr_accessor :description
+
+ # PLAN: any field may be linked. this would happen after :value and :type.
+ # attr_accessor :link
+ end
+
+ # Links are an area where I almost made the mistake of too much configuration. Presentations are configured in the view,
+ # and all of the view helpers are available. When I looked at the (simple) configuration I was building and realized that
+ # I could just as easily take the result of link_to, well, I felt a little silly.
+ #
+ # Compare:
+ #
+ # @grid.links = [
+ # {:name => 'Foo', :url => foo_path, :class => 'foo'}
+ # ]
+ #
+ # vs:
+ #
+ # @grid.links = [
+ # link_to('Foo', foo_path, :class => 'foo')
+ # ]
+ #
+ # Not only is the second example (the supported example, by the way) shorter and cleaner, it encourages the developer
+ # to stay in touch with the Rails internals and therefore discourages a configuration-heavy mindset.
+ def links=(set)
+ set.compact.each do |link|
+ raise ArgumentError, "Links must be strings, such as the output of link_to()." unless link.is_a?(String)
+ links << link
+ end
+ end
+ def links
+ @links ||= []
+ end
+
+ # Like links, except the link will appear for each record. This means that the link must be a block that accepts the
+ # record as its argument. For example:
+ #
+ # @grid.record_links = [
+ # proc{|record| link_to("Foo", foo_path(record), :class => 'foo') }
+ # ]
+ #
+ def record_links=(set)
+ set.compact.each do |link|
+ raise ArgumentError, "Record links must be blocks that accept the record as an argument." unless link.respond_to?(:call) and link.arity == 1
+ record_links << link
+ end
+ end
+ def record_links
+ @record_links ||= []
+ end
+
+ def paginate?
+ defined? WillPaginate and (presentable.is_a? WillPaginate::Collection or presentable.respond_to?(:total_entries))
+ end
+ end
+end