Insert link in contenteditable element

前端 未结 5 1598
灰色年华
灰色年华 2020-12-04 11:26

I\'m working on a simple blog system and I\'m using contenteditable so that users can format the text.

Up to now everything works like a charm.

Next thing i

相关标签:
5条回答
  • 2020-12-04 12:05

    As alfred said there are already well-developed editors, especially for the basic features. You can restrict it to use as few, or as many features, as you would like.

    The difficult part in developing it from scratch, is that all browsers act slightly differently. The following should get you moving in the right direction in most browsers, other than IE:

    var selected = document.getSelection();
    document.execCommand("insertHTML",false,"<a href='"+href+"'>"+selected+"</a>");
    
    0 讨论(0)
  • 2020-12-04 12:09

    Better looking answer:

    function link() {
      if (window.getSelection().toString()) {
        var a = document.createElement('a');
        a.href = 'http://www.google.com';
        a.title = 'GOOGLE';
        window.getSelection().getRangeAt(0).surroundContents(a);
      }
    }
    select some of text then click link button!
    <button onclick='link()'>link text to google</button>

    This method can be applied anywhere and does not require the element to be contenteidtable.

    you can add any event or attributes to the new A element like other elements.

    The window.getSelection().toString() checks if some text is actually selected. It works well in chrome, I don't have IE to test, anyway there are other methods to check it. But surroundContents() which is the key part is available in IE9 as suggested by MDN.

    Finally I suggest to use an iFrame instead of contenteditable div so there will be no worry about preserving the selection.

    0 讨论(0)
  • 2020-12-04 12:10

    EDIT It is not possible in IE in Execcommand, because we cannot insert quotes in 'href', we must do it in pure javascript with range :

    // IN DIV IN ONE IFRAME

    // Get the frame
    var iframe = document.getElementById('myframe');
    
    // Selection object in the frame
    theSelection = iframe.contentWindow.getSelection();
    
    // position of the selection to insert
    theRange = theSelection.getRangeAt(0);
    
    // get content inside the original selection (and delete content in)
    var fragment = theRange.extractContents();
    
    // Create a new link in frame
    var newLink = iframe.contentWindow.document.createElement('a');
    
    // Create a text element with the fragment to put in the link
    var theText = document.createTextNode(fragment.textContent);
    
    // URL 
    theLink.href = '#';
    
    // Title
    theLink.title = 'title';
    
    // Attribute 'onclick'
    theLink.setAttribute('onclick', thelink);
    
    // Target
    theLink.target = '_blank';
    
    // Add the text in the link
    theLink.appendChild(theText);
    
    // Insert the link at the range
    theRange.insertNode(newLink);
    

    // DIV WITHOUT FRAMES

    // Selection object in the window
    theSelection = window.getSelection();
    
    // begin of the selection to insert
    theRange = theSelection.getRangeAt(0);
    
    // get content inside the original selection (and delete content in)
    var fragment = theRange.extractContents();
    
    // Create a new link in the document
    var newLink = document.createElement('a');
    
    // Create a text element with the fragment to put in the link
    var theText = document.createTextNode(fragment.textContent);
    
    // URL 
    theLink.href = '#';
    
    // Title
    theLink.title = 'title';
    
    // Attribute 'onclick'
    theLink.setAttribute('onclick', thelink);
    
    // Target
    theLink.target = '_blank';
    
    // Add the text in the link
    theLink.appendChild(theText);
    
    // Insert the link at the range
    theRange.insertNode(newLink);
    
    0 讨论(0)
  • 2020-12-04 12:23

    document.execCommand() does this for you in all major browsers:

    document.execCommand("CreateLink", false, "http://stackoverflow.com/");
    

    To preserve the selection while your link dialog is displayed, you can use the following functions:

    function saveSelection() {
        if (window.getSelection) {
            sel = window.getSelection();
            if (sel.getRangeAt && sel.rangeCount) {
                var ranges = [];
                for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                    ranges.push(sel.getRangeAt(i));
                }
                return ranges;
            }
        } else if (document.selection && document.selection.createRange) {
            return document.selection.createRange();
        }
        return null;
    }
    
    function restoreSelection(savedSel) {
        if (savedSel) {
            if (window.getSelection) {
                sel = window.getSelection();
                sel.removeAllRanges();
                for (var i = 0, len = savedSel.length; i < len; ++i) {
                    sel.addRange(savedSel[i]);
                }
            } else if (document.selection && savedSel.select) {
                savedSel.select();
            }
        }
    }
    

    jsFiddle example: http://jsfiddle.net/JRKwH/1/

    UPDATE

    To get hold of the link(s) created (if any were created at all) is tricky. You could use my own Rangy library:

    var sel = rangy.getSelection();
    if (sel.rangeCount) {
        var links = sel.getRangeAt(0).getNodes([1], function(el) {
            return el.nodeName.toLowerCase() == "a";
        });
        alert(links.length);
    }
    

    ... or something like the following:

    function getLinksInSelection() {
        var selectedLinks = [];
        var range, containerEl, links, linkRange;
        if (window.getSelection) {
            sel = window.getSelection();
            if (sel.getRangeAt && sel.rangeCount) {
                linkRange = document.createRange();
                for (var r = 0; r < sel.rangeCount; ++r) {
                    range = sel.getRangeAt(r);
                    containerEl = range.commonAncestorContainer;
                    if (containerEl.nodeType != 1) {
                        containerEl = containerEl.parentNode;
                    }
                    if (containerEl.nodeName.toLowerCase() == "a") {
                        selectedLinks.push(containerEl);
                    } else {
                        links = containerEl.getElementsByTagName("a");
                        for (var i = 0; i < links.length; ++i) {
                            linkRange.selectNodeContents(links[i]);
                            if (linkRange.compareBoundaryPoints(range.END_TO_START, range) < 1 && linkRange.compareBoundaryPoints(range.START_TO_END, range) > -1) {
                                selectedLinks.push(links[i]);
                            }
                        }
                    }
                }
                linkRange.detach();
            }
        } else if (document.selection && document.selection.type != "Control") {
            range = document.selection.createRange();
            containerEl = range.parentElement();
            if (containerEl.nodeName.toLowerCase() == "a") {
                selectedLinks.push(containerEl);
            } else {
                links = containerEl.getElementsByTagName("a");
                linkRange = document.body.createTextRange();
                for (var i = 0; i < links.length; ++i) {
                    linkRange.moveToElementText(links[i]);
                    if (linkRange.compareEndPoints("StartToEnd", range) > -1 && linkRange.compareEndPoints("EndToStart", range) < 1) {
                        selectedLinks.push(links[i]);
                    } 
                }
            }
        }
        return selectedLinks;
    }
    

    jsFiddle: http://jsfiddle.net/JRKwH/3/

    0 讨论(0)
  • 2020-12-04 12:26

    I would do it this way:

    1. Create a link with a (possibly unique) initial bogus href attribute to identify it by.
    2. Fetch that element using document.querySelector('a[href=<unique-href>]').
    3. You now have a reference to the created element and can do with it as you please.

    The benefit of this is that you don't have to work with Selection at all.

    0 讨论(0)
提交回复
热议问题