active_element 0.0.2 → 0.0.4

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +8 -9
  5. data/active_element.gemspec +1 -1
  6. data/app/assets/javascripts/active_element/application.js +3 -1
  7. data/app/assets/javascripts/active_element/popover.js +6 -0
  8. data/app/assets/javascripts/active_element/setup.js +12 -0
  9. data/app/assets/javascripts/active_element/{search_field.js → text_search_field.js} +2 -2
  10. data/app/assets/javascripts/active_element/toast.js +8 -0
  11. data/app/assets/stylesheets/active_element/application.scss +65 -1
  12. data/app/controllers/active_element/application_controller.rb +13 -19
  13. data/app/views/active_element/components/form/_label.html.erb +2 -2
  14. data/app/views/active_element/components/form/_templates.html.erb +8 -8
  15. data/app/views/active_element/components/form.html.erb +3 -3
  16. data/app/views/active_element/components/table/_collection_row.html.erb +3 -3
  17. data/app/views/active_element/components/table/collection.html.erb +1 -1
  18. data/app/views/active_element/components/table/item.html.erb +3 -3
  19. data/app/views/active_element/navbar/_menu.html.erb +2 -2
  20. data/app/views/layouts/active_element.html.erb +21 -23
  21. data/app/views/layouts/active_element_error.html.erb +1 -1
  22. data/config/routes.rb +10 -1
  23. data/lib/active_element/components/button.rb +6 -41
  24. data/lib/active_element/components/form.rb +12 -3
  25. data/lib/active_element/components/text_search/active_record_authorization.rb +13 -0
  26. data/lib/active_element/components/text_search/authorization.rb +117 -0
  27. data/lib/active_element/components/text_search/component.rb +118 -0
  28. data/lib/active_element/components/text_search/sql.rb +107 -0
  29. data/lib/active_element/components/text_search.rb +23 -0
  30. data/lib/active_element/components/util/decorator.rb +2 -2
  31. data/lib/active_element/components/util/record_path.rb +84 -0
  32. data/lib/active_element/components/util.rb +7 -2
  33. data/lib/active_element/components.rb +1 -0
  34. data/lib/active_element/controller_action.rb +9 -10
  35. data/lib/active_element/controller_interface.rb +78 -0
  36. data/lib/active_element/permissions_check.rb +33 -29
  37. data/lib/active_element/permissions_report.rb +57 -0
  38. data/lib/active_element/route.rb +1 -1
  39. data/lib/active_element/routes.rb +1 -1
  40. data/lib/active_element/version.rb +1 -1
  41. data/lib/active_element.rb +24 -10
  42. data/lib/tasks/active_element.rake +1 -16
  43. data/rspec-documentation/pages/Components/Tables.md +2 -2
  44. data/rspec-documentation/spec_helper.rb +1 -1
  45. metadata +19 -12
  46. data/app/controllers/active_element/text_searches_controller.rb +0 -189
  47. data/lib/active_element/active_record_text_search_authorization.rb +0 -12
  48. data/lib/active_element/colorized_string.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26b1ee53510a64cb3215d2fc26b93bea88eb02e6dc9da9ceed48c64af7bdd4eb
4
- data.tar.gz: e942cc5ce6c22b456c40aa999304681970bb760a437bafd9a7f65a6365f8a487
3
+ metadata.gz: f044724b30fa122fb6700ecd4afa352e26d4b920aec89ee4ff3548cb2ef66c20
4
+ data.tar.gz: 5b0fab5e11fea56667782189c3ebdcdfe95fcc0935fa93ddfeb9ad9d7f8015af
5
5
  SHA512:
