brut-js 0.9.2 → 0.10.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brut-js",
3
- "version": "0.9.2",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "keywords": [ "WebComponents", "Custom Elements" ],
6
6
  "bugs": {
@@ -18,9 +18,12 @@ describe("<brut-cv-messages>", () => {
18
18
 
19
19
  element.createMessages({validityState,inputName})
20
20
 
21
- assert.equal(element.querySelectorAll("brut-cv").length,2)
21
+ const brutCvElements = element.querySelectorAll("brut-cv")
22
+ assert.equal(brutCvElements.length, 2)
22
23
  assert.match(element.textContent,new RegExp("This field does not match the pattern","m"))
23
24
  assert.match(element.textContent,new RegExp("This field is above the range","m"))
25
+ assert.equal(brutCvElements[0].getAttribute("client-side"),"")
26
+ assert.equal(brutCvElements[1].getAttribute("client-side"),"")
24
27
 
25
28
  element.clearClientSideMessages()
26
29
  assert.equal(element.textContent,"")
@@ -6,12 +6,12 @@ describe("<brut-form>", () => {
6
6
  <form>
7
7
  <label>
8
8
  <input required type="text" name="text">
9
- <brut-cv-messages>
9
+ <brut-cv-messages input-name="text">
10
10
  </brut-cv-messages>
11
11
  </label>
12
12
  <label>
13
13
  <input required type="number" name="number">
14
- <brut-cv-messages>
14
+ <brut-cv-messages input-name="number">
15
15
  </brut-cv-messages>
16
16
  </label>
17
17
  <input type="submit">Save</input>
@@ -134,48 +134,4 @@ describe("<brut-form>", () => {
134
134
  assert(gotValid)
135
135
  assert(!gotInvalid)
136
136
  })
137
- withHTML(`
138
- <brut-form>
139
- <form>
140
- <label>
141
- <input required type="text" name="text">
142
- </label>
143
- <brut-cv-messages input-name='text'>
144
- </brut-cv-messages>
145
- <input type="submit">Save</input>
146
- </form>
147
- </brut-form>
148
- `).test("locates the messages for errors based on name", ({window,document,assert}) => {
149
-
150
- const brutForm = document.querySelector("brut-form")
151
- const form = brutForm.querySelector("form")
152
- const button = form.querySelector("input[type=submit]")
153
- const textFieldLabel = form.querySelector("label:has(input[type=text])")
154
-
155
- let submitted = false
156
- let gotInvalid = false
157
- let gotValid = false
158
-
159
- form.addEventListener("submit", (event) => {
160
- event.preventDefault()
161
- submitted = true
162
- })
163
- brutForm.addEventListener("brut:valid", () => {
164
- gotValid = true
165
- })
166
- brutForm.addEventListener("brut:invalid", () => {
167
- gotInvalid = true
168
- })
169
-
170
- button.click()
171
-
172
- assert(!submitted)
173
- assert(!gotValid)
174
- assert(gotInvalid)
175
- assert.equal(brutForm.getAttribute("submitted-invalid"),"")
176
-
177
- let error = brutForm.querySelector("brut-cv[input-name='text'][key='cv.cs.valueMissing']")
178
- assert(error)
179
-
180
- })
181
137
  })
@@ -15,9 +15,15 @@ import I18nTranslation from "./I18nTranslation"
15
15
  * @property {string} key - the i18n translation key to use. It must map to the `key` of a `<brut-i18n-translation>` on the page or
16
16
  * the element will not render any text.
17
17
  * @property {string} input-name - the name of the input, used to insert into the message, e.g. "Title is required".
18
+ * @property {boolean} server-generated if true, this indicates the element's HTML was generated on the server.
19
+ * This means that your CSS can target it for display in all cases. If this is not present,
20
+ * you may want to avoid showing this element if the form has not been submitted yet.
21
+ * Does not affect behavior.
18
22
  * @property {boolean} server-side if true, this indicates the element contains constraint violation messages
19
- * from the server. Currently doesn't affect this element's behavior, however
20
- * AjaxSubmit will use it to locate where it should insert server-side errors.
23
+ * from the server. Does not affect behavior.
24
+ * @property {boolean} client-side if true, this indicates the element contains constraint violation messages
25
+ * from the client, however they may have been generated from the server, since the server may
26
+ * re-evaluate the client-side constraints. Does not affect behavior of this tag.
21
27
  *
22
28
  * @see I18nTranslation
23
29
  * @see ConstraintViolationMessages
@@ -33,12 +39,15 @@ class ConstraintViolationMessage extends BaseCustomElement {
33
39
  "key",
34
40
  "input-name",
35
41
  "server-side",
42
+ "client-side",
43
+ "server-generated",
36
44
  ]
37
45
 
38
46
  static createElement(document,attributes) {
39
47
  const element = document.createElement(ConstraintViolationMessage.tagName)
40
48
  element.setAttribute("key",this.i18nKey("cs", attributes.key))
41
49
  element.setAttribute("input-name",attributes["input-name"])
50
+ element.setAttribute("client-side","")
42
51
  if (Object.hasOwn(attributes,"show-warnings")) {
43
52
  element.setAttribute("show-warnings",attributes["show-warnings"])
44
53
  }
@@ -85,6 +94,12 @@ class ConstraintViolationMessage extends BaseCustomElement {
85
94
  serverSideChangedCallback({newValueAsBoolean}) {
86
95
  // attribute listed for documentation purposes only
87
96
  }
97
+ clientSideChangedCallback({newValueAsBoolean}) {
98
+ // attribute listed for documentation purposes only
99
+ }
100
+ serverGeneratedChangedCallback({newValueAsBoolean}) {
101
+ // attribute listed for documentation purposes only
102
+ }
88
103
 
89
104
  update() {
90
105
  if (!this.#key) {
package/src/Form.js CHANGED
@@ -15,10 +15,7 @@ import ConstraintViolationMessages from "./ConstraintViolationMessages"
15
15
  * set `submitted-invalid` on itself when that happens, thus allowing you to target invalid
16
16
  * fields only after a submission attempt.
17
17
  * * You may wish to control the messaging of client-side constraint violations
18
- * beyond what the browser gives you. Assuming your `INPUT` tags are inside a container
19
- * like `LABEL`, a `brut-cv` tag found in that container
20
- * (i.e. a sibling of your `INPUT`) will be modified to contain error messages specific
21
- * to the {@link external:ValidityState} of the control.
18
+ * beyond what the browser gives you. Assuming you have generated a `<brut-cv-messages input-name="«input name»"></brut-cv-messasges>`, it will be populated with `<brut-cv>` elements for each client-side constraint violation, based on the {@link external:ValidityState} of the control.
22
19
  *
23
20
  * @fires brut:invalid Fired when any element is found to be invalid
24
21
  * @fires brut:valid Fired when no element is found to be invalid. This should be reliable to know
@@ -29,12 +26,12 @@ import ConstraintViolationMessages from "./ConstraintViolationMessages"
29
26
  * <form ...>
30
27
  * <label>
31
28
  * <input type="text" required name="username">
32
- * <brut-cv-messages>
29
+ * <brut-cv-messages input-name="username">
33
30
  * </brut-cv-messages>
34
31
  * </label>
35
32
  * <div> <!-- container need not be a label -->
36
33
  * <input type="text" required minlength="4" name="alias">
37
- * <brut-cv-messages>
34
+ * <brut-cv-messages input-name="alias">
38
35
  * </brut-cv-messages>
39
36
  * </div>
40
37
  * <button>Submit</button>
@@ -45,13 +42,13 @@ import ConstraintViolationMessages from "./ConstraintViolationMessages"
45
42
  * <form ...>
46
43
  * <label>
47
44
  * <input type="text" required name="username">
48
- * <brut-cv-messages>
45
+ * <brut-cv-messages input-name="username">
49
46
  * <brut-cv>This field is required</brut-cv>
50
47
  * </brut-cv-messages>
51
48
  * </label>
52
49
  * <div> <!-- container need not be a label -->
53
50
  * <input type="text" required minlength="4" name="alias">
54
- * <brut-cv-messages>
51
+ * <brut-cv-messages input-name="alias">
55
52
  * <brut-cv>This field is required</brut-cv>
56
53
  * </brut-cv-messages>
57
54
  * </div>
@@ -107,28 +104,27 @@ class Form extends BaseCustomElement {
107
104
 
108
105
  #updateErrorMessages(event) {
109
106
  const element = event.target
110
- const selector = ConstraintViolationMessages.tagName
111
- let errorLabels = element.parentNode.querySelectorAll(selector)
112
- if (errorLabels.length == 0) {
113
- if (element.name && element.form) {
114
- const moreGeneralSelector = `${ConstraintViolationMessages.tagName}[input-name='${element.name}']`
115
- errorLabels = element.form.querySelectorAll(moreGeneralSelector)
116
- if (errorLabels.length == 0) {
117
- this.logger.warn(`Did not find any elements matching ${selector} or ${moreGeneralSelector}, so no error messages will be shown`)
118
- }
107
+ let constraintViolationMessages = []
108
+ if (element.name && element.form) {
109
+ const selector = `${ConstraintViolationMessages.tagName}[input-name='${element.name}']`
110
+ constraintViolationMessages = element.form.querySelectorAll(selector)
111
+ if (constraintViolationMessages.length == 0) {
112
+ this.logger.warn(`Did not find any elements matching ${selector}, so no error messages will be shown`)
113
+ }
114
+ }
115
+ else {
116
+ if (element.name) {
117
+ this.logger.warn("Element has a name (%s), but is not associated with any form.", element.name)
119
118
  }
120
119
  else {
121
- this.logger.warn("Did not find any elements matching %s and the form element has %s %s",
122
- selector,
123
- element.name ? "no name" : "a name, but",
124
- element.form ? "no form" : "though has a form")
120
+ this.logger.warn("Element has a form, but has no name, which means we cannot locate %s by input-name", ConstraintViolationMessages.tagName)
125
121
  }
126
122
  }
127
- if (errorLabels.length == 0) {
123
+ if (constraintViolationMessages.length == 0) {
128
124
  return
129
125
  }
130
126
  let anyErrors = false
131
- errorLabels.forEach( (errorLabel) => {
127
+ constraintViolationMessages.forEach( (errorLabel) => {
132
128
  if (element.validity.valid) {
133
129
  errorLabel.clearClientSideMessages()
134
130
  }