formstrap 0.4.5 → 0.4.6

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: '0379b9b80ad9551b56d07884264fcc37132b72d5539976ec4034800a09adaeb2'
4
- data.tar.gz: bbd8d0892fce51fa07375b3e6a414e169344825f5da142c5a06ab87a7696424b
3
+ metadata.gz: e4b8936b5898f98f1ec48da9e055b734a5869c3a06878c91c94b3db0511d3412
4
+ data.tar.gz: c7b810c58dd0b5245c41a4a085d744f9daa301d536875c0a4110c36afafa903b
5
5
  SHA512:
6
- metadata.gz: '0788d10916489c6fabe8798a87ffa10a75d46a4e57a2cd8c73455cc64630414ebbdbcfe213041437b22d108df2a3fa986e3692e8ea46ba25fdc28bb068142a42'
7
- data.tar.gz: 3fba876a0ce0c7be868100726d60af6b1b5aae1b8af675e4861b9ba016405920b1ff35f537a12ce9aa10865fb1e599662170446d999a9bc6e69752f9cf2dc252
6
+ metadata.gz: e64b6a8e8817a5770b17b6a420ae9d5d0f3a12263625088a05775a30035c7076999f99c9ce913d68cf1e70183ac9a237e1d905e54b854fe38017e01db3e8b73d
7
+ data.tar.gz: 364f70b46af019753bd9c0b371d5848bf86828007ebb9066fe37dc7d18f8bf99445ae29003aded25ceb497c2364a3d56790044375ca0b1b0b19c26b7ba5ffa98
@@ -4,15 +4,22 @@ import I18n from '../config/i18n'
4
4
 
