diff --git a/main.js b/main.js index 589878d62..1de30f4e6 100644 --- a/main.js +++ b/main.js @@ -9,10 +9,10 @@ var appIcon; // Report crashes to our server. crashReporter.start({ - productName: 'YourName', - companyName: 'YourCompany', - submitURL: 'https://your-domain.com/url-to-submit', - autoSubmit: true + productName: 'YourName', + companyName: 'YourCompany', + submitURL: 'https://your-domain.com/url-to-submit', + autoSubmit: true }); @@ -21,256 +21,259 @@ crashReporter.start({ var mainWindow = null; // single instance -const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => { - // Someone tried to run a second instance, we should focus our window. - if (mainWindow) { - mainWindow.show(); - if (mainWindow.isMinimized()) { - mainWindow.restore(); - } - mainWindow.focus(); - } -}) - -if (shouldQuit) { - app.quit() +// const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => { +const shouldQuit = app.requestSingleInstanceLock() +if (!shouldQuit) { + app.quit() +} else { + app.on('second-instance', (event, commandLine, workingDirectory) => { +// Someone tried to run a second instance, we should focus our window. + if (mainWindow) { + mainWindow.show(); + if (mainWindow.isMinimized()) { + mainWindow.restore(); + } + mainWindow.focus(); + } + }) +// app.on('ready',createWindow) } // Quit when all windows are closed. -app.on('window-all-closed', function() { - // if (process.platform != 'darwin') - app.quit(); -}); +// app.on('window-all-closed', function () { +// // if (process.platform != 'darwin') +// app.quit(); +// }); // 仅MAC // 避免可以启动多个app -app.on('open-file', function(e) { - // console.log('reopen'); - if(mainWindow) { - mainWindow.show(); - mainWindow.focus(); - } else { - openIt(); - } +app.on('open-file', function (e) { + // console.log('reopen'); + if (mainWindow) { + mainWindow.show(); + mainWindow.focus(); + } else { + openIt(); + } }); // 仅MAC // var appIsReady = false; -app.on('activate', function() { - console.log('activate'); - if(mainWindow) { - mainWindow.show(); - } - else { - // 有时, 重启电脑会出现这种情况 - // Cannot create BrowserWindow before app is ready - // 很可能app.on('ready')还没有出现, 但是ready后肯定有mainWindow了 - // 所以, 这一段注释掉 - // openIt(); - } +app.on('activate', function () { + console.log('activate'); + if (mainWindow) { + mainWindow.show(); + } + else { + // 有时, 重启电脑会出现这种情况 + // Cannot create BrowserWindow before app is ready + // 很可能app.on('ready')还没有出现, 但是ready后肯定有mainWindow了 + // 所以, 这一段注释掉 + // openIt(); + } }); // DB var DB = { - init: function () { - var me = this; - var db = require('db_main'); - - // 前端发来消息 - // m = {token: token, method: 'insert, findOne', dbname: 'notes', params: {username: "life"}}; - ipc.on('db-exec', function(event, m) { - // me._token2Sender[m.token] = event.sender; - db.exec(m, function (ret) { - // console.log('main called ret:'); - // console.log(ret); - if (ret && ret.ret) { - ret.ret = JSON.stringify(ret.ret); - } - event.sender.send('db-exec-ret', ret); - }); - }); - - /** - * 前端发消息过来说可以初始化了 - * @param {} event - * @param {Object} params { + init: function () { + var me = this; + var db = require('db_main'); + + // 前端发来消息 + // m = {token: token, method: 'insert, findOne', dbname: 'notes', params: {username: "life"}}; + ipc.on('db-exec', function (event, m) { + // me._token2Sender[m.token] = event.sender; + db.exec(m, function (ret) { + // console.log('main called ret:'); + // console.log(ret); + if (ret && ret.ret) { + ret.ret = JSON.stringify(ret.ret); + } + event.sender.send('db-exec-ret', ret); + }); + }); + + /** + * 前端发消息过来说可以初始化了 + * @param {} event + * @param {Object} params { curUser: 是当前用户 dbPath: string 是用户的dbPath dataBasePath: string 所有数据的基地址 * } - */ - ipc.on('db-init', function (event, params) { - db.init(params.curUser, params.dbPath, params.dataBasePath); - }); - } + */ + ipc.on('db-init', function (event, params) { + db.init(params.curUser, params.dbPath, params.dataBasePath); + }); + } }; // This method will be called when Electron has done everything // initialization and ready for creating browser windows. app.on('ready', openIt); -function removeEvents (win) { - win.removeAllListeners('closed'); - win.removeAllListeners('focus'); - win.removeAllListeners('blur'); - win.removeAllListeners('close'); +function removeEvents(win) { + win.removeAllListeners('closed'); + win.removeAllListeners('focus'); + win.removeAllListeners('blur'); + win.removeAllListeners('close'); } -function close (e, force) { - console.log('close:', force); - if (mainWindow) { - mainWindow.hide(); - e && e.preventDefault(); - mainWindow.webContents.send('closeWindow'); - } else { - app.quit(); - } +function close(e, force) { + console.log('close:', force); + if (mainWindow) { + mainWindow.hide(); + e && e.preventDefault(); + mainWindow.webContents.send('closeWindow'); + } else { + app.quit(); + } } -function bindEvents (win) { - mainWindow = win; - - // Emitted when the window is closed. - win.on('closed', function() { - console.log('closed'); - // Dereference the window object, usually you would store windows - // in an array if your app supports multi windows, this is the time - // when you should delete the corresponding element. - win = null; - }); - - win.on('focus', function() { - console.log('focus'); - // ipc.send('focusWindow'); mainProcess没有该方法 - if(win && win.webContents) - win.webContents.send('focusWindow'); - }); - win.on('blur', function() { - console.log('blur'); - if(win && win.webContents) - win.webContents.send('blurWindow'); - }); - - // 以前的关闭是真关闭, 现是是假关闭了 - // 关闭,先保存数据 - win.on('close', function(e) { - // windows支持tray, 点close就是隐藏 - if (process.platform.toLowerCase().indexOf('win') === 0) { // win32 - win.hide(); - e.preventDefault(); - return; - } +function bindEvents(win) { + mainWindow = win; - // mac 在docker下quit; - // linux直接点x linux不支持Tray - close(e, false); - }); + // Emitted when the window is closed. + win.on('closed', function () { + console.log('closed'); + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + win = null; + }); -} + win.on('focus', function () { + console.log('focus'); + // ipc.send('focusWindow'); mainProcess没有该方法 + if (win && win.webContents) + win.webContents.send('focusWindow'); + }); + win.on('blur', function () { + console.log('blur'); + if (win && win.webContents) + win.webContents.send('blurWindow'); + }); -function openIt() { - // 数据库 - DB.init(); - - // 协议 - var leanoteProtocol = require('leanote_protocol'); - leanoteProtocol.init(); - - // Create the browser window. - mainWindow = new BrowserWindow({ - width: 1050, - height: 595, - frame: process.platform != 'darwin', - transparent: false - } - ); + // 以前的关闭是真关闭, 现是是假关闭了 + // 关闭,先保存数据 + win.on('close', function (e) { + // windows支持tray, 点close就是隐藏 + if (process.platform.toLowerCase().indexOf('win') === 0) { // win32 + win.hide(); + e.preventDefault(); + return; + } - console.log('load: file://' + __dirname + '/note.html'); + // mac 在docker下quit; + // linux直接点x linux不支持Tray + close(e, false); + }); - // and load the index.html of the app. - mainWindow.loadURL('file://' + __dirname + '/note.html'); +} - bindEvents(mainWindow); +function openIt() { + // 数据库 + DB.init(); + + // 协议 + var leanoteProtocol = require('leanote_protocol'); + leanoteProtocol.init(); + + // Create the browser window. + mainWindow = new BrowserWindow({ + width: 1050, + height: 595, + frame: process.platform != 'darwin', + transparent: false + } + ); - // 前端发来可以关闭了 - ipc.on('quit-app', function(event, arg) { - console.log('get quit-app request'); - if (mainWindow) { - mainWindow.destroy(); - mainWindow = null; - } else { - app.quit(); - } - }); + console.log('load: file://' + __dirname + '/note.html'); - // open login.html and note.html - ipc.on('openUrl', function(event, arg) { - console.log('openUrl', arg); + // and load the index.html of the app. + mainWindow.loadURL('file://' + __dirname + '/note.html'); - var html = arg.html; - var everWindow = mainWindow; - var win2 = new BrowserWindow(arg); - win2.loadURL('file://' + __dirname + '/' + html); - mainWindow = win2; + bindEvents(mainWindow); - // remove all events then close it - removeEvents(everWindow); - everWindow.close(); + // 前端发来可以关闭了 + ipc.on('quit-app', function (event, arg) { + console.log('get quit-app request'); + if (mainWindow) { + mainWindow.destroy(); + mainWindow = null; + } else { + app.quit(); + } + }); - if (html.indexOf('note.html') >= 0) { - bindEvents(mainWindow) - } - }); + // open login.html and note.html + ipc.on('openUrl', function (event, arg) { + console.log('openUrl', arg); - pdfMain.init(); + var html = arg.html; + var everWindow = mainWindow; + var win2 = new BrowserWindow(arg); + win2.loadURL('file://' + __dirname + '/' + html); + mainWindow = win2; - function show () { - if (mainWindow) { - mainWindow.show(); - mainWindow.restore(); - mainWindow.focus(); - mainWindow.webContents.send('focusWindow'); - } else { - app.quit(); - } - } + // remove all events then close it + removeEvents(everWindow); + everWindow.close(); - var trayShowed = false; - ipc.on('show-tray', function(event, arg) { - if (trayShowed) { - return; - } - trayShowed = true; + if (html.indexOf('note.html') >= 0) { + bindEvents(mainWindow) + } + }); + + pdfMain.init(); - if (process.platform == 'linux') { - return; + function show() { + if (mainWindow) { + mainWindow.show(); + mainWindow.restore(); + mainWindow.focus(); + mainWindow.webContents.send('focusWindow'); + } else { + app.quit(); + } } - appIcon = new Tray(__dirname + '/public/images/tray/' + ( process.platform == 'darwin' ? 'trayTemplate.png' : 'tray.png')) - var contextMenu = Menu.buildFromTemplate([ - { - label: arg.Open, click: function () { - show(); + var trayShowed = false; + ipc.on('show-tray', function (event, arg) { + if (trayShowed) { + return; } - }, - { - label: arg.Close, click: function () { - close(null, true); + trayShowed = true; + + if (process.platform == 'linux') { + return; } - }, - ]); - appIcon.setToolTip('Leanote'); - // appIcon.setTitle('Leanote'); - // appIcon.setContextMenu(contextMenu); - - appIcon.on('click', function (e) { - show(); - e.preventDefault(); - }); - appIcon.on('right-click', function () { - appIcon.popUpContextMenu(contextMenu); - }); - }); + appIcon = new Tray(__dirname + '/public/images/tray/' + ( process.platform == 'darwin' ? 'trayTemplate.png' : 'tray.png')) + var contextMenu = Menu.buildFromTemplate([ + { + label: arg.Open, click: function () { + show(); + } + }, + { + label: arg.Close, click: function () { + close(null, true); + } + }, + ]); + appIcon.setToolTip('Leanote'); + // appIcon.setTitle('Leanote'); + // appIcon.setContextMenu(contextMenu); + + appIcon.on('click', function (e) { + show(); + e.preventDefault(); + }); + appIcon.on('right-click', function () { + appIcon.popUpContextMenu(contextMenu); + }); + + }); } diff --git a/public/js/app/api.js b/public/js/app/api.js index 6f6adc13e..4631c6d5a 100644 --- a/public/js/app/api.js +++ b/public/js/app/api.js @@ -1,226 +1,227 @@ - // 只有api的插件才能访问 var Api = { - notebook: Notebook, - note: Note, - tag: Tag, - loading: Loading, - gui: gui, - onClose: onClose, - switchToLoginWhenNoUser: switchToLoginWhenNoUser, - reloadApp: reloadApp, - isMac: isMac(), - nodeFs: NodeFs, - evtService: EvtService, - commonService: CommonService, - fileService: FileService, - noteService: NoteService, - userService: UserService, - dbService: db, - ipc: nodeRequire('electron').ipcRenderer, + notebook: Notebook, + note: Note, + tag: Tag, + loading: Loading, + gui: gui, + onClose: onClose, + switchToLoginWhenNoUser: switchToLoginWhenNoUser, + reloadApp: reloadApp, + isMac: isMac(), + nodeFs: NodeFs, + evtService: EvtService, + commonService: CommonService, + fileService: FileService, + noteService: NoteService, + userService: UserService, + dbService: db, + ipc: nodeRequire('electron').ipcRenderer, projectPath: projectPath, + path: Path, + + // 打开本地目录 + // mac和windows下不同 + openLocalDir: function (dir) { + if (isMac()) { + gui.Shell.showItemInFolder(dir); + } + else { + gui.Shell.openItem(dir); + } + }, + + // 得到当前版本 + getCurVersion: function (callback) { + var me = this; + var vFile = me.evtService.getProjectBasePath() + '/data/version'; + // fs.writeFileSync('./output.json',JSON.stringify({a:1,b:2})); + try { + var v = JSON.parse(fs.readFileSync(vFile)); + return v; + } catch (e) { + return false; + } + }, + + getConfigFilePath: function () { + return __dirname + '/public/config.js'; + }, + writeConfig: function (config) { + var me = this; + var fileData = "var Config = " + JSON.stringify(config, null, 4) + ';'; + var ok = me.commonService.writeFile(me.getConfigFilePath(), fileData); + return ok; + }, + + // data = {'en-us': {}, 'zh-cn' {}}; + // prefix = 'plugin.theme' + _langs: { + 'en-us': { + 'default': 'Default', + }, + 'zh-cn': { + 'default': '默认', + } + }, + curLang: curLang, + defaultLang: 'en-us', + // 添加语言包 + addLangMsgs: function (data, prefix) { + var me = this; + if (!data) { + return; + } + if (prefix) { + prefix += '.'; // prefix. + } + for (var lang in data) { + var msgs = data[lang] || {}; + me._langs[lang] || (me._langs[lang] = {}); + for (var key in msgs) { + me._langs[lang][prefix + key] = msgs[key]; + } + } + }, + isArray: function (obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + }, + // 国际化 + getMsg: function (key, prefix, data) { + var me = this; + if (!key) { + return ''; + } + var rawKey = key; + if (prefix) { + key = prefix + '.' + key; + } + + var msg = me._langs[me.curLang][key] || me._langs[me.defaultLang][key] + || rawKey; + + if (data) { + if (!me.isArray(data)) { + data = [data]; + } + for (var i = 0; i < data.length; ++i) { + msg = msg.replace("%s", data[i]); + } + } + return msg; + }, + + // 与之前lang.js取出的数据合并 + _init: function () { + var me = this; + me._langs[me.curLang] || (me._langs[me.curLang] = {}); + $.extend(me._langs[me.curLang], window.langData); - // 打开本地目录 - // mac和windows下不同 - openLocalDir: function (dir) { - if (isMac()) { - gui.Shell.showItemInFolder(dir); - } - else { - gui.Shell.openItem(dir); - } - }, - - // 得到当前版本 - getCurVersion: function (callback) { - var me = this; - var vFile = me.evtService.getProjectBasePath() + '/data/version'; - // fs.writeFileSync('./output.json',JSON.stringify({a:1,b:2})); - try { - var v = JSON.parse(fs.readFileSync(vFile)); - return v; - } catch(e) { - return false; - } - }, - - getConfigFilePath: function() { - return __dirname + '/public/config.js'; - }, - writeConfig: function(config) { - var me = this; - var fileData = "var Config = " + JSON.stringify(config, null, 4) + ';'; - var ok = me.commonService.writeFile(me.getConfigFilePath(), fileData); - return ok; - }, - - // data = {'en-us': {}, 'zh-cn' {}}; - // prefix = 'plugin.theme' - _langs: { - 'en-us': { - 'default': 'Default', - }, - 'zh-cn': { - 'default': '默认', - } - }, - curLang: curLang, - defaultLang: 'en-us', - // 添加语言包 - addLangMsgs: function(data, prefix) { - var me = this; - if(!data) { - return; - } - if(prefix) { - prefix += '.'; // prefix. - } - for(var lang in data) { - var msgs = data[lang] || {}; - me._langs[lang] || (me._langs[lang] = {}); - for(var key in msgs) { - me._langs[lang][prefix + key] = msgs[key]; - } - } - }, - isArray: function(obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; - }, - // 国际化 - getMsg: function(key, prefix, data) { - var me = this; - if(!key) { - return ''; - } - var rawKey = key; - if(prefix) { - key = prefix + '.' + key; - } - - var msg = me._langs[me.curLang][key] || me._langs[me.defaultLang][key] || rawKey; - - if(data) { - if(!me.isArray(data)) { - data = [data]; - } - for(var i = 0; i < data.length; ++i) { - msg = msg.replace("%s", data[i]); - } - } - return msg; - }, - - // 与之前lang.js取出的数据合并 - _init: function() { - var me = this; - me._langs[me.curLang] || (me._langs[me.curLang] = {}); - $.extend(me._langs[me.curLang], window.langData); - - // extend - window.getMsg = function(key, prefix, data) { - return me.getMsg(key, prefix, data); - }; - }, - - _callOpenAfter: function() { - - }, - - _themeMenu: null, - getThemeMenu: function() { - var me = this; - return me._themeMenu; - }, - setThemeMenu: function(menus) { - var me = this; - me._themeMenu = menus; - }, - - // markdown theme - _mdThemeMenu: null, - getMdThemeMenu: function() { - var me = this; - return me._mdThemeMenu; - }, - setMdThemeMenu: function(menus) { - var me = this; - me._mdThemeMenu = menus; - }, - - _importMenus: [], - addImportMenu: function(menu) { - var me = this; - me._importMenus.push(menu); - }, - getImportMenus: function() { - var me = this; - return me._importMenus; - }, - // 添加用户menu - addUserMenu: function(menus, pos) { - - - }, - addNotebookMenu: function(menu, pos) { - - }, - addTrashMenu: function(menu, pos) { - - }, - - // 导出 - _exportMenus: [], - addExportMenu: function(menu) { - var me = this; - me._exportMenus.push(menu); - }, - getExportMenus: function() { - var me = this; - return me._exportMenus; - }, - - // 导出, 笔记本下 - _exportMenusForNotebook: [], - addExportMenuForNotebook: function(menu) { - var me = this; - me._exportMenusForNotebook.push(menu); - }, - getExportMenusForNotebook: function() { - var me = this; - return me._exportMenusForNotebook; - }, - - // 更多菜单 - _moreMenus: [], - getMoreMenus: function() { - var me = this; - return me._moreMenus; - }, - addMoreMenu: function(menu) { - var me = this; - me._moreMenus.push(menu); - } + // extend + window.getMsg = function (key, prefix, data) { + return me.getMsg(key, prefix, data); + }; + }, + + _callOpenAfter: function () { + + }, + + _themeMenu: null, + getThemeMenu: function () { + var me = this; + return me._themeMenu; + }, + setThemeMenu: function (menus) { + var me = this; + me._themeMenu = menus; + }, + + // markdown theme + _mdThemeMenu: null, + getMdThemeMenu: function () { + var me = this; + return me._mdThemeMenu; + }, + setMdThemeMenu: function (menus) { + var me = this; + me._mdThemeMenu = menus; + }, + + _importMenus: [], + addImportMenu: function (menu) { + var me = this; + me._importMenus.push(menu); + }, + getImportMenus: function () { + var me = this; + return me._importMenus; + }, + // 添加用户menu + addUserMenu: function (menus, pos) { + + }, + addNotebookMenu: function (menu, pos) { + + }, + addTrashMenu: function (menu, pos) { + + }, + + // 导出 + _exportMenus: [], + addExportMenu: function (menu) { + var me = this; + me._exportMenus.push(menu); + }, + getExportMenus: function () { + var me = this; + return me._exportMenus; + }, + + // 导出, 笔记本下 + _exportMenusForNotebook: [], + addExportMenuForNotebook: function (menu) { + var me = this; + me._exportMenusForNotebook.push(menu); + }, + getExportMenusForNotebook: function () { + var me = this; + return me._exportMenusForNotebook; + }, + + // 更多菜单 + _moreMenus: [], + getMoreMenus: function () { + var me = this; + return me._moreMenus; + }, + addMoreMenu: function (menu) { + var me = this; + me._moreMenus.push(menu); + } }; //------------- // 全局事件机制 $.extend(Api, { - _eventCallbacks: {}, - _listen: function(type, callback) { - var callbacks = this._eventCallbacks[type] || (this._eventCallbacks[type] = []); + _eventCallbacks: {}, + _listen: function (type, callback) { + var callbacks = this._eventCallbacks[type] + || (this._eventCallbacks[type] = []); callbacks.push(callback); }, // on('a b', function(params) {}) - on: function(name, callback) { + on: function (name, callback) { var names = name.split(/\s+/); for (var i = 0; i < names.length; ++i) { - this._listen(names[i], callback); + this._listen(names[i], callback); } return this; }, // off('a b', function(params) {}) - off: function(name, callback) { + off: function (name, callback) { var types = name.split(/\s+/); var i, j, callbacks, removeIndex; for (i = 0; i < types.length; i++) { @@ -239,7 +240,7 @@ $.extend(Api, { } }, // LEA.trigger('a', {}); - trigger: function(type, params) { + trigger: function (type, params) { var callbacks = this._eventCallbacks[type] || []; if (callbacks.length === 0) { return; @@ -250,5 +251,4 @@ $.extend(Api, { } }); - Api._init(); diff --git a/public/js/app/notebook.js b/public/js/app/notebook.js index 84093173b..7881a5dbe 100644 --- a/public/js/app/notebook.js +++ b/public/js/app/notebook.js @@ -5,7 +5,7 @@ Notebook.notebooks = []; // 按次序 Notebook.notebookNavForListNote = ""; // html 为了note list上面和新建时的ul // 设置缓存 -Notebook.setCache = function(notebook) { +Notebook.setCache = function (notebook) { var notebookId = notebook.NotebookId; if (!notebookId) { return; @@ -16,11 +16,11 @@ Notebook.setCache = function(notebook) { $.extend(Notebook.cache[notebookId], notebook); }; -Notebook.getCurNotebookId = function() { +Notebook.getCurNotebookId = function () { return Notebook.curNotebookId; }; -Notebook.getCurNotebook = function() { +Notebook.getCurNotebook = function () { return Notebook.cache[Notebook.curNotebookId]; }; @@ -29,7 +29,7 @@ Notebook.getCurNotebook = function() { // 放在这里, 让addNote时调用 Notebook._newNotebookNumberNotes = {}; // notebookId => count Notebook._subNotebookNumberNotes = {}; -Notebook.reRenderNotebookNumberNotesIfIsNewNotebook = function(notebookId) { +Notebook.reRenderNotebookNumberNotesIfIsNewNotebook = function (notebookId) { var count = Notebook._newNotebookNumberNotes[notebookId]; if (count) { delete Notebook._newNotebookNumberNotes[notebookId]; @@ -39,7 +39,7 @@ Notebook.reRenderNotebookNumberNotesIfIsNewNotebook = function(notebookId) { Notebook.updateNotebookNumberNotes(notebookId, count); }; // 为了server Web调用 -Notebook.updateNotebookNumberNotes = function(notebookId, count) { +Notebook.updateNotebookNumberNotes = function (notebookId, count) { var self = this; var notebook = self.getNotebook(notebookId); // 为什么可能会没有? 因为可能是新加的笔记本, 此时该笔记本又有笔记, 一起同步过来 @@ -59,7 +59,7 @@ Notebook.updateNotebookNumberNotes = function(notebookId, count) { }; // 笔记本的笔记数量更新 -Notebook._updateNotebookNumberNotes = function(notebookId, n) { +Notebook._updateNotebookNumberNotes = function (notebookId, n) { var self = this; var notebook = self.getNotebook(notebookId); if (!notebook) { @@ -91,24 +91,24 @@ Notebook._updateNotebookNumberNotes = function(notebookId, n) { }; // addNote, copyNote, moveNote -Notebook.incrNotebookNumberNotes = function(notebookId) { +Notebook.incrNotebookNumberNotes = function (notebookId) { var self = this; self._updateNotebookNumberNotes(notebookId, 1); }; // moteNote, deleteNote -Notebook.minusNotebookNumberNotes = function(notebookId) { +Notebook.minusNotebookNumberNotes = function (notebookId) { var self = this; self._updateNotebookNumberNotes(notebookId, -1); }; // 得到notebook标题, 给note显示其notebook标题用 // called by Note -Notebook.getNotebook = function(notebookId) { +Notebook.getNotebook = function (notebookId) { return Notebook.cache[notebookId]; }; // called by Note -Notebook.getNotebookTitle = function(notebookId) { +Notebook.getNotebookTitle = function (notebookId) { var notebook = Notebook.cache[notebookId]; if (notebook) { return trimTitle(notebook.Title); @@ -119,15 +119,15 @@ Notebook.getNotebookTitle = function(notebookId) { /** * 我的notebooks - + */ // 得到下级notebooks -Notebook.getSubNotebooks = function(parentNotebookId) { +Notebook.getSubNotebooks = function (parentNotebookId) { var me = this; var treeObj = me.tree; @@ -141,6 +141,7 @@ Notebook.getSubNotebooks = function(parentNotebookId) { function filter(node) { return node.level == nextLevel; } + var nodes = treeObj.getNodesByFilter(filter, false, parentNode); if (nodes && nodes.length == 0) { @@ -153,7 +154,7 @@ Notebook.getSubNotebooks = function(parentNotebookId) { * Simple Tree Setting(基本版) * 笔记移动、复制时使用 */ -Notebook.getSimpleTreeSetting = function(options) { +Notebook.getSimpleTreeSetting = function (options) { // 添加自定义dom function addDiyDom(treeId, treeNode) { var spaceWidth = 5; @@ -167,7 +168,8 @@ Notebook.getSimpleTreeSetting = function(options) { switchObj.before(spaceStr); } } - var onDblClick = function(e, treeId, treeNode) { + + var onDblClick = function (e, treeId, treeNode) { var notebookId = treeNode.NotebookId; options.callback(notebookId); $("#leanoteDialog").modal('hide'); @@ -192,7 +194,7 @@ Notebook.getSimpleTreeSetting = function(options) { return setting; } -Notebook.getTreeSetting = function(isSearch, isShare) { +Notebook.getTreeSetting = function (isSearch, isShare) { var noSearch = !isSearch; var self = this; @@ -215,6 +217,7 @@ Notebook.getTreeSetting = function(isSearch, isShare) { switchObj.before(spaceStr); } } + // 拖拽 function beforeDrag(treeId, treeNodes) { for (var i = 0, l = treeNodes.length; i < l; i++) { @@ -237,7 +240,7 @@ Notebook.getTreeSetting = function(isSearch, isShare) { } var parentNode; var treeObj = self.tree; - var ajaxData = { curNotebookId: treeNode.NotebookId }; + var ajaxData = {curNotebookId: treeNode.NotebookId}; // 成为子节点, 那么只需要得到targetNode下所有的子结点即可 if (moveType == "inner") { @@ -246,7 +249,7 @@ Notebook.getTreeSetting = function(isSearch, isShare) { parentNode = targetNode.getParentNode(); } - // 在targetNode之前或之后, + // 在targetNode之前或之后, // 那么: 1) 需要将该parentNode下所有的node重新排序即可; 2) treeNodes[0]为parentNode的子 if (!parentNode) { var nodes = treeObj.getNodes(); // 得到所有nodes @@ -257,6 +260,7 @@ Notebook.getTreeSetting = function(isSearch, isShare) { function filter(node) { return node.level == nextLevel; } + var nodes = treeObj.getNodesByFilter(filter, false, parentNode); } @@ -274,21 +278,21 @@ Notebook.getTreeSetting = function(isSearch, isShare) { // 设置dirty状态 // 不需要设置parentNotebookId var ids = [ajaxData.curNotebookId].concat(ajaxData.siblings || []); - ids.forEach(function(notebookId) { + ids.forEach(function (notebookId) { if (notebookId) { Notebook.setDirtyOrNew(notebookId, true); } }); - setTimeout(function() { + setTimeout(function () { Notebook.changeNav(); }, 100); } - var onClick = function(e, treeId, treeNode) { + var onClick = function (e, treeId, treeNode) { var notebookId = treeNode.NotebookId; Notebook.changeNotebook(notebookId); }; - var onDblClick = function(e) { + var onDblClick = function (e) { var notebookId = $(e.target).attr("notebookId"); if (!Notebook.isAllNotebookId(notebookId) && !Notebook.isTrashNotebookId(notebookId)) { self.updateNotebookTitle(e.target); @@ -326,13 +330,13 @@ Notebook.getTreeSetting = function(isSearch, isShare) { onDrop: onDrop, onClick: onClick, onDblClick: onDblClick, - onExpand: function(event, treeId, treeNode) { + onExpand: function (event, treeId, treeNode) { // 展开时, 会有子笔记本, 如果之前有设置数量, 则重新设置 // 为了防止移动, 复制过来时没有该sub if (treeNode.isParent) { var childNotes = self.getSubNotebooks(treeNode.NotebookId); if (childNotes) { - childNotes.forEach(function(node) { + childNotes.forEach(function (node) { var notebookId = node.NotebookId; if (Notebook._subNotebookNumberNotes[notebookId] !== undefined) { $('#numberNotes_' + notebookId).html(Notebook._subNotebookNumberNotes[notebookId]); @@ -344,7 +348,7 @@ Notebook.getTreeSetting = function(isSearch, isShare) { } } }, - beforeRename: function(treeId, treeNode, newName, isCancel) { + beforeRename: function (treeId, treeNode, newName, isCancel) { if (newName == "") { if (treeNode.IsNew) { // 删除之 @@ -376,14 +380,14 @@ Notebook.getTreeSetting = function(isSearch, isShare) { Notebook.allNotebookId = "0"; Notebook.trashNotebookId = "-1"; -Notebook.curNotebookIsTrashOrAll = function() { +Notebook.curNotebookIsTrashOrAll = function () { return Notebook.curNotebookId == Notebook.trashNotebookId || Notebook.curNotebookId == Notebook.allNotebookId; }; -Notebook.curNotebookIsTrash = function() { +Notebook.curNotebookIsTrash = function () { return Notebook.curNotebookId == Notebook.trashNotebookId; }; // reload 是否再一次load -Notebook.renderNotebooks = function(notebooks, reload) { +Notebook.renderNotebooks = function (notebooks, reload) { var self = this; if (!notebooks || typeof notebooks != "object" || notebooks.length < 0) { @@ -396,19 +400,19 @@ Notebook.renderNotebooks = function(notebooks, reload) { notebook.Title = trimTitle(notebook.Title); } - notebooks = [{ NotebookId: Notebook.allNotebookId, Title: getMsg("all"), drop: false, drag: false }].concat(notebooks); - notebooks.push({ NotebookId: Notebook.trashNotebookId, Title: getMsg("trash"), drop: false, drag: false }); + notebooks = [{NotebookId: Notebook.allNotebookId, Title: getMsg("all"), drop: false, drag: false}].concat(notebooks); + notebooks.push({NotebookId: Notebook.trashNotebookId, Title: getMsg("trash"), drop: false, drag: false}); Notebook.notebooks = notebooks; // 缓存之 self.tree = $.fn.zTree.init($("#notebookList"), self.getTreeSetting(), notebooks); // 展开/折叠图标 var $notebookList = $("#notebookList"); - $notebookList.hover(function() { + $notebookList.hover(function () { if (!$(this).hasClass("showIcon")) { $(this).addClass("showIcon"); } - }, function() { + }, function () { $(this).removeClass("showIcon"); }); @@ -429,7 +433,7 @@ Notebook.renderNotebooks = function(notebooks, reload) { } }; -Notebook.cacheAllNotebooks = function(notebooks) { +Notebook.cacheAllNotebooks = function (notebooks) { var self = this; for (var i in notebooks) { var notebook = notebooks[i]; @@ -441,7 +445,7 @@ Notebook.cacheAllNotebooks = function(notebooks) { }; // 展开到笔记本 -Notebook.expandNotebookTo = function(notebookId, userId) { +Notebook.expandNotebookTo = function (notebookId, userId) { var me = this; var selected = false; var tree = me.tree; @@ -473,16 +477,16 @@ Notebook.expandNotebookTo = function(notebookId, userId) { }; -// RenderNotebooks调用, +// RenderNotebooks调用, // nav 为了新建, 快速选择, 移动笔记 // 这些在添加,修改,删除notebooks都要变动!!! -Notebook.renderNav = function(nav) { +Notebook.renderNav = function (nav) { var self = this; self.changeNav(); }; // 搜索notebook -Notebook.searchNotebookForAddNote = function(key) { +Notebook.searchNotebookForAddNote = function (key) { var self = this; if (key) { var notebooks = self.tree.getNodesByParamFuzzy("Title", key); @@ -499,7 +503,7 @@ Notebook.searchNotebookForAddNote = function(key) { }; // 搜索notebook -Notebook.searchNotebookForList = function(key) { +Notebook.searchNotebookForList = function (key) { var self = this; var $search = $("#notebookListForSearch"); var $notebookList = $("#notebookList"); @@ -524,13 +528,14 @@ Notebook.searchNotebookForList = function(key) { }; Notebook.everNotebooks = []; -Notebook.changeNav = function() { +Notebook.changeNav = function () { var self = Notebook; var notebooks = Notebook.tree.getNodes(); var pureNotebooks = []; // 不含新和垃圾 for (var i = 0; i < notebooks.length; ++i) { var notebookId = notebooks[i].NotebookId; - if (Notebook.isAllNotebookId(notebookId) || Notebook.isTrashNotebookId(notebookId)) {} else { + if (Notebook.isAllNotebookId(notebookId) || Notebook.isTrashNotebookId(notebookId)) { + } else { pureNotebooks.push(notebooks[i]); } } @@ -540,26 +545,26 @@ Notebook.changeNav = function() { }; /** - * 我的共享notebooks + * 我的共享notebooks
- + */ // TODO 层级 -Notebook.renderShareNotebooks = function(sharedUserInfos, shareNotebooks) { +Notebook.renderShareNotebooks = function (sharedUserInfos, shareNotebooks) { if (isEmpty(sharedUserInfos)) { return; } @@ -576,9 +581,9 @@ Notebook.renderShareNotebooks = function(sharedUserInfos, shareNotebooks) { } for (var i in sharedUserInfos) { var userInfo = sharedUserInfos[i]; - var userNotebooks = user2ShareNotebooks[userInfo.UserId] || { ShareNotebooks: [] }; + var userNotebooks = user2ShareNotebooks[userInfo.UserId] || {ShareNotebooks: []}; - userNotebooks.ShareNotebooks = [{ NotebookId: "-2", Title: "默认共享" }].concat(userNotebooks.ShareNotebooks) + userNotebooks.ShareNotebooks = [{NotebookId: "-2", Title: "默认共享"}].concat(userNotebooks.ShareNotebooks) var username = userInfo.Username || userInfo.Email; var header = tt('
', username, username); @@ -594,13 +599,13 @@ Notebook.renderShareNotebooks = function(sharedUserInfos, shareNotebooks) { } // 左侧导航, 选中某个notebook -Notebook.selectNotebook = function(target) { +Notebook.selectNotebook = function (target) { $(".notebook-item").removeClass("curSelectedNode"); $(target).addClass("curSelectedNode"); }; // 新建笔记导航 -Notebook.changeNotebookNavForNewNote = function(notebookId, title) { +Notebook.changeNotebookNavForNewNote = function (notebookId, title) { // 没有notebookId, 则选择第1个notebook // 第一个是全部笔记 if (!notebookId) { @@ -634,7 +639,7 @@ Notebook.changeNotebookNavForNewNote = function(notebookId, title) { // 2 notelist上面 > // 3 新建笔记 - js > // 转成我的nav <-> 共享 -Notebook.toggleToMyNav = function(userId, notebookId) { +Notebook.toggleToMyNav = function (userId, notebookId) { $("#sharedNotebookNavForListNav").hide(); $("#myNotebookNavForListNav").show(); @@ -645,7 +650,7 @@ Notebook.toggleToMyNav = function(userId, notebookId) { $("#tagSearch").hide(); }; -Notebook.changeNotebookNav = function(notebookId) { +Notebook.changeNotebookNav = function (notebookId) { Notebook.curNotebookId = notebookId; Notebook.toggleToMyNav(); @@ -665,32 +670,32 @@ Notebook.changeNotebookNav = function(notebookId) { Notebook.changeNotebookNavForNewNote(notebookId, notebook.Title); }; -Notebook.isAllNotebookId = function(notebookId) { +Notebook.isAllNotebookId = function (notebookId) { return notebookId == Notebook.allNotebookId; }; -Notebook.isTrashNotebookId = function(notebookId) { +Notebook.isTrashNotebookId = function (notebookId) { return notebookId == Notebook.trashNotebookId; }; // 当前选中的笔记本是否是"所有" // called by Note -Notebook.curActiveNotebookIsAll = function() { +Notebook.curActiveNotebookIsAll = function () { return Notebook.isAllNotebookId($("#notebookList .curSelectedNode").attr("notebookId")); }; -Notebook.curActiveNotebookIsTrash = function() { +Notebook.curActiveNotebookIsTrash = function () { return Notebook.isTrashNotebookId($("#notebookList .curSelectedNode").attr("notebookId")); }; -Notebook.renderCurNotebook = function() { - Notebook.changeNotebook(Notebook.curNotebookId); - } - // 改变笔记本 - // 0. 改变样式 - // 1. 改变note, 此时需要先保存 - // 2. ajax得到该notebook下的所有note - // 3. 使用Note.RederNotes() - // callback Pjax, 当popstate时调用 +Notebook.renderCurNotebook = function () { + Notebook.changeNotebook(Notebook.curNotebookId); +} +// 改变笔记本 +// 0. 改变样式 +// 1. 改变note, 此时需要先保存 +// 2. ajax得到该notebook下的所有note +// 3. 使用Note.RederNotes() +// callback Pjax, 当popstate时调用 Notebook.changeNotebookSeq = 1; -Notebook.changeNotebook = function(notebookId, callback, needRendNoteId) { +Notebook.changeNotebook = function (notebookId, callback, needRendNoteId) { var me = this; // 如果找不到 @@ -709,7 +714,7 @@ Notebook.changeNotebook = function(notebookId, callback, needRendNoteId) { Note.clearAll(); var url = "/note/listNotes/"; - var param = { notebookId: notebookId }; + var param = {notebookId: notebookId}; var cacheNotes = null; // 废纸篓 if (Notebook.isTrashNotebookId(notebookId)) { @@ -756,8 +761,8 @@ Notebook.changeNotebook = function(notebookId, callback, needRendNoteId) { // 这里可能点击过快导致前面点击的后来才返回 me.showNoteAndEditorLoading(); me.changeNotebookSeq++; - (function(seq) { - var callback2 = function(cacheNotes) { + (function (seq) { + var callback2 = function (cacheNotes) { // 后面点击过快, 之前的结果不要了 if (seq != me.changeNotebookSeq) { log("notebook changed too fast!"); @@ -781,7 +786,7 @@ Notebook.changeNotebook = function(notebookId, callback, needRendNoteId) { }; // 改变标签, isStarred是否是星笔记本 -Notebook.changeCurNotebookTitle = function(title, isStarred, subTitle, isTag, isSearch) { +Notebook.changeCurNotebookTitle = function (title, isStarred, subTitle, isTag, isSearch) { var me = this; var title = isTag ? title : trimTitle(title); $("#curNotebookForListNote").html(title); @@ -796,23 +801,23 @@ Notebook.changeCurNotebookTitle = function(title, isStarred, subTitle, isTag, is }; // 笔记列表与编辑器的mask loading -Notebook.showNoteAndEditorLoading = function() { +Notebook.showNoteAndEditorLoading = function () { $("#noteAndEditorMask").show(); }; -Notebook.hideNoteAndEditorLoading = function() { +Notebook.hideNoteAndEditorLoading = function () { $("#noteAndEditorMask").hide(); }; // 是否是当前选中的notebookId // 还包括共享 // called by Note -Notebook.isCurNotebook = function(notebookId) { +Notebook.isCurNotebook = function (notebookId) { return $(tt('#notebookList [notebookId="?"], #shareNotebooks [notebookId="?"]', notebookId, notebookId)).attr("class") == "active"; }; // 改变nav, 为了新建note // called by Note -Notebook.changeNotebookForNewNote = function(notebookId) { +Notebook.changeNotebookForNewNote = function (notebookId) { // 废纸篓 if (Notebook.isTrashNotebookId(notebookId) || Notebook.isAllNotebookId(notebookId)) { return; @@ -823,7 +828,7 @@ Notebook.changeNotebookForNewNote = function(notebookId) { // 2 得到笔记本 // 这里可以缓存起来, note按notebookId缓存 - Service.noteService.getNotes(notebookId, function(notes) { + Service.noteService.getNotes(notebookId, function (notes) { // note 导航 Note.renderNotes(notes, true); }); @@ -831,15 +836,15 @@ Notebook.changeNotebookForNewNote = function(notebookId) { //--------------------------- // 显示共享信息 -Notebook.listNotebookShareUserInfo = function(target) { - var notebookId = $(target).attr("notebookId"); - showDialogRemote("/share/listNotebookShareUserInfo", { notebookId: notebookId }); - } - // 共享笔记本 -Notebook.shareNotebooks = function(target) { +Notebook.listNotebookShareUserInfo = function (target) { + var notebookId = $(target).attr("notebookId"); + showDialogRemote("/share/listNotebookShareUserInfo", {notebookId: notebookId}); +} +// 共享笔记本 +Notebook.shareNotebooks = function (target) { var title = $(target).text(); - showDialog("dialogShareNote", { title: "分享笔记本给好友-" + title }); - setTimeout(function() { + showDialog("dialogShareNote", {title: "分享笔记本给好友-" + title}); + setTimeout(function () { $("#friendsEmail").focus(); }, 500); var notebookId = $(target).attr("notebookId"); @@ -849,7 +854,7 @@ Notebook.shareNotebooks = function(target) { //----------------------------- // 设为blog/unset -Notebook.setNotebook2Blog = function(target) { +Notebook.setNotebook2Blog = function (target) { var notebookId = $(target).attr("notebookId"); var notebook = Notebook.cache[notebookId]; var isBlog = true; @@ -867,7 +872,7 @@ Notebook.setNotebook2Blog = function(target) { // 如果当前在所有笔记本下 } else if (Notebook.curNotebookId == Notebook.allNotebookId) { - $("#noteItemList .item").each(function() { + $("#noteItemList .item").each(function () { var noteId = $(this).attr("noteId"); var note = Note.cache[noteId]; if (note.NotebookId == notebookId) { @@ -876,11 +881,11 @@ Notebook.setNotebook2Blog = function(target) { } }); } - ajaxPost("/notebook/setNotebook2Blog", { notebookId: notebookId, isBlog: isBlog }, function(ret) { + ajaxPost("/notebook/setNotebook2Blog", {notebookId: notebookId, isBlog: isBlog}, function (ret) { if (ret) { // 这里要设置notebook下的note的blog状态 Note.setAllNoteBlogStatus(notebookId, isBlog); - Notebook.setCache({ NotebookId: notebookId, IsBlog: isBlog }); + Notebook.setCache({NotebookId: notebookId, IsBlog: isBlog}); } }); } @@ -888,7 +893,7 @@ Notebook.setNotebook2Blog = function(target) { // 添加, 修改完后都要对notebook的列表重新计算 TODO // 修改笔记本标题 -Notebook.updateNotebookTitle = function(target) { +Notebook.updateNotebookTitle = function (target) { var self = Notebook; var notebookId = $(target).attr("notebookId"); @@ -899,7 +904,7 @@ Notebook.updateNotebookTitle = function(target) { } }; Notebook.subNotebookDirtyOrNew = {}; // notebookId => {dirty: new: } -Notebook.setDirtyOrNew = function(notebookId, isDirty, isNew) { +Notebook.setDirtyOrNew = function (notebookId, isDirty, isNew) { if (this._setDirtyOrNew(notebookId, isDirty, isNew)) { if (this.subNotebookDirtyOrNew[notebookId]) { delete this.subNotebookDirtyOrNew[notebookId]; @@ -907,11 +912,11 @@ Notebook.setDirtyOrNew = function(notebookId, isDirty, isNew) { } // 没找到, 可能是子笔记本, 还没展开 else { - this.subNotebookDirtyOrNew[notebookId] = { isDirty: isDirty, isNew: isNew }; + this.subNotebookDirtyOrNew[notebookId] = {isDirty: isDirty, isNew: isNew}; } }; -Notebook.setDirtyOrNewForSub = function(notebookId, isDirty, isNew) { +Notebook.setDirtyOrNewForSub = function (notebookId, isDirty, isNew) { var d = this.subNotebookDirtyOrNew[notebookId]; if (!d) { return; @@ -919,7 +924,7 @@ Notebook.setDirtyOrNewForSub = function(notebookId, isDirty, isNew) { this._setDirtyOrNew(notebookId, d.isDirty, d.isNew); }; -Notebook._setDirtyOrNew = function(notebookId, isDirty, isNew) { +Notebook._setDirtyOrNew = function (notebookId, isDirty, isNew) { var $o = $('#' + notebookId + '_a'); if ($o.length) { isDirty ? $o.addClass('nb-dirty') : $o.removeClass('nb-dirty'); @@ -929,10 +934,10 @@ Notebook._setDirtyOrNew = function(notebookId, isDirty, isNew) { return false; }; -Notebook.doUpdateNotebookTitle = function(notebookId, newTitle) { +Notebook.doUpdateNotebookTitle = function (notebookId, newTitle) { var self = Notebook; newTitle = trimTitle(newTitle); - NotebookService.updateNotebookTitle(notebookId, newTitle, function() { + NotebookService.updateNotebookTitle(notebookId, newTitle, function () { // 修改缓存 Notebook.cache[notebookId].Title = newTitle; // 改变nav @@ -950,7 +955,7 @@ Notebook.doUpdateNotebookTitle = function(notebookId, newTitle) { }; // 修改标题 for sync -Notebook.renderUpdateNoteTitle = function(notebookId, newTitle) { +Notebook.renderUpdateNoteTitle = function (notebookId, newTitle) { var self = this; // 修改缓存 if (!Notebook.cache[notebookId]) { @@ -979,20 +984,20 @@ Notebook.renderUpdateNoteTitle = function(notebookId, newTitle) { // 1 确保是展开的 // 2 在所有后面添加
  • Notebook.addNotebookSeq = 1; // inputId -Notebook.addNotebook = function() { +Notebook.addNotebook = function () { var self = Notebook; if ($("#myNotebooks").hasClass("closed")) { $("#myNotebooks .folderHeader").trigger("click"); } // 添加并修改 - self.tree.addNodes(null, { Title: "", NotebookId: getObjectId(), IsNew: true }, true, true); + self.tree.addNodes(null, {Title: "", NotebookId: getObjectId(), IsNew: true}, true, true); } // rename 调用 -Notebook.doAddNotebook = function(notebookId, title, parentNotebookId) { +Notebook.doAddNotebook = function (notebookId, title, parentNotebookId) { var self = Notebook; - Service.notebookService.addNotebook(notebookId, title, parentNotebookId, function(ret) { + Service.notebookService.addNotebook(notebookId, title, parentNotebookId, function (ret) { if (ret.NotebookId) { Notebook.cache[ret.NotebookId] = ret; var notebook = self.tree.getNodeByTId(notebookId); @@ -1010,7 +1015,7 @@ Notebook.doAddNotebook = function(notebookId, title, parentNotebookId) { //------------- // 添加子笔记本 -Notebook.addChildNotebook = function(target) { +Notebook.addChildNotebook = function (target) { var self = Notebook; if ($("#myNotebooks").hasClass("closed")) { $("#myNotebooks .folderHeader").trigger("click"); @@ -1019,12 +1024,23 @@ Notebook.addChildNotebook = function(target) { var notebookId = $(target).attr("notebookId"); // 添加并修改 - self.tree.addNodes(self.tree.getNodeByTId(notebookId), { Title: "", NotebookId: getObjectId(), IsNew: true }, false, true); + self.tree.addNodes(self.tree.getNodeByTId(notebookId), {Title: "", NotebookId: getObjectId(), IsNew: true}, false, true); +} + +Notebook.addChildNotebookDir = function (parentNotebookId, title) { + var self = Notebook; + var notebookId = getObjectId(); + // isSilent must be true and isNew must be false otherwise subDir name will be undefined + self.tree.addNodes(self.tree.getNodeByTId(parentNotebookId), + {Title: title, NotebookId: notebookId, IsNew: true}, true, false); + // save to db + Notebook.doAddNotebook(notebookId, title, parentNotebookId); + return notebookId; } //------------- // 删除 -Notebook.deleteNotebook = function(target) { +Notebook.deleteNotebook = function (target) { var self = Notebook; var notebookId = $(target).attr("notebookId"); @@ -1038,7 +1054,7 @@ Notebook.deleteNotebook = function(target) { alert('This notebook has sub notebooks, please delete sub notebooks firstly.'); return; } - NotebookService.deleteNotebook(notebookId, function(ok, msg) { + NotebookService.deleteNotebook(notebookId, function (ok, msg) { if (!ok) { alert(msg || "error"); return; @@ -1046,7 +1062,7 @@ Notebook.deleteNotebook = function(target) { self.deleteNotebookFromTree(notebookId); }) }; -Notebook.deleteNotebookFromTree = function(notebookId) { +Notebook.deleteNotebookFromTree = function (notebookId) { var self = this; self.tree.removeNode(self.tree.getNodeByTId(notebookId)); if (self.tree2) { @@ -1058,10 +1074,10 @@ Notebook.deleteNotebookFromTree = function(notebookId) { }; // 清空垃圾 -Notebook.clearTrash = function() { +Notebook.clearTrash = function () { var me = this; if (confirm(getMsg('Are you sure ?'))) { - NoteService.clearTrash(function() { + NoteService.clearTrash(function () { if (Notebook.curNotebookId == Notebook.trashNotebookId) { Note.clearAll(); Note.showEditorMask(); @@ -1075,34 +1091,34 @@ Notebook.clearTrash = function() { //---------------------- // 冲突解决, 增量sync时 // note是服务器端的笔记, newNote是本地复制后的笔记 -Notebook.fixSyncConflict = function(note, newNote) { +Notebook.fixSyncConflict = function (note, newNote) { // Note.cache[note.NoteId] = note; // Note.cache[newNote.NoteId] = newNote; /* - Note.addNoteCache(note); - Note.addNoteCache(newNote); - - var target = $(tt('[noteId="?"]', note.NoteId)); // - // 如果当前笔记在笔记列表中, 那么生成一个新笔记放在这个笔记上面 - if(target.length > 0) { - var newHtmlObject = Note._getNoteHtmlObjct(note); - newHtmlObject.insertBefore(target); - } - // 当前这个换成新复制的 - target.attr('noteId', newNote.NoteId); - // 重新render 左侧下, 因为有冲突了, 不要render内容啊 - - // 如果当前编辑的是这个笔记, 那切换到newNote上来 - if(Note.curNoteId == note.NoteId) { - Note.curNoteId = newNote.NoteId; - } - */ + Note.addNoteCache(note); + Note.addNoteCache(newNote); + + var target = $(tt('[noteId="?"]', note.NoteId)); // + // 如果当前笔记在笔记列表中, 那么生成一个新笔记放在这个笔记上面 + if(target.length > 0) { + var newHtmlObject = Note._getNoteHtmlObjct(note); + newHtmlObject.insertBefore(target); + } + // 当前这个换成新复制的 + target.attr('noteId', newNote.NoteId); + // 重新render 左侧下, 因为有冲突了, 不要render内容啊 + + // 如果当前编辑的是这个笔记, 那切换到newNote上来 + if(Note.curNoteId == note.NoteId) { + Note.curNoteId = newNote.NoteId; + } + */ }; // push // 本地 -> 添加到服务器上的 // 前端取消dirty -Notebook.addChanges = function(notebooks) { +Notebook.addChanges = function (notebooks) { var me = this; if (isEmpty(notebooks)) { return; @@ -1112,15 +1128,15 @@ Notebook.addChanges = function(notebooks) { me.setDirtyOrNew(notebook.NotebookId, false, false); } }; -Notebook.updateChanges = function(notebooks) { +Notebook.updateChanges = function (notebooks) { this.addChanges(notebooks); }; // 服务器adds/updates后, 一起渲染 -Notebook.reload = function() { +Notebook.reload = function () { var me = this; var curNotebookId = Notebook.curNotebookId; - NotebookService.getNotebooks(function(notebooks) { + NotebookService.getNotebooks(function (notebooks) { me.renderNotebooks(notebooks, true); // 定位到某个笔记本下 @@ -1135,7 +1151,7 @@ Notebook.reload = function() { // notebooks // <- server 服务器端添加过来的 // ? 如果是子先添加了, 再父添加呢? -Notebook.addSync = function(notebooks) { +Notebook.addSync = function (notebooks) { var me = this; if (isEmpty(notebooks)) { return; @@ -1144,14 +1160,14 @@ Notebook.addSync = function(notebooks) { for (var i = 0; i < notebooks.length; ++i) { var notebook = notebooks[i]; Notebook.setCache(notebook); - me.tree.addNodes(me.tree.getNodeByTId(notebook.ParentNotebookId), { Title: notebook.Title, NotebookId: notebook.NotebookId, IsNew: false }, // IsNew: false啊!!! + me.tree.addNodes(me.tree.getNodeByTId(notebook.ParentNotebookId), {Title: notebook.Title, NotebookId: notebook.NotebookId, IsNew: false}, // IsNew: false啊!!! true, true, false); } }; // 弃用, 一起渲染 reload // 更新 // 不对移动做修改, 只修改标题 -Notebook.updateSync = function(notebooks) { +Notebook.updateSync = function (notebooks) { var me = this; if (isEmpty(notebooks)) { return; @@ -1164,13 +1180,13 @@ Notebook.updateSync = function(notebooks) { me.renderUpdateNoteTitle(notebook.NotebookId, notebook.Title); } else { Notebook.setCache(notebook); - me.tree.addNodes(me.tree.getNodeByTId(notebook.ParentNotebookId), { Title: notebook.Title, NotebookId: notebook.NotebookId, IsNew: true }, true, true, false); + me.tree.addNodes(me.tree.getNodeByTId(notebook.ParentNotebookId), {Title: notebook.Title, NotebookId: notebook.NotebookId, IsNew: true}, true, true, false); } } }; // 删除 -Notebook.deleteSync = function(notebooks) { +Notebook.deleteSync = function (notebooks) { var me = this; if (isEmpty(notebooks)) { return; @@ -1185,17 +1201,17 @@ Notebook.deleteSync = function(notebooks) { // 初始化 -Notebook.init = function() { +Notebook.init = function () { //------------------- // 点击notebook /* - $("#myNotebooks").on("click", "ul.folderBody li a", function() { - var notebookId = $(this).attr("notebookId"); - Notebook.changeNotebook(notebookId); - }); - */ + $("#myNotebooks").on("click", "ul.folderBody li a", function() { + var notebookId = $(this).attr("notebookId"); + Notebook.changeNotebook(notebookId); + }); + */ // min - $("#minNotebookList").on("click", "li", function() { + $("#minNotebookList").on("click", "li", function () { var notebookId = $(this).find("a").attr("notebookId"); Notebook.changeNotebook(notebookId); }); @@ -1209,19 +1225,19 @@ Notebook.init = function() { this.menu = new gui.Menu(); this.addSub = new gui.MenuItem({ label: getMsg('Add sub notebook'), - click: function(e) { + click: function (e) { Notebook.addChildNotebook(me.target); } }); this.rename = new gui.MenuItem({ label: getMsg('Rename'), - click: function(e) { + click: function (e) { Notebook.updateNotebookTitle(me.target); } }); this.del = new gui.MenuItem({ label: getMsg('Delete'), - click: function(e) { + click: function (e) { Notebook.deleteNotebook(me.target); } }); @@ -1236,10 +1252,10 @@ Notebook.init = function() { var importSubmenus = new gui.Menu(); for (var i = 0; i < importMenus.length; ++i) { - (function(j) { + (function (j) { var clickCallback = importMenus[j].click; if (clickCallback) { - importMenus[i].click = function() { + importMenus[i].click = function () { var notebookId = $(me.target).attr("notebookId"); var notebook = Notebook.getNotebook(notebookId); clickCallback(notebook); @@ -1261,14 +1277,14 @@ Notebook.init = function() { var exportsSubMenus = new gui.Menu(); var exportMenus = Api.getExportMenusForNotebook() || []; for (var i = 0; i < exportMenus.length; ++i) { - (function(j) { + (function (j) { var menu = exportMenus[j]; var clickBac = menu.click; var menuItem = new gui.MenuItem({ label: menu.label, - click: function(e) { + click: function (e) { var notebookId = $(me.target).attr('notebookId'); clickBac && clickBac(notebookId); } @@ -1283,16 +1299,17 @@ Notebook.init = function() { this.exports = new gui.MenuItem({ label: getMsg('Export notes'), submenu: exportsSubMenus, - click: function(e) {} + click: function (e) { + } }); this.menu.append(this.exports); } - this.enable = function(name, ok) { + this.enable = function (name, ok) { this[name].enabled = ok; } - this.popup = function(e, target, isSearch) { + this.popup = function (e, target, isSearch) { me.target = target; var notebookId = $(target).attr("notebookId"); if (Notebook.isTrashNotebookId(notebookId)) { @@ -1308,12 +1325,12 @@ Notebook.init = function() { } // 是否已公开为blog /* - if(!notebook.IsBlog) { - items.push("unset2Blog"); - } else { - items.push("set2Blog"); - } - */ + if(!notebook.IsBlog) { + items.push("unset2Blog"); + } else { + items.push("set2Blog"); + } + */ // 是否还有笔记 if (Note.notebookHasNotes(notebookId)) { this.del.enabled = false; @@ -1328,6 +1345,7 @@ Notebook.init = function() { this.menu.popup(gui.getCurrentWindow(), e.originalEvent.x, e.originalEvent.y); } } + var newNotebookListMenuSys = new newNotebookListMenu(); // 清空回收站 @@ -1337,38 +1355,39 @@ Notebook.init = function() { this.menu = new gui.Menu(); this.clear = new gui.MenuItem({ label: 'Clear trash', - click: function(e) { + click: function (e) { Notebook.clearTrash(); } }); this.menu.append(this.clear); - this.popup = function(e, target) { + this.popup = function (e, target) { this.menu.popup(gui.getCurrentWindow(), e.originalEvent.x, e.originalEvent.y); } } + var newClearTrashMenuSys = new newClearTrashMenu(); // 添加笔记本 - $("#addNotebookPlus").click(function(e) { + $("#addNotebookPlus").click(function (e) { e.stopPropagation(); Notebook.addNotebook(); }); // notebook setting - $("#notebookList").on("click", ".notebook-setting", function(e) { + $("#notebookList").on("click", ".notebook-setting", function (e) { e.preventDefault(); e.stopPropagation(); var $p = $(this).parent(); newNotebookListMenuSys.popup(e, $p); }); - $("#notebookList").on('contextmenu', 'li a', function(e) { + $("#notebookList").on('contextmenu', 'li a', function (e) { newNotebookListMenuSys.popup(e, $(this)); }); - $("#notebookListForSearch").on('contextmenu', 'li a', function(e) { + $("#notebookListForSearch").on('contextmenu', 'li a', function (e) { newNotebookListMenuSys.popup(e, $(this), true); }); - $("#notebookListForSearch").on("click", ".notebook-setting", function(e) { + $("#notebookListForSearch").on("click", ".notebook-setting", function (e) { e.preventDefault(); e.stopPropagation(); var $p = $(this).parent(); diff --git a/public/js/app/service.js b/public/js/app/service.js index 7fe51a6d9..907ff4027 100644 --- a/public/js/app/service.js +++ b/public/js/app/service.js @@ -11,12 +11,12 @@ var db = require('db'); db.initGlobal(); // 所有service, 与数据库打交道 var Service = { - notebookService: require('notebook'), - noteService: require('note'), - userService: require('user'), - tagService: require('tag'), - apiService: require('api'), - syncServie: require('sync') + notebookService: require('notebook'), + noteService: require('note'), + userService: require('user'), + tagService: require('tag'), + apiService: require('api'), + syncServie: require('sync') }; // 全局变量 var ApiService = Service.apiService; @@ -32,11 +32,13 @@ var CommonService = require('common'); // NodeJs var NodeFs = require('fs'); +var Path = require('path'); // 分发服务 // route = /note/notebook // 过时 -Service.dispatch = function() {}; +Service.dispatch = function () { +}; var gui = require('gui'); // var remote = require('remote'); diff --git a/public/plugins/export_leanote/plugin.js b/public/plugins/export_leanote/plugin.js index d506a7df2..c98936b4d 100644 --- a/public/plugins/export_leanote/plugin.js +++ b/public/plugins/export_leanote/plugin.js @@ -24,592 +24,766 @@ ] } - * + * */ -define(function() { - var async; // = require('async'); - var resanitize; // = require('resanitize'); - - //=========== - // start - - var exportLeanote = { - langs: { - 'en-us': { - 'export': 'Export Leanote', - 'Exporting': 'Exporting', - 'Exporting: ': 'Exporting: ', - 'exportSuccess': 'Leanote saved successful!', - 'exportFailure': 'Leanote saved failure!', - 'notExists': 'Please sync your note to ther server firslty.' - }, - 'de-de': { - 'export': 'Als Leanote exportieren', - 'Exporting': 'Exportiere', - 'Exporting: ': 'Exportiere: ', - 'exportSuccess': 'Leanote erfolgreich gespeichert!', - 'exportFailure': 'Leanote speichern fehlgeschlagen!', - 'notExists': 'Bitte Notizen zuerst mit dem Server synchronisieren.' - }, - 'zh-cn': { - 'export': '导出Leanote', - 'Exporting': '正在导出', - 'Exporting: ': '正在导出: ', - 'exportSuccess': 'Leanote导出成功!', - 'exportFailure': 'Leanote导出失败!' - }, - 'zh-hk': { - 'export': '導出Leanote', - 'Exporting': '正在導出', - 'Exporting: ': '正在導出: ', - 'exportSuccess': 'Leanote導出成功!', - 'exportFailure': 'Leanote導出失敗!' - } - }, - - _inited: false, - init: function() { - var me = this; - if (me._inited) { - return; - } - - async = require('async'); - resanitize = require('resanitize'); - - me._inited = true; - }, - - replaceAll: function(src, pattern, to) { - if(!src) { - return src; - } - while(true) { - var oldSrc = src; - src = src.replace(pattern, to); - if(oldSrc === src) { - return src; - } - } - }, - - fixFilename: function(filename) { - var reg = new RegExp("/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\", 'g'); - filename = filename.replace(reg, "-"); - // 防止出现两个连续的- - while(filename.indexOf('--') != -1) { - filename = this.replaceAll(filename, '--', '-'); - } - if (filename.length > 1) { - // 最后一个- - filename = filename.replace(/\-$/, ''); - } - return filename; - }, - - 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','label','layer','legend','link','marquee','menu','meta','noframes', - 'noscript','object','optgroup','option','param','plaintext','script','select','style','textarea','xml'] - ); - return content; - }, - - getLeanoteTime: function(t) { - // 20151026T033928Z - // 2015 10 26 T 03 39 28 Z - // console.log(t); - if (!t) { - t = new Date(); - } - if (typeof t != 'object' || !('getTime' in t)) { - try { - t = new Date(t); - } - catch(e) { - t = new Date(); - } - } - return t.format("yyyy-MM-dd hh:mm:ss"); - }, - - render: function(note, callback) { - var me = this; - var appVersion = Api.getCurVersion() || {version: 'unknown'}; - var info = { - exportDate: me.getLeanoteTime(), - app: 'leanote.desktop.app.' + process.platform, - appVersion: appVersion.version, - apiVersion: '0.1', - notes: [] - } - me.fixFiles(note, function (content, files) { - // 非markdown才需要这样, 补全html标签 - if (!note.IsMarkdown) { - content = $('
    ' + content + '
    ').html(); - } - - var filesArr = []; - files || (files = {}); - for (var fileId in files) { - if (files.hasOwnProperty(fileId)) { - files[fileId].fileId = fileId; - filesArr.push(files[fileId]); - } - } - - var noteInfo = { - title: note.Title, - content: !note.IsMarkdown ? me.fixContent(content) : content, - tags: note.Tags, - author: Api.userService.email || Api.userService.username || '', - isMarkdown: note.IsMarkdown, - createdTime: me.getLeanoteTime(note.CreatedTime), - updatedTime: me.getLeanoteTime(note.UpdatedTime), - files: filesArr - }; - info.notes.push(noteInfo); - callback(JSON.stringify(info, null, 2)); - /* - enml.ENMLOfHTML(content, function(err, ENML) { - if (err) { - info.content = content; - } - else { - info.content = ENML; - } - - if (note.IsMarkdown) { - info.content = '
    ' + info.content + '
    '; - } - - callback(me.renderTpl(tpl, info, keys)); - }); - */ - }); - }, - - findAllImages: function (note) { - var content = note.Content; - var allMatchs = []; - - // markdown下 - // [](http://localhost://fileId=32); - if (note.IsMarkdown) { - var reg = new RegExp('!\\[([^\\]]*?)\\]\\(' + Api.evtService.getImageLocalUrlPrefix() + '\\?fileId=([0-9a-zA-Z]{24})\\)', 'g'); - var matches = reg.exec(content); - while(matches) { - var all = matches[0]; - var title = matches[1]; // img与src之间 - var fileId = matches[2]; - allMatchs.push({ - fileId: fileId, - title: title, - all: all - }); - // 下一个 - matches = reg.exec(content); - } - } - else { - var reg = new RegExp(']*?)src=["\']?' + Api.evtService.getImageLocalUrlPrefix() + '\\?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); - } - } - - return allMatchs; - }, - - findAllAttachs: function (note) { - var content = note.Content; - - var allMatchs = []; - // markdown下 - // ![](http://localhost://fileId=32); - if (note.IsMarkdown) { - var reg = new RegExp('\\[([^\\]]*?)\\]\\(' + Api.evtService.getAttachLocalUrlPrefix() + '\\?fileId=([0-9a-zA-Z]{24})\\)', 'g'); - var matches = reg.exec(content); - while(matches) { - var all = matches[0]; - var title = matches[1]; // img与src之间 - var fileId = matches[2]; - allMatchs.push({ - fileId: fileId, - title: title, - all: all, - isAttach: true - }); - // 下一个 - matches = reg.exec(content); - } - } - else { - var reg = new RegExp(']*?)href=["\']?' + Api.evtService.getAttachLocalUrlPrefix() + '\\?fileId=([0-9a-zA-Z]{24})["\']?(.*?)>([^<]*)', '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); - } - } - return allMatchs; - }, - - fixFiles: function (note, callback) { - var me = this; - - var content = note.Content; - - var allImages = me.findAllImages(note) || []; - var allAttachs = me.findAllAttachs(note) || []; - - var allMatchs = allImages.concat(allAttachs); - - if (allMatchs.length == 0) { - callback(content, []); - return; - } - - var files = {}; // fileId => {} - - function replaceContent () { - for (var i = 0; i < allMatchs.length; ++i) { - var eachMatch = allMatchs[i]; - var fileInfo = files[eachMatch.fileId]; - - var link; - if (!fileInfo) { - link = ''; - } - else { - if (note.IsMarkdown) { - var href; - if (!eachMatch.isAttach) { - href = 'leanote://file/getImage?fileId=' + eachMatch.fileId; - link = '![' + eachMatch.title + '](' + href + ')'; - } - else { - href = 'leanote://file/getAttach?fileId=' + eachMatch.fileId; - link = '[' + eachMatch.title + '](' + href + ')'; - } - } - else { - if (!eachMatch.isAttach) { - var href = 'leanote://file/getImage?fileId=' + eachMatch.fileId; - link = ''; - } - else { - var href = 'leanote://file/getAttach?fileId=' + eachMatch.fileId; - link = '' + eachMatch.title + ''; - } - } - } - - content = content.replace(eachMatch.all, link); - } - } - - // 附件 - var attachs = note.Attachs || []; - for (var i = 0; i < attachs.length; ++i) { - var attach = attachs[i]; - var base64AndMd5 = Api.fileService.getFileBase64AndMd5(attach.Path); - if (base64AndMd5) { - files[attach.FileId] = { - base64: base64AndMd5.base64, - md5: base64AndMd5.md5, - type: attach.Type, - title: attach.Title, - createdTime: me.getLeanoteTime(attach.UpdatedTime || attach.CreatedTime), - isAttach: true - } - } - } - - // 得到图片资源 - var fileIdFixed = {}; - async.eachSeries(allImages, function(eachMatch, cb) { - var fileId = eachMatch.fileId; - if (fileIdFixed[fileId]) { - cb(); - return; - } - - Api.fileService.getImageInfo(fileId, function(err, doc) { - fileIdFixed[fileId] = true; - if(doc) { - var base64AndMd5 = Api.fileService.getFileBase64AndMd5(doc.Path); - if (base64AndMd5) { - files[doc.FileId] = { - base64: base64AndMd5.base64, - md5: base64AndMd5.md5, - type: doc.Type, - title: doc.Title, - createdTime: me.getLeanoteTime(doc.UpdatedTime || doc.CreatedTime), - } - } - cb(); - } - else { - cb(); - } - }); - - }, function () { - replaceContent(); - callback(content, files); - }); - }, - - //-------------- - - // 得到可用的文件名, 避免冲突 - getExportedFilePath: function(pathInfo, n, cb) { - var me = this; - if(n > 1) { - pathInfo.nameNotExt = pathInfo.nameNotExtRaw + '-' + n; - } - var absPath = pathInfo.getFullPath(); - - // Api.nodeFs.existsSync(absPath) 总是返回false, 不知道什么原因 - // 在控制台上是可以的 - Api.nodeFs.exists(absPath, function(exists) { - if(!exists) { - cb(absPath); - } - else { - me.getExportedFilePath(pathInfo, n+1, cb); - } - }); - }, - - getTargetPath: function(callback) { - // showSaveDialog 不支持property选择文件夹 - Api.gui.dialog.showOpenDialog(Api.gui.getCurrentWindow(), - { - defaultPath: Api.gui.app.getPath('userDesktop') + '/', - properties: ['openDirectory'] - }, - function(targetPath) { - callback(targetPath); - } - ); - }, - - loadingIsClosed: false, - - exportLeanoteForNotebook: function (notebookId) { - var me = this; - if (!notebookId) { - return; - } - me.getTargetPath(function(targetPath) { - if (!targetPath) { - return; - } - - me.loadingIsClosed = false; - Api.loading.show(Api.getMsg('plugin.export_leanote.Exporting'), - { - hasProgress: true, - isLarge: true, - onClose: function () { - me.loadingIsClosed = true; - setTimeout(function() { - me.hideLoading(); - }); - }}); - Api.loading.setProgress(1); - - Api.noteService.getNotes(notebookId, function(notes) { - if (!notes) { - me.hideLoading(); - return; - } - - var total = notes.length; - var i = 0; - async.eachSeries(notes, function(note, cb) { - if (me.loadingIsClosed) { - cb(); - me.hideLoading(); - return; - } - i++; - Api.loading.setProgress(100 * i / total); - me._exportLeanote(note, targetPath, function() { - cb(); - }, i, total); - }, function() { - me.hideLoading(); - Notify.show({title: 'Info', body: getMsg('plugin.export_leanote.exportSuccess')}); - }); - }); - }); - }, - - hideLoading: function () { - setTimeout(function () { - Api.loading.hide(); - }, 1000); - }, - - exportLeanote: function (noteIds) { - var me = this; - if (!noteIds || noteIds.length == 0) { - return; - } - me.getTargetPath(function(targetPath) { - if (!targetPath) { - return; - } - - me.loadingIsClosed = false; - Api.loading.show(Api.getMsg('plugin.export_leanote.Exporting'), - { - hasProgress: true, - isLarge: true, - onClose: function () { - me.loadingIsClosed = true; - setTimeout(function() { - me.hideLoading(); - }); - }}); - Api.loading.setProgress(1); - - var i = 0; - var total = noteIds.length; - - async.eachSeries(noteIds, function(noteId, cb) { - if (me.loadingIsClosed) { - cb(); - return; - } - - i++; - Api.loading.setProgress(100 * i / total); - Api.noteService.getNote(noteId, function(note) { - me._exportLeanote(note, targetPath, function() { - cb(); - }, i, total); - }); - - }, function () { - me.hideLoading(); - Notify.show({title: 'Info', body: getMsg('plugin.export_leanote.exportSuccess')}); - }); - }); - }, - - _exportLeanote: function(note, path, callback, i, total) { - var me = this; - if(!note) { - return; - } - - if (me.loadingIsClosed) { - callback(); - return; - } - - setTimeout(function () { - Api.loading.setMsg(Api.getMsg('plugin.export_leanote.Exporting: ') + (note.Title || getMsg('Untitled'))); - Api.loading.setProgressRate(i + '/' + total); - }, 100); - - var name = note.Title ? note.Title + '.leanote' : getMsg('Untitled') + '.leanote'; - name = me.fixFilename(name); - - var targetPath = path + Api.commonService.getPathSep() + name; - - // 将路径和名字区分开 - var pathInfo = Api.commonService.splitFile(targetPath); - pathInfo.nameNotExt = me.fixFilename(pathInfo.nameNotExt); // 重新修正一次 - var nameNotExt = pathInfo.nameNotExt; - pathInfo.nameNotExtRaw = pathInfo.nameNotExt; - - // 得到可用文件的绝对路径 - me.getExportedFilePath(pathInfo, 1, function(absLeanoteFilePath) { - me.render(note, function (content) { - Api.commonService.writeFile(absLeanoteFilePath, content); - callback(); - }); - }); - }, - - // 打开前要执行的 - onOpen: function() { - var me = this; - var gui = Api.gui; - - var menu = { - label: Api.getMsg('plugin.export_leanote.export'), - enabled: function(noteIds) { - return true; - }, - click: (function() { - return function(noteIds) { - me.init(); - me.exportLeanote(noteIds); - } - })() - }; - Api.addExportMenu(menu); - - Api.addExportMenuForNotebook({ - label: Api.getMsg('plugin.export_leanote.export'), - enabled: function(notebookId) { - return true; - }, - click: (function() { - return function(notebookId) { - me.init(); - me.exportLeanoteForNotebook(notebookId); - } - })() - }); - }, - // 打开后 - onOpenAfter: function() { - }, - // 关闭时需要运行的 - onClose: function() { - } - }; - - return exportLeanote; -}); +define(function () { + var async; // = require('async'); + var resanitize; // = require('resanitize'); + + //=========== + // start + + var exportLeanote = { + langs: { + 'en-us': { + 'export': 'Export Leanote', + 'exportAll': 'Recursive Export Leanote', + 'Exporting': 'Exporting', + 'Exporting: ': 'Exporting: ', + 'exportSuccess': 'Leanote saved successful!', + 'exportFailure': 'Leanote saved failure!', + 'notExists': 'Please sync your note to ther server firslty.' + }, + 'de-de': { + 'export': 'Als Leanote exportieren', + 'exportAll': 'Exportation récursive', + 'Exporting': 'Exportiere', + 'Exporting: ': 'Exportiere: ', + 'exportSuccess': 'Leanote erfolgreich gespeichert!', + 'exportFailure': 'Leanote speichern fehlgeschlagen!', + 'notExists': 'Bitte Notizen zuerst mit dem Server synchronisieren.' + }, + 'zh-cn': { + 'export': '导出Leanote', + 'exportAll': '递归导出Leanote', + 'Exporting': '正在导出', + 'Exporting: ': '正在导出: ', + 'exportSuccess': 'Leanote导出成功!', + 'exportFailure': 'Leanote导出失败!' + }, + 'zh-hk': { + 'export': '導出Leanote', + 'exportAll': '遞歸導出Leanote', + 'Exporting': '正在導出', + 'Exporting: ': '正在導出: ', + 'exportSuccess': 'Leanote導出成功!', + 'exportFailure': 'Leanote導出失敗!' + } + }, + + _inited: false, + init: function () { + var me = this; + if (me._inited) { + return; + } + + async = require('async'); + resanitize = require('resanitize'); + + me._inited = true; + }, + + replaceAll: function (src, pattern, to) { + if (!src) { + return src; + } + while (true) { + var oldSrc = src; + src = src.replace(pattern, to); + if (oldSrc === src) { + return src; + } + } + }, + + fixFilename: function (filename) { + var reg = new RegExp("/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\", 'g'); + filename = filename.replace(reg, "-"); + // 防止出现两个连续的- + while (filename.indexOf('--') != -1) { + filename = this.replaceAll(filename, '--', '-'); + } + if (filename.length > 1) { + // 最后一个- + filename = filename.replace(/\-$/, ''); + } + return filename; + }, + + 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', 'label', 'layer', + 'legend', 'link', 'marquee', 'menu', 'meta', 'noframes', + 'noscript', 'object', 'optgroup', 'option', 'param', 'plaintext', + 'script', 'select', 'style', 'textarea', 'xml'] + ); + return content; + }, + + getLeanoteTime: function (t) { + // 20151026T033928Z + // 2015 10 26 T 03 39 28 Z + // console.log(t); + if (!t) { + t = new Date(); + } + if (typeof t != 'object' || !('getTime' in t)) { + try { + t = new Date(t); + } + catch (e) { + t = new Date(); + } + } + return t.format("yyyy-MM-dd hh:mm:ss"); + }, + + render: function (note, callback) { + var me = this; + var appVersion = Api.getCurVersion() || {version: 'unknown'}; + var info = { + exportDate: me.getLeanoteTime(), + app: 'leanote.desktop.app.' + process.platform, + appVersion: appVersion.version, + apiVersion: '0.1', + notes: [] + } + me.fixFiles(note, function (content, files) { + // 非markdown才需要这样, 补全html标签 + if (!note.IsMarkdown) { + content = $('
    ' + content + '
    ').html(); + } + + var filesArr = []; + files || (files = {}); + for (var fileId in files) { + if (files.hasOwnProperty(fileId)) { + files[fileId].fileId = fileId; + filesArr.push(files[fileId]); + } + } + + var noteInfo = { + title: note.Title, + content: !note.IsMarkdown ? me.fixContent(content) : content, + tags: note.Tags, + author: Api.userService.email || Api.userService.username || '', + isMarkdown: note.IsMarkdown, + createdTime: me.getLeanoteTime(note.CreatedTime), + updatedTime: me.getLeanoteTime(note.UpdatedTime), + files: filesArr + }; + info.notes.push(noteInfo); + callback(JSON.stringify(info, null, 2)); + /* + enml.ENMLOfHTML(content, function(err, ENML) { + if (err) { + info.content = content; + } + else { + info.content = ENML; + } + + if (note.IsMarkdown) { + info.content = '
    ' + info.content + '
    '; + } + + callback(me.renderTpl(tpl, info, keys)); + }); + */ + }); + }, + + findAllImages: function (note) { + var content = note.Content; + var allMatchs = []; + + // markdown下 + // [](http://localhost://fileId=32); + if (note.IsMarkdown) { + var reg = new RegExp('!\\[([^\\]]*?)\\]\\(' + + Api.evtService.getImageLocalUrlPrefix() + + '\\?fileId=([0-9a-zA-Z]{24})\\)', 'g'); + var matches = reg.exec(content); + while (matches) { + var all = matches[0]; + var title = matches[1]; // img与src之间 + var fileId = matches[2]; + allMatchs.push({ + fileId: fileId, + title: title, + all: all + }); + // 下一个 + matches = reg.exec(content); + } + } + else { + var reg = new RegExp(']*?)src=["\']?' + + Api.evtService.getImageLocalUrlPrefix() + + '\\?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); + } + } + + return allMatchs; + }, + + findAllAttachs: function (note) { + var content = note.Content; + + var allMatchs = []; + // markdown下 + // ![](http://localhost://fileId=32); + if (note.IsMarkdown) { + var reg = new RegExp('\\[([^\\]]*?)\\]\\(' + + Api.evtService.getAttachLocalUrlPrefix() + + '\\?fileId=([0-9a-zA-Z]{24})\\)', 'g'); + var matches = reg.exec(content); + while (matches) { + var all = matches[0]; + var title = matches[1]; // img与src之间 + var fileId = matches[2]; + allMatchs.push({ + fileId: fileId, + title: title, + all: all, + isAttach: true + }); + // 下一个 + matches = reg.exec(content); + } + } + else { + var reg = new RegExp(']*?)href=["\']?' + + Api.evtService.getAttachLocalUrlPrefix() + + '\\?fileId=([0-9a-zA-Z]{24})["\']?(.*?)>([^<]*)', '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); + } + } + return allMatchs; + }, + + fixFiles: function (note, callback) { + var me = this; + + var content = note.Content; + + var allImages = me.findAllImages(note) || []; + var allAttachs = me.findAllAttachs(note) || []; + + var allMatchs = allImages.concat(allAttachs); + + if (allMatchs.length == 0) { + callback(content, []); + return; + } + + var files = {}; // fileId => {} + + function replaceContent() { + for (var i = 0; i < allMatchs.length; ++i) { + var eachMatch = allMatchs[i]; + var fileInfo = files[eachMatch.fileId]; + + var link; + if (!fileInfo) { + link = ''; + } + else { + if (note.IsMarkdown) { + var href; + if (!eachMatch.isAttach) { + href = 'leanote://file/getImage?fileId=' + eachMatch.fileId; + link = '![' + eachMatch.title + '](' + href + ')'; + } + else { + href = 'leanote://file/getAttach?fileId=' + eachMatch.fileId; + link = '[' + eachMatch.title + '](' + href + ')'; + } + } + else { + if (!eachMatch.isAttach) { + var href = 'leanote://file/getImage?fileId=' + eachMatch.fileId; + link = ''; + } + else { + var href = 'leanote://file/getAttach?fileId=' + + eachMatch.fileId; + link = '' + eachMatch.title + ''; + } + } + } + + content = content.replace(eachMatch.all, link); + } + } + + // 附件 + var attachs = note.Attachs || []; + for (var i = 0; i < attachs.length; ++i) { + var attach = attachs[i]; + var base64AndMd5 = Api.fileService.getFileBase64AndMd5(attach.Path); + if (base64AndMd5) { + files[attach.FileId] = { + base64: base64AndMd5.base64, + md5: base64AndMd5.md5, + type: attach.Type, + title: attach.Title, + createdTime: me.getLeanoteTime( + attach.UpdatedTime || attach.CreatedTime), + isAttach: true + } + } + } + + // 得到图片资源 + var fileIdFixed = {}; + async.eachSeries(allImages, function (eachMatch, cb) { + var fileId = eachMatch.fileId; + if (fileIdFixed[fileId]) { + cb(); + return; + } + + Api.fileService.getImageInfo(fileId, function (err, doc) { + fileIdFixed[fileId] = true; + if (doc) { + var base64AndMd5 = Api.fileService.getFileBase64AndMd5(doc.Path); + if (base64AndMd5) { + files[doc.FileId] = { + base64: base64AndMd5.base64, + md5: base64AndMd5.md5, + type: doc.Type, + title: doc.Title, + createdTime: me.getLeanoteTime( + doc.UpdatedTime || doc.CreatedTime), + } + } + cb(); + } + else { + cb(); + } + }); + + }, function () { + replaceContent(); + callback(content, files); + }); + }, + + //-------------- + + // 得到可用的文件名, 避免冲突 + getExportedFilePath: function (pathInfo, n, cb) { + var me = this; + if (n > 1) { + pathInfo.nameNotExt = pathInfo.nameNotExtRaw + '-' + n; + } + var absPath = pathInfo.getFullPath(); + + // Api.nodeFs.existsSync(absPath) 总是返回false, 不知道什么原因 + // 在控制台上是可以的 + Api.nodeFs.exists(absPath, function (exists) { + if (!exists) { + cb(absPath); + } + else { + me.getExportedFilePath(pathInfo, n + 1, cb); + } + }); + }, + + getTargetPath: function (callback) { + // showSaveDialog 不支持property选择文件夹 + Api.gui.dialog.showOpenDialog(Api.gui.getCurrentWindow(), + { + defaultPath: Api.gui.app.getPath('userDesktop') + '/', + properties: ['openDirectory'] + }, + function (targetPath) { + callback(targetPath); + } + ); + }, + + loadingIsClosed: false, + + dfsExport: function (notebookId, targetPath, processedNoteNum, totalNoteNum) { + var me = this; + if (Api.notebook.getSubNotebooks(notebookId) != false) { + Api.notebook.getSubNotebooks(notebookId).forEach(function (note) { + // mkdir and set path + var subDir = Api.path.join(targetPath, note.Title); + if (Api.nodeFs.existsSync(subDir) == false) { + Api.nodeFs.mkdirSync(subDir); + } + + // dfs + var processPlan = me.dfsExport(note.NotebookId, subDir, + processedNoteNum, totalNoteNum); + processedNoteNum = processPlan[0]; + totalNoteNum = processPlan[1]; + }); + } + + // export + Api.noteService.getNotes(notebookId, function (notes) { + if (!notes) { + me.hideLoading(); + return; + } + + totalNoteNum += notes.length; + async.eachSeries(notes, function (note, cb) { + if (me.loadingIsClosed) { + cb(); + me.hideLoading(); + return; + } + processedNoteNum++; + Api.loading.setProgress(100 * processedNoteNum / totalNoteNum); + me._exportLeanote(note, targetPath, function () { + cb(); + }, processedNoteNum, totalNoteNum); + }, function () { + // close loading only first level allowed + }); + }); + + return [processedNoteNum, totalNoteNum]; + }, + + exportLeanoteForNotebookStructure: function (notebookId) { + var me = this; + if (!notebookId) { + return; + } + + me.getTargetPath(function (targetPath) { + if (!targetPath) { + return; + } + + targetPath = Api.path.join(targetPath[0], + Api.notebook.getNotebook(notebookId).Title); + if (Api.nodeFs.existsSync(targetPath) == false) { + Api.nodeFs.mkdirSync(targetPath); + } + + me.loadingIsClosed = false; + Api.loading.show(Api.getMsg('plugin.export_leanote.Exporting'), + { + hasProgress: true, + isLarge: true, + onClose: function () { + me.loadingIsClosed = true; + setTimeout(function () { + me.hideLoading(); + }); + } + }); + Api.loading.setProgress(1); + var processedNoteNum = 0; + var totalNoteNum = 1; + + // get tree structure only contains dir via notebookId then export notebook recursion + if (Api.notebook.getSubNotebooks(notebookId) != false) { + Api.notebook.getSubNotebooks(notebookId).forEach(function (note) { + // mkdir and set path + var subDir = Api.path.join(targetPath, note.Title); + if (Api.nodeFs.existsSync(subDir) == false) { + Api.nodeFs.mkdirSync(subDir); + } + + // dfs + var processPlan = me.dfsExport(note.NotebookId, subDir, processedNoteNum, totalNoteNum); + processedNoteNum = processPlan[0]; + totalNoteNum = processPlan[1]; + + }); + } + + // export + Api.noteService.getNotes(notebookId, function (notes) { + if (!notes) { + me.hideLoading(); + return; + } + + totalNoteNum += notes.length; + async.eachSeries(notes, function (note, cb) { + if (me.loadingIsClosed) { + cb(); + me.hideLoading(); + return; + } + ++processedNoteNum; + Api.loading.setProgress(100 * processedNoteNum / totalNoteNum); + me._exportLeanote(note, targetPath, function () { + cb(); + }, processedNoteNum, totalNoteNum); + }, function () { + me.hideLoading(); + Notify.show({ + title: 'Info', + body: getMsg('plugin.export_leanote.exportSuccess') + }); + }); + }); + }); + }, + + exportLeanoteForNotebook: function (notebookId) { + var me = this; + if (!notebookId) { + return; + } + me.getTargetPath(function (targetPath) { + if (!targetPath) { + return; + } + + me.loadingIsClosed = false; + Api.loading.show(Api.getMsg('plugin.export_leanote.Exporting'), + { + hasProgress: true, + isLarge: true, + onClose: function () { + me.loadingIsClosed = true; + setTimeout(function () { + me.hideLoading(); + }); + } + }); + Api.loading.setProgress(1); + + Api.noteService.getNotes(notebookId, function (notes) { + if (!notes) { + me.hideLoading(); + return; + } + + var total = notes.length; + var i = 0; + async.eachSeries(notes, function (note, cb) { + if (me.loadingIsClosed) { + cb(); + me.hideLoading(); + return; + } + i++; + Api.loading.setProgress(100 * i / total); + me._exportLeanote(note, targetPath, function () { + cb(); + }, i, total); + }, function () { + me.hideLoading(); + Notify.show({ + title: 'Info', + body: getMsg('plugin.export_leanote.exportSuccess') + }); + }); + }); + }); + }, + + hideLoading: function () { + setTimeout(function () { + Api.loading.hide(); + }, 1000); + }, + + exportLeanote: function (noteIds) { + var me = this; + if (!noteIds || noteIds.length == 0) { + return; + } + me.getTargetPath(function (targetPath) { + if (!targetPath) { + return; + } + + me.loadingIsClosed = false; + Api.loading.show(Api.getMsg('plugin.export_leanote.Exporting'), + { + hasProgress: true, + isLarge: true, + onClose: function () { + me.loadingIsClosed = true; + setTimeout(function () { + me.hideLoading(); + }); + } + }); + Api.loading.setProgress(1); + + var i = 0; + var total = noteIds.length; + + async.eachSeries(noteIds, function (noteId, cb) { + if (me.loadingIsClosed) { + cb(); + return; + } + + i++; + Api.loading.setProgress(100 * i / total); + Api.noteService.getNote(noteId, function (note) { + me._exportLeanote(note, targetPath, function () { + cb(); + }, i, total); + }); + + }, function () { + me.hideLoading(); + Notify.show({ + title: 'Info', + body: getMsg('plugin.export_leanote.exportSuccess') + }); + }); + }); + }, + + _exportLeanote: function (note, path, callback, i, total) { + var me = this; + if (!note) { + return; + } + + if (me.loadingIsClosed) { + callback(); + return; + } + + setTimeout(function () { + Api.loading.setMsg( + Api.getMsg('plugin.export_leanote.Exporting: ') + (note.Title + || getMsg('Untitled'))); + Api.loading.setProgressRate(i + '/' + total); + }, 100); + + var name = note.Title ? note.Title + '.leanote' : getMsg('Untitled') + + '.leanote'; + name = me.fixFilename(name); + + var targetPath = path + Api.commonService.getPathSep() + name; + + // 将路径和名字区分开 + var pathInfo = Api.commonService.splitFile(targetPath); + pathInfo.nameNotExt = me.fixFilename(pathInfo.nameNotExt); // 重新修正一次 + var nameNotExt = pathInfo.nameNotExt; + pathInfo.nameNotExtRaw = pathInfo.nameNotExt; + + // 得到可用文件的绝对路径 + me.getExportedFilePath(pathInfo, 1, function (absLeanoteFilePath) { + me.render(note, function (content) { + Api.commonService.writeFile(absLeanoteFilePath, content); + callback(); + }); + }); + }, + + // 打开前要执行的 + onOpen: function () { + var me = this; + var gui = Api.gui; + + var menu = { + label: Api.getMsg('plugin.export_leanote.export'), + enabled: function (noteIds) { + return true; + }, + click: (function () { + return function (noteIds) { + me.init(); + me.exportLeanote(noteIds); + } + })() + }; + // notebook右键 + Api.addExportMenu(menu); + + // 左侧树形菜单右键 + Api.addExportMenuForNotebook({ + label: Api.getMsg('plugin.export_leanote.export'), + enabled: function (notebookId) { + return true; + }, + click: (function () { + return function (notebookId) { + me.init(); + me.exportLeanoteForNotebook(notebookId); + } + })() + }); + Api.addExportMenuForNotebook({ + label: Api.getMsg('plugin.export_leanote.exportAll'), + enabled: function (notebookId) { + return true; + }, + click: (function () { + return function (notebookId) { + me.init(); + me.exportLeanoteForNotebookStructure(notebookId); + } + })() + }); + } + , + // 打开后 + onOpenAfter: function () { + } + , + // 关闭时需要运行的 + onClose: function () { + } + }; + + return exportLeanote; + } +); diff --git a/public/plugins/import_leanote/plugin.js b/public/plugins/import_leanote/plugin.js index a574005e1..4690e536c 100644 --- a/public/plugins/import_leanote/plugin.js +++ b/public/plugins/import_leanote/plugin.js @@ -3,48 +3,51 @@ * @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', - }, - 'de-de': { - 'importLeanote': 'Leanote Datei importieren', - 'Choose Leanote files(.leanote)': 'Leanote Dateien (.leanote) 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 leanote file ?": "Datei importieren: %s fehlgeschlagen! Ist das eine Leanote Datei?", - "Import: %s Success!": "Import: %s erfolgreich!" - }, - 'zh-cn': { - 'importLeanote': '导入Leanote', - 'Choose Leanote files(.leanote)': '选择Leanote文件(.leanote)', - '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(.leanote)': '選擇Leanote文件(.leanote)', - '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: ` +define(function () { + var importService; // = nodeRequire('./public/plugins/import_leanote/import'); + + var leanote = { + + langs: { + 'en-us': { + 'importLeanote': 'Import Leanote', + }, + 'de-de': { + 'importLeanote': 'Leanote Datei importieren', + 'Choose Leanote files(.leanote)': 'Leanote Dateien (.leanote) auswählen', + 'Choose Leanote directory(contains .leanote)': 'Choisissez le répertoire Leanote (contient .leanote)', + '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 leanote file ?": "Datei importieren: %s fehlgeschlagen! Ist das eine Leanote Datei?", + "Import: %s Success!": "Import: %s erfolgreich!" + }, + 'zh-cn': { + 'importLeanote': '导入Leanote', + 'Choose Leanote files(.leanote)': '选择Leanote文件(.leanote)', + 'Choose Leanote directory(contains .leanote)': '选择Leanote文件夹(.leanote)', + '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(.leanote)': '選擇Leanote文件(.leanote)', + 'Choose Leanote directory(contains .leanote)': '選擇Leanote文件夾(.leanote)', + '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: `