para 0.12.1 → 0.12.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ee25a77e578b14d822cbf8827991f6c6920c580acddeb2120d0e6a2570795fa
4
- data.tar.gz: 41ee3d94327eeeacfb5ee1da6430956d5862ed0e242d0d09180bef828e46a921
3
+ metadata.gz: d2e8f3dd97232094cbf6840ad5ec462068c43019dec82f3c872d48bb5f0d8ffa
4
+ data.tar.gz: 2b3d6cd3dbfa31daef6cdca4e3e040843f10e350f02c9687dec51f1c641de12c
5
5
  SHA512:
6
- metadata.gz: acd659f13038e225325293d30820d115f5054ca6ba36cccc44e5404bc2e5d0e01226815b41aa38bc3f8c76f6299891c621c4e7d1d2306eaaa76a9f1c97f24891
7
- data.tar.gz: 7da8328b9591a785d922ddd3f12c61f95d57f7c3e8a327b5667ad22cbfabeeaaabac1c7c8d0e6ed50dee7bc48ceb7e172aac92b3a9593b6919678e4b957bcc1a
6
+ metadata.gz: 1c5d0d01332d290463ac6b3c856e2260ee62625ceb9a9e76ea0887f13188ce7df691b23be95e40b20b271a19c5650975844944c6bf1f50262b8677eaa7189d86
7
+ data.tar.gz: 29ad0aba0dc5ac675f601e8891641aa28e38649550202a03858c46a9703e2a257a52e09bf5ee21ce74f6ca21e877c141888f081ffdba6b88c69fb1bafa4cadd3
@@ -31,12 +31,15 @@
31
31
  content: "\f0dc";
32
32
  opacity: .3;
33
33
  }
34
+
34
35
  .sort_link.asc:before {
35
- content: "\f0d7";
36
+ content: "\f0d8";
36
37
  }
38
+
37
39
  .sort_link.desc:before {
38
- content: "\f0d8";
40
+ content: "\f0d7";
39
41
  }
42
+
40
43
  .sort_link.asc.disabled:before,
41
44
  .sort_link.desc.disabled:before {
42
45
  opacity: .1;
@@ -22,11 +22,11 @@ function trackProgressFor(element, jobStatusUrl) {
22
22
  }
23
23
 
24
24
  document.documentElement.addEventListener('turbo:frame-load', function(e) {
25
- if (e.target.id != 'para_admin_modal') return;
25
+ if (e.target.id !== 'para_admin_modal') return;
26
26
 
27
27
  loadedElement = e.target.childNodes[0];
28
28
 
29
- var jobStatusUrl = loadedElement && loadedElement.dataset.jobStatusUrl;
29
+ var jobStatusUrl = loadedElement?.dataset?.jobStatusUrl;
30
30
  if (!jobStatusUrl) return;
31
31
 
32
32
  trackProgressFor(loadedElement, jobStatusUrl);
@@ -8,3 +8,6 @@ application.register("para-admin-flash-message", ParaAdminFlashMessageController
8
8
 
9
9
  import SelectizeFieldController from "./selectize_field_controller";
10
10
  application.register("selectize-field", SelectizeFieldController);
11
+
12
+ import NestedManyInputController from "./nested_many_input_controller";
13
+ application.register("nested-many-input", NestedManyInputController);
@@ -1,52 +1,70 @@
1
- Para.NestedManyField = class NestedManyField {
2
- constructor($field1) {
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ export default class extends Controller {
4
+ connect() {
3
5
  this.stoppingPropagation = this.stoppingPropagation.bind(this);
4
6
  this.afterInsertField = this.afterInsertField.bind(this);
5
7
  this.beforeRemoveField = this.beforeRemoveField.bind(this);
6
- // When a sub field is removed, update every sub field position
8
+ this.handleOrderingUpdated = this.handleOrderingUpdated.bind(this);
7
9
  this.afterRemoveField = this.afterRemoveField.bind(this);
8
10
  this.collapseShown = this.collapseShown.bind(this);
9
- this.$field = $field1;
11
+
12
+ this.$field = $(this.element);
10
13
  this.$fieldsList = this.$field.find('.fields-list');
11
- this.initializeOrderable();
14
+ this.initializeSortable();
12
15
  this.initializeCocoon();
13
16
  this.$field.on('shown.bs.collapse', this.stoppingPropagation(this.collapseShown));
14
17
  }
15
18
 
16
- initializeOrderable() {
17
- this.orderable = this.$field.hasClass('orderable');
18
- if (!this.orderable) {
19
- return;
20
- }
19
+ initializeSortable() {
20
+ this.isSortable = this.$field.hasClass('orderable');
21
+
22
+ if (!this.isSortable) return;
23
+
21
24
  return this.$fieldsList.sortable({
22
25
  handle: '.order-anchor',
23
26
  animation: 150,
24
- onUpdate: $.proxy(this.handleOrderingUpdated, this)
27
+ onUpdate: this.handleOrderingUpdated
25
28
  });
26
29
  }
27
30
 
28
31
  handleOrderingUpdated() {
29
32
  var formFields;
30
33
  formFields = [];
34
+
31
35
  return this.$fieldsList.find('.form-fields:visible').each(function(_i, el) {
32
- var $el, $parent, isNestedField, j, len;
36
+ let $parent, isNestedField, j, len;
37
+
33
38
  for (j = 0, len = formFields.length; j < len; j++) {
34
39
  $parent = formFields[j];
35
40
  isNestedField = $parent.find(el).length;
36
41
  }
42
+
37
43
  if (isNestedField) {
38
44
  return;
39
45
  }
40
- $el = $(el);
46
+
47
+ const $el = $(el);
41
48
  $el.find('.resource-position-field:eq(0)').val(formFields.length);
42
49
  return formFields.push($el);
43
50
  });
44
51
  }
45
52
 
46
53
  initializeCocoon() {
47
- this.$fieldsList.on('cocoon:after-insert', this.stoppingPropagation(this.afterInsertField));
48
- this.$fieldsList.on('cocoon:before-remove', this.stoppingPropagation(this.beforeRemoveField));
49
- return this.$fieldsList.on('cocoon:after-remove', this.stoppingPropagation(this.afterRemoveField));
54
+ this.$fieldsList.on(
55
+ 'cocoon:after-insert',
56
+ this.stoppingPropagation(this.afterInsertField)
57
+ );
58
+
59
+ this.$fieldsList.on(
60
+ 'cocoon:before-remove',
61
+ this.stoppingPropagation(this.beforeRemoveField)
62
+ );
63
+
64
+ return this.$fieldsList.on(
65
+ 'cocoon:after-remove',
66
+ this.stoppingPropagation(this.afterRemoveField)
67
+ );
50
68
  }
51
69
 
52
70
  stoppingPropagation(callback) {
@@ -61,9 +79,9 @@ Para.NestedManyField = class NestedManyField {
61
79
  if (($collapsible = $element.find('[data-open-on-insert="true"]')).length) {
62
80
  this.openInsertedField($collapsible);
63
81
  }
64
- if (this.orderable) {
82
+ if (this.isSortable) {
65
83
  this.$fieldsList.sortable('destroy');
66
- this.initializeOrderable();
84
+ this.initializeSortable();
67
85
  this.handleOrderingUpdated();
68
86
  }
69
87
  return $element.simpleForm();
@@ -90,22 +108,24 @@ Para.NestedManyField = class NestedManyField {
90
108
  }
91
109
 
92
110
  collapseShown(e) {
93
- var $target;
94
- $target = $(e.target);
95
- if ($target.is("[data-rendered]") || $target.data("rendered")) {
96
- return this.initializeCollapseContent($target);
111
+ const { target } = e;
112
+
113
+ if (target.dataset.isRendered) {
114
+ return this.initializeCollapseContent(target);
97
115
  } else {
98
- this.loadCollapseContent($target);
99
- return this.scrollToTarget($target);
116
+ this.loadCollapseContent(target);
117
+ return this.scrollToTarget(target);
100
118
  }
101
119
  }
102
120
 
103
- initializeCollapseContent($target) {
104
- this.scrollToTarget($target);
105
- return this.focusFirstField($target);
121
+ initializeCollapseContent(target) {
122
+ this.scrollToTarget(target);
123
+ return this.focusFirstVisibleInputInside(target);
106
124
  }
107
125
 
108
- scrollToTarget($target) {
126
+ scrollToTarget(target) {
127
+ const $target = $(target);
128
+
109
129
  var $affixNavTabs, $field, scrollOffset;
110
130
  $field = this.$field.find(`[data-toggle='collapse'][href='#${$target.attr('id')}']`);
111
131
  scrollOffset = -($('[data-header]').outerHeight() + 30);
@@ -117,35 +137,32 @@ Para.NestedManyField = class NestedManyField {
117
137
  });
118
138
  }
119
139
 
120
- focusFirstField($target) {
121
- return $target.find('input, textarea, select').eq('0').focus();
140
+ focusFirstVisibleInputInside(target) {
141
+ setTimeout(() => {
142
+ target.querySelector('input:not([type="hidden"]), textarea, select')?.focus();
143
+ }, 100);
122
144
  }
123
145
 
124
- loadCollapseContent($target) {
125
- var data, targetUrl;
126
- targetUrl = $target.data("render-path");
127
- if (!targetUrl) {
128
- return;
129
- }
130
- data = {
131
- "id": $target.data("id"),
132
- "object_name": $target.data("object-name"),
133
- "model_name": $target.data("model-name")
146
+ loadCollapseContent(target) {
147
+ const $target = $(target);
148
+ const targetUrl = target.dataset.renderPath;
149
+
150
+ if (!targetUrl) return;
151
+
152
+ const data = {
153
+ id: target.dataset.id,
154
+ object_name: target.dataset.objectName,
155
+ model_name: target.dataset.modelName
134
156
  };
135
- return $.get(targetUrl, data).then((resp) => {
136
- var $content;
137
- $content = $(resp);
138
- $target.find("[data-nested-form-container]:eq(0)").html($content);
157
+
158
+ $.get(targetUrl, data).then((resp) => {
159
+ const $content = $(resp);
160
+ $target.find('[data-nested-form-container]:eq(0)').html($content);
139
161
  $content.simpleForm();
140
- this.focusFirstField($target);
141
- return $target.data("rendered", true);
162
+
163
+ this.focusFirstVisibleInputInside(target);
164
+
165
+ target.dataset.isRendered = true;
142
166
  });
143
167
  }
144
-
145
168
  };
146
-
147
- $.simpleForm.onDomReady(function($document) {
148
- return $document.find('.nested-many-field').each(function(i, el) {
149
- return new Para.NestedManyField($(el));
150
- });
151
- });
@@ -14,11 +14,7 @@ import "./vendor/jquery.sortable";
14
14
 
15
15
  import "./application";
16
16
 
17
- import "./lib/page-loading";
18
-
19
- import "./inputs/material-input";
20
17
  import "./inputs/multi-select-input";
21
- import "./inputs/nested_many";
22
18
 
23
19
  import "./admin/async-progress";
24
20
  import "./admin/filters-form";
@@ -1,4 +1,4 @@
1
- .nested-many-field{ class: [('orderable' if orderable), ('nested-many-field-inset' if inset)] }
1
+ .nested-many-field{ class: [('orderable' if orderable), ('nested-many-field-inset' if inset)], data: { controller: "nested-many-input" } }
2
2
  .fields-list{ id: dom_identifier }
3
3
  = form.simple_fields_for attribute_name, resources, nested_attribute_name: attribute_name, orderable: orderable, track_attribute_mappings: render_partial do |nested_form|
4
4
  = render partial: find_partial_for(model, 'nested_many/container', partial_dir: 'inputs'), locals: { form: nested_form, model: nested_form.object.class, subclass: subclass, allow_destroy_if: allow_destroy_if, nested_locals: nested_locals, inset: inset, uncollapsed: uncollapsed, render_partial: render_partial, remote_partial_params: remote_partial_params }
@@ -56,6 +56,10 @@ module Para
56
56
 
57
57
  reference = model.reflect_on_all_associations.find do |association|
58
58
  association.foreign_key == name
59
+ rescue ArgumentError
60
+ # This can happen when the association is polymorphic and the foreign key can't
61
+ # be determined, in this case, we just ignore the association.
62
+ false
59
63
  end
60
64
 
61
65
  if reference
@@ -75,12 +79,11 @@ module Para
75
79
  true
76
80
  end
77
81
 
78
- #
79
82
  def searchable?
80
83
  options[:searchable] != false && (
81
- [:string, :text].include?(type.to_sym) && !name.match(/password/)
84
+ %i[string text].include?(type.to_sym) && !name.match(/password/)
82
85
  ) && (
83
- !model.respond_to?(:ransackable_attributes) ||
86
+ !model.respond_to?(:ransackable_attributes) ||
84
87
  model.ransackable_attributes.include?(name.to_s)
85
88
  )
86
89
  end
@@ -94,7 +97,7 @@ module Para
94
97
  def field_options
95
98
  self.class._field_options.each_with_object({}) do |params, hash|
96
99
  value = send(params[:method_name])
97
- hash[params[:key]] = value if value != nil || params[:options][:allow_nil]
100
+ hash[params[:key]] = value if !value.nil? || params[:options][:allow_nil]
98
101
  end
99
102
  end
100
103
 
@@ -42,8 +42,10 @@ module Para
42
42
  # attributes mappings above
43
43
  next if AttributeField::RelationField == fields_hash[name]
44
44
 
45
- # Remove foreign key, if existing, from fields
46
- fields_hash.delete(reflection.foreign_key.to_s)
45
+ unless through_polymorphic_reflection?(reflection)
46
+ # Remove foreign key, if existing, from fields
47
+ fields_hash.delete(reflection.foreign_key.to_s)
48
+ end
47
49
 
48
50
  # Do not process polymorphic belongs to for now ...
49
51
  if reflection.options[:polymorphic] == true
@@ -52,27 +54,25 @@ module Para
52
54
  end
53
55
 
54
56
  if model.nested_attributes_options[name]
55
- if reflection.collection?
56
- fields_hash[name] = AttributeField::NestedManyField.new(
57
- model, name: name, type: 'has_many', field_type: 'nested_many'
58
- )
59
- else
60
- fields_hash[name] = AttributeField::NestedOneField.new(
61
- model, name: name, type: 'belongs_to', field_type: 'nested_one'
62
- )
63
- end
64
- else
65
- if reflection.collection?
66
- remove_counter_cache_column!(name, reflection)
57
+ fields_hash[name] = if reflection.collection?
58
+ AttributeField::NestedManyField.new(
59
+ model, name: name, type: 'has_many', field_type: 'nested_many'
60
+ )
61
+ else
62
+ AttributeField::NestedOneField.new(
63
+ model, name: name, type: 'belongs_to', field_type: 'nested_one'
64
+ )
65
+ end
66
+ elsif reflection.collection?
67
+ remove_counter_cache_column!(name, reflection)
67
68
 
68
- fields_hash[name] = AttributeField::HasManyField.new(
69
- model, name: name, type: 'has_many', field_type: 'multi_select'
70
- )
71
- elsif !reflection.options[:through]
72
- fields_hash[name] = AttributeField::BelongsToField.new(
73
- model, name: name, type: 'belongs_to', field_type: 'selectize'
74
- )
75
- end
69
+ fields_hash[name] = AttributeField::HasManyField.new(
70
+ model, name: name, type: 'has_many', field_type: 'multi_select'
71
+ )
72
+ elsif !reflection.options[:through]
73
+ fields_hash[name] = AttributeField::BelongsToField.new(
74
+ model, name: name, type: 'belongs_to', field_type: 'selectize'
75
+ )
76
76
  end
77
77
  end
78
78
  end
@@ -84,14 +84,23 @@ module Para
84
84
  return unless (inverse_relation = reflection.inverse_of)
85
85
  return unless (counter_name = inverse_relation.options[:counter_cache])
86
86
 
87
- counter_name = if String === counter_name
88
- counter_name
89
- else
90
- "#{ name }_count"
91
- end
87
+ counter_name = if counter_name.is_a?(String)
88
+ counter_name
89
+ else
90
+ "#{name}_count"
91
+ end
92
92
 
93
93
  fields_hash.delete(counter_name)
94
94
  end
95
+
96
+ def through_polymorphic_reflection?(reflection)
97
+ reflection.through_reflection? && (
98
+ (
99
+ reflection.through_reflection.options[:polymorphic] &&
100
+ !reflection.through_reflection.options[:source_type]
101
+ ) || through_polymorphic_reflection?(reflection.through_reflection)
102
+ )
103
+ end
95
104
  end
96
105
  end
97
106
  end
data/lib/para/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Para
4
- VERSION = '0.12.1'
4
+ VERSION = '0.12.3'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: para
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.12.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Valentin Ballestrino
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-06 00:00:00.000000000 Z
11
+ date: 2024-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_decorator
@@ -479,15 +479,13 @@ files:
479
479
  - app/javascripts/para/application.js
480
480
  - app/javascripts/para/controllers/application.js
481
481
  - app/javascripts/para/controllers/index.js
482
+ - app/javascripts/para/controllers/nested_many_input_controller.js
482
483
  - app/javascripts/para/controllers/para_admin_flash_message_controller.js
483
484
  - app/javascripts/para/controllers/para_admin_modal_controller.js
484
485
  - app/javascripts/para/controllers/selectize_field_controller.js
485
486
  - app/javascripts/para/index.js
486
- - app/javascripts/para/inputs/material-input.js
487
487
  - app/javascripts/para/inputs/multi-select-input.js
488
- - app/javascripts/para/inputs/nested_many.js
489
488
  - app/javascripts/para/lib/fetch.js
490
- - app/javascripts/para/lib/page-loading.js
491
489
  - app/javascripts/para/plugins-includes.js.erb
492
490
  - app/javascripts/para/simple_form_extension/colorpicker.js
493
491
  - app/javascripts/para/simple_form_extension/datetimepicker.js
@@ -794,7 +792,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
794
792
  - !ruby/object:Gem::Version
795
793
  version: '0'
796
794
  requirements: []
797
- rubygems_version: 3.4.8
795
+ rubygems_version: 3.5.17
798
796
  signing_key:
799
797
  specification_version: 4
800
798
  summary: Rails admin engine
@@ -1,7 +0,0 @@
1
- $(document).on('page:change turbo:load turbo:frame-load', function() {
2
- return $('body').on('focusin focusout', 'input, select, textarea', function(e) {
3
- var focused;
4
- focused = e.type === 'focusin';
5
- return $(e.target).closest('.form-group').toggleClass('focused', focused);
6
- });
7
- });
@@ -1,42 +0,0 @@
1
- Para.PageLoading = class PageLoading {
2
- constructor() {
3
- this.start = this.start.bind(this);
4
- this.stop = this.stop.bind(this);
5
- }
6
-
7
- start() {
8
- return this.addLoadingMarkup();
9
- }
10
-
11
- stop() {
12
- return this.removeLoadingMarkup();
13
- }
14
-
15
- addLoadingMarkup() {
16
- $('<div/>', {
17
- class: 'loading-overlay',
18
- 'data-loading-overlay': true
19
- }).prependTo('body');
20
-
21
- $('<div/>', {
22
- class: 'loading-spinner',
23
- 'data-loading-spinner': true
24
- }).prependTo('body');
25
- }
26
-
27
- removeLoadingMarkup() {
28
- $('[data-loading-overlay]').remove();
29
- return $('[data-loading-spinner]').remove();
30
- }
31
-
32
- };
33
-
34
- // Global loading manager allowing to
35
- Para.loadingManager = new Para.PageLoading();
36
-
37
- $(document).on('turbo:before-fetch-request', Para.loadingManager.start);
38
-
39
- $(document).on('turbo:load turbo:frame-load turbo:before-stream-render turbo:frame-missing turbo:fetch-request-error', function() {
40
- Para.loadingManager.stop();
41
- return $('body').on('submit', '[data-para-form]:not([data-remote])', Para.loadingManager.start);
42
- });