# frozen_string_literal: true # A helper class for building HTML tables. Used in views. # # @example # <%= table_for @tags do |table| %> # <% table.column :name do |tag| %> # <%= link_to_wiki "?", tag.name %> # <%= link_to tag.name, posts_path(tags: tag.name) %> # <% end %> # <% table.column :post_count %> # <% end %> # # @see app/views/table_builder/_table.html.erb class TableBuilder # Represents a single column in the table. class Column attr_reader :attribute, :name, :block, :header_attributes, :body_attributes # Define a table column. # # @example # <% table.column :post_count %> # # @example # <% table.column :name do |tag| %> # <%= tag.pretty_name %> # <% end %> # # @param attribute [Symbol] The attribute in the model the column is for. # The column's name and value will come from this attribute by default. # @param name [String] the column's name, if different from the attribute name. # @param column [String] the column name # @param th [Hash] the HTML attributes for the column's tag. # @param td [Hash] the HTML attributes for the column's tag. # @param width [String] the HTML width value for the tag. # @yieldparam item a block that returns the column value based on the item. def initialize(attribute = nil, column: nil, th: {}, td: {}, width: nil, name: nil, &block) @attribute = attribute @column = column @header_attributes = { width: width, **th } @body_attributes = td @block = block @name = name || attribute @name = @name.to_s.titleize unless @name.is_a?(String) if @name.present? || @column.present? if @column.present? column_class = "#{@column}-column" else column_class = "#{@name.parameterize.dasherize}-column" end @header_attributes[:class] = "#{column_class} #{@header_attributes[:class]}".strip @body_attributes[:class] = "#{column_class} #{@body_attributes[:class]}".strip end end # Returns the value of the table cell. # @param item [ApplicationRecord] the table cell item # @param i [Integer] the table row number # @param j [Integer] the table column number # @return [#to_s] the value of the table cell def value(item, i, j) if block.present? block.call(item, i, j, self) nil elsif attribute.is_a?(Symbol) item.send(attribute) else "" end end end attr_reader :columns, :table_attributes, :row_attributes, :items # Build a table for an array of objects, one object per row. # # The tag is automatically given an HTML id of the form `{name}-table`. # For example, `posts-table`, `tags-table`. # # The tag is automatically given an HTML id of the form `{name}-{id}`. # For example, `post-1234`, `tag-4567`, etc. Each tag also gets a set of # data attributes for each model; see #html_data_attributes in app/policies. # # @param items [Array] The list of ActiveRecord objects to # build the table for. One item per table row. # @param tr [Hash] optional HTML attributes for the tag for each row # @param table_attributes [Hash] optional HTML attributes for the
tag # @yieldparam table [self] the table being built def initialize(items, tr: {}, **table_attributes) @items = items @columns = [] @table_attributes = { class: "striped", **table_attributes } @row_attributes = tr if items.respond_to?(:model_name) @table_attributes[:id] ||= "#{items.model_name.plural.dasherize}-table" end yield self if block_given? end # Add a column to the table. # @example # table.column(:name) def column(...) @columns << Column.new(...) end # Return the HTML attributes for each tag. # @param item [ApplicationRecord] the item for this row # @param i [Integer] the row number (unused) # @return [Hash] the attributes def all_row_attributes(item, i) return {} if !item.is_a?(ApplicationRecord) { id: "#{item.model_name.singular.dasherize}-#{item.id}", **row_attributes, **ApplicationController.helpers.data_attributes_for(item) } end end