feat: 编辑器新增WordToHtml (#967)

* feat: word转笔记(富文本html)
* fix: 本地化文件更新
pull/968/head
zhanzhenping 2024-07-12 09:52:20 +08:00 committed by GitHub
parent ab314fbf18
commit d8064f168a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 32534 additions and 1 deletions

View File

@ -321,6 +321,7 @@ private_blog_tips = Private blog, please enter password to access
print_text = Enable Printing print_text = Enable Printing
[doc] [doc]
word_to_html = Word to HTML
modify_doc = Modify Document modify_doc = Modify Document
comparison = Comparison comparison = Comparison
save_merge = Save Merge save_merge = Save Merge

View File

@ -321,6 +321,7 @@ private_blog_tips = 加密文章,请输入密码访问
print_text = 开启打印 print_text = 开启打印
[doc] [doc]
word_to_html = Word转笔记
modify_doc = 修改文档 modify_doc = 修改文档
comparison = 文档比较 comparison = 文档比较
save_merge = 保存合并 save_merge = 保存合并

View File

@ -2670,7 +2670,7 @@ div[data-type=codeBlock] .token.inserted {
.cherry-dropdown { .cherry-dropdown {
position: absolute; position: absolute;
width: 130px; width: 140px;
min-height: 40px; min-height: 40px;
background: #fff; background: #fff;
box-shadow: 0 5px 15px -5px rgba(0, 0, 0, 0.5); box-shadow: 0 5px 15px -5px rgba(0, 0, 0, 0.5);

View File

@ -131,6 +131,30 @@ $(function () {
onClick: showHistory, onClick: showHistory,
}); });
let customMenuTools = Cherry.createMenuHook('', {
iconName: '',
subMenuConfig: [
{
iconName: 'word',
name: 'Word',
onclick: ()=>{
let converter = new WordToHtmlConverter();
converter.handleFileSelect(function (response) {
if (response.messages.length) {
let messages = response.messages.map((item)=>{
return item.message + "<br/>";
}).join('\n');
layer.msg(messages);
}
converter.replaceHtmlBase64(response.value).then((html)=>{
window.editor.insertValue(html);
});
})
}
},
]
});
var basicConfig = { var basicConfig = {
id: 'manualEditorContainer', id: 'manualEditorContainer',
@ -226,6 +250,7 @@ $(function () {
'switchModel', 'switchModel',
'export', 'export',
'customMenuFName', 'customMenuFName',
'customMenuToolsName'
], ],
bubble: ['bold', 'italic', 'underline', 'strikethrough', 'sub', 'sup', 'quote', 'ruby', '|', 'size', 'color'], // array or false bubble: ['bold', 'italic', 'underline', 'strikethrough', 'sub', 'sup', 'quote', 'ruby', '|', 'size', 'color'], // array or false
sidebar: ['mobilePreview', 'copy', 'codeTheme', 'theme'], sidebar: ['mobilePreview', 'copy', 'codeTheme', 'theme'],
@ -236,6 +261,7 @@ $(function () {
customMenuDName: customMenuD, customMenuDName: customMenuD,
customMenuEName: customMenuE, customMenuEName: customMenuE,
customMenuFName: customMenuF, customMenuFName: customMenuF,
customMenuToolsName: customMenuTools,
}, },
}, },
drawioIframeUrl: '/static/cherry/drawio_demo.html', drawioIframeUrl: '/static/cherry/drawio_demo.html',

View File

@ -436,6 +436,19 @@ $(function () {
drawio.processMarkers(selStartLine, selEndLine) drawio.processMarkers(selStartLine, selEndLine)
drawio.show() drawio.show()
} else if (name === 'wordToContent') {
let converter = new WordToHtmlConverter();
converter.handleFileSelect(function (response) {
if (response.messages.length) {
let messages = response.messages.map((item)=>{
return item.message + "<br/>";
}).join('\n');
layer.msg(messages);
}
converter.replaceHtmlBase64(response.value).then((html)=>{
insertAndClearToMarkdown(html);
});
})
} else { } else {
var action = window.editor.toolbarHandlers[name]; var action = window.editor.toolbarHandlers[name];

View File

@ -0,0 +1,100 @@
class WordToHtmlConverter {
handleFileSelect(callback, accept = '.doc,.docx') {
let input = document.createElement('input');
input.type = 'file';
input.accept = accept;
input.onchange = (e)=>{
let file = e.target.files[0];
if (!file) {
return;
}
let reader = new FileReader();
reader.onload = (e)=>{
let arrayBuffer = e.target.result;
this.convertToHtml(arrayBuffer, (html)=>{
callback(html);
});
};
reader.readAsArrayBuffer(file);
};
input.click();
}
convertToHtml(arrayBuffer, callback) {
try {
mammoth.convertToHtml({arrayBuffer: arrayBuffer}).then(callback, function(error) {
layer.msg('Error: ' + error);
return
});
} catch (error) {
layer.msg('Error: ' + error);
return
}
}
replaceHtmlBase64(html) {
let regex = /<img\s+src="data:image\/[^;]*;base64,([^"]*)"/g;
let matches = [];
let match;
while ((match = regex.exec(html)) !== null) {
matches.push(match[1]);
}
if (matches.length === 0) {
return new Promise((resolve, reject) => {
resolve(html);
});
}
// 将base64转为blob
let promises = matches.map((base64)=>{
return new Promise((resolve, reject)=>{
let blob = this.base64ToBlob(base64);
let reader = new FileReader();
reader.onload = (e)=>{
resolve({base64, blob, url: e.target.result});
};
reader.readAsDataURL(blob);
});
});
return Promise.all(promises).then((results)=>{
let htmlCopy = html;
return Promise.all(results.map((result) => {
return this.uploadFile(result.blob).then((data) => {
htmlCopy = htmlCopy.replace(`data:image/png;base64,${result.base64}`, data.url);
});
})).then(() => {
return htmlCopy;
});
});
}
uploadFile(blob) {
let file = new File([blob], 'image.jpg', { type: 'image/jpeg' });
let formData = new FormData();
formData.append('editormd-file-file', file);
return fetch(window.fileUploadURL, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {return data})
.catch(error => {return error});
}
base64ToBlob(base64, type) {
let binary = atob(base64);
let array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: type});
}
}

