@yochanan was very close, but not quite what I needed. His solution added the link to a random area on the page. Likely because I am using a dynamic modal for entering a link, where as he used a static one.
For the solution to work as intended, I had to distinguish between mouseup and long-press, in addition to handling the window selection.
HTML
<div id="hold_text" contenteditable=false>This is some text. Select one or more words in here, by highlighting the word/s with your cursor.<br><br>Then click on the LINK button, add your link, and hit ENTER.</div> <button id="butt">LINK</button> <div id='modal'><a id='close'>X<a><input id="input" placeholder='paste url, then hit enter'></input></div>
CSS
* { font-family: arial; } body { background: #218c74; } #hold_text { height: 200px; width: 500px; background: #f7f1e3; border-radius: 4px; padding: 10px; font-size: 18px; } button { height : auto; width : auto; background : #ff5252; border-radius : 4px; padding: 8px; font-size: 18px; border: none; margin-top: 10px; cursor: pointer; color: white; } #modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); height: auto; width: auto; box-shadow: 2px 2px 30px black; display: none; border-radius: 4px; border : 2px solid #ffda79; } #close { cursor: pointer; color: white; margin: 5px; } input { width: 300px; height: 30px; font-size: 18px; border: none; outline: 0; }
JS
text = document.getElementById("hold_text"); button = document.getElementById("butt"); modal = document.getElementById("modal"); close = document.getElementById("close"); input = document.getElementById("input"); button.addEventListener("click", function() { modal.style.display = "block"; input.focus(); close.addEventListener("click", function(e) { modal.style.display = "none"; }); input.addEventListener("keypress", function(e) { if(e.key === "Enter") { createLink(e); modal.style.display = "none"; input.value = ""; } }) }); cnt = 0; text.addEventListener("mouseup", function() { cnt++; if(cnt === 2) { getSelectedText(); } setTimeout(function() { cnt = 0; }, 200) if(long_press) { getSelectedText(); long_press = false; } }) call_on_longpress(); long_press = false; function call_on_longpress() { var delay; var longpress = 400; text.addEventListener('mousedown', function(e) { var _this = this; delay = setTimeout(check, longpress); function check() { long_press = true; } }, true); text.addEventListener('mouseup', function(e) { clearTimeout(delay); }); text.addEventListener('mouseout', function(e) { clearTimeout(delay); }); } let selectedText, range; function getSelectedText() { const selectObj = window.getSelection(); selectedText = selectObj.toString(); range = selectObj.getRangeAt(0) } function createLink(e) { var a = document.createElement("a"); a.innerHTML = selectedText a.type = "link"; a.href = e.target.value a.target = "_blank"; range.deleteContents(); range.insertNode(a); }
RESULT

CodePen