Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pasting anchor link transforms selected text into link #49636

Open
porg opened this issue Apr 6, 2023 · 12 comments
Open

Pasting anchor link transforms selected text into link #49636

porg opened this issue Apr 6, 2023 · 12 comments
Labels
[Feature] Link Editing Link components (LinkControl, URLInput) and integrations (RichText link formatting) Needs Decision Needs a decision to be actionable or relevant [Type] Enhancement A suggestion for improvement.

Comments

@porg
Copy link

porg commented Apr 6, 2023

Reproduction

  1. Copy an anchor link like #introduction to your clipboard with ⌘-C.
  2. Select text portion which shall get a link.
  3. Paste your clipboard with ⌘-V

Result

Actual: The anchor link gets pasted as raw text and replaces the selected text.

Proposed: The selected text gets a link to a local anchor. HTML result should be:

As mentioned in the<a href="#introduction">intro</a> you have…

Workaround: Open link dialog with ⌘-K and paste the anchor link there and then apply it.

Video Recording of status quo and workarround

Wordpress Gutenberg - Pasting anchor link should transforms selected text into link - But as of WP 6.1.1 instead gets pasted as raw text and replaces the selected text

@kathrynwp kathrynwp added [Type] Enhancement A suggestion for improvement. [Feature] Link Editing Link components (LinkControl, URLInput) and integrations (RichText link formatting) labels Apr 6, 2023
@kevin940726
Copy link
Member

The paste handler for links uses isURL to determine if the text is a link.

// A URL was pasted, turn the selection into a link.
if ( ! isURL( pastedText ) ) {
return value;
}

Under the hood, it just uses new URL() to try creating a url instance, and return false if it fails. I don't think we can allow every possible URIs to be pasted as links (imaging pasting relative links). Whether anchor text should be treated as a link is up to discussion, one could also say that it's a hashtag and should be pasted as plain text too. Let's wait for other people's opinions if we all think that this is unexpected and confusing to work with :)

@kevin940726 kevin940726 added the Needs Decision Needs a decision to be actionable or relevant label Apr 11, 2023
@porg
Copy link
Author

porg commented May 31, 2023

@kevin940726 Thanks for identifying the responsible code and explaining how it works.

@ALL regarding the UX aspects:

1. URI scheme limitations

  • a) For security/abuse reasons it is clear that you want to be able to limit the URL scheme within comments.
  • b) But there's little reason limiting available schemes in links within the post/page body, which is under your control.
    • If someone wants to link to tel:// or ftps:// or file:// or intranet-app:// on purpose — Why forbid it?
    • Must WordPress content creators be "protected from themselves"? If so which concrete WordPress design guideline advocates for this?
    • IMHO it is not a CMS responsibility to limit/safeguard link schemes, but the web browser's responsibility.
    • Unless on a multi author server where an admin/editor wants/needs to set a central enforceable policy.

2. Relative links and anchor links

The negative implications of the limitating clipboard pasting of various URL/link formats far outweights the possibility of a false positive, which is very unlikely, as I will prove now:

a) Possible links forms

  • a0) Full URLs: These work already anyhow.
  • a1) Absolute server paths, starting with a slash, like /topic-a or /topic-a/ or /topic-b/subtopic-x/ are not common in prose text.
  • a2) Relative links with slash at the end like subtopic-y/ or ./cats/ or ../topic-x/ are not normal prose text either.
  • a3) Relative links with a slash only in the middle part(s) of the string like this/that or deep/deeper/deepest could be normal valid prose text indeed.
  • a4) Anchor links with a single word like: #topic could be a hashtag text.
  • a5) Anchor links with multiple hyphen separated words like #topic-with-longer-title cannot be hashtags as those are without hyphens.

b) Arguments / Rationale

  • b1) None of the samples is normal prose text you choose to replace the current text, except the special cases of a3 and a4. And for a4 then again: Why select a word and replace it with a hashtag? The probability is very low. Much more likely you will simply put a # character in front of an existing word designated as a hashtag or you will simply paste the hashtag at the cursor.
  • b2) The involved user interaction has a strong user intent, coincidence can be ruled out.
    • You select a certain text portion.
    • Then you insert your clipboard.
    • If you simply wanted to insert text as literal you most likely just insert at the cursor selection.
    • Selecting and then pasting is either replacement intent or "add link" intent. And that you paste a continuous string without whitespace is totally unlikely for multi sentence/paragraph text and also very unlikely for a single word.
    • And even if, you have plenty of alternatives: Just inisert at the cursor. Or select, delete, then insert.

Summary

Misinterpretation is very unlikely. Plenty workarounds available. Very good reasons to handle link pasting as easy and flexible as possible!

@kevin940726
Copy link
Member

Anchor links with multiple hyphen separated words like #topic-with-longer-title cannot be hashtags as those are without hyphens.

This depends on what the hashtag platform you're copying from. Some platforms allow hashtags with hyphens and it's implemented differently for each platform.

Slashes and hashbang are pretty generic and could be seen in other languages or context as well. It's always a trade-off. Unless we have more feedback and data collected, I don't think we should rush into any solution.

This discussion could be a great starting point though. I appreciate your feedback a lot! Let's wait for others' inputs or decide how we can make this more visible to others if you think it's worth pursuing!

@porg
Copy link
Author

porg commented Jun 1, 2023

Thanks for pointing out that 2a5) #hashtags-with-multiple-words-hyphen-separated are maybe found on some hashtag platforms, so maybe in 0.2% of use cases this plays a role.

