Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I got interested in this, so I've written the starting point for a full solution. The following uses my <a href="http://code.google.com/p/rangy/" rel="nofollow">Rangy library</a> with its <a href="http://code.google.com/p/rangy/wiki/SelectionSaveRestoreModule" rel="nofollow">selection save/restore module</a> to save and restore the selection and normalize cross browser issues. It surrounds all matching text (@whatever in this case) with a link element and positions the selection where it had been previously. This is triggered after there has been no keyboard activity for one second. It should be quite reusable.</p> <pre><code>function createLink(matchedTextNode) { var el = document.createElement("a"); el.style.backgroundColor = "yellow"; el.style.padding = "2px"; el.contentEditable = false; var matchedName = matchedTextNode.data.slice(1); // Remove the leading @ el.href = "http://www.example.com/?name=" + matchedName; matchedTextNode.data = matchedName; el.appendChild(matchedTextNode); return el; } function shouldLinkifyContents(el) { return el.tagName != "A"; } function surroundInElement(el, regex, surrounderCreateFunc, shouldSurroundFunc) { var child = el.lastChild; while (child) { if (child.nodeType == 1 &amp;&amp; shouldSurroundFunc(el)) { surroundInElement(child, regex, surrounderCreateFunc, shouldSurroundFunc); } else if (child.nodeType == 3) { surroundMatchingText(child, regex, surrounderCreateFunc); } child = child.previousSibling; } } function surroundMatchingText(textNode, regex, surrounderCreateFunc) { var parent = textNode.parentNode; var result, surroundingNode, matchedTextNode, matchLength, matchedText; while ( textNode &amp;&amp; (result = regex.exec(textNode.data)) ) { matchedTextNode = textNode.splitText(result.index); matchedText = result[0]; matchLength = matchedText.length; textNode = (matchedTextNode.length &gt; matchLength) ? matchedTextNode.splitText(matchLength) : null; surroundingNode = surrounderCreateFunc(matchedTextNode.cloneNode(true)); parent.insertBefore(surroundingNode, matchedTextNode); parent.removeChild(matchedTextNode); } } function updateLinks() { var el = document.getElementById("editable"); var savedSelection = rangy.saveSelection(); surroundInElement(el, /@\w+/, createLink, shouldLinkifyContents); rangy.restoreSelection(savedSelection); } var keyTimer = null, keyDelay = 1000; function keyUpLinkifyHandler() { if (keyTimer) { window.clearTimeout(keyTimer); } keyTimer = window.setTimeout(function() { updateLinks(); keyTimer = null; }, keyDelay); } </code></pre> <p>HTML:</p> <pre><code>&lt;p contenteditable="true" id="editable" onkeyup="keyUpLinkifyHandler()"&gt; Some editable content for @someone or other &lt;/p&gt; </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload