TinyMCE, link check:

- Use `wp.a11y.speak()` to announce bad URLs.
- Do not add a title to the link toolbar.
- Better error message.

Props afercia, azaozz.
See #36638.

git-svn-id: https://develop.svn.wordpress.org/trunk@38126 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Andrew Ozz 2016-07-21 03:41:17 +00:00
parent 7e52b06003
commit fb1fbcfdc0
4 changed files with 41 additions and 33 deletions

View File

@ -3906,26 +3906,25 @@ function wp_ajax_test_url() {
$href = get_bloginfo( 'url' ) . $href; $href = get_bloginfo( 'url' ) . $href;
} }
// No redirects
$response = wp_safe_remote_get( $href, array( $response = wp_safe_remote_get( $href, array(
'timeout' => 15, 'timeout' => 15,
// Use an explicit user-agent // Use an explicit user-agent
'user-agent' => 'WordPress URL Test', 'user-agent' => 'WordPress URL Test',
) ); ) );
$message = null; $error = false;
if ( is_wp_error( $response ) ) { if ( is_wp_error( $response ) ) {
$error = $response->get_error_message(); if ( strpos( $response->get_error_message(), 'resolve host' ) !== false ) {
$error = true;
if ( strpos( $message, 'resolve host' ) !== false ) {
$message = array( 'error' => __( 'Invalid host name.' ) );
} }
} elseif ( wp_remote_retrieve_response_code( $response ) === 404 ) {
wp_send_json_error( $message ); $error = true;
} }
if ( wp_remote_retrieve_response_code( $response ) === 404 ) { if ( $error ) {
wp_send_json_error( array( 'error' => __( 'Not found, HTTP error 404.' ) ) ); wp_send_json_error( array( 'httpError' => true ) );
} }
wp_send_json_success(); wp_send_json_success();

View File

