mirror of
https://github.com/leanote/desktop-app.git
synced 2025-10-14 23:22:40 +00:00
import html
This commit is contained in:
100
node_modules/file.js
generated
vendored
100
node_modules/file.js
generated
vendored
@@ -75,80 +75,44 @@ var File = {
|
||||
callback && callback(attach);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
// var buf = new Buffer(data, 'utf-8');
|
||||
// 读出来
|
||||
var err = fs.writeFile(filePath, data, 'ascii');
|
||||
if(err) {
|
||||
console.log(err);
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
var exec = require('child_process').exec,
|
||||
last = exec('"/Users/life/Documents/kuaipan/go/go-study/bin/file2" "' + txtPath + '" "' + filePath + '"');
|
||||
// last = exec('ls /');
|
||||
// last.stdout.on('data', function (data) {
|
||||
// console.log('标准输出:' + data);
|
||||
// });
|
||||
last.on('exit', function (code) {
|
||||
console.log('子进程已关闭,代码:' + code);
|
||||
fs.unlink(txtPath);
|
||||
if(!code) {
|
||||
if(isImage) {
|
||||
me._addImage(Common.objectId(), filePath, function(newImg) {
|
||||
newImg.IsImage = true;
|
||||
callback && callback(newImg);
|
||||
});
|
||||
} else {
|
||||
me._addAttach(filePath, fileTitle, callback)
|
||||
}
|
||||
} else {
|
||||
callback(false);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
/*
|
||||
// console.log(txtPath);
|
||||
// console.log(filePath);
|
||||
// 先写到txt中去, 然后调用命令将.txt -> img
|
||||
var txtPath = filePath + '.txt';
|
||||
var err = fs.writeFileSync(txtPath, data);
|
||||
Common.cmd([txtPath, filePath], function(code) {
|
||||
// console.log('子进程已关闭,代码:' + code);
|
||||
// fs.unlink(txtPath);
|
||||
if(!code) {
|
||||
try {
|
||||
if(isImage) {
|
||||
me._addImage(Common.objectId(), filePath, function(newImg) {
|
||||
newImg.IsImage = true;
|
||||
callback && callback(newImg);
|
||||
});
|
||||
} else {
|
||||
me._addAttach(filePath, fileTitle, callback)
|
||||
}
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
callback(false);
|
||||
}
|
||||
} else {
|
||||
callback(false);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
// return callback && callback({FileId: Common.objectId(), IsImage: true});
|
||||
|
||||
} catch(e) {
|
||||
console.log("error!!!");
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
|
||||
copyFile: function(originPath, isImage, callback) {
|
||||
var me = this;
|
||||
var basePath;
|
||||
if(isImage) {
|
||||
basePath = User.getCurUserImagesPath();
|
||||
} else {
|
||||
basePath = User.getCurUserAttachsPath();
|
||||
}
|
||||
|
||||
var filePathAttr = Common.splitFile(originPath);
|
||||
var fileId = Common.objectId();
|
||||
var newFilename = fileId + '_html_' + '.' + filePathAttr.ext;
|
||||
var newFilePath = basePath + '/' + newFilename;
|
||||
|
||||
Common.copyFile(originPath, newFilePath, function(ret) {
|
||||
if(ret) {
|
||||
if(isImage) {
|
||||
me._addImage(fileId, newFilePath, function(newImg) {
|
||||
newImg.IsImage = true;
|
||||
callback(newImg);
|
||||
});
|
||||
} else {
|
||||
me._addAttach(newFilePath, '', function(attach) {
|
||||
callback(attach);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
callback(false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getFileBase64: function(filePath) {
|
||||
try {
|
||||
// read binary data
|
||||
|
@@ -4,6 +4,7 @@ var Config = {
|
||||
"template",
|
||||
"import_leanote",
|
||||
"import_evernote",
|
||||
"import_html",
|
||||
"export_pdf",
|
||||
"export_html",
|
||||
"export_leanote",
|
||||
|
185
public/plugins/import_html/import.js
Executable file
185
public/plugins/import_html/import.js
Executable file
@@ -0,0 +1,185 @@
|
||||
var fs = require('fs');
|
||||
var Evt = require('evt');
|
||||
var File = require('file');
|
||||
var Note = require('note');
|
||||
var Web = require('web');
|
||||
var Tag = require('tag');
|
||||
var async = require('async');
|
||||
var Common = require('common');
|
||||
var path = require('path');
|
||||
var resanitize = require('resanitize');
|
||||
|
||||
var Import = {
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
// callback 是全局的
|
||||
// eachFileCallback是每一个文件的
|
||||
// eachNoteFileCallback是每一个笔记的
|
||||
// filePaths = []
|
||||
importFromHTML: function(notebookId, filePaths, callback,
|
||||
eachFileCallback,
|
||||
eachNoteCallback) {
|
||||
var me = this;
|
||||
// var filePaths = filePaths.split(';');
|
||||
//
|
||||
var filePaths = filePaths || [];
|
||||
|
||||
async.eachSeries(filePaths, function(path, cb) {
|
||||
|
||||
try {
|
||||
var data = fs.readFileSync(path, 'utf-8');
|
||||
me.parseHTML(notebookId, data, path, function(ret) {
|
||||
// 单个文件完成
|
||||
eachFileCallback(ret, path);
|
||||
cb();
|
||||
},
|
||||
// 单个笔记
|
||||
function(ret) {
|
||||
eachNoteCallback(ret);
|
||||
});
|
||||
} catch(e) {
|
||||
cb();
|
||||
return false;
|
||||
}
|
||||
}, function() {
|
||||
// 全部完成
|
||||
callback(true);
|
||||
});
|
||||
},
|
||||
|
||||
fixContent: function (content) {
|
||||
// srip unsage attrs
|
||||
var unsafeAttrs = ['id', , /on\w+/i, /data-\w+/i, 'clear', 'target'];
|
||||
content = content.replace(/<([^ >]+?) [^>]*?>/g, resanitize.filterTag(resanitize.stripAttrs(unsafeAttrs)));
|
||||
|
||||
// strip unsafe tags
|
||||
content = resanitize.stripUnsafeTags(content,
|
||||
['wbr','style', 'comment', 'plaintext', 'xmp', 'listing',
|
||||
'applet','base','basefont','bgsound','blink','body','button','dir','embed','fieldset','frameset','head',
|
||||
'html','iframe','ilayer','input','isindex','layer','legend','link','marquee','menu','meta','noframes',
|
||||
'noscript','object','optgroup','option','param','plaintext','script','select','textarea','xml']
|
||||
);
|
||||
return content;
|
||||
},
|
||||
|
||||
getTitle: function (htmlData, filename) {
|
||||
// 1. 在<title></title> header中找
|
||||
try {
|
||||
var title = htmlData.match(/<title[^>]*>([\s\S]*?)<\/title>/i)[1];
|
||||
if (title && title.replace(/(^\s*)|(\s*$)/g, "")) {
|
||||
return title;
|
||||
}
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
// 2. 通过文件名获取
|
||||
var pathInfo = Api.commonService.splitFile(filename);
|
||||
return pathInfo.nameNotExt;
|
||||
},
|
||||
|
||||
parseHTML: function (notebookId, htmlData, filename, callback, eachCallback) {
|
||||
var me = this;
|
||||
try {
|
||||
var body = htmlData.match(/<body[^>]*>([\s\S]*?)<\/body>/i)[1];
|
||||
if (!body) {
|
||||
console.log('没有body');
|
||||
return callback(false);
|
||||
}
|
||||
var title = this.getTitle(htmlData, filename) || getMsg('Untitled');
|
||||
|
||||
// 解析里面的图片
|
||||
var reg = /<img[^>]*?( src=(?:["'])([^>]+?)(?:["']))[^>]*?>/gi;
|
||||
var ret;
|
||||
var imagePaths = [];
|
||||
while(ret = reg.exec(body)) {
|
||||
console.log(ret);
|
||||
/*
|
||||
"<img id="wiz_todo_1429010269089_521433" class="wiz-todo-img wiz-img-cannot-drag" state="unchecked" _src="wiz测试笔记_files/unchecked.png" src="wiz测试笔记_files/unchecked.png" />"
|
||||
" src="wiz测试笔记_files/unchecked.png""
|
||||
"wiz测试笔记_files/unchecked.png"
|
||||
*/
|
||||
var imagePath = ret[2];
|
||||
var imagePathLower = imagePath.toLowerCase();
|
||||
// 是http图片,skip
|
||||
if (imagePathLower.indexOf('http://') < 0 && imagePathLower.indexOf('https://') < 0) {
|
||||
imagePaths.push(imagePath);
|
||||
}
|
||||
}
|
||||
var dirname = path.dirname(filename);
|
||||
var imagePath2ImageInfo = {}; // imagePath => imageInfo
|
||||
async.eachSeries(imagePaths, function(imagePath, cb) {
|
||||
|
||||
// 重复图片
|
||||
if (imagePath2ImageInfo[imagePath]) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
var absImagePath;
|
||||
// 绝对路径
|
||||
if (imagePath.indexOf('file://') == 0) {
|
||||
absImagePath = imagePath.substr('file://'.length);
|
||||
} else {
|
||||
absImagePath = path.join(dirname, imagePath);
|
||||
}
|
||||
if (fs.existsSync(absImagePath)) {
|
||||
File.copyFile(absImagePath, true, function (imageInfo) {
|
||||
if (imageInfo) {
|
||||
imagePath2ImageInfo[imagePath] = imageInfo;
|
||||
}
|
||||
cb();
|
||||
});
|
||||
} else {
|
||||
return cb();
|
||||
}
|
||||
}, function () {
|
||||
// 替换图片
|
||||
console.log(imagePath2ImageInfo);
|
||||
while(ret = reg.exec(body)) {
|
||||
// console.log('=====');
|
||||
// console.log(ret);
|
||||
var imagePath = ret[2];
|
||||
var imageInfo = imagePath2ImageInfo[imagePath];
|
||||
if (imageInfo) {
|
||||
// console.log('有的');
|
||||
var imageLink = ' src="leanote://file/getImage?fileId=' + imageInfo.FileId + '"';
|
||||
body = body.replace( ret[0], ret[0].replace(ret[1], imageLink) );
|
||||
}
|
||||
}
|
||||
|
||||
// console.log(body);
|
||||
|
||||
// OK了
|
||||
// 添加到数据库中
|
||||
var jsonNote = {
|
||||
Title: title,
|
||||
Content: me.fixContent(body),
|
||||
Tags: [],
|
||||
CreatedTime: new Date(),
|
||||
UpdatedTime: new Date(),
|
||||
|
||||
IsMarkdown: false,
|
||||
Attachs: null,
|
||||
|
||||
NotebookId: notebookId,
|
||||
Desc: '',
|
||||
NoteId: Common.objectId(),
|
||||
IsNew: true
|
||||
};
|
||||
jsonNote._id = jsonNote.NoteId;
|
||||
Note.updateNoteOrContent(jsonNote, function(insertedNote) {
|
||||
eachCallback && eachCallback(insertedNote);
|
||||
callback(true);
|
||||
});
|
||||
});
|
||||
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
callback(false);
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = Import;
|
225
public/plugins/import_html/plugin.js
Normal file
225
public/plugins/import_html/plugin.js
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* 导入html, 重构
|
||||
* @author life@leanote.com
|
||||
* @date 2015/04/09
|
||||
*/
|
||||
define(function() {
|
||||
var importService; // = nodeRequire('./public/plugins/import_html/import');
|
||||
|
||||
var html = {
|
||||
|
||||
langs: {
|
||||
'en-us': {
|
||||
'importHTML': 'Import HTML',
|
||||
},
|
||||
'de-de': {
|
||||
'importHTML': 'HTML Datei importieren',
|
||||
'Choose HTML files(.html)': 'HTML Dateien (.html) auswählen',
|
||||
'Close': "Schliessen",
|
||||
'Import to': "Importiere in Notizbuch",
|
||||
"Done! %s notes imported!": "Abgeschlossen! Es wurden %s Notizen importiert!",
|
||||
"Import file: %s Success!": "Datei importieren: %s erfolgreich!",
|
||||
"Import file: %s Failure, is html file ?": "Datei importieren: %s fehlgeschlagen! Ist das eine HTML Datei?",
|
||||
"Import: %s Success!": "Import: %s erfolgreich!"
|
||||
},
|
||||
'zh-cn': {
|
||||
'importHTML': '导入HTML/为知笔记',
|
||||
'Choose HTML files(.html)': '选择HTML文件(.html)',
|
||||
'Close': "关闭",
|
||||
'Import to': "导入至",
|
||||
"Done! %s notes imported!": "完成, 成功导入 %s 个笔记!",
|
||||
"Import file: %s Success!": "文件 %s 导入成功!",
|
||||
"Import file: %s Failure, is html file ?": "文件 %s 导入失败! 是HTML文件?",
|
||||
"Import: %s Success!": "导入笔记: %s 成功!"
|
||||
},
|
||||
'zh-hk': {
|
||||
'importHTML': '導入HTML',
|
||||
'Choose HTML files(.html)': '選擇HTML文件(.html)',
|
||||
'Close': "關閉",
|
||||
"Import to": "導入至",
|
||||
"Done! %s notes imported!": "完成, 成功導入 %s 個筆記!",
|
||||
"Import file: %s Success!": "文件 %s 導入成功!",
|
||||
"Import file: %s Failure, is html file ?": "文件 %s 導入失敗! 是HTML文件?",
|
||||
"Import: %s Success!": "導入筆記: %s 成功!"
|
||||
}
|
||||
},
|
||||
|
||||
_tpl: `
|
||||
<style>
|
||||
#importHTMLDialog .tab-pane {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
#importHTMLDialog .alert {
|
||||
margin-top: 10px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
<div class="modal fade bs-modal-sm" id="importHTMLDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle"><span class="lang">Import to</span> <span id="importDialogNotebook"></span></h4>
|
||||
</div>
|
||||
<div class="modal-body" id="">
|
||||
<div role="tabpanel">
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active" id="htmlTab">
|
||||
<!-- import -->
|
||||
<a id="chooseHTMLFile" class="btn btn-success btn-choose-file">
|
||||
<i class="fa fa-upload"></i>
|
||||
<span class="lang">Choose HTML files(.html)</span>
|
||||
</a>
|
||||
<!-- 消息 -->
|
||||
<div id="importHTMLMsg" class="alert alert-info">
|
||||
<div class="curImportFile"></div>
|
||||
<div class="curImportNote"></div>
|
||||
<div class="allImport"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="youdaoTab">
|
||||
<!-- 文件选择框 -->
|
||||
<input id="importHTMLInput" type="file" nwsaveas="" accept=".html" multiple style="" style="display: none"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer ">
|
||||
<button type="button" class="btn btn-default upgrade-cancel-btn lang" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
`,
|
||||
_importDialog: null,
|
||||
_curNotebook: null,
|
||||
_inited: false,
|
||||
|
||||
getMsg: function(txt, data) {
|
||||
return Api.getMsg(txt, 'plugin.import_html', data)
|
||||
},
|
||||
|
||||
init: function() {
|
||||
var me = this;
|
||||
me._inited = true;
|
||||
$('body').append(me._tpl);
|
||||
me._importDialog = $("#importHTMLDialog");
|
||||
|
||||
me._importDialog.find('.lang').each(function() {
|
||||
var txt = $.trim($(this).text());
|
||||
$(this).text(me.getMsg(txt));
|
||||
});
|
||||
|
||||
// 导入, 选择文件
|
||||
$('#chooseHTMLFile').click(function() {
|
||||
|
||||
Api.gui.dialog.showOpenDialog(Api.gui.getCurrentWindow(),
|
||||
{
|
||||
properties: ['openFile', 'multiSelections'],
|
||||
filters: [
|
||||
{ name: 'HTML', extensions: ['html'] }
|
||||
]
|
||||
},
|
||||
function(paths) {
|
||||
if(!paths) {
|
||||
return;
|
||||
}
|
||||
|
||||
var notebookId = me._curNotebook.NotebookId;
|
||||
|
||||
var n = 0;
|
||||
|
||||
me.clear();
|
||||
if (!importService) {
|
||||
importService = nodeRequire('./public/plugins/import_html/import');
|
||||
}
|
||||
|
||||
importService.importFromHTML(notebookId, paths,
|
||||
// 全局
|
||||
function(ok) {
|
||||
// $('#importHTMLMsg .curImportFile').html("");
|
||||
// $('#importHTMLMsg .curImportNote').html("");
|
||||
setTimeout(function() {
|
||||
$('#importHTMLMsg .allImport').html(me.getMsg('Done! %s notes imported!', n));
|
||||
}, 500);
|
||||
},
|
||||
// 单个文件
|
||||
function(ok, filename) {
|
||||
if(ok) {
|
||||
$('#importHTMLMsg .curImportFile').html(me.getMsg("Import file: %s Success!", filename));
|
||||
} else {
|
||||
$('#importHTMLMsg .curImportFile').html(me.getMsg("Import file: %s Failure, is html file ?", filename));
|
||||
}
|
||||
},
|
||||
// 单个笔记
|
||||
function(note) {
|
||||
if(note) {
|
||||
n++;
|
||||
$('#importHTMLMsg .curImportNote').html(me.getMsg("Import: %s Success!", note.Title));
|
||||
|
||||
// 不要是新的, 不然切换笔记时又会保存一次
|
||||
note.IsNew = false;
|
||||
// 插入到当前笔记中
|
||||
Note.addSync([note]);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
$('#importHTMLMsg .curImportFile').html("");
|
||||
$('#importHTMLMsg .curImportNote').html("");
|
||||
$('#importHTMLMsg .allImport').html('');
|
||||
},
|
||||
|
||||
open: function(notebook) {
|
||||
var me = this;
|
||||
if(!notebook) {
|
||||
return;
|
||||
}
|
||||
if(!me._inited) {
|
||||
me.init();
|
||||
}
|
||||
me.clear();
|
||||
|
||||
$('#importDialogNotebook').html(notebook.Title);
|
||||
|
||||
me._curNotebook = notebook;
|
||||
var notebookId = notebook.NotebookId;
|
||||
me._importDialog.modal('show');
|
||||
},
|
||||
|
||||
// 打开前要执行的
|
||||
onOpen: function() {
|
||||
var me = this;
|
||||
var gui = Api.gui;
|
||||
|
||||
Api.addImportMenu({
|
||||
label: Api.getMsg('plugin.import_html.importHTML'),
|
||||
click: (function() {
|
||||
return function(notebook) {
|
||||
me.open(notebook);
|
||||
};
|
||||
})()
|
||||
});
|
||||
},
|
||||
// 打开后
|
||||
onOpenAfter: function() {
|
||||
},
|
||||
// 关闭时需要运行的
|
||||
onClose: function() {
|
||||
}
|
||||
};
|
||||
|
||||
return html;
|
||||
});
|
Reference in New Issue
Block a user