yummy-guide-generic-administrate 0.5.1 → 0.5.4
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/README.md +20 -0
- data/app/helpers/yummy_guide/administrate/number_input_helper.rb +37 -0
- data/app/views/fields/number/_form.html.erb +23 -0
- data/lib/yummy_guide/administrate/engine.rb +8 -0
- data/lib/yummy_guide/administrate/version.rb +1 -1
- data/lib/yummy_guide/administrate.rb +1 -1
- data/spec/views/fields/number/form_spec.rb +48 -0
- data/spec/yummy_guide/administrate/number_input_helper_spec.rb +154 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 387008d1b76513f348890946b449fcc46cdbb4ed61f594378786288baf0e74b7
|
|
4
|
+
data.tar.gz: 672c758ae345bcee1b7726e41bca7f6e7d77b9b5d2f52896ffd5514095d96cf6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dbcf02d875cf41c10c080df757669320a22b9af01377848652445fac1ece7d1473f4c32f465c3c09a871702a3a77b3b28fc7883456f4b3ee25fa393566ab796f
|
|
7
|
+
data.tar.gz: 32b6e0fa25d8c7f5619c021be719cc28e74aa22c7c6f5a2220c0e5397d0589c52ffa26bdb9bb8e4d85213e8f342eb57fe0460ca7d6cc951b54ae552f24c39e1f
|
data/README.md
CHANGED
|
@@ -43,6 +43,8 @@ bundle install
|
|
|
43
43
|
- datetime フィルターや checkbox group の組み立てを補助する helper
|
|
44
44
|
- `YummyGuide::Administrate::DatetimeInputHelper`
|
|
45
45
|
- 管理画面フォーム用の date + time 入力 helper
|
|
46
|
+
- `YummyGuide::Administrate::NumberInputHelper`
|
|
47
|
+
- 管理画面フォーム用の number input text 化 helper
|
|
46
48
|
- 共通 partial / assets
|
|
47
49
|
- collection partial
|
|
48
50
|
- fixed table header partial
|
|
@@ -102,9 +104,14 @@ class Admin::ApplicationController < Administrate::ApplicationController
|
|
|
102
104
|
helper YummyGuide::Administrate::CollectionHelper
|
|
103
105
|
helper YummyGuide::Administrate::DatetimeInputHelper
|
|
104
106
|
helper YummyGuide::Administrate::FilterFormHelper
|
|
107
|
+
helper YummyGuide::Administrate::NumberInputHelper
|
|
105
108
|
end
|
|
106
109
|
```
|
|
107
110
|
|
|
111
|
+
`NumberInputHelper` は `Administrate::ApplicationController` の view helper として
|
|
112
|
+
自動適用されます。`Administrate::ApplicationController` を継承しない独自 admin
|
|
113
|
+
controller で同じ挙動が必要な場合だけ、上記のように明示的に読み込んでください。
|
|
114
|
+
|
|
108
115
|
### Collection partial
|
|
109
116
|
|
|
110
117
|
ホストアプリ側の `app/views/administrate/application/_collection.html.erb` から、
|
|
@@ -293,6 +300,19 @@ def search_term
|
|
|
293
300
|
end
|
|
294
301
|
```
|
|
295
302
|
|
|
303
|
+
### Number input helper
|
|
304
|
+
|
|
305
|
+
Admin/Administrate 画面では、`number_field` / `number_field_tag` を
|
|
306
|
+
`type="text"` かつ `inputmode="decimal"` の input として描画します。これにより、
|
|
307
|
+
ブラウザ標準の number spinner や mouse wheel による意図しない数値変更を避けます。
|
|
308
|
+
|
|
309
|
+
`class`, `id`, `name`, `value`, `data`, `required`, `disabled`, `readonly`,
|
|
310
|
+
`placeholder` などの通常 option は維持されます。`min`, `max`, `step`, `in`,
|
|
311
|
+
`within` は `type="number"` 前提のブラウザ制御なので出力しません。
|
|
312
|
+
|
|
313
|
+
`range_field` / `range_field_tag` は対象外で、従来どおり `type="range"` として描画
|
|
314
|
+
されます。raw HTML の `<input type="number">` は helper を通らないため対象外です。
|
|
315
|
+
|
|
296
316
|
### Asset の読み込み
|
|
297
317
|
|
|
298
318
|
この engine の asset はホストアプリ側で明示的に読み込んでください。
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YummyGuide
|
|
4
|
+
module Administrate
|
|
5
|
+
module NumberInputHelper
|
|
6
|
+
NUMBER_INPUT_CONTROL_OPTIONS = %i[type min max step in within].freeze
|
|
7
|
+
|
|
8
|
+
def number_field(object_name, method, options = {})
|
|
9
|
+
text_field(object_name, method, yummy_guide_administrate_number_input_options(options))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def number_field_tag(name, value = nil, options = {})
|
|
13
|
+
return super if yummy_guide_administrate_range_input?(options)
|
|
14
|
+
|
|
15
|
+
text_field_tag(name, value, yummy_guide_administrate_number_input_options(options))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def yummy_guide_administrate_range_input?(options)
|
|
21
|
+
options[:type].to_s == "range" || options["type"].to_s == "range"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def yummy_guide_administrate_number_input_options(options)
|
|
25
|
+
options = options.to_h.deep_dup
|
|
26
|
+
|
|
27
|
+
NUMBER_INPUT_CONTROL_OPTIONS.each do |option|
|
|
28
|
+
options.delete(option)
|
|
29
|
+
options.delete(option.to_s)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
options[:inputmode] ||= "decimal"
|
|
33
|
+
options
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
# Number Form Partial
|
|
3
|
+
|
|
4
|
+
This partial renders an input element for number attributes.
|
|
5
|
+
Use a text input to avoid browser-provided number spinner controls.
|
|
6
|
+
|
|
7
|
+
## Local variables:
|
|
8
|
+
|
|
9
|
+
- `f`:
|
|
10
|
+
A Rails form generator, used to help create the appropriate input fields.
|
|
11
|
+
- `field`:
|
|
12
|
+
An instance of [Administrate::Field::Number][1].
|
|
13
|
+
A wrapper around the number pulled from the database.
|
|
14
|
+
|
|
15
|
+
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Number
|
|
16
|
+
%>
|
|
17
|
+
|
|
18
|
+
<div class="field-unit__label">
|
|
19
|
+
<%= f.label field.attribute %>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="field-unit__field">
|
|
22
|
+
<%= f.text_field field.attribute, inputmode: "decimal" %>
|
|
23
|
+
</div>
|
|
@@ -16,6 +16,14 @@ module YummyGuide
|
|
|
16
16
|
yummy_guide_administrate/sticky_table_headers.js
|
|
17
17
|
]
|
|
18
18
|
end
|
|
19
|
+
|
|
20
|
+
initializer "yummy_guide.administrate.number_input_helper" do |app|
|
|
21
|
+
app.config.to_prepare do
|
|
22
|
+
next unless defined?(::Administrate::ApplicationController)
|
|
23
|
+
|
|
24
|
+
::Administrate::ApplicationController.helper YummyGuide::Administrate::NumberInputHelper
|
|
25
|
+
end
|
|
26
|
+
end
|
|
19
27
|
end
|
|
20
28
|
end
|
|
21
29
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "rails"
|
|
4
4
|
require "administrate"
|
|
5
5
|
|
|
6
|
+
require_relative "../../app/helpers/yummy_guide/administrate/number_input_helper"
|
|
6
7
|
require_relative "administrate/version"
|
|
7
8
|
require_relative "administrate/engine"
|
|
8
9
|
|
|
@@ -10,4 +11,3 @@ module YummyGuide
|
|
|
10
11
|
module Administrate
|
|
11
12
|
end
|
|
12
13
|
end
|
|
13
|
-
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "nokogiri"
|
|
5
|
+
|
|
6
|
+
RSpec.describe "fields/number/_form" do
|
|
7
|
+
subject(:fragment) { Nokogiri::HTML.fragment(rendered) }
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
stub_const("SpecNumberFormResource", Class.new do
|
|
11
|
+
extend ActiveModel::Naming
|
|
12
|
+
include ActiveModel::Conversion
|
|
13
|
+
|
|
14
|
+
attr_accessor :base_salary
|
|
15
|
+
|
|
16
|
+
def persisted?
|
|
17
|
+
false
|
|
18
|
+
end
|
|
19
|
+
end)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
let(:rendered) do
|
|
23
|
+
view.render(
|
|
24
|
+
partial: "fields/number/form",
|
|
25
|
+
locals: { f: form_builder, field: field }
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
let(:view) do
|
|
30
|
+
ActionView::Base.with_empty_template_cache.new(
|
|
31
|
+
ActionView::LookupContext.new([File.expand_path("../../../../app/views", __dir__)]),
|
|
32
|
+
{},
|
|
33
|
+
nil
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
let(:resource) { SpecNumberFormResource.new }
|
|
38
|
+
let(:form_builder) { ActionView::Helpers::FormBuilder.new(:job_match, resource, view, {}) }
|
|
39
|
+
let(:field) { Struct.new(:attribute).new(:base_salary) }
|
|
40
|
+
|
|
41
|
+
it "renders number attributes as a decimal-friendly text input" do
|
|
42
|
+
input = fragment.at_css('input[name="job_match[base_salary]"]')
|
|
43
|
+
|
|
44
|
+
expect(input["type"]).to eq("text")
|
|
45
|
+
expect(input["inputmode"]).to eq("decimal")
|
|
46
|
+
expect(rendered).not_to include('type="number"')
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "nokogiri"
|
|
5
|
+
|
|
6
|
+
RSpec.describe YummyGuide::Administrate::NumberInputHelper do
|
|
7
|
+
subject(:helper_host) do
|
|
8
|
+
Class.new do
|
|
9
|
+
include ActionView::Context
|
|
10
|
+
include ActionView::Helpers::FormHelper
|
|
11
|
+
include ActionView::Helpers::FormTagHelper
|
|
12
|
+
include ActionView::Helpers::OutputSafetyHelper
|
|
13
|
+
include ActionView::Helpers::TagHelper
|
|
14
|
+
include YummyGuide::Administrate::NumberInputHelper
|
|
15
|
+
end.new
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
before do
|
|
19
|
+
stub_const("SpecNumberInputResource", Class.new do
|
|
20
|
+
extend ActiveModel::Naming
|
|
21
|
+
include ActiveModel::Conversion
|
|
22
|
+
|
|
23
|
+
attr_accessor :base_salary
|
|
24
|
+
|
|
25
|
+
def persisted?
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
end)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
let(:resource) do
|
|
32
|
+
SpecNumberInputResource.new.tap do |record|
|
|
33
|
+
record.base_salary = "123.45"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def fragment(html)
|
|
38
|
+
Nokogiri::HTML.fragment(html)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe "#number_field" do
|
|
42
|
+
it "renders a decimal-friendly text input without number-only control attributes" do
|
|
43
|
+
html = helper_host.number_field(
|
|
44
|
+
:job_match,
|
|
45
|
+
:base_salary,
|
|
46
|
+
class: "payment-input",
|
|
47
|
+
data: { role: "base-salary" },
|
|
48
|
+
required: true,
|
|
49
|
+
disabled: true,
|
|
50
|
+
readonly: true,
|
|
51
|
+
placeholder: "0.0",
|
|
52
|
+
value: "100.5",
|
|
53
|
+
min: 0,
|
|
54
|
+
max: 999,
|
|
55
|
+
step: "any",
|
|
56
|
+
in: 1..10,
|
|
57
|
+
within: 1..10
|
|
58
|
+
)
|
|
59
|
+
input = fragment(html).at_css("input")
|
|
60
|
+
|
|
61
|
+
expect(input["type"]).to eq("text")
|
|
62
|
+
expect(input["inputmode"]).to eq("decimal")
|
|
63
|
+
expect(input["class"]).to eq("payment-input")
|
|
64
|
+
expect(input["id"]).to eq("job_match_base_salary")
|
|
65
|
+
expect(input["name"]).to eq("job_match[base_salary]")
|
|
66
|
+
expect(input["value"]).to eq("100.5")
|
|
67
|
+
expect(input["data-role"]).to eq("base-salary")
|
|
68
|
+
expect(input["required"]).to eq("required")
|
|
69
|
+
expect(input["disabled"]).to eq("disabled")
|
|
70
|
+
expect(input["readonly"]).to eq("readonly")
|
|
71
|
+
expect(input["placeholder"]).to eq("0.0")
|
|
72
|
+
expect(input["min"]).to be_nil
|
|
73
|
+
expect(input["max"]).to be_nil
|
|
74
|
+
expect(input["step"]).to be_nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "keeps range fields as range inputs" do
|
|
78
|
+
input = fragment(helper_host.range_field(:job_match, :base_salary, value: "50")).at_css("input")
|
|
79
|
+
|
|
80
|
+
expect(input["type"]).to eq("range")
|
|
81
|
+
expect(input["value"]).to eq("50")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe "#number_field_tag" do
|
|
86
|
+
it "renders a decimal-friendly text input without number-only control attributes" do
|
|
87
|
+
html = helper_host.number_field_tag(
|
|
88
|
+
"job_match[base_salary]",
|
|
89
|
+
"200.5",
|
|
90
|
+
id: "base_salary",
|
|
91
|
+
class: "payment-input",
|
|
92
|
+
data: { role: "base-salary" },
|
|
93
|
+
required: true,
|
|
94
|
+
disabled: true,
|
|
95
|
+
readonly: true,
|
|
96
|
+
placeholder: "0.0",
|
|
97
|
+
min: 0,
|
|
98
|
+
max: 999,
|
|
99
|
+
step: "any",
|
|
100
|
+
in: 1..10,
|
|
101
|
+
within: 1..10
|
|
102
|
+
)
|
|
103
|
+
input = fragment(html).at_css("input")
|
|
104
|
+
|
|
105
|
+
expect(input["type"]).to eq("text")
|
|
106
|
+
expect(input["inputmode"]).to eq("decimal")
|
|
107
|
+
expect(input["id"]).to eq("base_salary")
|
|
108
|
+
expect(input["name"]).to eq("job_match[base_salary]")
|
|
109
|
+
expect(input["value"]).to eq("200.5")
|
|
110
|
+
expect(input["class"]).to eq("payment-input")
|
|
111
|
+
expect(input["data-role"]).to eq("base-salary")
|
|
112
|
+
expect(input["required"]).to eq("required")
|
|
113
|
+
expect(input["disabled"]).to eq("disabled")
|
|
114
|
+
expect(input["readonly"]).to eq("readonly")
|
|
115
|
+
expect(input["placeholder"]).to eq("0.0")
|
|
116
|
+
expect(input["min"]).to be_nil
|
|
117
|
+
expect(input["max"]).to be_nil
|
|
118
|
+
expect(input["step"]).to be_nil
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "keeps range field tags as range inputs" do
|
|
122
|
+
input = fragment(helper_host.range_field_tag("base_salary", "50")).at_css("input")
|
|
123
|
+
|
|
124
|
+
expect(input["type"]).to eq("range")
|
|
125
|
+
expect(input["value"]).to eq("50")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "keeps explicit range type options as range inputs" do
|
|
129
|
+
input = fragment(helper_host.number_field_tag("base_salary", "50", "type" => "range")).at_css("input")
|
|
130
|
+
|
|
131
|
+
expect(input["type"]).to eq("range")
|
|
132
|
+
expect(input["value"]).to eq("50")
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
describe "form builder integration" do
|
|
137
|
+
it "routes f.number_field through the helper override" do
|
|
138
|
+
form_builder = ActionView::Helpers::FormBuilder.new(:job_match, resource, helper_host, {})
|
|
139
|
+
input = fragment(form_builder.number_field(:base_salary)).at_css("input")
|
|
140
|
+
|
|
141
|
+
expect(input["type"]).to eq("text")
|
|
142
|
+
expect(input["inputmode"]).to eq("decimal")
|
|
143
|
+
expect(input["value"]).to eq("123.45")
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it "keeps f.range_field as a range input" do
|
|
147
|
+
form_builder = ActionView::Helpers::FormBuilder.new(:job_match, resource, helper_host, {})
|
|
148
|
+
input = fragment(form_builder.range_field(:base_salary, value: "50")).at_css("input")
|
|
149
|
+
|
|
150
|
+
expect(input["type"]).to eq("range")
|
|
151
|
+
expect(input["value"]).to eq("50")
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yummy-guide-generic-administrate
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- akatsuki-kk
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: administrate
|
|
@@ -109,6 +109,8 @@ files:
|
|
|
109
109
|
- app/helpers/yummy_guide/administrate/collection_helper.rb
|
|
110
110
|
- app/helpers/yummy_guide/administrate/datetime_input_helper.rb
|
|
111
111
|
- app/helpers/yummy_guide/administrate/filter_form_helper.rb
|
|
112
|
+
- app/helpers/yummy_guide/administrate/number_input_helper.rb
|
|
113
|
+
- app/views/fields/number/_form.html.erb
|
|
112
114
|
- app/views/fields/yummy_guide_administrate/area/picture/_form.html.erb
|
|
113
115
|
- app/views/fields/yummy_guide_administrate/area/picture/_index.html.erb
|
|
114
116
|
- app/views/fields/yummy_guide_administrate/area/picture/_show.html.erb
|
|
@@ -129,6 +131,7 @@ files:
|
|
|
129
131
|
- lib/yummy_guide/administrate/engine.rb
|
|
130
132
|
- lib/yummy_guide/administrate/version.rb
|
|
131
133
|
- spec/spec_helper.rb
|
|
134
|
+
- spec/views/fields/number/form_spec.rb
|
|
132
135
|
- spec/yummy/guide/generic/administrate_spec.rb
|
|
133
136
|
- spec/yummy_guide/administrate/application_dashboard_spec.rb
|
|
134
137
|
- spec/yummy_guide/administrate/collection_helper_spec.rb
|
|
@@ -138,6 +141,7 @@ files:
|
|
|
138
141
|
- spec/yummy_guide/administrate/fields/version_item_field_spec.rb
|
|
139
142
|
- spec/yummy_guide/administrate/fields/version_whodunnit_field_spec.rb
|
|
140
143
|
- spec/yummy_guide/administrate/filter_form_helper_spec.rb
|
|
144
|
+
- spec/yummy_guide/administrate/number_input_helper_spec.rb
|
|
141
145
|
- yummy-guide-generic-administrate.gemspec
|
|
142
146
|
homepage: https://github.com/yummy-guide/generic-administrate
|
|
143
147
|
licenses:
|