diff --git a/source/.htaccess b/source/.htaccess index 41562793b..28cf19561 100644 --- a/source/.htaccess +++ b/source/.htaccess @@ -28,6 +28,10 @@ RedirectMatch \/2.*\/(.*)? http://struts.apache.org/$1 # page downloads.html was renamed to releases.html RedirectMatch \/downloads /releases +# page pure-java-script-client-side-validation was folded into client-side-validation as a +# deprecated section, see WW-5694 +RedirectMatch permanent \/core\-developers\/pure\-java\-script\-client\-side\-validation(\.html)?$ /core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated + # always points to the most recent announce-YYYY page, no manual update needed {% assign announcements = site.pages | where_exp: "page", "page.path contains 'announce-'" | sort: "path" -%} RedirectMatch \/announce.html(#a[0-9]+)? {{ announcements.last.url }}$1 diff --git a/source/core-developers/ajax-client-side-validation.md b/source/core-developers/ajax-client-side-validation.md index b9e47ed69..2f52ccff5 100644 --- a/source/core-developers/ajax-client-side-validation.md +++ b/source/core-developers/ajax-client-side-validation.md @@ -14,8 +14,9 @@ parent: ## Description -AJAX-based client side validation improves upon [Pure JavaScript Client Side Validation](pure-java-script-client-side-validation) -by using a combination of JavaScript, DOM manipulation, and remote server communication. Unlike the pure client side +AJAX-based client side validation improves upon [Pure JavaScript Client Side Validation](client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since 7.4.0 [WW-5694](https://issues.apache.org/jira/browse/WW-5694), removed in 8.0.0 +[WW-5696](https://issues.apache.org/jira/browse/WW-5696)) by using a combination of JavaScript, DOM manipulation, and remote server communication. Unlike the pure client side implementation, AJAX-based validation communicates with the server. This means all your validation rules that worked when submitting a form will still work within the browser. diff --git a/source/core-developers/client-side-validation.md b/source/core-developers/client-side-validation.md index 20a8dabad..e3a2949a5 100644 --- a/source/core-developers/client-side-validation.md +++ b/source/core-developers/client-side-validation.md @@ -14,57 +14,162 @@ parent: ## Basics -The framework adds support for client-side validation on top of the standard validation framework. +Since Struts 7.4.0, the [html5 theme](../tag-developers/html5-theme) can derive HTML5 constraint-validation +attributes (`required`, `minlength`, `maxlength`, `pattern`, `min`, `max`) directly from a field's +server-side [validators](validation), so the browser rejects obviously-invalid input before the form is +even submitted. This replaces the older, generated-JavaScript validator used by the _xhtml theme_ and +_css_xhtml theme_, which is now deprecated — see [Pure JavaScript Client Side Validation +(deprecated)](#pure-javascript-client-side-validation-deprecated) below. -Client-side validation can be enabled on a per-form basis by specifying `validate="true"` in the _form_ tag. +There is also [AJAX Client Side Validation](ajax-client-side-validation), which runs the full server-side +validation stack (including visitor validators and `validate()`) over AJAX and is unaffected by any of this. -```jsp - - ... - -``` +## HTML5 Constraint Validation -If a `name` for the form is not given, the action mapping name will be used as the form name. Otherwise, a correct -`action` and `namespace` attributes must be provided to the `` tag. +### Enabling it -## Referencing "submitProfile" in the "/user" namespace +HTML5 constraint validation is off by default. Turn it on with the `struts.ui.html5.constraints` constant: -```jsp - - ... - +```properties +struts.ui.html5.constraints=true +``` + +It only has an effect on fields rendered with the `html5` theme (see [Using the HTML5 +theme](../tag-developers/html5-theme#using-the-html5-theme)). There is no per-form opt-in attribute — +unlike the deprecated JavaScript validator, this feature does not use ``. Once the +constant is on and a field's theme is `html5`, its validators are consulted automatically. + +> The constant defaults to `false` so existing `html5`-theme forms keep rendering unchanged. The default is +> expected to flip to `true` in a future major release, tracked by +> [WW-5696](https://issues.apache.org/jira/browse/WW-5696). + +### The governing rule: never false-reject + +The mapping is deliberately conservative. A constraint is emitted only when the browser cannot reject +input the server would have accepted. If the browser rejected something the server allows, the user would +be stuck with a form that will not submit and no explanation why. Being conservative simply costs a field +its client-side check — that's a harmless, quiet failure mode, so the mapping always chooses it over the +alternative. + +The clearest consequence of this rule: **Struts never sets or changes an input's `type`.** A field stays +whatever `type` the developer gave it. In particular: + +- Switching a field to `type="number"` would reject a value like `1234,50`, which the framework's + locale-aware numeric conversion happily accepts in a comma-decimal locale. +- The browsers' `email` and `url` input grammars don't match `EmailValidator` and `UrlValidator`. + +So `min`/`max` range constraints are only ever added to a control the developer *already* made numeric +(`type="number"` or `type="range"`) — Struts will never promote a plain text field into one just because +an `int` or `double` validator is attached to it. + +### Mapping table + +| Validator | Emits | Condition | +|---|---|---| +| `requiredstring` | `required` | on text-entry controls (`text`, `search`, `tel`, `password`, `email`, `url`) and `textarea` | +| `required` | `required` | only on `radio` and `file` | +| `stringlength` | `minlength` / `maxlength` | on text-entry or `textarea`, and only if the validator has `trim="false"`; each attribute is added only if actually configured | +| `regex` | `pattern` | on text-entry controls only, and only if `caseSensitive="true"`, `trim="false"`, the regex is ECMAScript-safe (see below), and the validator is not an `email` or `creditcard` validator (both extend `RegexFieldValidator` but carry grammars the browser does not share) | +| `int`, `short`, `long` | `min` / `max` | only when the control is already `type="number"` or `type="range"` | +| `double` | `min` / `max` | same as above; only inclusive bounds are emitted — exclusive bounds have no HTML equivalent and are omitted | +| `date` | — | nothing yet; temporal `min`/`max` is deferred to a future release | +| `email`, `url`, `creditcard` | — | never emitted | +| `fieldexpression`, `expression`, `conversion`, visitor validators | — | never emitted | +| any validator carrying a message | `data-msg-` | always added, including for validators that emit no constraint attribute at all | + +Two of these conditions are easy to miss and sharply limit how often `required`, `minlength`/`maxlength`, +and `pattern` actually show up: + +**`required` is split across two validators, and they don't behave alike.** `requiredstring` fails on +null, empty, and (by default) blank values, so it is strictly stricter than the browser's `required` — safe +to emit on any text-entry control. Plain `required`, however, only fails on a null value, an empty array, +or an empty collection. That means an empty text input (which submits `""`, not nothing), a `select` with +an empty-valued option, and an **unticked checkbox** (`CheckboxInterceptor` substitutes the parameter +`"false"` for it) all pass server-side validation while a browser `required` attribute would block them. +Only `radio` and `file` controls omit their parameter entirely when left empty, so those are the only two +control types where plain `required` agrees with the server — which is why the table above emits `required` +for the `required` validator on those two types alone. + +**Both `minlength`/`maxlength` and `pattern` need `trim="false"`, which is not the default.** Both +`StringLengthFieldValidator.trim` and `RegexFieldValidator.trim` default to `true`, so the server measures +or matches the field's *trimmed* value while the HTML attribute constrains the *raw* one. A `stringlength` +validator with `maxLength="4"` accepts `"abcd "` — it trims to four characters, which is within the limit — +but a browser enforcing `maxlength="4"` would stop the user typing the fifth character at all. Likewise, a +`regex` of `[a-z]+` accepts `"abc "` server-side (it trims to `"abc"` first) while the browser, matching the +raw value, blocks it. Because of this, `minlength`/`maxlength` and `pattern` are only ever emitted +for validators explicitly configured with `trim="false"` — which most existing `stringlength` and `regex` +validators are not. In practice, expect both to show up rarely until applications start setting +`trim="false"` deliberately for fields where it's safe. + +**ECMAScript-safe** means the regex uses only constructs that mean the same thing in Java's regex engine +and in the browser's: literals, `\d`/`\w` and their negations, character classes without POSIX or Unicode +property syntax, grouping, alternation, anchors, and bounded quantifiers. Notably, **`\s` and `\S` are +excluded** — Java's `\s` is ASCII-only by default while ECMAScript's `\s` covers the wider Unicode +whitespace set, so a pattern like `^\S+$` would accept a value containing a non-breaking space server-side +and reject it in the browser. Any regex using a construct outside this allowlist simply gets no `pattern` +attribute at all — it is never rejected loudly, it just quietly doesn't get a client-side check. + +### `data-msg-*` attributes + +Every validator carrying a message — even one that emits no HTML constraint attribute at all — adds a +`data-msg-` attribute (for example `data-msg-email`, `data-msg-regex`) holding the +validator's fully resolved, internationalized message. **Struts ships no JavaScript that reads these.** +They exist purely as a hook: an application can write its own script to read `data-msg-*` and show +whichever messages it wants, in whatever way it wants, including for validators (like `email` or +`creditcard`) that never get a native browser check. + +### `requiredLabel` is unrelated to the `required` attribute + +This is a common point of confusion: the `requiredLabel` tag attribute only controls whether a visual +marker (usually `*`) is drawn next to a field's label. It has no connection to the HTML `required` +attribute described above, and setting `requiredLabel="true"` does not make a field required in the +browser — the two are decided completely independently. + +### Extension point: `HtmlConstraintProvider` + +The mapping above is implemented by `StrutsHtmlConstraintProvider`, the default implementation of the +`HtmlConstraintProvider` interface, registered under the `struts.htmlConstraintProvider` constant: + +```properties +struts.htmlConstraintProvider=struts ``` -Technically, the form's action attribute can refer to a "path" that includes the namespace and action as a URI. -But, client-side validation **requires** that the action name and namespeact to be set separately. +An application that wants a less conservative mapping — for example, treating an `email` validator as +`type="email"`, or emitting `pattern` for case-insensitive regexes by rewriting them — can register its own +`HtmlConstraintProvider` implementation under this constant instead of the default. This is the escape +hatch for every limitation described above: the framework's own mapping stays deliberately conservative, +but nothing stops an application from replacing it with one that fits its own validators and locales. + +## Pure JavaScript Client Side Validation (deprecated) {#pure-javascript-client-side-validation-deprecated} + +> **Deprecated since Struts 7.4.0 ([WW-5694](https://issues.apache.org/jira/browse/WW-5694)), removed in +> Struts 8.0.0 ([WW-5696](https://issues.apache.org/jira/browse/WW-5696)).** New applications should use +> the [html5 theme's constraint validation](#html5-constraint-validation) described above instead. -## Won't work with client-side validation! +The `` attribute enables an older client-side validation mechanism, used by the +_xhtml theme_ and _css_xhtml theme_. It uses 100% client-side JavaScript, generated from the same +validation configuration used server-side, to try to reject bad input before the form is submitted: ```jsp - + ... - ``` -All the usual [validation configuration](validation) steps apply to client-side validation. Client-side validation -uses the same validation rules as server-side validation. If server-side validation doesn't work, then client-side -validation won't work either. +If a `name` for the form is not given, the action mapping name is used as the form name. Otherwise, a +correct `action` and `namespace` attribute must be provided to the `` tag — client-side validation +requires the action name and namespace to be resolvable separately, so a form whose `action` is given as a +full URI (for example ``) will not get +client-side validation, even though the form still works. -## The left hand doesn't know ... - -> The required attribute on many _Struts Tags_ is not integrated with client-side validation! The tag attribute is used -> by certain themes (like xhtml) to put a visual marker (usually '*') next to the field. The tag doesn't know -> if the validation system actually "requires" the field or not. +Because the validation logic is repeated in generated JavaScript, only a subset of validators is +supported (`required`, `requiredstring`, `stringlength`, `regex`, `email`, `url`, `int`, `double`), it is +not available for visitor validators at all, and — being a separate implementation of each validator's +logic — some values the JavaScript accepts may still be rejected server-side, or vice versa. This is one of +the reasons it is being replaced: the html5 theme's constraint validation above is derived directly from +the real validators, rather than reimplementing them in JavaScript. ## Example -See [Client Validation example](client-validation-example) for a complete example of client-side validation. - -## Client Side Validation Types - -There are two styles of client side validation. - -|[Pure JavaScript Client Side Validation](pure-java-script-client-side-validation)|Used by the _xhtml theme_ and _css_xhtml theme_| -|-----------------------------------------------------|--------------------------------------------------| -|[AJAX Client Side Validation](ajax-client-side-validation)|Use to used by the _ajax theme_ | +See [Client Validation example](client-validation-example) for a complete, though now-deprecated, example +of the JavaScript-based client-side validation described above. diff --git a/source/core-developers/client-validation-example.md b/source/core-developers/client-validation-example.md index 751e08121..3e3d5573a 100644 --- a/source/core-developers/client-validation-example.md +++ b/source/core-developers/client-validation-example.md @@ -8,6 +8,12 @@ parent: # Client Validation Example +> **Deprecated since Struts 7.4.0 ([WW-5694](https://issues.apache.org/jira/browse/WW-5694)), removed in +> Struts 8.0.0 ([WW-5696](https://issues.apache.org/jira/browse/WW-5696)).** This example walks through the +> generated-JavaScript client-side validator (``) used by the _xhtml theme_ and +> _css_xhtml theme_. New applications should use the [html5 theme's constraint +> validation](client-side-validation#html5-constraint-validation) instead. + Let's create a Client-Side validation workflow, step by step. The `validate` attribute is set to `true`. > Note: Some themes do not support client-side validation. diff --git a/source/core-developers/pure-java-script-client-side-validation.md b/source/core-developers/pure-java-script-client-side-validation.md deleted file mode 100644 index 43fde3e84..000000000 --- a/source/core-developers/pure-java-script-client-side-validation.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -layout: default -title: Pure JavaScript Client Side Validation -parent: - title: Client Side Validation - url: client-side-validation ---- - -# Pure JavaScript Client Side Validation -{:.no_toc} - -* Will be replaced with the ToC, excluding a header -{:toc} - -## Description - -Pure JavaScript client side validation is the simplest but least feature-rich type of [Client Side Validation](client-side-validation). -This type of validation uses 100% client-side JavaScript code to try to validate the values entered by the user. -Because the validation logic is actually repeated in the JavaScript code, it is important to understand that -some values will be considered acceptable by the JavaScript code but will be marked as unacceptable by the server-side [Validation](validation). - -Only the following validators are supported: - -* required validator -* requiredstring validator -* stringlength validator -* regex validator -* email validator -* url validator -* int validator -* double validator - -> JavaScript client validation is not available for visitor validations. - -## Error reporting - -Because client side validation does not talk to the server, the theme (_xhtml theme_ or _css_xhtml theme_ ) is responsible -for properly manipulating the HTML DOM to display the error message inline. The JavaScript that is responsible for doing -this logic is `validation.js` and can be found in each theme. - -> Errors are reported using the default validation message, not the internationalized version that the server-side might -> be aware of. This is a known issue. You may want to try the [AJAX Client Side Validation](ajax-client-side-validation) -> for messages that are fully internationalized. - -## Additional Validator Support - -If you wish to add additional validator support beyond those listed, you may override the _xhtml theme_ template -`form-close-validate.ftl`. This file contains the JavaScript that tries to validate each user-entered value from within -the browser. The _css_xhtml theme_ extends the _xhtml theme_ and therefore doesn't have its own `form-close-validate.ftl` -template. diff --git a/source/tag-developers/css-xhtml-theme.md b/source/tag-developers/css-xhtml-theme.md index a6d3e73e0..0cd207e23 100644 --- a/source/tag-developers/css-xhtml-theme.md +++ b/source/tag-developers/css-xhtml-theme.md @@ -14,8 +14,10 @@ The _css_xhtml theme_ provides all the basics that the [simple theme](simple-the [textfield](textfield-tag), [select](select-tag), etc) - Labels for each of the HTML [Struts Tags](struts-tags), placed according to the CSS stylesheet - [Validation](../core-developers/validation) and error reporting -- [Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation) using 100% - JavaScript on the browser +- [Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) + using 100% JavaScript on the browser — deprecated since 7.4.0 + ([WW-5694](https://issues.apache.org/jira/browse/WW-5694)), removed in 8.0.0 + ([WW-5696](https://issues.apache.org/jira/browse/WW-5696)); use the [html5 theme](html5-theme) instead ## Wrapping the Simple Theme @@ -69,15 +71,17 @@ The head includes a style sheet. The contents of **styles.css** are: ### Form template The css_xhtml [form](form-tag) template is almost exactly like the _xhtml form template_ , including support for -[Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation). The difference -is that instead of printing out an opening and closing `` element, there are no elements. Instead, the CSS rules -for the individual HTML tags are assumed to handle all display logic. However, as noted, client-side validation is still -supported. +[Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since 7.4.0 [WW-5694](https://issues.apache.org/jira/browse/WW-5694), removed in 8.0.0 +[WW-5696](https://issues.apache.org/jira/browse/WW-5696)). The difference is that instead of printing out an opening and closing +`
` element, there are no elements. Instead, the CSS rules for the individual HTML tags are assumed to handle all +display logic. However, as noted, client-side validation is still supported. ### css_xhtml form template The css_xhtml [form](form-tag) template is almost exactly like the _xhtml form template_ , including support for -[Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation). The only -difference is that instead of printing out an opening and closing `
` element, there are no elements. Instead, -the CSS rules for the individual HTML tags are assumed to handle all display logic. However, as noted, client side -validation is still supported. +[Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since 7.4.0 [WW-5694](https://issues.apache.org/jira/browse/WW-5694), removed in 8.0.0 +[WW-5696](https://issues.apache.org/jira/browse/WW-5696)). The only difference is that instead of printing out an opening and +closing `
` element, there are no elements. Instead, the CSS rules for the individual HTML tags are assumed to +handle all display logic. However, as noted, client side validation is still supported. diff --git a/source/tag-developers/form-tag.md b/source/tag-developers/form-tag.md index 52684722e..c516e3730 100644 --- a/source/tag-developers/form-tag.md +++ b/source/tag-developers/form-tag.md @@ -41,3 +41,10 @@ There are two flavours [Client Side Validation](../core-developers/client-side-v are using (xhtml, ajax, etc). If you are using the [xhtml theme](xhtml-theme) or [css_xhtml theme](css-xhtml-theme), pure client side validation will be used. Read the [Client Side Validation](../core-developers/client-side-validation) docs for more information. + +> **`validate` is deprecated since Struts 7.4.0 and will be removed in 8.0.0** +> ([WW-5694](https://issues.apache.org/jira/browse/WW-5694), +> [WW-5696](https://issues.apache.org/jira/browse/WW-5696)). It only controls the older, generated-JavaScript +> client-side validator used by the xhtml and css_xhtml themes. It has no effect on the [html5 theme's constraint +> validation](../core-developers/client-side-validation#html5-constraint-validation), which applications should +> use instead. diff --git a/source/tag-developers/xhtml-theme.md b/source/tag-developers/xhtml-theme.md index feb021489..50297eea9 100644 --- a/source/tag-developers/xhtml-theme.md +++ b/source/tag-developers/xhtml-theme.md @@ -19,8 +19,10 @@ The xhtml provides all the basics that the [simple theme](simple-theme) provides - Labels for each of the HTML [Struts Tags](struts-tags) on the left hand side (or top, depending on the `labelposition` attribute) - [Validation](../core-developers/validation) and error reporting -- [Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation) using - 100% JavaScript on the browser +- [Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) + using 100% JavaScript on the browser — deprecated since 7.4.0 + ([WW-5694](https://issues.apache.org/jira/browse/WW-5694)), removed in 8.0.0 + ([WW-5696](https://issues.apache.org/jira/browse/WW-5696)); use the [html5 theme](html5-theme) instead ## Wrapping the Simple Theme @@ -94,7 +96,9 @@ The head template imports a style sheet. The contents of **styles.css** are: The xhtml form template sets up the wrapping table around all the other form elements. In addition to creating this wrapping table, the opening and closing templates also, if the `validate` parameter is set to true, enable -[Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation). +[Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since 7.4.0 [WW-5694](https://issues.apache.org/jira/browse/WW-5694), removed in 8.0.0 +[WW-5696](https://issues.apache.org/jira/browse/WW-5696)). {% highlight freemarker %} {% remote_file_content https://raw.githubusercontent.com/apache/struts/main/core/src/main/resources/template/xhtml/form.ftl %} @@ -110,7 +114,9 @@ The closing template, `form-close.ftl`: The xhtml form template sets up the wrapping table around all the other [xhtml theme](xhtml-theme) form elements. In addition to creating this wrapping table, the opening and closing templates also, if the `validate` parameter is set -to `true`, enable [Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation.htmk). +to `true`, enable [Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since 7.4.0 [WW-5694](https://issues.apache.org/jira/browse/WW-5694), removed in 8.0.0 +[WW-5696](https://issues.apache.org/jira/browse/WW-5696)). See the **form.ftl** contents: