I have a HTML form with a field in which the user can supply text. In that text they might want to include a link to another website amongst the plain text. Ideally, when they paste a URL from another source into the text area, it becomes clickable as they're editing. Is there a simple solution for implementing this feature without using external tools such as the one suggested in this answer?
The closest I've gotten is by using a <div>contenteditable="true"</div> and dragging hyperlinks into the div. Unfortunately, when a div has contenteditable="true" anchors become un-clickable which was addressed here by holding the ctrl button to set contenteditable="false"; however, then we lose ctrl+v functionality. Additionally, I'm not sure how I will be able to submit the data if the tag is a <div> instead of <textarea>.
When using <textarea>, the link is copied as plain-text and isn't a clickable link. I believe anchors aren't allowed in a <textarea>.
I don't believe <input type="url"> works because the text area may contain content that isn't a URL.
Refer to snippet to see my attempts.
var content = document.getElementById('content');
document.addEventListener('keydown', function(event) {
if (event.keyCode === 17) { // when ctrl is pressed
content.contentEditable = false; // disable contentEditable
}
}, false);
document.addEventListener('keyup', function(event) {
if (event.keyCode === 17) { // when ctrl is released
content.contentEditable = true; // reenable contentEditable
}
}, false);
<textarea></textarea>
<div id="content" contenteditable="true"></div>
<input type="url">
Rather than ctrl click, you can add a button to toggle Preview/Edit like :
var content = document.getElementById('content');
var previewButton = document.getElementById('previewButton');
previewButton.addEventListener('click', function(event) {
if (event.target.value === "Preview") { // when btn is first clicked
event.target.value = "Edit";
content.contentEditable = false; // disable contentEditable
} else {
event.target.value = "Preview";
content.contentEditable = true; // enablecontentEditable
}
}, false);
<div id="content" contenteditable="true"></div>
<input type="button" value="Preview" id="previewButton" />
Using a mutationObserver that looks for new anchors in the text area, this script will set contentEditable = false when the user mouses over the anchor and toggle it back on when they mouse off.
var target = document.getElementById('content');
var observer = new MutationObserver(function(mutations) {
let mutation = mutations.pop();
if (mutation.type === 'childList') {
let anchors = mutation.target.getElementsByTagName('a')
for (let i = 0; i < anchors.length; i++) {
let anchor = anchors[i]
anchor.addEventListener('mouseover', function() {
content.contentEditable = false; // disable contentEditable
});
anchor.addEventListener('mouseleave', function() {
content.contentEditable = true; // disable contentEditable
// restor caret position somehow
});
}
}
});
var config = {
attributes: false,
childList: true,
characterData: false
};
observer.observe(target, config);
<div id="content" contenteditable="true"></div>
Restoring the caret to it's position before switching contentEditable to false is not done which reduces usability.
Not sure whether the text area can be submitted with the form when it is a <div> rather than a <textarea>.