Open cnspray opened 4 years ago
使用turndown.js和turndown-plugin-gfm.js转换为markdown的好处是,非标准表格为解析为html格式,包含合并之类的。下面是自己尝试做的一个demo.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://unpkg.com/turndown/dist/turndown.js"></script>
<script src="https://unpkg.com/turndown-plugin-gfm/dist/turndown-plugin-gfm.js"></script>
</head>
<body>
<div id="tmpdiv">dddd</div>
<textarea style="width:100%;height:100px" id="dd" ></textarea>
<textarea style="width:100%;height:500px" id="dd1" ></textarea>
</body>
<script>
dd.addEventListener("paste",
function(e) {
if (! (e.clipboardData && e.clipboardData.items)) {
return;
}
for (var i = 0,
len = e.clipboardData.items.length; i < len; i++) {
var item = e.clipboardData.items[i];
if (item.kind === "string" && item.type === "text/html") {
item.getAsString(function(str) {
if(isWordDocument(str)){
//处理一下html,忽略特殊情况下尾部乱码
str=str.match(/(<html[\s\S]*<\/html>)/gi)[0];
/* document.getElementById("dd1").innerText=str=str.replace(/<head>[\s\S]*<\/head>/gi,"")
//去掉注释
.replace(/<!--[\s\S]*?-->/ig, ""); */
//return;
//去掉头部描述
str=str.replace(/<head>[\s\S]*<\/head>/gi,"")
//去掉注释
.replace(/<!--[\s\S]*?-->/ig, "")
//去掉隐藏元素
.replace(/<([a-z0-9]*)[^>]*\s*display:none[\s\S]*?><\/\1>/gi,'');
//处理其他冗余代码
str=filterPasteWord(str);
//上传文件
str=str.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/gi, function (match, capture) {
var path=capture.replace("file:///",'');
//upload
return '<img src="' + path + '" />';
})
var gfm = turndownPluginGfm.gfm;
var turndownService = new TurndownService({
headingStyle: 'atx',
hr: '- - -',
bulletListMarker: '-',
codeBlockStyle: 'indented',
fence: '```',
emDelimiter: '_',
strongDelimiter: '**'});
turndownService.use(gfm);
turndownService.keep(['sub', 'sup']);
var markdown = turndownService.turndown(str);
document.getElementById("dd1").innerText=markdown;
return markdown;
}else{
var gfm = turndownPluginGfm.gfm;
var turndownService = new TurndownService({
headingStyle: 'atx',
hr: '- - -',
bulletListMarker: '-',
codeBlockStyle: 'indented',
fence: '```',
emDelimiter: '_',
strongDelimiter: '**'});
turndownService.use(gfm);
turndownService.keep(['sub', 'sup']);
var markdown = turndownService.turndown(str);
document.getElementById("dd1").innerText=markdown;
return markdown;
}
})
}
}
});
//判断粘贴的内容是否来自office
function isWordDocument(str) {
return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<(v|o):|lang=)/ig.test(str) || /\"urn:schemas-microsoft-com:office:office/ig.test(str);
}
//去除冗余属性和标签
function filterPasteWord(str) {
return str.replace(/[\t\r\n]+/g, ' ').replace(/<!--[\s\S]*?-->/ig, "")
//转换图片
.replace(/<v:shape [^>]*>[\s\S]*?.<\/v:shape>/gi,
function(str) {
//opera能自己解析出image所这里直接返回空
if ( !! window.opera && window.opera.version) {
return '';
}
try {
//有可能是bitmap占为图,无用,直接过滤掉,主要体现在粘贴excel表格中
if (/Bitmap/i.test(str)) {
return '';
}
var src = str.match(/src=\s*"([^"]*)"/i)[1];
return '<img src="' + src + '" />';
} catch(e) {
return '';
}
})
//针对wps添加的多余标签处理
.replace(/<\/?div[^>]*>/g, '')
.replace(/<\/?span[^>]*>/g, '')
.replace(/<\/?font[^>]*>/g, '')
.replace(/<\/?col[^>]*>/g, '')
.replace(/<\/?(span|div|o:p|v:.*?|input|label)[\s\S]*?>/g, '')
//去掉所有属性,需要保留单元格合并
//.replace(/<([a-zA-Z]+)\s*[^><]*>/g, "<$1>")
//去掉多余的属性
.replace(/v:\w+=(["']?)[^'"]+\1/g, '')
.replace(/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi, "").replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>")
//去掉多余的属性
.replace(/\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/gi, '')
//清除多余的font/span不能匹配 有可能是空格
.replace(/<(font|span)[^>]*>(\s*)<\/\1>/gi,
function(a, b, c) {
return c.replace(/[\t\r\n ]+/g, " ");
})
//去掉style属性
.replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, "$1")
// 去除不带引号的属性
.replace(/(class|border|cellspacing|MsoNormalTable|valign|width|center| |x:str|height|x:num|cellpadding)(=[^ \f\n\r\t\v>]*)?/g, "")
// 去除多余空格
.replace(/(\S+)(\s+)/g, function(match, p1, p2) {
return p1 + ' ';
})
.replace(/(\s)(>|<)/g, function(match, p1, p2) {
return p2;
})
//处理表格中的p标签
.replace(/(<table[^>]*[\s\S]*?><\/table>)/gi,function(a){
if (a.match(/(<table>)/gi).length>1){ return a} else {
return a.replace(/<\/p><p>/g, "<br/>")
.replace(/<\/?p[^>]*>/g, '')
.replace(/<td> <\/td>/g, "<td></td>")
}});
}
</script>
提供一个思路: 一、从office 文档粘贴为markdown的功能主要使用turndown.js和turndown-plugin-gfm.js,粘贴时判断是否从office 粘贴,如果是,去掉head和注释,去掉隐藏元素,然后转换。 存在问题:图片显示的是本地地址。另外不能拦截到editor的默认粘贴事件,导致粘贴时,总是重复。
二、导入word文档直接转换为markdown的功能主要使用mammoth.browser.js,因为该插件转换为markdown 的支持不好,先转换为html,再使用使用turndown.js和turndown-plugin-gfm.js,转换为markdown。使用该插件,对于 包含
<w:vanish />
的元素应跳过不解析。使用mammoth.browser.js转换的word,里面包含图片的,自动转换为base64编码,如果后端有服务器的,将base64上传至服务器,返回路径。