active_element 0.0.3 → 0.0.5

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/Gemfile.lock +3 -7
  4. data/active_element.gemspec +1 -1
  5. data/app/assets/javascripts/active_element/application.js +3 -1
  6. data/app/assets/javascripts/active_element/popover.js +6 -0
  7. data/app/assets/javascripts/active_element/setup.js +12 -0
  8. data/app/assets/javascripts/active_element/{search_field.js → text_search_field.js} +2 -2
  9. data/app/assets/javascripts/active_element/toast.js +8 -0
  10. data/app/assets/stylesheets/active_element/application.scss +65 -1
  11. data/app/controllers/active_element/application_controller.rb +12 -18
  12. data/app/views/active_element/components/form/_label.html.erb +2 -2
  13. data/app/views/active_element/components/form/_templates.html.erb +8 -8
  14. data/app/views/active_element/components/form.html.erb +3 -3
  15. data/app/views/active_element/components/table/_collection_row.html.erb +3 -3
  16. data/app/views/active_element/components/table/collection.html.erb +1 -1
  17. data/app/views/active_element/components/table/item.html.erb +3 -3
  18. data/app/views/active_element/navbar/_menu.html.erb +2 -2
  19. data/app/views/layouts/active_element.html.erb +21 -23
  20. data/config/routes.rb +10 -1
  21. data/lib/active_element/components/button.rb +6 -41
  22. data/lib/active_element/components/form.rb +12 -3
  23. data/lib/active_element/components/text_search/active_record_authorization.rb +13 -0
  24. data/lib/active_element/components/text_search/authorization.rb +117 -0
  25. data/lib/active_element/components/text_search/component.rb +118 -0
  26. data/lib/active_element/components/text_search/sql.rb +107 -0
  27. data/lib/active_element/components/text_search.rb +23 -0
  28. data/lib/active_element/components/util/decorator.rb +2 -2
  29. data/lib/active_element/components/util/record_path.rb +84 -0
  30. data/lib/active_element/components/util.rb +7 -2
  31. data/lib/active_element/components.rb +1 -0
  32. data/lib/active_element/controller_action.rb +9 -10
  33. data/lib/active_element/controller_interface.rb +78 -0
  34. data/lib/active_element/permissions_check.rb +33 -29
  35. data/lib/active_element/permissions_report.rb +57 -0
  36. data/lib/active_element/route.rb +1 -1
  37. data/lib/active_element/routes.rb +1 -1
  38. data/lib/active_element/version.rb +1 -1
  39. data/lib/active_element.rb +24 -10
  40. data/lib/tasks/active_element.rake +1 -16
  41. data/rspec-documentation/pages/Components/Tables.md +2 -2
  42. data/rspec-documentation/spec_helper.rb +1 -1
  43. metadata +19 -12
  44. data/app/controllers/active_element/text_searches_controller.rb +0 -189
  45. data/lib/active_element/active_record_text_search_authorization.rb +0 -12
  46. data/lib/active_element/colorized_string.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 655d08db8eadabaadb33cb07a264edaa864eda4173c11bc3f2cf5655eb3a6227
4
- data.tar.gz: a194ffc1b2e3b0debe6f6bbc8173ed0ba8ae7125dfaf63b4e8794c01fc66f04a
3
+ metadata.gz: 55c4ed1b8eb3233fc4c071184ac145f01888d72b751fafafa68ff32873600e15
4
+ data.tar.gz: ce1fba3786c8b1084678a26f27bb72107fdfec3de8dec53e6ccf4d45e32d526c
5
5
  SHA512:
6
- metadata.gz: 2f0fc5677bfb2c341aedab2b4bf5f0c1150731bea95331f71bc0a1102a0bd8d9d89aba94c427e603328225feac7273ed5f6ca55616eb11f88852b8eeeae06a19
7
- data.tar.gz: 17e0e9b4dbc007e6ad6c7aabd941100a24188c461bfe6a35b781b7a4538b7b7b02b59c2733e5326f9946ac2097975be6205482a0f4fa04e35e34bf093c433baf
6
+ metadata.gz: 5f3461c71414a3264a4e8911e642a5ca2fddbcf8cb456eef49f777a86eae69b094a35e7e133401428d4168062198a88fe63e6c909e62dab46ca965d00d7aa85e
7
+ data.tar.gz: 469fb951cb7ccd0ab11ebb54b207d2c59ca5a8fbe2fc06f49d3ef58aaff69389870ec39e48b2c243a503ac036ae8d198e19c6120b7a4d881ba56a5b839f66e0f
data/.rubocop.yml CHANGED
@@ -2,6 +2,7 @@ require:
2
2
  - rubocop-rake
3
3
  - rubocop-rspec
4
4
  - rubocop-rails
5
+ - rubocop-factory_bot
5
6
 
6
7
  AllCops:
7
8
  NewCops: enable
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- active_element (0.0.3)
4
+ active_element (0.0.5)
5
5
  bootstrap (~> 5.3.0alpha3)
6
- faraday (~> 2.7)
7
6
  kaminari (~> 1.2)
7
+ paintbrush (~> 0.1.2)
8
8
  rails (~> 6.1)
9
9
  rouge (~> 4.1)
10
10
  sassc (~> 2.4)
@@ -102,10 +102,6 @@ GEM
102
102
  factory_bot_rails (5.2.0)
103
103
  factory_bot (~> 5.2.0)
104
104
  railties (>= 4.2.0)
105
- faraday (2.7.5)
106
- faraday-net_http (>= 2.0, < 3.1)
107
- ruby2_keywords (>= 0.0.4)
108
- faraday-net_http (3.0.2)
109
105
  ffi (1.15.5)
110
106
  globalid (1.1.0)
111
107
  activesupport (>= 5.0)
@@ -153,6 +149,7 @@ GEM
153
149
  racc (~> 1.4)
154
150
  orm_adapter (0.5.0)
155
151
  paint (2.3.0)
152
+ paintbrush (0.1.2)
156
153
  parallel (1.23.0)
157
154
  parser (3.2.2.1)
158
155
  ast (~> 2.4.1)
@@ -252,7 +249,6 @@ GEM
252
249
  rubocop-capybara (~> 2.17)
253
250
  rubocop-factory_bot (~> 2.22)
254
251
  ruby-progressbar (1.13.0)
255
- ruby2_keywords (0.0.5)
256
252
  sassc (2.4.0)
257
253
  ffi (~> 1.9)
258
254
  sassc-rails (2.1.2)
@@ -31,8 +31,8 @@ Gem::Specification.new do |spec|
31
31
  spec.metadata['rubygems_mfa_required'] = 'true'
32
32
 
33
33
  spec.add_runtime_dependency 'bootstrap', '~> 5.3.0alpha3'
34
- spec.add_runtime_dependency 'faraday', '~> 2.7'
35
34
  spec.add_runtime_dependency 'kaminari', '~> 1.2'
35
+ spec.add_runtime_dependency 'paintbrush', '~> 0.1.2'
36
36
  spec.add_runtime_dependency 'rails', '~> 6.1'
37
37
  spec.add_runtime_dependency 'rouge', '~> 4.1'
38
38
  spec.add_runtime_dependency 'sassc', '~> 2.4'
@@ -4,7 +4,9 @@
4
4
  //= require active_element/theme
5
5
  //= require active_element/secret
6
6
  //= require active_element/json_field
7
- //= require active_element/search_field
7
+ //= require active_element/text_search_field
8
8
  //= require active_element/form
9
9
  //= require active_element/confirm
10
10
  //= require active_element/pagination
11
+ //= require active_element/toast
12
+ //= require active_element/popover
@@ -0,0 +1,6 @@
1
+ (() => {
2
+ const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
3
+ const popoverList = popoverTriggerList.map(function (element) {
4
+ return new bootstrap.Popover(element)
5
+ })
6
+ })();
@@ -20,6 +20,17 @@
20
20
  return element;
21
21
  };
22
22
 
23
+ const navbar = document.querySelector('.navbar.application-menu');
24
+
25
+ window.addEventListener('scroll', () => {
26
+ if (window.scrollY > 50) {
27
+ navbar.classList.add('shrink');
28
+ } else {
29
+ navbar.classList.remove('shrink');
30
+ }
31
+ });
32
+
33
+
23
34
  const ActiveElement = {
24
35
  log: (message) => { console.log(`[ActiveElement] ${message}`); },
25
36
  _id: 0,
@@ -28,6 +39,7 @@
28
39
  cloneElement,
29
40
  components: {},
30
41
  jsonData: {},
42
+ controller_path: document.querySelector('meta[name="active_element_controller_path"]').content
31
43
  };
32
44
 
