diff --git a/src/wp-includes/js/tinymce/plugins/wplink/plugin.js b/src/wp-includes/js/tinymce/plugins/wplink/plugin.js
index 9f1a4eb91e..c426e80128 100644
--- a/src/wp-includes/js/tinymce/plugins/wplink/plugin.js
+++ b/src/wp-includes/js/tinymce/plugins/wplink/plugin.js
@@ -56,7 +56,7 @@
renderHtml: function() {
return (
'
' +
- '' +
+ '' +
'' +
'
'
);
@@ -235,6 +235,11 @@
inputInstance.reset();
editor.nodeChanged();
+
+ // Audible confirmation message when a link has been inserted in the Editor.
+ if ( typeof window.wp !== 'undefined' && window.wp.a11y && typeof window.wpLinkL10n !== 'undefined' ) {
+ window.wp.a11y.speak( window.wpLinkL10n.linkInserted );
+ }
} );
editor.addCommand( 'wp_link_cancel', function() {
@@ -371,11 +376,22 @@
},
focus: function( event, ui ) {
$input.attr( 'aria-activedescendant', 'mce-wp-autocomplete-' + ui.item.ID );
+ /*
+ * Don't empty the URL input field, when using the arrow keys to
+ * highlight items. See api.jqueryui.com/autocomplete/#event-focus
+ */
event.preventDefault();
},
select: function( event, ui ) {
$input.val( ui.item.permalink );
$( element.firstChild.nextSibling ).val( ui.item.title );
+
+ if ( 9 === event.keyCode && typeof window.wp !== 'undefined' &&
+ window.wp.a11y && typeof window.wpLinkL10n !== 'undefined' ) {
+ // Audible confirmation message when a link has been selected.
+ window.wp.a11y.speak( window.wpLinkL10n.linkSelected );
+ }
+
return false;
},
open: function() {
@@ -413,13 +429,21 @@
'aria-autocomplete': 'list',
'aria-expanded': 'false',
'aria-owns': $input.autocomplete( 'widget' ).attr( 'id' )
- } )
+ } )
.on( 'focus', function() {
- $input.autocomplete( 'search' );
+ var inputValue = $input.val();
+ /*
+ * Don't trigger a search if the URL field already has a link or is empty.
+ * Also, avoids screen readers announce `No search results`.
+ */
+ if ( inputValue && ! /^https?:/.test( inputValue ) ) {
+ $input.autocomplete( 'search' );
+ }
} )
.autocomplete( 'widget' )
.addClass( 'wplink-autocomplete' )
- .attr( 'role', 'listbox' );
+ .attr( 'role', 'listbox' )
+ .removeAttr( 'tabindex' ); // Remove the `tabindex=0` attribute added by jQuery UI.
}
tinymce.$( input ).on( 'keydown', function( event ) {
@@ -483,7 +507,20 @@
var url = inputInstance.getURL() || null,
text = inputInstance.getLinkText() || null;
- editor.focus(); // Needed for IE
+ /*
+ * Accessibility note: moving focus back to the editor confuses
+ * screen readers. They will announce again the Editor ARIA role
+ * `application` and the iframe `title` attribute.
+ *
+ * Unfortunately IE looses the selection when the editor iframe
+ * looses focus, so without returning focus to the editor, the code
+ * in the modal will not be able to get the selection, place the caret
+ * at the same location, etc.
+ */
+ if ( tinymce.Env.ie ) {
+ editor.focus(); // Needed for IE
+ }
+
window.wpLink.open( editor.id, url, text, linkNode );
editToolbar.tempHide = true;
diff --git a/src/wp-includes/js/wplink.js b/src/wp-includes/js/wplink.js
index c32a998449..3851c2fd59 100644
--- a/src/wp-includes/js/wplink.js
+++ b/src/wp-includes/js/wplink.js
@@ -1,7 +1,7 @@
var wpLink;
-( function( $, wpLinkL10n ) {
+( function( $, wpLinkL10n, wp ) {
var editor, correctedURL, linkNode,
inputs = {},
isTouch = ( 'ontouchend' in document );
@@ -76,6 +76,10 @@ var wpLink;
},
focus: function( event, ui ) {
$input.attr( 'aria-activedescendant', 'mce-wp-autocomplete-' + ui.item.ID );
+ /*
+ * Don't empty the URL input field, when using the arrow keys to
+ * highlight items. See api.jqueryui.com/autocomplete/#event-focus
+ */
event.preventDefault();
},
select: function( event, ui ) {
@@ -85,6 +89,9 @@ var wpLink;
inputs.text.val( ui.item.title );
}
+ // Audible confirmation message when a link has been selected.
+ wp.a11y.speak( wpLinkL10n.linkSelected );
+
return false;
},
open: function() {
@@ -117,15 +124,21 @@ var wpLink;
$input.attr( {
'aria-owns': $input.autocomplete( 'widget' ).attr( 'id' )
- } )
+ } )
.on( 'focus', function() {
- $input.autocomplete( 'search' );
+ var inputValue = $input.val();
+ /*
+ * Don't trigger a search if the URL field already has a link or is empty.
+ * Also, avoids screen readers announce `No search results`.
+ */
+ if ( inputValue && ! /^https?:/.test( inputValue ) ) {
+ $input.autocomplete( 'search' );
+ }
} )
.autocomplete( 'widget' )
.addClass( 'wplink-autocomplete' )
- .attr( 'role', 'listbox' );
-
-
+ .attr( 'role', 'listbox' )
+ .removeAttr( 'tabindex' ); // Remove the `tabindex=0` attribute added by jQuery UI.
},
// If URL wasn't corrected last time and doesn't start with http:, https:, ? # or /, prepend http://
@@ -170,7 +183,7 @@ var wpLink;
editor = null;
}
- if ( editor && window.tinymce.isIE && ! editor.windowManager.wplinkBookmark ) {
+ if ( editor && window.tinymce.isIE ) {
editor.windowManager.wplinkBookmark = editor.selection.getBookmark();
}
}
@@ -402,6 +415,9 @@ var wpLink;
wpLink.close();
textarea.focus();
+
+ // Audible confirmation message when a link has been inserted in the Editor.
+ wp.a11y.speak( wpLinkL10n.linkInserted );
},
mceUpdate: function() {
@@ -450,6 +466,9 @@ var wpLink;
wpLink.close( 'noReset' );
editor.focus();
editor.nodeChanged();
+
+ // Audible confirmation message when a link has been inserted in the Editor.
+ wp.a11y.speak( wpLinkL10n.linkInserted );
},
keydown: function( event ) {
@@ -511,4 +530,4 @@ var wpLink;
};
$( document ).ready( wpLink.init );
-})( jQuery, window.wpLinkL10n );
+})( jQuery, window.wpLinkL10n, window.wp );
diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php
index b40bab76a5..9b4643fc2d 100644
--- a/src/wp-includes/script-loader.php
+++ b/src/wp-includes/script-loader.php
@@ -204,7 +204,7 @@ function wp_default_scripts( &$scripts ) {
$scripts->add( 'jquery-effects-transfer', "/wp-includes/js/jquery/ui/effect-transfer$dev_suffix.js", array('jquery-effects-core'), '1.11.4', 1 );
$scripts->add( 'jquery-ui-accordion', "/wp-includes/js/jquery/ui/accordion$dev_suffix.js", array('jquery-ui-core', 'jquery-ui-widget'), '1.11.4', 1 );
- $scripts->add( 'jquery-ui-autocomplete', "/wp-includes/js/jquery/ui/autocomplete$dev_suffix.js", array('jquery-ui-menu'), '1.11.4', 1 );
+ $scripts->add( 'jquery-ui-autocomplete', "/wp-includes/js/jquery/ui/autocomplete$dev_suffix.js", array( 'jquery-ui-menu', 'wp-a11y' ), '1.11.4', 1 );
$scripts->add( 'jquery-ui-button', "/wp-includes/js/jquery/ui/button$dev_suffix.js", array('jquery-ui-core', 'jquery-ui-widget'), '1.11.4', 1 );
$scripts->add( 'jquery-ui-datepicker', "/wp-includes/js/jquery/ui/datepicker$dev_suffix.js", array('jquery-ui-core'), '1.11.4', 1 );
$scripts->add( 'jquery-ui-dialog', "/wp-includes/js/jquery/ui/dialog$dev_suffix.js", array('jquery-ui-resizable', 'jquery-ui-draggable', 'jquery-ui-button', 'jquery-ui-position'), '1.11.4', 1 );
@@ -226,10 +226,10 @@ function wp_default_scripts( &$scripts ) {
// Strings for 'jquery-ui-autocomplete' live region messages
did_action( 'init' ) && $scripts->localize( 'jquery-ui-autocomplete', 'uiAutocompleteL10n', array(
- 'noResults' => __( 'No search results.' ),
- /* translators: Number of results found when using jQuery UI Autocomplete */
- 'oneResult' => __( '1 result found. Use up and down arrow keys to navigate.' ),
- 'manyResults' => __( '%d results found. Use up and down arrow keys to navigate.' ),
+ 'noResults' => __( 'No search results.' ),
+ /* translators: Number of results found when using jQuery UI Autocomplete */
+ 'oneResult' => __( '1 result found. Use up and down arrow keys to navigate.' ),
+ 'manyResults' => __( '%d results found. Use up and down arrow keys to navigate.' ),
) );
// deprecated, not used in core, most functionality is included in jQuery 1.3
@@ -252,13 +252,13 @@ function wp_default_scripts( &$scripts ) {
$scripts->add( 'thickbox', "/wp-includes/js/thickbox/thickbox.js", array('jquery'), '3.1-20121105', 1 );
did_action( 'init' ) && $scripts->localize( 'thickbox', 'thickboxL10n', array(
- 'next' => __('Next >'),
- 'prev' => __('< Prev'),
- 'image' => __('Image'),
- 'of' => __('of'),
- 'close' => __('Close'),
- 'noiframes' => __('This feature requires inline frames. You have iframes disabled or your browser does not support them.'),
- 'loadingAnimation' => includes_url('js/thickbox/loadingAnimation.gif'),
+ 'next' => __('Next >'),
+ 'prev' => __('< Prev'),
+ 'image' => __('Image'),
+ 'of' => __('of'),
+ 'close' => __('Close'),
+ 'noiframes' => __('This feature requires inline frames. You have iframes disabled or your browser does not support them.'),
+ 'loadingAnimation' => includes_url('js/thickbox/loadingAnimation.gif'),
) );
$scripts->add( 'jcrop', "/wp-includes/js/jcrop/jquery.Jcrop.min.js", array('jquery'), '0.9.12');
@@ -401,13 +401,15 @@ function wp_default_scripts( &$scripts ) {
$scripts->add( 'admin-bar', "/wp-includes/js/admin-bar$suffix.js", array(), false, 1 );
- $scripts->add( 'wplink', "/wp-includes/js/wplink$suffix.js", array( 'jquery' ), false, 1 );
+ $scripts->add( 'wplink', "/wp-includes/js/wplink$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
did_action( 'init' ) && $scripts->localize( 'wplink', 'wpLinkL10n', array(
'title' => __('Insert/edit link'),
'update' => __('Update'),
'save' => __('Add Link'),
'noTitle' => __('(no title)'),
- 'noMatchesFound' => __('No results found.')
+ 'noMatchesFound' => __('No results found.'),
+ 'linkSelected' => __( 'Link selected.' ),
+ 'linkInserted' => __( 'Link inserted.' ),
) );
$scripts->add( 'wpdialogs', "/wp-includes/js/wpdialog$suffix.js", array( 'jquery-ui-dialog' ), false, 1 );