simple_form_bs5_file_input 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1d471d34041e586ad2c8c3ef309ccb56730677ed198daf08e5a14e014b1f66e2
4
+ data.tar.gz: 45d007078895c2229164228d776be1dd0e2d6182b2140e34d1f91491ce8d1aa7
5
+ SHA512:
6
+ metadata.gz: 8a232a086495c5b63b5228cb01abbffb6e6edccb3234f39a5cd1e816ef4cea5d747a2b145516d3e7562f10d67436991077757cfbde56a41e97f9c646ea8f6e05
7
+ data.tar.gz: b89e928a07c3b264543779b5a798a3b11bbae7d0f9074ce8a1312d74b347023bac1c339198d11e790b1bc1a96a8244b79540a81943aeb2723aa3cc49ae7c158b
data/.eslintrc.yml ADDED
@@ -0,0 +1,180 @@
1
+ env:
2
+ browser: true
3
+ extends: "eslint:recommended"
4
+ rules:
5
+ # key: 0 = allow, 1 = warn, 2 = error
6
+
7
+ # Possible Errors
8
+ no-await-in-loop: 1
9
+ no-console: 1
10
+ no-extra-parens: [1, 'all']
11
+ no-template-curly-in-string: 0
12
+
13
+ # Best Practices
14
+ accessor-pairs: 0
15
+ array-callback-return: 0
16
+ block-scoped-var: 1
17
+ class-methods-use-this: 0
18
+ complexity: 0
19
+ consistent-return: 0
20
+ curly: [1, 'all']
21
+ default-case: 1
22
+ dot-location: [1, 'property']
23
+ dot-notation: 0
24
+ eqeqeq: 1
25
+ guard-for-in: 0
26
+ max-classes-per-file: 0
27
+ no-alert: 1
28
+ no-caller: 1
29
+ no-div-regex: 1
30
+ no-else-return: 0
31
+ no-empty-function: 1
32
+ no-eq-null: 1
33
+ no-eval: 0
34
+ no-extend-native: 0
35
+ no-extra-bind: 0
36
+ no-extra-label: 1
37
+ no-floating-decimal: 1
38
+ no-implicit-coercion: 1
39
+ no-implied-eval: 1
40
+ no-invalid-this: 0
41
+ no-iterator: 1
42
+ no-labels: 0
43
+ no-lone-blocks: 1
44
+ no-loop-func: 1
45
+ no-magic-numbers: 0
46
+ no-multi-spaces: 1
47
+ no-multi-str: 1
48
+ no-new: 0
49
+ no-new-func: 1
50
+ no-new-wrappers: 1
51
+ no-octal-escape: 1
52
+ no-param-reassign: 1
53
+ no-proto: 1
54
+ no-restricted-globals: 1
55
+ no-restricted-properties: 0
56
+ no-return-assign: 1
57
+ no-return-await: 1
58
+ no-script-url: 1
59
+ no-self-compare: 1
60
+ no-sequences: 1
61
+ no-throw-literal: 1
62
+ no-unmodified-loop-condition: 1
63
+ no-unused-expressions: 1
64
+ no-useless-call: 1
65
+ no-useless-concat: 1
66
+ no-useless-return: 1
67
+ no-void: 1
68
+ no-warning-comments: 0
69
+ prefer-named-capture-group: 0
70
+ prefer-promise-reject-errors: 1
71
+ radix: 1
72
+ require-await: 1
73
+ require-unicode-regexp: 0
74
+ vars-on-top: 1
75
+ wrap-iife: 1
76
+ yoda: 1
77
+
78
+ # Strict Mode
79
+ strict: [1, 'safe']
80
+
81
+ # Variables
82
+ init-declarations: 0
83
+ no-label-var: 1
84
+ no-implicit-globals: 0
85
+ no-shadow: 1
86
+ no-undef-init: 1
87
+ no-undefined: 1
88
+ no-use-before-define: 1
89
+
90
+ # Stylistic Issues
91
+ array-bracket-newline: 0
92
+ array-bracket-spacing: [1, 'never']
93
+ array-element-newline: 0
94
+ block-spacing: [1, 'always']
95
+ brace-style: [1, '1tbs']
96
+ camelcase: 1
97
+ capitalized-comments: 0
98
+ comma-dangle: [1, 'never']
99
+ comma-spacing: [1, { "before": false, "after": true }]
100
+ comma-style: 1
101
+ computed-property-spacing: [1, 'never']
102
+ consistent-this: [1, 'that']
103
+ eol-last: 1
104
+ func-call-spacing: [1, 'never']
105
+ func-name-matching: [1, 'always']
106
+ func-names: 0
107
+ func-style: [1, 'expression']
108
+ function-paren-newline: [1, 'never']
109
+ id-blacklist: 0
110
+ id-length: 0
111
+ id-match: 0
112
+ implicit-arrow-linebreak: 0
113
+ indent: [1, 4]
114
+ jsx-quotes: 0
115
+ key-spacing: 1
116
+ keyword-spacing: 1
117
+ line-comment-position: [1, 'above']
118
+ linebreak-style: [1, 'unix']
119
+ lines-around-comment: 0
120
+ lines-between-class-members: [1, 'always', { exceptAfterSingleLine: true }]
121
+ max-depth: [1, 4]
122
+ max-len: 0
123
+ max-lines: 0
124
+ max-lines-per-function: 0
125
+ max-nested-callbacks: 0
126
+ max-params: [1, 4]
127
+ max-statements: 0
128
+ max-statements-per-line: [1, { max: 1 }]
129
+ multiline-comment-style: 0
130
+ multiline-ternary: 0
131
+ new-cap: 1
132
+ new-parens: 1
133
+ newline-per-chained-call: 1
134
+ no-array-constructor: 0
135
+ no-bitwise: 0
136
+ no-continue: 0
137
+ no-inline-comments: 0
138
+ no-lonely-if: 1
139
+ no-mixed-operators: 0
140
+ no-multi-assign: 1
141
+ no-multiple-empty-lines: 1
142
+ no-negated-condition: 0
143
+ no-nested-ternary: 1
144
+ no-new-object: 0
145
+ no-plusplus: 1
146
+ no-restricted-syntax: 0
147
+ no-tabs: 1
148
+ no-ternary: 0
149
+ no-trailing-spaces: 1
150
+ no-underscore-dangle: 1
151
+ no-unneeded-ternary: 1
152
+ no-whitespace-before-property: 1
153
+ nonblock-statement-body-position: 1
154
+ object-curly-newline: 0
155
+ object-curly-spacing: [1, 'always']
156
+ object-property-newline: 0
157
+ one-var: [1, 'consecutive']
158
+ one-var-declaration-per-line: [1, 'always']
159
+ operator-assignment: [1, 'always']
160
+ operator-linebreak: 0
161
+ padded-blocks: [1, 'never']
162
+ padding-line-between-statements: 0
163
+ prefer-object-spread: 0
164
+ quote-props: 0
165
+ quotes: [1, 'single']
166
+ semi: [1, 'always']
167
+ semi-spacing: [1, { before: false, after: true }]
168
+ semi-style: [1, 'last']
169
+ sort-keys: 0
170
+ sort-vars: 0
171
+ space-before-blocks: [1, 'always']
172
+ space-before-function-paren: [1, 'always']
173
+ space-in-parens: [1, 'never']
174
+ space-infix-ops: 0
175
+ space-unary-ops: [1, { words: true, nonwords: false }]
176
+ spaced-comment: [1, 'always', { markers: ["global", "="] }]
177
+ switch-colon-spacing: [1, { after: true, before: false }]
178
+ template-tag-spacing: [1, 'always']
179
+ unicode-bom: [1, 'never']
180
+ wrap-regex: 1
data/.sass-lint.yml ADDED
@@ -0,0 +1,55 @@
1
+ # Linter Options
2
+ options:
3
+ # Don't merge default rules
4
+ merge-default-rules: false
5
+ # Set the formatter to 'html'
6
+ formatter: html
7
+ # Output file instead of logging results
8
+ output-file: 'linters/sass-lint.html'
9
+ # Raise an error if more than 50 warnings are generated
10
+ max-warnings: 50
11
+ # File Options
12
+ files:
13
+ include:
14
+ - 'app/assets/stylesheets/**/*.s+(a|c)ss'
15
+ - 'docs/themes/**/*.s+(a|c)ss'
16
+ ignore:
17
+ - 'vendor/**/*.*'
18
+ # Rule Configuration
19
+ rules:
20
+ class-name-format: 0
21
+ extends-before-mixins: 2
22
+ extends-before-declarations: 2
23
+ mixins-before-declarations:
24
+ - 2
25
+ -
26
+ exclude:
27
+ - breakpoint
28
+ - breakpoint-next
29
+ - breakpoint-min
30
+ - breakpoint-max
31
+ - breakpoint-infix
32
+ - media-breakpoint-up
33
+ - media-breakpoint-down
34
+ - media-breakpoint-between
35
+ - media-breakpoint-only
36
+ - mq
37
+ no-warn: 1
38
+ no-debug: 1
39
+ hex-length:
40
+ - 2
41
+ -
42
+ style: long
43
+ hex-notation:
44
+ - 2
45
+ -
46
+ style: uppercase
47
+ indentation:
48
+ - 4
49
+ -
50
+ size: 4
51
+ property-sort-order:
52
+ - 1
53
+ -
54
+ order: alphabetical
55
+ ignore-custom-properties: false
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ gem 'simple_form'
6
+
7
+ # Specify your gem's dependencies in simple_form_bs5_file_input.gemspec
8
+ gemspec
9
+
10
+ gem 'pg', '~> 1.1'
11
+ gem 'bootsnap', '>= 1.4.4', require: false
12
+ gem 'devise'
13
+ gem 'bootstrap'
14
+ gem 'jquery-rails'
data/Gemfile.lock ADDED
@@ -0,0 +1,202 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ simple_form_bs5_file_input (0.0.1)
5
+ rails
6
+ simple_form
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ actioncable (6.1.4.1)
12
+ actionpack (= 6.1.4.1)
13
+ activesupport (= 6.1.4.1)
14
+ nio4r (~> 2.0)
15
+ websocket-driver (>= 0.6.1)
16
+ actionmailbox (6.1.4.1)
17
+ actionpack (= 6.1.4.1)
18
+ activejob (= 6.1.4.1)
19
+ activerecord (= 6.1.4.1)
20
+ activestorage (= 6.1.4.1)
21
+ activesupport (= 6.1.4.1)
22
+ mail (>= 2.7.1)
23
+ actionmailer (6.1.4.1)
24
+ actionpack (= 6.1.4.1)
25
+ actionview (= 6.1.4.1)
26
+ activejob (= 6.1.4.1)
27
+ activesupport (= 6.1.4.1)
28
+ mail (~> 2.5, >= 2.5.4)
29
+ rails-dom-testing (~> 2.0)
30
+ actionpack (6.1.4.1)
31
+ actionview (= 6.1.4.1)
32
+ activesupport (= 6.1.4.1)
33
+ rack (~> 2.0, >= 2.0.9)
34
+ rack-test (>= 0.6.3)
35
+ rails-dom-testing (~> 2.0)
36
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
37
+ actiontext (6.1.4.1)
38
+ actionpack (= 6.1.4.1)
39
+ activerecord (= 6.1.4.1)
40
+ activestorage (= 6.1.4.1)
41
+ activesupport (= 6.1.4.1)
42
+ nokogiri (>= 1.8.5)
43
+ actionview (6.1.4.1)
44
+ activesupport (= 6.1.4.1)
45
+ builder (~> 3.1)
46
+ erubi (~> 1.4)
47
+ rails-dom-testing (~> 2.0)
48
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
49
+ activejob (6.1.4.1)
50
+ activesupport (= 6.1.4.1)
51
+ globalid (>= 0.3.6)
52
+ activemodel (6.1.4.1)
53
+ activesupport (= 6.1.4.1)
54
+ activerecord (6.1.4.1)
55
+ activemodel (= 6.1.4.1)
56
+ activesupport (= 6.1.4.1)
57
+ activestorage (6.1.4.1)
58
+ actionpack (= 6.1.4.1)
59
+ activejob (= 6.1.4.1)
60
+ activerecord (= 6.1.4.1)
61
+ activesupport (= 6.1.4.1)
62
+ marcel (~> 1.0.0)
63
+ mini_mime (>= 1.1.0)
64
+ activesupport (6.1.4.1)
65
+ concurrent-ruby (~> 1.0, >= 1.0.2)
66
+ i18n (>= 1.6, < 2)
67
+ minitest (>= 5.1)
68
+ tzinfo (~> 2.0)
69
+ zeitwerk (~> 2.3)
70
+ autoprefixer-rails (10.3.3.0)
71
+ execjs (~> 2)
72
+ bcrypt (3.1.16)
73
+ bootsnap (1.9.1)
74
+ msgpack (~> 1.0)
75
+ bootstrap (5.1.0)
76
+ autoprefixer-rails (>= 9.1.0)
77
+ popper_js (>= 2.9.3, < 3)
78
+ sassc-rails (>= 2.0.0)
79
+ builder (3.2.4)
80
+ concurrent-ruby (1.1.9)
81
+ crass (1.0.6)
82
+ devise (4.8.0)
83
+ bcrypt (~> 3.0)
84
+ orm_adapter (~> 0.1)
85
+ railties (>= 4.1.0)
86
+ responders
87
+ warden (~> 1.2.3)
88
+ erubi (1.10.0)
89
+ execjs (2.8.1)
90
+ ffi (1.15.4)
91
+ globalid (0.5.2)
92
+ activesupport (>= 5.0)
93
+ i18n (1.8.10)
94
+ concurrent-ruby (~> 1.0)
95
+ jquery-rails (4.4.0)
96
+ rails-dom-testing (>= 1, < 3)
97
+ railties (>= 4.2.0)
98
+ thor (>= 0.14, < 2.0)
99
+ listen (3.7.0)
100
+ rb-fsevent (~> 0.10, >= 0.10.3)
101
+ rb-inotify (~> 0.9, >= 0.9.10)
102
+ loofah (2.12.0)
103
+ crass (~> 1.0.2)
104
+ nokogiri (>= 1.5.9)
105
+ mail (2.7.1)
106
+ mini_mime (>= 0.1.1)
107
+ marcel (1.0.2)
108
+ method_source (1.0.0)
109
+ mini_mime (1.1.2)
110
+ mini_portile2 (2.6.1)
111
+ minitest (5.14.4)
112
+ msgpack (1.4.2)
113
+ nio4r (2.5.8)
114
+ nokogiri (1.12.5)
115
+ mini_portile2 (~> 2.6.1)
116
+ racc (~> 1.4)
117
+ orm_adapter (0.5.0)
118
+ pg (1.2.3)
119
+ popper_js (2.9.3)
120
+ racc (1.5.2)
121
+ rack (2.2.3)
122
+ rack-test (1.1.0)
123
+ rack (>= 1.0, < 3)
124
+ rails (6.1.4.1)
125
+ actioncable (= 6.1.4.1)
126
+ actionmailbox (= 6.1.4.1)
127
+ actionmailer (= 6.1.4.1)
128
+ actionpack (= 6.1.4.1)
129
+ actiontext (= 6.1.4.1)
130
+ actionview (= 6.1.4.1)
131
+ activejob (= 6.1.4.1)
132
+ activemodel (= 6.1.4.1)
133
+ activerecord (= 6.1.4.1)
134
+ activestorage (= 6.1.4.1)
135
+ activesupport (= 6.1.4.1)
136
+ bundler (>= 1.15.0)
137
+ railties (= 6.1.4.1)
138
+ sprockets-rails (>= 2.0.0)
139
+ rails-dom-testing (2.0.3)
140
+ activesupport (>= 4.2.0)
141
+ nokogiri (>= 1.6)
142
+ rails-html-sanitizer (1.4.2)
143
+ loofah (~> 2.3)
144
+ railties (6.1.4.1)
145
+ actionpack (= 6.1.4.1)
146
+ activesupport (= 6.1.4.1)
147
+ method_source
148
+ rake (>= 0.13)
149
+ thor (~> 1.0)
150
+ rake (13.0.6)
151
+ rb-fsevent (0.11.0)
152
+ rb-inotify (0.10.1)
153
+ ffi (~> 1.0)
154
+ responders (3.0.1)
155
+ actionpack (>= 5.0)
156
+ railties (>= 5.0)
157
+ sassc (2.4.0)
158
+ ffi (~> 1.9)
159
+ sassc-rails (2.1.2)
160
+ railties (>= 4.0.0)
161
+ sassc (>= 2.0)
162
+ sprockets (> 3.0)
163
+ sprockets-rails
164
+ tilt
165
+ simple_form (5.1.0)
166
+ actionpack (>= 5.2)
167
+ activemodel (>= 5.2)
168
+ sprockets (4.0.2)
169
+ concurrent-ruby (~> 1.0)
170
+ rack (> 1, < 3)
171
+ sprockets-rails (3.2.2)
172
+ actionpack (>= 4.0)
173
+ activesupport (>= 4.0)
174
+ sprockets (>= 3.0.0)
175
+ sqlite3 (1.4.2)
176
+ thor (1.1.0)
177
+ tilt (2.0.10)
178
+ tzinfo (2.0.4)
179
+ concurrent-ruby (~> 1.0)
180
+ warden (1.2.9)
181
+ rack (>= 2.0.9)
182
+ websocket-driver (0.7.5)
183
+ websocket-extensions (>= 0.1.0)
184
+ websocket-extensions (0.1.5)
185
+ zeitwerk (2.4.2)
186
+
187
+ PLATFORMS
188
+ ruby
189
+
190
+ DEPENDENCIES
191
+ bootsnap (>= 1.4.4)
192
+ bootstrap
193
+ devise
194
+ jquery-rails
195
+ listen
196
+ pg (~> 1.1)
197
+ simple_form
198
+ simple_form_bs5_file_input!
199
+ sqlite3
200
+
201
+ BUNDLED WITH
202
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Noesya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # simple_form_bs5_file_input
2
+
3
+ A nice improvement for the `file` field in [Simple Form](https://github.com/heartcombo/simple_form).
4
+
5
+ **Simple Form Bootstrap 5 File Input** aims to add directs controls to your file fields in Simple Form.
6
+
7
+
8
+ ## Installation
9
+
10
+ Add it to your Gemfile:
11
+
12
+ ```ruby
13
+ gem 'simple_form_bs5_file_input'
14
+ ```
15
+
16
+ Run the following command to install it:
17
+
18
+ ```console
19
+ bundle install
20
+ ```
21
+
22
+ Add it to your application.sass:
23
+
24
+ ```
25
+ @import 'simple_form_bs5_file_input'
26
+ ```
27
+
28
+ Add it to your application.js:
29
+
30
+ ```
31
+ //= require simple_form_bs5_file_input
32
+ ```
33
+
34
+ ### Active Storage
35
+
36
+ **Simple Form Bootstrap 5 File Input** relies on [Active Storage](https://github.com/rails/rails/tree/main/activestorage), so it presumes that you installed Active Storage.
37
+
38
+ ### Bootstrap
39
+
40
+ **Simple Form Bootstrap 5 File Input** relies on the [Bootstrap 5](http://getbootstrap.com/) markup, so it presumes that you installed Simple Form with the Bootstrap option. To do that you have to use the `bootstrap` option in the Simple Form install generator, like this:
41
+
42
+ ```console
43
+ rails generate simple_form:install --bootstrap
44
+ ```
45
+
46
+ You have to be sure that you added a copy of the [Bootstrap 5](http://getbootstrap.com/)
47
+ assets on your application.
48
+
49
+ ## Usage
50
+ **Simple Form Bootstrap 5 File Input** comes with one new input type which is meant to replace the standard `:file` field: `:single_deletable_file`
51
+
52
+ To start using **Simple Form Bootstrap 5 File Input** you just have to change the input type of the `:file` field to these new kind.
53
+
54
+ So basically your field:
55
+ ```erb
56
+ <%= f.input :my_file %>
57
+ ```
58
+ becomes
59
+ ```erb
60
+ <%= f.input :my_file,
61
+ as: :single_deletable_file %>
62
+ ```
63
+ Of course you can still add the options you want, like for example `input_html: { accept: '.jpg,.jpeg,.png' }`
64
+
65
+ You can also add a direct preview (WARNING: preview can only work with images!) by using `preview: true` or any custom width for the preview: `preview: 500`. If you don't specify the preview size it will be 1000px witdh by default.
66
+ Note that the preview uses the boostrap classes `img-fluid` and `img-thumbnail`.
67
+
68
+
69
+ ### Direct upload
70
+
71
+ The new field is still compatible with the `direct_upload` param.
72
+ ```erb
73
+ <%= f.input :my_file,
74
+ as: :single_deletable_file,
75
+ direct_upload: true %>
76
+ ```
77
+ Please remember to include the `activestorage.js` library in order to use the direct_upload feature.
78
+ Direct upload will send the file BEFORE the page submission. You will get a progress bar in the file field while the file is uploading.
79
+
80
+
81
+ ## I18n
82
+
83
+ **Simple Form Bootstrap 5 File Input** uses the I18n API to manage the texts displayed. Feel free to overwrite the keys or add languages.
84
+
85
+ ## Information
86
+
87
+ ### Supported Ruby / Rails versions
88
+
89
+ We intend to maintain support for all Ruby / Rails versions that haven't reached end-of-life.
90
+
91
+ For more information about specific versions please check [Ruby](https://www.ruby-lang.org/en/downloads/branches/)
92
+ and [Rails](https://guides.rubyonrails.org/maintenance_policy.html) maintenance policies, and our test matrix.
93
+
94
+ ### Bug reports
95
+
96
+ If you discover any bugs, feel free to create an issue on GitHub. Please add as much information as
97
+ possible to help us in fixing the potential bug. We also encourage you to help even more by forking and sending us a pull request.
98
+
99
+ https://github.com/noesya/simple_form_bs5_file_input/issues
100
+
101
+ ## Maintainers
102
+
103
+ * Pierre-André Boissinot (https://github.com/pabois)
104
+
105
+
106
+ ## License
107
+
108
+ MIT License.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512.001 512.001"><path fill="#E40000" d="M294.111 256.001L504.109 46.003c10.523-10.524 10.523-27.586 0-38.109-10.524-10.524-27.587-10.524-38.11 0L256 217.892 46.002 7.894C35.478-2.63 18.416-2.63 7.893 7.894s-10.524 27.586 0 38.109l209.998 209.998L7.893 465.999c-10.524 10.524-10.524 27.586 0 38.109 10.524 10.524 27.586 10.523 38.109 0L256 294.11l209.997 209.998c10.524 10.524 27.587 10.523 38.11 0 10.523-10.524 10.523-27.586 0-38.109L294.111 256.001z"/></svg>
@@ -0,0 +1,85 @@
1
+ /*global $, document, window */
2
+ window.inputSingleDeletableFile = {
3
+ onDelete: function (e) {
4
+ 'use strict';
5
+ var $scope = $(this).parents('.js-sdfi-deletable-file');
6
+ e.preventDefault();
7
+ e.stopPropagation();
8
+ $('.js-sdfi-deletable-file__hidden-field', $scope).val('true');
9
+ $('input[type="file"]', $scope).val('');
10
+ $scope.removeClass('sdfi-deletable-file--with-file');
11
+ // $('.custom-file-preview', scope).hide();
12
+ },
13
+
14
+ onChange: function () {
15
+ 'use strict';
16
+ var $scope = $(this).parents('.js-sdfi-deletable-file'),
17
+ fileName = $(this).val()
18
+ .split('\\')
19
+ .pop(),
20
+ hasPreview = $('.js-sdfi-deletable-file__preview', $scope).length > 0,
21
+ reader,
22
+ size;
23
+ if (fileName !== '') {
24
+ $scope.addClass('sdfi-deletable-file--with-file');
25
+ $('.js-sdfi-deletable-file__label', $scope).html(fileName);
26
+ $('.js-sdfi-deletable-file__hidden-field', $scope).val('');
27
+ }
28
+ // preview
29
+ if (hasPreview && this.files && this.files[0]) {
30
+ size = $('.js-sdfi-deletable-file__preview', $scope).attr('data-size')
31
+ .split('x');
32
+ reader = new FileReader();
33
+ reader.onload = function (e) {
34
+ $('.js-sdfi-deletable-file__preview', $scope).html('<img src="' + e.target.result + '" width="' + size[0] + '" height="auto" class="img-fluid img-thumbnail">');
35
+ };
36
+ reader.readAsDataURL(this.files[0]);
37
+ }
38
+ },
39
+
40
+ bindEvents: function (field) {
41
+ 'use strict';
42
+ // click on the fake "replace file" btn launch the file input choice
43
+ $('.js-sdfi-deletable-file__change-btn', $(field)).on('click', function () {
44
+ $('input[type="file"]', $(field)).click();
45
+ });
46
+ $('.js-sdfi-deletable-file__delete-btn', $(field)).on('click', this.onDelete);
47
+ $('input[type="file"]', $(field)).on('change', this.onChange);
48
+ }
49
+ };
50
+
51
+ $(document).ready(function () {
52
+ 'use strict';
53
+ $('.js-sdfi-deletable-file').each(function () {
54
+ window.inputSingleDeletableFile.bindEvents(this);
55
+ });
56
+ });
57
+
58
+ /* Direct upload methods */
59
+
60
+ window.addEventListener('direct-upload:initialize', function (event) {
61
+ 'use strict';
62
+ var target = event.target,
63
+ $scope = $(target).parents('.js-sdfi-deletable-file');
64
+ $('.sdfi-deletable-file__upload-progress', $scope).css('width', '0%');
65
+ $scope.addClass('sdfi-deletable-file--uploading');
66
+ });
67
+
68
+ window.addEventListener('direct-upload:progress', function (event) {
69
+ 'use strict';
70
+ var target = event.target,
71
+ progress = event.detail.progress,
72
+ $scope = $(target).parents('.js-sdfi-deletable-file');
73
+ $('.sdfi-deletable-file__upload-progress', $scope).css('width', progress + '%');
74
+ });
75
+
76
+ window.addEventListener('direct-upload:error', function (event) {
77
+ 'use strict';
78
+ var target = event.target,
79
+ error = event.detail.error,
80
+ $scope = $(target).parents('.js-sdfi-deletable-file');
81
+ event.preventDefault();
82
+ $('.sdfi-deletable-file__upload-progress', $scope).css('width', '0%');
83
+ $scope.removeClass('sdfi-deletable-file--uploading');
84
+ alert(error);
85
+ });
@@ -0,0 +1,82 @@
1
+ .sdfi-deletable-file
2
+ position: relative
3
+
4
+ &__preview
5
+ margin-top: 1rem
6
+ display: none
7
+
8
+ &__block
9
+ display: none
10
+ padding: 0
11
+ position: relative
12
+
13
+ .btn
14
+ @include gradient-bg($form-file-button-bg)
15
+ border: 0
16
+ border-bottom-right-radius: 0
17
+ border-top-right-radius: 0
18
+ border-right: 1px solid var(--bs-gray-400)
19
+ color: $form-file-button-color
20
+ white-space: nowrap
21
+
22
+ &:focus
23
+ box-shadow: none
24
+
25
+ &:hover:not(:disabled):not([readonly])
26
+ background-color: $form-file-button-hover-bg
27
+
28
+ .sdfi-deletable-file__label
29
+ cursor: pointer
30
+ overflow: hidden
31
+ padding: .25rem .7rem
32
+ text-overflow: ellipsis
33
+ white-space: nowrap
34
+
35
+ &.is-valid
36
+ .btn
37
+ border-right-color: var(--bs-green)
38
+
39
+ &__delete-btn
40
+ align-self: center
41
+ background-color: white
42
+ background-image: asset-url('icon-cancel.svg')
43
+ background-position: center
44
+ background-repeat: no-repeat
45
+ background-size: .9em
46
+ cursor: pointer
47
+ flex-shrink: 0
48
+ height: 1.5rem
49
+ margin-right: .7rem
50
+ margin-top: 1px
51
+ width: calc(0.75em + 0.375rem)
52
+
53
+ &__upload-background, &__upload-progress
54
+ border-radius: .2rem
55
+ display: none
56
+ height: 100%
57
+ left: 0
58
+ position: absolute
59
+ top: 0
60
+
61
+ &__upload-background
62
+ background-color: #FFFFFF
63
+ width: 100%
64
+
65
+ &__upload-progress
66
+ background-color: #E0E0E0
67
+ pointer-events: none
68
+ width: 0%
69
+
70
+ &--with-file
71
+ input[type='file']
72
+ display: none
73
+
74
+ .sdfi-deletable-file__preview
75
+ display: flex
76
+
77
+ .sdfi-deletable-file__block
78
+ display: flex
79
+
80
+ &--uploading
81
+ .sdfi-deletable-file__upload-background, .sdfi-deletable-file__upload-progress
82
+ display: block
@@ -0,0 +1,3 @@
1
+ en:
2
+ simple_form_bs5_file_input:
3
+ replace_file: 'Change the file'
@@ -0,0 +1,3 @@
1
+ fr:
2
+ simple_form_bs5_file_input:
3
+ replace_file: 'Remplacer le fichier'
@@ -0,0 +1,53 @@
1
+ class ActiveRecord::Base
2
+ def self.has_one_attached_deletable(name, dependent: :purge_later)
3
+ class_eval do
4
+ attr_accessor :"#{name}_delete"
5
+ attr_accessor :"#{name}_infos"
6
+
7
+ before_validation { send(name).purge_later if send("#{name}_attachment").present? && send("#{name}_delete") == 'true' }
8
+ after_commit :"resize_#{name}", unless: Proc.new { |u| u.send("#{name}_infos").blank? }
9
+
10
+ define_method :"#{name}_delete=" do |value|
11
+ instance_variable_set :"@#{name}_delete", value
12
+ end
13
+
14
+ define_method :"resize_#{name}" do
15
+ return unless send(name).attached?
16
+
17
+ params = JSON(send("#{name}_infos"))
18
+ # reset the infos to prevent multiple resize if multiple save
19
+ instance_variable_set :"@#{name}_infos", nil
20
+
21
+ # From Rails 6, ImageProcessing uses an 'auto-orient' by default to interpret the EXIF Orientation metadata.
22
+ # We declare it in the transformations hash for Rails 5
23
+ transformations = {
24
+ :'auto-orient' => true,
25
+ crop: "#{params['width'].round}x#{params['height'].round}+#{params['x'].round}+#{params['y'].round}",
26
+ repage: true,
27
+ :'+' => true
28
+ }
29
+
30
+ variant = Rails::VERSION::MAJOR >= 6 ? send(name).variant(**transformations)
31
+ : send(name).variant(combine_options: transformations)
32
+
33
+ variant_url = variant.processed.service_url
34
+ downloaded_image = URI.open(variant_url)
35
+ attachable = { io: downloaded_image, filename: send(name).filename.to_s }
36
+
37
+ if Rails::VERSION::MAJOR >= 6
38
+ # Prevent double-update on the record, losing ActiveModel::Dirty data.
39
+ # Based on Rails source code:
40
+ # - https://github.com/rails/rails/blob/v6.0.2.2/activestorage/lib/active_storage/attached/model.rb
41
+ # - https://github.com/rails/rails/blob/v6.0.2.2/activestorage/lib/active_storage/attached/one.rb
42
+ attachment_change = ActiveStorage::Attached::Changes::CreateOne.new("#{name}", self, attachable)
43
+ attachment_change.save
44
+ attachment_change.upload
45
+ else
46
+ self.send(name).attach(**attachable)
47
+ end
48
+ end
49
+ end
50
+
51
+ has_one_attached name
52
+ end
53
+ end
@@ -0,0 +1,95 @@
1
+ class SingleDeletableFileInput < SimpleForm::Inputs::Base
2
+ delegate :url_helpers, to: 'Rails.application.routes'
3
+
4
+ include ActionView::Helpers::AssetTagHelper
5
+ include ActionDispatch::Routing::PolymorphicRoutes
6
+
7
+ def input(wrapper_options = nil)
8
+ format('
9
+ <div class="sdfi-deletable-file js-sdfi-deletable-file %s">
10
+ %s
11
+ <div class="%s">
12
+ <button type="button" class="btn js-sdfi-deletable-file__change-btn">%s</button>
13
+ <label for="%s" class="sdfi-deletable-file__label js-sdfi-deletable-file__label">
14
+ %s
15
+ </label>
16
+ <div class="sdfi-deletable-file__delete-btn js-sdfi-deletable-file__delete-btn"></div>
17
+ <div class="sdfi-deletable-file__upload-background"></div>
18
+ <div class="sdfi-deletable-file__upload-progress"></div>
19
+ <input type="hidden" name="%s" class="js-sdfi-deletable-file__hidden-field" %s />
20
+ </div>
21
+ %s
22
+ </div>
23
+ ', has_file_class, input_field(wrapper_options), field_classes(wrapper_options), change_file_text, field_id, existing_file_name_or_default_text, input_hidden_name, input_hidden_value, preview_div)
24
+ end
25
+
26
+ def preview_div
27
+ if options[:preview]
28
+ format('<div class="sdfi-deletable-file__preview js-sdfi-deletable-file__preview" data-size="%s">%s</div>', preview_image_width, preview_image_tag)
29
+ end
30
+ end
31
+
32
+ def has_file_class
33
+ 'sdfi-deletable-file--with-file' if should_display_file?
34
+ end
35
+
36
+ def input_field(wrapper_options)
37
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
38
+ if options[:direct_upload]
39
+ merged_input_options[:data] = {} if merged_input_options[:data].nil?
40
+ merged_input_options[:data]['direct-upload-url'] = Rails.application.routes.url_helpers.rails_direct_uploads_path
41
+ end
42
+ @builder.file_field(attribute_name, merged_input_options)
43
+ end
44
+
45
+ def field_classes(wrapper_options)
46
+ # "form-control is-valid single_deletable_file optional"
47
+ "sdfi-deletable-file__block #{merge_wrapper_options(input_html_options, wrapper_options)[:class].join(' ')}"
48
+ end
49
+
50
+ def change_file_text
51
+ I18n.t('simple_form_bs5_file_input.replace_file')
52
+ end
53
+
54
+ def field_id
55
+ "#{object_name}_#{reflection_or_attribute_name}"
56
+ end
57
+
58
+ def existing_file_name_or_default_text
59
+ if should_display_file?
60
+ "#{file_attachment.filename}"
61
+ end
62
+ end
63
+
64
+ def input_hidden_name
65
+ "#{@builder.object_name}[#{attribute_name.to_s}_delete]"
66
+ end
67
+
68
+ def input_hidden_value
69
+ "value='true'" if @builder.object.send("#{attribute_name}_delete") == 'true'
70
+ end
71
+
72
+ private
73
+
74
+ def file_attachment
75
+ @builder.object.send("#{attribute_name}_attachment")
76
+ end
77
+
78
+ def should_display_file?
79
+ file_attachment.present?
80
+ end
81
+
82
+ def preview_image_width
83
+ options[:preview] == true ? default_preview_image_width : options[:preview].to_i
84
+ end
85
+
86
+ def preview_image_tag
87
+ if should_display_file? && file_attachment&.variable?
88
+ image_tag(file_attachment.variant(resize: "#{preview_image_width}x").processed.url, class: 'img-fluid img-thumbnail', width: preview_image_width)
89
+ end
90
+ end
91
+
92
+ def default_preview_image_width
93
+ 1000
94
+ end
95
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleFormBs5FileInput
2
+ VERSION = "0.0.1".freeze
3
+ end
@@ -0,0 +1,40 @@
1
+ require 'has_one_attached_deletable'
2
+ require 'simple_form_bs5_file_input/single_deletable_file_input'
3
+
4
+ module SimpleFormBs5FileInput
5
+ def self.add_paths!
6
+ Sprockets.append_path stylesheets_path
7
+ Sprockets.append_path images_path
8
+ Sprockets.append_path javascripts_path
9
+ end
10
+
11
+ def self.add_locales!
12
+ I18n.load_path += Dir["#{root_path}/config/locales/*.yml"]
13
+ end
14
+
15
+ private
16
+
17
+ def self.stylesheets_path
18
+ File.join assets_path, 'stylesheets'
19
+ end
20
+
21
+ def self.images_path
22
+ File.join assets_path, 'images'
23
+ end
24
+
25
+ def self.javascripts_path
26
+ File.join assets_path, 'javascripts'
27
+ end
28
+
29
+ def self.assets_path
30
+ @assets_path ||= File.join root_path, 'assets'
31
+ end
32
+
33
+ def self.root_path
34
+ @root_path ||= File.expand_path '..', File.dirname(__FILE__)
35
+ end
36
+
37
+ end
38
+
39
+ SimpleFormBs5FileInput.add_paths!
40
+ SimpleFormBs5FileInput.add_locales!
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "simple_form_bs5_file_input/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'simple_form_bs5_file_input'
7
+ s.version = SimpleFormBs5FileInput::VERSION
8
+ s.summary = "Simple Form BS5 File Input"
9
+ s.description = "Improve Simple Form basic input field, add controls/preview on the field."
10
+ s.authors = ["Pierre-andré Boissinot"]
11
+ s.email = 'pa@boissinot.paris'
12
+ s.files = Dir.chdir(File.expand_path('..', __FILE__)) do
13
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
14
+ end
15
+ s.require_paths = ['lib']
16
+ s.homepage =
17
+ 'https://github.com/noesya/simple_form_bs5_file_input'
18
+ s.license = 'MIT'
19
+
20
+ s.add_dependency "rails"
21
+ s.add_dependency "simple_form"
22
+
23
+ s.add_development_dependency "listen"
24
+ s.add_development_dependency "sqlite3"
25
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_form_bs5_file_input
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pierre-andré Boissinot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-10-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: simple_form
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: listen
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Improve Simple Form basic input field, add controls/preview on the field.
70
+ email: pa@boissinot.paris
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - ".eslintrc.yml"
76
+ - ".sass-lint.yml"
77
+ - Gemfile
78
+ - Gemfile.lock
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - assets/images/icon-cancel.svg
83
+ - assets/javascripts/simple_form_bs5_file_input.js
84
+ - assets/stylesheets/simple_form_bs5_file_input.sass
85
+ - config/locales/en.yml
86
+ - config/locales/fr.yml
87
+ - lib/has_one_attached_deletable.rb
88
+ - lib/simple_form_bs5_file_input.rb
89
+ - lib/simple_form_bs5_file_input/single_deletable_file_input.rb
90
+ - lib/simple_form_bs5_file_input/version.rb
91
+ - simple_form_bs5_file_input.gemspec
92
+ homepage: https://github.com/noesya/simple_form_bs5_file_input
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubygems_version: 3.1.4
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Simple Form BS5 File Input
115
+ test_files: []