File diff suppressed because it is too large Load Diff

View File

@ -388,6 +388,8 @@
<script src="{{cdnjs "/static/cherry/cherry-markdown.js" "version"}}" type="text/javascript"></script> <script src="{{cdnjs "/static/cherry/cherry-markdown.js" "version"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/js/custom-elements-builtin-0.6.5.min.js"}}" type="text/javascript"></script> <script src="{{cdnjs "/static/js/custom-elements-builtin-0.6.5.min.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/js/x-frame-bypass-1.0.2.js"}}" type="text/javascript"></script> <script src="{{cdnjs "/static/js/x-frame-bypass-1.0.2.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/mammoth/mammoth.browser.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/js/word-to-html.js"}}" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
$(function () { $(function () {

View File

@ -98,6 +98,8 @@
<a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.draw"}}"><i class="fa fa-paint-brush item" aria-hidden="true" name="drawio"></i></a> <a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.draw"}}"><i class="fa fa-paint-brush item" aria-hidden="true" name="drawio"></i></a>
<a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.template"}}"><i class="fa fa-tachometer last" name="template"></i></a> <a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.template"}}"><i class="fa fa-tachometer last" name="template"></i></a>
<a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.word_to_html"}}"><i class="fa fa-file-word-o last" name="wordToContent"></i></a>
</div> </div>
<div class="editormd-group pull-right"> <div class="editormd-group pull-right">
@ -456,6 +458,8 @@
<script src="{{cdnjs "/static/js/markdown.js" "version"}}" type="text/javascript"></script> <script src="{{cdnjs "/static/js/markdown.js" "version"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/js/custom-elements-builtin-0.6.5.min.js"}}" type="text/javascript"></script> <script src="{{cdnjs "/static/js/custom-elements-builtin-0.6.5.min.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/js/x-frame-bypass-1.0.2.js"}}" type="text/javascript"></script> <script src="{{cdnjs "/static/js/x-frame-bypass-1.0.2.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/mammoth/mammoth.browser.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/js/word-to-html.js"}}" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
$(function () { $(function () {
editLangPath = {{cdnjs "/static/editor.md/languages/"}} + lang editLangPath = {{cdnjs "/static/editor.md/languages/"}} + lang