Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop Chrome from turning relative links to absolute links on copy/paste?

I'm copying rich text from a div with contenteditable="true" and pasting it to a Medium draft. Most of the formatting is preserved fine, but for some reason I don't understand all relative links are converted to absolute ones. I don't know on what step this happens. I even thought Medium could be listening to "paste" events. This would be the worst case scenario, because I'd have very little control over it. But if so, how do they have access to the URL of the page I was when I copied the content? Indeed, after checking with other browsers, I concluded it's Chrome's fault, and not Medium's. On Safari it works perfectly, on Firefox it doesn't work at all (but that's a topic for another question…).

To make things more clear, I'm trying to mimic the behavior of the footnotes plugin I use on my Wordpress blog by writing a bookmarklet that does essentially the same.

Here's a demo page where you can paste text with a wiki-like syntax for inline references and parse them into proper footnotes:

https://rawgit.com/arielpontes/footnoter/master/index.html

In both modes of usage ([1] copy/pasting to the demo page or [2] using the bookmarklet), the resulting html has proper relative links. However, after pasting back to Medium on Chrome, they become absolute, pointing to rawgit.com and breaking the functionality.

If I run the code from my local machine instead of rawgit.com, however, the links are kept in relative form after paste even on Chrome.

What could possibly be going on? Is there any way to fix it?

like image 754
Ariel Avatar asked Jul 29 '16 15:07

Ariel


People also ask

How do you fix copy and paste on Google Chrome?

If you can't use the copy-paste option in Chrome, disable your extensions, clear the cache and update the browser. On the other hand, if the webpage you're visiting disabled text selection, press CTRL + U to access the source code. We hope this guide helped you restore the copy-paste function in Chrome.

How do you copy and paste and keep hyperlinks?

Find the link that you want to copy and highlight it with the cursor. You can do this by clicking twice (or, sometimes, three times). Then, right click and click the option for "Copy Link." Or, you can press Control (or Command on a Mac) + C. Then, go to where you want to paste the link and right click again.

How do I make a copied link clickable?

Select the text or picture that you want to display as a hyperlink. Press Ctrl+K. You can also right-click the text or picture and click Link on the shortcut menu. In the Insert Hyperlink box, type or paste your link in the Address box.


2 Answers

TL;DR - The one that in charge for the pasted content is the program that puts it in the clipboard.

Every time that you copy something into the clipboard, the application that does the copy can put there several data-types, so the program that you paste into will be able to use the one that works best for it. In case of a browser - when you select a content of a webpage and copy to your clipboard - the browser will create two types (html/plain and text/html), so if you paste that content into a program that can handle html - the data you will paste will be html, but if not - that data will be plain text.

Basically you have two options:

  1. Override the content that the browser saves in the clipboard (this way - no matter where the content will be pasted - it will look exactly the way you want to)
  2. Hijack the paste event, get the data from the clipboard, change it the way you want, and put it into the editor yourself.

$('#text').on('paste', function(e) {
  if ($('input[name=paste-type]:checked').val() == 'special') {
    e.preventDefault();
    if (window.getSelection) {
      sel = window.getSelection();
      if (sel.rangeCount) {
        range = sel.getRangeAt(0);
        range.deleteContents();
        node = document.createElement("p");
        text = 'Replacement text only for the paste'
        node.appendChild(document.createTextNode(text))
        range.insertNode(node);
      }
    }
  }
});
$(document).on('copy', function(e) {
  if ($('input[name=copy-type]:checked').val() == 'special') {
    e.preventDefault();
    if (window.getSelection) {
      sel = window.getSelection();
      if (sel.rangeCount) {
        range = sel.getRangeAt(0);
        nodes = range.cloneContents().childNodes
        content = ''
        contentPlain = ''
        for (var i = 0; i < nodes.length; i++) {
          node = nodes[i];
          contentPlain += node.textContent
          if (node.nodeType == 3) {
            content += node.textContent
          } else if (node.nodeType == 1) {
            content += node.outerHTML
          }
        }
      }
    } else {
      content = '<span style="color: red; background: yellow;">Replacement text only for the copy</span>';
    }
    e.originalEvent.clipboardData.setData('text/html', content);
    e.originalEvent.clipboardData.setData('text/plain', contentPlain);
  }
});
$('#btn1').click(function() {
  $('#ta1').val($('#text').html());
});
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<div id="text" contenteditable="true" style="width: 400px; height :250px; border: 1px solid black;">Paste your text here...</div><br />
<textarea id="ta1" style="width: 400px; height: 150px; border: 1px solid green;" disabled="disabled"></textarea><br />
<button id="btn1">View HTML</button><br />
<label for="reg"><input type="radio" name="paste-type" value="regular" id="reg" checked="checked" /> Regular Paste</label>
<label for="special"><input type="radio" name="paste-type" value="special" id="special" /> Force my paste</label>
<br /><br />
<label for="copy-reg"><input type="radio" name="copy-type" value="regular" id="copy-reg" checked="checked" /> Regular Copy</label>
<label for="copy-special"><input type="radio" name="copy-type" value="special" id="copy-special" /> Force my copy</label>
<br /><br />
<div style="width: 400px; height: 300px; border: 1px solid red;">
    <p>Nonumes molestiae <b>scripserit mei eu. In sea singulis evertitur</b>, verear inimicus delicatissimi ad eam. Eu eros scripserit cum, nam ferri ludus saperet te, ex sea nostro prompta inciderint. Est at causae .</p>
    <p>Quem feugait nam cu, sed <span style="background: red;">tantas meliore eu. Propriae efficiendi at</span> has, in usu nusquam noluisse, no nam natum verterem. Eu tation dignissim pro. Id eos wisi mollis commune</p>
    <p>Ea has quando blandit <a href="#a1">intellegebat, iusto</a> fabulas eos in, per consul suscipit inciderint cu. Ea veri possim nostrud vis. Id civibi. Ut duo posse <a href="#a2">graecis voluptatibus</a>, mea eu errem possim quaestio.</p>
</div>

In the example above I gave options you can play with (original copy/paste and special copy/paste).
You can see that in the example of special-copy - I built the html string to put in the clipboard from the selection in the page (based on the DOM elements). This way I was able to get the exact value of the href (without changing it to the absolute path).

For your convenient, the exact same code in jsfiddle: https://jsfiddle.net/m0ad3uaa/

like image 178
Dekel Avatar answered Oct 24 '22 04:10

Dekel


The issue is client-side. Browsers copy links with absolute URLs, this is to prevent issues arising when you paste links into different areas.

For example, if I click a link on http://site1.com which looks like this <a href="/myresource.jpg">, I'll be directed to http://site1.com/myresource.jpg.

Now, if you were to copy that same tag to http://site2.com, the link would now point to http://site2.com/myresource.jpg, which may or may not exist.

This makes sense in most cases, as if you're using Chrome, you're unlikely to be trying to copy a site, assets and all. It also fixes issues where <img> tags would point to assets which don't exist.

However, in saying all of that, it is possible to programmatically mess with what is being selected.

There's a great example of this here: http://bavotasan.com/2010/add-a-copyright-notice-to-copied-text/

Essentially, you'll just want to change document.oncopy to take window.getSelection() and remove all instances of your domain name, ensuring that the links are relative instead.

like image 37
Joundill Avatar answered Oct 24 '22 04:10

Joundill