bullet_train-fields 1.3.21 → 1.3.22

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: b7a0d3f08265c7e50f763434c57c88f284be710d7d63ce0cc8fbaff886311db9
4
- data.tar.gz: b035e5ff82398aa88f30b757516b6c03ac31d01256b88c24c938dec2638c0ffb
3
+ metadata.gz: c547b13d9d1ff85a1cf3eea7e65f028285a26b65c8df77cddd30244fffd4934d
4
+ data.tar.gz: 5070d18444d36f773334b04460e506c5196f8d30f9832a782f6b3221368b0c35
5
5
  SHA512:
6
- metadata.gz: 85e68bcc552bd519e3f6b0d6792109a3e3d2602b943aa29e0806f4b6ef777a6eb371fae067e9e8d8f0feff2cf1cf67353dcf34751900aa6d9965d493f838b862
7
- data.tar.gz: a539896e8d1deabf39906b9e385521975a4816a6a4b3afbbdc058489c4ebf0793a2074f5e4a56ab5e94e3f37d400cccd8324ee25e0c2c6c80b15ab74771cc676
6
+ metadata.gz: 3fbe6e3df3014fe0ae7e5d61ae88643d7c5d7ea4c819f4617b1fb1ee4e735b0b9c38ce111eacff30b14414eb8dd5ca2f4f562929571f9ad8aadaf31e43b7507d
7
+ data.tar.gz: d4edcea75f716cab08849f03414381c6a29b03a5350df76bf5af4717fc0a01862f0cd6b7278e39e9850f7990dfdf44d28ba85a249d7018b0956d6439c03e285c
@@ -0,0 +1,127 @@
1
+ module Fields::AddressFieldHelper
2
+ def populate_country_options
3
+ ([Addresses::Country.find_by(name: "United States"), Addresses::Country.find_by(name: "Canada")] + Addresses::Country.all).map { |country| [country.name, country.id] }.uniq
4
+ end
5
+
6
+ def populate_region_options(address_form)
7
+ return [] if address_form.object.country_id.nil?
8
+ Addresses::Region.where(country_id: address_form.object.country_id).map { |region| [region.name, region.id] }
9
+ end
10
+
11
+ def admin_division_label_for(address_form)
12
+ # using country_id because it's fastest, even if this case statement is hard to read
13
+ admin_divisions_key = case address_form.object.country_id
14
+ when 233, 31, 142, 239, 101
15
+ :states
16
+ when 39
17
+ :provinces_territories
18
+ when 109
19
+ :prefectures
20
+ when 107, 45, 116, 182, 207, 219, 230, 156, 204
21
+ :provinces
22
+ when 14
23
+ :states_territories
24
+ when 59
25
+ :regions
26
+ when 82, 15
27
+ :federal_states
28
+ when 75
29
+ :departments
30
+ when 105
31
+ :counties
32
+ when 214
33
+ :cantons
34
+ else
35
+ :default
36
+ end
37
+ path = [:addresses, :fields, :admin_divisions, admin_divisions_key]
38
+ t(path.compact.join("."))
39
+ end
40
+
41
+ def postal_code_label_for(address_form)
42
+ key = if address_form.object.country_id == 233
43
+ :zip_code
44
+ else
45
+ :postal_code
46
+ end
47
+ path = [:addresses, :fields, key, :label]
48
+ t(path.compact.join("."))
49
+ end
50
+
51
+ def address_formatted(address, one_line: false)
52
+ return "" if address.all_blank?
53
+
54
+ formatted = [
55
+ address.address_one,
56
+ address.address_two,
57
+ address_city_line_formatted(address),
58
+ address.country&.name&.upcase
59
+ ].reject(&:blank?)
60
+
61
+ if one_line
62
+ formatted.join(", ") # simplistic
63
+ else
64
+ simple_format(formatted.join("\n"))
65
+ end
66
+ end
67
+
68
+ def address_city_line_formatted(address)
69
+ country_iso2 = address.country&.iso2 # can be nil or empty
70
+ city = address.city
71
+ region = address.region&.name
72
+ postal_code = address.postal_code
73
+
74
+ # adapted from https://github.com/cainlevy/snail/blob/master/lib/snail.rb
75
+ # using iso2 property here because it's a port of what's used in snail gem
76
+ # will be cleaned up below if parts missing
77
+ formatted = case country_iso2
78
+ when "CN", "IN"
79
+ "#{city}, #{region} #{postal_code}"
80
+ when "BR"
81
+ "#{postal_code} #{city}#{"-" unless city.nil? || city.empty? || region.nil? || region.empty?}#{region}"
82
+ when "MX", "SK"
83
+ "#{postal_code} #{city}, #{region}"
84
+ when "IT"
85
+ "#{postal_code} #{city} #{region}"
86
+ when "BY"
87
+ "#{postal_code} #{city}#{"-" unless city.nil? || city.empty? || region.nil? || region.empty?}#{region}"
88
+ when "US", "CA", "AU", nil, ""
89
+ "#{city} #{region} #{postal_code}"
90
+ when "IL", "DK", "FI", "FR", "DE", "GR", "NO", "ES", "SE", "TR", "CY", "PT", "MK", "BA"
91
+ "#{postal_code} #{city}"
92
+ when "KW", "SY", "OM", "EE", "LU", "BE", "IS", "CH", "AT", "MD", "ME", "RS", "BG", "GE", "PL", "AM", "HR", "RO", "AZ"
93
+ "#{postal_code} #{city}"
94
+ when "NL"
95
+ "#{postal_code} #{city}"
96
+ when "IE"
97
+ "#{city}, #{region}\n#{postal_code}"
98
+ when "GB", "RU", "UA", "JO", "LB", "IR", "SA", "NZ"
99
+ "#{city} #{postal_code}" # Locally these may be on separate lines. The USPS prefers the city line above the country line, though.
100
+ when "EC"
101
+ "#{postal_code} #{city}"
102
+ when "HK", "IQ", "YE", "QA", "AL"
103
+ city.to_s
104
+ when "AE"
105
+ "#{postal_code}\n#{city}"
106
+ when "JP"
107
+ "#{city}, #{region}\n#{postal_code}"
108
+ when "EG", "ZA", "IM", "KZ", "HU"
109
+ "#{city}\n#{postal_code}"
110
+ when "LV"
111
+ "#{city}, LV-#{postal_code}".gsub(/LV-\s*$/, "") # undo if no postal code
112
+ when "LT"
113
+ "LT-#{postal_code} #{city}".gsub(/^LT-\s*/, "") # undo if no postal code
114
+ when "SI"
115
+ "SI-#{postal_code} #{city}".gsub(/^SI-\s*/, "") # undo if no postal code
116
+ when "CZ"
117
+ "#{postal_code} #{region}\n#{city}"
118
+ else
119
+ "#{city} #{region} #{postal_code}"
120
+ end
121
+
122
+ # clean up separators when missing pieces
123
+ formatted.strip # remove extra spaces and newlines before and after
124
+ .gsub(/^,\s*/, "") # remove extra comma from start
125
+ .gsub(/\s*,$/, "") # remove extra comma from end
126
+ end
127
+ end
@@ -0,0 +1,30 @@
1
+ module RefreshFieldsHelper
2
+ def accept_query_string_override_for(form, method)
3
+ field_name = form.field_name(method)
4
+
5
+ new_value = new_value_from_query_string(field_name)
6
+ return if new_value.nil?
7
+
8
+ form.object[method] = new_value
9
+ end
10
+
11
+ private
12
+
13
+ def new_value_from_query_string(field_name)
14
+ params.dig(*params_dig_path_for_field_name(field_name))
15
+ end
16
+
17
+ def params_dig_path_for_field_name(field_name)
18
+ dig_path = []
19
+
20
+ nested_keys = Rack::Utils.parse_nested_query(field_name)
21
+
22
+ while !nested_keys.nil? && nested_keys.keys.size
23
+ key = nested_keys.keys.first
24
+ dig_path << key.to_sym
25
+ nested_keys = nested_keys[key]
26
+ end
27
+
28
+ dig_path
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static values = {
5
+ dependentsSelector: String
6
+ }
7
+
8
+ updateDependents(event) {
9
+ if (!this.hasDependents) { return false }
10
+
11
+ this.dependents.forEach((dependent) => {
12
+ dependent.dispatchEvent(new CustomEvent(`${this.identifier}:updated`, { detail: { event: event }, bubbles: true, cancelable: false }))
13
+ })
14
+ }
15
+
16
+ get hasDependents() {
17
+ return (this.dependents.length > 0)
18
+ }
19
+
20
+ get dependents() {
21
+ if (!this.dependentsSelectorValue) { return [] }
22
+ return document.querySelectorAll(this.dependentsSelectorValue)
23
+ }
24
+ }
@@ -11,6 +11,8 @@ import FileItemController from './fields/file_item_controller'
11
11
  import PasswordController from './fields/password_controller'
12
12
  import PhoneController from './fields/phone_controller'
13
13
  import SuperSelectController from './fields/super_select_controller'
14
+ import DependableController from './dependable_controller'
15
+ import RefreshFieldsController from './refresh_fields_controller'
14
16
 
15
17
  export const controllerDefinitions = [
16
18
  [FieldController, 'fields/field_controller.js'],
@@ -24,6 +26,8 @@ export const controllerDefinitions = [
24
26
  [PasswordController, 'fields/password_controller.js'],
25
27
  [PhoneController, 'fields/phone_controller.js'],
26
28
  [SuperSelectController, 'fields/super_select_controller.js'],
29
+ [DependableController, 'dependable_controller.js'],
30
+ [RefreshFieldsController, 'refresh_fields_controller.js'],
27
31
  ].map(function(d) {
28
32
  const key = d[1]
29
33
  const controller = d[0]
@@ -45,4 +49,6 @@ export {
45
49
  PasswordController,
46
50
  PhoneController,
47
51
  SuperSelectController,
52
+ DependableController,
53
+ RefreshFieldsController,
48
54
  }
@@ -0,0 +1,68 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = [ "field" ]
5
+ static values = {
6
+ valuesStore: { type: Object, default: {} },
7
+ loading: { type: Boolean, default: false }
8
+ }
9
+ static classes = [ "loading" ]
10
+
11
+ updateFrameFromDependentField(event) {
12
+ const field = event?.detail?.event?.detail?.event?.target || // super select nests its original jQuery event, contains <select> target
13
+ event?.detail?.event?.target || // dependable_controller will include the original event in detail
14
+ event?.target // maybe it was fired straight from the field
15
+
16
+ if (!field) { return }
17
+
18
+ this.storeFieldValues()
19
+
20
+ this.loadingValue = true
21
+ this.disableFieldInputWhileRefreshing()
22
+
23
+ const frame = this.element
24
+ frame.src = this.constructNewUrlUpdatingField(field.name, field.value)
25
+ }
26
+
27
+ finishFrameUpdate(event) {
28
+ if (event.target !== this.element) { return }
29
+
30
+ this.restoreFieldValues()
31
+ this.loadingValue = false
32
+ }
33
+
34
+ constructNewUrlUpdatingField(fieldName, fieldValue) {
35
+ const url = new URL(window.location.href)
36
+ url.searchParams.set(fieldName, fieldValue)
37
+
38
+ return url.href
39
+ }
40
+
41
+ disableFieldInputWhileRefreshing() {
42
+ this.fieldTargets.forEach(field => field.disabled = true )
43
+ }
44
+
45
+ loadingValueChanged() {
46
+ if (!this.hasLoadingClass) { return }
47
+ this.element.classList.toggle(...this.loadingClasses, this.loadingValue)
48
+ }
49
+
50
+ storeFieldValues() {
51
+ this.fieldTargets.forEach(field => {
52
+ let storeUpdate = {}
53
+ storeUpdate[field.name] = field.value
54
+ this.valuesStoreValue = Object.assign(this.valuesStoreValue, storeUpdate)
55
+ })
56
+ }
57
+
58
+ restoreFieldValues() {
59
+ this.fieldTargets.forEach(field => {
60
+ const storedValue = this.valuesStoreValue[field.name]
61
+ if (storedValue === undefined) { return }
62
+ field.value = storedValue
63
+ field.dispatchEvent(new Event('change')) // ensures cascading effects, including super-select validating against valid options
64
+ })
65
+
66
+ this.valuesStoreValue = {}
67
+ }
68
+ }
@@ -1,5 +1,5 @@
1
1
  module BulletTrain
2
2
  module Fields
3
- VERSION = "1.3.21"
3
+ VERSION = "1.3.22"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet_train-fields
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.21
4
+ version: 1.3.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Culver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-31 00:00:00.000000000 Z
11
+ date: 2023-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standard
@@ -99,11 +99,14 @@ files:
99
99
  - app/controllers/concerns/fields/date_support.rb
100
100
  - app/controllers/concerns/fields/options_support.rb
101
101
  - app/controllers/concerns/fields/super_select_support.rb
102
+ - app/helpers/fields/address_field_helper.rb
102
103
  - app/helpers/fields/cloudinary_image_helper.rb
103
104
  - app/helpers/fields/html_editor_helper.rb
104
105
  - app/helpers/fields/phone_field_helper.rb
105
106
  - app/helpers/fields/trix_editor_helper.rb
106
107
  - app/helpers/fields_helper.rb
108
+ - app/helpers/refresh_fields_helper.rb
109
+ - app/javascript/controllers/dependable_controller.js
107
110
  - app/javascript/controllers/fields/button_toggle_controller.js
108
111
  - app/javascript/controllers/fields/cloudinary_image_controller.js
109
112
  - app/javascript/controllers/fields/color_picker_controller.js
@@ -116,6 +119,7 @@ files:
116
119
  - app/javascript/controllers/fields/phone_controller.js
117
120
  - app/javascript/controllers/fields/super_select_controller.js
118
121
  - app/javascript/controllers/index.js
122
+ - app/javascript/controllers/refresh_fields_controller.js
119
123
  - app/javascript/index.js
120
124
  - app/javascript/trix_editor.js
121
125
  - config/routes.rb