effective_datatables 4.7.16 → 4.15.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +278 -24
  4. data/app/assets/javascripts/effective_datatables/bulk_actions.js.coffee +32 -9
  5. data/app/assets/javascripts/effective_datatables/download.js.coffee +10 -0
  6. data/app/assets/javascripts/effective_datatables/flash.js.coffee +1 -1
  7. data/app/assets/javascripts/effective_datatables/initialize.js.coffee +22 -13
  8. data/app/assets/javascripts/effective_datatables/inline_crud.js.coffee +42 -13
  9. data/app/assets/javascripts/effective_datatables/reorder.js.coffee +8 -2
  10. data/app/assets/javascripts/effective_datatables/reset.js.coffee +23 -2
  11. data/app/assets/javascripts/vendor/jquery.delayedChange.js +1 -2
  12. data/app/assets/stylesheets/dataTables/dataTables.bootstrap4.scss +1 -3
  13. data/app/controllers/effective/datatables_controller.rb +34 -0
  14. data/app/helpers/effective_datatables_controller_helper.rb +2 -0
  15. data/app/helpers/effective_datatables_helper.rb +22 -6
  16. data/app/helpers/effective_datatables_private_helper.rb +30 -20
  17. data/app/models/effective/datatable.rb +57 -4
  18. data/app/models/effective/datatable_column.rb +2 -0
  19. data/app/models/effective/datatable_column_tool.rb +5 -3
  20. data/app/models/effective/datatable_dsl_tool.rb +7 -5
  21. data/app/models/effective/datatable_value_tool.rb +9 -8
  22. data/app/models/effective/effective_datatable/attributes.rb +21 -0
  23. data/app/models/effective/effective_datatable/collection.rb +3 -1
  24. data/app/models/effective/effective_datatable/compute.rb +11 -7
  25. data/app/models/effective/effective_datatable/cookie.rb +6 -0
  26. data/app/models/effective/effective_datatable/csv.rb +71 -0
  27. data/app/models/effective/effective_datatable/dsl/bulk_actions.rb +3 -1
  28. data/app/models/effective/effective_datatable/dsl/charts.rb +2 -0
  29. data/app/models/effective/effective_datatable/dsl/datatable.rb +20 -6
  30. data/app/models/effective/effective_datatable/dsl/filters.rb +3 -1
  31. data/app/models/effective/effective_datatable/dsl.rb +7 -3
  32. data/app/models/effective/effective_datatable/format.rb +52 -24
  33. data/app/models/effective/effective_datatable/hooks.rb +2 -0
  34. data/app/models/effective/effective_datatable/params.rb +9 -2
  35. data/app/models/effective/effective_datatable/resource.rb +26 -13
  36. data/app/models/effective/effective_datatable/state.rb +4 -2
  37. data/app/views/effective/datatables/_active_storage_column.html.haml +4 -0
  38. data/app/views/effective/datatables/_bulk_actions_dropdown.html.haml +3 -2
  39. data/app/views/effective/datatables/_buttons.html.haml +14 -0
  40. data/config/effective_datatables.rb +8 -1
  41. data/config/locales/en.yml +4 -1
  42. data/config/locales/es.yml +4 -1
  43. data/config/locales/nl.yml +4 -1
  44. data/config/routes.rb +1 -0
  45. data/lib/effective_datatables/engine.rb +6 -4
  46. data/lib/effective_datatables/version.rb +1 -1
  47. data/lib/effective_datatables.rb +5 -0
  48. metadata +11 -10
  49. data/app/datatables/effective_style_guide_datatable.rb +0 -47
  50. data/app/models/effective/access_denied.rb +0 -17
  51. 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: '0782f0833ce459c31e724f049f4819e6276c4464c85822d9140f254747cde9cc'
4
- data.tar.gz: 542aeb3d78e19c1dc8dff1adf8b7b6965c3a2b7d1a906c26560a42013a8c0e66
3
+ metadata.gz: 97162d77c01d7bc35d4d9bbda9b7f61d815628c7ded32c1c9c8a0a16e630c42f
4
+ data.tar.gz: 2bd27055dd9822c798373d0f073dc049ce471401cef071d50320a02f03d5c491
5
5
  SHA512:
