Class: Listpress::Listing

Inherits:
Object
  • Object
show all
Defined in:
lib/listpress/listing.rb

Overview

definition of a listing - made from DSL in a View

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, collection, options = {}, params = {}) ⇒ Listing

Args:

name: name of the listing
collection: collection of items to list - usually AR relation
options: configuration of listing given as specified in template
params: request params for this specific listing

Options:

per_page: Limit output to this many items and turn paging on
default_sort: Use this sort if none specified in params (eg: "id:asc")
default_filter: Hash with default values for filters
resolver: Specify custom Resolver class - Resolver applies filters and sorting to collection - default Listpress::DefaultResolver
view: Partial used to render the listing component, default 'shared/listing'
listing_view: Partial used to show the listed items, default 'shared/listing_table'
filters_view: Partial used to show filters, default 'shared/listing_filters'


21
22
23
24
25
26
27
28
29
30
# File 'lib/listpress/listing.rb', line 21

def initialize(name, collection, options = {}, params = {})
  @name = name
  @collection = collection
  @options = options
  @params = params
  @columns = []
  @filters = []
  @captures = {}
  @item_attributes = {}
end

Instance Attribute Details

#capturesObject (readonly)

Returns the value of attribute captures.



4
5
6
# File 'lib/listpress/listing.rb', line 4

def captures
  @captures
end

#collectionObject (readonly)

returns filtered, sorted and paged collection



127
128
129
# File 'lib/listpress/listing.rb', line 127

def collection
  @collection
end

#columnsObject (readonly)

Returns the value of attribute columns.



4
5
6
# File 'lib/listpress/listing.rb', line 4

def columns
  @columns
end

#filtersObject (readonly)

Returns the value of attribute filters.



4
5
6
# File 'lib/listpress/listing.rb', line 4

def filters
  @filters
end

#nameObject (readonly)

Returns the value of attribute name.



4
5
6
# File 'lib/listpress/listing.rb', line 4

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



4
5
6
# File 'lib/listpress/listing.rb', line 4

def options
  @options
end

#paramsObject (readonly)

Returns the value of attribute params.



4
5
6
# File 'lib/listpress/listing.rb', line 4

def params
  @params
end

Class Method Details

.flatten_params(params, level = 0) ⇒ Object

returns representation of arbitrarily nested params as list of pairs [field_name, value], that can be used in forms to recreate the params



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/listpress/listing.rb', line 183

def self.flatten_params(params, level=0)
  out = []

  case params
  when Array
    params.each do |v|
      out += flatten_params(v, level+1).collect {|kk, vv| ['[]' + kk, vv]}
    end
  when Hash
    params.each do |k, v|
      k = level > 0 ? "[#{k}]" : k.to_s
      out += flatten_params(v, level+1).collect {|kk, vv| [k + kk, vv]}
    end
  else
    out << ['', params]
  end

  out
end

Instance Method Details

#column(*args, &block) ⇒ Object

Defines a column

Usage:

<%= listing collection, options do |l| %>
  <% l.column :id, class: "right-align", sort: true %>
  <% l.column :name, sort: true, helper: :shorten, edit: true %>
  <% l.column :special, th_options: { title: "Special column"}, td_options: { title: "With special cells" } %>
  <% l.column(:block) { |item| link_to item.name, edit_item_path(item) } %>

Options:

- attr: First argument if given is attribute name - unless a block is specified, this attribute will be called on the model to get content of the cell
- label: Label of the column, defaults to human_attribute_name of `attr`
- class: Used as HTML class for this column's cells
- sort: Allow sorting of this column
  - true to sort by the `attr` (must be an SQL column)
  - column name to sort by other SQL column
  - Arel.sql() to sort by arbitrary SQL
- edit: true to activate in-line editing with SimpleForm, hash to pass options to SimpleForm `input` builder method. Use association: true to call SimpleForm `association` instead.
- th_options: HTML attributes for column header
- td_options: HTML attributes for column cells
- helper: use this helper to format cell value - if cell value given by block, applies to block result


53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/listpress/listing.rb', line 53

def column(*args, &block)
  opts = args.extract_options!
  attr = args[0] || ""

  column = opts.merge(attr: attr)
  column[:proc] = block if block_given?

  if column[:edit]
    SimpleForm rescue raise("To use in-line editing simple_form gem is required.")
  end

  @columns << column
end

#columns_with_td_optionsObject



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/listpress/listing.rb', line 147

def columns_with_td_options
  columns.collect do |col|
    td_options = col[:td_options].deep_dup || {}
    td_options[:class] = Array.wrap(td_options[:class]) + Array.wrap(col[:class])
    if col[:edit]
      if col[:edit] == :actions
        td_options[:class] << (edit? ? "editing-actions" : "editable-actions")
      else
        td_options[:class] << (edit? ? "editing" : "editable")
      end
    end

    [col, td_options]
  end
