effective_datatables 4.7.16 → 4.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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...')