rails-fort 0.1.6 → 1.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9924c8ff5baded75fe1dabe106d84dbfd64069dc
4
- data.tar.gz: cf9b5c601665bd00972247bb6fd5746cf0b56790
2
+ SHA256:
3
+ metadata.gz: 4def9cb0b3f3e14b33e1b34efa92e70dba9d7aea7f57cfe69c1d141cbfc5f149
4
+ data.tar.gz: 17bace62f5d924ecf13daf02f8836eb48f3a3e07ee96c7f14235988d1c5d00cf
5
5
  SHA512:
6
- metadata.gz: 84438ba3ea9a63dcde8e88787e3f974a9110b8c78a6bfeb9a9ae82ec0e1df57adc71e48a5ce81d430a61d195efbcfd5bd62c2ccc61c9eca4efe7cdb167f9e7d8
7
- data.tar.gz: 12c353eb6780bf32befea2127f336f971c861ddabc6f9b01b1c23ea8211e963af79fd754a89480b1c582014b9ad8f5f1c0e0374d1edf1ea6f52f0cef1faa7ed5
6
+ metadata.gz: a5a4098a1bb92800febb3bd8ac7df48994b2e5d2b79a8eb144c13dbd98f4f7f5c91d57a2d1071777c5faecb91b1e8c1637e07e0f0bacef54ea75235f35278e6e
7
+ data.tar.gz: 0e54e8564ebceee75c96101308abf3bb31b293def4ba571e098f68366ebf68fae0f0a8f4b2b8966753be216be70536e2105afc2ca13a62e5e4dada221e176194
@@ -0,0 +1,55 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, master ]
6
+ pull_request:
7
+ branches: [ main, master ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ ruby: ['3.0', '3.1', '3.2', '3.3']
16
+ rails: ['6.0', '6.1', '7.0', '7.1', '7.2', '8.0']
17
+ exclude:
18
+ # Rails 7.2+ requires Ruby 3.1+
19
+ - ruby: '3.0'
20
+ rails: '7.2'
21
+ - ruby: '3.0'
22
+ rails: '8.0'
23
+
24
+ env:
25
+ RAILS_VERSION: ${{ matrix.rails }}
26
+
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+
30
+ - name: Set up Ruby
31
+ uses: ruby/setup-ruby@v1
32
+ with:
33
+ ruby-version: ${{ matrix.ruby }}
34
+ bundler-cache: true
35
+
36
+ - name: Run tests
37
+ run: bundle exec rake
38
+
39
+ - name: Run RuboCop
40
+ run: bundle exec rubocop
41
+
42
+ security:
43
+ runs-on: ubuntu-latest
44
+
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+
48
+ - name: Set up Ruby
49
+ uses: ruby/setup-ruby@v1
50
+ with:
51
+ ruby-version: '3.3'
52
+ bundler-cache: true
53
+
54
+ - name: Security audit
55
+ run: bundle exec bundle-audit --update
data/.gitignore CHANGED
@@ -1,9 +1,38 @@
1
+ ## Ruby/Bundler
1
2
  /.bundle/
2
- /.yardoc
3
+ /vendor/bundle/
3
4
  /Gemfile.lock
5
+
6
+ ## Documentation
7
+ /.yardoc/
4
8
  /_yardoc/
5
- /coverage/
6
9
  /doc/
7
- /pkg/
10
+ /rdoc/
11
+
12
+ ## Testing
13
+ /coverage/
8
14
  /spec/reports/
15
+ /test/tmp/
16
+ /test/version_tmp/
17
+
18
+ ## Build artifacts
19
+ /pkg/
9
20
  /tmp/
21
+ *.gem
22
+
23
+ ## IDE and OS files
24
+ .DS_Store
25
+ .idea/
26
+ .vscode/
27
+ *.swp
28
+ *.swo
29
+ *~
30
+ .ruby-version
31
+ .ruby-gemset
32
+
33
+ ## Environment
34
+ .env
35
+ .env.local
36
+
37
+ ## Logs
38
+ npm-debug.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,35 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+ Exclude:
6
+ - 'vendor/**/*'
7
+ - 'bin/**/*'
8
+ - 'app/assets/javascripts/fort.js'
9
+
10
+ Style/Documentation:
11
+ Enabled: false
12
+
13
+ Style/StringLiterals:
14
+ Enabled: true
15
+ EnforcedStyle: double_quotes
16
+
17
+ Style/FrozenStringLiteralComment:
18
+ Enabled: true
19
+ EnforcedStyle: always
20
+
21
+ Layout/LineLength:
22
+ Max: 120
23
+ Exclude:
24
+ - '*.gemspec'
25
+
26
+ Metrics/BlockLength:
27
+ Exclude:
28
+ - 'spec/**/*'
29
+ - '*.gemspec'
30
+
31
+ Gemspec/DevelopmentDependencies:
32
+ Enabled: false
33
+
34
+ Gemspec/AddRuntimeDependency:
35
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [1.0.0] - 2026-05-30
6
+
7
+ First modern release on RubyGems.
8
+
9
+ ### Added
10
+
11
+ - New vanilla JavaScript implementation (`fort.js`) — no jQuery, no `document.body` rewriting
12
+ - `fort.css` as a first-class stylesheet (include via `*= require fort`)
13
+ - Support for `fort-ignore` class in addition to `ignore`
14
+ - Accessible progress bar attributes (`role="progressbar"`, `aria-*`)
15
+ - Explicit `railties` runtime dependency (>= 6.0, < 9.0)
16
+ - GitHub Actions CI, RuboCop, bundler-audit, RSpec
17
+ - CHANGELOG, UPGRADE_GUIDE, and modern README
18
+
19
+ ### Changed
20
+
21
+ - **Breaking (JS):** Replaced legacy vendored `fort.min.js` with `FortProgress` class
22
+ - **Breaking (Ruby):** Minimum Ruby 3.0, Rails 6.0+
23
+ - `config/fort.yml` format unchanged (`type`, `value`, `height`, `duration`, `alignment`)
24
+ - Progress bar DOM uses `.fort-bar` (legacy `.top-one` / `.top-two` classes retained in CSS for compatibility)
25
+
26
+ ### Removed
27
+
28
+ - jQuery dependency
29
+ - Legacy vendor `fort.min.js` and `fort.min.css`
30
+ - Travis CI
31
+
32
+ ### Notes
33
+
34
+ - Original upstream Fort.js GitHub repository is unavailable; JS is maintained in this gem
35
+
36
+ ## [0.2.0] - Previous Release
37
+
38
+ - jQuery-based integration with vendored Fort.js
39
+ - Form completion progress bar with `config/fort.yml`
40
+
41
+ ---
42
+
43
+ For upgrade instructions, see [UPGRADE_GUIDE.md](UPGRADE_GUIDE.md)
data/CODE_OF_CONDUCT.md CHANGED
@@ -11,3 +11,4 @@ Project maintainers have the right and responsibility to remove, edit, or reject
11
11
  Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
12
 
13
13
  This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
14
+
data/Gemfile CHANGED
@@ -1,4 +1,9 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
2
4
 
3
- # Specify your gem's dependencies in rails-fort.gemspec
4
5
  gemspec
6
+
7
+ if (rails_version = ENV.fetch("RAILS_VERSION", nil))
8
+ gem "railties", "~> #{rails_version}.0"
9
+ end
data/README.md CHANGED
@@ -1,96 +1,138 @@
1
1
  # Rails::Fort
2
2
 
3
- [![Build Status](https://travis-ci.org/ethirajsrinivasan/rails-fort.svg?branch=master)](https://travis-ci.org/ethirajsrinivasan/rails-fort)
4
- [![Code Climate](https://codeclimate.com/github/ethirajsrinivasan/rails-fort/badges/gpa.svg)](https://codeclimate.com/github/ethirajsrinivasan/rails-fort)
5
- [![security](https://hakiri.io/github/ethirajsrinivasan/rails-fort/master.svg)](https://hakiri.io/github/ethirajsrinivasan/rails-fort/master)
3
+ [![CI](https://github.com/ethirajsrinivasan/rails-fort/actions/workflows/ci.yml/badge.svg)](https://github.com/ethirajsrinivasan/rails-fort/actions/workflows/ci.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/rails-fort.svg)](https://badge.fury.io/rb/rails-fort)
6
5
 
6
+ Modern progress bar for form completion
7
7
 
8
- rails-fort gem gives you modern progress bar for form completion
8
+ ## Requirements
9
+
10
+ - Ruby >= 3.0
11
+ - Rails >= 6.0
12
+ - No jQuery required
9
13
 
10
14
  ## Installation
11
15
 
12
16
  Add this line to your application's Gemfile:
13
17
 
14
18
  ```ruby
15
- gem 'rails-fort'
19
+ gem 'rails-fort', '~> 1.0'
16
20
  ```
17
21
 
18
22
  And then execute:
19
23
 
20
- $ bundle install
24
+ ```bash
25
+ bundle install
26
+ ```
27
+
28
+ ### Asset Pipeline Setup
21
29
 
22
- Or install it yourself as:
30
+ **For Rails 6.x / 7.x with Sprockets:**
23
31
 
24
- $ gem install rails-fort
32
+ In `app/assets/javascripts/application.js`:
25
33
 
26
- To use this gem add this require statement to your application.js file:
34
+ ```javascript
35
+ //= require rails_fort
36
+ ```
27
37
 
28
- //= require rails_fort
38
+ In `app/assets/stylesheets/application.css`:
29
39
 
30
- ## Usage
40
+ ```css
41
+ *= require fort
42
+ ```
43
+
44
+ **For Rails 7+ with Import Maps:**
45
+
46
+ Add to `config/importmap.rb`:
47
+
48
+ ```ruby
49
+ pin "rails_fort", to: "rails_fort.js"
50
+ pin "fort", to: "fort.js"
51
+ ```
52
+
53
+ Import in `application.js`:
31
54
 
32
- rails-fort will automatically detect all `<input>` inside form
55
+ ```javascript
56
+ import "rails_fort"
57
+ ```
58
+
59
+ Include `fort.css` through your stylesheet pipeline or asset host.
33
60
 
34
- Certain fields:
61
+ ## Usage
35
62
 
36
- If you want to exclude certain fields add a class named 'ignore' to the field. rails-fort will not detect the field after you do so.
63
+ Rails-Fort tracks `input`, `textarea`, and `select` fields inside forms and shows a fixed progress bar as the user completes the form.
37
64
 
38
- Example
65
+ ### Exclude fields
39
66
 
40
- <input type="text" class='ignore'>
67
+ Add `ignore` or `fort-ignore` to skip a field:
41
68
 
69
+ ```html
70
+ <input type="text" class="ignore">
71
+ ```
42
72
 
43
- You can also set default configuration in fort.yml under config folder, example
73
+ ### Configuration (`config/fort.yml`)
44
74
 
45
- height: '20px'
46
- duration: '3s'
47
- alignment: 'bottom'
48
- type: 'solid'
49
- value: '#009DFF'
75
+ ```yaml
76
+ height: '20px'
77
+ duration: '3s'
78
+ alignment: 'bottom'
79
+ type: 'solid'
80
+ value: '#009DFF'
81
+ ```
50
82
 
83
+ ### Effects
51
84
 
52
- Effects:
85
+ **Solid**
53
86
 
54
- * Solid
87
+ ```yaml
88
+ type: 'solid'
89
+ value: '#009DFF'
90
+ ```
55
91
 
56
- type: 'solid'
57
- value: '#009DFF'
92
+ **Gradient** (two colors)
58
93
 
59
- * Gradient
94
+ ```yaml
95
+ type: 'gradient'
96
+ value: ['#009DFF', '#47B9FF']
97
+ ```
60
98
 
61
- type: 'gradient'
62
- value: ["#009DFF", "#47B9FF"]
99
+ **Sections**
63
100
 
64
- Note: Only two values can be passed
101
+ ```yaml
102
+ type: 'sections'
103
+ value: ['#009DFF', '#4AF2A1', '#FB5229']
104
+ ```
65
105
 
66
- * Sections
106
+ **Flash**
67
107
 
68
- type: 'sections'
69
- value: ["#009DFF", "#4AF2A1", "#FB5229"]
108
+ ```yaml
109
+ type: 'flash'
110
+ value: ['#009DFF', '#000', '#6638F0']
111
+ ```
70
112
 
71
- * Flash
113
+ **Merge**
72
114
 
73
- type: 'flash'
74
- value: ["#009DFF", "#000", "#6638F0"]
115
+ ```yaml
116
+ type: 'merge'
117
+ value: '#009DFF'
118
+ ```
75
119
 
76
- * Merge
120
+ ## Upgrading
77
121
 
78
- type: 'merge'
79
- value: '#009DFF'
122
+ Upgrading from the legacy **0.x** gem? See [UPGRADE_GUIDE.md](UPGRADE_GUIDE.md) for **1.0.0**.
80
123
 
81
- effects can be added by changing type and value fields in fort.yml
124
+ ## JavaScript
82
125
 
126
+ The progress bar is implemented in vanilla JavaScript (`app/assets/javascripts/fort.js`) and vendored inside this gem. The original [Fort.js](https://github.com/idriskhenchil/Fort.js) repository by Idris Khenchil is no longer available; this gem maintains a compatible `fort.yml` API with a new implementation.
83
127
 
84
128
  ## Contributing
85
129
 
86
- Bug reports and pull requests are welcome on GitHub at https://github.com/ethirajsrinivasan/rails-fort. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
87
-
88
- ##Thanks
130
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ethirajsrinivasan/rails-fort. Contributors are expected to adhere to the [Contributor Covenant](CODE_OF_CONDUCT.md) code of conduct.
89
131
 
90
- Thanks to [Idris Khenchil](https://github.com/idriskhenchil/Fort.js) for writing an awesome fort plugin.
132
+ ## Thanks
91
133
 
134
+ Thanks to Idris Khenchil for the original Fort.js form progress bar concept.
92
135
 
93
136
  ## License
94
137
 
95
138
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
96
-
data/Rakefile CHANGED
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
  RSpec::Core::RakeTask.new
4
- task :default => :spec
6
+ task default: :spec
data/UPGRADE_GUIDE.md ADDED
@@ -0,0 +1,107 @@
1
+ # Upgrade Guide: Rails-Fort 0.x to 1.0.0
2
+
3
+ ## Overview
4
+
5
+ Rails-Fort **1.0.0** is the first modern release on RubyGems. It combines Ruby/Rails modernization (Ruby 3.0+, Rails 6.0+) with a **rewritten JavaScript engine** while keeping the same `config/fort.yml` format.
6
+
7
+ ## What Changed
8
+
9
+ ### Ruby & Rails
10
+
11
+ | Component | 0.x | 1.0.0 |
12
+ |-----------|-----|-------|
13
+ | Ruby | >= 2.7 (varied) | >= 3.0 |
14
+ | Rails | >= 4.2 | >= 6.0 |
15
+
16
+ ### JavaScript
17
+
18
+ | Topic | 0.x | 1.0.0 |
19
+ |-------|-----|-------|
20
+ | jQuery | Required | **Not required** |
21
+ | Implementation | Vendored legacy `fort.min.js` | New `fort.js` (`FortProgress`) |
22
+ | CSS | Bundled minified vendor file | `*= require fort` in your stylesheet manifest |
23
+ | DOM behavior | Rewrote `document.body` innerHTML | Inserts progress bar elements only |
24
+ | Ignore class | `ignore` | `ignore` or `fort-ignore` |
25
+ | Upstream repo | idriskhenchil/Fort.js (now 404) | Maintained in this gem |
26
+
27
+ ### Unchanged
28
+
29
+ - `config/fort.yml` keys: `height`, `duration`, `alignment`, `type`, `value`
30
+ - Effect types: `solid`, `gradient`, `sections`, `flash`, `merge`
31
+ - `//= require rails_fort` in `application.js`
32
+
33
+ ## Upgrade Steps
34
+
35
+ ### 1. Update Gemfile
36
+
37
+ ```ruby
38
+ gem 'rails-fort', '~> 1.0'
39
+ ```
40
+
41
+ ```bash
42
+ bundle update rails-fort
43
+ ```
44
+
45
+ ### 2. Add stylesheet (new in 1.0)
46
+
47
+ In `app/assets/stylesheets/application.css` (or equivalent):
48
+
49
+ ```css
50
+ *= require fort
51
+ ```
52
+
53
+ ### 3. Remove jQuery requirement
54
+
55
+ You no longer need jQuery for rails-fort. Remove any load order that existed only for this gem.
56
+
57
+ ### 4. Keep `config/fort.yml`
58
+
59
+ Existing configuration should work as-is, for example:
60
+
61
+ ```yaml
62
+ height: '20px'
63
+ duration: '3s'
64
+ alignment: 'bottom'
65
+ type: 'solid'
66
+ value: '#009DFF'
67
+ ```
68
+
69
+ ### 5. Test your forms
70
+
71
+ 1. Load a page with a form
72
+ 2. Confirm the progress bar appears (top or bottom per `alignment`)
73
+ 3. Fill fields and verify width/color effects
74
+ 4. Confirm fields with class `ignore` are skipped
75
+
76
+ ## Troubleshooting
77
+
78
+ ### Progress bar not visible
79
+
80
+ - Ensure **both** JS and CSS are included (`rails_fort` + `fort` stylesheet)
81
+ - Check the browser console for errors
82
+ - Verify `config/fort.yml` is valid YAML
83
+
84
+ ### Custom CSS targeting old markup
85
+
86
+ 1.0 still applies `.top-one` and `.top-two` on bar elements for compatibility. Prefer `.fort-bar` for new custom styles.
87
+
88
+ ### Turbo / Turbolinks
89
+
90
+ Re-initialize on page change if needed:
91
+
92
+ ```javascript
93
+ document.addEventListener("turbo:load", function () {
94
+ if (window._railsFortInstance) {
95
+ window._railsFortInstance.destroy();
96
+ window._railsFortInstance = new FortProgress(/* your config */);
97
+ window._railsFortInstance.init();
98
+ }
99
+ });
100
+ ```
101
+
102
+ For Sprockets-only apps, a full page load re-runs `rails_fort.js.erb` automatically.
103
+
104
+ ## Getting Help
105
+
106
+ - [GitHub Issues](https://github.com/ethirajsrinivasan/rails-fort/issues)
107
+ - [CHANGELOG.md](CHANGELOG.md)
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Rails-Fort — form completion progress bar (vanilla JavaScript).
3
+ *
4
+ * Initialized from rails_fort.js.erb with config from config/fort.yml.
5
+ */
6
+ class FortProgress {
7
+ constructor(config = {}) {
8
+ this.config = {
9
+ type: config.type || "solid",
10
+ value: config.value ?? "#009DFF",
11
+ height: config.height || "4px",
12
+ duration: config.duration || "1s",
13
+ alignment: config.alignment || "top"
14
+ };
15
+ this.bars = [];
16
+ this.containers = [];
17
+ this._sortedFlashColors = null;
18
+ }
19
+
20
+ init() {
21
+ this._prepareForms();
22
+ this._buildBars();
23
+ this._bindFields();
24
+ this._update();
25
+ }
26
+
27
+ destroy() {
28
+ this._unbindFields();
29
+ this.bars.forEach((bar) => bar.remove());
30
+ this.bars = [];
31
+ }
32
+
33
+ _prepareForms() {
34
+ document.querySelectorAll("form").forEach((form) => {
35
+ if (form.dataset.fortWrapped === "true") return;
36
+
37
+ const wrapper = document.createElement("div");
38
+ wrapper.className = "fort-form form";
39
+ form.parentNode.insertBefore(wrapper, form);
40
+ wrapper.appendChild(form);
41
+ form.dataset.fortWrapped = "true";
42
+ this.containers.push(wrapper);
43
+ });
44
+
45
+ document.querySelectorAll(".fort-form, .form").forEach((container) => {
46
+ if (!this.containers.includes(container)) {
47
+ this.containers.push(container);
48
+ }
49
+ });
50
+ }
51
+
52
+ _buildBars() {
53
+ this.bars.forEach((bar) => bar.remove());
54
+ this.bars = [];
55
+
56
+ if (this.config.type === "merge") {
57
+ this.bars.push(this._createBar("fort-bar top-one"));
58
+ this.bars.push(this._createBar("fort-bar fort-bar--secondary top-two"));
59
+ } else {
60
+ this.bars.push(this._createBar("fort-bar top-one"));
61
+ }
62
+
63
+ const isBottom = this.config.alignment === "bottom";
64
+
65
+ this.bars.forEach((bar) => {
66
+ bar.style.height = this.config.height;
67
+ bar.style.transitionDuration = this.config.duration;
68
+
69
+ if (isBottom) {
70
+ bar.classList.add("fort-bar--bottom");
71
+ bar.style.top = "auto";
72
+ bar.style.bottom = "0";
73
+ } else {
74
+ bar.style.top = "0";
75
+ bar.style.bottom = "auto";
76
+ }
77
+
78
+ document.body.appendChild(bar);
79
+ });
80
+ }
81
+
82
+ _createBar(className) {
83
+ const bar = document.createElement("div");
84
+ bar.className = className;
85
+ bar.setAttribute("role", "progressbar");
86
+ bar.setAttribute("aria-valuemin", "0");
87
+ bar.setAttribute("aria-valuemax", "100");
88
+
89
+ const fill = document.createElement("div");
90
+ fill.className = "fort-bar__fill colors";
91
+ bar.appendChild(fill);
92
+
93
+ return bar;
94
+ }
95
+
96
+ _bindFields() {
97
+ this._getFields().forEach((field) => {
98
+ field.addEventListener("input", this._update);
99
+ field.addEventListener("change", this._update);
100
+ });
101
+ }
102
+
103
+ _unbindFields() {
104
+ this._getFields().forEach((field) => {
105
+ field.removeEventListener("input", this._update);
106
+ field.removeEventListener("change", this._update);
107
+ });
108
+ }
109
+
110
+ _getFields() {
111
+ const fields = [];
112
+
113
+ this.containers.forEach((container) => {
114
+ container.querySelectorAll("input, textarea, select").forEach((field) => {
115
+ if (this._shouldTrack(field)) {
116
+ fields.push(field);
117
+ }
118
+ });
119
+ });
120
+
121
+ return fields;
122
+ }
123
+
124
+ _shouldTrack(field) {
125
+ const type = (field.type || "").toLowerCase();
126
+
127
+ if (type === "button" || type === "submit" || type === "hidden") {
128
+ return false;
129
+ }
130
+
131
+ if (field.classList.contains("ignore") || field.classList.contains("fort-ignore")) {
132
+ return false;
133
+ }
134
+
135
+ return true;
136
+ }
137
+
138
+ _isFilled(field) {
139
+ if (field.type === "checkbox" || field.type === "radio") {
140
+ return field.checked;
141
+ }
142
+
143
+ return String(field.value || "").trim().length > 0;
144
+ }
145
+
146
+ _getCounts() {
147
+ const fields = this._getFields();
148
+ const total = fields.length;
149
+ const filled = fields.filter((field) => this._isFilled(field)).length;
150
+
151
+ return { total, filled, percent: total === 0 ? 0 : (filled / total) * 100 };
152
+ }
153
+
154
+ _update = () => {
155
+ const { total, filled, percent } = this._getCounts();
156
+ const unfilled = total - filled;
157
+
158
+ this.bars.forEach((bar) => {
159
+ bar.setAttribute("aria-valuenow", String(Math.round(percent)));
160
+ });
161
+
162
+ switch (this.config.type) {
163
+ case "gradient":
164
+ this._applyGradient(percent);
165
+ break;
166
+ case "sections":
167
+ this._applySections();
168
+ break;
169
+ case "flash":
170
+ this._applyFlash(total, unfilled);
171
+ break;
172
+ case "merge":
173
+ this._applyMerge(percent);
174
+ break;
175
+ default:
176
+ this._applySolid(percent);
177
+ }
178
+ };
179
+
180
+ _applySolid(percent) {
181
+ const bar = this.bars[0];
182
+ const fill = bar.querySelector(".fort-bar__fill");
183
+
184
+ bar.style.width = `${percent}%`;
185
+ fill.style.background = this._colorValue();
186
+ }
187
+
188
+ _applyGradient(percent) {
189
+ const colors = this._colorArray();
190
+
191
+ if (colors.length < 2) {
192
+ this._applySolid(percent);
193
+ return;
194
+ }
195
+
196
+ const bar = this.bars[0];
197
+ const fill = bar.querySelector(".fort-bar__fill");
198
+
199
+ bar.style.width = `${percent}%`;
200
+ fill.style.background = `linear-gradient(to right, ${colors[0]}, ${colors[1]})`;
201
+ }
202
+
203
+ _applySections() {
204
+ const colors = this._colorArray();
205
+
206
+ if (colors.length === 0) {
207
+ return;
208
+ }
209
+
210
+ const { percent } = this._getCounts();
211
+ const bar = this.bars[0];
212
+ const fill = bar.querySelector(".fort-bar__fill");
213
+ const stops = [];
214
+
215
+ colors.forEach((color, index) => {
216
+ const stop = Math.floor((1000 * (index + 1)) / colors.length) / 10;
217
+ stops.push(`${color} ${stop}%`);
218
+ });
219
+
220
+ bar.style.width = `${percent}%`;
221
+ fill.style.background = `linear-gradient(to right, ${stops.join(", ")})`;
222
+ fill.style.width = "100%";
223
+ }
224
+
225
+ _applyFlash(total, unfilled) {
226
+ const colors = this._colorArray().slice().sort();
227
+ const bar = this.bars[0];
228
+ const fill = bar.querySelector(".fort-bar__fill");
229
+ const filled = total - unfilled;
230
+ const percent = total === 0 ? 0 : (filled / total) * 100;
231
+
232
+ bar.style.width = `${percent}%`;
233
+
234
+ if (colors.length === 0) {
235
+ fill.style.background = this._colorValue();
236
+ return;
237
+ }
238
+
239
+ const index = Math.max(0, Math.min(colors.length - 1, unfilled - 1));
240
+ fill.style.background = colors[index] || colors[0];
241
+ }
242
+
243
+ _applyMerge(percent) {
244
+ const color = this._colorValue();
245
+ const half = percent / 2;
246
+
247
+ this.bars.forEach((bar) => {
248
+ bar.style.width = `${half}%`;
249
+ const fill = bar.querySelector(".fort-bar__fill");
250
+ fill.style.background = color;
251
+ });
252
+ }
253
+
254
+ _colorValue() {
255
+ const value = this.config.value;
256
+
257
+ if (Array.isArray(value)) {
258
+ return value[0] || "#009DFF";
259
+ }
260
+
261
+ return value || "#009DFF";
262
+ }
263
+
264
+ _colorArray() {
265
+ const value = this.config.value;
266
+
267
+ if (Array.isArray(value)) {
268
+ return value;
269
+ }
270
+
271
+ return [value || "#009DFF"];
272
+ }
273
+ }
274
+
275
+ // Export for tests and module loaders; global for Sprockets.
276
+ if (typeof module !== "undefined" && module.exports) {
277
+ module.exports = FortProgress;
278
+ }
279
+
280
+ window.FortProgress = FortProgress;
@@ -1,20 +1,29 @@
1
- $(document).ready(function(){
2
- $("form").wrap( "<div class='form'></div>" );
3
- <% path_to_file = "#{Rails.root}/config/fort.yml" %>
4
- <% if File.exist?(path_to_file) %>
5
- fortconfig = <%= JSON.dump(YAML.load_file(path_to_file)) %>;
6
- if (fortconfig.type == null)
7
- fortconfig.type = "solid"
8
- if(fortconfig.value instanceof Array)
9
- Fort[fortconfig.type].apply(this,fortconfig.value)
10
- else
11
- Fort[fortconfig.type](fortconfig.value)
12
- Fort.config({
13
- height: fortconfig.height,
14
- duration: fortconfig.duration,
15
- alignment: fortconfig.alignment
16
- });
17
- <% else %>
18
- Fort.solid("#009DFF");
19
- <% end %>
20
- });
1
+ //= require fort
2
+
3
+ (function () {
4
+ "use strict";
5
+
6
+ <% path_to_file = Rails.root.join("config/fort.yml").to_s %>
7
+ <% fortconfig = File.exist?(path_to_file) ? YAML.load_file(path_to_file) : { "type" => "solid", "value" => "#009DFF" } %>
8
+
9
+ var config = <%= JSON.dump(fortconfig) %>;
10
+
11
+ if (config.type == null) {
12
+ config.type = "solid";
13
+ }
14
+
15
+ function startFort() {
16
+ if (window._railsFortInstance) {
17
+ window._railsFortInstance.destroy();
18
+ }
19
+
20
+ window._railsFortInstance = new FortProgress(config);
21
+ window._railsFortInstance.init();
22
+ }
23
+
24
+ if (document.readyState === "loading") {
25
+ document.addEventListener("DOMContentLoaded", startFort);
26
+ } else {
27
+ startFort();
28
+ }
29
+ })();
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Rails-Fort progress bar styles
3
+ */
4
+
5
+ .fort-bar,
6
+ .top-one {
7
+ background: #009dff;
8
+ position: fixed;
9
+ z-index: 1031;
10
+ left: 0;
11
+ height: 4px;
12
+ width: 0;
13
+ overflow: hidden;
14
+ transition: width 1s ease, background 0.3s ease;
15
+ top: 0;
16
+ bottom: auto;
17
+ }
18
+
19
+ .fort-bar--secondary,
20
+ .top-two {
21
+ background: #009dff;
22
+ position: fixed;
23
+ z-index: 1031;
24
+ right: 0;
25
+ left: auto;
26
+ transform: scaleX(-1);
27
+ height: 4px;
28
+ width: 0;
29
+ overflow: hidden;
30
+ transition: width 1s ease, background 0.3s ease;
31
+ top: 0;
32
+ bottom: auto;
33
+ }
34
+
35
+ .fort-bar--bottom,
36
+ .top-one.fort-bar--bottom,
37
+ .top-two.fort-bar--bottom {
38
+ top: auto;
39
+ bottom: 0;
40
+ }
41
+
42
+ .fort-bar__fill,
43
+ .top-one .colors,
44
+ .top-two .colors {
45
+ width: 100%;
46
+ height: 100%;
47
+ }
48
+
49
+ .fort-form,
50
+ .form {
51
+ /* wrapper for forms; no extra layout rules required */
52
+ }
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rails
2
4
  module Fort
3
- VERSION = "0.1.6"
5
+ VERSION = "1.0.0"
4
6
  end
5
7
  end
data/lib/rails/fort.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rails/fort/version"
2
4
 
3
5
  module Rails
data/rails-fort.gemspec CHANGED
@@ -1,33 +1,43 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'rails/fort/version'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/rails/fort/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
6
  spec.name = "rails-fort"
8
7
  spec.version = Rails::Fort::VERSION
9
- spec.authors = ["ethiraj"]
8
+ spec.authors = ["ethi"]
10
9
  spec.email = ["ethirajsrinivasan@gmail.com"]
11
10
 
12
11
  spec.summary = "Modern progress bar for form completion"
13
- spec.description = "Modern progress bar for form completion"
12
+ spec.description = "Rails-Fort provides a modern, animated progress bar for form completion tracking. It automatically detects form fields and displays visual progress as users fill out forms, with multiple customizable effect types including solid, gradient, sections, flash, and merge animations."
14
13
  spec.homepage = "https://github.com/ethirajsrinivasan/rails-fort"
15
14
  spec.license = "MIT"
16
15
 
17
- # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
- # delete this section to allow pushing this gem to any host.
19
- if spec.respond_to?(:metadata)
20
- spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
- else
22
- raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
16
+ spec.metadata = {
17
+ "allowed_push_host" => "https://rubygems.org",
18
+ "homepage_uri" => spec.homepage,
19
+ "source_code_uri" => "https://github.com/ethirajsrinivasan/rails-fort",
20
+ "bug_tracker_uri" => "https://github.com/ethirajsrinivasan/rails-fort/issues",
21
+ "changelog_uri" => "https://github.com/ethirajsrinivasan/rails-fort/blob/master/CHANGELOG.md",
22
+ "documentation_uri" => "https://github.com/ethirajsrinivasan/rails-fort/blob/master/README.md",
23
+ "rubygems_mfa_required" => "true"
24
+ }
25
+
26
+ spec.files = Dir.chdir(__dir__) do
27
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
28
  end
24
29
 
25
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
30
  spec.bindir = "exe"
27
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
32
  spec.require_paths = ["lib"]
29
- spec.required_ruby_version = '>= 1.9.3'
30
- spec.add_development_dependency "bundler", "~> 1.10"
31
- spec.add_development_dependency "rake", "~> 10.0"
32
- spec.add_development_dependency 'rspec'
33
+
34
+ spec.required_ruby_version = ">= 3.0"
35
+
36
+ spec.add_runtime_dependency "railties", ">= 6.0", "< 9.0"
37
+
38
+ spec.add_development_dependency "bundler", "~> 2.4"
39
+ spec.add_development_dependency "bundler-audit", "~> 0.9"
40
+ spec.add_development_dependency "rake", "~> 13.0"
41
+ spec.add_development_dependency "rspec", "~> 3.12"
42
+ spec.add_development_dependency "rubocop", "~> 1.50"
33
43
  end
metadata CHANGED
@@ -1,86 +1,144 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-fort
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
- - ethiraj
8
- autorequire:
7
+ - ethi
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2016-09-27 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: railties
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '6.0'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '6.0'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9.0'
13
32
  - !ruby/object:Gem::Dependency
14
33
  name: bundler
15
34
  requirement: !ruby/object:Gem::Requirement
16
35
  requirements:
17
36
  - - "~>"
18
37
  - !ruby/object:Gem::Version
19
- version: '1.10'
38
+ version: '2.4'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '2.4'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler-audit
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '0.9'
20
53
  type: :development
21
54
  prerelease: false
22
55
  version_requirements: !ruby/object:Gem::Requirement
23
56
  requirements:
24
57
  - - "~>"
25
58
  - !ruby/object:Gem::Version
26
- version: '1.10'
59
+ version: '0.9'
27
60
  - !ruby/object:Gem::Dependency
28
61
  name: rake
29
62
  requirement: !ruby/object:Gem::Requirement
30
63
  requirements:
31
64
  - - "~>"
32
65
  - !ruby/object:Gem::Version
33
- version: '10.0'
66
+ version: '13.0'
34
67
  type: :development
35
68
  prerelease: false
36
69
  version_requirements: !ruby/object:Gem::Requirement
37
70
  requirements:
38
71
  - - "~>"
39
72
  - !ruby/object:Gem::Version
40
- version: '10.0'
73
+ version: '13.0'
41
74
  - !ruby/object:Gem::Dependency
42
75
  name: rspec
43
76
  requirement: !ruby/object:Gem::Requirement
44
77
  requirements:
45
- - - ">="
78
+ - - "~>"
46
79
  - !ruby/object:Gem::Version
47
- version: '0'
80
+ version: '3.12'
48
81
  type: :development
49
82
  prerelease: false
50
83
  version_requirements: !ruby/object:Gem::Requirement
51
84
  requirements:
52
- - - ">="
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '3.12'
88
+ - !ruby/object:Gem::Dependency
89
+ name: rubocop
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '1.50'
95
+ type: :development
96
+ prerelease: false
97
+ version_requirements: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
53
100
  - !ruby/object:Gem::Version
54
- version: '0'
55
- description: Modern progress bar for form completion
101
+ version: '1.50'
102
+ description: Rails-Fort provides a modern, animated progress bar for form completion
103
+ tracking. It automatically detects form fields and displays visual progress as users
104
+ fill out forms, with multiple customizable effect types including solid, gradient,
105
+ sections, flash, and merge animations.
56
106
  email:
57
107
  - ethirajsrinivasan@gmail.com
58
108
  executables: []
59
109
  extensions: []
60
110
  extra_rdoc_files: []
61
111
  files:
112
+ - ".github/workflows/ci.yml"
62
113
  - ".gitignore"
63
- - ".travis.yml"
114
+ - ".rspec"
115
+ - ".rubocop.yml"
116
+ - CHANGELOG.md
64
117
  - CODE_OF_CONDUCT.md
65
118
  - Gemfile
66
119
  - LICENSE.txt
67
120
  - README.md
68
121
  - Rakefile
122
+ - UPGRADE_GUIDE.md
123
+ - app/assets/javascripts/fort.js
69
124
  - app/assets/javascripts/rails_fort.js.erb
125
+ - app/assets/stylesheets/fort.css
70
126
  - bin/console
71
127
  - bin/setup
72
128
  - lib/rails/fort.rb
73
129
  - lib/rails/fort/version.rb
74
- - npm-debug.log
75
130
  - rails-fort.gemspec
76
- - vendor/assets/javascripts/fort.min.js
77
- - vendor/assets/stylesheets/fort.min.css
78
131
  homepage: https://github.com/ethirajsrinivasan/rails-fort
79
132
  licenses:
80
133
  - MIT
81
134
  metadata:
82
135
  allowed_push_host: https://rubygems.org
83
- post_install_message:
136
+ homepage_uri: https://github.com/ethirajsrinivasan/rails-fort
137
+ source_code_uri: https://github.com/ethirajsrinivasan/rails-fort
138
+ bug_tracker_uri: https://github.com/ethirajsrinivasan/rails-fort/issues
139
+ changelog_uri: https://github.com/ethirajsrinivasan/rails-fort/blob/master/CHANGELOG.md
140
+ documentation_uri: https://github.com/ethirajsrinivasan/rails-fort/blob/master/README.md
141
+ rubygems_mfa_required: 'true'
84
142
  rdoc_options: []
85
143
  require_paths:
86
144
  - lib
@@ -88,16 +146,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
88
146
  requirements:
89
147
  - - ">="
90
148
  - !ruby/object:Gem::Version
91
- version: 1.9.3
149
+ version: '3.0'
92
150
  required_rubygems_version: !ruby/object:Gem::Requirement
93
151
  requirements:
94
152
  - - ">="
95
153
  - !ruby/object:Gem::Version
96
154
  version: '0'
97
155
  requirements: []
98
- rubyforge_project:
99
- rubygems_version: 2.5.1
100
- signing_key:
156
+ rubygems_version: 3.6.7
101
157
  specification_version: 4
102
158
  summary: Modern progress bar for form completion
103
159
  test_files: []
data/.travis.yml DELETED
@@ -1,8 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 1.9.3
4
- - 2.0.0
5
- - 2.1.4
6
- - 2.1.5
7
- - 2.2.1
8
- before_install: gem install bundler -v 1.10.6
data/npm-debug.log DELETED
@@ -1,18 +0,0 @@
1
- 0 info it worked if it ends with ok
2
- 1 verbose cli [ '/usr/bin/nodejs', '/usr/bin/npm', 'completion' ]
3
- 2 info using npm@1.3.10
4
- 3 info using node@v0.10.25
5
- 4 error Error: ENOENT, open '/usr/share/npm/lib/utils/completion.sh'
6
- 5 error If you need help, you may report this log at:
7
- 5 error <http://github.com/isaacs/npm/issues>
8
- 5 error or email it to:
9
- 5 error <npm-@googlegroups.com>
10
- 6 error System Linux 3.19.0-25-generic
11
- 7 error command "/usr/bin/nodejs" "/usr/bin/npm" "completion"
12
- 8 error cwd /home/ethi/apps/gems/rails-fort
13
- 9 error node -v v0.10.25
14
- 10 error npm -v 1.3.10
15
- 11 error path /usr/share/npm/lib/utils/completion.sh
16
- 12 error code ENOENT
17
- 13 error errno 34
18
- 14 verbose exit [ 34, true ]
@@ -1 +0,0 @@
1
- var Fort={clean:function(){for(var e=document.querySelectorAll(".form"),t=e.length;t--;){var o=e[t].querySelectorAll("input, textarea, select");Array.prototype.forEach.call(o,function(e){0!=e.value.length&&(e.classList?e.classList.add("ignore"):e.className+=" ignore")});var n=e[t].querySelectorAll("input[type=hidden]");Array.prototype.forEach.call(n,function(e){e.classList?e.classList.add("ignore"):e.className+=" ignore"})}},solid:function(e){function t(t){for(var o=[],r=n.length;r--;)n[r].value.length||o.push(n[r]);for(var l=o.length,s=n.length,a=document.querySelectorAll(".top-one"),i=a.length;i--;)a[i].style.width=100-l/s*100+"%";document.getElementById("top1").style.background=e}Fort.clean(),document.body.innerHTML='<div class="top-one" id="top1"><div class="colors"></div></div>'+document.body.innerHTML;for(var o=document.querySelectorAll(".form"),n=[],r=o.length;r--;)for(var l=o[r].querySelectorAll("input, textarea, select"),s=l.length;s--;){classes=l[s].className.replace(/\s+/g," ").split(" "),ignore=!1;for(var a=classes.length;a--;)if("ignore"==classes[a]){ignore=!0;break}"button"==l[s].type||"submit"==l[s].type||ignore||(n.push(l[s]),l[s].addEventListener("input",t,!1))}},gradient:function(e,t){function o(o){for(var n=[],l=r.length;l--;)r[l].value.length||n.push(r[l]);for(var s=n.length,a=r.length,i=document.querySelectorAll(".top-one"),c=i.length;c--;)i[c].style.width=100-s/a*100+"%";orientation="to right";var u="linear-gradient("+orientation+", "+e+", "+t+")";document.getElementById("top1").style.background=u}Fort.clean(),document.body.innerHTML='<div class="top-one" id="top1"><div class="colors"></div></div>'+document.body.innerHTML;for(var n=document.querySelectorAll(".form"),r=[],l=n.length;l--;)for(var s=n[l].querySelectorAll("input, textarea, select"),a=s.length;a--;){classes=s[a].className.replace(/\s+/g," ").split(" "),ignore=!1;for(var i=classes.length;i--;)if("ignore"==classes[i]){ignore=!0;break}"button"==s[a].type||"submit"==s[a].type||ignore||(r.push(s[a]),s[a].addEventListener("input",o,!1))}},sections:function(){function e(e){for(var t=[],o=s.length;o--;)s[o].value.length||t.push(s[o]);for(var n=t.length,r=s.length,l=document.querySelectorAll(".top-one"),a=l.length;a--;)l[a].style.width=100-n/r*100+"%"}function t(e){var t=[],o=0;for(n=0;n<2*e.length;n++){n%2&&o++;var r=Math.floor(1e3*o/e.length)/10;t.push([e[n-o],r+"%"])}return t}function o(e){var t,o=e.length;for(t=0;o>t;t++)e[t]=e[t].join(" ");return"linear-gradient( to right, "+e.join(", ")+")"}Fort.clean();for(var n=0;n<arguments.length;++n)var r=Array.prototype.slice.call(arguments);document.body.innerHTML='<div class="top-one" id="top1"><div class="colors"></div></div>'+document.body.innerHTML;for(var l=document.querySelectorAll(".form"),s=[],n=l.length;n--;)for(var a=l[n].querySelectorAll("input, textarea, select"),i=a.length;i--;){classes=a[i].className.replace(/\s+/g," ").split(" "),ignore=!1;for(var c=classes.length;c--;)if("ignore"==classes[c]){ignore=!0;break}"button"==a[i].type||"submit"==a[i].type||ignore||(s.push(a[i]),a[i].addEventListener("input",e,!1))}document.getElementsByClassName("top-one").innerHTML='<div class="colors"></div>',document.querySelector(".colors").style.background=o(t(r.sort()));var u=window.innerWidth+"px";document.querySelector(".colors").style.width=u},flash:function(){function e(e){for(var t=[],o=l.length;o--;)l[o].value.length||t.push(l[o]);for(var r=t.length,s=l.length,a=document.querySelectorAll(".top-one"),i=a.length;i--;)a[i].style.width=100-r/s*100+"%",a[i].style.background=n[s-r-1]}Fort.clean();for(var t=0;t<arguments.length;++t){arguments.length,arguments[t]}var o=Array.prototype.slice.call(arguments),n=o.sort();document.body.innerHTML='<div class="top-one" id="top1"><div class="colors"></div></div>'+document.body.innerHTML;for(var r=document.querySelectorAll(".form"),l=[],t=r.length;t--;)for(var s=r[t].querySelectorAll("input, textarea, select"),a=s.length;a--;){classes=s[a].className.replace(/\s+/g," ").split(" "),ignore=!1;for(var i=classes.length;i--;)if("ignore"==classes[i]){ignore=!0;break}"button"==s[a].type||"submit"==s[a].type||ignore||(l.push(s[a]),s[a].addEventListener("input",e,!1))}},merge:function(e){function t(t){for(var o=[],r=n.length;r--;)n[r].value.length||o.push(n[r]);for(var l=o.length,s=n.length,a=document.querySelectorAll("#top1"),i=a.length;i--;){precalct=100-l/s*100;var c=precalct/2;a[i].style.width=c+"%"}for(var l=o.length,s=n.length,a=document.querySelectorAll("#top2"),i=a.length;i--;){precalct=100-l/s*100;var c=precalct/2;a[i].style.width=c+"%"}document.getElementById("top1").style.background=e,document.getElementById("top2").style.background=e}Fort.clean(),document.body.innerHTML='<div class="top-one" id="top1"><div class="colors"></div></div>'+document.body.innerHTML,document.body.innerHTML='<div class="top-two" id="top2"><div class="colors"></div></div>'+document.body.innerHTML;for(var o=document.querySelectorAll(".form"),n=[],r=o.length;r--;)for(var l=o[r].querySelectorAll("input, textarea, select"),s=l.length;s--;){classes=l[s].className.replace(/\s+/g," ").split(" "),ignore=!1;for(var a=classes.length;a--;)if("ignore"==classes[a]){ignore=!0;break}"button"==l[s].type||"submit"==l[s].type||ignore||(n.push(l[s]),l[s].addEventListener("input",t,!1))}},config:function(e){var t=document.querySelector("#top1"),o=document.querySelector("#top2")||{style:{}};e.height&&(t.style.height=e.height,o.style.height=e.height),e.alignment&&("top"===e.alignment?(t.style.top=0,t.style.bottom="auto",o.style.top=0,o.style.bottom="auto"):(t.style.top="auto",t.style.bottom=0,o.style.top="auto",o.style.bottom=0)),e.duration&&(t.style.transitionDuration=e.duration,o.style.transitionDuration=e.duration)}};
@@ -1 +0,0 @@
1
- .top-one{background:#009dff;position:fixed;z-index:1031;top:0;left:0;height:4px;transition:all 1s;width:0;overflow:hidden}.top-two{background:#009dff;position:fixed;z-index:1031;top:0;right:0;transform:rotate(180deg);height:4px;transition:all 1s;width:0;overflow:hidden}.colors{width:100%;height:4px}