سؤال

I have been staring at this problem for some time now and have not managed to get a working solution.

I am using the Rangy library to ensure best support for Ranges.

Objectives

  1. Make a selection and wrap with a link. Even if the selection is within a link.
  2. Make a full selection of a already linked selection and replace it with a link.

Example

I wish to convert the following, where | being a selection range.

  link to |add a link| to
<a href="http://example.com">link to |add a link| to</a>

Expected

  link to |add a link| to
<a href="http://example.com">link to</a> |<a href="http://example.com/pre">add a link</a>| <a href="http://example.com">to</a>

Test Expectations Plnkr

I thank you for your help.

Update (2013-05-15 21:37 UTC):

I have the following

range = document.getSelection();
link = document.createElement('a');
link.href = "http://example.com/new";
range.surroundContents(link);

I have also updated the plnkr tests

هل كانت مفيدة؟

المحلول

I have managed to find a solution that allows support for all 3 scenarios.

rangy.createModule('SafeWrapLink', function(api, module) {
  var surroundSelectionWithLink;
  surroundSelectionWithLink = (function(href) {
    var after, afterLink, afterLinkHref, before, beforeLink, beforeLinkHref, currentLink, fullText, link, par, parNode, range, selectionText;
    range = document.getSelection().getRangeAt(0);
    selectionText = range.toString();
    if (range.commonAncestorContainer.nodeName !== "#text") {
      beforeLinkHref = range.commonAncestorContainer.childNodes[0].getAttribute('href');
      afterLinkHref = range.commonAncestorContainer.childNodes[2].getAttribute('href');
      par = range.commonAncestorContainer;
      parNode = par;
    } else {
      par = range.commonAncestorContainer.parentNode;
      currentLink = par.getAttribute('href');
      parNode = par.parentNode;
    }
    fullText = par.innerText;
    before = fullText.match(new RegExp("^(.*)" + selectionText))[1];
    after = fullText.match(new RegExp(selectionText + "(.*)$"))[1];

    // Build link for before selection
    beforeLink = document.createElement('a');
    beforeLink.href = beforeLinkHref || currentLink;
    beforeLink.innerText = before;

    // Build link to insert
    link = document.createElement('a');
    link.href = href;
    link.innerText = selectionText;

    // Build link for after selection
    afterLink = document.createElement('a');
    afterLink.href = afterLinkHref || currentLink;
    afterLink.innerText = after;

    // Append the links in order
    if (beforeLink.innerText.length > 0) {
      parNode.appendChild(beforeLink);
    }
    parNode.appendChild(link);
    if (afterLink.innerText.length > 0) {
      parNode.appendChild(afterLink);
    }

    // remove old linking
    if (par === range.commonAncestorContainer) {
      par.removeChild(par.childNodes[0]);
      return par.removeChild(par.childNodes[1]);
    } else {
      return parNode.removeChild(par);
    }
  });
  return api.util.extend(api, {
    surroundSelectionWithLink: surroundSelectionWithLink
  });
});

then after a selection is made call the following

rangy.surroundSelectionWithLink('http://www.example.com/added');

see the tests and live code on plnkr.co

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top