diff --git a/packages/block-editor/src/components/link-control/index.js b/packages/block-editor/src/components/link-control/index.js index 38fec35f6ab6b6..4bbb1c1232b7bb 100644 --- a/packages/block-editor/src/components/link-control/index.js +++ b/packages/block-editor/src/components/link-control/index.js @@ -13,9 +13,10 @@ import { useCallback, useState, Fragment } from '@wordpress/element'; import { safeDecodeURI, filterURLForDisplay, - isURL, prependHTTP, getProtocol, + isValidFragment, + isUri, } from '@wordpress/url'; import { useInstanceId } from '@wordpress/compose'; import { useSelect } from '@wordpress/data'; @@ -85,31 +86,22 @@ function LinkControl( { }; const handleEntitySearch = async ( val, args ) => { - const results = await Promise.all( [ - fetchSearchSuggestions( val, { - ...( args.isInitialSuggestions ? { perPage: 3 } : {} ), - } ), - handleDirectEntry( val ), - ] ); - - const couldBeURL = ! val.includes( ' ' ); - - // If it's potentially a URL search then concat on a URL search suggestion - // just for good measure. That way once the actual results run out we always - // have a URL option to fallback on. - return couldBeURL && ! args.isInitialSuggestions ? results[ 0 ].concat( results[ 1 ] ) : results[ 0 ]; + return await fetchSearchSuggestions( val, { + ...( args.isInitialSuggestions ? { perPage: 3 } : {} ), + } ); }; - // Effects - const getSearchHandler = useCallback( ( val, args ) => { - const protocol = getProtocol( val ) || ''; - const isMailto = protocol.includes( 'mailto' ); - const isInternal = startsWith( val, '#' ); - const isTel = protocol.includes( 'tel' ); + const couldBeURI = function( val ) { + const isInternal = startsWith( val, '#' ) && isValidFragment( val ); + const includesWWW = !! ( val && val.includes( 'www.' ) ); - const handleManualEntry = isInternal || isMailto || isTel || isURL( val ) || ( val && val.includes( 'www.' ) ); + return isUri( val ) || includesWWW || isInternal; + }; - return ( handleManualEntry ) ? handleDirectEntry( val, args ) : handleEntitySearch( val, args ); + // Effects + const getSearchHandler = useCallback( ( val, args ) => { + // If it has a fragment and it is valid + return ( couldBeURI( val ) ) ? handleDirectEntry( val, args ) : handleEntitySearch( val, args ); }, [ handleDirectEntry, fetchSearchSuggestions ] ); // Render Components diff --git a/packages/url/README.md b/packages/url/README.md index 9436880c51f43c..7b59a0258a442c 100644 --- a/packages/url/README.md +++ b/packages/url/README.md @@ -227,6 +227,25 @@ _Returns_ - `boolean`: Whether or not it looks like an email. +# **isURI** + +Determines whether the given string looks like a URI (of any type). + +_Usage_ + +```js +const isURI = isURI( 'https://wordpress.org' ); // true +const anotherURI = isURI('mailto:hello@wordpress.org'); // true +``` + +_Parameters_ + +- _uri_ `string`: The string to scrutinise. + +_Returns_ + +- `boolean`: Whether or not it looks like a URI. + # **isURL** Determines whether the given string looks like a URL. diff --git a/packages/url/package.json b/packages/url/package.json index 73c82ab0daeb52..bd92afdcb1e6fc 100644 --- a/packages/url/package.json +++ b/packages/url/package.json @@ -24,7 +24,8 @@ "dependencies": { "@babel/runtime": "^7.4.4", "lodash": "^4.17.15", - "qs": "^6.5.2" + "qs": "^6.5.2", + "valid-url": "^1.0.9" }, "publishConfig": { "access": "public" diff --git a/packages/url/src/index.js b/packages/url/src/index.js index 3a47cba0bc3b59..e108c326b12311 100644 --- a/packages/url/src/index.js +++ b/packages/url/src/index.js @@ -1,3 +1,5 @@ + +export { isURI } from './is-uri'; export { isURL } from './is-url'; export { isEmail } from './is-email'; export { getProtocol } from './get-protocol'; diff --git a/packages/url/src/is-uri.js b/packages/url/src/is-uri.js new file mode 100644 index 00000000000000..6f98411c5e510a --- /dev/null +++ b/packages/url/src/is-uri.js @@ -0,0 +1,21 @@ +/** + * External dependencies + */ +import { isUri } from 'valid-url'; + +/** + * Determines whether the given string looks like a URI (of any type). + * + * @param {string} uri The string to scrutinise. + * + * @example + * ```js + * const isURI = isURI( 'https://wordpress.org' ); // true + * const anotherURI = isURI('mailto:hello@wordpress.org'); // true + * ``` + * + * @return {boolean} Whether or not it looks like a URI. + */ +export function isURI( uri ) { + return isUri( uri ); +}