summaryrefslogtreecommitdiffstatshomepage
path: root/src/js/_enqueues/lib/nav-menu.js
diff options
context:
space:
mode:
authorJoe Dolson <joedolson@git.wordpress.org>2025-03-06 23:46:47 +0000
committerJoe Dolson <joedolson@git.wordpress.org>2025-03-06 23:46:47 +0000
commitc44c37d996ae00164c733de98faad1212a57f5c6 (patch)
tree1c4ffef480a6ca9b81826769588573c0fe1c2047 /src/js/_enqueues/lib/nav-menu.js
parent408a01ab8d56136d1e6a4e1f24f429afb2053f8f (diff)
downloadwordpress-c44c37d996ae00164c733de98faad1212a57f5c6.tar.gz
wordpress-c44c37d996ae00164c733de98faad1212a57f5c6.zip
Menus: Validate custom links and add accessible error messages.
Add URL validation in the admin navigation menu manager that matches the validation in the customizer when adding custom links. Improve accessibility of both custom link forms by adding `aria-invalid` and `aria-describedby` attributes with visible error messages and announcing the error using `wp.a11y.speak()`. Props joedolson, nikitasolanki1812, akrocks, pathan-amaankhan, rcreators, ironprogrammer, audrasjb, ankit-k-gupta, chaion07, rinkalpagdar, snehapatil02, jainil07, parthvataliya. Fixes #60619, #60969. git-svn-id: https://develop.svn.wordpress.org/trunk@59948 602fd350-edb4-49c9-b593-d223f7449a82
Diffstat (limited to 'src/js/_enqueues/lib/nav-menu.js')
-rw-r--r--src/js/_enqueues/lib/nav-menu.js60
1 files changed, 57 insertions, 3 deletions
diff --git a/src/js/_enqueues/lib/nav-menu.js b/src/js/_enqueues/lib/nav-menu.js
index 398f54ecfd..68e285d90d 100644
--- a/src/js/_enqueues/lib/nav-menu.js
+++ b/src/js/_enqueues/lib/nav-menu.js
@@ -1102,13 +1102,53 @@
}, 500 ) );
$('#add-custom-links input[type="text"]').on( 'keypress', function(e){
- $('#customlinkdiv').removeClass('form-invalid');
+ $( '#customlinkdiv' ).removeClass( 'form-invalid' );
+ $( '#custom-menu-item-url' ).removeAttr( 'aria-invalid' ).removeAttr( 'aria-describedby' );
+ $( '#custom-url-error' ).hide();
if ( e.keyCode === 13 ) {
e.preventDefault();
$( '#submit-customlinkdiv' ).trigger( 'click' );
}
});
+
+ $( '#submit-customlinkdiv' ).on( 'click', function (e) {
+ var urlInput = $( '#custom-menu-item-url' ),
+ url = urlInput.val().trim(),
+ errorMessage = $( '#custom-url-error' ),
+ urlWrap = $( '#menu-item-url-wrap' ),
+ urlRegex;
+
+ // Hide the error message initially
+ errorMessage.hide();
+ urlWrap.removeClass( 'has-error' );
+
+ /*
+ * Allow URLs including:
+ * - http://example.com/
+ * - //example.com
+ * - /directory/
+ * - ?query-param
+ * - #target
+ * - mailto:foo@example.com
+ *
+ * Any further validation will be handled on the server when the setting is attempted to be saved,
+ * so this pattern does not need to be complete.
+ */
+ urlRegex = /^((\w+:)?\/\/\w.*|\w+:(?!\/\/$)|\/|\?|#)/;
+ if ( ! urlRegex.test( url ) ) {
+ e.preventDefault();
+ urlInput.addClass( 'form-invalid' )
+ .attr( 'aria-invalid', 'true' )
+ .attr( 'aria-describedby', 'custom-url-error' );
+
+ errorMessage.show();
+ var errorText = errorMessage.text();
+ urlWrap.addClass( 'has-error' );
+ // Announce error message via screen reader
+ wp.a11y.speak( errorText, 'assertive' );
+ }
+ });
},
/**
@@ -1389,7 +1429,8 @@
addCustomLink : function( processMethod ) {
var url = $('#custom-menu-item-url').val().toString(),
- label = $('#custom-menu-item-name').val();
+ label = $('#custom-menu-item-name').val(),
+ urlRegex;
if ( '' !== url ) {
url = url.trim();
@@ -1397,7 +1438,20 @@
processMethod = processMethod || api.addMenuItemToBottom;
- if ( '' === url || 'https://' == url || 'http://' == url ) {
+ /*
+ * Allow URLs including:
+ * - http://example.com/
+ * - //example.com
+ * - /directory/
+ * - ?query-param
+ * - #target
+ * - mailto:foo@example.com
+ *
+ * Any further validation will be handled on the server when the setting is attempted to be saved,
+ * so this pattern does not need to be complete.
+ */
+ urlRegex = /^((\w+:)?\/\/\w.*|\w+:(?!\/\/$)|\/|\?|#)/;
+ if ( ! urlRegex.test( url ) ) {
$('#customlinkdiv').addClass('form-invalid');
return false;
}