6
- metadata.gz: e3d5d2b2882d1e3ddcbe4c3d3c3aadd39bac2762148812d463d6e6df81972f54108f3ac43b195525550ea8cf6e19b30cb8e59431033b161b771e2a863f5269f9
7
- data.tar.gz: d6d4a623ff93445d973ab43ac94c74eb617f6ab73f3ab49bffee3f9a018bda34acc2e9a020c38f537ca8e49c5d3bb4386ef62102cf7b2e4ce2ba0bb1220cc7b6
6
+ metadata.gz: c9dc8ec715c992280a32943a7a2e6190d3af8d87260145aed268b94bdee2f3d4b574ddf5f10fdfd9de68f5d651da1958c120b4e08945099c65700a52bcd7e752
7
+ data.tar.gz: a400b8fbe592d4af7bd347aeb7f4e0ae2fe3597f0edba862c01ffc4cd15eeb6ba5fe1ead8dcbb8e5f43f23cbdc9242ef197d5b4861add208f8656e9c900728ea
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 CHANGED
@@ -8,9 +8,9 @@ gemspec
8
8
  gem 'devise', '~> 4.9'
9
9
  gem 'devpack', '~> 0.4.1'
10
10
  gem 'factory_bot_rails', '~> 5.2'
11
+ gem 'paintbrush', path: '../paintbrush'
11
12
  gem 'rake', '~> 13.0'
12
13
  gem 'rspec', '~> 3.12'
13
- gem 'rspec-documentation'
14
14
  gem 'rspec-file_fixtures', '~> 0.1.6'
15
15
  gem 'rspec-html', '~> 0.3.2'
16
16
  gem 'rspec-its', '~> 1.3'
data/Gemfile.lock CHANGED
@@ -1,10 +1,15 @@
1
+ PATH
2
+ remote: ../paintbrush
3
+ specs:
4
+ paintbrush (0.1.1)
5
+
1
6
  PATH
2
7
  remote: .
3
8
  specs:
4
- active_element (0.0.1)
9
+ active_element (0.0.4)
5
10
  bootstrap (~> 5.3.0alpha3)
6
- faraday (~> 2.7)
7
11
  kaminari (~> 1.2)
12
+ paintbrush (~> 0.1.1)
8
13
  rails (~> 6.1)
9
14
  rouge (~> 4.1)
10
15
  sassc (~> 2.4)
@@ -102,10 +107,6 @@ GEM
102
107
  factory_bot_rails (5.2.0)
103
108
  factory_bot (~> 5.2.0)
104
109
  railties (>= 4.2.0)
105
- faraday (2.7.4)
106
- faraday-net_http (>= 2.0, < 3.1)
107
- ruby2_keywords (>= 0.0.4)
108
- faraday-net_http (3.0.2)
109
110
  ffi (1.15.5)
110
111
  globalid (1.1.0)
111
112
  activesupport (>= 5.0)
@@ -202,7 +203,6 @@ GEM
202
203
  rspec-mocks (~> 3.12.0)
203
204
  rspec-core (3.12.2)
204
205
  rspec-support (~> 3.12.0)
205
- rspec-documentation (0.0.1)
206
206
  rspec-expectations (3.12.3)
207
207
  diff-lcs (>= 1.2.0, < 2.0)
208
208
  rspec-support (~> 3.12.0)
@@ -253,7 +253,6 @@ GEM
253
253
  rubocop-capybara (~> 2.17)
254
254
  rubocop-factory_bot (~> 2.22)
255
255
  ruby-progressbar (1.13.0)
256
- ruby2_keywords (0.0.5)
257
256
  sassc (2.4.0)
258
257
  ffi (~> 1.9)
259
258
  sassc-rails (2.1.2)
@@ -299,9 +298,9 @@ DEPENDENCIES
299
298
  devise (~> 4.9)
300
299
  devpack (~> 0.4.1)
301
300
  factory_bot_rails (~> 5.2)
301
+ paintbrush!
302
302
  rake (~> 13.0)
303
303
  rspec (~> 3.12)
304
- rspec-documentation
305
304
  rspec-file_fixtures (~> 0.1.6)
306
305
  rspec-html (~> 0.3.2)
307
306
  rspec-its (~> 1.3)
@@ -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.1'
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
- render_to_string partial: "/active_element/#{hook}"
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>
@@ -26,7 +26,7 @@
26
26
  }
27
27
  </style>
28
28
 
29
- <%= render_active_element_hook 'before_error_content' %>
29
+ <%= render_active_element_hook 'active_element/before_error_content' %>
30
30
 
31
31
  <body>
32
32
  <div class="wrapper">
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