33
45
  window.ActiveElement = ActiveElement;
@@ -37,7 +37,7 @@
37
37
  resultsItem.innerText = attributes.length === 0 ? value : `${attributes.join(', ')} (${value})`;
38
38
  resultsItem.addEventListener('click', () => {
39
39
  hiddenInput.value = value;
40
- element.value = attributes.length == 0 ? value : `${attributes.join(', ')} (${value})`;
40
+ element.value = value;
41
41
  searchResultsContainer.replaceChildren();
42
42
  searchResultsContainer.classList.add('d-none');
43
43
  });
@@ -97,7 +97,7 @@
97
97
  searchResultsContainer.replaceChildren();
98
98
 
99
99
  fetch(
100
- '/_text_search/',
100
+ `/${ActiveElement.controller_path}/_active_element_text_search/`,
101
101
  {
102
102
  method: 'POST',
103
103
  headers: { 'Content-Type': 'application/json' },
@@ -0,0 +1,8 @@
1
+ (() => {
2
+ const elements = [].slice.call(document.querySelectorAll('.toast'));
3
+ const toasts = elements.map(function (element) {
4
+ return new bootstrap.Toast(element, { animation: true, autohide: true, delay: 10000 })
5
+ });
6
+
7
+ toasts.forEach((toast) => toast.show());
8
+ })();
@@ -1,7 +1,22 @@
1
1
  @import "variables";
2
2
  @import "bootstrap";
3
3
 
4
- .navbar-brand {
4
+ .navbar.application-menu {
5
+ height: 5rem;
6
+ transition: height 0.5s ease-in-out, background-position 0.8s ease-in-out;
7
+ background-position: right 1.2rem center;
8
+ background-repeat: no-repeat;
9
+
10
+ &.shrink {
11
+ height: 3rem;
12
+ background-position: right -50rem center;
13
+ }
14
+
15
+ &:hover {
16
+ height: 5rem;
17
+ background-position: right 1.2rem center;
18
+ background-repeat: no-repeat;
19
+ }
5
20
  }
6
21
 
7
22
  td.action-column {
@@ -51,6 +66,55 @@ form {
51
66
  }
52
67
  }
53
68
 
69
+ .search-field-results {
70
+ min-width: 20rem;
71
+ position: absolute;
72
+ .search-field-result {
73
+ cursor: pointer;
74
+ &:hover {
75
+ background-color: #{$blue};
76
+ color: #{$white};
77
+ }
78
+ }
79
+ }
80
+
81
+ .flash.toast {
82
+ position: absolute;
83
+ margin-top: 2rem;
84
+ margin-right: 1rem;
85
+ padding: 0;
86
+
87
+ &.notice {
88
+ .toast-body {
89
+ background: #{$blue-100};
90
+ }
91
+ }
92
+
93
+ &.alert {
94
+ .toast-body {
95
+ background: #{$red-100};
96
+ }
97
+ }
98
+ }
99
+
100
+ [data-bs-theme="dark"] {
101
+ .flash.toast {
102
+ &.notice {
103
+ .toast-body {
104
+ color: #{$white};
105
+ background: #{$blue-700};
106
+ }
107
+ }
108
+
109
+ &.alert {
110
+ .toast-body {
111
+ color: #{$white};
112
+ background: #{$red-700};
113
+ }
114
+ }
115
+ }
116
+ }
117
+
54
118
  #theme-select {
55
119
  font-size: 1.5rem;
56
120
  padding: 0.2rem 0.8rem;
@@ -8,34 +8,28 @@ module ActiveElement
8
8
 
9
9
  layout 'active_element'
10
10
 
11
- before_action -> { authenticate_user! }
12
- before_action -> { ActiveElement::ControllerAction.new(self).process_action }
13
-
14
- helper_method :active_element_component
15
- helper_method :render_active_element_hook
16
-
17
- def self.permit_user(permissions, **kwargs)
18
- active_element_permissions << [permissions, kwargs]
19
-
20
- nil
11
+ def self.active_element
12
+ @active_element ||= ActiveElement::ControllerInterface.new(self)
21
13
  end
22
14
 
23
- def active_element_component
24
- @active_element_component ||= ActiveElement::Component.new(self)
15
+ def active_element
16
+ @active_element ||= ActiveElement::ControllerInterface.new(self.class, self)
25
17
  end
26
18
 
19
+ before_action -> { active_element.authenticator&.call }
20
+ before_action -> { ActiveElement::ControllerAction.new(self).process_action }
21
+
22
+ helper_method :active_element
23
+ helper_method :render_active_element_hook
24
+
27
25
  def render_active_element_hook(hook)
28
26
  render_to_string partial: hook
29
27
  rescue ActionView::MissingTemplate
30
28
  nil
31
29
  end
32
30
 
33
- def missing_template_store
34
- @missing_template_store ||= {}
35
- end
36
-
37
- def self.active_element_permissions
38
- @active_element_permissions ||= []
31
+ def _active_element_text_search
32
+ render(**ActiveElement::Components::TextSearch::Component.new(controller: self).response)
39
33
  end
40
34
  end
41
35
  end
@@ -1,6 +1,6 @@
1
- <%= form.label field, options[:label] do %>
1
+ <%= form.label field do %>
2
+ <%= options[:label] %>
2
3
  <% if options[:description].present? %>
3
- <%= options[:label] %>
4
4
  <button type="button"
5
5
  style="background: none; border: none; outline: 0; position: absolute; margin-top: 0.3rem"
6
6
  data-bs-toggle="popover"
@@ -17,25 +17,25 @@
17
17
 
18
18
  <select id="json-select-template" class="form-select m-1 json-select-field"></select>
19
19
 
20
- <%= active_element_component.destroy_button id: 'json-delete-button-template',
20
+ <%= active_element.component.destroy_button id: 'json-delete-button-template',
21
21
  class: 'button-sm json-delete-button' %>
22
22
 
23
- <%= active_element_component.button 'Delete Item', type: 'danger', id: 'json-delete-object-button-template',
23
+ <%= active_element.component.button 'Delete Item', type: 'danger', id: 'json-delete-object-button-template',
24
24
  class: 'json-delete-button w-25 float-end json-delete-object-button' %>
25
25
 
26
- <%= active_element_component.button id: 'json-append-button-template',
26
+ <%= active_element.component.button id: 'json-append-button-template',
27
27
  class: 'btn-sm mt-3 mb-3 json-add-field-button' %>
28
28
 
29
- <%= active_element_component.button 'Hide', id: 'json-expand-collapse-button-template',
29
+ <%= active_element.component.button 'Hide', id: 'json-expand-collapse-button-template',
30
30
  class: 'float-end expand-collapse-button' %>
31
31
 
32
32
  </div>
33
33
 
34
- <%= active_element_component.button 'Expand Form', id: 'form-expand-button-template', class: 'mb-1 btn-sm' do %>
34
+ <%= active_element.component.button 'Expand Form', id: 'form-expand-button-template', class: 'mb-1 btn-sm' do %>
35
35
  <i class="fa-solid fa-fw fa-up-right-and-down-left-from-center"></i>
36
36
  <% end %>
37
37
 
38
- <%= active_element_component.button 'Collapse Form', id: 'form-collapse-button-template', class: 'mb-1 btn-sm' do %>
38
+ <%= active_element.component.button 'Collapse Form', id: 'form-collapse-button-template', class: 'mb-1 btn-sm' do %>
39
39
  <i class="fa-solid fa-fw fa-down-left-and-up-right-to-center"></i>
40
40
  <% end %>
41
41
 
@@ -76,10 +76,10 @@
76
76
  </div>
77
77
 
78
78
  <div id="form-confirm-button-template">
79
- <%= active_element_component.button 'Confirm' %>
79
+ <%= active_element.component.button 'Confirm' %>
80
80
  </div>
81
81
 
82
82
  <div id="form-cancel-button-template">
83
- <%= active_element_component.button 'Cancel' %>
83
+ <%= active_element.component.button 'Cancel' %>
84
84
  </div>
85
85
  </div>
@@ -1,5 +1,5 @@
1
1
  <% if destroy %>
2
- <%= active_element_component.destroy_button(record, float: 'end') %>
2
+ <%= active_element.component.destroy_button(record, float: 'end') %>
3
3
  <% end %>
4
4
 
5
5
  <% if modal %>
@@ -7,7 +7,7 @@
7
7
  <div class="mt-4 mb-5 ms-3">
8
8
 
9
9
  <div class="p-3 pb-4 border-bottom d-inline">
10
- <%= active_element_component.button(
10
+ <%= active_element.component.button(
11
11
  title: title.presence || 'Show Form',
12
12
  icon: 'arrow-up-right-dots',
13
13
  data: { field_type: 'form-modal', form_id: id, form_title: title }) %>
@@ -40,7 +40,7 @@
40
40
  <%= form_with local: true, **kwargs, method: method, id: id, class: "#{class_name} m-3 #{modal == false && expanded == false ? 'd-none' : nil}" do |form| %>
41
41
  <% if %i[top both].include?(submit_position) %>
42
42
  <div class="form-group sticky-top" style="top: 0.5rem;">
43
- <%= form.submit submit_label, class: 'btn btn-success float-end' %>
43
+ <%= form.submit submit_label, class: "btn btn-#{method == :post ? 'success' : 'primary'} float-end" %>
44
44
  </div>
45
45
  <% end %>
46
46
 
@@ -12,19 +12,19 @@
12
12
 
13
13
  <% if show %>
14
14
  <td class="<%= "#{class_name}-show" %> action-column text-end">
15
- <%= active_element_component.show_button(item, show, class: 'btn-sm') %>
15
+ <%= active_element.component.show_button(item, show, class: 'btn-sm') %>
16
16
  </td>
17
17
  <% end %>
18
18
 
19
19
  <% if edit %>
20
20
  <td class="<%= "#{class_name}-edit" %> action-column text-end">
21
- <%= active_element_component.edit_button(item, show, class: 'btn-sm') %>
21
+ <%= active_element.component.edit_button(item, show, class: 'btn-sm') %>
22
22
  </td>
23
23
  <% end %>
24
24
 
25
25
  <% if destroy %>
26
26
  <td class="<%= "#{class_name}-destroy" %> action-column text-end">
27
- <%= active_element_component.destroy_button(item, destroy, class: 'btn-sm') %>
27
+ <%= active_element.component.destroy_button(item, destroy, class: 'btn-sm') %>
28
28
  </td>
29
29
  <% end %>
30
30
  </tr>
@@ -1,5 +1,5 @@
1
1
  <% if new %>
2
- <%= active_element_component.new_button(collection, float: 'end', class: 'mb-3') %>
2
+ <%= active_element.component.new_button(collection, float: 'end', class: 'mb-3') %>
3
3
  <% end %>
4
4
 
5
5
  <% if display_pagination %>
@@ -1,13 +1,13 @@
1
1
  <% if destroy && item.present? %>
2
- <%= active_element_component.destroy_button(item, destroy, float: 'end') %>
2
+ <%= active_element.component.destroy_button(item, destroy, float: 'end') %>
3
3
  <% end %>
4
4
 
5
5
  <% if edit && item.present? %>
6
- <%= active_element_component.edit_button(item, edit, float: 'end') %>
6
+ <%= active_element.component.edit_button(item, edit, float: 'end') %>
7
7
  <% end %>
8
8
 
9
9
  <% if new %>
10
- <%= active_element_component.new_button(item, float: 'end', class: 'mb-3') %>
10
+ <%= active_element.component.new_button(item, float: 'end', class: 'mb-3') %>
11
11
  <% end %>
12
12
 
13
13
  <table class="<%= class_name %> table" style="<%= style %>">
@@ -7,14 +7,14 @@
7
7
  </button>
8
8
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
9
9
  <ul class="navbar-nav me-auto mb-2 mb-lg-0">
10
- <% ActiveElement.navbar_items(current_user).each do |navbar_item| %>
10
+ <% ActiveElement.navbar_items(active_element.current_user).each do |navbar_item| %>
11
11
  <li class="nav-item">
12
12
  <%=
13
13
  link_to navbar_item.fetch(:title) { navbar_item.fetch(:label) },
14
14
  navbar_item.fetch(:path),
15
15
  class: "nav-link #{
16
16
  ActiveElement.active_path_class(
17
- user: current_user,
17
+ user: active_element.current_user,
18
18
  current_navbar_item: navbar_item,
19
19
  current_path: request.path,
20
20
  controller_path: controller_path,
@@ -7,18 +7,15 @@
7
7
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.9.2/umd/popper.min.js" integrity="sha512-2rNj2KJ+D8s1ceNasTIex6z4HWyOnEYLVC3FigGOmyQCZc2eBXKgOxQmo3oKLHyfcj53uz4QMsRCWNbLd32Q1g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
8
8
 
9
9
  <%= stylesheet_link_tag 'active_element/application', 'data-turbolinks-track': 'reload' %>
10
- <%= javascript_include_tag 'active_element/application', 'data-turbolinks-track': 'reload' %>
11
10
 
12
11
  <% if Rails.application.assets.find_asset('application.css').present? %>
13
12
  <%= stylesheet_link_tag 'application', 'data-turbolinks-track': 'reload' %>
14
13
  <% end %>
15
14
 
16
- <% if Rails.application.assets.find_asset('application.js').present? %>
17
- <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
18
- <% end %>
19
-
20
15
  <%= csrf_meta_tag %>
21
16
 
17
+ <meta name="active_element_controller_path" content="<%= controller_path %>">
18
+
22
19
  <%= render_active_element_hook 'active_element/after_head' %>
23
20
  </head>
24
21
 
@@ -28,11 +25,21 @@
28
25
  <%= render_active_element_hook 'active_element/after_navbar' %>
29
26
 
30
27
  <% flash.each do |type, message| %>
31
- <div class="flash card text-bg-<%= { notice: 'info', alert: 'danger' }.fetch(type.to_sym, 'info') %> flash <%= type %> float-end">
32
- <div class="card-body">
33
- <%= message %>
34
- <button type="button" class="btn-close" aria-label="Close"></button>
35
- </div>
28
+ <div class="flash toast <%= type %> position-absolute top-0 end-0 mt-5" role="alert" aria-live="assertive" aria-atomic="true">
29
+ <div class="toast-header">
30
+ <% if type == 'notice' %>
31
+ <i class="fa-solid me-2 text-info fa-circle-info"></i>
32
+ <% elsif type == 'alert' %>
33
+ <i class="fa-solid me-2 text-danger fa-circle-exclamation"></i>
34
+ <% else %>
35
+ <i class="fa-solid me-2 text-info fa-circle-info"></i>
36
+ <% end %>
37
+ <strong class="me-auto"><%= type.titleize %></strong>
38
+ <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
39
+ </div>
40
+ <div class="toast-body fw-bold align-middle">
41
+ <%= message %>
42
+ </div>
36
43
  </div>
37
44
  <% end %>
38
45
 
@@ -48,18 +55,9 @@
48
55
 
49
56
  <%= render_active_element_hook 'active_element/after_content' %>
50
57
 
51
- <script>
52
- var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
53
- var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
54
- return new bootstrap.Popover(popoverTriggerEl)
55
- })
56
-
57
- document.querySelectorAll('.flash .btn-close').forEach(element => {
58
- element.onclick = ev => {
59
- ev.stopPropagation();
60
- ev.target.parentElement.parentElement.classList.add('d-none');
61
- };
62
- });
63
- </script>
58
+ <%= javascript_include_tag 'active_element/application', 'data-turbolinks-track': 'reload' %>
59
+ <% if Rails.application.assets.find_asset('application.js').present? %>
60
+ <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
61
+ <% end %>
64
62
  </body>
65
63
  </html>
data/config/routes.rb CHANGED
@@ -1,5 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  ActiveElement::Engine.routes.draw do
4
- post '/_text_search', controller: 'active_element/text_searches', action: 'create'
4
+ ActiveElement.eager_load_controllers
5
+
6
+ ActiveElement::ApplicationController.descendants.map do |descendant|
7
+ post "#{descendant.controller_path}/_active_element_text_search",
8
+ controller: descendant.controller_path,
9
+ action: '_active_element_text_search'
10
+
11
+ # Permissions for text search are managed by ActiveElement::Components::TextSearch::Authorization
12
+ descendant.active_element.permit_action :_active_element_text_search, always: true
13
+ end
5
14
  end
@@ -3,7 +3,6 @@
3
3
  module ActiveElement
4
4
  module Components
5
5
  # A clickable button.
6
- # rubocop:disable Metrics/ClassLength
7
6
  class Button
8
7
  # rubocop:disable Metrics/MethodLength
9
8
  def initialize(controller, record, flag_or_options, confirm: false, type: :primary, method: nil,
@@ -75,45 +74,6 @@ module ActiveElement
75
74
  { 'end' => 'float-end', 'start' => 'float-start', nil => nil }.fetch(float)
76
75
  end
77
76
 
78
- def namespace_prefix
79
- # XXX: We guess the namespace from the current controller's module name. This will work
80
- # most of the time but will break the current record's controller exists in a different
81
- # namespace to the current controller, e.g. `BackEndAdmin::UsersController` and
82
- # `FrontEndAdmin::ThemesController` - if `FrontEndAdmin::ThemesController` renders a
83
- # collection of `User` objects, the "show" path will be wrong:
84
- # `front_end_admin_user_path`. Maybe descend through the full controller class tree to
85
- # find a best match ?
86
- namespace = controller.class.name.deconstantize.underscore
87
- return nil if namespace.blank?
88
-
89
- "#{namespace}_"
90
- end
91
-
92
- def record_path
93
- return nil if record.nil?
94
-
95
- controller.helpers.public_send(default_record_path, record)
96
- rescue NoMethodError
97
- controller.helpers.public_send(sti_record_path, record)
98
- end
99
-
100
- def default_record_path
101
- "#{record_path_prefix}#{namespace_prefix}#{record_name}_path"
102
- end
103
-
104
- def sti_record_path
105
- "#{record_path_prefix}#{namespace_prefix}#{sti_record_name}_path"
106
- end
107
-
108
- def record_path_prefix
109
- case type
110
- when :edit
111
- 'edit_'
112
- when :new
113
- 'new_'
114
- end
115
- end
116
-
117
77
  def title
118
78
  return flag_or_options[:title] if flag_or_options.is_a?(Hash) && flag_or_options[:title].present?
119
79
  return default_action_title if %i[show destroy edit new].include?(type)
@@ -150,7 +110,12 @@ module ActiveElement
150
110
  def sti_record_name
151
111
  Util.sti_record_name(record)
152
112
  end
113
+
114
+ def record_path
115
+ return nil unless record.class.is_a?(ActiveModel::Naming)
116
+
117
+ Util::RecordPath.new(record: record, controller: controller, type: type).path
118
+ end
153
119
  end
154
120
  end
155
- # rubocop:enable Metrics/ClassLength
156
121
  end
@@ -22,6 +22,7 @@ module ActiveElement
22
22
  @modal = modal
23
23
  @kwargs = kwargs
24
24
  @columns = columns
25
+ @action = kwargs.delete(:action) { default_action }
25
26
  @method = kwargs.delete(:method) { default_method }.to_s.downcase.to_sym
26
27
  end
27
28
  # rubocop:enable Metrics/MethodLength
@@ -30,7 +31,7 @@ module ActiveElement
30
31
  'active_element/components/form'
31
32
  end
32
33
 
33
- def locals # rubocop:disable Metrics/MethodLength
34
+ def locals # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
34
35
  {
35
36
  component: self,
36
37
  fields: Util::FormFieldMapping.new(record, fields, i18n).fields_with_types_and_options,
@@ -39,6 +40,7 @@ module ActiveElement
39
40
  submit_position: submit_position,
40
41
  class_name: class_name,
41
42
  method: method,
43
+ action: action,
42
44
  kwargs: kwargs,
43
45
  destroy: destroy,
44
46
  modal: modal,
@@ -130,7 +132,8 @@ module ActiveElement
130
132
 
131
133
  private
132
134
 
133
- attr_reader :fields, :submit, :title, :kwargs, :item, :method, :destroy, :modal, :expanded, :columns
135
+ attr_reader :fields, :submit, :title, :kwargs, :item, :method, :action,
136
+ :destroy, :modal, :expanded, :columns
134
137
 
135
138
  def valid_field?(field)
136
139
  return true if record.respond_to?("#{field}_changed?") && !record.public_send("#{field}_changed?")
@@ -197,7 +200,7 @@ module ActiveElement
197
200
 
198
201
  def default_method
199
202
  case controller.action_name
200
- when 'edit'
203
+ when 'edit', 'update'
201
204
  'PATCH'
202
205
  when 'index'
203
206
  'GET'
@@ -205,6 +208,12 @@ module ActiveElement
205
208
  'POST'
206
209
  end
207
210
  end
211
+
212
+ def default_action
213
+ return controller.request.path unless record.is_a?(ActiveModel::Naming)
214
+
215
+ Util::RecordPath.new(record: record, controller: controller).path
216
+ end
208
217
  end
209
218
  end
210
219
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveRecord::Base.class_eval do
4
+ class << self
5
+ def authorize_active_element_text_search(with:, providing:)
6
+ ActiveElement::Components::TextSearch.register_authorized_text_search(
7
+ model: self,
8
+ with: with,
9
+ providing: providing
10
+ )
11
+ end
12
+ end
13
+ end