I am trying to insert a link into selected text, as is common with front-end editors.
I can add a link to the user's text selection like this:
var sel = window.getSelection();
var e = document.createElement("a");
e.innerHTML = sel.toString();
e.type = "link";
e.href = "www.the_link_to_open.com"
e.target = "_blank";
var range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode(e)
This successfully adds an <a>
tag around the selected word, with the properties needed for the added link, like this:
<a type="link" href="www.the_link_to_open.com" target="_blank">highlighted text</a>
However, the flow a user would go through in the editor is to select the word/s, then open an input where they can add the link. But, as soon as the user clicks (focuses) on the input field the window.getSelection()
registers the input as the selection, which obviously makes adding the link impossible (since the selected word needs to be the selection).
I tried storing the result of window.getSelection()
to use later, but this seems to dynamically change the stored value regardless. I even tried a hard(?) copy to try and store the window.getSelection()
permanently using const selection = JSON.stringify(window.getSelection())
but this doesn't capture the output.
How can one keep the selection object stored when the user focuses away from the selected text?
CodePudding user response:
here you have a working solution with two function as described in my comment above.
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);
}
document.querySelector('.text').addEventListener('mouseup', getSelectedText)
document.querySelector('.link').addEventListener('change', (e) => createLink(e))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div class="text">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Minima illum, quod assumenda nisi illo hic quo minus excepturi quasi labore debitis nemo molestiae nesciunt, neque laboriosam repellendus necessitatibus vero corporis.
</div>
<br />
<div>
<label>Add url</label>
<input class="link" type="text" />
</div>
</body>
</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
How about you do it the other way around? You create the new “a” element before you show the input to the user, but you add an id attribute. This way you can later, after the user confirms the input prompt, find it by its id, change the href to the user input and remove the id again.
var sel = window.getSelection();
var e = document.createElement("a");
e.innerHTML = sel.toString();
e.type = "link";
e.href = "www.willBeOverwritten.com"
e.target = "_blank";
e.id = "newLinkWaitingForUserInput"
var range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode(e)
//Show input popup
//in the callback of the popup:
var userInput = "www.userInput.com";
//Search for the newly created link
var link = document.getElementById("newLinkWaitingForUserInput");
//Set the href to the userinput
link.href = userInput;
//remove the id
link.removeAttribute("id");
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
Of course you also have to remove the “a” element if the user cancels the input prompt.
CodePudding user response: