docs: HTML5 constraint validation, deprecate the JavaScript validator (#326)

* docs: document html5 constraint validation, deprecate the JS validator

Rewrites client-side-validation.md around the html5 theme's new HTML5
constraint-validation attributes (struts.ui.html5.constraints), including the
never-false-reject rule, the full validator-to-attribute mapping, the
trim="false"/caseSensitive="true" conditions on stringlength/regex, the
never-change-the-type rule, data-msg-* hooks, the requiredLabel/required
distinction, and the swappable HtmlConstraintProvider extension point.

Deprecates the older generated-JavaScript client-side validator (xhtml/
css_xhtml themes, <s:form validate="true">) per WW-5694, removed in 8.0.0 per
WW-5696: deletes pure-java-script-client-side-validation.md, repoints its
inbound links (xhtml-theme.md, css-xhtml-theme.md, ajax-client-side-validation.md)
to the deprecated section of the rewritten page, adds deprecation banners to
client-validation-example.md and form-tag.md's validate attribute.

Drops the deleted page's claim that client-side messages are not
internationalized: ValidatorSupport.getMessage resolves through
DelegatingValidatorContext and textProviderFactory, so they always were.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: stop asserting a specific version for the html5.constraints default flip

The shipped javadoc and default.properties deliberately say the
struts.ui.html5.constraints default is "expected to flip in a future major
release" rather than naming 8.0.0, since the release version is chosen at
release time from the accumulated semver impact. The docs page asserted "in
Struts 8.0.0" instead, which is a firmer commitment than the code itself
makes. Softened to match the code's wording, with WW-5696 linked so the claim
stays traceable.

Also makes every other "removed in 8.0.0" claim (the JS validator's removal)
cite WW-5694/WW-5696 inline rather than floating as a bare assertion. Naming
8.0.0 for that removal is kept as-is: it's a major-version removal, already
committed to in Form.java's own @Deprecated(since = "7.4.0", forRemoval =
true) javadoc, and WW-5696 is filed against it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: add the regex validator's fourth pattern gate, generalize the trim note

The regex row promised pattern whenever text-entry, caseSensitive="true",
trim="false" and ECMAScript-safe held, but StrutsHtmlConstraintProvider has a
fourth gate: email and creditcard validators are excluded even then, since
both extend RegexFieldValidator but carry grammars the browser doesn't share.

Also generalizes the trim="false" explanation: StringLengthFieldValidator.trim
defaults to true just like RegexFieldValidator.trim, so minlength/maxlength are
emitted just as rarely as pattern is, for the same reason (server measures/
matches the trimmed value, browser sees the raw one). The page previously
warned about this only for pattern, which understated stringlength's own
reach. Reworked into one shared paragraph covering both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: fix the stringlength example's direction (server accepts, browser blocks)

The previous sentence said a stringlength validator with maxLength="4" would
reject "abcd " server-side after trimming — backwards. Trimmed to "abcd" (4
chars), StringLengthFieldValidator.validateValue only rejects when
trimmedLength > maxLengthToUse, and 4 > 4 is false, so the server accepts it.
The paragraph exists to show the server-accepts/browser-blocks asymmetry that
makes emitting the constraint attribute risky if trim isn't false; an example
asserting the opposite direction illustrated nothing.

Corrected to state the server accepts "abcd " while a browser maxlength="4"
would stop the fifth character from ever being typed, matching the direction
of the retained [a-z]+/"abc " regex example alongside it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: redirect the removed pure-javascript page to its new section

The page was folded into client-side-validation.md as a deprecated section,
which frees the URL but 404s external inbound links to a page that has been
live for years. Internal links were already updated; this covers the ones we
do not control.

Uses .htaccess rather than leaving a stub page behind, following the existing
"downloads was renamed to releases" precedent in the same file: no orphan page
in the nav tree, and the reader lands on the section rather than on a pointer
to it. Matches both the extensionless and .html forms.

Issued as a permanent (301) redirect. The fold-in is not going to be undone,
and 301 is what consolidates the old URL's link equity onto the new section;
the surrounding rules only default to 302 because none of them ever specified.

Pins the target heading's anchor explicitly with {#...} instead of relying on
kramdown's auto_ids. The generated id is identical today, but eight internal
links and the redirect now depend on it, so it should not be a side effect of
the heading's wording.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
8 files changed
tree: 025089315b84488b8734898e692d5e23f29e128d
  1. .claude/
  2. docs/
  3. source/
  4. src/
  5. .asf.yaml
  6. .gitignore
  7. _config.yml
  8. CLAUDE.md
  9. docker-arm64-serve.sh
  10. docker-build.sh
  11. Dockerfile
  12. Gemfile
  13. GEMINI.md
  14. Jenkinsfile
  15. Jenkinsfile.javadocs
  16. PLACEHOLDER
  17. pom.xml
  18. README.md
README.md

Apache Struts Website

This project is used to update the main Apache Struts website http://struts.apache.org/
See the update website documentation on how to push changes online. However as ASF is using aggressive caching, for a while one still may need to forcely reload the page (CMD+R or Shift+F5) after changes.

Site is generated by Jekyll and uses pure html either markdown format. To test website locally you can use the below command:

bundle exec jekyll serve -w --trace --host 0.0.0.0

or you can use Docker (please install it first) with one of the provided scripts:

./docker-run.fish

when running fish-shell, or:

./docker-run.sh

when running Bash or Sh.

The continuously generated website can then be accessed at http://localhost:4000

All pages are generated into the content folder.

There are two scripts used to build the image but this should be used only when Dockerfile was modified.

Some redirect rules are configured in source/.htaccess file.

Preparing a new release

When announcing a new release, update the following files together:

  1. _config.yml - bump current_version / prev_version (and the matching *_short and release_date variables).
  2. source/announce-YYYY.md - add the announcement entry for the new release in the current year's file.
  3. source/releases.md - move the version that has just been superseded into the Prior Releases table so the page reflects what is no longer the recommended download.