JSFiddle - React, Tailwind, and code Playground
HTML
<p id="editable" contenteditable="true">
Select something up here and click the input below
<br> on firefox the input get the focus and the text still selected.
<br> on chrome the text still selected but the input lose focus
</p>
<table>
<tr>
<td>
<input type="text" id="special" style="border: solid blue 1px" placeholder="insert valid link incl. http://">
</td>
<td>
<button id="button">Add link</button>
</td>
</tr>
</table>
CSS
.selected {
background-color: dodgerblue;
color: white;
}
JavaScript
!function(doc, win) {
var input = doc.getElementById('special')
, editable = doc.getElementById('editable')
, button = doc.getElementById('button')
, fragment = null
, range = null;
function saveSelection() {
if (win.getSelection) {
sel = win.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
return sel.getRangeAt(0);
}
} else if (doc.selection && doc.selection.createRange) {
return doc.selection.createRange();
}
return null;
}
/* Not needed, unless you want also restore selection
function restoreSelection() {
if (range) {
if (win.getSelection) {
sel = win.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (doc.selection && range.select) {
range.select();
}
}
}
*/
function saveRangeEvent(event) {
range = saveSelection();
if (range && !range.collapsed) {
fragment = range.cloneContents();
toggleButton();
}
}
function toggleButton() {
button.disabled = !fragment || !input.value.match(/^https?:.*/);
}
toggleButton();
editable.addEventListener('mouseup', saveRangeEvent);
editable.addEventListener('keyup', saveRangeEvent);
button.addEventListener('click', function(event) {
// insert link
var link = doc.createElement('a');
link.href = input.value;
input.value = '';
range.surroundContents(link);
toggleButton();
});
input.addEventListener('keyup', toggleButton);
input.addEventListener('change', toggleButton);
input.addEventListener('mousedown', function(event) {
// create fake selection
if (fragment) {
var span = doc.createElement('span');
span.className = 'selected';
range.surroundContents(span);
}
});
input.addEventListener('blur', function(event) {
// remove fake selection
if (fragment) {
range.deleteContents();
range.insertNode(fragment);
...