satis 2.1.5 → 2.1.8
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 +4 -4
- data/app/components/satis/dropdown/component_controller.js +26 -0
- data/app/components/satis/sidebar_menu_item/component.css +4 -0
- data/app/components/satis/sidebar_menu_item/component_controller.js +91 -60
- data/lib/satis/forms/builder.rb +132 -132
- data/lib/satis/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ea32c052f123438b8208bfd8fa7dccfa23f09021f9c7033c5432663dbf719e1
|
4
|
+
data.tar.gz: 73a82438192349081cc304038a73db04cb3b1a1fb503b5170e27c4e9c5568369
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1521ccc6f5a19ac00f532b04ee1e794ba051e956bc95c9ca39b96919f81455130101e69fd09eb452fd51dbcc313041266da24abac4321955cc9b188303dd6e0e
|
7
|
+
data.tar.gz: b4d56886421bcd276828a103bf1611ebe4d3812aa997d5cac043303187cfd8d6846c5e24022f7d8330fb4f6e1e4a13a0975710dcc2ac0ffb510aabf41d174bc8
|
@@ -615,6 +615,32 @@ export default class DropdownComponentController extends ApplicationController {
|
|
615
615
|
this.selectItem(dataDiv)
|
616
616
|
this.setSelectedItem(dataDiv.getAttribute("data-satis-dropdown-item-value"))
|
617
617
|
this.searchQueryValue = ""
|
618
|
+
} else if(this.searchQueryValue?.length > 0) {
|
619
|
+
// hide all items that don't match the search query
|
620
|
+
const searchValue = this.searchQueryValue
|
621
|
+
let matches = []
|
622
|
+
this.itemTargets.forEach((item) => {
|
623
|
+
const text = item.getAttribute("data-satis-dropdown-item-text")
|
624
|
+
const matched = this.needsExactMatchValue
|
625
|
+
? searchValue.localeCompare(text, undefined, { sensitivity: "base" }) === 0
|
626
|
+
: new RegExp(searchValue, "i").test(text)
|
627
|
+
|
628
|
+
const isHidden = item.classList.contains("hidden")
|
629
|
+
if (!isHidden) {
|
630
|
+
if (matched) {
|
631
|
+
matches.push(item)
|
632
|
+
} else {
|
633
|
+
item.classList.toggle("hidden", true)
|
634
|
+
}
|
635
|
+
}
|
636
|
+
})
|
637
|
+
|
638
|
+
// don't show results
|
639
|
+
if (matches.length > 0) {
|
640
|
+
this.showResultsList(event)
|
641
|
+
} else {
|
642
|
+
if (!this.showSelectedItem()) this.hideResultsList(event)
|
643
|
+
}
|
618
644
|
}
|
619
645
|
|
620
646
|
if (itemCount > 0) {
|
@@ -9,6 +9,10 @@
|
|
9
9
|
}
|
10
10
|
}
|
11
11
|
|
12
|
+
&.active > [data-satis-sidebar-menu-item-target="link"] [data-satis-sidebar-menu-item-target="indicator"] {
|
13
|
+
@apply rotate-90;
|
14
|
+
}
|
15
|
+
|
12
16
|
&__link {
|
13
17
|
@apply text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 hover:text-gray-900 w-full flex items-center pl-2 pr-1 py-2 text-left text-sm font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500
|
14
18
|
}
|
@@ -1,87 +1,118 @@
|
|
1
1
|
import ApplicationController from "satis/controllers/application_controller"
|
2
|
-
import {
|
2
|
+
import {debounce} from "satis/utils"
|
3
3
|
|
4
4
|
export default class SidebarMenuItemComponentController extends ApplicationController {
|
5
5
|
static targets = ["link", "indicator", "submenu"]
|
6
6
|
|
7
7
|
connect() {
|
8
8
|
super.connect()
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
let sidebar = el.closest("nav.sidebar")
|
14
|
-
if(sidebar.querySelectorAll('.active').length > 0){
|
15
|
-
sidebar.querySelectorAll('.active').forEach((ele) => {
|
16
|
-
ele.classList.remove("active")
|
17
|
-
ele.classList.remove("focus")
|
18
|
-
})
|
19
|
-
}
|
20
|
-
el.classList.add("active")
|
21
|
-
}
|
22
|
-
})
|
23
|
-
|
24
|
-
if (this.isActive) {
|
25
|
-
this.linkTarget.classList.add("active")
|
26
|
-
|
27
|
-
if (this.hasSubmenuTarget) {
|
28
|
-
this.submenuTarget.classList.remove("hidden")
|
29
|
-
if(!this.submenuTarget.classList.contains("hidden") && !this.indicatorTarget.hasAttribute("data-fa-transform")){
|
30
|
-
this.indicatorTarget.setAttribute("data-fa-transform", "rotate-90")
|
31
|
-
}
|
32
|
-
if (this.linkTarget){
|
33
|
-
this.linkTarget.classList.add("focus")
|
34
|
-
}
|
35
|
-
} else {
|
36
|
-
this.linkTarget.classList.add("focus")
|
9
|
+
if (this.hasSubmenuTarget) {
|
10
|
+
const active = this.isActive
|
11
|
+
if (active) {
|
12
|
+
this.showSubmenu()
|
37
13
|
}
|
38
14
|
}
|
15
|
+
|
16
|
+
this.boundUpdateFocus = this.updateFocus.bind(this)
|
17
|
+
this.boundOpenListener = this.openListener.bind(this)
|
18
|
+
|
19
|
+
this.updateFocus(true)
|
20
|
+
this.element.addEventListener('sts-sidebar-menu-item:open', this.boundOpenListener)
|
21
|
+
window.addEventListener('popstate', debounce(this.boundUpdateFocus, 200))
|
22
|
+
}
|
23
|
+
|
24
|
+
disconnect() {
|
25
|
+
super.disconnect()
|
26
|
+
this.element.removeEventListener('sts-sidebar-menu-item:open', this.boundOpenListener)
|
27
|
+
window.removeEventListener('popstate', debounce(this.boundUpdateFocus, 200))
|
39
28
|
}
|
40
29
|
|
41
30
|
open(event) {
|
42
|
-
if (
|
43
|
-
|
44
|
-
|
45
|
-
|
31
|
+
if (this.hasSubmenuTarget) {
|
32
|
+
const sidebar = this.element.closest('nav.sidebar')
|
33
|
+
sidebar.dispatchEvent(new CustomEvent('sts-sidebar-menu-item:open', { detail: { element: this.element } }))
|
34
|
+
|
35
|
+
if (!this.isSubmenuVisible) {
|
36
|
+
this.showSubmenu()
|
37
|
+
event.preventDefault()
|
38
|
+
} else {
|
39
|
+
this.hideSubmenu()
|
40
|
+
}
|
41
|
+
|
42
|
+
if (this.linkTarget.classList.contains("focus")) {
|
43
|
+
event.preventDefault()
|
44
|
+
} else {
|
45
|
+
this.linkTarget.classList.toggle("focus", true)
|
46
46
|
}
|
47
|
-
event.preventDefault()
|
48
47
|
}
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
} else{
|
56
|
-
this.indicatorTarget.removeAttribute("data-fa-transform", "rotate-90")
|
57
|
-
}
|
58
|
-
event.preventDefault()
|
59
|
-
|
60
|
-
}
|
61
|
-
}
|
48
|
+
}
|
49
|
+
|
50
|
+
openListener(event) {
|
51
|
+
if (event.detail.element !== this.element && !this.element.contains(event.detail.element)) {
|
52
|
+
this.hideSubmenu()
|
53
|
+
this.linkTarget.classList.toggle("focus", false)
|
62
54
|
}
|
63
55
|
}
|
64
56
|
|
65
|
-
|
66
|
-
|
57
|
+
// This method is used to show the submenu
|
58
|
+
showSubmenu() {
|
59
|
+
if (!this.hasSubmenuTarget || this.isSubmenuVisible) return
|
60
|
+
|
61
|
+
this.submenuTarget.classList.toggle("hidden", false)
|
62
|
+
this.element.classList.toggle("active", true)
|
63
|
+
}
|
64
|
+
|
65
|
+
// This method is used to hide the submenu
|
66
|
+
hideSubmenu() {
|
67
|
+
if (!this.hasSubmenuTarget || !this.isSubmenuVisible) return
|
68
|
+
|
69
|
+
this.submenuTarget.classList.toggle("hidden", true)
|
70
|
+
this.element.classList.toggle("active", false)
|
71
|
+
}
|
72
|
+
|
73
|
+
updateFocus(scroll = false) {
|
74
|
+
if (!this.hasLinkTarget) return
|
75
|
+
const focusedItem = this.element.closest('nav.sidebar').querySelector('a.focus')
|
76
|
+
const linkInUrl = this.linkInUrl()
|
77
|
+
if (linkInUrl && (!focusedItem || linkInUrl > this.linkInUrl(focusedItem))) {
|
78
|
+
focusedItem?.classList.toggle("focus", false)
|
79
|
+
this.linkTarget.classList.toggle("focus", true)
|
80
|
+
if (scroll) this.linkTarget.scrollIntoView({ behavior: 'instant', block: 'nearest' })
|
81
|
+
} else
|
82
|
+
this.linkTarget.classList.toggle("focus", false)
|
83
|
+
}
|
84
|
+
|
85
|
+
linkInUrl(target = this.linkTarget) {
|
86
|
+
if(!target || target.href.length === 0 || target.pathname !== window.location.pathname || target.origin !== window.location.origin)
|
87
|
+
return 0
|
88
|
+
|
89
|
+
let c = 1;
|
90
|
+
if(target.hash === window.location.hash) c++
|
91
|
+
window.location.search.split('&').forEach((param) => {if (target.search.includes(param)) c+=2})
|
92
|
+
return c
|
67
93
|
}
|
68
94
|
|
69
95
|
get isActive() {
|
70
|
-
return this.linkInUrl || this.
|
96
|
+
return this.linkInUrl() || this.element.classList.contains("active")
|
97
|
+
|| Array.from(this.element.querySelectorAll('a[data-satis-sidebar-menu-item-target="link"]'))
|
98
|
+
.some((link) => link.classList.contains("active") || this.linkInUrl(link))
|
99
|
+
}
|
100
|
+
|
101
|
+
get isSubmenuVisible() {
|
102
|
+
return !this.submenuTarget.classList.contains("hidden")
|
71
103
|
}
|
72
104
|
|
73
105
|
get hasOpenSubmenus() {
|
74
|
-
return
|
75
|
-
return !el.classList.contains("hidden")
|
76
|
-
// return Array.from(el.querySelectorAll('[data-satis-sidebar-menu-item-target="submenu"]')).some((el) => {
|
77
|
-
// return !el.classList.contains("hidden")
|
78
|
-
// })
|
79
|
-
})
|
106
|
+
return this.openSubmenus.length > 0
|
80
107
|
}
|
81
108
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
109
|
+
/**
|
110
|
+
* Get a list of all open submenus
|
111
|
+
* @returns {NodeListOf<Element>}
|
112
|
+
*/
|
113
|
+
get openSubmenus() {
|
114
|
+
// scope to first match. check if there are any submenus that are not hidden
|
115
|
+
return this.element.querySelectorAll('[data-satis-sidebar-menu-item-target="submenu"]:not([class*="hidden"])')
|
86
116
|
}
|
117
|
+
|
87
118
|
}
|
data/lib/satis/forms/builder.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
3
|
+
require "satis/concerns/contextual_translations"
|
4
|
+
require "satis/forms/concerns/buttons"
|
5
|
+
require "satis/forms/concerns/file"
|
6
|
+
require "satis/forms/concerns/required"
|
7
|
+
require "satis/forms/concerns/select"
|
8
|
+
require "satis/forms/concerns/options"
|
9
9
|
|
10
10
|
module Satis
|
11
11
|
module Forms
|
@@ -27,13 +27,13 @@ module Satis
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# Regular input
|
30
|
-
def input(method, options = {}, &
|
30
|
+
def input(method, options = {}, &)
|
31
31
|
@form_options = options
|
32
32
|
|
33
33
|
options[:input_html] ||= {}
|
34
34
|
options[:input_html][:disabled] = options.delete(:disabled)
|
35
35
|
|
36
|
-
send(input_type_for(method, options), method, options, &
|
36
|
+
send(input_type_for(method, options), method, options, &)
|
37
37
|
end
|
38
38
|
|
39
39
|
# NOTE: TDG - seems to be overwritten below
|
@@ -44,14 +44,14 @@ module Satis
|
|
44
44
|
# end
|
45
45
|
|
46
46
|
# A codemirror editor, backed by a text-area
|
47
|
-
def editor(method, options = {}, &
|
47
|
+
def editor(method, options = {}, &)
|
48
48
|
@form_options = options
|
49
49
|
|
50
|
-
editor_input(method, options, &
|
50
|
+
editor_input(method, options, &)
|
51
51
|
end
|
52
52
|
|
53
53
|
# Simple-form like association
|
54
|
-
def association(name, options, &
|
54
|
+
def association(name, options, &)
|
55
55
|
@form_options = options
|
56
56
|
|
57
57
|
@association = name
|
@@ -59,10 +59,10 @@ module Satis
|
|
59
59
|
|
60
60
|
method = reflection.join_foreign_key
|
61
61
|
|
62
|
-
send(input_type_for(method, options), method, options, &
|
62
|
+
send(input_type_for(method, options), method, options, &)
|
63
63
|
end
|
64
64
|
|
65
|
-
|
65
|
+
alias_method :rails_fields_for, :fields_for
|
66
66
|
|
67
67
|
# Wrapper around fields_for, using Satis::Forms::Builder
|
68
68
|
# Example:
|
@@ -73,7 +73,7 @@ module Satis
|
|
73
73
|
# printers_form.input :name
|
74
74
|
# end
|
75
75
|
# end
|
76
|
-
def fields_for(*args, &
|
76
|
+
def fields_for(*args, &)
|
77
77
|
options = args.extract_options!
|
78
78
|
name = args.first
|
79
79
|
template_object = args.second
|
@@ -88,14 +88,14 @@ module Satis
|
|
88
88
|
html_options[:data] ||= {}
|
89
89
|
html_options[:data] = flatten_hash(html_options[:data])
|
90
90
|
html_options[:data][:controller] =
|
91
|
-
[
|
92
|
-
html_options[:class] = [
|
91
|
+
["satis-fields-for"].concat(options[:html]&.[](:data)&.[](:controller).to_s.split).join(" ")
|
92
|
+
html_options[:class] = ["fields_for"].concat(options[:html]&.[](:class).to_s.split).join(" ")
|
93
93
|
|
94
94
|
options[:builder] ||= if self.class < ActionView::Helpers::FormBuilder
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
95
|
+
self.class
|
96
|
+
else
|
97
|
+
Satis::Forms::Builder
|
98
|
+
end
|
99
99
|
|
100
100
|
# Only do the whole nested-form thing with a collection
|
101
101
|
if show_actions
|
@@ -106,7 +106,7 @@ module Satis
|
|
106
106
|
options: options
|
107
107
|
}
|
108
108
|
tag.div(**html_options) do
|
109
|
-
render
|
109
|
+
render "shared/fields_for", view_options, &block
|
110
110
|
end
|
111
111
|
|
112
112
|
# FIXME: You would want to do this:
|
@@ -116,13 +116,13 @@ module Satis
|
|
116
116
|
else
|
117
117
|
invalid_feedback = nil
|
118
118
|
if @object.errors.messages[name].present?
|
119
|
-
invalid_feedback = tag.div(@object.errors.messages[name].join(
|
120
|
-
|
119
|
+
invalid_feedback = tag.div(@object.errors.messages[name].join(", "),
|
120
|
+
class: "invalid-feedback")
|
121
121
|
end
|
122
122
|
safe_join [
|
123
|
-
|
124
|
-
|
125
|
-
|
123
|
+
invalid_feedback,
|
124
|
+
rails_fields_for(*args, options, &)
|
125
|
+
].compact
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
@@ -130,24 +130,24 @@ module Satis
|
|
130
130
|
options = args.extract_options!
|
131
131
|
form_group(*args, options) do
|
132
132
|
safe_join [
|
133
|
-
|
134
|
-
|
135
|
-
|
133
|
+
(custom_label(*args, options[:label]) unless options[:label] == false),
|
134
|
+
rich_text_area(*args, options)
|
135
|
+
]
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
139
139
|
# A switch backed by a hidden value
|
140
|
-
def switch(method, options = {}, &
|
140
|
+
def switch(method, options = {}, &)
|
141
141
|
@form_options = options
|
142
142
|
|
143
|
-
switch_input(method, options, &
|
143
|
+
switch_input(method, options, &)
|
144
144
|
end
|
145
145
|
|
146
146
|
# A hidden input
|
147
|
-
def hidden(method, options = {}, &
|
147
|
+
def hidden(method, options = {}, &)
|
148
148
|
@form_options = options
|
149
149
|
|
150
|
-
hidden_input(method, options, &
|
150
|
+
hidden_input(method, options, &)
|
151
151
|
end
|
152
152
|
|
153
153
|
# Non public
|
@@ -155,19 +155,19 @@ module Satis
|
|
155
155
|
def input_type_for(method, options)
|
156
156
|
object_type = object_type_for_method(method)
|
157
157
|
input_type = case object_type
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
158
|
+
when :date then :date_time
|
159
|
+
when :datetime then :date_time
|
160
|
+
when :integer then :string
|
161
|
+
when :float then :string
|
162
|
+
else object_type
|
163
|
+
end
|
164
164
|
override_input_type = if options[:as]
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
165
|
+
options[:as]
|
166
|
+
elsif options[:collection]
|
167
|
+
:select
|
168
|
+
elsif options[:url]
|
169
|
+
:dropdown
|
170
|
+
end
|
171
171
|
|
172
172
|
"#{override_input_type || input_type}_input"
|
173
173
|
end
|
@@ -175,38 +175,38 @@ module Satis
|
|
175
175
|
def form_group(method, options = {}, &block)
|
176
176
|
tag.div(class: "form-group form-group-#{method}", data: options.delete(:data)) do
|
177
177
|
safe_join [
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
178
|
+
block.call,
|
179
|
+
hint_text(options[:hint]),
|
180
|
+
error_text(method)
|
181
|
+
].compact
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
185
185
|
def hint_text(text)
|
186
186
|
return if text.nil?
|
187
187
|
|
188
|
-
tag.small text, class:
|
188
|
+
tag.small text, class: "form-text text-muted"
|
189
189
|
end
|
190
190
|
|
191
191
|
# FIXME: These don't work for relations or location_id, error is on location
|
192
192
|
# When using the association helper, we need to set a @assocation variable
|
193
193
|
# any other input should clear it
|
194
194
|
def error_text(method)
|
195
|
-
return if !has_error?(method) && !has_error?(method.to_s.gsub(/_id$/,
|
195
|
+
return if !has_error?(method) && !has_error?(method.to_s.gsub(/_id$/, ""))
|
196
196
|
|
197
197
|
all_errors = @object.errors[method].dup
|
198
|
-
all_errors += @object.errors[method.to_s.gsub(/_id$/,
|
198
|
+
all_errors += @object.errors[method.to_s.gsub(/_id$/, "")] if method.to_s.ends_with?("_id")
|
199
199
|
|
200
|
-
tag.div(all_errors.uniq.join(
|
201
|
-
|
200
|
+
tag.div(all_errors.uniq.join("<br />").html_safe,
|
201
|
+
class: "invalid-feedback")
|
202
202
|
end
|
203
203
|
|
204
204
|
def object_type_for_method(method)
|
205
205
|
result = if @object.respond_to?(:type_for_attribute) && @object.has_attribute?(method)
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
206
|
+
@object.type_for_attribute(method.to_s).try(:type)
|
207
|
+
elsif @object.respond_to?(:column_for_attribute) && @object.has_attribute?(method)
|
208
|
+
@object.column_for_attribute(method).try(:type)
|
209
|
+
end
|
210
210
|
result || :string
|
211
211
|
end
|
212
212
|
|
@@ -220,40 +220,40 @@ module Satis
|
|
220
220
|
all_classes = "#{options[:class]} form-label".strip
|
221
221
|
label(method, title, class: all_classes, data: options[:data]) do |translation|
|
222
222
|
safe_join [
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
223
|
+
tag.span(title || translation, class: required?(method) ? "required" : ""),
|
224
|
+
" ",
|
225
|
+
required(method, options),
|
226
|
+
help(method, options)
|
227
|
+
]
|
228
228
|
end
|
229
229
|
end
|
230
230
|
|
231
231
|
def required(method, _options = {})
|
232
232
|
return unless required?(method)
|
233
233
|
|
234
|
-
tag.i(class:
|
234
|
+
tag.i(class: "fas fa-hexagon-exclamation")
|
235
235
|
end
|
236
236
|
|
237
237
|
def help(method, options = {})
|
238
|
-
text =
|
239
|
-
|
240
|
-
else
|
241
|
-
Satis.config.default_help_text.call(@template, @object, method,
|
242
|
-
@options[:help_scope] || options[:help_scope])
|
243
|
-
end
|
238
|
+
text = options[:help].presence || Satis.config.default_help_text.call(@template, @object, method,
|
239
|
+
@options[:help_scope] || options[:help_scope])
|
244
240
|
|
245
241
|
return if text.blank?
|
246
242
|
|
247
|
-
tag.i(class:
|
243
|
+
tag.i(class: "fal fa-circle-info", "data-controller": "help", "data-help-content-value": text)
|
248
244
|
end
|
249
245
|
|
250
246
|
def hidden_input(method, options = {})
|
251
247
|
hidden_field(method, options[:input_html] || {})
|
252
248
|
end
|
253
249
|
|
250
|
+
def password_input(method, options = {})
|
251
|
+
string_input(method, options.merge(as: :password))
|
252
|
+
end
|
253
|
+
|
254
254
|
# Inputs and helpers
|
255
255
|
def string_input(method, options = {})
|
256
|
-
orig_data = options.fetch(:data, {}).merge(controller:
|
256
|
+
orig_data = options.fetch(:data, {}).merge(controller: "satis-input")
|
257
257
|
scrollable = options.fetch(:scrollable, false)
|
258
258
|
|
259
259
|
css_class = ["form-control"]
|
@@ -261,58 +261,58 @@ module Satis
|
|
261
261
|
css_class << "noscroll" unless scrollable
|
262
262
|
|
263
263
|
data = options[:input_html].fetch(:data, {})
|
264
|
-
data = data.merge(
|
264
|
+
data = data.merge("satis-input-target" => "input")
|
265
265
|
options[:input_html] = options[:input_html].merge(data: data)
|
266
266
|
|
267
267
|
form_group(method, options.merge(data: orig_data)) do
|
268
268
|
safe_join [
|
269
|
-
|
270
|
-
|
271
|
-
|
269
|
+
(custom_label(method, options[:label], options) unless options[:label] == false),
|
270
|
+
string_field(method, merge_input_options({as: options[:as], class: "#{css_class.join(" ")}"}, options[:input_html]))
|
271
|
+
]
|
272
272
|
end
|
273
273
|
end
|
274
274
|
|
275
275
|
def number_input(method, options = {})
|
276
276
|
form_group(method, options) do
|
277
277
|
safe_join [
|
278
|
-
|
279
|
-
|
280
|
-
|
278
|
+
(custom_label(method, options[:label], options) unless options[:label] == false),
|
279
|
+
number_field(method,
|
280
|
+
merge_input_options({class: "form-control #{
|
281
281
|
if has_error?(method)
|
282
|
-
|
283
|
-
end}"
|
284
|
-
|
282
|
+
"is-invalid"
|
283
|
+
end}"}, options[:input_html]))
|
284
|
+
]
|
285
285
|
end
|
286
286
|
end
|
287
287
|
|
288
288
|
def text_input(method, options = {})
|
289
289
|
form_group(method, options) do
|
290
290
|
safe_join [
|
291
|
-
|
292
|
-
|
293
|
-
|
291
|
+
(custom_label(method, options[:label], options) unless options[:label] == false),
|
292
|
+
text_area(method,
|
293
|
+
merge_input_options({class: "form-control #{
|
294
294
|
if has_error?(method)
|
295
|
-
|
296
|
-
end}"
|
297
|
-
|
295
|
+
"is-invalid"
|
296
|
+
end}"}, options[:input_html]))
|
297
|
+
]
|
298
298
|
end
|
299
299
|
end
|
300
300
|
|
301
301
|
def input_array(method, options = {})
|
302
302
|
form_group(method, options) do
|
303
303
|
safe_join [
|
304
|
-
|
305
|
-
|
306
|
-
|
304
|
+
(custom_label(method, options[:label], options) unless options[:label] == false),
|
305
|
+
render(Satis::InputArray::Component.new(form: self, attribute: method, **options))
|
306
|
+
]
|
307
307
|
end
|
308
308
|
end
|
309
309
|
|
310
310
|
def editor_input(method, options = {}, &block)
|
311
311
|
form_group(method, options) do
|
312
312
|
safe_join [
|
313
|
-
|
314
|
-
|
315
|
-
|
313
|
+
(custom_label(method, options[:label], options) unless options[:label] == false),
|
314
|
+
@template.render(Satis::Editor::Component.new(form: self, attribute: method, **options, &block))
|
315
|
+
]
|
316
316
|
end
|
317
317
|
# form_group(method, options) do
|
318
318
|
# safe_join [
|
@@ -343,11 +343,11 @@ module Satis
|
|
343
343
|
|
344
344
|
def boolean_input(method, options = {})
|
345
345
|
form_group(method, options) do
|
346
|
-
tag.div(class:
|
346
|
+
tag.div(class: "custom-control custom-checkbox") do
|
347
347
|
safe_join [
|
348
|
-
|
349
|
-
|
350
|
-
|
348
|
+
check_box(method, merge_input_options({class: "custom-control-input"}, options[:input_html])),
|
349
|
+
label(method, options[:label], class: "custom-control-label")
|
350
|
+
]
|
351
351
|
end
|
352
352
|
end
|
353
353
|
end
|
@@ -357,7 +357,7 @@ module Satis
|
|
357
357
|
def switch_input(method, options = {}, &block)
|
358
358
|
form_group(method, options) do
|
359
359
|
render(Satis::Switch::Component.new(form: self, attribute: method, title: options[:label], **options,
|
360
|
-
|
360
|
+
&block))
|
361
361
|
end
|
362
362
|
end
|
363
363
|
|
@@ -371,10 +371,10 @@ module Satis
|
|
371
371
|
end
|
372
372
|
form_group(method, options) do
|
373
373
|
safe_join [
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
374
|
+
(custom_label(method, options[:label], options) unless options[:label] == false),
|
375
|
+
render(Satis::DateTimePicker::Component.new(form: self, attribute: method, title: options[:label], **options,
|
376
|
+
&block))
|
377
|
+
]
|
378
378
|
end
|
379
379
|
end
|
380
380
|
|
@@ -385,43 +385,43 @@ module Satis
|
|
385
385
|
# 'data-phone-number-target': 'input',
|
386
386
|
# 'data-action': 'keyup->phone-number#change blur->phone-number#change' }
|
387
387
|
|
388
|
-
tag.div(
|
388
|
+
tag.div("data-controller" => "phone-number") do
|
389
389
|
safe_join [
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
390
|
+
hidden_field(method,
|
391
|
+
merge_input_options({class: "form-control", "data-phone-number-target": "hiddenInput"},
|
392
|
+
options[:input_html])),
|
393
|
+
@template.text_field_tag("dummy", @object.try(method), class: "form-control #{
|
394
394
|
if has_error?(method)
|
395
|
-
|
396
|
-
end}",
|
397
|
-
|
398
|
-
|
395
|
+
"is-invalid"
|
396
|
+
end}", "data-phone-number-target": "input",
|
397
|
+
"data-action": "input->phone-number#change")
|
398
|
+
]
|
399
399
|
end
|
400
400
|
end
|
401
401
|
|
402
402
|
def collection_of(input_type, method, options = {})
|
403
403
|
form_builder_method, custom_class, input_builder_method = case input_type
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
404
|
+
when :radio_buttons then [:collection_radio_buttons,
|
405
|
+
"custom-radio", :radio_button]
|
406
|
+
when :check_boxes then [:collection_check_boxes,
|
407
|
+
"custom-checkbox", :check_box]
|
408
|
+
else raise 'Invalid input_type for collection_of, valid input_types are ":radio_buttons", ":check_boxes"'
|
409
|
+
end
|
410
410
|
options[:value_method] ||= :last
|
411
411
|
options[:text_method] ||= options[:label_method] || :first
|
412
412
|
form_group(method, options) do
|
413
413
|
safe_join [
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
414
|
+
(custom_label(method, options[:label], options) unless options[:label] == false),
|
415
|
+
(send(form_builder_method, method, options[:collection], options[:value_method],
|
416
|
+
options[:text_method]) do |b|
|
417
|
+
tag.div(class: "custom-control #{custom_class}") do
|
418
|
+
safe_join [
|
419
|
+
b.send(input_builder_method, options.fetch(:input_html, {}).merge(class: "custom-control-input")),
|
420
|
+
b.label(class: "custom-control-label")
|
421
|
+
]
|
422
|
+
end
|
423
|
+
end)
|
424
|
+
]
|
425
425
|
end
|
426
426
|
end
|
427
427
|
|
@@ -447,9 +447,9 @@ module Satis
|
|
447
447
|
when /password/ then password_field(method, options)
|
448
448
|
# FIXME: Possibly use time_zone_select with dropdown?
|
449
449
|
when /time_zone/ then time_zone_select(method, options.delete(:priority_zones), options,
|
450
|
-
|
450
|
+
{class: "custom-select form-control"})
|
451
451
|
# FIXME: Possibly use country_select with dropdown?
|
452
|
-
when /country/ then country_select(method, options, class:
|
452
|
+
when /country/ then country_select(method, options, class: "custom-select form-control")
|
453
453
|
when /email/ then email_field(method, options)
|
454
454
|
when /phone/ then phone_input(method, options)
|
455
455
|
when /url/ then url_field(method, options)
|
@@ -470,7 +470,7 @@ module Satis
|
|
470
470
|
hash.each_with_object({}) do |(k, v), h|
|
471
471
|
if v.is_a? Hash
|
472
472
|
flatten_hash(v).map do |h_k, h_v|
|
473
|
-
h["#{k}_#{h_k}"
|
473
|
+
h[:"#{k}_#{h_k}"] = h_v
|
474
474
|
end
|
475
475
|
else
|
476
476
|
h[k] = v
|
data/lib/satis/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: satis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom de Grunt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: browser
|