5
5
  export default class extends Controller {
6
6
  static values = {
7
- selected: Array
7
+ remoteUrl: String,
8
+ remoteValue: String,
9
+ remoteLabel: String,
10
+ remoteQueryParam: String
8
11
  }
9
12
 
10
13
  connect () {
11
- if (this.element.hasAttribute('multiple') || this.element.dataset.tomSelect === 'true') {
14
+ if (this.isMultiple() || this.isTomSelect() || this.isRemote()) {
12
15
  this.initTomSelect()
13
16
  }
14
17
  }
15
18
 
19
+ disconnect () {
20
+ this.element.tomselect.destroy()
21
+ }
22
+
16
23
  defaultOptions () {
17
24
  return {
18
25
  plugins: ['drag_drop', 'caret_position', 'input_autogrow'],
@@ -22,6 +29,29 @@ export default class extends Controller {
22
29
  }
23
30
  }
24
31
 
32
+ isMultiple () {
33
+ return this.element.hasAttribute('multiple')
34
+ }
35
+
36
+ isTomSelect () {
37
+ return this.element.dataset.tomSelect === 'true'
38
+ }
39
+
40
+ isRemote () {
41
+ return this.remoteUrlValue
42
+ }
43
+
44
+ defaultLoadOptions () {
45
+ return (query, callback) => {
46
+ if (!query.length) return callback()
47
+
48
+ fetch(`${this.remoteUrlValue}.json?${this.remoteQueryParamValue}=${encodeURIComponent(query)}`)
49
+ .then(response => response.json())
50
+ .then(data => { callback(data) })
51
+ .catch(() => { callback() })
52
+ }
53
+ }
54
+
25
55
  renderOptions () {
26
56
  return {
27
57
  en: {
@@ -51,7 +81,13 @@ export default class extends Controller {
51
81
  const defaultOptions = this.defaultOptions()
52
82
  const options = {
53
83
  create: this.hasTags(),
54
- items: this.selectedValue
84
+ ...(this.isRemote() && {
85
+ valueField: this.remoteValueValue,
86
+ labelField: this.remoteLabelValue,
87
+ searchField: this.remoteLabelValue,
88
+ load: this.defaultLoadOptions()
89
+ }
90
+ )
55
91
  }
56
92
 
57
93
  /* eslint-disable no-new */
@@ -13398,10 +13398,13 @@ var repeater_controller_default = class extends Controller {
13398
13398
  var import_tom_select = __toESM(require_tom_select_complete());
13399
13399
  var select_controller_default = class extends Controller {
13400
13400
  connect() {
13401
- if (this.element.hasAttribute("multiple") || this.element.dataset.tomSelect === "true") {
13401
+ if (this.isMultiple() || this.isTomSelect() || this.isRemote()) {
13402
13402
  this.initTomSelect();
13403
13403
  }
13404
13404
  }
13405
+ disconnect() {
13406
+ this.element.tomselect.destroy();
13407
+ }
13405
13408
  defaultOptions() {
13406
13409
  return {
13407
13410
  plugins: ["drag_drop", "caret_position", "input_autogrow"],
@@ -13410,6 +13413,26 @@ var select_controller_default = class extends Controller {
13410
13413
  render: this.renderOptions()[i18n_default.locale]
13411
13414
  };
13412
13415
  }
13416
+ isMultiple() {
13417
+ return this.element.hasAttribute("multiple");
13418
+ }
13419
+ isTomSelect() {
13420
+ return this.element.dataset.tomSelect === "true";
13421
+ }
13422
+ isRemote() {
13423
+ return this.remoteUrlValue;
13424
+ }
13425
+ defaultLoadOptions() {
13426
+ return (query, callback) => {
13427
+ if (!query.length)
13428
+ return callback();
13429
+ fetch(`${this.remoteUrlValue}.json?${this.remoteQueryParamValue}=${encodeURIComponent(query)}`).then((response) => response.json()).then((data) => {
13430
+ callback(data);
13431
+ }).catch(() => {
13432
+ callback();
13433
+ });
13434
+ };
13435
+ }
13413
13436
  renderOptions() {
13414
13437
  return {
13415
13438
  en: {
@@ -13437,13 +13460,21 @@ var select_controller_default = class extends Controller {
13437
13460
  const defaultOptions = this.defaultOptions();
13438
13461
  const options = {
13439
13462
  create: this.hasTags(),
13440
- items: this.selectedValue
13463
+ ...this.isRemote() && {
13464
+ valueField: this.remoteValueValue,
13465
+ labelField: this.remoteLabelValue,
13466
+ searchField: this.remoteLabelValue,
13467
+ load: this.defaultLoadOptions()
13468
+ }
13441
13469
  };
13442
13470
  new import_tom_select.default(this.element, { ...defaultOptions, ...options });
13443
13471
  }
13444
13472
  };
13445
13473
  __publicField(select_controller_default, "values", {
13446
- selected: Array
13474
+ remoteUrl: String,
13475
+ remoteValue: String,
13476
+ remoteLabel: String,
13477
+ remoteQueryParam: String
13447
13478
  });
13448
13479
 
13449
13480
  // app/assets/javascripts/formstrap/controllers/textarea_controller.js
@@ -36,7 +36,7 @@ module Formstrap
36
36
  end
37
37
 
38
38
  def attribute_with_id
39
- attribute_with_id = collection? ? "#{association_foreign_key}s" : foreign_key
39
+ attribute_with_id = collection? ? "#{singular_name}_ids" : foreign_key
40
40
 
41
41
  if attribute_with_id.nil?
42
42
  raise(AssociationDoesNotExistError, "Association attribute that was passed does not exist.")
@@ -46,11 +46,28 @@ module Formstrap
46
46
  end
47
47
 
48
48
  def collection
49
- association_class.all.map { |item| [item.to_s, item.id] }
49
+ if remote
50
+ collection_for_values
51
+ else
52
+ association_class.all.map { |item| [item.to_s, item.id] }
53
+ end
50
54
  end
51
55
 
52
56
  private
53
57
 
58
+ def collection_for_values
59
+ if collection?
60
+ form.object.send(attribute).map { |item| option_for_item[item] }
61
+ else
62
+ [option_for_item(form.object.send(attribute))]
63
+ end
64
+ end
65
+
66
+ def option_for_item(item)
67
+ return unless item
68
+ [item.send(remote[:label]), item.send(remote[:value])]
69
+ end
70
+
54
71
  def association_foreign_key
55
72
  reflection.association_foreign_key
56
73
  end
@@ -63,6 +80,10 @@ module Formstrap
63
80
  form.object.class.reflect_on_association(attribute)
64
81
  end
65
82
 
83
+ def singular_name
84
+ reflection.name.to_s.singularize
85
+ end
86
+
66
87
  def association_class
67
88
  reflection.klass
68
89
  end
@@ -85,6 +106,7 @@ module Formstrap
85
106
  tags: tags,
86
107
  controller: "select"
87
108
  },
109
+ remote: remote,
88
110
  multiple: tags,
89
111
  placeholder: placeholder
90
112
  }
@@ -92,7 +92,7 @@ module Formstrap
92
92
  if attached.is_a?(ActiveStorage::Attached::Many)
93
93
  form.object.send(nested_attribute).build
94
94
  else
95
- form.object.send("build_#{nested_attribute}")
95
+ form.object.send(:"build_#{nested_attribute}")
96
96
  end
97
97
  end
98
98
 
@@ -24,7 +24,7 @@ module Formstrap
24
24
  lang: I18n.locale,
25
25
  # button to control a block/line in the editor
26
26
  control: false,
27
- minHeight: '57px',
27
+ minHeight: "57px",
28
28
  theme: "light",
29
29
  # Popup when highlighting text
30
30
  context: false,
@@ -34,11 +34,11 @@ module Formstrap
34
34
  # Options in block/line popup
35
35
  control: [],
36
36
  # Options in format popup
37
- format: %w[text h1 h2 h3 h4],
37
+ format: %w[text h1 h2 h3 h4]
38
38
  },
39
39
  block: {
40
40
  # Outline block/line in the editor
41
- outline: false,
41
+ outline: false
42
42
  },
43
43
  buttons: {
44
44
  # Options when highlighting text
@@ -46,9 +46,9 @@ module Formstrap
46
46
  # Options in toolbar on the right
47
47
  extrabar: %w[],
48
48
  # Options in toolbar on the left
49
- toolbar: %w[format bold italic deleted list table link html],
49
+ toolbar: %w[format bold italic deleted list table link html]
50
50
  },
51
- plugins: %w[emoji linkstyles],
51
+ plugins: %w[emoji linkstyles]
52
52
  }.delete_if { |k, v| v.nil? }
53
53
  end
54
54
  end
@@ -9,7 +9,7 @@ module Formstrap
9
9
  include Formstrap::Wrappable
10
10
 
11
11
  def input_options
12
- keys = attributes - %i[append attribute collection float form input_group include_blank label prepend validate selected tags wrapper]
12
+ keys = attributes - %i[append attribute collection float form input_group include_blank label prepend validate selected tags wrapper remote]
13
13
  options = to_h.slice(*keys)
14
14
  default_input_options.deep_merge(options)
15
15
  end
@@ -35,9 +35,27 @@ module Formstrap
35
35
  private
36
36
 
37
37
  def default_options
38
- selected = attribute.nil? ? nil : form.object&.send(attribute)
39
38
  {
40
- selected: selected
39
+ selected: value
40
+ }
41
+ end
42
+
43
+ def value
44
+ attribute.nil? ? nil : form.object&.send(attribute)
45
+ end
46
+
47
+ def is_remote?
48
+ return false unless remote
49
+ remote.has_key?(:url)
50
+ end
51
+
52
+ def remote_options
53
+ return nil unless is_remote?
54
+ {
55
+ select_remote_url_value: remote[:url],
56
+ select_remote_value_value: remote&.dig(:value) || "name",
57
+ select_remote_label_value: remote&.dig(:label) || "id",
58
+ select_remote_query_param_value: remote&.dig(:query_param) || "search"
41
59
  }
42
60
  end
43
61
 
@@ -48,7 +66,7 @@ module Formstrap
48
66
  data: {
49
67
  tags: tags,
50
68
  controller: "select",
51
- "select_selected_value": select_options[:selected]
69
+ **remote_options
52
70
  },
53
71
  multiple: tags,
54
72
  placeholder: placeholder
@@ -14,7 +14,7 @@ module Formstrap
14
14
  options = {
15
15
  redactor: {
16
16
  context: !toolbar,
17
- extrabar: toolbar,
17
+ extrabar: toolbar
18
18
  }
19
19
  }
20
20
 
@@ -24,7 +24,7 @@ class ViewModel
24
24
 
25
25
  def initialize(hash = {})
26
26
  hash.each do |key, value|
27
- instance_variable_set("@#{key}", value)
27
+ instance_variable_set(:"@#{key}", value)
28
28
  end
29
29
  end
30
30
 
@@ -45,11 +45,11 @@ class ViewModel
45
45
  end
46
46
 
47
47
  def value_for(attribute)
48
- reserved_methods.include?(attribute) ? instance_variable_get("@#{attribute}") : send(attribute)
48
+ reserved_methods.include?(attribute) ? instance_variable_get(:"@#{attribute}") : send(attribute)
49
49
  end
50
50
 
51
51
  def method_missing(m, *args, &block)
52
- instance_variable_get("@#{m}")
52
+ instance_variable_get(:"@#{m}")
53
53
  end
54
54
 
55
55
  def respond_to_missing?
@@ -6,7 +6,21 @@
6
6
  # * +form+ - Form object
7
7
  #
8
8
  # ==== Optional parameters
9
+ # * +append+ - Display as input group with text on the right-hand side
9
10
  # * +collection+ - Values to create option tags for
11
+ # * +float+ - Use floating labels. Defaults to false
12
+ # * +hint+ - Informative text to assist with data input. HTML markup is allowed.
13
+ # * +label+ - Text to display inside label tag. Defaults to the attribute name. Set to false if you don"t want to show a label.
14
+ # * +plaintext+ - Render input as plain text.
15
+ # * +prepend+ - Display as input group with text on the left-hand side
16
+ # * +remote+ - Hash with all options for remote data fetching
17
+ # * +wrapper+ - Hash with all options for the surrounding html tag
18
+ #
19
+ # ==== Remote options
20
+ # * +url+ -- JSON endpoint to fetch data from
21
+ # * +value+ -- JSON attribute to use as the value for the option tag
22
+ # * +label+ -- JSON attribute to use as the label for the option tag
23
+ # * +query_param+ -- The query parameter used for searching the json endpoint, default: "search"
10
24
  #
11
25
  #
12
26
  # ==== Examples
@@ -14,17 +28,25 @@
14
28
  # <%= form_with do |form| %#>
15
29
  # <%= render "formstrap/association", form: form, attribute: :product %#>
16
30
  # <% end %#>
31
+ #
32
+ # Remote data
33
+ # <%= form_with do |form| %#>
34
+ # <%= render "formstrap/association", form: form, attribute: :product, remote: {url: admin_products_path, value: "id", label: "name"} %#>
35
+ # <% end %#>
17
36
 
18
37
  association = Formstrap::AssociationView.new(local_assigns)
19
-
20
38
  %>
21
39
 
22
- <%= render "formstrap/wrapper", association.wrapper_options do %>
23
- <%= render "formstrap/label", association.label_options if association.prepend_label? %>
24
- <%= render "formstrap/input_group", association.input_group_options do %>
25
- <%= form.select(association.attribute_with_id, formstrap: false, choices: association.collection, options: association.select_options, html_options: association.input_options) %>
26
- <% end %>
27
- <%= render "formstrap/validation", association.validation_options if association.validate? %>
28
- <%= render "formstrap/hint", association.hint_options if association.hint? %>
29
- <%= render "formstrap/label", association.label_options if association.append_label? %>
30
- <% end %>
40
+ <%= render(
41
+ "formstrap/select",
42
+ form: form,
43
+ attribute: association.attribute_with_id,
44
+ collection: association.collection,
45
+ wrapper: association.wrapper_options,
46
+ float: association.float,
47
+ hint: association.hint,
48
+ plaintext: association.plaintext,
49
+ prepend: association.prepend,
50
+ append: association.append,
51
+ remote: association.remote
52
+ ) %>
@@ -16,6 +16,13 @@
16
16
  # * +prepend+ - Display as input group with text on the left-hand side
17
17
  # * +tags+ - Allow options to be created dynamically. This will set the multiple attribute to true
18
18
  # * +wrapper+ - Hash with all options for the surrounding html tag
19
+ # * +remote+ - Hash with all options for remote data fetching
20
+ #
21
+ # ==== Remote options
22
+ # * +url+ -- JSON endpoint to fetch data from
23
+ # * +value+ -- JSON attribute to use as the value for the option tag
24
+ # * +label+ -- JSON attribute to use as the label for the option tag
25
+ # * +query_param+ -- The query parameter used for searching the json endpoint
19
26
  #
20
27
  # ==== References
21
28
  # https://headmin.dev/docs/forms/select
@@ -27,6 +34,11 @@
27
34
  # <%= form_with do |form| %#>
28
35
  # <%= render "formstrap/select", form: form, attribute: :color, collection: %w[red green blue] %#>
29
36
  # <% end %#>
37
+ #
38
+ # Remote data
39
+ # <%= form_with do |form| %#>
40
+ # <%= render "formstrap/select", form: form, attribute: :id, collection: [["Page 1", 1]], remote: {url: admin_pages_path, value: "id", label: "title"} %#>
41
+ # <% end %#>
30
42
 
31
43
  select = Formstrap::SelectView.new(local_assigns)
32
44
  %>
@@ -34,7 +46,13 @@
34
46
  <%= render "formstrap/wrapper", select.wrapper_options do %>
35
47
  <%= render "formstrap/label", select.label_options if select.prepend_label? %>
36
48
  <%= render "formstrap/input_group", select.input_group_options do %>
37
- <%= form.select(select.attribute, formstrap: false, choices: select.collection, options: select.select_options, html_options: select.input_options) %>
49
+ <%= form.select(
50
+ select.attribute,
51
+ formstrap: false,
52
+ choices: select.collection,
53
+ options: select.select_options,
54
+ html_options: select.input_options
55
+ ) %>
38
56
  <% end %>
39
57
  <%= render "formstrap/validation", select.validation_options if select.validate? %>
40
58
  <%= render "formstrap/hint", select.hint_options if select.hint? %>
@@ -114,8 +114,8 @@ module Formstrap
114
114
  end
115
115
  end
116
116
 
117
- def repeater_for(attribute, options = {}, &block)
118
- @template.render("formstrap/repeater", form: self, attribute: attribute, **options, &block)
117
+ def repeater_for(attribute, options = {}, &)
118
+ @template.render("formstrap/repeater", form: self, attribute: attribute, **options, &)
119
119
  end
120
120
 
121
121
  def redactor(attribute, formstrap: true, **options)
@@ -1,15 +1,15 @@
1
1
  module Formstrap
2
2
  module FormHelper
3
- def formstrap_form_for(record, options = {}, &block)
3
+ def formstrap_form_for(record, options = {}, &)
4
4
  # ToDo: Can we pass info about the view here (e.g. host, protocol ...)
5
5
  options = options.reverse_merge({builder: Formstrap::FormBuilder})
6
- form_for(record, options, &block)
6
+ form_for(record, options, &)
7
7
  end
8
8
 
9
- def formstrap_form_with(options = {}, &block)
9
+ def formstrap_form_with(options = {}, &)
10
10
  # ToDo: Can we pass info about the view here (e.g. host, protocol ...)
11
11
  options = options.reverse_merge({builder: Formstrap::FormBuilder})
12
- form_with(**options, &block)
12
+ form_with(**options, &)
13
13
  end
14
14
  end
15
15
  end
@@ -1,3 +1,3 @@
1
1
  module Formstrap
2
- VERSION = "0.4.5"
2
+ VERSION = "0.4.6"
3
3
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontierdotbe/formstrap",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "Bootstrap-powered Form Helpers",
5
5
  "module": "app/assets/javascripts/formstrap.js",
6
6
  "main": "app/assets/javascripts/formstrap.js",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: formstrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jef Vlamings
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-21 00:00:00.000000000 Z
11
+ date: 2025-01-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: An extensive Bootstrap form library to power your Ruby On Rails application.
14
14
  email: