From fb5e3be03bbe83f94adc336a7210806b79dbaa91 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 6 Mar 2024 18:38:22 -0500 Subject: [PATCH] Don't validate `input[type="checkbox"]:disabled` When validating with `CheckboxValidator`, don't include `:disabled` checkboxes when determining group validity. --- CHANGELOG.md | 4 ++++ README.md | 2 ++ app/assets/javascripts/constraint_validations.es.js | 10 +++++----- .../javascripts/constraint_validations.es.js.map | 2 +- app/assets/javascripts/constraint_validations.js | 8 ++++---- app/assets/javascripts/constraint_validations.js.map | 2 +- app/javascript/constraint_validations/index.js | 6 +----- app/javascript/constraint_validations/util.js | 4 ++++ .../validators/checkbox_validator.js | 4 ++-- test/dummy/app/views/forms/new.html.erb | 5 +++-- test/system/validations_test.rb | 10 +++++++--- 11 files changed, 34 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b660091..577e4e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +* Add support for opting-into Checkbox group `[required]` validation + + *Sean Doyle* + * Ignore `[disabled]` fields while validating *Sean Doyle* diff --git a/README.md b/README.md index 5e7a4e4..e5bb710 100644 --- a/README.md +++ b/README.md @@ -419,6 +419,8 @@ Then, render a group of `` elements as `[required]`: ``` +Disabled form controls won't be validated. + #### How it works To work-around the quirks of built-in support, `ConstraintValidations` monitors diff --git a/app/assets/javascripts/constraint_validations.es.js b/app/assets/javascripts/constraint_validations.es.js index a2c9272..ec16c5d 100644 --- a/app/assets/javascripts/constraint_validations.es.js +++ b/app/assets/javascripts/constraint_validations.es.js @@ -1,3 +1,7 @@ +function isFieldElement(element) { + return !element.disabled && "validity" in element && element.willValidate +} + function readValidationMessages(input) { try { return JSON.parse(input.getAttribute("data-validation-messages")) || {} @@ -39,7 +43,7 @@ class CheckboxValidator { } validate(target) { - const checkboxesInGroup = checkboxGroup(target); + const checkboxesInGroup = checkboxGroup(target).filter(isFieldElement); const allRequired = checkboxesInGroup.every((checkbox) => checkbox.getAttribute("aria-required") === "true"); const someChecked = checkboxesInGroup.some((checkbox) => checkbox.checked); @@ -328,9 +332,5 @@ function getValidationMessage(input) { return validationMessage || input.validationMessage } -function isFieldElement(element) { - return !element.disabled && "validity" in element && element.willValidate -} - export default ConstraintValidations; //# sourceMappingURL=constraint_validations.es.js.map diff --git a/app/assets/javascripts/constraint_validations.es.js.map b/app/assets/javascripts/constraint_validations.es.js.map index 35988c8..a2924ec 100644 --- a/app/assets/javascripts/constraint_validations.es.js.map +++ b/app/assets/javascripts/constraint_validations.es.js.map @@ -1 +1 @@ -{"version":3,"file":"constraint_validations.es.js","sources":["../../javascript/constraint_validations/util.js","../../javascript/constraint_validations/validators/checkbox_validator.js","../../javascript/constraint_validations/index.js"],"sourcesContent":["export function readValidationMessages(input) {\n try {\n return JSON.parse(input.getAttribute(\"data-validation-messages\")) || {}\n } catch(_) {\n return {}\n }\n}\n","import { readValidationMessages } from \"../util\"\n\nexport default class {\n ignoringMutations = false\n\n constructor(constraintValidations, predicate) {\n this.constraintValidations = constraintValidations\n this.mutationObserver = new MutationObserver(this.handleMutation)\n this.enabled = typeof predicate === \"function\" ?\n predicate :\n (group) => !!predicate\n }\n\n connect() {\n this.mutationObserver.observe(this.element, {\n attributeFilter: [\"required\"],\n childList: true,\n subtree: true\n })\n this.overrideNodes(this.element.querySelectorAll(\"input[type=checkbox][required]\"))\n }\n\n disconnect() {\n this.mutationObserver.disconnect()\n }\n\n willValidate(target) {\n return this.willValidateGroup(checkboxGroup(target))\n }\n\n willValidateGroup(group) {\n return group.length > 0 && this.enabled(group)\n }\n\n validate(target) {\n const checkboxesInGroup = checkboxGroup(target)\n const allRequired = checkboxesInGroup.every((checkbox) => checkbox.getAttribute(\"aria-required\") === \"true\")\n const someChecked = checkboxesInGroup.some((checkbox) => checkbox.checked)\n\n if (allRequired && someChecked) {\n for (const checkbox of checkboxesInGroup) {\n this.constraintValidations.clearValidity(checkbox)\n }\n } else if (allRequired) {\n for (const checkbox of checkboxesInGroup) {\n const validationMessages = readValidationMessages(checkbox)\n\n checkbox.setCustomValidity(validationMessages.valueMissing)\n this.constraintValidations.reportValidity(checkbox)\n }\n }\n }\n\n handleMutation = (mutationRecords) => {\n if (this.ignoringMutations) return\n\n for (const { addedNodes, target, type } of mutationRecords) {\n if (type === \"attributes\") {\n if (target.required) {\n this.swapRequiredWithAriaRequired(target)\n } else {\n target.removeAttribute(\"aria-required\")\n }\n } else if (addedNodes.length) {\n this.overrideNodes(addedNodes)\n }\n }\n }\n\n overrideNodes(nodes) {\n const requiredCheckboxes = querySelectorAllNodes(\"input[type=checkbox][required]\", nodes)\n\n for (const checkbox of requiredCheckboxes) {\n if (checkbox.required) {\n const group = checkboxGroup(checkbox)\n\n if (this.willValidateGroup(group)) {\n for (const checkboxInGroup of group) {\n this.swapRequiredWithAriaRequired(checkboxInGroup)\n this.validate(checkboxInGroup)\n }\n }\n }\n }\n }\n\n swapRequiredWithAriaRequired(element) {\n this.ignoringMutations = true\n element.required = false\n element.setAttribute(\"aria-required\", \"true\")\n setTimeout(() => this.ignoringMutations = false, 0)\n }\n\n get element() {\n return this.constraintValidations.element\n }\n}\n\nfunction checkboxGroup(formControl) {\n const results = new Set\n const { name, form } = formControl\n\n if (name && form instanceof HTMLFormElement) {\n const group = form.elements.namedItem(name)\n const elements = Symbol.iterator in group ?\n group :\n [group]\n\n for (const element of elements) {\n if (element.type === \"checkbox\") {\n results.add(element)\n }\n }\n\n if (results.size === 1 && results.has(formControl)) {\n results.clear()\n }\n }\n\n return Array.from(results)\n}\n\nfunction querySelectorAllNodes(selector, nodes, elements = new Set) {\n for (const node of nodes) {\n if (node instanceof Element) {\n if (node.matches(selector)) {\n elements.add(node)\n }\n\n elements.add(...querySelectorAllNodes(selector, node.children, elements))\n }\n }\n\n return Array.from(elements)\n}\n","import { readValidationMessages } from \"./util\"\nimport CheckboxValidator from \"./validators/checkbox_validator\"\n\nconst defaultOptions = {\n disableSubmitWhenInvalid: false,\n validateOn: [\"blur\", \"input\"],\n validators: {\n checkbox: false\n }\n}\n\nexport default class ConstraintValidations {\n static connect(element = document, options = {}) {\n new this(element, options).connect()\n }\n\n constructor(element = document, options = {}) {\n this.element = element\n this.options = { ...defaultOptions, ...options }\n this.validators = [\n new CheckboxValidator(this, this.options.validators.checkbox)\n ]\n }\n\n connect() {\n this.validators.forEach(validator => validator.connect())\n this.element.addEventListener(\"invalid\", this.reportFieldValidity, { capture: true, passive: false })\n\n for (const eventName of this.options.validateOn) {\n this.element.addEventListener(eventName, this.clearAndReportFieldValidity, { capture: true, passive: true })\n }\n\n this.element.addEventListener(\"input\", this.toggleSubmitsDisabled)\n\n this.reportValidationMessages(\n this.element instanceof HTMLFormElement ?\n [this.element] :\n Array.from(this.element.querySelectorAll(\"form\"))\n )\n }\n\n disconnect() {\n this.element.removeEventListener(\"invalid\", this.reportFieldValidity, { capture: true, passive: false })\n\n for (const eventName of this.options.validateOn) {\n this.element.removeEventListener(eventName, this.clearAndReportFieldValidity, { capture: true, passive: true })\n }\n\n this.element.removeEventListener(\"input\", this.toggleSubmitsDisabled)\n this.validators.forEach(validator => validator.disconnect())\n }\n\n reportFieldValidity = (event) => {\n if (isFieldElement(event.target) && this.reportValidity(event.target)) {\n event.preventDefault()\n\n focusFirstInvalidField(event.target.form || event.target)\n }\n }\n\n clearAndReportFieldValidity = ({ target }) => {\n const validator = this.validators.find(validator => validator.willValidate(target))\n\n if (validator) {\n validator.validate(target)\n } else if (isFieldElement(target)) {\n this.clearValidity(target)\n this.reportValidity(target)\n }\n }\n\n toggleSubmitsDisabled = ({ target }) => {\n if (isFieldElement(target) && this.willDisableSubmitWhenInvalid(target)) {\n disableSubmitWhenInvalid(target.form)\n }\n }\n\n reportValidationMessages(forms) {\n const invalidFields = []\n\n for (const form of forms) {\n for (const element of Array.from(form.elements).filter(isFieldElement)) {\n const serverRenderedInvalid = /true/i.test(element.getAttribute(\"aria-invalid\"))\n const id = element.getAttribute(\"aria-errormessage\")\n const errorMessageElement = document.getElementById(id)\n const validationMessage = errorMessageElement?.textContent\n\n if (validationMessage) {\n element.setCustomValidity(validationMessage)\n }\n\n if (validationMessage || serverRenderedInvalid) {\n this.reportValidity(element)\n invalidFields.push(element)\n }\n\n if (this.willDisableSubmitWhenInvalid(element)) {\n disableSubmitWhenInvalid(form)\n }\n }\n }\n\n const [firstInvalidField] = invalidFields\n firstInvalidField?.focus()\n }\n\n willDisableSubmitWhenInvalid(target) {\n return typeof this.options.disableSubmitWhenInvalid === \"function\" ?\n this.options.disableSubmitWhenInvalid(target) :\n !!this.options.disableSubmitWhenInvalid\n }\n\n clearValidity(input) {\n input.setCustomValidity(\"\")\n\n this.reportValidity(input)\n }\n\n reportValidity(input) {\n const id = input.getAttribute(\"aria-errormessage\")\n const validationMessage = getValidationMessage(input)\n const element = document.getElementById(id) || createValidationMessageFragment(input.form)\n\n if (input.form?.noValidate) {\n return false\n } else if (id && element) {\n element.id = id\n element.innerHTML = validationMessage\n\n if (validationMessage) {\n input.setCustomValidity(validationMessage)\n input.setAttribute(\"aria-describedby\", id)\n input.setAttribute(\"aria-invalid\", \"true\")\n } else {\n input.removeAttribute(\"aria-describedby\")\n input.removeAttribute(\"aria-invalid\")\n }\n\n if (!element.parentElement) {\n input.insertAdjacentElement(\"afterend\", element)\n }\n\n if (input.form && this.willDisableSubmitWhenInvalid(input)) disableSubmitWhenInvalid(input.form)\n\n return true\n } else {\n return false\n }\n }\n}\n\nfunction focusFirstInvalidField(element) {\n if (element instanceof HTMLFormElement) {\n return Array.from(element.elements).some(field => focusFirstInvalidField(field))\n } else if (isFieldElement(element) && !element.validity.valid) {\n element.focus()\n element.scrollIntoView()\n return true\n } else {\n return false\n }\n}\n\nfunction disableSubmitWhenInvalid(form) {\n if (!form || form.noValidate) return\n\n const isValid = Array.from(form.elements).filter(isFieldElement).every(input => input.validity.valid)\n\n for (const element of form.elements) {\n if (element.type == \"submit\" && !element.formNoValidate) {\n element.disabled = !isValid\n }\n }\n}\n\nfunction createValidationMessageFragment(form) {\n if (form) {\n const template = form.querySelector(\"[data-validation-message-template]\")\n\n return template?.content.children[0].cloneNode()\n }\n}\n\nfunction getValidationMessage(input) {\n const validationMessages = Object.entries(readValidationMessages(input))\n\n const [ _, validationMessage ] = validationMessages.find(([ key ]) => input.validity[key]) || [ null, null ]\n\n return validationMessage || input.validationMessage\n}\n\nfunction isFieldElement(element) {\n return !element.disabled && \"validity\" in element && element.willValidate\n}\n"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"constraint_validations.es.js","sources":["../../javascript/constraint_validations/util.js","../../javascript/constraint_validations/validators/checkbox_validator.js","../../javascript/constraint_validations/index.js"],"sourcesContent":["export function isFieldElement(element) {\n return !element.disabled && \"validity\" in element && element.willValidate\n}\n\nexport function readValidationMessages(input) {\n try {\n return JSON.parse(input.getAttribute(\"data-validation-messages\")) || {}\n } catch(_) {\n return {}\n }\n}\n","import { isFieldElement, readValidationMessages } from \"../util\"\n\nexport default class {\n ignoringMutations = false\n\n constructor(constraintValidations, predicate) {\n this.constraintValidations = constraintValidations\n this.mutationObserver = new MutationObserver(this.handleMutation)\n this.enabled = typeof predicate === \"function\" ?\n predicate :\n (group) => !!predicate\n }\n\n connect() {\n this.mutationObserver.observe(this.element, {\n attributeFilter: [\"required\"],\n childList: true,\n subtree: true\n })\n this.overrideNodes(this.element.querySelectorAll(\"input[type=checkbox][required]\"))\n }\n\n disconnect() {\n this.mutationObserver.disconnect()\n }\n\n willValidate(target) {\n return this.willValidateGroup(checkboxGroup(target))\n }\n\n willValidateGroup(group) {\n return group.length > 0 && this.enabled(group)\n }\n\n validate(target) {\n const checkboxesInGroup = checkboxGroup(target).filter(isFieldElement)\n const allRequired = checkboxesInGroup.every((checkbox) => checkbox.getAttribute(\"aria-required\") === \"true\")\n const someChecked = checkboxesInGroup.some((checkbox) => checkbox.checked)\n\n if (allRequired && someChecked) {\n for (const checkbox of checkboxesInGroup) {\n this.constraintValidations.clearValidity(checkbox)\n }\n } else if (allRequired) {\n for (const checkbox of checkboxesInGroup) {\n const validationMessages = readValidationMessages(checkbox)\n\n checkbox.setCustomValidity(validationMessages.valueMissing)\n this.constraintValidations.reportValidity(checkbox)\n }\n }\n }\n\n handleMutation = (mutationRecords) => {\n if (this.ignoringMutations) return\n\n for (const { addedNodes, target, type } of mutationRecords) {\n if (type === \"attributes\") {\n if (target.required) {\n this.swapRequiredWithAriaRequired(target)\n } else {\n target.removeAttribute(\"aria-required\")\n }\n } else if (addedNodes.length) {\n this.overrideNodes(addedNodes)\n }\n }\n }\n\n overrideNodes(nodes) {\n const requiredCheckboxes = querySelectorAllNodes(\"input[type=checkbox][required]\", nodes)\n\n for (const checkbox of requiredCheckboxes) {\n if (checkbox.required) {\n const group = checkboxGroup(checkbox)\n\n if (this.willValidateGroup(group)) {\n for (const checkboxInGroup of group) {\n this.swapRequiredWithAriaRequired(checkboxInGroup)\n this.validate(checkboxInGroup)\n }\n }\n }\n }\n }\n\n swapRequiredWithAriaRequired(element) {\n this.ignoringMutations = true\n element.required = false\n element.setAttribute(\"aria-required\", \"true\")\n setTimeout(() => this.ignoringMutations = false, 0)\n }\n\n get element() {\n return this.constraintValidations.element\n }\n}\n\nfunction checkboxGroup(formControl) {\n const results = new Set\n const { name, form } = formControl\n\n if (name && form instanceof HTMLFormElement) {\n const group = form.elements.namedItem(name)\n const elements = Symbol.iterator in group ?\n group :\n [group]\n\n for (const element of elements) {\n if (element.type === \"checkbox\") {\n results.add(element)\n }\n }\n\n if (results.size === 1 && results.has(formControl)) {\n results.clear()\n }\n }\n\n return Array.from(results)\n}\n\nfunction querySelectorAllNodes(selector, nodes, elements = new Set) {\n for (const node of nodes) {\n if (node instanceof Element) {\n if (node.matches(selector)) {\n elements.add(node)\n }\n\n elements.add(...querySelectorAllNodes(selector, node.children, elements))\n }\n }\n\n return Array.from(elements)\n}\n","import { isFieldElement, readValidationMessages } from \"./util\"\nimport CheckboxValidator from \"./validators/checkbox_validator\"\n\nconst defaultOptions = {\n disableSubmitWhenInvalid: false,\n validateOn: [\"blur\", \"input\"],\n validators: {\n checkbox: false\n }\n}\n\nexport default class ConstraintValidations {\n static connect(element = document, options = {}) {\n new this(element, options).connect()\n }\n\n constructor(element = document, options = {}) {\n this.element = element\n this.options = { ...defaultOptions, ...options }\n this.validators = [\n new CheckboxValidator(this, this.options.validators.checkbox)\n ]\n }\n\n connect() {\n this.validators.forEach(validator => validator.connect())\n this.element.addEventListener(\"invalid\", this.reportFieldValidity, { capture: true, passive: false })\n\n for (const eventName of this.options.validateOn) {\n this.element.addEventListener(eventName, this.clearAndReportFieldValidity, { capture: true, passive: true })\n }\n\n this.element.addEventListener(\"input\", this.toggleSubmitsDisabled)\n\n this.reportValidationMessages(\n this.element instanceof HTMLFormElement ?\n [this.element] :\n Array.from(this.element.querySelectorAll(\"form\"))\n )\n }\n\n disconnect() {\n this.element.removeEventListener(\"invalid\", this.reportFieldValidity, { capture: true, passive: false })\n\n for (const eventName of this.options.validateOn) {\n this.element.removeEventListener(eventName, this.clearAndReportFieldValidity, { capture: true, passive: true })\n }\n\n this.element.removeEventListener(\"input\", this.toggleSubmitsDisabled)\n this.validators.forEach(validator => validator.disconnect())\n }\n\n reportFieldValidity = (event) => {\n if (isFieldElement(event.target) && this.reportValidity(event.target)) {\n event.preventDefault()\n\n focusFirstInvalidField(event.target.form || event.target)\n }\n }\n\n clearAndReportFieldValidity = ({ target }) => {\n const validator = this.validators.find(validator => validator.willValidate(target))\n\n if (validator) {\n validator.validate(target)\n } else if (isFieldElement(target)) {\n this.clearValidity(target)\n this.reportValidity(target)\n }\n }\n\n toggleSubmitsDisabled = ({ target }) => {\n if (isFieldElement(target) && this.willDisableSubmitWhenInvalid(target)) {\n disableSubmitWhenInvalid(target.form)\n }\n }\n\n reportValidationMessages(forms) {\n const invalidFields = []\n\n for (const form of forms) {\n for (const element of Array.from(form.elements).filter(isFieldElement)) {\n const serverRenderedInvalid = /true/i.test(element.getAttribute(\"aria-invalid\"))\n const id = element.getAttribute(\"aria-errormessage\")\n const errorMessageElement = document.getElementById(id)\n const validationMessage = errorMessageElement?.textContent\n\n if (validationMessage) {\n element.setCustomValidity(validationMessage)\n }\n\n if (validationMessage || serverRenderedInvalid) {\n this.reportValidity(element)\n invalidFields.push(element)\n }\n\n if (this.willDisableSubmitWhenInvalid(element)) {\n disableSubmitWhenInvalid(form)\n }\n }\n }\n\n const [firstInvalidField] = invalidFields\n firstInvalidField?.focus()\n }\n\n willDisableSubmitWhenInvalid(target) {\n return typeof this.options.disableSubmitWhenInvalid === \"function\" ?\n this.options.disableSubmitWhenInvalid(target) :\n !!this.options.disableSubmitWhenInvalid\n }\n\n clearValidity(input) {\n input.setCustomValidity(\"\")\n\n this.reportValidity(input)\n }\n\n reportValidity(input) {\n const id = input.getAttribute(\"aria-errormessage\")\n const validationMessage = getValidationMessage(input)\n const element = document.getElementById(id) || createValidationMessageFragment(input.form)\n\n if (input.form?.noValidate) {\n return false\n } else if (id && element) {\n element.id = id\n element.innerHTML = validationMessage\n\n if (validationMessage) {\n input.setCustomValidity(validationMessage)\n input.setAttribute(\"aria-describedby\", id)\n input.setAttribute(\"aria-invalid\", \"true\")\n } else {\n input.removeAttribute(\"aria-describedby\")\n input.removeAttribute(\"aria-invalid\")\n }\n\n if (!element.parentElement) {\n input.insertAdjacentElement(\"afterend\", element)\n }\n\n if (input.form && this.willDisableSubmitWhenInvalid(input)) disableSubmitWhenInvalid(input.form)\n\n return true\n } else {\n return false\n }\n }\n}\n\nfunction focusFirstInvalidField(element) {\n if (element instanceof HTMLFormElement) {\n return Array.from(element.elements).some(field => focusFirstInvalidField(field))\n } else if (isFieldElement(element) && !element.validity.valid) {\n element.focus()\n element.scrollIntoView()\n return true\n } else {\n return false\n }\n}\n\nfunction disableSubmitWhenInvalid(form) {\n if (!form || form.noValidate) return\n\n const isValid = Array.from(form.elements).filter(isFieldElement).every(input => input.validity.valid)\n\n for (const element of form.elements) {\n if (element.type == \"submit\" && !element.formNoValidate) {\n element.disabled = !isValid\n }\n }\n}\n\nfunction createValidationMessageFragment(form) {\n if (form) {\n const template = form.querySelector(\"[data-validation-message-template]\")\n\n return template?.content.children[0].cloneNode()\n }\n}\n\nfunction getValidationMessage(input) {\n const validationMessages = Object.entries(readValidationMessages(input))\n\n const [ _, validationMessage ] = validationMessages.find(([ key ]) => input.validity[key]) || [ null, null ]\n\n return validationMessage || input.validationMessage\n}\n"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/app/assets/javascripts/constraint_validations.js b/app/assets/javascripts/constraint_validations.js index 01a9fca..2e8b0e9 100644 --- a/app/assets/javascripts/constraint_validations.js +++ b/app/assets/javascripts/constraint_validations.js @@ -1,5 +1,8 @@ var ConstraintValidations = function() { "use strict"; + function isFieldElement(element) { + return !element.disabled && "validity" in element && element.willValidate; + } function readValidationMessages(input) { try { return JSON.parse(input.getAttribute("data-validation-messages")) || {}; @@ -32,7 +35,7 @@ var ConstraintValidations = function() { return group.length > 0 && this.enabled(group); } validate(target) { - const checkboxesInGroup = checkboxGroup(target); + const checkboxesInGroup = checkboxGroup(target).filter(isFieldElement); const allRequired = checkboxesInGroup.every((checkbox => checkbox.getAttribute("aria-required") === "true")); const someChecked = checkboxesInGroup.some((checkbox => checkbox.checked)); if (allRequired && someChecked) { @@ -269,9 +272,6 @@ var ConstraintValidations = function() { const [_, validationMessage] = validationMessages.find((([key]) => input.validity[key])) || [ null, null ]; return validationMessage || input.validationMessage; } - function isFieldElement(element) { - return !element.disabled && "validity" in element && element.willValidate; - } return ConstraintValidations; }(); //# sourceMappingURL=constraint_validations.js.map diff --git a/app/assets/javascripts/constraint_validations.js.map b/app/assets/javascripts/constraint_validations.js.map index 63bad35..c6519d3 100644 --- a/app/assets/javascripts/constraint_validations.js.map +++ b/app/assets/javascripts/constraint_validations.js.map @@ -1 +1 @@ -{"version":3,"file":"constraint_validations.js","sources":["../../javascript/constraint_validations/util.js","../../javascript/constraint_validations/validators/checkbox_validator.js","../../javascript/constraint_validations/index.js"],"sourcesContent":["export function readValidationMessages(input) {\n try {\n return JSON.parse(input.getAttribute(\"data-validation-messages\")) || {}\n } catch(_) {\n return {}\n }\n}\n","import { readValidationMessages } from \"../util\"\n\nexport default class {\n ignoringMutations = false\n\n constructor(constraintValidations, predicate) {\n this.constraintValidations = constraintValidations\n this.mutationObserver = new MutationObserver(this.handleMutation)\n this.enabled = typeof predicate === \"function\" ?\n predicate :\n (group) => !!predicate\n }\n\n connect() {\n this.mutationObserver.observe(this.element, {\n attributeFilter: [\"required\"],\n childList: true,\n subtree: true\n })\n this.overrideNodes(this.element.querySelectorAll(\"input[type=checkbox][required]\"))\n }\n\n disconnect() {\n this.mutationObserver.disconnect()\n }\n\n willValidate(target) {\n return this.willValidateGroup(checkboxGroup(target))\n }\n\n willValidateGroup(group) {\n return group.length > 0 && this.enabled(group)\n }\n\n validate(target) {\n const checkboxesInGroup = checkboxGroup(target)\n const allRequired = checkboxesInGroup.every((checkbox) => checkbox.getAttribute(\"aria-required\") === \"true\")\n const someChecked = checkboxesInGroup.some((checkbox) => checkbox.checked)\n\n if (allRequired && someChecked) {\n for (const checkbox of checkboxesInGroup) {\n this.constraintValidations.clearValidity(checkbox)\n }\n } else if (allRequired) {\n for (const checkbox of checkboxesInGroup) {\n const validationMessages = readValidationMessages(checkbox)\n\n checkbox.setCustomValidity(validationMessages.valueMissing)\n this.constraintValidations.reportValidity(checkbox)\n }\n }\n }\n\n handleMutation = (mutationRecords) => {\n if (this.ignoringMutations) return\n\n for (const { addedNodes, target, type } of mutationRecords) {\n if (type === \"attributes\") {\n if (target.required) {\n this.swapRequiredWithAriaRequired(target)\n } else {\n target.removeAttribute(\"aria-required\")\n }\n } else if (addedNodes.length) {\n this.overrideNodes(addedNodes)\n }\n }\n }\n\n overrideNodes(nodes) {\n const requiredCheckboxes = querySelectorAllNodes(\"input[type=checkbox][required]\", nodes)\n\n for (const checkbox of requiredCheckboxes) {\n if (checkbox.required) {\n const group = checkboxGroup(checkbox)\n\n if (this.willValidateGroup(group)) {\n for (const checkboxInGroup of group) {\n this.swapRequiredWithAriaRequired(checkboxInGroup)\n this.validate(checkboxInGroup)\n }\n }\n }\n }\n }\n\n swapRequiredWithAriaRequired(element) {\n this.ignoringMutations = true\n element.required = false\n element.setAttribute(\"aria-required\", \"true\")\n setTimeout(() => this.ignoringMutations = false, 0)\n }\n\n get element() {\n return this.constraintValidations.element\n }\n}\n\nfunction checkboxGroup(formControl) {\n const results = new Set\n const { name, form } = formControl\n\n if (name && form instanceof HTMLFormElement) {\n const group = form.elements.namedItem(name)\n const elements = Symbol.iterator in group ?\n group :\n [group]\n\n for (const element of elements) {\n if (element.type === \"checkbox\") {\n results.add(element)\n }\n }\n\n if (results.size === 1 && results.has(formControl)) {\n results.clear()\n }\n }\n\n return Array.from(results)\n}\n\nfunction querySelectorAllNodes(selector, nodes, elements = new Set) {\n for (const node of nodes) {\n if (node instanceof Element) {\n if (node.matches(selector)) {\n elements.add(node)\n }\n\n elements.add(...querySelectorAllNodes(selector, node.children, elements))\n }\n }\n\n return Array.from(elements)\n}\n","import { readValidationMessages } from \"./util\"\nimport CheckboxValidator from \"./validators/checkbox_validator\"\n\nconst defaultOptions = {\n disableSubmitWhenInvalid: false,\n validateOn: [\"blur\", \"input\"],\n validators: {\n checkbox: false\n }\n}\n\nexport default class ConstraintValidations {\n static connect(element = document, options = {}) {\n new this(element, options).connect()\n }\n\n constructor(element = document, options = {}) {\n this.element = element\n this.options = { ...defaultOptions, ...options }\n this.validators = [\n new CheckboxValidator(this, this.options.validators.checkbox)\n ]\n }\n\n connect() {\n this.validators.forEach(validator => validator.connect())\n this.element.addEventListener(\"invalid\", this.reportFieldValidity, { capture: true, passive: false })\n\n for (const eventName of this.options.validateOn) {\n this.element.addEventListener(eventName, this.clearAndReportFieldValidity, { capture: true, passive: true })\n }\n\n this.element.addEventListener(\"input\", this.toggleSubmitsDisabled)\n\n this.reportValidationMessages(\n this.element instanceof HTMLFormElement ?\n [this.element] :\n Array.from(this.element.querySelectorAll(\"form\"))\n )\n }\n\n disconnect() {\n this.element.removeEventListener(\"invalid\", this.reportFieldValidity, { capture: true, passive: false })\n\n for (const eventName of this.options.validateOn) {\n this.element.removeEventListener(eventName, this.clearAndReportFieldValidity, { capture: true, passive: true })\n }\n\n this.element.removeEventListener(\"input\", this.toggleSubmitsDisabled)\n this.validators.forEach(validator => validator.disconnect())\n }\n\n reportFieldValidity = (event) => {\n if (isFieldElement(event.target) && this.reportValidity(event.target)) {\n event.preventDefault()\n\n focusFirstInvalidField(event.target.form || event.target)\n }\n }\n\n clearAndReportFieldValidity = ({ target }) => {\n const validator = this.validators.find(validator => validator.willValidate(target))\n\n if (validator) {\n validator.validate(target)\n } else if (isFieldElement(target)) {\n this.clearValidity(target)\n this.reportValidity(target)\n }\n }\n\n toggleSubmitsDisabled = ({ target }) => {\n if (isFieldElement(target) && this.willDisableSubmitWhenInvalid(target)) {\n disableSubmitWhenInvalid(target.form)\n }\n }\n\n reportValidationMessages(forms) {\n const invalidFields = []\n\n for (const form of forms) {\n for (const element of Array.from(form.elements).filter(isFieldElement)) {\n const serverRenderedInvalid = /true/i.test(element.getAttribute(\"aria-invalid\"))\n const id = element.getAttribute(\"aria-errormessage\")\n const errorMessageElement = document.getElementById(id)\n const validationMessage = errorMessageElement?.textContent\n\n if (validationMessage) {\n element.setCustomValidity(validationMessage)\n }\n\n if (validationMessage || serverRenderedInvalid) {\n this.reportValidity(element)\n invalidFields.push(element)\n }\n\n if (this.willDisableSubmitWhenInvalid(element)) {\n disableSubmitWhenInvalid(form)\n }\n }\n }\n\n const [firstInvalidField] = invalidFields\n firstInvalidField?.focus()\n }\n\n willDisableSubmitWhenInvalid(target) {\n return typeof this.options.disableSubmitWhenInvalid === \"function\" ?\n this.options.disableSubmitWhenInvalid(target) :\n !!this.options.disableSubmitWhenInvalid\n }\n\n clearValidity(input) {\n input.setCustomValidity(\"\")\n\n this.reportValidity(input)\n }\n\n reportValidity(input) {\n const id = input.getAttribute(\"aria-errormessage\")\n const validationMessage = getValidationMessage(input)\n const element = document.getElementById(id) || createValidationMessageFragment(input.form)\n\n if (input.form?.noValidate) {\n return false\n } else if (id && element) {\n element.id = id\n element.innerHTML = validationMessage\n\n if (validationMessage) {\n input.setCustomValidity(validationMessage)\n input.setAttribute(\"aria-describedby\", id)\n input.setAttribute(\"aria-invalid\", \"true\")\n } else {\n input.removeAttribute(\"aria-describedby\")\n input.removeAttribute(\"aria-invalid\")\n }\n\n if (!element.parentElement) {\n input.insertAdjacentElement(\"afterend\", element)\n }\n\n if (input.form && this.willDisableSubmitWhenInvalid(input)) disableSubmitWhenInvalid(input.form)\n\n return true\n } else {\n return false\n }\n }\n}\n\nfunction focusFirstInvalidField(element) {\n if (element instanceof HTMLFormElement) {\n return Array.from(element.elements).some(field => focusFirstInvalidField(field))\n } else if (isFieldElement(element) && !element.validity.valid) {\n element.focus()\n element.scrollIntoView()\n return true\n } else {\n return false\n }\n}\n\nfunction disableSubmitWhenInvalid(form) {\n if (!form || form.noValidate) return\n\n const isValid = Array.from(form.elements).filter(isFieldElement).every(input => input.validity.valid)\n\n for (const element of form.elements) {\n if (element.type == \"submit\" && !element.formNoValidate) {\n element.disabled = !isValid\n }\n }\n}\n\nfunction createValidationMessageFragment(form) {\n if (form) {\n const template = form.querySelector(\"[data-validation-message-template]\")\n\n return template?.content.children[0].cloneNode()\n }\n}\n\nfunction getValidationMessage(input) {\n const validationMessages = Object.entries(readValidationMessages(input))\n\n const [ _, validationMessage ] = validationMessages.find(([ key ]) => input.validity[key]) || [ null, null ]\n\n return validationMessage || input.validationMessage\n}\n\nfunction isFieldElement(element) {\n return !element.disabled && \"validity\" in element && element.willValidate\n}\n"],"names":["readValidationMessages","input","JSON","parse","getAttribute","_","[object Object]","constraintValidations","predicate","this","mutationObserver","MutationObserver","handleMutation","enabled","group","observe","element","attributeFilter","childList","subtree","overrideNodes","querySelectorAll","disconnect","target","willValidateGroup","checkboxGroup","length","checkboxesInGroup","allRequired","every","checkbox","someChecked","some","checked","clearValidity","validationMessages","setCustomValidity","valueMissing","reportValidity","mutationRecords","ignoringMutations","addedNodes","type","required","swapRequiredWithAriaRequired","removeAttribute","nodes","requiredCheckboxes","querySelectorAllNodes","checkboxInGroup","validate","setAttribute","setTimeout","formControl","results","Set","name","form","HTMLFormElement","elements","namedItem","Symbol","iterator","add","size","has","clear","Array","from","selector","node","Element","matches","children","defaultOptions","disableSubmitWhenInvalid","validateOn","validators","ConstraintValidations","document","options","connect","CheckboxValidator","forEach","validator","addEventListener","reportFieldValidity","capture","passive","eventName","clearAndReportFieldValidity","toggleSubmitsDisabled","reportValidationMessages","removeEventListener","event","isFieldElement","preventDefault","focusFirstInvalidField","find","willValidate","willDisableSubmitWhenInvalid","forms","invalidFields","filter","serverRenderedInvalid","test","id","errorMessageElement","getElementById","validationMessage","textContent","push","firstInvalidField","focus","getValidationMessage","createValidationMessageFragment","noValidate","innerHTML","parentElement","insertAdjacentElement","field","validity","valid","scrollIntoView","isValid","formNoValidate","disabled","template","querySelector","content","cloneNode","Object","entries","key"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"constraint_validations.js","sources":["../../javascript/constraint_validations/util.js","../../javascript/constraint_validations/validators/checkbox_validator.js","../../javascript/constraint_validations/index.js"],"sourcesContent":["export function isFieldElement(element) {\n return !element.disabled && \"validity\" in element && element.willValidate\n}\n\nexport function readValidationMessages(input) {\n try {\n return JSON.parse(input.getAttribute(\"data-validation-messages\")) || {}\n } catch(_) {\n return {}\n }\n}\n","import { isFieldElement, readValidationMessages } from \"../util\"\n\nexport default class {\n ignoringMutations = false\n\n constructor(constraintValidations, predicate) {\n this.constraintValidations = constraintValidations\n this.mutationObserver = new MutationObserver(this.handleMutation)\n this.enabled = typeof predicate === \"function\" ?\n predicate :\n (group) => !!predicate\n }\n\n connect() {\n this.mutationObserver.observe(this.element, {\n attributeFilter: [\"required\"],\n childList: true,\n subtree: true\n })\n this.overrideNodes(this.element.querySelectorAll(\"input[type=checkbox][required]\"))\n }\n\n disconnect() {\n this.mutationObserver.disconnect()\n }\n\n willValidate(target) {\n return this.willValidateGroup(checkboxGroup(target))\n }\n\n willValidateGroup(group) {\n return group.length > 0 && this.enabled(group)\n }\n\n validate(target) {\n const checkboxesInGroup = checkboxGroup(target).filter(isFieldElement)\n const allRequired = checkboxesInGroup.every((checkbox) => checkbox.getAttribute(\"aria-required\") === \"true\")\n const someChecked = checkboxesInGroup.some((checkbox) => checkbox.checked)\n\n if (allRequired && someChecked) {\n for (const checkbox of checkboxesInGroup) {\n this.constraintValidations.clearValidity(checkbox)\n }\n } else if (allRequired) {\n for (const checkbox of checkboxesInGroup) {\n const validationMessages = readValidationMessages(checkbox)\n\n checkbox.setCustomValidity(validationMessages.valueMissing)\n this.constraintValidations.reportValidity(checkbox)\n }\n }\n }\n\n handleMutation = (mutationRecords) => {\n if (this.ignoringMutations) return\n\n for (const { addedNodes, target, type } of mutationRecords) {\n if (type === \"attributes\") {\n if (target.required) {\n this.swapRequiredWithAriaRequired(target)\n } else {\n target.removeAttribute(\"aria-required\")\n }\n } else if (addedNodes.length) {\n this.overrideNodes(addedNodes)\n }\n }\n }\n\n overrideNodes(nodes) {\n const requiredCheckboxes = querySelectorAllNodes(\"input[type=checkbox][required]\", nodes)\n\n for (const checkbox of requiredCheckboxes) {\n if (checkbox.required) {\n const group = checkboxGroup(checkbox)\n\n if (this.willValidateGroup(group)) {\n for (const checkboxInGroup of group) {\n this.swapRequiredWithAriaRequired(checkboxInGroup)\n this.validate(checkboxInGroup)\n }\n }\n }\n }\n }\n\n swapRequiredWithAriaRequired(element) {\n this.ignoringMutations = true\n element.required = false\n element.setAttribute(\"aria-required\", \"true\")\n setTimeout(() => this.ignoringMutations = false, 0)\n }\n\n get element() {\n return this.constraintValidations.element\n }\n}\n\nfunction checkboxGroup(formControl) {\n const results = new Set\n const { name, form } = formControl\n\n if (name && form instanceof HTMLFormElement) {\n const group = form.elements.namedItem(name)\n const elements = Symbol.iterator in group ?\n group :\n [group]\n\n for (const element of elements) {\n if (element.type === \"checkbox\") {\n results.add(element)\n }\n }\n\n if (results.size === 1 && results.has(formControl)) {\n results.clear()\n }\n }\n\n return Array.from(results)\n}\n\nfunction querySelectorAllNodes(selector, nodes, elements = new Set) {\n for (const node of nodes) {\n if (node instanceof Element) {\n if (node.matches(selector)) {\n elements.add(node)\n }\n\n elements.add(...querySelectorAllNodes(selector, node.children, elements))\n }\n }\n\n return Array.from(elements)\n}\n","import { isFieldElement, readValidationMessages } from \"./util\"\nimport CheckboxValidator from \"./validators/checkbox_validator\"\n\nconst defaultOptions = {\n disableSubmitWhenInvalid: false,\n validateOn: [\"blur\", \"input\"],\n validators: {\n checkbox: false\n }\n}\n\nexport default class ConstraintValidations {\n static connect(element = document, options = {}) {\n new this(element, options).connect()\n }\n\n constructor(element = document, options = {}) {\n this.element = element\n this.options = { ...defaultOptions, ...options }\n this.validators = [\n new CheckboxValidator(this, this.options.validators.checkbox)\n ]\n }\n\n connect() {\n this.validators.forEach(validator => validator.connect())\n this.element.addEventListener(\"invalid\", this.reportFieldValidity, { capture: true, passive: false })\n\n for (const eventName of this.options.validateOn) {\n this.element.addEventListener(eventName, this.clearAndReportFieldValidity, { capture: true, passive: true })\n }\n\n this.element.addEventListener(\"input\", this.toggleSubmitsDisabled)\n\n this.reportValidationMessages(\n this.element instanceof HTMLFormElement ?\n [this.element] :\n Array.from(this.element.querySelectorAll(\"form\"))\n )\n }\n\n disconnect() {\n this.element.removeEventListener(\"invalid\", this.reportFieldValidity, { capture: true, passive: false })\n\n for (const eventName of this.options.validateOn) {\n this.element.removeEventListener(eventName, this.clearAndReportFieldValidity, { capture: true, passive: true })\n }\n\n this.element.removeEventListener(\"input\", this.toggleSubmitsDisabled)\n this.validators.forEach(validator => validator.disconnect())\n }\n\n reportFieldValidity = (event) => {\n if (isFieldElement(event.target) && this.reportValidity(event.target)) {\n event.preventDefault()\n\n focusFirstInvalidField(event.target.form || event.target)\n }\n }\n\n clearAndReportFieldValidity = ({ target }) => {\n const validator = this.validators.find(validator => validator.willValidate(target))\n\n if (validator) {\n validator.validate(target)\n } else if (isFieldElement(target)) {\n this.clearValidity(target)\n this.reportValidity(target)\n }\n }\n\n toggleSubmitsDisabled = ({ target }) => {\n if (isFieldElement(target) && this.willDisableSubmitWhenInvalid(target)) {\n disableSubmitWhenInvalid(target.form)\n }\n }\n\n reportValidationMessages(forms) {\n const invalidFields = []\n\n for (const form of forms) {\n for (const element of Array.from(form.elements).filter(isFieldElement)) {\n const serverRenderedInvalid = /true/i.test(element.getAttribute(\"aria-invalid\"))\n const id = element.getAttribute(\"aria-errormessage\")\n const errorMessageElement = document.getElementById(id)\n const validationMessage = errorMessageElement?.textContent\n\n if (validationMessage) {\n element.setCustomValidity(validationMessage)\n }\n\n if (validationMessage || serverRenderedInvalid) {\n this.reportValidity(element)\n invalidFields.push(element)\n }\n\n if (this.willDisableSubmitWhenInvalid(element)) {\n disableSubmitWhenInvalid(form)\n }\n }\n }\n\n const [firstInvalidField] = invalidFields\n firstInvalidField?.focus()\n }\n\n willDisableSubmitWhenInvalid(target) {\n return typeof this.options.disableSubmitWhenInvalid === \"function\" ?\n this.options.disableSubmitWhenInvalid(target) :\n !!this.options.disableSubmitWhenInvalid\n }\n\n clearValidity(input) {\n input.setCustomValidity(\"\")\n\n this.reportValidity(input)\n }\n\n reportValidity(input) {\n const id = input.getAttribute(\"aria-errormessage\")\n const validationMessage = getValidationMessage(input)\n const element = document.getElementById(id) || createValidationMessageFragment(input.form)\n\n if (input.form?.noValidate) {\n return false\n } else if (id && element) {\n element.id = id\n element.innerHTML = validationMessage\n\n if (validationMessage) {\n input.setCustomValidity(validationMessage)\n input.setAttribute(\"aria-describedby\", id)\n input.setAttribute(\"aria-invalid\", \"true\")\n } else {\n input.removeAttribute(\"aria-describedby\")\n input.removeAttribute(\"aria-invalid\")\n }\n\n if (!element.parentElement) {\n input.insertAdjacentElement(\"afterend\", element)\n }\n\n if (input.form && this.willDisableSubmitWhenInvalid(input)) disableSubmitWhenInvalid(input.form)\n\n return true\n } else {\n return false\n }\n }\n}\n\nfunction focusFirstInvalidField(element) {\n if (element instanceof HTMLFormElement) {\n return Array.from(element.elements).some(field => focusFirstInvalidField(field))\n } else if (isFieldElement(element) && !element.validity.valid) {\n element.focus()\n element.scrollIntoView()\n return true\n } else {\n return false\n }\n}\n\nfunction disableSubmitWhenInvalid(form) {\n if (!form || form.noValidate) return\n\n const isValid = Array.from(form.elements).filter(isFieldElement).every(input => input.validity.valid)\n\n for (const element of form.elements) {\n if (element.type == \"submit\" && !element.formNoValidate) {\n element.disabled = !isValid\n }\n }\n}\n\nfunction createValidationMessageFragment(form) {\n if (form) {\n const template = form.querySelector(\"[data-validation-message-template]\")\n\n return template?.content.children[0].cloneNode()\n }\n}\n\nfunction getValidationMessage(input) {\n const validationMessages = Object.entries(readValidationMessages(input))\n\n const [ _, validationMessage ] = validationMessages.find(([ key ]) => input.validity[key]) || [ null, null ]\n\n return validationMessage || input.validationMessage\n}\n"],"names":["isFieldElement","element","disabled","willValidate","readValidationMessages","input","JSON","parse","getAttribute","_","[object Object]","constraintValidations","predicate","this","mutationObserver","MutationObserver","handleMutation","enabled","group","observe","attributeFilter","childList","subtree","overrideNodes","querySelectorAll","disconnect","target","willValidateGroup","checkboxGroup","length","checkboxesInGroup","filter","allRequired","every","checkbox","someChecked","some","checked","clearValidity","validationMessages","setCustomValidity","valueMissing","reportValidity","mutationRecords","ignoringMutations","addedNodes","type","required","swapRequiredWithAriaRequired","removeAttribute","nodes","requiredCheckboxes","querySelectorAllNodes","checkboxInGroup","validate","setAttribute","setTimeout","formControl","results","Set","name","form","HTMLFormElement","elements","namedItem","Symbol","iterator","add","size","has","clear","Array","from","selector","node","Element","matches","children","defaultOptions","disableSubmitWhenInvalid","validateOn","validators","ConstraintValidations","document","options","connect","CheckboxValidator","forEach","validator","addEventListener","reportFieldValidity","capture","passive","eventName","clearAndReportFieldValidity","toggleSubmitsDisabled","reportValidationMessages","removeEventListener","event","preventDefault","focusFirstInvalidField","find","willDisableSubmitWhenInvalid","forms","invalidFields","serverRenderedInvalid","test","id","errorMessageElement","getElementById","validationMessage","textContent","push","firstInvalidField","focus","getValidationMessage","createValidationMessageFragment","noValidate","innerHTML","parentElement","insertAdjacentElement","field","validity","valid","scrollIntoView","isValid","formNoValidate","template","querySelector","content","cloneNode","Object","entries","key"],"mappings":"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"} \ No newline at end of file diff --git a/app/javascript/constraint_validations/index.js b/app/javascript/constraint_validations/index.js index 88ff1e3..59c4f83 100644 --- a/app/javascript/constraint_validations/index.js +++ b/app/javascript/constraint_validations/index.js @@ -1,4 +1,4 @@ -import { readValidationMessages } from "./util" +import { isFieldElement, readValidationMessages } from "./util" import CheckboxValidator from "./validators/checkbox_validator" const defaultOptions = { @@ -188,7 +188,3 @@ function getValidationMessage(input) { return validationMessage || input.validationMessage } - -function isFieldElement(element) { - return !element.disabled && "validity" in element && element.willValidate -} diff --git a/app/javascript/constraint_validations/util.js b/app/javascript/constraint_validations/util.js index 01268ae..513f835 100644 --- a/app/javascript/constraint_validations/util.js +++ b/app/javascript/constraint_validations/util.js @@ -1,3 +1,7 @@ +export function isFieldElement(element) { + return !element.disabled && "validity" in element && element.willValidate +} + export function readValidationMessages(input) { try { return JSON.parse(input.getAttribute("data-validation-messages")) || {} diff --git a/app/javascript/constraint_validations/validators/checkbox_validator.js b/app/javascript/constraint_validations/validators/checkbox_validator.js index 06ad7d9..43dd23e 100644 --- a/app/javascript/constraint_validations/validators/checkbox_validator.js +++ b/app/javascript/constraint_validations/validators/checkbox_validator.js @@ -1,4 +1,4 @@ -import { readValidationMessages } from "../util" +import { isFieldElement, readValidationMessages } from "../util" export default class { ignoringMutations = false @@ -33,7 +33,7 @@ export default class { } validate(target) { - const checkboxesInGroup = checkboxGroup(target) + const checkboxesInGroup = checkboxGroup(target).filter(isFieldElement) const allRequired = checkboxesInGroup.every((checkbox) => checkbox.getAttribute("aria-required") === "true") const someChecked = checkboxesInGroup.some((checkbox) => checkbox.checked) diff --git a/test/dummy/app/views/forms/new.html.erb b/test/dummy/app/views/forms/new.html.erb index 65f2ec4..a507610 100644 --- a/test/dummy/app/views/forms/new.html.erb +++ b/test/dummy/app/views/forms/new.html.erb @@ -43,9 +43,10 @@ <%= form.collection_check_boxes :multiple_required_checkbox, [ ["1", "Multiple required checkbox #1"], - ["2", "Multiple required checkbox #2"] + ["2", "Multiple required checkbox #2"], + ["3", "Multiple required checkbox #3", disabled: true] ], :first, :second do |builder| %> - <%= builder.check_box %> + <%= builder.check_box builder.object.third.to_h %> <%= builder.label %> <% end %> diff --git a/test/system/validations_test.rb b/test/system/validations_test.rb index bb21ed8..e07fff2 100644 --- a/test/system/validations_test.rb +++ b/test/system/validations_test.rb @@ -289,13 +289,17 @@ class ValidationsTest < ApplicationSystemTestCase end test "observes connection of multiple [required] checkboxes" do + connected = proc do |input| + input.assert_matches_selector :element, required: false, "aria-required": "true" + end + visit new_form_path(hotwire_enabled: true, checkbox: true) click_button "Skip Validations" within_fieldset "Multiple [required] checkboxes" do - assert_unchecked_field "Multiple required checkbox", exact: false, valid: false, count: 2 do |input| - input.assert_matches_selector :element, required: false, "aria-required": "true" - end + assert_unchecked_field "Multiple required checkbox #1", valid: false, &connected + assert_unchecked_field "Multiple required checkbox #2", valid: false, &connected + assert_unchecked_field "Multiple required checkbox #3", disabled: true, valid: true, &connected end end