simple_form_password_with_hints 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []