simple_form_password_with_hints 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: 98458d88dfc28b816842f0dc56ad249d4b54496e05c266d386b80cb2b4f559e4
4
+ data.tar.gz: 99191725c33b8633b7c2b56d9685201242b4a3e7a793419dea654588ed5d0e0b
5
+ SHA512:
6
+ metadata.gz: 25135c64eafba3a0b3a793c87098ac93fd0d98160effcad1f933c87f7b46745a67ce7b958b71b29d8e12f19e36745d0e9bdc81ec48ea76ce0dcd0b8789f7dc00
7
+ data.tar.gz: 7128e1b3b8c2fc69e0d9bb64d261854203fdaddbce818f8876d4cfdc640f83fe6088b821e68d3bc74055f177760c296f384025ec81e05f0f29820bcb8f249d7e
data/.DS_Store ADDED
Binary file
data/.eslintrc.yml ADDED
@@ -0,0 +1,183 @@
1
+ env:
2
+ browser: true
3
+ es6: true
4
+ extends: "eslint:recommended"
5
+ parserOptions:
6
+ sourceType: 'script'
7
+ rules:
8
+ # key: 0 = allow, 1 = warn, 2 = error
9
+
10
+ # Possible Errors
11
+ no-await-in-loop: 1
12
+ no-console: 1
13
+ no-extra-parens: [1, 'all']
14
+ no-template-curly-in-string: 0
15
+
16
+ # Best Practices
17
+ accessor-pairs: 0
18
+ array-callback-return: 0
19
+ block-scoped-var: 1
20
+ class-methods-use-this: 0
21
+ complexity: 0
22
+ consistent-return: 0
23
+ curly: [1, 'all']
24
+ default-case: 1
25
+ dot-location: [1, 'property']
26
+ dot-notation: 0
27
+ eqeqeq: 1
28
+ guard-for-in: 0
29
+ max-classes-per-file: 0
30
+ no-alert: 1
31
+ no-caller: 1
32
+ no-div-regex: 1
33
+ no-else-return: 0
34
+ no-empty-function: 1
35
+ no-eq-null: 1
36
+ no-eval: 0
37
+ no-extend-native: 0
38
+ no-extra-bind: 0
39
+ no-extra-label: 1
40
+ no-floating-decimal: 1
41
+ no-implicit-coercion: 1
42
+ no-implied-eval: 1
43
+ no-invalid-this: 0
44
+ no-iterator: 1
45
+ no-labels: 0
46
+ no-lone-blocks: 1
47
+ no-loop-func: 1
48
+ no-magic-numbers: 0
49
+ no-multi-spaces: 1
50
+ no-multi-str: 1
51
+ no-new: 0
52
+ no-new-func: 1
53
+ no-new-wrappers: 1
54
+ no-octal-escape: 1
55
+ no-param-reassign: 1
56
+ no-proto: 1
57
+ no-restricted-globals: 1
58
+ no-restricted-properties: 0
59
+ no-return-assign: 1
60
+ no-return-await: 1
61
+ no-script-url: 1
62
+ no-self-compare: 1
63
+ no-sequences: 1
64
+ no-throw-literal: 1
65
+ no-unmodified-loop-condition: 1
66
+ no-unused-expressions: 1
67
+ no-useless-call: 1
68
+ no-useless-concat: 1
69
+ no-useless-return: 1
70
+ no-void: 1
71
+ no-warning-comments: 0
72
+ prefer-named-capture-group: 0
73
+ prefer-promise-reject-errors: 1
74
+ radix: 1
75
+ require-await: 1
76
+ require-unicode-regexp: 0
77
+ vars-on-top: 1
78
+ wrap-iife: 1
79
+ yoda: 1
80
+
81
+ # Strict Mode
82
+ strict: [1, 'safe']
83
+
84
+ # Variables
85
+ init-declarations: 0
86
+ no-label-var: 1
87
+ no-implicit-globals: 0
88
+ no-shadow: 1
89
+ no-undef-init: 1
90
+ no-undefined: 1
91
+ no-use-before-define: 1
92
+
93
+ # Stylistic Issues
94
+ array-bracket-newline: 0
95
+ array-bracket-spacing: [1, 'never']
96
+ array-element-newline: 0
97
+ block-spacing: [1, 'always']
98
+ brace-style: [1, '1tbs']
99
+ camelcase: 1
100
+ capitalized-comments: 0
101
+ comma-dangle: [1, 'never']
102
+ comma-spacing: [1, { "before": false, "after": true }]
103
+ comma-style: 1
104
+ computed-property-spacing: [1, 'never']
105
+ consistent-this: [1, 'that']
106
+ eol-last: 1
107
+ func-call-spacing: [1, 'never']
108
+ func-name-matching: [1, 'always']
109
+ func-names: 0
110
+ func-style: [1, 'expression']
111
+ function-paren-newline: [1, 'never']
112
+ id-blacklist: 0
113
+ id-length: 0
114
+ id-match: 0
115
+ implicit-arrow-linebreak: 0
116
+ indent: [1, 4]
117
+ jsx-quotes: 0
118
+ key-spacing: 1
119
+ keyword-spacing: 1
120
+ line-comment-position: [1, 'above']
121
+ linebreak-style: [1, 'unix']
122
+ lines-around-comment: 0
123
+ lines-between-class-members: [1, 'always', { exceptAfterSingleLine: true }]
124
+ max-depth: [1, 4]
125
+ max-len: 0
126
+ max-lines: 0
127
+ max-lines-per-function: 0
128
+ max-nested-callbacks: 0
129
+ max-params: [1, 4]
130
+ max-statements: 0
131
+ max-statements-per-line: [1, { max: 1 }]
132
+ multiline-comment-style: 0
133
+ multiline-ternary: 0
134
+ new-cap: 1
135
+ new-parens: 1
136
+ newline-per-chained-call: 1
137
+ no-array-constructor: 0
138
+ no-bitwise: 0
139
+ no-continue: 0
140
+ no-inline-comments: 0
141
+ no-lonely-if: 1
142
+ no-mixed-operators: 0
143
+ no-multi-assign: 1
144
+ no-multiple-empty-lines: 1
145
+ no-negated-condition: 0
146
+ no-nested-ternary: 1
147
+ no-new-object: 0
148
+ no-plusplus: 1
149
+ no-restricted-syntax: 0
150
+ no-tabs: 1
151
+ no-ternary: 0
152
+ no-trailing-spaces: 1
153
+ no-underscore-dangle: 1
154
+ no-unneeded-ternary: 1
155
+ no-whitespace-before-property: 1
156
+ nonblock-statement-body-position: 1
157
+ object-curly-newline: 0
158
+ object-curly-spacing: [1, 'always']
159
+ object-property-newline: 0
160
+ one-var: [1, 'consecutive']
161
+ one-var-declaration-per-line: [1, 'always']
162
+ operator-assignment: [1, 'always']
163
+ operator-linebreak: 0
164
+ padded-blocks: [1, 'never']
165
+ padding-line-between-statements: 0
166
+ prefer-object-spread: 0
167
+ quote-props: 0
168
+ quotes: [1, 'single']
169
+ semi: [1, 'always']
170
+ semi-spacing: [1, { before: false, after: true }]
171
+ semi-style: [1, 'last']
172
+ sort-keys: 0
173
+ sort-vars: 0
174
+ space-before-blocks: [1, 'always']
175
+ space-before-function-paren: [1, 'always']
176
+ space-in-parens: [1, 'never']
177
+ space-infix-ops: 0
178
+ space-unary-ops: [1, { words: true, nonwords: false }]
179
+ spaced-comment: [1, 'always', { markers: ["global", "="] }]
180
+ switch-colon-spacing: [1, { after: true, before: false }]
181
+ template-tag-spacing: [1, 'always']
182
+ unicode-bom: [1, 'never']
183
+ wrap-regex: 1
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
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_password_with_hints.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_password_with_hints (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 (4.6.0)
76
+ autoprefixer-rails (>= 9.1.0)
77
+ popper_js (>= 1.14.3, < 2)
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.1)
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.4)
115
+ mini_portile2 (~> 2.6.1)
116
+ racc (~> 1.4)
117
+ orm_adapter (0.5.0)
118
+ pg (1.2.3)
119
+ popper_js (1.16.0)
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_password_with_hints!
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,145 @@
1
+ # simple_form_password_with_hints
2
+
3
+ A nice improvement for the password fields in [Simple Form](https://github.com/heartcombo/simple_form).
4
+
5
+ **Simple Form Password With Hints** aims to add directs (javascript) controls to your password fields in Simple Form.
6
+
7
+
8
+
9
+ ## Installation
10
+
11
+ Add it to your Gemfile:
12
+
13
+ ```ruby
14
+ gem 'simple_form_password_with_hints'
15
+ ```
16
+
17
+ Run the following command to install it:
18
+
19
+ ```console
20
+ bundle install
21
+ ```
22
+
23
+ ### Bootstrap
24
+
25
+ **Simple Form Password With Hints** relies on the [Bootstrap](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:
26
+
27
+ ```console
28
+ rails generate simple_form:install --bootstrap
29
+ ```
30
+
31
+ You have to be sure that you added a copy of the [Bootstrap](http://getbootstrap.com/)
32
+ assets on your application.
33
+
34
+ ## Usage
35
+
36
+ **Simple Form Password With Hints** comes with two new input types. One is meant to replace the standard `:password` field: `:password_with_hints`. The second one is meant to replace the `:password_confirmation` field: `:password_with_sync`.
37
+
38
+ To start using **Simple Form Password With Hints** you just have to change the input type of the `:password` / `:password_confirmation` fields.
39
+
40
+ So basically your field:
41
+ ```erb
42
+ <%= f.input :password %>
43
+ ```
44
+ becomes
45
+ ```erb
46
+ <%= f.input :password,
47
+ as: :password_with_hints,
48
+ validators: {
49
+ length: 6,
50
+ uppercase_char: true,
51
+ lowercase_char: true,
52
+ numeric_char: true,
53
+ special_char: '#&@?!'
54
+ } %>
55
+ ```
56
+
57
+ and your field
58
+ ```erb
59
+ <%= f.input :password_confirmation %>
60
+ ```
61
+ becomes
62
+ ```erb
63
+ <%= f.input :password_confirmation,
64
+ as: :password_with_sync,
65
+ compare_with_field: :password %>
66
+ ```
67
+
68
+ For both kind of fields you can add an option `allow_password_uncloaking: true` which will add an eye on the right side of the field. Clicking on the eye will toggle the visibility of the password field between stars (******) and text (Mypassword!).
69
+
70
+ Of course you can add every other current option to your fields.
71
+
72
+ For `:password_with_hints` field you can safely ignore every validator you don't want to use. Just set the test to false or delete the line.
73
+
74
+ ### Model validation
75
+
76
+ Please keep in mind that the controls are only indicatives, and don't prevent to submit the fields, even when all checks are not filled.
77
+ So you will have to ensure of the password complexity in the model file.
78
+ Basically in your `User` model you will have to add a test like this:
79
+ ```erb
80
+ validate :password_complexity
81
+
82
+ def password_complexity
83
+ # Regexp extracted from https://stackoverflow.com/questions/19605150/regex-for-password-must-contain-at-least-eight-characters-at-least-one-number-a
84
+ return if password.blank? || password =~ /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!,@$%^&*+£µ-]).{8,70}$/
85
+ errors.add :password, 'Your password is not strong enough'
86
+ end
87
+ ```
88
+
89
+ This regex matches the validators:
90
+ ```erb
91
+ validators: {
92
+ length: 8,
93
+ uppercase_char: true,
94
+ lowercase_char: true,
95
+ numeric_char: true,
96
+ special_char: '#?!,@$%^&*+£µ-'
97
+ }
98
+ ```
99
+
100
+ If you use `Devise` you might want to use the gem setup directly. And maybe add the special chars list in the configuration.
101
+ So in you `config/application.rb` you might add `config.allowed_special_chars = '#?!,@$%^&*+£µ-'`.
102
+ And then your regex in the model file should look like that:
103
+ ```erb
104
+ /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#{Rails.application.config.allowed_special_chars}]).{#{Devise.password_length.first},#{Devise.password_length.last}}$/
105
+ ```
106
+ and the validator:
107
+ ```erb
108
+ validators: {
109
+ length: Devise.password_length.first,
110
+ uppercase_char: true,
111
+ lowercase_char: true,
112
+ numeric_char: true,
113
+ special_char: Rails.application.config.allowed_special_chars
114
+ }
115
+ ```
116
+
117
+
118
+ ## I18n
119
+
120
+ **Simple Form With Hints** uses the I18n API to manage the texts displayed. Feel free to overwrite the keys or add languages.
121
+
122
+ ## Information
123
+
124
+ ### Supported Ruby / Rails versions
125
+
126
+ We intend to maintain support for all Ruby / Rails versions that haven't reached end-of-life.
127
+
128
+ For more information about specific versions please check [Ruby](https://www.ruby-lang.org/en/downloads/branches/)
129
+ and [Rails](https://guides.rubyonrails.org/maintenance_policy.html) maintenance policies, and our test matrix.
130
+
131
+ ### Bug reports
132
+
133
+ If you discover any bugs, feel free to create an issue on GitHub. Please add as much information as
134
+ 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.
135
+
136
+ https://github.com/noesya/simple_form_password_with_hints/issues
137
+
138
+ ## Maintainers
139
+
140
+ * Pierre-André Boissinot (https://github.com/pabois)
141
+
142
+
143
+ ## License
144
+
145
+ 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,3 @@
1
+ <svg width="8" height="6" viewBox="0 0 8 6" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M0.5 3.5L2.5 5.5L7.5 0.5" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512.001 512.001"><path d="M316.332 195.662c-4.16-4.16-10.923-4.16-15.083 0s-4.16 10.944 0 15.083c12.075 12.075 18.752 28.139 18.752 45.248 0 35.285-28.715 64-64 64-17.109 0-33.173-6.656-45.248-18.752-4.16-4.16-10.923-4.16-15.083 0-4.16 4.139-4.16 10.923 0 15.083 16.085 16.128 37.525 25.003 60.331 25.003 47.061 0 85.333-38.272 85.333-85.333 0-22.807-8.874-44.247-25.002-60.332zM270.87 172.131c-4.843-.853-9.792-1.472-14.869-1.472-47.061 0-85.333 38.272-85.333 85.333 0 5.077.619 10.027 1.493 14.869.917 5.163 5.419 8.811 10.475 8.811.619 0 1.237-.043 1.877-.171 5.781-1.024 9.664-6.571 8.64-12.352-.661-3.627-1.152-7.317-1.152-11.157 0-35.285 28.715-64 64-64 3.84 0 7.531.491 11.157 1.131 5.675 1.152 11.328-2.859 12.352-8.64 1.024-5.781-2.858-11.328-8.64-12.352z"/><path d="M509.462 249.102c-2.411-2.859-60.117-70.208-139.712-111.445-5.163-2.709-11.669-.661-14.379 4.587-2.709 5.227-.661 11.669 4.587 14.379 61.312 31.744 110.293 81.28 127.04 99.371-25.429 27.541-125.504 128-230.997 128-35.797 0-71.872-8.64-107.264-25.707-5.248-2.581-11.669-.341-14.229 4.971-2.581 5.291-.341 11.669 4.971 14.229 38.293 18.496 77.504 27.84 116.523 27.84 131.435 0 248.555-136.619 253.483-142.443 3.369-3.969 3.348-9.793-.023-13.782zM325.996 118.947c-24.277-8.171-47.829-12.288-69.995-12.288-131.435 0-248.555 136.619-253.483 142.443-3.115 3.669-3.371 9.003-.597 12.992 1.472 2.112 36.736 52.181 97.856 92.779a10.48 10.48 0 005.888 1.792c3.435 0 6.827-1.664 8.875-4.8 3.264-4.885 1.92-11.52-2.987-14.763-44.885-29.845-75.605-65.877-87.104-80.533 24.555-26.667 125.291-128.576 231.552-128.576 19.861 0 41.131 3.755 63.189 11.157 5.589 2.005 11.648-1.088 13.504-6.699 1.878-5.589-1.109-11.626-6.698-13.504z"/><path d="M444.865 67.128c-4.16-4.16-10.923-4.16-15.083 0L67.116 429.795c-4.16 4.16-4.16 10.923 0 15.083a10.716 10.716 0 007.552 3.115c2.731 0 5.461-1.045 7.531-3.115L444.865 82.211c4.16-4.16 4.16-10.923 0-15.083z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 511.992 511.992"><path d="M510.096 249.937c-4.032-5.867-100.928-143.275-254.101-143.275-131.435 0-248.555 136.619-253.483 142.443-3.349 3.968-3.349 9.792 0 13.781C7.44 268.71 124.56 405.329 255.995 405.329S504.549 268.71 509.477 262.886c3.094-3.669 3.371-8.981.619-12.949zM255.995 383.996c-105.365 0-205.547-100.48-230.997-128 25.408-27.541 125.483-128 230.997-128 123.285 0 210.304 100.331 231.552 127.424-24.534 26.645-125.291 128.576-231.552 128.576z"/><path d="M255.995 170.662c-47.061 0-85.333 38.272-85.333 85.333s38.272 85.333 85.333 85.333 85.333-38.272 85.333-85.333-38.272-85.333-85.333-85.333zm0 149.334c-35.285 0-64-28.715-64-64s28.715-64 64-64 64 28.715 64 64-28.715 64-64 64z"/></svg>
@@ -0,0 +1,87 @@
1
+ /*global $, RegExp */
2
+ $(function () {
3
+ 'use strict';
4
+ var getCheckRegex = function (key, $check) {
5
+ var regex,
6
+ min,
7
+ chars;
8
+ switch (key) {
9
+ case 'uppercase':
10
+ regex = '[A-Z]';
11
+ break;
12
+ case 'lowercase':
13
+ regex = '[a-z]';
14
+ break;
15
+ case 'number':
16
+ regex = '[0-9]';
17
+ break;
18
+ case 'special':
19
+ // hyphen must be at the end
20
+ chars = $check.data('chars');
21
+ regex = '[' + chars + ']';
22
+ break;
23
+ case 'length':
24
+ min = $check.data('length');
25
+ regex = '.{' + min + ',128}';
26
+ break;
27
+ default:
28
+ break;
29
+ }
30
+ return regex;
31
+ },
32
+ performCheck = function ($container, key, password) {
33
+ var $check = $('.js-sfpwh-hint-' + key, $container),
34
+ regexKey = getCheckRegex(key, $check),
35
+ regex = new RegExp(regexKey);
36
+ if ($check.length) {
37
+ if (password.match(regex)) {
38
+ $check.removeClass('sfpwh-hint--invalid');
39
+ } else {
40
+ $check.addClass('sfpwh-hint--invalid');
41
+ }
42
+ }
43
+ },
44
+ compareFields = function (e) {
45
+ var $field = $(e.data.$field),
46
+ $target = $(e.data.$target),
47
+ $container = $field.parents('.password_with_sync'),
48
+ $check = $('.js-sfpwh-hint-match', $container);
49
+
50
+ if ($field.val() !== '' && $field.val() === $target.val()) {
51
+ $check.removeClass('sfpwh-hint--invalid');
52
+ } else {
53
+ $check.addClass('sfpwh-hint--invalid');
54
+ }
55
+ };
56
+
57
+ $('.js-sfpwh-hints-input').on('input', function () {
58
+ var $container = $(this).parents('.password_with_hints'),
59
+ checks = ['length', 'uppercase', 'lowercase', 'number', 'special'],
60
+ password = $(this).val(),
61
+ i;
62
+ for (i = 0; i < checks.length; i += 1) {
63
+ performCheck($container, checks[i], password);
64
+ }
65
+ });
66
+
67
+ $('.js-sfpwh-password-toggle').on('click', function () {
68
+ var $container = $(this).parents('.password_with_hints, .password_with_sync'),
69
+ $input = $('.js-sfpwh-input', $container),
70
+ type = $input.attr('type');
71
+ $(this).toggleClass('sfpwh-password-toggle-revealed');
72
+ if (type === 'text') {
73
+ $input.attr('type', 'password');
74
+ } else {
75
+ $input.attr('type', 'text');
76
+ }
77
+ });
78
+
79
+ $('.js-sfpwh-sync-input').each(function (index, value) {
80
+ var $field = $(value),
81
+ $form = $field.parents('form'),
82
+ $target = $('input[name="' + $field.data('link-to') + '"]', $form);
83
+
84
+ $field.on('input', { $field: $field, $target: $target }, compareFields);
85
+ $target.on('input', { $field: $field, $target: $target }, compareFields);
86
+ });
87
+ });
@@ -0,0 +1,46 @@
1
+ .password_with_hints, .password_with_sync
2
+ position: relative
3
+ .sfpwh
4
+ &-controls
5
+ text-align: right
6
+ -moz-user-select: none !important
7
+ -ms-user-select: none !important
8
+ -webkit-user-select: none !important
9
+ user-select: none !important
10
+ & ~.invalid-feedback
11
+ margin-top: -1.275rem
12
+ &-hint
13
+ font-size: 11px
14
+ white-space: nowrap
15
+ &:not(:first-child)
16
+ margin-left: 10px
17
+ &::before
18
+ background-image: asset-url('icon-check.svg')
19
+ background-position: center
20
+ background-repeat: no-repeat
21
+ background-size: 10px auto
22
+ content: ''
23
+ display: inline-block
24
+ height: 10px
25
+ margin-right: 4px
26
+ margin-top: -2px
27
+ vertical-align: middle
28
+ width: 10px
29
+ &--invalid
30
+ &::before
31
+ background-image: asset-url('icon-cancel.svg')
32
+ background-size: 8px auto
33
+ &-password-toggle
34
+ cursor: pointer
35
+ position: absolute
36
+ right: 10px
37
+ top: calc(50% - 9px)
38
+ width: 20px
39
+ &::before
40
+ content: asset-url('icon-eye.svg')
41
+ &-revealed
42
+ &::before
43
+ content: asset-url('icon-eye-slash.svg')
44
+
45
+ .is-invalid ~ .sfpwh-password-toggle
46
+ right: 35px
@@ -0,0 +1,8 @@
1
+ en:
2
+ simple_form_password_with_hints:
3
+ test_chars: "%{min_length} characters minimum"
4
+ test_uppercase: 'Uppercase'
5
+ test_lowercase: 'Lowercase'
6
+ test_numeric: 'Number'
7
+ test_special_char: 'Special character'
8
+ test_fields_matching: 'Fields are similar'
@@ -0,0 +1,76 @@
1
+ class PasswordWithHintsInput < SimpleForm::Inputs::Base
2
+ enable :placeholder, :maxlength, :minlength
3
+
4
+ def input(wrapper_options = nil)
5
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
6
+ merged_input_options[:class] << " js-sfpwh-input js-sfpwh-hints-input "
7
+ @builder.password_field(attribute_name, merged_input_options) +
8
+ password_uncloaking_div +
9
+ template.content_tag(:div, '', class: 'sfpwh-controls js-sfpwh-controls') do
10
+ [
11
+ length_div,
12
+ uppercase_div,
13
+ lowercase_div,
14
+ numeric_div,
15
+ special_char_div,
16
+ ].compact.join.html_safe
17
+ end
18
+ end
19
+
20
+ def password_uncloaking_div
21
+ template.content_tag(
22
+ :span,
23
+ '',
24
+ class: 'sfpwh-password-toggle js-sfpwh-password-toggle'
25
+ ) if options[:allow_password_uncloaking]
26
+ end
27
+
28
+ def length_div
29
+ template.content_tag(
30
+ :span,
31
+ t('simple_form_password_with_hints.test_chars', min_length: options[:validators][:length]),
32
+ data: { length: options[:validators][:length] },
33
+ class: 'sfpwh-hint sfpwh-hint--invalid sfpwh-hint--length js-sfpwh-hint-length'
34
+ ) if should_display?(:length)
35
+ end
36
+
37
+ def uppercase_div
38
+ template.content_tag(
39
+ :span,
40
+ t('simple_form_password_with_hints.test_uppercase'),
41
+ class: 'sfpwh-hint sfpwh-hint--invalid sfpwh-hint--uppercase js-sfpwh-hint-uppercase'
42
+ ) if should_display?(:uppercase_char)
43
+ end
44
+
45
+ def lowercase_div
46
+ template.content_tag(
47
+ :span,
48
+ t('simple_form_password_with_hints.test_lowercase'),
49
+ class: 'sfpwh-hint sfpwh-hint--invalid sfpwh-hint--lowercase js-sfpwh-hint-lowercase'
50
+ ) if should_display?(:lowercase_char)
51
+ end
52
+
53
+ def numeric_div
54
+ template.content_tag(
55
+ :span,
56
+ t('simple_form_password_with_hints.test_numeric'),
57
+ class: 'sfpwh-hint sfpwh-hint--invalid sfpwh-hint--number js-sfpwh-hint-number'
58
+ ) if should_display?(:numeric_char)
59
+ end
60
+
61
+ def special_char_div
62
+ template.content_tag(
63
+ :span,
64
+ t('simple_form_password_with_hints.test_special_char'),
65
+ data: { chars: options[:validators][:special_char] },
66
+ class: 'sfpwh-hint sfpwh-hint--invalid sfpwh-hint--special js-sfpwh-hint-special'
67
+ ) if should_display?(:special_char)
68
+ end
69
+
70
+ private
71
+
72
+ def should_display?(test)
73
+ options.has_key?(:validators) && options[:validators].has_key?(test) && options[:validators][test] != false
74
+ end
75
+
76
+ end
@@ -0,0 +1,41 @@
1
+ class PasswordWithSyncInput < SimpleForm::Inputs::Base
2
+ enable :placeholder, :maxlength, :minlength
3
+
4
+ def input(wrapper_options = nil)
5
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
6
+ merged_input_options[:class] << " js-sfpwh-input js-sfpwh-sync-input "
7
+ if options[:compare_with_field]
8
+ if merged_input_options[:data].nil?
9
+ merged_input_options[:data] = { link_to: linked_field_name }
10
+ else
11
+ merged_input_options[:data][:link_to] = linked_field_name
12
+ end
13
+ @builder.password_field(attribute_name, merged_input_options) +
14
+ password_uncloaking_div +
15
+ template.content_tag(:div, '', class: 'sfpwh-controls js-sfpwh-controls') do
16
+ template.content_tag(
17
+ :span,
18
+ t('simple_form_password_with_hints.test_fields_matching'),
19
+ class: 'sfpwh-hint sfpwh-hint--invalid sfpwh-hint--match js-sfpwh-hint-match'
20
+ )
21
+ end
22
+ else
23
+ @builder.password_field(attribute_name, merged_input_options)
24
+ end
25
+ end
26
+
27
+ def password_uncloaking_div
28
+ template.content_tag(
29
+ :span,
30
+ '',
31
+ class: 'sfpwh-password-toggle js-sfpwh-password-toggle'
32
+ ) if options[:allow_password_uncloaking]
33
+ end
34
+
35
+ def linked_field_name
36
+ "#{@builder.object_name}[#{options[:compare_with_field]}]"
37
+ end
38
+
39
+
40
+
41
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleFormPasswordWithHints
2
+ VERSION = "0.0.1".freeze
3
+ end
@@ -0,0 +1,40 @@
1
+ require 'simple_form_password_with_hints/password_with_hints_input'
2
+ require 'simple_form_password_with_hints/password_with_sync_input'
3
+
4
+ module SimpleFormPasswordWithHints
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
+ SimpleFormPasswordWithHints.add_paths!
40
+ SimpleFormPasswordWithHints.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_password_with_hints/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'simple_form_password_with_hints'
7
+ s.version = SimpleFormPasswordWithHints::VERSION
8
+ s.summary = "Simple Form Password with Hints"
9
+ s.description = "Improve Simple Form basic password field, add controls 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_password_with_hints'
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,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_form_password_with_hints
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-09-22 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 password field, add controls on the field.
70
+ email: pa@boissinot.paris
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - ".DS_Store"
76
+ - ".eslintrc.yml"
77
+ - ".gitignore"
78
+ - ".sass-lint.yml"
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE
82
+ - README.md
83
+ - Rakefile
84
+ - assets/images/icon-cancel.svg
85
+ - assets/images/icon-check.svg
86
+ - assets/images/icon-eye-slash.svg
87
+ - assets/images/icon-eye.svg
88
+ - assets/javascripts/simple_form_password_with_hints.js
89
+ - assets/stylesheets/simple_form_password_with_hints.sass
90
+ - config/locales/en.yml
91
+ - lib/simple_form_password_with_hints.rb
92
+ - lib/simple_form_password_with_hints/password_with_hints_input.rb
93
+ - lib/simple_form_password_with_hints/password_with_sync_input.rb
94
+ - lib/simple_form_password_with_hints/version.rb
95
+ - simple_form_password_with_hints.gemspec
96
+ homepage: https://github.com/noesya/simple_form_password_with_hints
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubygems_version: 3.1.4
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Simple Form Password with Hints
119
+ test_files: []