anchorcontenteditablerelative-pathabsolute-pathclipboard-interaction

How to handle URL relative/absolute "glitch" in contenteditable when copy and pasting


In contenteditable regions, if you paste an element with a URL attribute, in some browsers it converts the URL from relative to absolute.

I've read through some bug reports that claim it's "fixed" in the latest release, but it's not.

I threw together this fiddle to demonstrate: Hurray for Demos!

It's there, it's ugly, and I'm wondering what is the best way to fix it.

  1. The 1st idea that comes to mind is onpaste, find all anchors in the current node and parse it with regex. Not ideal I suppose, but it might be effective.

  2. ???

  3. ???

I really wish they'd just leave things alone and not create so many browser related issues with contenteditable, but I guess that would make it too easy.

Any thoughts on the best way to address this?


Solution

  • CKEditor, before letting browser break the data, copies all src, name and href attributes to data-cke-saved-src|href attributes. Unfortunately, since data is a string, it has to be done by regexp. You can find the code here: /core/htmldataprocessor.js#L772-L783.

    var protectElementRegex = /<(a|area|img|input|source)\b([^>]*)>/gi,
        // Be greedy while looking for protected attributes. This will let us avoid an unfortunate
        // situation when "nested attributes", which may appear valid, are also protected.
        // I.e. if we consider the following HTML:
        //
        //  <img data-x="&lt;a href=&quot;X&quot;" />
        //
        // then the "non-greedy match" returns:
        //
        //  'href' => '&quot;X&quot;' // It's wrong! Href is not an attribute of <img>.
        //
        // while greedy match returns:
        //
        //  'data-x' => '&lt;a href=&quot;X&quot;'
        //
        // which, can be easily filtered out (#11508).
        protectAttributeRegex = /([\w-]+)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+))/gi,
        protectAttributeNameRegex = /^(href|src|name)$/i;
    
    function protectAttributes( html ) {
        return html.replace( protectElementRegex, function( element, tag, attributes ) {
            return '<' + tag + attributes.replace( protectAttributeRegex, function( fullAttr, attrName ) {
                // Avoid corrupting the inline event attributes (#7243).
                // We should not rewrite the existed protected attributes, e.g. clipboard content from editor. (#5218)
                if ( protectAttributeNameRegex.test( attrName ) && attributes.indexOf( 'data-cke-saved-' + attrName ) == -1 )
                    return ' data-cke-saved-' + fullAttr + ' data-cke-' + CKEDITOR.rnd + '-' + fullAttr;
    
                return fullAttr;
            } ) + '>';
        } );
    }
    

    Then, while processing HTML taken from editable element, data-cke-saved-* attributes override the original ones.