6

I know how to set an <a /> tag with the href attribute in a contenteditable like this:

execCommand("CreateLink", false, "#jumpmark");

which will result in

<a href="#jumpmark">selection</a>

However I cannot figure out how to set an anchor name instead of the href.
This is my desired result:

<a name="jumpmark">selection</a>

Can anyone help me?

Side notes: I am using jQuery and Rangy as libraries, however I would prefer a solution that works directly with execCommand.

Update: Here's a jsfiddle: http://jsfiddle.net/fjYHr/ Select some text and click the button. All I want is that with the button click a link is inserted with a name attribute set instead of the href.

Horen
  • 11,184
  • 11
  • 71
  • 113
  • I'm guessing `execCommand` is something of "Rangy" (don't know what that is). Couldn't you just use jQuery's `.attr("name", "jumpmark")` to do that? – Ian Dec 19 '12 at 09:04
  • 1
    No the `execCommand` is a browser command which enables you to change content in `contenteditable` elements. See http://www.quirksmode.org/dom/execCommand.html for an explanation – Horen Dec 19 '12 at 09:06
  • 2
    Can't believe I've never seen that before. Is it necessary to use `execCommand`? Why couldn't you use jQuery (or plain Javascript) to create the element, set its attribute, and then append it to the DOM where you want? – Ian Dec 19 '12 at 09:09
  • because I need to work on the current selection. Specifically I don't have a jQuery object that I can append to, meaning I don't have a DOM node that I can work on. – Horen Dec 19 '12 at 09:11
  • What do you mean the "current selection". You don't need jQuery objects or whatever, forget I said that. Just think of the normal way you add elements to the page with Javascript - use `createElement`, set its attribute, append to DOM. I guess I still don't understand why it's _necessary_ to use `execCommand` – Ian Dec 19 '12 at 09:13
  • @Horen: `I don't have a jQuery object that I can append to`: You can make one `$('closestStaticElememnt').append('...')` or `$('...').appendTo('closestStaticelEmemnt')`, see [jQuery documentation](http://api.jquery.com/) for additional research. – Nope Dec 19 '12 at 09:13
  • @Ian here is a jsfiddle that shows the way I intend to use it: http://jsfiddle.net/fjYHr/ Select some text and then click the button. How would you do that with jQuery only? – Horen Dec 19 '12 at 09:17
  • @Horen Ahh I finally understand. Didn't know you actually meant the text selection when you said "selection". This is a thinker... – Ian Dec 19 '12 at 09:27
  • @Ian Ok, sorry if it was unclear. I updated my question. – Horen Dec 19 '12 at 09:27

3 Answers3

2

I see you're using Rangy, but I don't how to use it at all. Before I realized what Rangy was, I looked up how to get the current selection. I found a function that gets it and replaces it with a passed in value. I ended up modfiying it, but here it is:

http://jsfiddle.net/fjYHr/1/

$(document).ready(function () {
    $("#setlink").click(function () {
        replaceSelectedText("jumplink");
    });
});

function replaceSelectedText(nameValue) {
    var sel, sel2, range;
    if (window.getSelection) {
        sel = window.getSelection();
        sel2 = ""+sel;  // Copy selection value
        if (sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();
            var newA = document.createElement("a");
            newA.name = nameValue;
            newA.innerHTML = sel2;
            range.insertNode(newA);
        }
    } else if (document.selection && document.selection.createRange) {
        // Not sure what to do here
        range = document.selection.createRange();
        var newA = "<a name='" + nameValue.replace(/'/g, "") + "'>" + range.text + "</a>";
        range.text = newA;
    }
}

Notice how I store the original current selection, then replace it with an <a> element that gets its name set with the passed-in value.

As for the document.selection part (which seems to be used by IE < 9), I'm not 100% sure that the code I provided will work (actually allow HTML in the selection, and not escaping it). But it's my attempt :)

Ian
  • 50,146
  • 13
  • 101
  • 111
  • Looks good - thanks :) I'll test for cross browser compatibility. – Horen Dec 19 '12 at 09:53
  • Thanks, and no problem. You'd obviously want to change the name of the function and/or clean it up a little. It looks like `document.selection` (the `else if` part) is mainly used in IE < 9. Otherwise, `window.selection` looks pretty standard. If you have IE < 9 to test on, you could try just using an HTML string, so who knows – Ian Dec 19 '12 at 10:04
  • @Horen And I just updated the answer with what I would try using for the second part. Not sure if it will work, can't test either :) – Ian Dec 19 '12 at 10:15
2

You could use something like the following, which is adapted from the pasteHtmlAtCaret() function from this answer of mine:

Demo: http://jsfiddle.net/F8Zny/

Code:

function surroundSelectedText(element) {
    var sel, range;
    if (window.getSelection) {
        // IE9 and non-IE
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            element.appendChild( document.createTextNode(range.toString()) );
            range.deleteContents();
            range.insertNode(element);

            // Preserve the selection
            range = range.cloneRange();
            range.setStartAfter(element);
            range.collapse(true);
            sel.removeAllRanges();
            sel.addRange(range);
        }
    } else if (document.selection && document.selection.type != "Control") {
        // IE < 9
        var selRange = document.selection.createRange();
        element.appendChild( document.createTextNode(selRange.text) );
        selRange.pasteHTML(element.outerHTML);
    }
}

If you must use document.execCommand() then you could use the InsertHTML command in non-IE browsers. However, IE does not support it.

document.execCommand("InsertHTML", false, '<a name="jumpmark">selection</a>');
Community
  • 1
  • 1
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • How do you place the cursor after the anchor when it's inserted. If the anchor is placed at the end of the line it's not possible to edit outside the anchor. This is also a problem if the anchored text is the only text on the page. – Quentin Engles Feb 06 '13 at 07:26
1

As you've seen execCommand is rather limited in the attributes you can set, as such you cannot set the name attribute using it - only the href.

As you have jQuery set as a tag, you can use that as an alternative:

var $a = $('<a></a>').attr('name', 'jumpmark').appendTo('body');

Update

I need to work on the current selection. Specifically I don't have a jQuery object that I can append to, meaning I don't have a DOM node that I can work on

In this case use a plugin such as Rangy to get the selection which you can then amend with jQuery as required.

Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339