Javascript 在 contenteditable 元素中插入链接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5605401/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Insert link in contenteditable element
提问by PeeHaa
I'm working on a simple blog system and I'm using contenteditable so that users can format the text.
我正在开发一个简单的博客系统,我正在使用 contenteditable 以便用户可以格式化文本。
Up to now everything works like a charm.
到目前为止,一切都像一个魅力。
Next thing i want is that users can add a hyperlink in the text.
接下来我想要的是用户可以在文本中添加超链接。
The user have to select (part of) the text and click on the link button. After that a popup opens where users should enter the link address.
用户必须选择(部分)文本并单击链接按钮。之后,将打开一个弹出窗口,用户应在其中输入链接地址。
When the user clicks on the accept button I want to add the link to the text they selected in the contenteditable.
当用户单击接受按钮时,我想将链接添加到他们在 contenteditable 中选择的文本。
How can I implement this functionality, since I have no clue how to do this?
我怎样才能实现这个功能,因为我不知道如何做到这一点?
My site: http://82.170.147.49/blog/3/alpha-release
我的网站:http: //82.170.147.49/blog/3/alpha-release
jsFiddle of my site: http://jsfiddle.net/qhN9j/
我网站的 jsFiddle:http: //jsfiddle.net/qhN9j/
回答by Tim Down
document.execCommand()
does this for you in all major browsers:
document.execCommand()
在所有主要浏览器中为您执行此操作:
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/
jsFiddle 示例: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 Rangylibrary:
获取创建的链接(如果有的话)是很棘手的。你可以使用我自己的Rangy库:
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/
jsFiddle:http: //jsfiddle.net/JRKwH/3/
回答by clmarquart
As alfred said there are already well-developed editors, especially for the basic features. You can restrict it to use as few, or as many features, as you would like.
正如阿尔弗雷德所说,已经有完善的编辑器,尤其是基本功能。您可以根据需要限制它使用尽可能少或尽可能多的功能。
The difficult part in developing it from scratch, is that all browsers act slightly differently. The following shouldget you moving in the right direction in most browsers, other than IE:
从头开始开发它的难点在于所有浏览器的行为略有不同。以下应该让你在大多数浏览器中朝着正确的方向前进,除了 IE:
var selected = document.getSelection();
document.execCommand("insertHTML",false,"<a href='"+href+"'>"+selected+"</a>");
回答by Ali
Better looking answer:
更好看的答案:
function link() {
if (window.getSelection().toString()) {
var a = document.createElement('a');
a.href = 'http://www.google.com';
a.title = 'GOOGLE';
window.getSelection().getRangeAt(0).surroundContents(a);
}
}
select some of text then click link button!
<button onclick='link()'>link text to google</button>
This method can be applied anywhere and does not require the element to be contenteidtable
.
此方法可以应用于任何地方,并且不需要元素为contenteidtable
。
you can add any event or attributes to the new A element like other elements.
您可以像其他元素一样向新的 A 元素添加任何事件或属性。
The window.getSelection().toString()
checks if some text is actually selected. It works well in chrome, I don't have IE to test, anyway there are other methods to check it. But surroundContents()
which is the key part is available in IE9 as suggested by MDN.
在window.getSelection().toString()
检查一些文字,在实际选择。它在chrome中运行良好,我没有IE可以测试,无论如何还有其他方法可以检查它。但这surroundContents()
是 MDN 建议的 IE9 中可用的关键部分。
Finally I suggest to use an iFrame instead of contenteditable div so there will be no worry about preserving the selection.
最后,我建议使用 iFrame 而不是 contenteditable div,这样就不用担心保留选择了。
回答by antibug
EDIT It is not possible in IE in Execcommand, because we cannot insert quotes in 'href', we must do it in pure javascript with range :
// IN DIV IN ONE IFRAME
编辑 在 Execcommand 中的 IE 中是不可能的,因为我们不能在 'href' 中插入引号,我们必须在具有范围的纯 javascript 中进行:
// 在一个 IFRAME 中的 DIV
// Get the frame
var iframe = document.getElementById('myframe');
// Selection object in the frame
theSelection = iframe.contentWindow.getSelection();
// position of the selection to insert
theRange = theSelection.getRangeAt(0);
// get content inside the original selection (and delete content in)
var fragment = theRange.extractContents();
// Create a new link in frame
var newLink = iframe.contentWindow.document.createElement('a');
// Create a text element with the fragment to put in the link
var theText = document.createTextNode(fragment.textContent);
// URL
theLink.href = '#';
// Title
theLink.title = 'title';
// Attribute 'onclick'
theLink.setAttribute('onclick', thelink);
// Target
theLink.target = '_blank';
// Add the text in the link
theLink.appendChild(theText);
// Insert the link at the range
theRange.insertNode(newLink);
// DIV WITHOUT FRAMES
// 没有框架的 DIV
// Selection object in the window
theSelection = window.getSelection();
// begin of the selection to insert
theRange = theSelection.getRangeAt(0);
// get content inside the original selection (and delete content in)
var fragment = theRange.extractContents();
// Create a new link in the document
var newLink = document.createElement('a');
// Create a text element with the fragment to put in the link
var theText = document.createTextNode(fragment.textContent);
// URL
theLink.href = '#';
// Title
theLink.title = 'title';
// Attribute 'onclick'
theLink.setAttribute('onclick', thelink);
// Target
theLink.target = '_blank';
// Add the text in the link
theLink.appendChild(theText);
// Insert the link at the range
theRange.insertNode(newLink);
回答by Erik Aigner
I would do it this way:
我会这样做:
- Create a link with a (possibly unique) initial bogus
href
attribute to identify it by. - Fetch that element using
document.querySelector('a[href=<unique-href>]')
. - You now have a reference to the created element and can do with it as you please.
- 创建一个带有(可能是唯一的)初始虚假
href
属性的链接以识别它。 - 使用 获取该元素
document.querySelector('a[href=<unique-href>]')
。 - 您现在拥有对创建的元素的引用,并且可以随心所欲地使用它。
The benefit of this is that you don't have to work with Selection
at all.
这样做的好处是您根本不必与之合作Selection
。