But then again, the strongest argument, overarching all others, is anyhow 2b2) the interaction in that scenario: That selecting a single word or multiple words/sentences/paragraphs and then pasting a continuous string without spaces (different forms of links), is highly unlikely, and if intentional plenty alternatives are available: just insert at cursor, or first delete then insert at cursor.

Independently of this, overall, let's have some further input:

CC: @getdave @mtias @annezazu @talldan @mrfoxtalbot

@getdave
Copy link
Contributor

getdave commented Jun 6, 2023

Great discussion here - thank you.

I've recently raised a PR to make the "URL" detection a little looser and based more on sensible heuristics rather than hard rulesets.

#51011

I think we should test that PR and see if it resolves the issue described.

@porg
Copy link
Author

porg commented Jun 6, 2023

  1. Thanks for the appreciation!

  2. Is there a test server instance which runs this your PR? I would test there and give you feedback then. I now PM you on WordPress Slack, so that you could potentially give me credentials, if a test server exists.

@porg
Copy link
Author

porg commented Jun 6, 2023

WordPress Gutenberg PR 51011 as of 2023-06-06 11:11 +0200

WordPress Gutenberg PR 51011 tested on 2023-06-06--1112+0200

@getdave
Copy link
Contributor

getdave commented Jun 6, 2023

Thank you. Any chance you could paste your test content here in text form? That will allow me to write tests against these criteria 🙇

@porg
Copy link
Author

porg commented Jun 6, 2023

Yes. Will follow soon.

@getdave
Copy link
Contributor

getdave commented Jun 6, 2023

Oh I just realised @kevin940726 said that this code was responsible

// A URL was pasted, turn the selection into a link.
if ( ! isURL( pastedText ) ) {
return value;
}

That's outside the scope of #51011 as it's a separate area of the codebase. Apologies for confusion here. Plain text on that test data would still be useful however.

@porg
Copy link
Author

porg commented Jun 6, 2023

Link Pasting - Data Set for conducting manual/automated tests

As Screenshot in Twenty Twenty Three theme

WordPress Gutenberg PR 51011 Test Data Set

As WordPress markup

<!-- wp:columns {"align":"wide"} -->
<div class="wp-block-columns alignwide"><!-- wp:column -->
<div class="wp-block-column"><!-- wp:heading -->
<h2 class="wp-block-heading">Pasteboard</h2>
<!-- /wp:heading -->

<!-- wp:code -->
<pre class="wp-block-code"><code>#one
#two-words
/elsewhere
/elsewhere/
/elsewhere/dreaming
/elsewhere/dreaming/

wordpress.org
www.wordpress.org
https:&#47;&#47;wordpress.org

wordpress.org/plugins
www.wordpress.org/plugins
https://wordpress.org/plugins

wordpress.org/plugins/
www.wordpress.org/plugins/
https://wordpress.org/plugins/

file:///Applications/
ftp://ftp.gnu.org/gnu/diffutils/
tel://+1-877-273-3049</code></pre>
<!-- /wp:code --></div>
<!-- /wp:column -->

<!-- wp:column -->
<div class="wp-block-column"><!-- wp:heading -->
<h2 class="wp-block-heading">Rich Text Section</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Anchor links</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>with one word: One</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Anchor link with two words: Two Words</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Absolute path link Level 1: Elsewhere</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Absolute path link Level 1 with slash: Elsewhere</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Absolute path link Level 2: Dreaming</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Absolute path link Level 2 with slash: Dreaming</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Links to Homepage</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Homepage as URL as domain name only: WordPress</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Homepage as URL on www subdomain: WordPress</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Homepage as full URL with scheme and on main domain: WordPress</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Links to page without final slash</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>URL without scheme with domain to page: Plugins</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>URL without scheme with www subdomain to page: Plugins</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>URL with scheme on main domain to page: Plugins</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Links to page with final slash</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>URL without scheme with domain to page/: Plugins</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>URL without scheme with www subdomain to page/: Plugins</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>URL with scheme on main domain to page/: Plugins</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Custom Scheme Links</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>File scheme link: Apps</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>FTP scheme link: GNU Diffutils</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Telephone Number: Call support</p>
<!-- /wp:paragraph --></div>
<!-- /wp:column --></div>
<!-- /wp:columns -->

<!-- wp:separator -->
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<!-- /wp:separator -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Local Link Targets</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3,"anchor":"link-target-one"} -->
<h3 class="wp-block-heading" id="link-target-one">One</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Anchor links lead to me which could also be interpreted as hashtag text. But its unlikely that you first select a word to then replace it with a hashtag. And if the less likely scenario still has plenty workarounds: Select, delete, then paste the literal hashtag. Or paste the hashtag and then remove outdated text portions.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3,"anchor":"link-target-one"} -->
<h3 class="wp-block-heading" id="link-target-one">Two Words</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Anchor links lead to me which could be interpreted as hashtags on platforms which allow multiple hyphen separated words. This in itself is very unlikely. And it becomes even more unlikely that you select multiple words to then replace with a multi-word-hashtag. And again for this edge case various workarounds exist. Hence it has to make place to first and foremost serve the commonplace scenario conveniently.</p>
<!-- /wp:paragraph -->

@porg
Copy link
Author

porg commented Jun 6, 2023

Scope here or elsewhere — I'd appreciate if someone changes it.
And I hope that my concrete test data set can help for test evaluation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Link Editing Link components (LinkControl, URLInput) and integrations (RichText link formatting) Needs Decision Needs a decision to be actionable or relevant [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

No branches or pull requests

4 participants