mirror of
https://github.com/leanote/desktop-app.git
synced 2025-10-19 18:14:15 +00:00
import leanote ok
This commit is contained in:
@@ -16,11 +16,10 @@
|
|||||||
author: 'leanote', // 作者, 没用
|
author: 'leanote', // 作者, 没用
|
||||||
createdTime: '2015-10-12 12:00:00',
|
createdTime: '2015-10-12 12:00:00',
|
||||||
updatedTime: '2015-10-12 12:00:00',
|
updatedTime: '2015-10-12 12:00:00',
|
||||||
files: {
|
files: [
|
||||||
// fileId =>
|
{fileId: '', base64: '', md5: '', type: 'png', 'isAttach': false, createdTime: '2031-12-31 12:12:32'}
|
||||||
'32323': {base64: '', md5: '', type: 'png', 'isAttach': false, createdTime: '2031-12-31 12:12:32'}
|
{fileId: '', base64: '', md5: '', type: 'png', 'isAttach': false, createdTime: '2031-12-31 12:12:32'}
|
||||||
'32323': {base64: '', md5: '', type: 'png', 'isAttach': false, createdTime: '2031-12-31 12:12:32'}
|
]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -110,6 +109,16 @@ define(function() {
|
|||||||
}
|
}
|
||||||
me.fixFiles(note, function (content, files) {
|
me.fixFiles(note, function (content, files) {
|
||||||
content = $('<div>' + content + '</div>').html();
|
content = $('<div>' + content + '</div>').html();
|
||||||
|
|
||||||
|
var filesArr = [];
|
||||||
|
files || (files = {});
|
||||||
|
for (var fileId in files) {
|
||||||
|
if (files.hasOwnProperty(fileId)) {
|
||||||
|
files[fileId].fileId = fileId;
|
||||||
|
filesArr.push(files[fileId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var noteInfo = {
|
var noteInfo = {
|
||||||
title: note.Title,
|
title: note.Title,
|
||||||
content: content,
|
content: content,
|
||||||
@@ -118,7 +127,7 @@ define(function() {
|
|||||||
isMarkdown: note.IsMarkdown,
|
isMarkdown: note.IsMarkdown,
|
||||||
createdTime: me.getLeanoteTime(note.CreatedTime),
|
createdTime: me.getLeanoteTime(note.CreatedTime),
|
||||||
updatedTime: me.getLeanoteTime(note.UpdatedTime),
|
updatedTime: me.getLeanoteTime(note.UpdatedTime),
|
||||||
files: files || []
|
files: filesArr
|
||||||
};
|
};
|
||||||
info.notes.push(noteInfo);
|
info.notes.push(noteInfo);
|
||||||
callback(JSON.stringify(info, null, 2));
|
callback(JSON.stringify(info, null, 2));
|
||||||
|
239
public/plugins/import_leanote/import.js
Executable file
239
public/plugins/import_leanote/import.js
Executable file
@@ -0,0 +1,239 @@
|
|||||||
|
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 Import = {
|
||||||
|
// 解析Leanote
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
exportDate: '2015-10-12 12:00:00',
|
||||||
|
app: 'leanote.desktop.app.mac',
|
||||||
|
appVersion: '1.0',
|
||||||
|
notes: [
|
||||||
|
{
|
||||||
|
title: 'life',
|
||||||
|
content: 'laldfadf', // 图片, 附件链接为 leanote://api/file/getImage?fileId=xxxx, leanote://api/file/getAttach?fileId=3232323
|
||||||
|
tags: [1,2,3],
|
||||||
|
isMarkdown: true,
|
||||||
|
author: 'leanote', // 作者, 没用
|
||||||
|
createdTime: '2015-10-12 12:00:00',
|
||||||
|
updatedTime: '2015-10-12 12:00:00',
|
||||||
|
files: [
|
||||||
|
{fileId: '', base64: '', md5: '', type: 'png', 'isAttach': false, createdTime: '2031-12-31 12:12:32'}
|
||||||
|
{fileId: '', base64: '', md5: '', type: 'png', 'isAttach': false, createdTime: '2031-12-31 12:12:32'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// callback 是全局的
|
||||||
|
// eachFileCallback是每一个文件的
|
||||||
|
// eachNoteFileCallback是每一个笔记的
|
||||||
|
// filePaths = []
|
||||||
|
importFromLeanote: function(notebookId, filePaths, callback,
|
||||||
|
eachFileCallback,
|
||||||
|
eachNoteCallback) {
|
||||||
|
var me = this;
|
||||||
|
// var filePaths = filePaths.split(';');
|
||||||
|
//
|
||||||
|
var filePaths = filePaths || [];
|
||||||
|
|
||||||
|
async.eachSeries(filePaths, function(path, cb) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
var json = JSON.parse(fs.readFileSync(path));
|
||||||
|
me.parseLeanote(notebookId, json, function(ret) {
|
||||||
|
// 单个文件完成
|
||||||
|
eachFileCallback(ret, path)
|
||||||
|
cb();
|
||||||
|
},
|
||||||
|
// 单个笔记
|
||||||
|
function(ret) {
|
||||||
|
eachNoteCallback(ret);
|
||||||
|
});
|
||||||
|
} catch(e) {
|
||||||
|
cb();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, function() {
|
||||||
|
// 全部完成
|
||||||
|
callback(true);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 2015-12-12 12:00:00
|
||||||
|
parseLeanoteTime: function (str) {
|
||||||
|
if (!str || typeof str != 'string' || str.length != '2015-12-12 12:00:00'.length) {
|
||||||
|
return new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
var d = new Date(str);
|
||||||
|
// invalid
|
||||||
|
if (isNaN(d.getTime())) {
|
||||||
|
return new Date();
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理内容中的链接
|
||||||
|
fixContentLink: function (note, filesFixed) {
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
var content = note.content;
|
||||||
|
var allMatchs = [];
|
||||||
|
// 图片处理后, 可以替换内容中的链接了
|
||||||
|
// leanote://api/file/getImage?fileId=xxxx,
|
||||||
|
var reg = new RegExp('<img([^>]*?)src=["\']?leanote://api/file/getImage\\?fileId=([0-9a-zA-Z]{24})["\']?(.*?)>', 'g');
|
||||||
|
var matches = reg.exec(content);
|
||||||
|
while(matches) {
|
||||||
|
var all = matches[0];
|
||||||
|
var pre = matches[1]; // img与src之间
|
||||||
|
var fileId = matches[2];
|
||||||
|
var back = matches[3]; // src与>之间
|
||||||
|
allMatchs.push({
|
||||||
|
fileId: fileId,
|
||||||
|
pre: pre,
|
||||||
|
back: back,
|
||||||
|
all: all
|
||||||
|
});
|
||||||
|
// 下一个
|
||||||
|
matches = reg.exec(content);
|
||||||
|
}
|
||||||
|
// 处理附件
|
||||||
|
var reg = new RegExp('<a([^>]*?)href=["\']?leanote://api/file/getAttach\\?fileId=([0-9a-zA-Z]{24})["\']?(.*?)>([^<]*)</a>', 'g');
|
||||||
|
var matches = reg.exec(content);
|
||||||
|
// 先找到所有的
|
||||||
|
while(matches) {
|
||||||
|
var all = matches[0];
|
||||||
|
var pre = matches[1]; // a 与href之间
|
||||||
|
var fileId = matches[2];
|
||||||
|
var back = matches[3] // href与>之间
|
||||||
|
var title = matches[4];
|
||||||
|
|
||||||
|
allMatchs.push({
|
||||||
|
fileId: fileId,
|
||||||
|
title: title,
|
||||||
|
pre: pre,
|
||||||
|
back: back,
|
||||||
|
isAttach: true,
|
||||||
|
all: all
|
||||||
|
});
|
||||||
|
// 下一个
|
||||||
|
matches = reg.exec(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 替换内容
|
||||||
|
for (var i = 0; i < allMatchs.length; ++i) {
|
||||||
|
var eachMatch = allMatchs[i];
|
||||||
|
var fileInfo = filesFixed[eachMatch.fileId];
|
||||||
|
|
||||||
|
var link;
|
||||||
|
if (!fileInfo) {
|
||||||
|
link = '';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!eachMatch.isAttach) {
|
||||||
|
// 用新的FileId
|
||||||
|
var href = Api.evtService.localUrl + '/api/file/getImage?fileId=' + fileInfo.FileId;
|
||||||
|
link = '<img ' + eachMatch.pre + 'src="' + href + '"' + eachMatch.back + '>';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var href = Api.evtService.localUrl + '/api/file/getAttach?fileId=' + fileInfo.FileId;
|
||||||
|
link = '<a ' + eachMatch.pre + 'href="' + href + '"' + eachMatch.back + '>' + eachMatch.title + '</a>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content = content.replace(eachMatch.all, link);
|
||||||
|
}
|
||||||
|
note.content = content;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 解析笔记
|
||||||
|
parseNote: function (notebookId, note, callback) {
|
||||||
|
var me = this;
|
||||||
|
// 先把files保存到本地
|
||||||
|
var files = note.files || [];
|
||||||
|
if (Common.isEmpty(files)) {
|
||||||
|
files = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var filesFixed = {}; // fileId(旧) => {fileId: (新fileId)}
|
||||||
|
var attachs = [];
|
||||||
|
async.eachSeries(files,
|
||||||
|
function(file, cb) {
|
||||||
|
var isAttach = file.isAttach;
|
||||||
|
File.writeBase64(file.base64, !isAttach, file.type, file.title, function(fileOk) {
|
||||||
|
if(fileOk) {
|
||||||
|
filesFixed[file.fileId] = fileOk;
|
||||||
|
if(isAttach) {
|
||||||
|
attachs.push(fileOk);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('文件保存错误!');
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}, function () {
|
||||||
|
|
||||||
|
me.fixContentLink(note, filesFixed);
|
||||||
|
|
||||||
|
// 添加到数据库中
|
||||||
|
var jsonNote = {
|
||||||
|
Title: note.title,
|
||||||
|
Content: note.content,
|
||||||
|
Tags: note.tags || [],
|
||||||
|
CreatedTime: me.parseLeanoteTime(note.createdTime),
|
||||||
|
UpdatedTime: me.parseLeanoteTime(note.updatedTime),
|
||||||
|
|
||||||
|
IsMarkdown: note.isMarkdown || false,
|
||||||
|
Attachs: attachs,
|
||||||
|
|
||||||
|
NotebookId: notebookId,
|
||||||
|
Desc: '',
|
||||||
|
NoteId: Common.objectId(),
|
||||||
|
IsNew: true
|
||||||
|
};
|
||||||
|
jsonNote._id = jsonNote.NoteId;
|
||||||
|
|
||||||
|
for(var h = 0; h < jsonNote.Tags.length; ++h) {
|
||||||
|
var tagTitle = jsonNote.Tags[h];
|
||||||
|
if (tagTitle) {
|
||||||
|
Tag.addOrUpdateTag(tagTitle, function(tag) {
|
||||||
|
Web.addTag(tag);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Note.updateNoteOrContent(jsonNote, function(insertedNote) {
|
||||||
|
callback && callback(insertedNote);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
parseLeanote: function (notebookId, json, callback, eachCallback) {
|
||||||
|
var me = this;
|
||||||
|
var notes = json.notes || [];
|
||||||
|
|
||||||
|
if (Common.isEmpty(notes)) {
|
||||||
|
callback(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async.eachSeries(notes, function(note, cb) {
|
||||||
|
me.parseNote(notebookId, note, function (insertedNote) {
|
||||||
|
eachCallback(insertedNote);
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}, function () {
|
||||||
|
callback(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Import;
|
216
public/plugins/import_leanote/plugin.js
Normal file
216
public/plugins/import_leanote/plugin.js
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/**
|
||||||
|
* 导入leanote, 重构
|
||||||
|
* @author life@leanote.com
|
||||||
|
* @date 2015/04/09
|
||||||
|
*/
|
||||||
|
define(function() {
|
||||||
|
var importService = nodeRequire('./public/plugins/import_leanote/import');
|
||||||
|
|
||||||
|
var leanote = {
|
||||||
|
|
||||||
|
langs: {
|
||||||
|
'en-us': {
|
||||||
|
'importLeanote': 'Import Leanote',
|
||||||
|
},
|
||||||
|
'zh-cn': {
|
||||||
|
'importLeanote': '导入Leanote',
|
||||||
|
'Choose Leanote files(.enex)': '选择Leanote文件(.enex)',
|
||||||
|
'Close': "关闭",
|
||||||
|
'Import to': "导入至",
|
||||||
|
"Done! %s notes imported!": "完成, 成功导入 %s 个笔记!",
|
||||||
|
"Import file: %s Success!": "文件 %s 导入成功!",
|
||||||
|
"Import file: %s Failure, is leanote file ?": "文件 %s 导入失败! 是Leanote文件?",
|
||||||
|
"Import: %s Success!": "导入笔记: %s 成功!"
|
||||||
|
},
|
||||||
|
'zh-hk': {
|
||||||
|
'importLeanote': '導入Leanote',
|
||||||
|
'Choose Leanote files(.enex)': '選擇Leanote文件(.enex)',
|
||||||
|
'Close': "關閉",
|
||||||
|
"Import to": "導入至",
|
||||||
|
"Done! %s notes imported!": "完成, 成功導入 %s 個筆記!",
|
||||||
|
"Import file: %s Success!": "文件 %s 導入成功!",
|
||||||
|
"Import file: %s Failure, is leanote file ?": "文件 %s 導入失敗! 是Leanote文件?",
|
||||||
|
"Import: %s Success!": "導入筆記: %s 成功!"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_tpl: `
|
||||||
|
<style>
|
||||||
|
#importLeanoteDialog .tab-pane {
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
#importLeanoteDialog .alert {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="modal fade bs-modal-sm" id="importLeanoteDialog" 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">
|
||||||
|
|
||||||
|
<!-- Nav tabs -->
|
||||||
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
|
<li role="presentation" class="active"><a href="#leanoteTab" aria-controls="leanoteTab" role="tab" data-toggle="tab">Leanote</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Tab panes -->
|
||||||
|
<div class="tab-content">
|
||||||
|
<div role="tabpanel" class="tab-pane active" id="leanoteTab">
|
||||||
|
<!-- import -->
|
||||||
|
<a id="chooseLeanoteFile" class="btn btn-success btn-choose-file">
|
||||||
|
<i class="fa fa-upload"></i>
|
||||||
|
<span class="lang">Choose Leanote files(.leanote)</span>
|
||||||
|
</a>
|
||||||
|
<!-- 消息 -->
|
||||||
|
<div id="importLeanoteMsg" 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="importLeanoteInput" type="file" nwsaveas="" accept=".enex" 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_leanote', data)
|
||||||
|
},
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
var me = this;
|
||||||
|
me._inited = true;
|
||||||
|
$('body').append(me._tpl);
|
||||||
|
me._importDialog = $("#importLeanoteDialog");
|
||||||
|
|
||||||
|
me._importDialog.find('.lang').each(function() {
|
||||||
|
var txt = $.trim($(this).text());
|
||||||
|
$(this).text(me.getMsg(txt));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 导入, 选择文件
|
||||||
|
$('#chooseLeanoteFile').click(function() {
|
||||||
|
|
||||||
|
Api.gui.dialog.showOpenDialog(Api.gui.getCurrentWindow(),
|
||||||
|
{
|
||||||
|
properties: ['openFile', 'multiSelections'],
|
||||||
|
filters: [
|
||||||
|
{ name: 'Leanote', extensions: ['leanote'] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
function(paths) {
|
||||||
|
if(!paths) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var notebookId = me._curNotebook.NotebookId;
|
||||||
|
|
||||||
|
var n = 0;
|
||||||
|
|
||||||
|
me.clear();
|
||||||
|
|
||||||
|
importService.importFromLeanote(notebookId, paths,
|
||||||
|
// 全局
|
||||||
|
function(ok) {
|
||||||
|
// $('#importLeanoteMsg .curImportFile').html("");
|
||||||
|
// $('#importLeanoteMsg .curImportNote').html("");
|
||||||
|
setTimeout(function() {
|
||||||
|
$('#importLeanoteMsg .allImport').html(me.getMsg('Done! %s notes imported!', n));
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
// 单个文件
|
||||||
|
function(ok, filename) {
|
||||||
|
if(ok) {
|
||||||
|
$('#importLeanoteMsg .curImportFile').html(me.getMsg("Import file: %s Success!", filename));
|
||||||
|
} else {
|
||||||
|
$('#importLeanoteMsg .curImportFile').html(me.getMsg("Import file: %s Failure, is leanote file ?", filename));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 单个笔记
|
||||||
|
function(note) {
|
||||||
|
if(note) {
|
||||||
|
n++;
|
||||||
|
$('#importLeanoteMsg .curImportNote').html(me.getMsg("Import: %s Success!", note.Title));
|
||||||
|
|
||||||
|
// 插入到当前笔记中
|
||||||
|
Note.addSync([note]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
clear: function() {
|
||||||
|
$('#importLeanoteMsg .curImportFile').html("");
|
||||||
|
$('#importLeanoteMsg .curImportNote').html("");
|
||||||
|
$('#importLeanoteMsg .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_leanote.importLeanote'),
|
||||||
|
click: (function() {
|
||||||
|
return function(notebook) {
|
||||||
|
me.open(notebook);
|
||||||
|
};
|
||||||
|
})()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 打开后
|
||||||
|
onOpenAfter: function() {
|
||||||
|
},
|
||||||
|
// 关闭时需要运行的
|
||||||
|
onClose: function() {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return leanote;
|
||||||
|
});
|
Reference in New Issue
Block a user