├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gemfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── app ├── assets │ ├── images │ │ └── constraint_validations │ │ │ └── .keep │ └── javascripts │ │ ├── constraint_validations.es.js │ │ ├── constraint_validations.es.js.map │ │ ├── constraint_validations.js │ │ └── constraint_validations.js.map └── javascript │ └── constraint_validations │ ├── index.js │ ├── util.js │ └── validators │ └── checkbox_validator.js ├── bin └── rails ├── bug_report_template.rb ├── config └── routes.rb ├── constraint_validations.gemspec ├── lib ├── constraint_validations.rb ├── constraint_validations │ ├── engine.rb │ ├── form_builder.rb │ ├── form_builder │ │ └── extensions.rb │ └── version.rb └── tasks │ └── constraint_validations_tasks.rake ├── package.json ├── rollup.config.js ├── test ├── application_system_test_case.rb ├── constraint_validations │ ├── form_builder_test.rb │ └── tag_extensions_test.rb ├── constraint_validations_test.rb ├── dummy │ ├── Rakefile │ ├── app │ │ ├── assets │ │ │ ├── config │ │ │ │ └── manifest.js │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── javascripts │ │ │ │ └── application.js │ │ │ └── stylesheets │ │ │ │ └── application.css │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ ├── forms_controller.rb │ │ │ └── messages_controller.rb │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── models │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ ├── form.rb │ │ │ └── message.rb │ │ └── views │ │ │ ├── forms │ │ │ └── new.html.erb │ │ │ ├── layouts │ │ │ └── application.html.erb │ │ │ └── messages │ │ │ └── new.html.erb │ ├── bin │ │ ├── rails │ │ ├── rake │ │ └── setup │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── cable.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── application_controller_renderer.rb │ │ │ ├── assets.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── content_security_policy.rb │ │ │ ├── cookies_serializer.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── permissions_policy.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ └── en.yml │ │ └── routes.rb │ ├── lib │ │ └── assets │ │ │ └── .keep │ ├── log │ │ └── .keep │ └── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ └── favicon.ico ├── system │ └── validations_test.rb └── test_helper.rb └── yarn.lock /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: seanpdoyle 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | 15 | Save the contents of [bug_report_template.rb](https://github.com/seanpdoyle/constraint_validations/blob/main/bug_report_template.rb) to your local filesystem as `bug.rb`, then test the file by executing `ruby bug.rb`. 16 | 17 | If executing `ruby bug.rb` succeeds, change the `SystemTest` to reproduce the issue you're experiencing. When you've reproduced the bug, paste the contents of `bug.rb` below: 18 | 19 | ```ruby 20 | # replace this comment with the contents of `bug.rb` 21 | ``` 22 | 23 | **Expected behavior** 24 | A clear and concise description of what you expected to happen. 25 | 26 | **Screenshots** 27 | If applicable, add screenshots to help explain your problem. 28 | 29 | **Desktop (please complete the following information):** 30 | - OS: [e.g. iOS] 31 | - Browser [e.g. chrome, safari] 32 | - Version [e.g. 22] 33 | 34 | **Smartphone (please complete the following information):** 35 | - Device: [e.g. iPhone6] 36 | - OS: [e.g. iOS8.1] 37 | - Browser [e.g. stock browser, safari] 38 | - Version [e.g. 22] 39 | 40 | **Additional context** 41 | Add any other context about the problem here. 42 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "CI Tests" 2 | 3 | on: 4 | - "pull_request" 5 | 6 | jobs: 7 | test: 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | hotwire-enabled: 12 | - true 13 | - false 14 | ruby-version: 15 | - "3.1" 16 | - "3.2" 17 | - "3.3" 18 | rails-version: 19 | - "7.1" 20 | - "7.2" 21 | - "main" 22 | selenium-browser: 23 | - "headless_chrome" 24 | - "headless_firefox" 25 | exclude: 26 | - { ruby-version: "3.1", rails-version: "main" } 27 | 28 | env: 29 | RAILS_VERSION: "${{ matrix.rails-version }}" 30 | SELENIUM_BROWSER: "${{ matrix.selenium-browser }}" 31 | 32 | name: ${{ format('Tests (Ruby {0}, Rails {1}, Browser {2}, Hotwire {3})', matrix.ruby-version, matrix.rails-version, matrix.selenium-browser, matrix.hotwire-enabled) }} 33 | runs-on: "ubuntu-latest" 34 | 35 | steps: 36 | - uses: "actions/checkout@v2" 37 | - uses: "actions/setup-node@v2" 38 | with: 39 | cache: "yarn" 40 | - uses: "ruby/setup-ruby@v1" 41 | with: 42 | ruby-version: ${{ matrix.ruby-version }} 43 | bundler-cache: true 44 | 45 | - run: | 46 | yarn install 47 | yarn build 48 | 49 | - run: bin/rails test test/**/*_test.rb 50 | 51 | - name: Fail when generated changes are not checked-in 52 | run: | 53 | git update-index --refresh 54 | git diff-index --quiet HEAD -- 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /doc/ 3 | /log/*.log 4 | /pkg/ 5 | /tmp/ 6 | /test/dummy/log/*.log 7 | /test/dummy/tmp/ 8 | .byebug_history 9 | Gemfile.lock 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | * Drop [end-of-life Ruby][] versions 2.7 and 3.0. 10 | 11 | *Sean Doyle* 12 | 13 | [end-of-life Ruby]: https://www.ruby-lang.org/en/downloads/branches/ 14 | 15 | * Drop [end-of-life Rails][] versions 6.1 and 7.0 16 | 17 | *Sean Doyle* 18 | 19 | [end-of-life Rails]: https://rubyonrails.org/maintenance 20 | 21 | # 0.1.2 - 2024-10-08 22 | 23 | * Use `Set.add` correctly 24 | 25 | *Sean Doyle* 26 | 27 | ## 0.1.1 - 2024-09-27 28 | 29 | * Expand version matrix to include `ruby@3.3` and `rails@7.2` 30 | 31 | *Sean Doyle* 32 | 33 | * Don't validate Checkbox groups until `validateOn` events 34 | 35 | *Sean Doyle* 36 | 37 | * Add support for opting-into Checkbox group `[required]` validation 38 | 39 | *Sean Doyle* 40 | 41 | * Ignore `[disabled]` fields while validating 42 | 43 | *Sean Doyle* 44 | 45 | * Resolve issue where `:index` was ignored for multiply-nested forms 46 | 47 | *Sean Doyle* 48 | 49 | * Pair calls to [HTMLElement.focus][] with [Element.scrollIntoView][] to 50 | work-around iOS Safari quirks 51 | 52 | *Sean Doyle* 53 | 54 | [HTMLElement.focus]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus 55 | [Element.scrollIntoView]: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView 56 | 57 | * Remove `ruby@2.7`-`rails@main` and `ruby@3.0`-`rails@main` pairings from CI 58 | matrix 59 | 60 | *Sean Doyle* 61 | 62 | * Render server-generated custom validation messages during initial error 63 | reporting 64 | 65 | *Sean Doyle* 66 | 67 | * Focus the first `[aria-invalid]` form control managed by 68 | `ConstraintValidations` on initial page load. 69 | 70 | * Disable submit button when `disableSubmitWhenInvalid: true` and the initial 71 | server-rendered `
` element has invalid fields 72 | 73 | *Sean Doyle* 74 | 75 | * Do not disable a submit button with `[formnovalidate]` as part of handling 76 | `disableSubmitWhenInvalid: true` configuration 77 | 78 | *Sean Doyle* 79 | 80 | ## 0.1.0 - 2023-12-04 81 | 82 | * Add support for Collection `` elements) 88 | 89 | *Sean Doyle* 90 | 91 | * Omit `[aria-*]`- and `[data-*]`-prefixed attributes from `[type="hidden"]` 92 | fields 93 | 94 | *Sean Doyle* 95 | 96 | * Drop intended support for Action Text until the engine itself adds test 97 | coverage. 98 | 99 | *Sean Doyle* 100 | 101 | * Eager-load classes in `CI=true` environments to guard against Zeitwerk 102 | auto-loading issues. 103 | 104 | *Sean Doyle* 105 | 106 | * Extend built-in Action View and Action Text classes with their 107 | fully-qualified class names instead of re-opening their modules or classes. 108 | 109 | *Sean Doyle* 110 | 111 | * (Re-)Validate on both `blur` and `input` events. Re-configure those values 112 | with the `validatesOn:` configuration key. 113 | 114 | *Sean Doyle* 115 | 116 | * Replace `application/validation_messages` JSON template with a configuration 117 | option. 118 | 119 | *Sean Doyle* 120 | 121 | * When a field is determined to be invalid during a client-side submission 122 | validation, focus the first field that is invalid. When multiple fields are 123 | invalid, do not focus fields after the first. When validating on `blur` events, 124 | **do not** focus, since focus is moving manually on behalf of the user. 125 | 126 | *Sean Doyle* 127 | 128 | * Skip `invalid` event intercepts when both `