@ -1065,7 +1065,7 @@ final class _WP_Editors {
'Ctrl + letter:' => __( 'Ctrl + letter:' ), 'Ctrl + letter:' => __( 'Ctrl + letter:' ),
'Letter' => __( 'Letter' ), 'Letter' => __( 'Letter' ),
'Action' => __( 'Action' ), 'Action' => __( 'Action' ),
'Invalid host name.' => __( 'Invalid host name.' ), 'Warning: the link has been inserted but the destination cannot be reached.' => __( 'Warning: the link has been inserted but the destination cannot be reached.' ),
'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' => 'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' =>
__( 'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' ), __( 'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' ),
'When starting a new paragraph with one of these formatting shortcuts followed by a space, the formatting will be applied automatically. Press Backspace or Escape to undo.' => 'When starting a new paragraph with one of these formatting shortcuts followed by a space, the formatting will be applied automatically. Press Backspace or Escape to undo.' =>

View File

@ -94,6 +94,9 @@
var doingUndoRedoTimer; var doingUndoRedoTimer;
var $ = window.jQuery; var $ = window.jQuery;
var urlErrors = {}; var urlErrors = {};
var emailRegex = /^(mailto:)?[a-z0-9._%+-]+@[a-z0-9][a-z0-9.-]*\.[a-z]{2,63}$/i;
var speak = ( typeof window.wp !== 'undefined' && window.wp.a11y && window.wp.a11y.speak ) ? window.wp.a11y.speak : function() {};
var hasLinkError = false;
function getSelectedLink() { function getSelectedLink() {
var href, html, var href, html,
@ -147,6 +150,16 @@
}); });
} }
function setLinkError( $link ) {
hasLinkError = true;
$link.attr( 'data-wplink-url-error', 'true' );
speak( editor.translate( 'Warning: the link has been inserted but the destination cannot be reached.' ), 'assertive' );
if ( toolbar && toolbar.visible() ) {
toolbar.$el.find( '.wp-link-preview a' ).addClass( 'wplink-url-error' );
}
}
function checkLink( node ) { function checkLink( node ) {
var $link = editor.$( node ); var $link = editor.$( node );
var href = $link.attr( 'href' ); var href = $link.attr( 'href' );
@ -155,13 +168,14 @@
return; return;
} }
// Early check hasLinkError = false;
if ( /^http/i.test( href ) && ! /\.[a-z]{2,63}(\/|$)/i.test( href ) ) {
urlErrors[href] = tinymce.translate( 'Invalid host name.' ); if ( /^http/i.test( href ) && ! /^https?:\/\/[a-z0-9][a-z0-9.-]*\.[a-z]{2,63}(\/|$)/i.test( href ) ) {
urlErrors[href] = true;
} }
if ( urlErrors.hasOwnProperty( href ) ) { if ( urlErrors.hasOwnProperty( href ) ) {
$link.attr( 'data-wplink-url-error', 'true' ); setLinkError( $link );
return; return;
} else { } else {
$link.removeAttr( 'data-wplink-url-error' ); $link.removeAttr( 'data-wplink-url-error' );
@ -179,13 +193,9 @@
return; return;
} }
if ( response.data && response.data.error ) { if ( response.data && response.data.httpError ) {
urlErrors[href] = response.data.error; urlErrors[href] = true;
$link.attr( 'data-wplink-url-error', 'true' ); setLinkError( $link );
if ( toolbar && toolbar.visible() ) {
toolbar.$el.find( '.wp-link-preview a' ).addClass( 'wplink-url-error' ).attr( 'title', editor.dom.encode( response.data.error ) );
}
} }
}); });
} }
@ -274,7 +284,7 @@
return; return;
} }
if ( ! /^(?:[a-z]+:|#|\?|\.|\/)/.test( href ) ) { if ( ! /^(?:[a-z]+:|#|\?|\.|\/)/.test( href ) && ! emailRegex.test( href ) ) {
href = 'http://' + href; href = 'http://' + href;
} }
@ -291,8 +301,8 @@
editor.nodeChanged(); editor.nodeChanged();
// Audible confirmation message when a link has been inserted in the Editor. // Audible confirmation message when a link has been inserted in the Editor.
if ( typeof window.wp !== 'undefined' && window.wp.a11y && typeof window.wpLinkL10n !== 'undefined' ) { if ( typeof window.wpLinkL10n !== 'undefined' && ! hasLinkError ) {
window.wp.a11y.speak( window.wpLinkL10n.linkInserted ); speak( window.wpLinkL10n.linkInserted );
} }
} ); } );
@ -449,10 +459,9 @@
$input.val( ui.item.permalink ); $input.val( ui.item.permalink );
$( element.firstChild.nextSibling ).val( ui.item.title ); $( element.firstChild.nextSibling ).val( ui.item.title );
if ( 9 === event.keyCode && typeof window.wp !== 'undefined' && if ( 9 === event.keyCode && typeof window.wpLinkL10n !== 'undefined' ) {
window.wp.a11y && typeof window.wpLinkL10n !== 'undefined' ) {
// Audible confirmation message when a link has been selected. // Audible confirmation message when a link has been selected.
window.wp.a11y.speak( window.wpLinkL10n.linkSelected ); speak( window.wpLinkL10n.linkSelected );
} }
return false; return false;
@ -536,7 +545,7 @@
editor.on( 'wptoolbar', function( event ) { editor.on( 'wptoolbar', function( event ) {
var linkNode = editor.dom.getParent( event.element, 'a' ), var linkNode = editor.dom.getParent( event.element, 'a' ),
$linkNode, href, edit, title; $linkNode, href, edit;
if ( typeof window.wpLink !== 'undefined' && window.wpLink.modalOpen ) { if ( typeof window.wpLink !== 'undefined' && window.wpLink.modalOpen ) {
editToolbar.tempHide = true; editToolbar.tempHide = true;
@ -561,12 +570,12 @@
previewInstance.setURL( href ); previewInstance.setURL( href );
event.element = linkNode; event.element = linkNode;
event.toolbar = toolbar; event.toolbar = toolbar;
title = urlErrors.hasOwnProperty( href ) ? editor.dom.encode( urlErrors[ href ] ) : null;
if ( $linkNode.attr( 'data-wplink-url-error' ) === 'true' ) { if ( $linkNode.attr( 'data-wplink-url-error' ) === 'true' ) {
toolbar.$el.find( '.wp-link-preview a' ).addClass( 'wplink-url-error' ).attr( 'title', title ); toolbar.$el.find( '.wp-link-preview a' ).addClass( 'wplink-url-error' );
} else { } else {
toolbar.$el.find( '.wp-link-preview a' ).removeClass( 'wplink-url-error' ).attr( 'title', null ); toolbar.$el.find( '.wp-link-preview a' ).removeClass( 'wplink-url-error' );
hasLinkError = false;
} }
} }
} else if ( editToolbar.visible() ) { } else if ( editToolbar.visible() ) {

View File

@ -2,8 +2,8 @@ var wpLink;
( function( $, wpLinkL10n, wp ) { ( function( $, wpLinkL10n, wp ) {
var editor, searchTimer, River, Query, correctedURL, linkNode, var editor, searchTimer, River, Query, correctedURL, linkNode,
emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i, emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,63}$/i,
urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i, urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,63}[^ "]*$/i,
inputs = {}, inputs = {},
rivers = {}, rivers = {},
isTouch = ( 'ontouchend' in document ); isTouch = ( 'ontouchend' in document );