firefox 3之后,出于安全考虑,浏览器禁止了js从剪贴板获取数据,但是很多时候,我们需要对粘贴的数据进行处理。对其自动加超链接便是其中最常见的要求之一。那么该如何去实现呢?
tinymce有一个插件,叫linkautodetect的,它可以在用户输入类似Url、email地址时,用于判断是否自动为其添加超链接。但是该插件只有在按空格(space)建以及回车(enter)时,才会为其添加超链接。
tinymce还有一个插件,叫paste的,用于处理从word或其他地方粘贴数据时进行处理。(本文的解决办法将不使用paste插件。因其可能导致中文乱码问题(个人猜测))。
综合以上两个插件,一个不算完美但可应用的简化版 paste时自动添加超链接功能实现如下:
思路: 在paste动作将内容粘贴之前,建一个div层做容器,用于接收内容,将光标移动至容器层。系统动作paste发生之后,我们获取到的容器层内的innerHTML即为粘贴的内容。取出粘贴的内容,利用replace正则替换内容中的Url、email地址。并将新内容替换旧内容。
难点: 1、光标位置操作
2、替换的正则匹配(如何排除已添加的,正确处理开始、结尾处等)
解决如下: 在tinymce编辑器的环境中,初始化编辑器时
在editor的初始化参数setup中添加
setup : function (ed){
.....
ed.onPaste.add(function (ed, e){
//mark the paste
mark_paste_content(ed, e);
//execute the check url after paste
setTimeout(function(){
paste_link_detect(ed);
}, 100);
});
....
}
函数 mark_paste_content 定义如下:
//construct a containner for pasteing
function mark_paste_content(ed, ev){
var marker, dom = ed.dom, sel = ed.selection, markerId = 'paste_marker';
//To add a marker into the content
var insert_marker = function (){
var h = '
';
var skip_undo = true;
// First delete the contents seems to work better on WebKit
if (!ed.selection.isCollapsed())
ed.getDoc().execCommand('Delete', false, null);
// It's better to use the insertHTML method on Gecko since it will combine paragraphs correctly before inserting the contents
ed.execCommand(tinymce.isGecko ? 'insertHTML' : 'mceInsertContent', false, h, {skip_undo : skip_undo});
}
// Insert a marker for the caret position
insert_marker();
//record the cursor position
marker = dom.get(markerId);
rng = sel.getRng();
rng.setStart(marker, 0);
rng.setEnd(marker, 1);
sel.setRng(rng);
console.log(ed.getContent());
}
函数 paste_link_detect定义如下:
//To add hyperlink to url address automatically when doing paste.
function paste_link_detect(ed){
var marker, dom = ed.dom, sel = ed.selection, markerId = 'paste_marker';
//Used for detecting url on paste
var PRE_email = /([^a-z0-9_=@\-\"\':]|^)([a-z0-9_\-]+(\.[_a-z0-9\-]+)*@([_a-z0-9\-]+\.)+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel))($|(?=[^a-z0-9]))/gim;
var PRE_url = /([^a-z0-9=@\-\"\'\\\/\.]|^)((https?|ftp|news):\/\/)?(([a-z]([a-z0-9\-]*\.)+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel)|(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*))?(\?[a-z0-9+_\-\.%=&]*)?(#[a-z][a-z0-9_]*)?)($|(?=[^a-z0-9#?&%+\-@=]))/gim;
var detectPasteLink = function(htmlstr){
htmlstr = htmlstr.replace(PRE_url, '$1
$2$4$16');
htmlstr = htmlstr.replace(PRE_email, '$1
$2$6');
return htmlstr;
}
node = dom.get(markerId);
pnode = node.parentNode;
//replace url
var htmlstr = node.innerHTML;
//fix a bug on firefox: firefox automatically add a br to marker span
if('
' == htmlstr.substring(htmlstr.length-4)){
htmlstr = htmlstr.substring(0, htmlstr.length-4);
}
console.log(htmlstr);
html_pasted = detectPasteLink(htmlstr);
//cross the empty anchor and useless anchor
html_pasted = html_pasted.replace(/
]*)>]*>(.*?)<\/a><\/a>/gim, '$2');
html_pasted = html_pasted.replace(/
]*>[\s\r\n\t\f]*<\/a>/gim, '');
//check if the content changed
var rng = sel.getRng();
var frag = rng.createContextualFragment(html_pasted);
//Use a div to wrap the pasted content. Or it will have problem under safari and chrome
var new_node = document.createElement('div');
new_node.appendChild(frag);
var nextsibling = node.nextSibling;
while(nextsibling && nextsibling.nodeType !=1){
nextsibling = nextsibling.nextSibling;
}
//replace the content
pnode.replaceChild(new_node, node);
//var needtoremovenext = false;
if(!nextsibling){
//needtoremovenext = true;
nextsibling = document.createElement('span');
nextsibling.innerHTML = ' ';
pnode.appendChild(nextsibling);
}
//reset the cursor position
rng.setStartAfter(nextsibling);
rng.setEndAfter(nextsibling);
sel.setRng(rng);
//if(needtoremovenext){
// dom.remove(nextsibling);
//}
// Remove marker if it's left
while (elm = dom.get(markerId))
dom.remove(elm);
}