Listpress
Listing helper for Timepress projects.
Requirements
- Listpress requires jQuery to run.
- Listpress styles are built on top of Bootstrap, but all templates and looks can be customized if you need to use something else.
Installation
Add this line to your application's Gemfile:
gem 'listpress', :git => '[email protected]:timepress/listpress.git', :branch => "master"
And then execute:
$ bundle install
Add listpress to your application.js
import "listpress"
Add listpress to your app/config/importmap.rb
pin "listpress", to: "listpress.js" # from gem
And assets/config/manifest.js
//= link listpress.js
Listpress uses Rails importmaps to import jQuery, use bin/importmap
to make jQuery available if you didn't do so yet.
bin/importmap pin [email protected] --download
And styles to your application.scss
. Styles are built on top of Boostrap 5.
@import 'listpress';
Usage
In your view:
<%#
create listing for @messages
`name` is optional but required to differentiate between multiple listings on the same page if present
`per_page` activates paging
`default_sort` "name_of_column:desc" or "name_of_column:asc" - works only if column has sort enabled
`default_filter` { name_of_filter: "value of filter" }
%>
<%= listing @messages, name: :messages, per_page: 100, default_sort: "date:desc", default_filter: { resolved: false } do |l| %>
<%# :code filter will use where(code: filter_value), because model has this attribute %>
<% l.filter :code, as: :select, collection: Message.distinct.order(:code).pluck(:code) %>
<%# :resolved filter will call method "resolved" on collection passing filter value as argument, (instead of attribute :resolved) %>
<% l.filter :resolved, as: :boolean, method: :resolved %>
<%# custom filter - block returns filtered collection %>
<% l.filter(:code_ends_with, as: :text) {|collection, value| collection.where('code LIKE ?', "%#{value}")} %>
<%# will use search method on the collection %>
<% l.filter :search, as: :search %>
<%# set html attributes for whole item (for <tr> tag) %>
<% l.item_attributes {|item| { class: item.red? "red" : "" }} %>
<%# add class "nowrap", allow sorting by :date, custom output specified with a block %>
<%# th_options sets html attributes for column header, td_options for column values %>
<% l.column(:date, class: "nowrap", sort: true, th_options: {title: "Wow such dates"}, td_options: {title: "Very short"}) {|m| lf m.date, format: :short} %>
<%# passes the output (even if given by block) through format_helper() %>
<% l.column(:number, class: "num", helper: :format_number) %>
<%# custom field label and output %>
<% l.column("!", class: "nowrap") do |m| %>
<span title="Status" style="color: red"><%= m.status %></span>
<% end %>
<% sort by custom SQL %>
<% l.column(:customer, sort: Arel.sql("customers.name")) {|m| m.customer.name} %>
<% l.column(:subject, sort: true) do |m| %>
<% if m.resolved? %>
<%= link_to m.subject, ote_msg_path(m, type: 'dec') %>
<% else %>
<b><%= link_to m.subject, ote_msg_path(m, type: 'dec') %></b>
<% end %>
<% end %>
<% end %>
In your controller:
def index
@messages = Message.all # listing gets the whole collection and it will apply sorting, filtering and paging on it's own
respond_with_listing # just as render :index, but with some tricks to manage AJAX requests
end
Overriding views
You can copy and override these templates to update the markup or add new filter types.
app/views/shared/_listing.html.erb
app/views/shared/_listing_filters.html.erb
app/views/shared/_listing_table.html.erb
In-line editing
For in-line editing SimpleForm gem is required. Then you can specify editable columns with :edit
option like this:
<%= listing @pages, per_page: 100, default_sort: "date:desc" do |l| %>
<%# produces: f.input :title %>
<% l.column :title, edit: true %>
<%# produces: f.input :published, as: :boolean %>
<% l.column :published, helper: :bool, edit: { as: :boolean } %>
<%# produces: f.association :author, as: :select, collection: User.all.pluck(:name, :id) %>
<% l.column :author, helper: :bool, edit: { association: true, as: :select, collection: User.all.pluck(:name, :id) } %>
<%# uses this column to place the editing form and "Save" and "Cancel" buttons %>
<% l.column edit: :actions do |p| %>
<%= link_to "Edit", edit_page_path(p) %>
<% end %>
<% end %>
edit: true
turns on editing with default SimpleForm f.input
field for attribute of the same name as column.
If you specify edit: hash
, the hash is passed as options to f.input
.
If you need to use f.association
field, use edit: {associtation: true}
Use edit: :actions
to specify a column where the form and it's submit buttons should be placed. This should be specified exactly once.
Javascript events
update.listpress
(data:url
) - is triggered on.listing
after the listing is updated with AJAX - you can listen to this to initialize active components in table or react to document location changes - current state url is passed as data.refresh.listpress
- trigger this on a listing item.listing-item
to reload the item - causes AJAX request that returns only this item and overwrite item in listing - filters are ignorededit.listpress
(data:index
) - trigger this on a listing item.listing-item
to load an in-line editing form for this item.index
is index of.editable
(resp..editing
) cell that should be focused when loaded.
I18n
Listpress defines I18n keys in listpress
scope for cs
and en
languages.