6
- metadata.gz: 90302ac7327123ce9e0a2520d70030ec8eb905c508bb15329641ae90210b5a7018723076b2c421150e289c7e2cc4b90193b8076d6bc5a5cb239c0864b4eaed5b
7
- data.tar.gz: 2ebeed000e1e53e6948d7832c750322177c3c13db53ce61f2d0049ece7589b81499862b04ea760963a8e8c70228b7920efc3df6924980a58d945c4ac632ee497
6
+ metadata.gz: b7a59f37ce683bfb17e6b75715dee88a9125d26380988d7e9db9fd2c7f818e00235ee7418680d3dad90dabcf3c4e991bfb81ca32b7a4b80556573bf722a7e49f
7
+ data.tar.gz: 11d06c3f01185c4d92248bb40a32e78376eca5ae6bbbbabd5997a9a4a0a52f4d6ce1fb70bca5b6c50aa4ad60fb747b7060b3aaaf39bae0fbb5d51420cfbe9cef
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2019 Code and Effect Inc.
1
+ Copyright 2021 Code and Effect Inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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 Google charts.
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
 
@@ -46,6 +46,7 @@ Please check out [Effective Datatables 3.x](https://github.com/code-and-effect/e
46
46
  * [order](#order)
47
47
  * [reorder](#reorder)
48
48
  * [aggregate](#aggregate)
49
+ * [download](#download)
49
50
  * [filters](#filters)
50
51
  * [scope](#scope)
51
52
  * [filter](#filter)
@@ -54,7 +55,8 @@ Please check out [Effective Datatables 3.x](https://github.com/code-and-effect/e
54
55
  * [bulk_action](#bulk_action_divider)
55
56
  * [bulk_download](#bulk_download)
56
57
  * [bulk_action_content](#bulk_action_content)
57
- * [charts](#charts)
58
+ * [Charts](#charts)
59
+ * [Inline](#inline)
58
60
  * [Extras](#extras)
59
61
  * [Advanced Search and Sort](#advanced-search-and-sort)
60
62
  * [Addtional Functionality](#additional-functionality)
@@ -196,6 +198,13 @@ class PostsDatatable < Effective::Datatable
196
198
  # POSTs to the given url with params[:ids], an Array of ids for all selected rows
197
199
  # These actions are assumed to change the underlying collection
198
200
  bulk_action 'Approve all', bulk_approve_posts_path, data: { confirm: 'Approve all selected posts?' }
201
+ # GETs to the given url. Pass the ids via cookie, encoded in url, or LocalStorage.
202
+ # These actions are assumed to redirect the user to some other page.
203
+ bulk_action 'Action 1 | ids encoded in params', action_1_posts_path, data: { method: :get }
204
+
205
+ bulk_action 'Action 2 | ids stored in _ids_ field in local storage', action_2_posts_path, data: { 'payload-mode' => 'local-storage', method: :get }
206
+
207
+ bulk_action 'Action 3 | ids stored in _ids_ field in a cookie', action_3_posts_path, data: { 'payload-mode' => 'cookie', method: :get }
199
208
  bulk_action_divider
200
209
  bulk_action 'Destroy all', bulk_destroy_posts_path, data: { confirm: 'Destroy all selected posts?' }
201
210
  end
@@ -453,7 +462,7 @@ The `datatable do ... end` block configures a table of data.
453
462
 
454
463
  Initialize the datatable in your controller or view, `@datatable = PostsDatatable.new(self)`, and render it in your view `<%= render_datatable(@datatable) %>`
455
464
 
456
- ### col
465
+ ## col
457
466
 
458
467
  This is the main DSL method that you will interact with.
459
468
 
@@ -526,7 +535,7 @@ You can also use the joined syntax, `col 'user.email'` to create a column for ju
526
535
 
527
536
  This feature is only working with `belongs_to` and you need to add the `.joins(:user)` to the collection do ... end block yourself.
528
537
 
529
- ### val
538
+ ## val
530
539
 
531
540
  Shorthand for value, this command also creates a column on the datatable.
532
541
 
@@ -548,7 +557,7 @@ This is implemented as a full Array search/sort and is much slower for large dat
548
557
 
549
558
  The `.format do ... end` block can then be used to apply custom formatting.
550
559
 
551
- ### bulk_actions_col
560
+ ## bulk_actions_col
552
561
 
553
562
  Creates a column of checkboxes for use with the `bulk_actions` section.
554
563
 
@@ -558,7 +567,7 @@ Use these checkboxes to select all / none / one or more rows for the `bulk_actio
558
567
 
559
568
  You can only have one `bulk_actions_col` per datatable.
560
569
 
561
- ### actions_col
570
+ ## actions_col
562
571
 
563
572
  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
573
 
@@ -596,7 +605,13 @@ Any `data-remote` actions will be hijacked and performed as inline ajax by datat
596
605
 
597
606
  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
607
 
599
- ### length
608
+ If the automatic actions_col aren't being displayed, try setting the namespace directly when calling the table
609
+
610
+ ```
611
+ MyApp::UsersTable.new(namespace: :my_app)
612
+ ```
613
+
614
+ ## length
600
615
 
601
616
  Sets the default number of rows per page. Valid lengths are `5`, `10`, `25`, `50`, `100`, `250`, `500`, `:all`
602
617
 
@@ -606,7 +621,7 @@ When not specified, effective_datatables uses the default as per the `config/ini
606
621
  length 100
607
622
  ```
608
623
 
609
- ### order
624
+ ## order
610
625
 
611
626
  Sets the default order of table rows. The first argument is the column, the second the direction.
612
627
 
@@ -618,7 +633,7 @@ When not specified, effective_datatables will sort by the first defined column.
618
633
  order :created_at, :asc|:desc
619
634
  ```
620
635
 
621
- ### reorder
636
+ ## reorder
622
637
 
623
638
  Enables drag-and-drop row re-ordering.
624
639
 
@@ -636,7 +651,7 @@ reorder :position
636
651
 
637
652
  Using `reorder` will sort the collection by this field and disable all other column sorting.
638
653
 
639
- ### aggregate
654
+ ## aggregate
640
655
 
641
656
  The `aggregate` command inserts a row in the table's `tfoot`.
642
657
 
@@ -673,6 +688,30 @@ end.aggregate { |values, column| distance_of_time_in_words(values.min, values.ma
673
688
 
674
689
  In the above example, `values` is an Array containing all row's values for one column at a time.
675
690
 
691
+ ## download
692
+
693
+ Add a Download button which streams a CSV file containing all rows and columns in the table's collection, ignoring any search, sort or filtering.
694
+
695
+ This is an opt-in feature.
696
+
697
+ To enable, please set `config.download = true` in your `config/initializers/effective_datatables.rb` file.
698
+
699
+ Once enabled, you can disable it on an individual table by:
700
+
701
+ ```ruby
702
+ datatable do
703
+ download false
704
+ end
705
+ ```
706
+
707
+ and you can exclude individual columns from being rendered on the CSV export
708
+
709
+ ```ruby
710
+ col :first_name, csv: false
711
+ ```
712
+
713
+ The column will still appear in the export, but the contents will be blank.
714
+
676
715
  ## filters
677
716
 
678
717
  Creates a single form with fields for each `filter` and a single radio input field for all `scopes`.
@@ -681,7 +720,7 @@ The form is submitted by an AJAX POST action, or, in some advanced circumstances
681
720
 
682
721
  Initialize the datatable in your controller or view, `@datatable = PostsDatatable.new(self)`, and render its filters anywhere with `<%= render_datatable_filters(@datatable) %>`.
683
722
 
684
- ### scope
723
+ ## scope
685
724
 
686
725
  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
726
 
@@ -705,7 +744,7 @@ class Post < ApplicationRecord | ActiveRecord::Base
705
744
  end
706
745
  ```
707
746
 
708
- ### filter
747
+ ## filter
709
748
 
710
749
  Each filter has a name and a default/fallback value. If the form is submitted blank, the default values are used.
711
750
 
@@ -758,7 +797,7 @@ Creates a single dropdown menu with a link to each action, download or content.
758
797
 
759
798
  Along with this section, you must put a `bulk_actions_col` somewhere in your `datatable do ... end` section.
760
799
 
761
- ### bulk_action
800
+ ## bulk_action
762
801
 
763
802
  Creates a link that becomes clickable when one or more checkbox/rows are selected as per the `bulk_actions_col` column.
764
803
 
@@ -771,6 +810,12 @@ You can also specify `data-method: :get` to instead make a `GET` request with th
771
810
  ```ruby
772
811
  bulk_actions do
773
812
  bulk_action 'Approve all', bulk_approve_posts_path, data: { confirm: 'Approve all selected posts?' }
813
+
814
+ bulk_action 'Action 1 | ids encoded in params', action_1_posts_path, data: { method: :get }
815
+
816
+ bulk_action 'Action 2 | ids stored in _ids_ field in local storage', action_2_posts_path, data: { 'payload-mode' => 'local-storage', method: :get }
817
+
818
+ bulk_action 'Action 3 | ids stored in _ids_ field in a cookie', action_3_posts_path, data: { 'payload-mode' => 'cookie', method: :get }
774
819
  end
775
820
  ```
776
821
 
@@ -780,6 +825,9 @@ In your `routes` file:
780
825
  resources :posts do
781
826
  collection do
782
827
  post :bulk_approve
828
+ get :action_1
829
+ get :action_2
830
+ get :action_3
783
831
  end
784
832
  end
785
833
  ```
@@ -798,6 +846,22 @@ def bulk_approve
798
846
  render json: { status: 500, message: 'An error occured while approving a post.' }
799
847
  end
800
848
  end
849
+
850
+ def action_1
851
+ @posts = Post.where(id: params[:ids])
852
+
853
+ render :some_partial
854
+ end
855
+
856
+ def action_2
857
+ @posts = Post.where(id: cookies[:ids].split(','))
858
+
859
+ render :some_partial
860
+ end
861
+
862
+ def action_3
863
+ render :some_partial # and get ids via JS: localStorage.getItem('ids');
864
+ end
801
865
  ```
802
866
 
803
867
  or if using [effective_resources](https://github.com/code-and-effect/effective_resources):
@@ -814,11 +878,11 @@ def approve!
814
878
  end
815
879
  ```
816
880
 
817
- ### bulk_action_divider
881
+ ## bulk_action_divider
818
882
 
819
883
  Inserts a menu divider `<li class='divider' role='separator'></li>`
820
884
 
821
- ### bulk_download
885
+ ## bulk_download
822
886
 
823
887
  So it turns out there are some http issues with using an AJAX action to download a file.
824
888
 
@@ -859,7 +923,7 @@ def bulk_export_report
859
923
  end
860
924
  ```
861
925
 
862
- ### bulk_action_content
926
+ ## bulk_action_content
863
927
 
864
928
  Blindly inserts content into the dropdown.
865
929
 
@@ -873,12 +937,16 @@ end
873
937
 
874
938
  Don't actually use this.
875
939
 
876
- ## charts
940
+ # Charts
877
941
 
878
942
  Create a [Google Chart](https://developers.google.com/chart/interactive/docs/quick_start) based on your searched collection, filters and attributes.
879
943
 
880
944
  No javascript required. Just use the `chart do ... end` block and return an Array of Arrays.
881
945
 
946
+ The first collection, `collection` is the raw results as returned from the `collection do` block.
947
+
948
+ The second collection, `searched_collection` is the results after the table's search columns have been applied, but irregardless of pagination.
949
+
882
950
  ```ruby
883
951
  charts do
884
952
  chart :breakfast, 'BarChart' do |collection|
@@ -894,6 +962,18 @@ charts do
894
962
  [date.strftime('%F'), posts.length]
895
963
  end
896
964
  end
965
+
966
+ chart :posts_per_user, 'ColumnChart' do |collection, searched_collection|
967
+ measured_posts = if search.present?
968
+ ["Posts with #{search.map { |k, v| k.to_s + ' ' + v.to_s }.join(',')}", searched_collection.length]
969
+ else
970
+ ['All Posts', collection.length]
971
+ end
972
+
973
+ [['Posts', 'Count'], measured_posts] +
974
+ searched_collection.group_by(&:user).map { |user, posts| [user.last_name, posts.length] }
975
+ end
976
+
897
977
  end
898
978
  ```
899
979
 
@@ -914,11 +994,169 @@ All options passed to `chart` are used to initialize the chart javascript.
914
994
 
915
995
  By default, the only package that is loaded is `corechart`, see the `config/initializers/effective_datatables.rb` file to add more packages.
916
996
 
917
- ## Extras
997
+ # Inline
998
+
999
+ Any datatable can be used as an inline datatable, to create, update and destroy resources without leaving the current page.
1000
+
1001
+ 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)`.
1002
+
1003
+ 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)
1004
+ (only the `thing` data model and `things_datatable` are being used inline)
1005
+
1006
+ 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.
1007
+
1008
+ Here is how I build rails models for inline datatable CRUD operations:
1009
+
1010
+ 1. Create a new model file `app/models/thing.rb`:
1011
+
1012
+ ```ruby
1013
+ class Thing < ApplicationRecord
1014
+ belongs_to :user
1015
+
1016
+ effective_resource do
1017
+ title :string
1018
+ description :text
1019
+ timestamps
1020
+ end
1021
+
1022
+ scope :deep, -> { includes(:user) }
1023
+ scope :sorted, -> { order(:title) }
1024
+
1025
+ def to_s
1026
+ title
1027
+ end
1028
+ end
1029
+ ```
1030
+
1031
+ 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.
1032
+
1033
+ 2. Generate a migration. Run `rails generate effective:migration things` to create a migration based off the model file then `rails db:migrate`.
1034
+
1035
+ 3. Scaffold the rest. Run `rails generate effective:scaffold_controller things` which will create:
1036
+
1037
+ - A controller `app/controllers/things_controller.rb`:
1038
+
1039
+ ```ruby
1040
+ class ThingsController < ApplicationController
1041
+ include Effective::CrudController
1042
+ end
1043
+ ```
1044
+
1045
+ 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.
1046
+
1047
+ - A datatable `app/datatables/things_datatable.rb`:
1048
+
1049
+ ```ruby
1050
+ class ThingsDatatable < Effective::Datatable
1051
+ datatable do
1052
+ col :title
1053
+ col :description
1054
+ actions_col
1055
+ end
1056
+
1057
+ collection do
1058
+ Thing.deep.all
1059
+ end
1060
+ end
1061
+ ```
1062
+
1063
+ This is an ordinary datatable. As long as it's an ActiveRecord collection, inline crud will work.
1064
+
1065
+ - A view partial `app/views/things/_thing.html.haml`:
1066
+
1067
+ ```ruby
1068
+ %table.table
1069
+ %tbody
1070
+ %tr
1071
+ %th Title
1072
+ %td= thing.title
1073
+ %tr
1074
+ %th Description
1075
+ %td= thing.description
1076
+ ```
1077
+
1078
+ 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`.
1079
+
1080
+ - A form partial `app/views/things/_form.html.haml`:
1081
+
1082
+ ```ruby
1083
+ = effective_form_with(model: thing) do |f|
1084
+ = f.text_field :title
1085
+ = f.text_area :description
1086
+ = f.submit
1087
+ ```
1088
+
1089
+ 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.
1090
+
1091
+ This `_form.html` is an effective gems convention. This file must exist for your resource.
1092
+
1093
+ - A resources entry in `config/routes.rb`:
1094
+
1095
+ ```ruby
1096
+ Rails.application.routes.draw do
1097
+ resources :things do
1098
+ post :approve, on: :member
1099
+ post :reject, on: :member
1100
+ end
1101
+ end
1102
+ ```
1103
+
1104
+ 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.
1105
+
1106
+
1107
+ 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).
1108
+
1109
+ ```ruby
1110
+ = render_datatable(@datatable, inline: true)
1111
+ ```
1112
+
1113
+ Your datatable should now have New, Show, Edit, Approve and Reject buttons. Click them for inline functionality.
1114
+
1115
+ ## Troubleshooting Inline
1116
+
1117
+ If things aren't working, try the following:
1118
+
1119
+ - Double check your javascripts:
1120
+
1121
+ ```ruby
1122
+ //= require jquery3
1123
+ //= require popper
1124
+ //= require bootstrap
1125
+ //= require effective_bootstrap
1126
+ //= require effective_datatables
1127
+ //= require jquery_ujs
1128
+ ```
1129
+
1130
+ The inline functionality requires one of sprockets jquery_ujs, sprockets rails_ujs or webpack @rails/ujs libraries.
1131
+
1132
+ - Double check your stylesheets:
1133
+
1134
+ ```ruby
1135
+ @import 'bootstrap';
1136
+ @import 'effective_bootstrap';
1137
+ @import 'effective_datatables';
1138
+ ```
1139
+
1140
+ - Make sure your datatable is not being rendered inside a `<form>...</form>` tag. It will display a javascript console error and won't work.
1141
+
1142
+ - 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.
1143
+
1144
+ ## A note on how it works
1145
+
1146
+ We use good old `rails_ujs` for all inline actions.
1147
+
1148
+ When inline, any of the actions_col actions, as well as the New button, will be changed into `data-remote: true` actions.
1149
+
1150
+ 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.
1151
+
1152
+ 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).
1153
+
1154
+
1155
+ # Extras
918
1156
 
919
1157
  The following commands don't quite fit into the DSL, but are present nonetheless.
920
1158
 
921
- ### simple
1159
+ ## simple
922
1160
 
923
1161
  To render a simple table, without pagination, sorting, filtering, export buttons, per page, and default visibility:
924
1162
 
@@ -926,7 +1164,7 @@ To render a simple table, without pagination, sorting, filtering, export buttons
926
1164
  <%= render_datatable(@datatable, simple: true) %>
927
1165
  ```
928
1166
 
929
- ### index
1167
+ ## index
930
1168
 
931
1169
  If you just want to render a datatable and nothing else, there is a quick way to skip creating a view:
932
1170
 
@@ -940,13 +1178,13 @@ end
940
1178
 
941
1179
  will render `views/effective/datatables/index` with the assigned datatable.
942
1180
 
943
- ## Advanced Search and Sort
1181
+ # Advanced Search and Sort
944
1182
 
945
1183
  The built-in search and ordering can be overridden on a per-column basis.
946
1184
 
947
1185
  The only gotcha here is that you must be aware of the type of collection.
948
1186
 
949
- ### With ActiveRecord collection
1187
+ ## With ActiveRecord collection
950
1188
 
951
1189
  In the case of a `col` and an ActiveRecord collection:
952
1190
 
@@ -978,7 +1216,7 @@ If `column[:sql_column].blank?` then this `col` has fallen back to being a `val`
978
1216
 
979
1217
  Try adding `col :post_category, sql_column: 'post_categories.title'`
980
1218
 
981
- ### With Array collection
1219
+ ## With Array collection
982
1220
 
983
1221
  And in the case of a `col` with an Array collection, or any `val`:
984
1222
 
@@ -1017,7 +1255,7 @@ end
1017
1255
 
1018
1256
  The search and sort for each column will be merged together to form the final results.
1019
1257
 
1020
- ### Default search collection
1258
+ ## Default search collection
1021
1259
 
1022
1260
  When using a `col :comments` type belongs_to or has_many column, a search collection for that class will be loaded.
1023
1261
 
@@ -1139,6 +1377,22 @@ def finalize(collection)
1139
1377
  end
1140
1378
  ```
1141
1379
 
1380
+ ## Render outside of view
1381
+
1382
+ You can render a datatable outside the view.
1383
+
1384
+ Anything you pass to the `rendered` method is treated as view/request params.
1385
+
1386
+ You can test filters and scopes by passing them here.
1387
+
1388
+ ```
1389
+ post = Post.create!
1390
+ datatable = PostsDatatable.new.rendered(end_date: Time.zone.now+2.days, current_user_id: 1)
1391
+
1392
+ assert_equal 1, datatable.collection.count
1393
+ assert_equal [post], datatable.collection
1394
+ ```
1395
+
1142
1396
  ## Authorization
1143
1397
 
1144
1398
  All authorization checks are handled via the config.authorization_method found in the `config/initializers/effective_datatables.rb` file.
@@ -19,11 +19,12 @@ $(document).on 'change', ".dataTables_wrapper input[data-role='bulk-actions']",
19
19
 
20
20
  toggleDropdown = ($wrapper) ->
21
21
  $bulkActions = $wrapper.children().first().find('.buttons-bulk-actions').children('button')
22
+ selected = $wrapper.find("input[data-role='bulk-action']:checked").length
22
23
 
23
- if $wrapper.find("input[data-role='bulk-action']:checked").length > 0
24
- $bulkActions.removeAttr('disabled')
24
+ if selected > 0
25
+ $bulkActions.removeAttr('disabled').text("Bulk Actions (#{selected} items)")
25
26
  else
26
- $bulkActions.attr('disabled', 'disabled')
27
+ $bulkActions.attr('disabled', 'disabled').text('Bulk Actions')
27
28
 
28
29
  restoreSelected = ($table, selected) ->
29
30
  $bulkActions = $table.closest('.dataTables_wrapper').children().first().find('.buttons-bulk-actions').children('button')
@@ -41,11 +42,25 @@ restoreSelected = ($table, selected) ->
41
42
 
42
43
  if present then $bulkActions.removeAttr('disabled') else $bulkActions.attr('disabled', 'disabled')
43
44
 
44
- #### Bulk Action link behaviour
45
+ # rails_ujs data-confirm requires special attention
46
+ # https://github.com/rails/rails/blob/main/actionview/app/assets/javascripts/rails-ujs/features/confirm.coffee
47
+ $(document).on 'confirm:complete', '.dataTables_wrapper .buttons-bulk-actions a', (event) ->
48
+ if event.originalEvent.detail && event.originalEvent.detail[0] == true
49
+ doBulkActionPost(event)
50
+ (window.Rails || $.rails).stopEverything(event)
51
+ return false
52
+
45
53
  $(document).on 'click', '.dataTables_wrapper .buttons-bulk-actions a', (event) ->
46
- event.preventDefault() # prevent the click
54
+ unless $(event.currentTarget).data('confirm')
55
+ doBulkActionPost(event)
56
+ event.preventDefault()
57
+
58
+ doBulkActionPost = (event) ->
59
+ $bulkAction = $(event.currentTarget) # This is the regular <a href=...> tag maybe with data-confirm
60
+
61
+ document.cookie = 'ids=; expires=Thu, 01 Jan 1970 00:00:00 GMT'
62
+ localStorage.removeItem('ids')
47
63
 
48
- $bulkAction = $(event.currentTarget) # This is a regular <a href=...> tag
49
64
  $wrapper = $bulkAction.closest('.dataTables_wrapper')
50
65
  $table = $wrapper.find('table.dataTable').first()
51
66
  $processing = $table.siblings('.dataTables_processing').first()
@@ -54,6 +69,7 @@ $(document).on 'click', '.dataTables_wrapper .buttons-bulk-actions a', (event) -
54
69
  url = $bulkAction.attr('href')
55
70
  title = $bulkAction.text()
56
71
  download = $bulkAction.data('bulk-download')
72
+ payload_mode = $bulkAction.data('payload-mode')
57
73
  token = $table.data('authenticity-token')
58
74
  values = $.map($selected, (input) -> input.getAttribute('value'))
59
75
  method = $bulkAction.data('ajax-method')
@@ -61,10 +77,17 @@ $(document).on 'click', '.dataTables_wrapper .buttons-bulk-actions a', (event) -
61
77
  return unless url && values
62
78
 
63
79
  if method == 'GET'
64
- if url.includes('?')
65
- window.location.assign(url + '&' + $.param({ids: values}))
80
+ if payload_mode == 'cookie'
81
+ document.cookie = "ids=#{values}";
82
+ window.location.assign(url)
83
+ else if payload_mode == 'local-storage'
84
+ localStorage.setItem('ids', values);
85
+ window.location.assign(url)
66
86
  else
67
- window.location.assign(url + '?' + $.param({ids: values}))
87
+ if url.includes('?')
88
+ window.location.assign(url + '&' + $.param({ids: values}))
89
+ else
90
+ window.location.assign(url + '?' + $.param({ids: values}))
68
91
 
69
92
  return
70
93
 
@@ -0,0 +1,10 @@
1
+ $(document).on 'click', '.dataTables_wrapper a.buttons-download', (event) ->
2
+ $button = $(event.currentTarget)
3
+ $table = $('#' + $button.attr('aria-controls'))
4
+
5
+ url = $table.data('source').replace('.json', '/download.csv')
6
+ attributes = 'attributes=' + encodeURIComponent($table.data('attributes'))
7
+
8
+ $button.attr('href', url + '?' + attributes)
9
+
10
+ setTimeout (=> $button.attr('href', 'download.csv')), 0
@@ -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 1500)
19
+ delay = (if status == 'danger' then 4000 else 1000)
20
20
 
21
21
  $processing.html(message).data('timeout', setTimeout( =>
22
22
  $processing.html('Processing...')