How to Make Clickable Anchor in Contenteditable Div

How to make clickable anchor in contentEditable div?

Just wrap the link in another div, like so:

<div contentEditable="true">

<div contentEditable="false">
Bla bla <a href="http://google.com">Google</a> Bla bla
</div>
</div>​

how to make clickable links after changing a contentEditable div?

If we assume an explanation always comes before a link every time, you can split the html in the #story and link the every second text, and you can disable the last clicked button to avoid any bugs.

// Edit : now works with all randomly placed links

var story = $("#story").html();
$('#btnedit').click(function(){$('#story').prop('contentEditable', true).focus();$('#story').html(story)
$("#btnsave").css("pointer-events", "all");$(this).css("pointer-events", "none");});
$('#btnsave').click(function(){ $(this).css("pointer-events", "none"); $("#btnedit").css("pointer-events", "all"); $('#story').prop('contentEditable', false).blur(); var newContent = ""; story = $("#story").html();
var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; newContent = story.replace(exp,"<a href=\"$1\">$1</a>");
$("#story").html(newContent);});
.story{white-space:pre-wrap;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><button id='btnedit'>EDIT</button><button id='btnsave'>SAVE</button>
<div class='story' id='story'>lorem ipsumhttps://www.youtube.com/lorem ipsumhttps://www.google.com/</div>

How to edit a link within a contentEditable div

I'm pretty sure this is what you were looking for, however I used jQuery just to make the concept a little easier to mock. jsbin preview available, so go look at it. If anyone is able to convert this to pure JS for the sake of the answer, I have made it a community wiki.

It works by binding to the keyup/click events on the editable div, then checking for the node that the users caret is being placed at using window.getSelection() for the Standards, or document.selection for those IE people. The rest of the code handles popping/handling the edits.

jQuery methods:

function getSelectionStartNode(){
var node,selection;
if (window.getSelection) { // FF3.6, Safari4, Chrome5 (DOM Standards)
selection = getSelection();
node = selection.anchorNode;
}
if (!node && document.selection) { // IE
selection = document.selection
var range = selection.getRangeAt ? selection.getRangeAt(0) : selection.createRange();
node = range.commonAncestorContainer ? range.commonAncestorContainer :
range.parentElement ? range.parentElement() : range.item(0);
}
if (node) {
return (node.nodeName == "#text" ? node.parentNode : node);
}
}

$(function() {
$("#editLink").hide();
$("#myEditable").bind('keyup click', function(e) {
var $node = $(getSelectionStartNode());
if ($node.is('a')) {
$("#editLink").css({
top: $node.offset().top - $('#editLink').height() - 5,
left: $node.offset().left
}).show().data('node', $node);
$("#linktext").val($node.text());
$("#linkhref").val($node.attr('href'));
$("#linkpreview").attr('href', $node.attr('href'));
} else {
$("#editLink").hide();
}
});
$("#linktext").bind('keyup change', function() {
var $node = $("#editLink").data('node');
$node.text($(this).val());
});
$("#linkhref").bind('keyup change', function() {
var $node = $("#editLink").data('node');
$node.attr('href', $(this).val());
$node.and('#linkpreview').attr('href',$(this).val());
});
});

Insert link in contenteditable element

document.execCommand() does this for you in all major browsers:

document.execCommand("CreateLink", false, "http://stackoverflow.com/");

To preserve the selection while your link dialog is displayed, you can use the following functions:

function saveSelection() {
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
var ranges = [];
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
ranges.push(sel.getRangeAt(i));
}
return ranges;
}
} else if (document.selection && document.selection.createRange) {
return document.selection.createRange();
}
return null;
}

function restoreSelection(savedSel) {
if (savedSel) {
if (window.getSelection) {
sel = window.getSelection();
sel.removeAllRanges();
for (var i = 0, len = savedSel.length; i < len; ++i) {
sel.addRange(savedSel[i]);
}
} else if (document.selection && savedSel.select) {
savedSel.select();
}
}
}

jsFiddle example: http://jsfiddle.net/JRKwH/1/

UPDATE

To get hold of the link(s) created (if any were created at all) is tricky. You could use my own Rangy library:

var sel = rangy.getSelection();
if (sel.rangeCount) {
var links = sel.getRangeAt(0).getNodes([1], function(el) {
return el.nodeName.toLowerCase() == "a";
});
alert(links.length);
}

... or something like the following:

function getLinksInSelection() {
var selectedLinks = [];
var range, containerEl, links, linkRange;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
linkRange = document.createRange();
for (var r = 0; r < sel.rangeCount; ++r) {
range = sel.getRangeAt(r);
containerEl = range.commonAncestorContainer;
if (containerEl.nodeType != 1) {
containerEl = containerEl.parentNode;
}
if (containerEl.nodeName.toLowerCase() == "a") {
selectedLinks.push(containerEl);
} else {
links = containerEl.getElementsByTagName("a");
for (var i = 0; i < links.length; ++i) {
linkRange.selectNodeContents(links[i]);
if (linkRange.compareBoundaryPoints(range.END_TO_START, range) < 1 && linkRange.compareBoundaryPoints(range.START_TO_END, range) > -1) {
selectedLinks.push(links[i]);
}
}
}
}
linkRange.detach();
}
} else if (document.selection && document.selection.type != "Control") {
range = document.selection.createRange();
containerEl = range.parentElement();
if (containerEl.nodeName.toLowerCase() == "a") {
selectedLinks.push(containerEl);
} else {
links = containerEl.getElementsByTagName("a");
linkRange = document.body.createTextRange();
for (var i = 0; i < links.length; ++i) {
linkRange.moveToElementText(links[i]);
if (linkRange.compareEndPoints("StartToEnd", range) > -1 && linkRange.compareEndPoints("EndToStart", range) < 1) {
selectedLinks.push(links[i]);
}
}
}
}
return selectedLinks;
}

jsFiddle: http://jsfiddle.net/JRKwH/3/

contentEditable attr set to true makes links in content unclickable

you have to make the link uneditable:

<div class='content-output' contentEditable='true'>
My content and link here: <a contentEditable='false' href='https://www.youtube.com/watch?v=dQw4w9WgXcQ' target='_blank'>Some video</a>
</div>

https://jsfiddle.net/ce13w610/1/

Hyperlink within div tag

Unfortunately what you're trying to do isn't simple. First of all, a clickable hyperlink is something that needs an anchor tag <a> and by making contenteditable as true, you cant simply type <a>..., You might want to look into using some libraries such as QuillJS or SlateJS.

The following is an example of QuillJS, if you need to links to be auto-converted, you'd need to use another library that extends Quill's logic

var quill = new Quill('#editor-container', {  modules: {    toolbar: [      [{        header: [1, 2, false]      }],      ['bold', 'italic', 'underline'],      ['image', 'code-block', 'link']    ]  },  placeholder: 'Compose an epic...',  theme: 'snow' // or 'bubble'});
#editor-container {  height: 375px;}
<link href="//cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet" /><link href="//cdn.quilljs.com/1.3.6/quill.bubble.css" rel="stylesheet" /><link href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.css" rel="stylesheet" /><link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/monokai-sublime.min.css" rel="stylesheet" /><script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.js"></script><script src="//cdn.quilljs.com/1.3.6/quill.js"></script>

<div id="editor-container"></div>

Adding link inside a DIV that looks like a Text Area

I've attached the same question asked previously. The anchor tag is contenteditable, and thus not clickable. You could wrap the anchor tag in another div that takes contenteditable off.

How to make clickable anchor in contentEditable div?

Allowing the user to paste clickable hyperlinks into a text area while editing

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>


Related Topics



Leave a reply



Submit