Skip to content

Commit 91d2e1e

Browse files
edmund-dunntonytaylorndouglas
authored
VACMS-15785: alt text validation (#15787)
* VACMS-15435: hard validation for alt text field * VACMS-15436: clientside validation for alt text field * VACMS-15436: updated composer.lock * VACMS-15436: fix linting errors * VACMS-15436: one more linting error fixed * VACMS-15436: more linting fixes * VACMS-15785: updated composer.lock * VACMS-15962: theming changes for image form * VACMS-15962: fix linting errors * VACMS-15962: final fix * VACMS-15783: Alt-Text Validation Testing (#16159) * VACMS-15783 adds alt-text validation tests * VACMS-15785: update composer.lock, fix merge error * VACMS-15785: fix for spacing around error * VACMS-15785: updated composer.lock * Updates content * smdh --------- Co-authored-by: Tony Taylor <[email protected]> Co-authored-by: Nathan Douglas <[email protected]>
1 parent 8a12098 commit 91d2e1e

26 files changed

+987
-57
lines changed

composer.json

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"drupal/block_content_permissions": "^1.6",
3535
"drupal/cer": "^5.0@beta",
3636
"drupal/change_labels": "dev-3326097-remove-dependency-on-drupal-autoservices#7f92f90b456ac2f394dd434257e39e1d9b3086eb",
37+
"drupal/clientside_validation": "^4.0",
3738
"drupal/ckeditor_abbreviation": "^4.0@alpha",
3839
"drupal/coder": "^8.3",
3940
"drupal/codit_menu_tools": "^1.0@alpha",
@@ -204,6 +205,7 @@
204205
"mikey179/vfsstream": "^1.6",
205206
"mnsami/composer-custom-directory-installer": "^2.0",
206207
"npm-asset/dropzone": "^5.5",
208+
"npm-asset/jquery-validation": "^1.17",
207209
"npm-asset/yarn": "1.19.1",
208210
"oomphinc/composer-installers-extender": "^2.0",
209211
"orakili/composer-drupal-info-file-patch-helper": "*",
@@ -366,6 +368,9 @@
366368
"3200122 - Remove delete hook": "https://www.drupal.org/files/issues/2021-02-24/delete-hook-added-in-dev-causes-test-failures.patch",
367369
"3254663 - Notice: Undefined index: target_bundles on Drupal\\cer\\Entity\\CorrespondingReference->synchronizeCorrespondingField()": "https://www.drupal.org/files/issues/2022-02-14/prevent-undefined-index-3254663-6.patch"
368370
},
371+
"drupal/clientside_validation": {
372+
"2949540 - Allow specific form ids for clientside validation": "https://www.drupal.org/files/issues/2023-10-27/2949540-31.patch"
373+
},
369374
"drupal/consumer_image_styles": {
370375
"3301224 - Follow-up: Very slow JSON:API responses when images are stored on AWS bucket": "https://www.drupal.org/files/issues/2023-02-07/3301224-9.patch"
371376
},

composer.lock

+76-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
55
"This file is @generated automatically"
66
],
7-
"content-hash": "dd7a8b38039836aeebdc472d433eaf95",
7+
"content-hash": "519122c85d79517c409d1c39cf3c0b00",
88
"packages": [
99
{
1010
"name": "asm89/stack-cors",
@@ -2990,6 +2990,68 @@
29902990
"issues": "http://drupal.org/project/issues/ckeditor_abbreviation"
29912991
}
29922992
},
2993+
{
2994+
"name": "drupal/clientside_validation",
2995+
"version": "4.0.2",
2996+
"source": {
2997+
"type": "git",
2998+
"url": "https://git.drupalcode.org/project/clientside_validation.git",
2999+
"reference": "4.0.2"
3000+
},
3001+
"dist": {
3002+
"type": "zip",
3003+
"url": "https://ftp.drupal.org/files/projects/clientside_validation-4.0.2.zip",
3004+
"reference": "4.0.2",
3005+
"shasum": "bfaf0fa81d645427c1b3ccfd2d5e493a10b7f483"
3006+
},
3007+
"require": {
3008+
"drupal/core": "^9.4 || ^10.0",
3009+
"php": ">=7.4.0"
3010+
},
3011+
"require-dev": {
3012+
"drupal/clientside_validation_demo": "*",
3013+
"drupal/clientside_validation_jquery": "*"
3014+
},
3015+
"type": "drupal-module",
3016+
"extra": {
3017+
"drupal": {
3018+
"version": "4.0.2",
3019+
"datestamp": "1676011269",
3020+
"security-coverage": {
3021+
"status": "covered",
3022+
"message": "Covered by Drupal's security advisory policy"
3023+
}
3024+
}
3025+
},
3026+
"notification-url": "https://packages.drupal.org/8/downloads",
3027+
"license": [
3028+
"GPL-2.0+"
3029+
],
3030+
"authors": [
3031+
{
3032+
"name": "attiks",
3033+
"homepage": "https://www.drupal.org/user/105002"
3034+
},
3035+
{
3036+
"name": "Jelle_S",
3037+
"homepage": "https://www.drupal.org/user/829198"
3038+
},
3039+
{
3040+
"name": "joseph.olstad",
3041+
"homepage": "https://www.drupal.org/user/1321830"
3042+
},
3043+
{
3044+
"name": "nikunjkotecha",
3045+
"homepage": "https://www.drupal.org/user/694082"
3046+
}
3047+
],
3048+
"description": "This module adds clientside validation",
3049+
"homepage": "https://www.drupal.org/project/clientside_validation",
3050+
"support": {
3051+
"source": "https://git.drupalcode.org/project/clientside_validation",
3052+
"issues": "https://drupal.org/project/issues/clientside_validation"
3053+
}
3054+
},
29933055
{
29943056
"name": "drupal/coder",
29953057
"version": "8.3.22",
@@ -17070,6 +17132,18 @@
1707017132
"MIT"
1707117133
]
1707217134
},
17135+
{
17136+
"name": "npm-asset/jquery-validation",
17137+
"version": "1.20.0",
17138+
"dist": {
17139+
"type": "tar",
17140+
"url": "https://registry.npmjs.org/jquery-validation/-/jquery-validation-1.20.0.tgz"
17141+
},
17142+
"type": "npm-asset",
17143+
"license": [
17144+
"MIT"
17145+
]
17146+
},
1707317147
{
1707417148
"name": "npm-asset/yarn",
1707517149
"version": "1.19.1",
@@ -26771,5 +26845,5 @@
2677126845
"platform-overrides": {
2677226846
"php": "8.1"
2677326847
},
26774-
"plugin-api-version": "2.6.0"
26848+
"plugin-api-version": "2.3.0"
2677526849
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
_core:
2+
default_config_hash: GfA9lmRURupNRAARLoOTo1Ihq1-M3ktT0sKSjUcL2sw
3+
enable_all_forms: true
4+
enabled_forms: { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
_core:
2+
default_config_hash: 3YUV4RQQ4k8drO7uzYJ7lNc5Az0iDAH5YW8KbZVxjeY
3+
use_cdn: false
4+
cdn_base_url: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/'
5+
validate_all_ajax_forms: 2
6+
force_validate_on_blur: 0

config/sync/core.entity_form_display.media.image.default.yml

+20-4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ dependencies:
88
- field.field.media.image.field_media_submission_guideline
99
- field.field.media.image.field_owner
1010
- field.field.media.image.image
11-
- image.style.3_2_medium_thumbnail
11+
- image.style.full_content_width
1212
- media.type.image
1313
module:
14+
- change_labels
1415
- field_group
1516
- image_widget_crop
1617
- markup
@@ -47,6 +48,7 @@ content:
4748
maxlength: 300
4849
counter_position: after
4950
js_prevent_submit: true
51+
count_only_mode: false
5052
count_html_characters: true
5153
textcount_status_message: 'Characters Remaining: <span class="remaining_count">@remaining_count</span>'
5254
third_party_settings: { }
@@ -68,14 +70,23 @@ content:
6870
region: content
6971
settings:
7072
progress_indicator: throbber
71-
preview_image_style: 3_2_medium_thumbnail
73+
preview_image_style: full_content_width
7274
crop_preview_image_style: crop_thumbnail
73-
crop_list: { }
75+
crop_list:
76+
- '2_1'
77+
- '2_3'
78+
- '3_2'
79+
- '7_2'
80+
- freeform
81+
- original
82+
- square
7483
crop_types_required: { }
7584
warn_multiple_usages: false
7685
show_crop_area: true
7786
show_default_crop: true
78-
third_party_settings: { }
87+
third_party_settings:
88+
change_labels:
89+
remove_label: ''
7990
name:
8091
type: string_textfield
8192
weight: 1
@@ -84,6 +95,11 @@ content:
8495
size: 60
8596
placeholder: ''
8697
third_party_settings: { }
98+
translation:
99+
weight: 10
100+
region: content
101+
settings: { }
102+
third_party_settings: { }
87103
hidden:
88104
created: true
89105
field_media_in_library: true

config/sync/core.extension.yml

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ module:
2424
change_labels: 0
2525
ckeditor5: 0
2626
ckeditor_abbreviation: 0
27+
clientside_validation: 0
28+
clientside_validation_jquery: 0
2729
codit_menu_tools: 0
2830
components: 0
2931
computed_breadcrumbs: 0

docroot/design-system/components/input/input.scss

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@
2323
}
2424

2525
.form-item--error-message {
26-
color: var(--va-red-bright);
26+
color: var(--va-red-dark);
27+
margin: 5px 0;
2728
}

docroot/design-system/components/tokens/_variables.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
--color-absolutezero-hover: var(--va-blue-dark);
9696
--color-absolutezero-active: var(--va-blue-darker);
9797
--color-sunglow: var(--va-gold-med);
98-
--color-maximumred: var(--va-red-bright);
98+
--color-maximumred: var(--va-red-dark);
9999
--color-lightninggreen: var(--va-green);
100100
--color-lightgray: var(--va-gray-lighter);
101101
--color-whitesmoke: var(--va-gray-lightest);

docroot/modules/custom/va_gov_backend/src/EventSubscriber/ThemeEventSubscriber.php

-19
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
use Drupal\core_event_dispatcher\Event\Theme\ThemeSuggestionsAlterEvent;
88
use Drupal\core_event_dispatcher\FormHookEvents;
99
use Drupal\core_event_dispatcher\ThemeHookEvents;
10-
use Drupal\field_event_dispatcher\Event\Field\WidgetSingleElementFormAlterEvent;
11-
use Drupal\field_event_dispatcher\FieldHookEvents;
12-
use Drupal\image\Plugin\Field\FieldWidget\ImageWidget;
1310
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1411

1512
/**
@@ -22,27 +19,11 @@ class ThemeEventSubscriber implements EventSubscriberInterface {
2219
*/
2320
public static function getSubscribedEvents(): array {
2421
return [
25-
FieldHookEvents::WIDGET_SINGLE_ELEMENT_FORM_ALTER => 'formWidgetAlter',
2622
FormHookEvents::FORM_ALTER => 'formAlter',
2723
ThemeHookEvents::THEME_SUGGESTIONS_ALTER => 'themeSuggestionsAlter',
2824
];
2925
}
3026

31-
/**
32-
* Widget form alter Event call.
33-
*
34-
* @param \Drupal\field_event_dispatcher\Event\Field\WidgetSingleElementFormAlterEvent $event
35-
* The event.
36-
*/
37-
public function formWidgetAlter(WidgetSingleElementFormAlterEvent $event): void {
38-
$element = &$event->getElement();
39-
$context = $event->getContext();
40-
// If this is an image field type of instance.
41-
if ($context['widget'] instanceof ImageWidget) {
42-
$element['#process'][] = '_va_gov_media_image_field_widget_process';
43-
}
44-
}
45-
4627
/**
4728
* Form alter Event call.
4829
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* @file
3+
* Attaches behaviors VA GOv Media module.
4+
*/
5+
(($, Drupal, once, drupalSettings) => {
6+
if (typeof drupalSettings.cvJqueryValidateOptions === "undefined") {
7+
drupalSettings.cvJqueryValidateOptions = {};
8+
}
9+
10+
if (drupalSettings.clientside_validation_jquery.force_validate_on_blur) {
11+
drupalSettings.cvJqueryValidateOptions.onfocusout = (element) => {
12+
// "eager" validation
13+
this.element(element);
14+
};
15+
}
16+
17+
drupalSettings.cvJqueryValidateOptions.rules = {
18+
"image[0][alt]": {
19+
remote: {
20+
url: `${drupalSettings.path.baseUrl}media/validate`,
21+
type: "post",
22+
data: {
23+
value() {
24+
return $("textarea[data-drupal-selector='edit-image-0-alt']").val();
25+
},
26+
},
27+
dataType: "json",
28+
},
29+
},
30+
"media[0][fields][image][0][alt]": {
31+
remote: {
32+
url: `${drupalSettings.path.baseUrl}media/validate`,
33+
type: "post",
34+
data: {
35+
value() {
36+
return $(
37+
"textarea[data-drupal-selector='edit-media-0-fields-image-0-alt']"
38+
).val();
39+
},
40+
},
41+
dataType: "json",
42+
},
43+
},
44+
};
45+
46+
// Add messages with translations from backend.
47+
$.extend(
48+
$.validator.messages,
49+
drupalSettings.clientside_validation_jquery.messages
50+
);
51+
52+
/**
53+
* Attaches jQuery validate behavior to forms.
54+
*
55+
* @type {Drupal~behavior}
56+
*
57+
* @prop {Drupal~behaviorAttach} attach
58+
* Attaches the outline behavior to the right context.
59+
*/
60+
Drupal.behaviors.altTextValidate = {
61+
// eslint-disable-next-line no-unused-vars
62+
attach(context) {
63+
// Allow all modules to update the validate options.
64+
// Example of how to do this is shown below.
65+
$(document).trigger(
66+
"cv-jquery-validate-options-update",
67+
drupalSettings.cvJqueryValidateOptions
68+
);
69+
70+
// Process for all the forms on the page everytime,
71+
// we already use once so we should be good.
72+
once("altTextValidate", "body form").forEach((element) => {
73+
$(element).validate(drupalSettings.cvJqueryValidateOptions);
74+
});
75+
},
76+
};
77+
// eslint-disable-next-line no-undef
78+
})(jQuery, Drupal, once, drupalSettings);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* DO NOT EDIT THIS FILE.
3+
* See the following change record for more information,
4+
* https://www.drupal.org/node/2815083
5+
* @preserve
6+
**/
7+
var _this = this;
8+
(function ($, Drupal, once, drupalSettings) {
9+
if (typeof drupalSettings.cvJqueryValidateOptions === "undefined") {
10+
drupalSettings.cvJqueryValidateOptions = {};
11+
}
12+
if (drupalSettings.clientside_validation_jquery.force_validate_on_blur) {
13+
drupalSettings.cvJqueryValidateOptions.onfocusout = function (element) {
14+
_this.element(element);
15+
};
16+
}
17+
drupalSettings.cvJqueryValidateOptions.rules = {
18+
"image[0][alt]": {
19+
remote: {
20+
url: drupalSettings.path.baseUrl + "media/validate",
21+
type: "post",
22+
data: {
23+
value: function value() {
24+
return $("textarea[data-drupal-selector='edit-image-0-alt']").val();
25+
}
26+
},
27+
dataType: "json"
28+
}
29+
},
30+
"media[0][fields][image][0][alt]": {
31+
remote: {
32+
url: drupalSettings.path.baseUrl + "media/validate",
33+
type: "post",
34+
data: {
35+
value: function value() {
36+
return $("textarea[data-drupal-selector='edit-media-0-fields-image-0-alt']").val();
37+
}
38+
},
39+
dataType: "json"
40+
}
41+
}
42+
};
43+
$.extend($.validator.messages, drupalSettings.clientside_validation_jquery.messages);
44+
Drupal.behaviors.altTextValidate = {
45+
attach: function attach(context) {
46+
$(document).trigger("cv-jquery-validate-options-update", drupalSettings.cvJqueryValidateOptions);
47+
once("altTextValidate", "body form").forEach(function (element) {
48+
$(element).validate(drupalSettings.cvJqueryValidateOptions);
49+
});
50+
}
51+
};
52+
})(jQuery, Drupal, once, drupalSettings);

0 commit comments

Comments
 (0)