satis 2.1.5 → 2.1.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|