end

#edit?Boolean

Returns:

  • (Boolean)


139
140
141
# File 'lib/listpress/listing.rb', line 139

def edit?
  params[:edit]
end

#filter(*args, &block) ⇒ Object

Defines a filter

Usage: <%= listing collection, options do |l| %>

<% l.filter :search, as: :search %>
<% l.filter :name, as: :text %>
<% l.filter(:active, as: :boolean) {|collection, value| collection.where(active: value)} %>
...

<% end %>

Filter value is either used on collection method with the same name as the filter (ie. the first filter calls ‘collection.search(filter_value)`) or you can use block to alter your collection



96
97
98
99
100
101
102
103
104
# File 'lib/listpress/listing.rb', line 96

def filter(*args, &block)
  opts = args.extract_options!
  name = args[0] || ""

  filter = opts.merge(name: name)
  filter[:proc] = block if block_given?

  @filters << filter
end

#filter_value(filter_name) ⇒ Object

return current value of filter filter_name



223
224
225
226
227
228
229
230
231
# File 'lib/listpress/listing.rb', line 223

def filter_value(filter_name)
  if params[:filter].respond_to?(:dig)
    params[:filter].dig(filter_name)
  elsif options[:default_filter]
    options[:default_filter][filter_name]
  else
    nil
  end
end

#filters_viewObject

partial used to render filters



239
240
241
# File 'lib/listpress/listing.rb', line 239

def filters_view
  options[:filters_view] || 'shared/listing_filters'
end

#flatten_params(*args) ⇒ Object



203
204
205
# File 'lib/listpress/listing.rb', line 203

def flatten_params(*args)
  self.class.flatten_params(*args)
end

#human_name(attr) ⇒ Object

finds human_name (using I18n) for column attr



107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/listpress/listing.rb', line 107

def human_name(attr)
  return "" unless attr.present?

  return attr if attr.is_a?(String)

  if @collection.respond_to?(:model)
    @collection.model.human_attribute_name(attr)
  elsif @collection.respond_to?(:human_attribute_name)
    @collection.human_attribute_name(attr)
  else
    attr.to_s.humanize
  end
end

#item_attributes(*args, &block) ⇒ Object

Defines attributes for each item (tr).

Usage:

<%= listing collection, options do |l| %>
  <% l.item_attributes {|item| { class: item.red? ? "red" : "" }} %>
  ...


73
74
75
76
77
78
79
80
81
# File 'lib/listpress/listing.rb', line 73

def item_attributes(*args, &block)
  if block_given?
    @item_attributes[:proc] = block
  elsif !args.empty?
    @item_attributes = args.extract_options!
  else
    @item_attributes
  end
end

#item_attributes_for(item) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/listpress/listing.rb', line 163

def item_attributes_for(item)
  if item_attributes[:proc]
    attributes = item_attributes[:proc].call(item)
  else
    attributes = item_attributes.deep_dup
  end

  if item.respond_to?(:id)
    attributes[:data] ||= {}
    attributes[:data][:id] = item.id
  end

  attributes[:class] = Array.wrap(attributes[:class])
  attributes[:class] << 'listing-item'

  attributes
end

#item_refresh?Boolean

Returns:

  • (Boolean)


135
136
137
# File 'lib/listpress/listing.rb', line 135

def item_refresh?
  params[:item_id].present?
end

#listing_viewObject

partial used to render the listing of items



244
245
246
# File 'lib/listpress/listing.rb', line 244

def listing_view
  options[:listing_view] || 'shared/listing_table'
end

#page_param_nameObject



143
144
145
# File 'lib/listpress/listing.rb', line 143

def page_param_name
  "#{name}[page]"
end

#paginate?Boolean

Returns:

  • (Boolean)


131
132
133
# File 'lib/listpress/listing.rb', line 131

def paginate?
  options[:per_page]
end

#resolverObject

return resolver object which decides how to filter, sort and page a collection according to listing params and options



122
123
124
# File 'lib/listpress/listing.rb', line 122

def resolver
  @resolver ||= (options[:resolver] || DefaultResolver).new(@collection, self)
end

#sortObject

returns current sorting as [attr, dir] (both symbols) or nil if not set



208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/listpress/listing.rb', line 208

def sort
  s = params[:sort].presence || options.dig(:default_sort)

  if s.present?
    attr, dir = s.split(':', 2)

    if %w(asc desc).include?(dir)
      return attr.to_sym, dir.to_sym
    end
  end

  nil
end

#viewObject

partial used to render the whole component



234
235
236
# File 'lib/listpress/listing.rb', line 234

def view
  options[:view] || 'shared/listing'
end