我正在使用codemirror,配置为显示javascript。
我有这样的代码:
...
var ref = 'http://www.example.com/test.html';
var ref2 = 'http://www.example.com/test2.html';
...
当显示编辑器时,如果我可以点击编辑器中可能存在的链接,那将是很棒的。该链接显然会在不同的选项卡上打开页面。
有一种简单的方法可以达到这个目的吗?
答案 0 :(得分:12)
不是很容易,但你要做的是:
编写可识别此类链接的叠加模式。基本上,这是一种模式,当它找到看起来像链接的东西时会吐出自定义标记类型,否则为null。您可以使用simple mode addon来简化此操作。您可以使用此令牌类型的CSS类(例如"link"
变为cm-link
)来设置链接的样式。
通过调用addOverlay
方法让编辑器使用叠加层。
在您的编辑器上注册mousedown
事件处理程序(instance.getWrapperElement().addEventListener(...)
)。
在此处理程序中,检查事件' target
是否具有链接CSS类。如果是,则用户点击链接。
如果是这样,请使用coordsChar
方法,使用鼠标事件中的坐标,找到单击文档中的位置。从该位置周围的文档文本中提取实际链接,然后按照该链接进行操作。
(或者,更好的是,不是直接干扰点击,而是可能将光标放在链接中或选择它,只要光标位于链接文本内,就会显示包含常规链接的窗口小部件。)
答案 1 :(得分:7)
这是我提出的解决方案:
演示:plunkr
代码:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.css"/>
<style>
html, body { height:100%; }
.CodeMirror .cm-url { color: blue; }
</style>
</head>
<body>
<script>
var cm = CodeMirror(document.body);
cm.setValue('hover over the links below\nlink1 https://plnkr.co/edit/5m31E14HUEhSXrXtOkNJ some text\nlink2 google.com\n');
hyperlinkOverlay(cm);
function hoverWidgetOnOverlay(cm, overlayClass, widget) {
cm.addWidget({line:0, ch:0}, widget, true);
widget.style.position = 'fixed';
widget.style.zIndex=100000;
widget.style.top=widget.style.left='-1000px'; // hide it
widget.dataset.token=null;
cm.getWrapperElement().addEventListener('mousemove', e => {
let onToken=e.target.classList.contains("cm-"+overlayClass), onWidget=(e.target===widget || widget.contains(e.target));
if (onToken && e.target.innerText!==widget.dataset.token) { // entered token, show widget
var rect = e.target.getBoundingClientRect();
widget.style.left=rect.left+'px';
widget.style.top=rect.bottom+'px';
//let charCoords=cm.charCoords(cm.coordsChar({ left: e.pageX, top:e.pageY }));
//widget.style.left=(e.pageX-5)+'px';
//widget.style.top=(cm.charCoords(cm.coordsChar({ left: e.pageX, top:e.pageY })).bottom-1)+'px';
widget.dataset.token=e.target.innerText;
if (typeof widget.onShown==='function') widget.onShown();
} else if ((e.target===widget || widget.contains(e.target))) { // entered widget, call widget.onEntered
if (widget.dataset.entered==='true' && typeof widget.onEntered==='function') widget.onEntered();
widget.dataset.entered='true';
} else if (!onToken && widget.style.left!=='-1000px') { // we stepped outside
widget.style.top=widget.style.left='-1000px'; // hide it
delete widget.dataset.token;
widget.dataset.entered='false';
if (typeof widget.onHidden==='function') widget.onHidden();
}
return true;
});
}
function hyperlinkOverlay(cm) {
if (!cm) return;
const rx_word = "\" "; // Define what separates a word
function isUrl(s) {
if (!isUrl.rx_url) {
// taken from https://gist.github.com/dperini/729294
isUrl.rx_url=/^(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i;
// valid prefixes
isUrl.prefixes=['http:\/\/', 'https:\/\/', 'ftp:\/\/', 'www.'];
// taken from https://w3techs.com/technologies/overview/top_level_domain/all
isUrl.domains=['com','ru','net','org','de','jp','uk','br','pl','in','it','fr','au','info','nl','ir','cn','es','cz','kr','ua','ca','eu','biz','za','gr','co','ro','se','tw','mx','vn','tr','ch','hu','at','be','dk','tv','me','ar','no','us','sk','xyz','fi','id','cl','by','nz','il','ie','pt','kz','io','my','lt','hk','cc','sg','edu','pk','su','bg','th','top','lv','hr','pe','club','rs','ae','az','si','ph','pro','ng','tk','ee','asia','mobi'];
}
if (!isUrl.rx_url.test(s)) return false;
for (let i=0; i<isUrl.prefixes.length; i++) if (s.startsWith(isUrl.prefixes[i])) return true;
for (let i=0; i<isUrl.domains.length; i++) if (s.endsWith('.'+isUrl.domains[i]) || s.includes('.'+isUrl.domains[i]+'\/') ||s.includes('.'+isUrl.domains[i]+'?')) return true;
return false;
}
cm.addOverlay({
token: function(stream) {
let ch = stream.peek();
let word = "";
if (rx_word.includes(ch) || ch==='\uE000' || ch==='\uE001') {
stream.next();
return null;
}
while ((ch = stream.peek()) && !rx_word.includes(ch)) {
word += ch;
stream.next();
}
if (isUrl(word)) return "url"; // CSS class: cm-url
}},
{ opaque : true } // opaque will remove any spelling overlay etc
);
let widget=document.createElement('button');
widget.innerHTML='→'
widget.onclick=function(e) {
if (!widget.dataset.token) return;
let link=widget.dataset.token;
if (!(new RegExp('^(?:(?:https?|ftp):\/\/)', 'i')).test(link)) link="http:\/\/"+link;
window.open(link, '_blank');
return true;
};
hoverWidgetOnOverlay(cm, 'url', widget);
}
</script>
</body>
</html>
答案 2 :(得分:1)
这是一个起点,但有待改进。
LIVE DEMO
function makeHyperLink(innerTextInside)
{
var all = document.getElementsByTagName("*");
for (var i=0, max=all.length; i < max; i++) {
if(all[i].innerText == innerTextInside)
{
all[i].innerHTML="<a target='_blank' href='https://google.com'>THIS IS A LINK TO GOOGLE</a>"
}
}
}