effective_datatables 4.8.0 → 4.8.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +199 -24
- data/app/assets/javascripts/effective_datatables/flash.js.coffee +1 -1
- data/app/assets/javascripts/effective_datatables/initialize.js.coffee +9 -4
- data/app/assets/javascripts/effective_datatables/inline_crud.js.coffee +42 -13
- data/app/assets/javascripts/effective_datatables/reorder.js.coffee +8 -2
- data/app/assets/javascripts/vendor/jquery.delayedChange.js +1 -1
- data/app/assets/stylesheets/dataTables/dataTables.bootstrap4.scss +1 -3
- data/app/helpers/effective_datatables_helper.rb +3 -1
- data/app/helpers/effective_datatables_private_helper.rb +12 -8
- data/app/models/effective/datatable.rb +28 -2
- data/app/models/effective/datatable_value_tool.rb +0 -6
- data/app/models/effective/effective_datatable/attributes.rb +1 -0
- data/app/models/effective/effective_datatable/compute.rb +1 -0
- data/app/models/effective/effective_datatable/cookie.rb +2 -0
- data/app/models/effective/effective_datatable/dsl/filters.rb +1 -1
- data/app/models/effective/effective_datatable/format.rb +9 -9
- data/app/models/effective/effective_datatable/params.rb +5 -0
- data/app/models/effective/effective_datatable/resource.rb +10 -9
- data/app/models/effective/effective_datatable/state.rb +1 -1
- data/app/views/effective/datatables/_active_storage_column.html.haml +1 -1
- data/app/views/effective/datatables/_bulk_actions_dropdown.html.haml +3 -2
- data/config/effective_datatables.rb +5 -1
- data/config/locales/en.yml +3 -1
- data/config/locales/es.yml +3 -1
- data/config/locales/nl.yml +3 -1
- data/lib/effective_datatables/version.rb +1 -1
- data/lib/effective_datatables.rb +4 -0
- metadata +6 -9
- data/app/datatables/effective_style_guide_datatable.rb +0 -45
- data/app/models/effective/access_denied.rb +0 -17
- data/app/views/effective/style_guide/_effective_datatables.html.haml +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb1dc8f3ac21b885c37e56552192568b059350efcdcd7bd79784d87d91a4bee3
|
4
|
+
data.tar.gz: 46094ee0a00e9246b8dde73c2c9ab4f531c84a287f2cd7db7da467cc0dab6d92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51f91cf414121df572748ce03da5732b53011ad113db667b95284276f9ec628ec12ff0f8f614567ab88c770f9fa674059c6b8ca9a1ab1a5701e4dd8dbd509c2f
|
7
|
+
data.tar.gz: 1fbacd63b25ba9ba0556ccfec605a07ff5a3c6e5ddfc8da6dc723e66bfc4a72cb0d9c97d796a4acdb419e7fa5d1a2c8b8ec760bb4df77dbcee9b79708fce235d
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Does the right thing with searching sql columns as well as computed values from
|
|
8
8
|
|
9
9
|
Displays links to associated edit/show/destroy actions based on `current_user` authorized actions.
|
10
10
|
|
11
|
-
Other features include aggregate (total/average) footer rows, bulk actions, show/hide columns, responsive collapsing columns and
|
11
|
+
Other features include aggregate (total/average) footer rows, bulk actions, show/hide columns, responsive collapsing columns, google charts, and inline crud.
|
12
12
|
|
13
13
|
This gem includes the jQuery DataTables assets.
|
14
14
|
|
@@ -54,7 +54,8 @@ Please check out [Effective Datatables 3.x](https://github.com/code-and-effect/e
|
|
54
54
|
* [bulk_action](#bulk_action_divider)
|
55
55
|
* [bulk_download](#bulk_download)
|
56
56
|
* [bulk_action_content](#bulk_action_content)
|
57
|
-
* [
|
57
|
+
* [Charts](#charts)
|
58
|
+
* [Inline](#inline)
|
58
59
|
* [Extras](#extras)
|
59
60
|
* [Advanced Search and Sort](#advanced-search-and-sort)
|
60
61
|
* [Addtional Functionality](#additional-functionality)
|
@@ -453,7 +454,7 @@ The `datatable do ... end` block configures a table of data.
|
|
453
454
|
|
454
455
|
Initialize the datatable in your controller or view, `@datatable = PostsDatatable.new(self)`, and render it in your view `<%= render_datatable(@datatable) %>`
|
455
456
|
|
456
|
-
|
457
|
+
## col
|
457
458
|
|
458
459
|
This is the main DSL method that you will interact with.
|
459
460
|
|
@@ -526,7 +527,7 @@ You can also use the joined syntax, `col 'user.email'` to create a column for ju
|
|
526
527
|
|
527
528
|
This feature is only working with `belongs_to` and you need to add the `.joins(:user)` to the collection do ... end block yourself.
|
528
529
|
|
529
|
-
|
530
|
+
## val
|
530
531
|
|
531
532
|
Shorthand for value, this command also creates a column on the datatable.
|
532
533
|
|
@@ -548,7 +549,7 @@ This is implemented as a full Array search/sort and is much slower for large dat
|
|
548
549
|
|
549
550
|
The `.format do ... end` block can then be used to apply custom formatting.
|
550
551
|
|
551
|
-
|
552
|
+
## bulk_actions_col
|
552
553
|
|
553
554
|
Creates a column of checkboxes for use with the `bulk_actions` section.
|
554
555
|
|
@@ -558,7 +559,7 @@ Use these checkboxes to select all / none / one or more rows for the `bulk_actio
|
|
558
559
|
|
559
560
|
You can only have one `bulk_actions_col` per datatable.
|
560
561
|
|
561
|
-
|
562
|
+
## actions_col
|
562
563
|
|
563
564
|
When working with an ActiveRecord based collection, this column will consider the `current_user`'s authorization, and generate links to edit, show and destroy actions for any collection class.
|
564
565
|
|
@@ -596,7 +597,7 @@ Any `data-remote` actions will be hijacked and performed as inline ajax by datat
|
|
596
597
|
|
597
598
|
If you'd like to opt-out of this behavior, use `actions_col(inline: false)` or add `data-inline: false` to your action link.
|
598
599
|
|
599
|
-
|
600
|
+
## length
|
600
601
|
|
601
602
|
Sets the default number of rows per page. Valid lengths are `5`, `10`, `25`, `50`, `100`, `250`, `500`, `:all`
|
602
603
|
|
@@ -606,7 +607,7 @@ When not specified, effective_datatables uses the default as per the `config/ini
|
|
606
607
|
length 100
|
607
608
|
```
|
608
609
|
|
609
|
-
|
610
|
+
## order
|
610
611
|
|
611
612
|
Sets the default order of table rows. The first argument is the column, the second the direction.
|
612
613
|
|
@@ -618,7 +619,7 @@ When not specified, effective_datatables will sort by the first defined column.
|
|
618
619
|
order :created_at, :asc|:desc
|
619
620
|
```
|
620
621
|
|
621
|
-
|
622
|
+
## reorder
|
622
623
|
|
623
624
|
Enables drag-and-drop row re-ordering.
|
624
625
|
|
@@ -636,7 +637,7 @@ reorder :position
|
|
636
637
|
|
637
638
|
Using `reorder` will sort the collection by this field and disable all other column sorting.
|
638
639
|
|
639
|
-
|
640
|
+
## aggregate
|
640
641
|
|
641
642
|
The `aggregate` command inserts a row in the table's `tfoot`.
|
642
643
|
|
@@ -681,7 +682,7 @@ The form is submitted by an AJAX POST action, or, in some advanced circumstances
|
|
681
682
|
|
682
683
|
Initialize the datatable in your controller or view, `@datatable = PostsDatatable.new(self)`, and render its filters anywhere with `<%= render_datatable_filters(@datatable) %>`.
|
683
684
|
|
684
|
-
|
685
|
+
## scope
|
685
686
|
|
686
687
|
All defined scopes are rendered as a single radio button form field. Works great with the [effective_form_inputs](https://github.com/code-and-effect/effective_form_inputs) gem.
|
687
688
|
|
@@ -705,7 +706,7 @@ class Post < ApplicationRecord | ActiveRecord::Base
|
|
705
706
|
end
|
706
707
|
```
|
707
708
|
|
708
|
-
|
709
|
+
## filter
|
709
710
|
|
710
711
|
Each filter has a name and a default/fallback value. If the form is submitted blank, the default values are used.
|
711
712
|
|
@@ -758,7 +759,7 @@ Creates a single dropdown menu with a link to each action, download or content.
|
|
758
759
|
|
759
760
|
Along with this section, you must put a `bulk_actions_col` somewhere in your `datatable do ... end` section.
|
760
761
|
|
761
|
-
|
762
|
+
## bulk_action
|
762
763
|
|
763
764
|
Creates a link that becomes clickable when one or more checkbox/rows are selected as per the `bulk_actions_col` column.
|
764
765
|
|
@@ -814,11 +815,11 @@ def approve!
|
|
814
815
|
end
|
815
816
|
```
|
816
817
|
|
817
|
-
|
818
|
+
## bulk_action_divider
|
818
819
|
|
819
820
|
Inserts a menu divider `<li class='divider' role='separator'></li>`
|
820
821
|
|
821
|
-
|
822
|
+
## bulk_download
|
822
823
|
|
823
824
|
So it turns out there are some http issues with using an AJAX action to download a file.
|
824
825
|
|
@@ -859,7 +860,7 @@ def bulk_export_report
|
|
859
860
|
end
|
860
861
|
```
|
861
862
|
|
862
|
-
|
863
|
+
## bulk_action_content
|
863
864
|
|
864
865
|
Blindly inserts content into the dropdown.
|
865
866
|
|
@@ -873,7 +874,7 @@ end
|
|
873
874
|
|
874
875
|
Don't actually use this.
|
875
876
|
|
876
|
-
|
877
|
+
# Charts
|
877
878
|
|
878
879
|
Create a [Google Chart](https://developers.google.com/chart/interactive/docs/quick_start) based on your searched collection, filters and attributes.
|
879
880
|
|
@@ -930,11 +931,169 @@ All options passed to `chart` are used to initialize the chart javascript.
|
|
930
931
|
|
931
932
|
By default, the only package that is loaded is `corechart`, see the `config/initializers/effective_datatables.rb` file to add more packages.
|
932
933
|
|
933
|
-
|
934
|
+
# Inline
|
935
|
+
|
936
|
+
Any datatable can be used as an inline datatable, to create, update and destroy resources without leaving the current page.
|
937
|
+
|
938
|
+
If your datatable is already working with `actions_col` and being rendered from an `Effective::CrudController` controller, all you need to do is change your view from `render_datatable(@datatable)` to `render_datatable(@datatable, inline: true)`.
|
939
|
+
|
940
|
+
Click here for a [Inline Live Demo](https://effective-datatables-demo.herokuapp.com/things) and here for an [Inline Code Example](https://github.com/code-and-effect/effective_datatables_demo)
|
941
|
+
(only the `thing` data model and `things_datatable` are being used inline)
|
942
|
+
|
943
|
+
To use effective_datatables as an inline CRUD builder, you will be relying heavily on [effective_resources](https://github.com/code-and-effect/effective_resources) which is a dependency of this gem. I would also recommend you install [effective_developer](https://github.com/code-and-effect/effective_developer) to get access to some scaffolds and generators. It's not required but I'm gonna use them in this example.
|
944
|
+
|
945
|
+
Here is how I build rails models for inline datatable CRUD operations:
|
946
|
+
|
947
|
+
1. Create a new model file `app/models/thing.rb`:
|
948
|
+
|
949
|
+
```ruby
|
950
|
+
class Thing < ApplicationRecord
|
951
|
+
belongs_to :user
|
952
|
+
|
953
|
+
effective_resource do
|
954
|
+
title :string
|
955
|
+
description :text
|
956
|
+
timestamps
|
957
|
+
end
|
958
|
+
|
959
|
+
scope :deep, -> { includes(:user) }
|
960
|
+
scope :sorted, -> { order(:title) }
|
961
|
+
|
962
|
+
def to_s
|
963
|
+
title
|
964
|
+
end
|
965
|
+
end
|
966
|
+
```
|
967
|
+
|
968
|
+
The `effective_resource do` block comes from the [effective_resources](https://github.com/code-and-effect/effective_resources) gem and is used to build any permitted_params.
|
969
|
+
|
970
|
+
2. Generate a migration. Run `rails generate effective:migration things` to create a migration based off the model file then `rails db:migrate`.
|
971
|
+
|
972
|
+
3. Scaffold the rest. Run `rails generate effective:scaffold_controller things` which will create:
|
973
|
+
|
974
|
+
- A controller `app/controllers/things_controller.rb`:
|
975
|
+
|
976
|
+
```ruby
|
977
|
+
class ThingsController < ApplicationController
|
978
|
+
include Effective::CrudController
|
979
|
+
end
|
980
|
+
```
|
981
|
+
|
982
|
+
The Effective::CrudController comes from [effective_resources](https://github.com/code-and-effect/effective_resources) gem and handles the standard 7 CRUD actions and member and collection actions. It is opinionated code that follows rails conventions. It considers the `routes.rb` and `ability.rb` or other authorization, to find all available actions.
|
983
|
+
|
984
|
+
- A datatable `app/datatables/things_datatable.rb`:
|
985
|
+
|
986
|
+
```ruby
|
987
|
+
class ThingsDatatable < Effective::Datatable
|
988
|
+
datatable do
|
989
|
+
col :title
|
990
|
+
col :description
|
991
|
+
actions_col
|
992
|
+
end
|
993
|
+
|
994
|
+
collection do
|
995
|
+
Thing.deep.all
|
996
|
+
end
|
997
|
+
end
|
998
|
+
```
|
999
|
+
|
1000
|
+
This is an ordinary datatable. As long as it's an ActiveRecord collection, inline crud will work.
|
1001
|
+
|
1002
|
+
- A view partial `app/views/things/_thing.html.haml`:
|
1003
|
+
|
1004
|
+
```ruby
|
1005
|
+
%table.table
|
1006
|
+
%tbody
|
1007
|
+
%tr
|
1008
|
+
%th Title
|
1009
|
+
%td= thing.title
|
1010
|
+
%tr
|
1011
|
+
%th Description
|
1012
|
+
%td= thing.description
|
1013
|
+
```
|
1014
|
+
|
1015
|
+
This file is what rails uses when you call `render(thing)` and what datatables uses for the inline `show` action. It's important that its called `_thing.html`.
|
1016
|
+
|
1017
|
+
- A form partial `app/views/things/_form.html.haml`:
|
1018
|
+
|
1019
|
+
```ruby
|
1020
|
+
= effective_form_with(model: thing) do |f|
|
1021
|
+
= f.text_field :title
|
1022
|
+
= f.text_area :description
|
1023
|
+
= f.submit
|
1024
|
+
```
|
1025
|
+
|
1026
|
+
The `effective_form_with` comes from [effective_bootstrap](https://github.com/code-and-effect/effective_bootstrap) gem and is a drop-in replacement for the newer `form_with` syntax. It's really good, you should use it, but an ordinary `form_with` will work here just fine.
|
1027
|
+
|
1028
|
+
This `_form.html` is an effective gems convention. This file must exist for your resource.
|
1029
|
+
|
1030
|
+
- A resources entry in `config/routes.rb`:
|
1031
|
+
|
1032
|
+
```ruby
|
1033
|
+
Rails.application.routes.draw do
|
1034
|
+
resources :things do
|
1035
|
+
post :approve, on: :member
|
1036
|
+
post :reject, on: :member
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
```
|
1040
|
+
|
1041
|
+
Above we have `resources :things` for the 7 crud actions. And we add two more member actions, which datatables will call `approve!` or `reject!` on thing.
|
1042
|
+
|
1043
|
+
|
1044
|
+
4. Render in the view. Create an `app/views/things/index.html.haml` and call `render_datatable(@datatable, inline: true)` or `render_inline_datatable(@datatable).
|
1045
|
+
|
1046
|
+
```ruby
|
1047
|
+
= render_datatable(@datatable, inline: true)
|
1048
|
+
```
|
1049
|
+
|
1050
|
+
Your datatable should now have New, Show, Edit, Approve and Reject buttons. Click them for inline functionality.
|
1051
|
+
|
1052
|
+
## Troubleshooting Inline
|
1053
|
+
|
1054
|
+
If things aren't working, try the following:
|
1055
|
+
|
1056
|
+
- Double check your javascripts:
|
1057
|
+
|
1058
|
+
```ruby
|
1059
|
+
//= require jquery3
|
1060
|
+
//= require popper
|
1061
|
+
//= require bootstrap
|
1062
|
+
//= require effective_bootstrap
|
1063
|
+
//= require effective_datatables
|
1064
|
+
//= require jquery_ujs
|
1065
|
+
```
|
1066
|
+
|
1067
|
+
The inline functionality requires one of sprockets jquery_ujs, sprockets rails_ujs or webpack @rails/ujs libraries.
|
1068
|
+
|
1069
|
+
- Double check your stylesheets:
|
1070
|
+
|
1071
|
+
```ruby
|
1072
|
+
@import 'bootstrap';
|
1073
|
+
@import 'effective_bootstrap';
|
1074
|
+
@import 'effective_datatables';
|
1075
|
+
```
|
1076
|
+
|
1077
|
+
- Make sure your datatable is not being rendered inside a `<form>...</form>` tag. It will display a javascript console error and won't work.
|
1078
|
+
|
1079
|
+
- Double check your `resources :things` are in `routes.rb` in the same namespace as the controller, and that you have authorization for those actions in `ability.rb` or whatever your `config/initializers/effective_datatables.rb` `config.authorization_method` returns.
|
1080
|
+
|
1081
|
+
## A note on how it works
|
1082
|
+
|
1083
|
+
We use good old `rails_ujs` for all inline actions.
|
1084
|
+
|
1085
|
+
When inline, any of the actions_col actions, as well as the New button, will be changed into `data-remote: true` actions.
|
1086
|
+
|
1087
|
+
The [inline_crud javascript](https://github.com/code-and-effect/effective_datatables/blob/master/app/assets/javascripts/effective_datatables/inline_crud.js.coffee) handles fetching the form, or view partial and expanding/collapsing the appropriate row of the datatable.
|
1088
|
+
|
1089
|
+
When an inline action is clicked, effective_datatables will make an AJAX request to the server, which could be received by an `Effective::CrudController` that will handle the `.js` format, and respond_with the appropriate [rails_ujs .js.erb views](https://github.com/code-and-effect/effective_resources/tree/master/app/views/application).
|
1090
|
+
|
1091
|
+
|
1092
|
+
# Extras
|
934
1093
|
|
935
1094
|
The following commands don't quite fit into the DSL, but are present nonetheless.
|
936
1095
|
|
937
|
-
|
1096
|
+
## simple
|
938
1097
|
|
939
1098
|
To render a simple table, without pagination, sorting, filtering, export buttons, per page, and default visibility:
|
940
1099
|
|
@@ -942,7 +1101,7 @@ To render a simple table, without pagination, sorting, filtering, export buttons
|
|
942
1101
|
<%= render_datatable(@datatable, simple: true) %>
|
943
1102
|
```
|
944
1103
|
|
945
|
-
|
1104
|
+
## index
|
946
1105
|
|
947
1106
|
If you just want to render a datatable and nothing else, there is a quick way to skip creating a view:
|
948
1107
|
|
@@ -956,13 +1115,13 @@ end
|
|
956
1115
|
|
957
1116
|
will render `views/effective/datatables/index` with the assigned datatable.
|
958
1117
|
|
959
|
-
|
1118
|
+
# Advanced Search and Sort
|
960
1119
|
|
961
1120
|
The built-in search and ordering can be overridden on a per-column basis.
|
962
1121
|
|
963
1122
|
The only gotcha here is that you must be aware of the type of collection.
|
964
1123
|
|
965
|
-
|
1124
|
+
## With ActiveRecord collection
|
966
1125
|
|
967
1126
|
In the case of a `col` and an ActiveRecord collection:
|
968
1127
|
|
@@ -994,7 +1153,7 @@ If `column[:sql_column].blank?` then this `col` has fallen back to being a `val`
|
|
994
1153
|
|
995
1154
|
Try adding `col :post_category, sql_column: 'post_categories.title'`
|
996
1155
|
|
997
|
-
|
1156
|
+
## With Array collection
|
998
1157
|
|
999
1158
|
And in the case of a `col` with an Array collection, or any `val`:
|
1000
1159
|
|
@@ -1033,7 +1192,7 @@ end
|
|
1033
1192
|
|
1034
1193
|
The search and sort for each column will be merged together to form the final results.
|
1035
1194
|
|
1036
|
-
|
1195
|
+
## Default search collection
|
1037
1196
|
|
1038
1197
|
When using a `col :comments` type belongs_to or has_many column, a search collection for that class will be loaded.
|
1039
1198
|
|
@@ -1155,6 +1314,22 @@ def finalize(collection)
|
|
1155
1314
|
end
|
1156
1315
|
```
|
1157
1316
|
|
1317
|
+
## Render outside of view
|
1318
|
+
|
1319
|
+
You can render a datatable outside the view.
|
1320
|
+
|
1321
|
+
Anything you pass to the `rendered` method is treated as view/request params.
|
1322
|
+
|
1323
|
+
You can test filters and scopes by passing them here.
|
1324
|
+
|
1325
|
+
```
|
1326
|
+
post = Post.create!
|
1327
|
+
datatable = PostsDatatable.new.rendered(end_date: Time.zone.now+2.days, current_user_id: 1)
|
1328
|
+
|
1329
|
+
assert_equal 1, datatable.collection.count
|
1330
|
+
assert_equal [post], datatable.collection
|
1331
|
+
```
|
1332
|
+
|
1158
1333
|
## Authorization
|
1159
1334
|
|
1160
1335
|
All authorization checks are handled via the config.authorization_method found in the `config/initializers/effective_datatables.rb` file.
|
@@ -16,7 +16,7 @@ flash = (message, status = '') ->
|
|
16
16
|
timeout = $processing.data('timeout')
|
17
17
|
clearTimeout(timeout) if timeout
|
18
18
|
|
19
|
-
delay = (if status == 'danger' then 4000 else
|
19
|
+
delay = (if status == 'danger' then 4000 else 1000)
|
20
20
|
|
21
21
|
$processing.html(message).data('timeout', setTimeout( =>
|
22
22
|
$processing.html('Processing...')
|
@@ -5,6 +5,9 @@ initializeDataTables = (target) ->
|
|
5
5
|
buttons_export_columns = options['buttons_export_columns'] || ':not(.col-actions)'
|
6
6
|
reorder = datatable.data('reorder')
|
7
7
|
|
8
|
+
if datatable.data('inline') && datatable.closest('form').length > 0
|
9
|
+
console.error('inline datatable cannot work inside a form')
|
10
|
+
|
8
11
|
if options['buttons'] == false
|
9
12
|
options['buttons'] = []
|
10
13
|
|
@@ -49,7 +52,7 @@ initializeDataTables = (target) ->
|
|
49
52
|
displayStart: datatable.data('display-start')
|
50
53
|
iDisplayLength: datatable.data('display-length')
|
51
54
|
language: datatable.data('language')
|
52
|
-
lengthMenu: [[5, 10, 25, 50, 100, 250, 500, 9999999], ['5', '10', '25', '50', '100', '250', '500', '
|
55
|
+
lengthMenu: [[5, 10, 25, 50, 100, 250, 500, 9999999], ['5', '10', '25', '50', '100', '250', '500', datatable.data('all-label')]]
|
53
56
|
order: datatable.data('display-order')
|
54
57
|
processing: true
|
55
58
|
responsive: true
|
@@ -77,7 +80,7 @@ initializeDataTables = (target) ->
|
|
77
80
|
filter_name = name.replace('filters[', '').substring(0, name.length-9)
|
78
81
|
|
79
82
|
params['filter'][filter_name] = $form.find("input[name='#{name}']:checked").val()
|
80
|
-
|
83
|
+
|
81
84
|
else if $input.attr('id')
|
82
85
|
filter_name = $input.attr('id').replace('filters_', '')
|
83
86
|
params['filter'][filter_name] = $input.val()
|
@@ -162,7 +165,6 @@ initializeDataTables = (target) ->
|
|
162
165
|
$input.on 'change', (event) -> dataTableSearch($(event.currentTarget))
|
163
166
|
else if $input.is('input')
|
164
167
|
$input.delayedChange ($input) -> dataTableSearch($input)
|
165
|
-
$input.on('paste', -> dataTableSearch($input))
|
166
168
|
|
167
169
|
# Do the actual search
|
168
170
|
dataTableSearch = ($input) -> # This is the function called by a select or input to run the search
|
@@ -172,7 +174,9 @@ initializeDataTables = (target) ->
|
|
172
174
|
|
173
175
|
value = $input.val()
|
174
176
|
|
175
|
-
if
|
177
|
+
if Array.isArray(value)
|
178
|
+
# Nothing
|
179
|
+
else if value.startsWith('"') && value.endsWith('"')
|
176
180
|
value = value.substring(1, value.length-1)
|
177
181
|
else
|
178
182
|
value = $.trim(value)
|
@@ -196,6 +200,7 @@ initializeDataTables = (target) ->
|
|
196
200
|
|
197
201
|
table.addClass('initialized')
|
198
202
|
table.children('thead').trigger('effective-bootstrap:initialize')
|
203
|
+
table.children('thead').find('input[autofocus]').first().focus()
|
199
204
|
true
|
200
205
|
|
201
206
|
destroyDataTables = ->
|
@@ -1,15 +1,34 @@
|
|
1
1
|
# To achieve inline crud, we use rails' data-remote links, and override their behaviour when inside a datatable
|
2
2
|
# This works with EffectiveForm.remote_form which is part of the effective_bootstrap gem.
|
3
3
|
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
# https://github.com/rails/jquery-ujs/wiki/ajax
|
5
|
+
# https://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#rails-ujs-event-handlers
|
6
|
+
|
7
|
+
$(document).on 'ajax:before', '.dataTables_wrapper .col-actions', (event) ->
|
8
|
+
$action = $(event.target)
|
9
|
+
$table = $(event.target).closest('table')
|
8
10
|
|
9
11
|
return true if ('' + $action.data('inline')) == 'false'
|
10
12
|
|
11
|
-
$params = $.param(
|
12
|
-
|
13
|
+
$params = $.param(
|
14
|
+
{
|
15
|
+
_datatable_id: $table.attr('id'),
|
16
|
+
_datatable_attributes: $table.data('attributes'),
|
17
|
+
_datatable_action: true
|
18
|
+
}
|
19
|
+
)
|
20
|
+
|
21
|
+
$action.attr('data-params', $params)
|
22
|
+
true
|
23
|
+
|
24
|
+
# We click the New/Edit/Action button from the col-actions
|
25
|
+
$(document).on 'ajax:beforeSend', '.dataTables_wrapper .col-actions', (event, xhr, settings) ->
|
26
|
+
[xhr, settings] = event.detail if event.detail # rails/ujs
|
27
|
+
|
28
|
+
$action = $(event.target)
|
29
|
+
$table = $(event.target).closest('table')
|
30
|
+
|
31
|
+
return true if ('' + $action.data('inline')) == 'false'
|
13
32
|
|
14
33
|
if $action.closest('.effective-datatables-inline-row,table.dataTable').hasClass('effective-datatables-inline-row')
|
15
34
|
# Nothing.
|
@@ -22,6 +41,8 @@ $(document).on 'ajax:beforeSend', '.dataTables_wrapper .col-actions', (e, xhr, s
|
|
22
41
|
|
23
42
|
# We have either completed the resource action, or fetched the inline form to load.
|
24
43
|
$(document).on 'ajax:success', '.dataTables_wrapper .col-actions', (event, data) ->
|
44
|
+
[data, status, xhr] = event.detail if event.detail # rails/ujs
|
45
|
+
|
25
46
|
$action = $(event.target)
|
26
47
|
|
27
48
|
return true if ('' + $action.data('inline')) == 'false'
|
@@ -54,12 +75,22 @@ $(document).on 'ajax:error', '.dataTables_wrapper', (event) ->
|
|
54
75
|
EffectiveForm.remote_form_flash = ''
|
55
76
|
true
|
56
77
|
|
57
|
-
|
58
|
-
|
59
|
-
|
78
|
+
## Now for the fetched form. We add the datatables params attributes
|
79
|
+
|
80
|
+
$(document).on 'ajax:before', '.dataTables_wrapper .col-inline-form', (event) ->
|
81
|
+
$action = $(event.target)
|
82
|
+
$form = $action.closest('form')
|
83
|
+
$table = $action.closest('table')
|
84
|
+
|
85
|
+
if $form.find('input[name=_datatable_id]').length == 0
|
86
|
+
$('<input>').attr(
|
87
|
+
{type: 'hidden', name: '_datatable_id', value: $table.attr('id')}
|
88
|
+
).appendTo($form)
|
60
89
|
|
61
|
-
|
62
|
-
|
90
|
+
if $form.find('input[name=_datatable_attributes]').length == 0
|
91
|
+
$('<input>').attr(
|
92
|
+
{type: 'hidden', name: '_datatable_attributes', value: $table.data('attributes')}
|
93
|
+
).appendTo($form)
|
63
94
|
|
64
95
|
true
|
65
96
|
|
@@ -92,7 +123,6 @@ beforeNew = ($action) ->
|
|
92
123
|
|
93
124
|
# Append spinner and show Processing
|
94
125
|
$th.append($table.data('spinner'))
|
95
|
-
$table.DataTable().flash()
|
96
126
|
$table.one 'draw.dt', (event) ->
|
97
127
|
$th.find('a').show().siblings('svg').remove() if event.target == event.currentTarget
|
98
128
|
|
@@ -121,7 +151,6 @@ beforeEdit = ($action) ->
|
|
121
151
|
|
122
152
|
# Append spinner and show Processing
|
123
153
|
$td.append($table.data('spinner'))
|
124
|
-
$table.DataTable().flash()
|
125
154
|
|
126
155
|
afterEdit = ($action) ->
|
127
156
|
$tr = $action.closest('tr')
|
@@ -8,7 +8,14 @@ reorder = (event, diff, edit) ->
|
|
8
8
|
return unless oldNode? && newNode?
|
9
9
|
|
10
10
|
url = @context[0].ajax.url.replace('.json', '/reorder.json')
|
11
|
-
|
11
|
+
|
12
|
+
data = {
|
13
|
+
'authenticity_token': $('head').find("meta[name='csrf-token']").attr('content'),
|
14
|
+
'reorder[id]': oldNode.data('reorder-resource'),
|
15
|
+
'reorder[old]': oldNode.val(),
|
16
|
+
'reorder[new]': newNode.val(),
|
17
|
+
'attributes': $table.data('attributes')
|
18
|
+
}
|
12
19
|
|
13
20
|
@context[0].rowreorder.c.enable = false
|
14
21
|
|
@@ -40,4 +47,3 @@ $(document).on 'click', '.dataTables_wrapper a.buttons-reorder', (event) ->
|
|
40
47
|
$table.addClass('reordering')
|
41
48
|
|
42
49
|
column.visible(!column.visible())
|
43
|
-
|
@@ -162,9 +162,7 @@ div.dataTables_scrollFoot > .dataTables_scrollFootInner > table {
|
|
162
162
|
text-align: center;
|
163
163
|
}
|
164
164
|
}
|
165
|
-
|
166
|
-
padding-right: 20px;
|
167
|
-
}
|
165
|
+
|
168
166
|
table.dataTable.table-sm .sorting:before,
|
169
167
|
table.dataTable.table-sm .sorting_asc:before,
|
170
168
|
table.dataTable.table-sm .sorting_desc:before {
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# These are expected to be called by a developer. They are part of the datatables DSL.
|
2
2
|
module EffectiveDatatablesHelper
|
3
|
-
def render_datatable(datatable, input_js: {}, buttons: true, charts: true, entries: true, filters: true, inline: false, pagination: true, search: true, simple: false, sort: true)
|
3
|
+
def render_datatable(datatable, input_js: {}, buttons: true, charts: true, entries: true, filters: true, inline: false, namespace: nil, pagination: true, search: true, simple: false, sort: true)
|
4
4
|
raise 'expected datatable to be present' unless datatable
|
5
5
|
raise 'expected input_js to be a Hash' unless input_js.kind_of?(Hash)
|
6
6
|
|
@@ -10,6 +10,7 @@ module EffectiveDatatablesHelper
|
|
10
10
|
|
11
11
|
datatable.attributes[:inline] = true if inline
|
12
12
|
datatable.attributes[:sortable] = false unless sort
|
13
|
+
datatable.attributes[:namespace] = namespace if namespace
|
13
14
|
|
14
15
|
datatable.view ||= self
|
15
16
|
|
@@ -40,6 +41,7 @@ module EffectiveDatatablesHelper
|
|
40
41
|
id: datatable.to_param,
|
41
42
|
class: html_class,
|
42
43
|
data: {
|
44
|
+
'all-label' => I18n.t('effective_datatables.all'),
|
43
45
|
'attributes' => EffectiveDatatables.encrypt(datatable.attributes),
|
44
46
|
'authenticity-token' => form_authenticity_token,
|
45
47
|
'bulk-actions' => datatable_bulk_actions(datatable),
|
@@ -44,7 +44,7 @@ module EffectiveDatatablesPrivateHelper
|
|
44
44
|
action = { action: :new, class: ['btn', column[:btn_class].presence].compact.join(' '), 'data-remote': true }
|
45
45
|
|
46
46
|
if column[:actions][:new].kind_of?(Hash) # This might be active_record_array_collection?
|
47
|
-
action
|
47
|
+
action.merge!(column[:actions][:new])
|
48
48
|
|
49
49
|
effective_resource = (datatable.effective_resource || datatable.fallback_effective_resource)
|
50
50
|
klass = (column[:actions][:new][:klass] || effective_resource&.klass || datatable.collection_class)
|
@@ -84,7 +84,7 @@ module EffectiveDatatablesPrivateHelper
|
|
84
84
|
collection = opts[:search].delete(:collection)
|
85
85
|
value = datatable.state[:search][name]
|
86
86
|
|
87
|
-
options = opts[:search].
|
87
|
+
options = opts[:search].merge!(
|
88
88
|
name: nil,
|
89
89
|
feedback: false,
|
90
90
|
label: false,
|
@@ -92,24 +92,26 @@ module EffectiveDatatablesPrivateHelper
|
|
92
92
|
data: { 'column-name': name, 'column-index': opts[:index] }
|
93
93
|
)
|
94
94
|
|
95
|
+
options.delete(:fuzzy)
|
96
|
+
|
95
97
|
case options.delete(:as)
|
96
98
|
when :string, :text, :number
|
97
99
|
form.text_field name, options
|
98
100
|
when :date, :datetime
|
99
|
-
form.date_field name, options.reverse_merge(
|
101
|
+
form.date_field name, options.reverse_merge!(
|
100
102
|
date_linked: false, prepend: false, input_js: { useStrict: true, keepInvalid: true }
|
101
103
|
)
|
102
104
|
when :time
|
103
|
-
form.time_field name, options.reverse_merge(
|
105
|
+
form.time_field name, options.reverse_merge!(
|
104
106
|
date_linked: false, prepend: false, input_js: { useStrict: false, keepInvalid: true }
|
105
107
|
)
|
106
108
|
when :select, :boolean
|
107
|
-
options[:input_js] = (options[:input_js] || {}).reverse_merge(placeholder: '')
|
109
|
+
options[:input_js] = (options[:input_js] || {}).reverse_merge!(placeholder: '')
|
108
110
|
|
109
111
|
form.select name, collection, options
|
110
112
|
when :bulk_actions
|
111
113
|
options[:data]['role'] = 'bulk-actions'
|
112
|
-
form.check_box name, options.merge(label: ' ')
|
114
|
+
form.check_box name, options.merge!(label: ' ')
|
113
115
|
end
|
114
116
|
end
|
115
117
|
|
@@ -139,7 +141,7 @@ module EffectiveDatatablesPrivateHelper
|
|
139
141
|
placeholder: (opts[:label] || name.to_s.titleize),
|
140
142
|
value: value,
|
141
143
|
wrapper: { class: 'form-group col-auto'}
|
142
|
-
}.merge(opts.except(:as, :collection, :parse, :value))
|
144
|
+
}.merge!(opts.except(:as, :collection, :parse, :value))
|
143
145
|
|
144
146
|
options[:name] = '' unless datatable._filters_form_required?
|
145
147
|
|
@@ -149,6 +151,8 @@ module EffectiveDatatablesPrivateHelper
|
|
149
151
|
elsif as == :boolean
|
150
152
|
collection ||= [true, false].map { |value| [t("effective_datatables.boolean_#{value}"), value] }
|
151
153
|
form.public_send(:select, name, collection, options) # boolean
|
154
|
+
elsif as == :string
|
155
|
+
form.public_send(:text_field, name, options)
|
152
156
|
elsif form.respond_to?(as)
|
153
157
|
form.public_send(as, name, options) # check_box, text_area
|
154
158
|
else
|
@@ -169,7 +173,7 @@ module EffectiveDatatablesPrivateHelper
|
|
169
173
|
label: false,
|
170
174
|
required: false,
|
171
175
|
wrapper: { class: 'form-group col-auto'}
|
172
|
-
}.merge(opts.except(:checked, :value))
|
176
|
+
}.merge!(opts.except(:checked, :value))
|
173
177
|
|
174
178
|
form.radios :scope, collection, options
|
175
179
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Effective
|
2
2
|
class Datatable
|
3
3
|
attr_reader :attributes # Anything that we initialize our table with. That's it. Can't be changed by state.
|
4
|
-
attr_reader :effective_resource
|
5
4
|
attr_reader :state
|
5
|
+
attr_accessor :effective_resource
|
6
6
|
|
7
7
|
# Hashes of DSL options
|
8
8
|
attr_reader :_aggregates
|
@@ -53,10 +53,36 @@ module Effective
|
|
53
53
|
self.view = view if view
|
54
54
|
end
|
55
55
|
|
56
|
+
def rendered(params = {})
|
57
|
+
raise('expected a hash of params') unless params.kind_of?(Hash)
|
58
|
+
|
59
|
+
view = ApplicationController.renderer.controller.helpers
|
60
|
+
|
61
|
+
view.class_eval do
|
62
|
+
attr_accessor :rendered_params
|
63
|
+
|
64
|
+
def current_user
|
65
|
+
rendered_params[:current_user]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if params[:current_user_id]
|
70
|
+
params[:current_user] = User.find(params[:current_user_id])
|
71
|
+
end
|
72
|
+
|
73
|
+
view.rendered_params = params
|
74
|
+
|
75
|
+
self.view = view
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
56
79
|
# Once the view is assigned, we initialize everything
|
57
80
|
def view=(view)
|
58
81
|
@view = (view.respond_to?(:view_context) ? view.view_context : view)
|
59
|
-
|
82
|
+
|
83
|
+
unless @view.respond_to?(:params) || @view.respond_to?(:rendered_params)
|
84
|
+
raise 'expected view to respond to params'
|
85
|
+
end
|
60
86
|
|
61
87
|
assert_attributes!
|
62
88
|
load_attributes!
|
@@ -10,6 +10,7 @@ module Effective
|
|
10
10
|
|
11
11
|
def load_cookie!
|
12
12
|
return unless EffectiveDatatables.save_state
|
13
|
+
return unless view.respond_to?(:cookies)
|
13
14
|
|
14
15
|
@dt_cookie = view.cookies.signed['_effective_dt']
|
15
16
|
|
@@ -33,6 +34,7 @@ module Effective
|
|
33
34
|
|
34
35
|
def save_cookie!
|
35
36
|
return unless EffectiveDatatables.save_state
|
37
|
+
return unless view.respond_to?(:cookies)
|
36
38
|
|
37
39
|
@dt_cookie ||= []
|
38
40
|
@dt_cookie << [cookie_key, cookie_payload]
|
@@ -16,7 +16,7 @@ module Effective
|
|
16
16
|
next unless state[:visible][name]
|
17
17
|
|
18
18
|
if opts[:partial]
|
19
|
-
locals = { datatable: self, column: opts }.merge(resource_col_locals(opts))
|
19
|
+
locals = { datatable: self, column: opts }.merge!(resource_col_locals(opts))
|
20
20
|
|
21
21
|
rendered[name] = (view.render(
|
22
22
|
partial: opts[:partial],
|
@@ -27,7 +27,6 @@ module Effective
|
|
27
27
|
spacer_template: SPACER_TEMPLATE
|
28
28
|
) || '').split(SPACER)
|
29
29
|
elsif opts[:as] == :actions # This is actions_col and actions_col do .. end, but not actions_col partial: 'something'
|
30
|
-
resources = collection.map { |row| row[opts[:index]] }
|
31
30
|
locals = { datatable: self, column: opts, spacer_template: SPACER_TEMPLATE }
|
32
31
|
|
33
32
|
atts = {
|
@@ -36,16 +35,17 @@ module Effective
|
|
36
35
|
effective_resource: effective_resource,
|
37
36
|
locals: locals,
|
38
37
|
partial: opts[:actions_partial],
|
39
|
-
}.
|
38
|
+
}.merge!(opts[:actions]).tap(&:compact!)
|
40
39
|
|
41
40
|
rendered[name] = if effective_resource.blank?
|
42
|
-
|
41
|
+
collection.map { |row| row[opts[:index]] }.map do |resource|
|
43
42
|
polymorphic_resource = Effective::Resource.new(resource, namespace: controller_namespace)
|
44
43
|
(view.render_resource_actions(resource, atts.merge(effective_resource: polymorphic_resource), &opts[:format]) || '')
|
45
44
|
end
|
46
45
|
else
|
47
|
-
(view.render_resource_actions(
|
46
|
+
(view.render_resource_actions(collection.map { |row| row[opts[:index]] }, atts, &opts[:format]) || '').split(SPACER)
|
48
47
|
end
|
48
|
+
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
@@ -88,9 +88,9 @@ module Effective
|
|
88
88
|
when :currency
|
89
89
|
view.number_to_currency(value)
|
90
90
|
when :date
|
91
|
-
(value.strftime(
|
91
|
+
value.respond_to?(:strftime) ? value.strftime(EffectiveDatatables.format_date) : BLANK
|
92
92
|
when :datetime
|
93
|
-
(value.strftime(
|
93
|
+
value.respond_to?(:strftime) ? value.strftime(EffectiveDatatables.format_datetime) : BLANK
|
94
94
|
when :decimal
|
95
95
|
value
|
96
96
|
when :duration
|
@@ -116,7 +116,7 @@ module Effective
|
|
116
116
|
when Numeric ; view.number_to_currency(value)
|
117
117
|
end
|
118
118
|
when :time
|
119
|
-
(value.strftime(
|
119
|
+
value.respond_to?(:strftime) ? value.strftime(EffectiveDatatables.format_time) : BLANK
|
120
120
|
else
|
121
121
|
value.to_s
|
122
122
|
end
|
@@ -135,7 +135,7 @@ module Effective
|
|
135
135
|
end
|
136
136
|
|
137
137
|
# Merge local options. Special behaviour for remote: false
|
138
|
-
if column[:actions].
|
138
|
+
if column[:actions].present? && column[:actions].kind_of?(Hash)
|
139
139
|
column[:actions].each do |action, opts|
|
140
140
|
next unless opts.kind_of?(Hash)
|
141
141
|
|
@@ -6,18 +6,23 @@ module Effective
|
|
6
6
|
|
7
7
|
def datatables_ajax_request?
|
8
8
|
return @_datatables_ajax_request unless @_datatables_ajax_request.nil?
|
9
|
+
return unless view.respond_to?(:params)
|
9
10
|
|
10
11
|
@_datatables_ajax_request = (view.present? && view.params.key?(:draw) && view.params.key?(:columns))
|
11
12
|
end
|
12
13
|
|
13
14
|
def datatables_inline_request?
|
14
15
|
return @_datatables_inline_request unless @_datatables_inline_request.nil?
|
16
|
+
return unless view.respond_to?(:params)
|
15
17
|
|
16
18
|
@_datatables_inline_request = (view.present? && view.params[:_datatable_id].to_s.split('-')[0...-1] == to_param.split('-')[0...-1])
|
17
19
|
end
|
18
20
|
|
19
21
|
def params
|
20
22
|
return {} unless view.present?
|
23
|
+
return view.rendered_params if view.respond_to?(:rendered_params)
|
24
|
+
return {} unless view.respond_to?(:request)
|
25
|
+
|
21
26
|
@params ||= {}.tap do |params|
|
22
27
|
Rack::Utils.parse_query(URI(view.request.referer.presence || '/').query).each { |k, v| params[k.to_sym] = v }
|
23
28
|
view.params.each { |k, v| params[k.to_sym] = v }
|
@@ -4,7 +4,7 @@ module Effective
|
|
4
4
|
AGGREGATE_SQL_FUNCTIONS = ['ARRAY_AGG(', 'AVG(', 'COUNT(', 'MAX(', 'MIN(', 'STRING_AGG(', 'SUM(']
|
5
5
|
|
6
6
|
def admin_namespace?
|
7
|
-
|
7
|
+
[:admin, 'admin'].include?(controller_namespace)
|
8
8
|
end
|
9
9
|
|
10
10
|
def controller_namespace
|
@@ -31,7 +31,7 @@ module Effective
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def load_effective_resource!
|
34
|
-
@effective_resource
|
34
|
+
@effective_resource ||= if active_record_collection?
|
35
35
|
Effective::Resource.new(collection_class, namespace: controller_namespace)
|
36
36
|
end
|
37
37
|
end
|
@@ -98,9 +98,11 @@ module Effective
|
|
98
98
|
opts[:sql_as_column] = true if (effective_resource.table && effective_resource.column(name).blank?)
|
99
99
|
end
|
100
100
|
|
101
|
-
if opts[:sql_column].present?
|
102
|
-
opts[:
|
101
|
+
if opts[:sql_column].present?
|
102
|
+
sql_column = opts[:sql_column].to_s
|
103
|
+
opts[:sql_as_column] = true if AGGREGATE_SQL_FUNCTIONS.any? { |str| sql_column.start_with?(str) }
|
103
104
|
end
|
105
|
+
|
104
106
|
end
|
105
107
|
end
|
106
108
|
|
@@ -200,6 +202,7 @@ module Effective
|
|
200
202
|
|
201
203
|
def load_resource_belongs_tos!
|
202
204
|
return unless active_record_collection?
|
205
|
+
return unless @_collection_apply_belongs_to
|
203
206
|
|
204
207
|
changed = attributes.select do |attribute, value|
|
205
208
|
attribute = attribute.to_s
|
@@ -210,7 +213,7 @@ module Effective
|
|
210
213
|
next unless columns[associated]
|
211
214
|
|
212
215
|
if columns[associated][:as] == :belongs_to
|
213
|
-
|
216
|
+
unless @_collection.where_values_hash.include?(attribute)
|
214
217
|
@_collection = @_collection.where(attribute => value)
|
215
218
|
end
|
216
219
|
|
@@ -218,10 +221,8 @@ module Effective
|
|
218
221
|
elsif columns[associated][:as] == :belongs_to_polymorphic
|
219
222
|
associated_type = attributes["#{associated}_type".to_sym] || raise("Expected #{associated}_type attribute to be present when #{associated}_id is present on a polymorphic belongs to")
|
220
223
|
|
221
|
-
|
222
|
-
|
223
|
-
@_collection = @_collection.where(attribute => value).where("#{associated}_type" => associated_type)
|
224
|
-
end
|
224
|
+
unless @_collection.where_values_hash.include?(attribute) || @_collection.where_values_hash.include?("#{associated}_type")
|
225
|
+
@_collection = @_collection.where(attribute => value).where("#{associated}_type" => associated_type)
|
225
226
|
end
|
226
227
|
|
227
228
|
columns.delete(associated)
|
@@ -198,7 +198,7 @@ module Effective
|
|
198
198
|
def parse_filter_value(filter, value)
|
199
199
|
return filter[:parse].call(value) if filter[:parse]
|
200
200
|
return nil if value.blank? && !filter[:required]
|
201
|
-
Effective::Attribute.new(filter[:value]).parse(value, name: filter[:name])
|
201
|
+
Effective::Attribute.new(filter[:as] || filter[:value] || :string).parse(value, name: filter[:name])
|
202
202
|
end
|
203
203
|
|
204
204
|
def cookie_state_params
|
@@ -1,4 +1,4 @@
|
|
1
1
|
- Array(resource.public_send(column[:name])).each do |file|
|
2
2
|
.col-resource_item
|
3
3
|
- title = [file.content_type, number_to_human_size(file.byte_size)].map(&:presence).compact
|
4
|
-
= link_to(file.filename, url_for(file), title: title)
|
4
|
+
= link_to(file.filename, url_for(file), title: title, target: '_blank')
|
@@ -1,8 +1,9 @@
|
|
1
1
|
.btn-group.buttons-bulk-actions
|
2
2
|
%button.btn.btn-link.btn-sm.dropdown-toggle{'type': 'button', 'data-toggle': 'dropdown', 'aria-haspopup': true, 'aria-expanded': false, 'disabled': 'disabled'}
|
3
|
-
|
3
|
+
= t('effective_datatables.bulk_actions')
|
4
4
|
.dropdown-menu
|
5
5
|
- if datatable._bulk_actions.present?
|
6
6
|
= datatable._bulk_actions.join.html_safe
|
7
7
|
- else
|
8
|
-
%a.dropdown-item{href: '#'}
|
8
|
+
%a.dropdown-item{href: '#'}
|
9
|
+
= t('effective_datatables.no_bulk_actions')
|
@@ -35,8 +35,12 @@ EffectiveDatatables.setup do |config|
|
|
35
35
|
config.save_state = true
|
36
36
|
|
37
37
|
# Configure the _effective_dt cookie.
|
38
|
-
config.cookie_max_size =
|
38
|
+
config.cookie_max_size = 1500 # String size. Final byte size is about 1.5 times bigger, after rails signs it
|
39
39
|
config.cookie_domain = :all # Should usually be :all
|
40
40
|
config.cookie_tld_length = nil # Leave nil to autodetect, or set to probably 2
|
41
41
|
|
42
|
+
# Date formatting
|
43
|
+
config.format_datetime = '%F %H:%M'
|
44
|
+
config.format_date = '%F'
|
45
|
+
config.format_time = '%H:%M'
|
42
46
|
end
|
data/config/locales/en.yml
CHANGED
data/config/locales/es.yml
CHANGED
data/config/locales/nl.yml
CHANGED
data/lib/effective_datatables.rb
CHANGED
@@ -16,6 +16,10 @@ module EffectiveDatatables
|
|
16
16
|
mattr_accessor :cookie_domain
|
17
17
|
mattr_accessor :cookie_tld_length
|
18
18
|
|
19
|
+
mattr_accessor :format_datetime
|
20
|
+
mattr_accessor :format_date
|
21
|
+
mattr_accessor :format_time
|
22
|
+
|
19
23
|
mattr_accessor :debug
|
20
24
|
|
21
25
|
alias_method :max_cookie_size, :cookie_max_size
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_datatables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.8.
|
4
|
+
version: 4.8.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -129,11 +129,9 @@ files:
|
|
129
129
|
- app/assets/stylesheets/effective_datatables.scss
|
130
130
|
- app/assets/stylesheets/effective_datatables/_overrides.bootstrap4.scss
|
131
131
|
- app/controllers/effective/datatables_controller.rb
|
132
|
-
- app/datatables/effective_style_guide_datatable.rb
|
133
132
|
- app/helpers/effective_datatables_controller_helper.rb
|
134
133
|
- app/helpers/effective_datatables_helper.rb
|
135
134
|
- app/helpers/effective_datatables_private_helper.rb
|
136
|
-
- app/models/effective/access_denied.rb
|
137
135
|
- app/models/effective/datatable.rb
|
138
136
|
- app/models/effective/datatable_column.rb
|
139
137
|
- app/models/effective/datatable_column_tool.rb
|
@@ -163,7 +161,6 @@ files:
|
|
163
161
|
- app/views/effective/datatables/_resource_column.html.haml
|
164
162
|
- app/views/effective/datatables/_spacer_template.html
|
165
163
|
- app/views/effective/datatables/index.html.haml
|
166
|
-
- app/views/effective/style_guide/_effective_datatables.html.haml
|
167
164
|
- config/effective_datatables.rb
|
168
165
|
- config/locales/en.yml
|
169
166
|
- config/locales/es.yml
|
@@ -178,7 +175,7 @@ homepage: https://github.com/code-and-effect/effective_datatables
|
|
178
175
|
licenses:
|
179
176
|
- MIT
|
180
177
|
metadata: {}
|
181
|
-
post_install_message:
|
178
|
+
post_install_message:
|
182
179
|
rdoc_options: []
|
183
180
|
require_paths:
|
184
181
|
- lib
|
@@ -193,8 +190,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
193
190
|
- !ruby/object:Gem::Version
|
194
191
|
version: '0'
|
195
192
|
requirements: []
|
196
|
-
rubygems_version: 3.
|
197
|
-
signing_key:
|
193
|
+
rubygems_version: 3.1.2
|
194
|
+
signing_key:
|
198
195
|
specification_version: 4
|
199
196
|
summary: Uniquely powerful server-side searching, sorting and filtering of any ActiveRecord
|
200
197
|
or Array collection as well as post-rendered content displayed as a frontend jQuery
|
@@ -1,45 +0,0 @@
|
|
1
|
-
class EffectiveStyleGuideDatatable < Effective::Datatable
|
2
|
-
datatable do
|
3
|
-
length 10
|
4
|
-
|
5
|
-
col :id
|
6
|
-
col :material, search: { collection: ['Stainless Steel', 'Copper', 'Cast Iron', 'Composite'] }
|
7
|
-
col :bowl, search: { collection: ['Single Bowl', 'Double Bowl', 'Triple Bowl'] }
|
8
|
-
col :name
|
9
|
-
col :date, as: :date
|
10
|
-
end
|
11
|
-
|
12
|
-
# Set the permission check to the same as Effective::StyleGuide
|
13
|
-
def collection_class
|
14
|
-
defined?(Effective::StyleGuide) ? Effective::StyleGuide : super
|
15
|
-
end
|
16
|
-
|
17
|
-
collection do
|
18
|
-
now = Time.zone.now
|
19
|
-
[
|
20
|
-
[1, 'Stainless Steel', 'Single Bowl', 'KOHLER Staccato', (now + 1.day)],
|
21
|
-
[2, 'Stainless Steel', 'Double Bowl', 'KOHLER Vault Undercounter', (now + 1.day)],
|
22
|
-
[3, 'Stainless Steel', 'Triple Bowl', 'KRAUS All-In-One', (now + 1.day)],
|
23
|
-
[4, 'Stainless Steel', 'Single Bowl', 'KOHLER Vault Dual Mount', (now + 1.day)],
|
24
|
-
[5, 'Stainless Steel', 'Single Bowl', 'KRAUS All-In-One Undermount', (now + 2.days)],
|
25
|
-
[6, 'Stainless Steel', 'Double Bowl', 'Glacier Bay All-in-One', (now + 2.days)],
|
26
|
-
[7, 'Stainless Steel', 'Single Bowl', 'Elkay Neptune', (now + 2.days)],
|
27
|
-
[8, 'Copper', 'Single Bowl', 'ECOSINKS Apron Front Dual Mount', (now + 2.days)],
|
28
|
-
[9, 'Copper', 'Double Bowl', 'ECOSINKS Dual Mount Front Hammered', (now + 2.days)],
|
29
|
-
[10, 'Copper', 'Triple Bowl', 'Glarier Bay Undermount', (now + 3.days)],
|
30
|
-
[11, 'Copper', 'Single Bowl', 'Whitehaus Undermount', (now + 3.days)],
|
31
|
-
[12, 'Copper', 'Double Bowl', 'Belle Foret Apron Front', (now + 3.days)],
|
32
|
-
[13, 'Copper', 'Double Bowl', 'Pegasus Dual Mount', (now + 3.days)],
|
33
|
-
[14, 'Cast Iron', 'Double Bowl', 'KOHLER Whitehaven', (now + 3.days)],
|
34
|
-
[15, 'Cast Iron', 'Triple Bowl', 'KOHLER Hartland', (now + 3.days)],
|
35
|
-
[16, 'Cast Iron', 'Single Bowl', 'KOHLER Cape Dory Undercounter', (now + 4.days)],
|
36
|
-
[17, 'Cast Iron', 'Double Bowl', 'KOLER Bakersfield', (now + 4.days)],
|
37
|
-
[18, 'Cast Iron', 'Double Bowl', 'American Standard Offset', (now + 4.days)],
|
38
|
-
[19, 'Cast Iron', 'Single Bowl', 'Brookfield Top', (now + 4.days)],
|
39
|
-
[20, 'Composite', 'Single Bowl', 'Blanco Diamond Undermount', (now + 5.days)],
|
40
|
-
[21, 'Composite', 'Double Bowl', 'Mont Blanc Waterbrook', (now + 5.days)],
|
41
|
-
[22, 'Composite', 'Triple Bowl', 'Pegasus Triple Mount', (now + 5.days)],
|
42
|
-
[23, 'Composite', 'Single Bowl', 'Swanstone Dual Mount', (now + 5.days)]
|
43
|
-
]
|
44
|
-
end
|
45
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
unless defined?(Effective::AccessDenied)
|
2
|
-
module Effective
|
3
|
-
class AccessDenied < StandardError
|
4
|
-
attr_reader :action, :subject
|
5
|
-
|
6
|
-
def initialize(message = nil, action = nil, subject = nil)
|
7
|
-
@message = message
|
8
|
-
@action = action
|
9
|
-
@subject = subject
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_s
|
13
|
-
@message || I18n.t(:'unauthorized.default', :default => 'Access Denied')
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1 +0,0 @@
|
|
1
|
-
= render_datatable(EffectiveStyleGuideDatatable.new)
|