|
| 1 | +/** |
| 2 | + * 导出HTML插件 |
| 3 | + * @author life life@leanote.com |
| 4 | + * 选择目录, 将图片保存到文件夹中, 有个html文件(以笔记名命名) |
| 5 | + * 注意, fs.existsSync总返回false, readFileSync可用 |
| 6 | + */ |
| 7 | +define(function() { |
| 8 | + var async = require('async'); |
| 9 | + |
| 10 | + var exportHTML = { |
| 11 | + langs: { |
| 12 | + 'en-us': { |
| 13 | + 'export': 'Export HTML', |
| 14 | + 'exportSuccess': 'HTML saved successful!', |
| 15 | + 'exportFailure': 'HTML saved failure!', |
| 16 | + 'notExists': 'Please sync your note to ther server firslty.' |
| 17 | + }, |
| 18 | + 'zh-cn': { |
| 19 | + 'export': '导出HTML', |
| 20 | + 'exportSuccess': 'HTML导出成功!', |
| 21 | + 'exportFailure': 'HTML导出失败!' |
| 22 | + }, |
| 23 | + 'zh-hk': { |
| 24 | + 'export': '導出HTML', |
| 25 | + 'exportSuccess': 'HTML導出成功!', |
| 26 | + 'exportFailure': 'HTML導出失敗!' |
| 27 | + } |
| 28 | + }, |
| 29 | + |
| 30 | + _inited: false, |
| 31 | + init: function() { |
| 32 | + var me = this; |
| 33 | + me._inited = true; |
| 34 | + }, |
| 35 | + |
| 36 | + getPluginPath: function() { |
| 37 | + return Api.evtService.getProjectBasePath() + '/public/plugins/export_html' ; |
| 38 | + }, |
| 39 | + |
| 40 | + htmlTpl: '', |
| 41 | + markdownTpl: '', |
| 42 | + getTpl: function(isMarkdown) { |
| 43 | + var tpl = isMarkdown ? this.markdownTpl : this.htmlTpl; |
| 44 | + if(tpl) { |
| 45 | + return tpl; |
| 46 | + } |
| 47 | + var basePluginPath = this.getPluginPath(); |
| 48 | + |
| 49 | + var tplName = isMarkdown ? 'markdown' : 'html'; |
| 50 | + var tplPath = basePluginPath + '/tpl/' + tplName + '.tpl'; |
| 51 | + tpl = Api.nodeFs.readFileSync(tplPath, 'utf-8'); |
| 52 | + isMarkdown ? (this.markdownTpl = tpl) : (this.htmlTpl = tpl); |
| 53 | + return tpl; |
| 54 | + }, |
| 55 | + // 生成html或markdown |
| 56 | + render: function(note) { |
| 57 | + var tpl = this.getTpl(note.IsMarkdown); |
| 58 | + var title = note.Title || getMsg('Untitled'); |
| 59 | + tpl = tpl.replace(/\{title\}/g, title); |
| 60 | + tpl = tpl.replace(/\{content\}/g, note.Content); |
| 61 | + return tpl; |
| 62 | + }, |
| 63 | + |
| 64 | + replaceAll: function(src, pattern, to) { |
| 65 | + if(!src) { |
| 66 | + return src; |
| 67 | + } |
| 68 | + while(true) { |
| 69 | + var oldSrc = src; |
| 70 | + src = src.replace(pattern, to); |
| 71 | + if(oldSrc === src) { |
| 72 | + return src; |
| 73 | + } |
| 74 | + } |
| 75 | + }, |
| 76 | + |
| 77 | + fixFilename: function(filename) { |
| 78 | + var reg = new RegExp("/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\", 'g'); |
| 79 | + filename = filename.replace(reg, "-"); |
| 80 | + // 防止出现两个连续的- |
| 81 | + while(filename.indexOf('--') != -1) { |
| 82 | + filename = this.replaceAll(filename, '--', '-'); |
| 83 | + } |
| 84 | + return filename; |
| 85 | + }, |
| 86 | + |
| 87 | + // 写图片,并替换图片路径 |
| 88 | + writeFiles: function(filesPath, content, callback) { |
| 89 | + var me = this; |
| 90 | + // http://127.0.0.1:8912/api/file/getImage?fileId=5581029f6289dc3301000000 |
| 91 | + // 找到图片 |
| 92 | + var reg = new RegExp(Api.evtService.localUrl + '/api/file/getImage\\?fileId=([0-9a-zA-Z]{24})', 'g'); |
| 93 | + // console.log(Api.evtService.localUrl + '/api/file/getImage\\?fileId=([0-9a-zA-Z]{24})'); |
| 94 | + var matches = content.match(reg); |
| 95 | + // content = content.replace(reg, Evt.leanoteUrl + '/api/file/getImage'); |
| 96 | + |
| 97 | + if(matches && matches.length) { |
| 98 | + Api.nodeFs.mkdirSync(filesPath); |
| 99 | + // 取最后一个名字 |
| 100 | + var pathInfo = Api.commonService.splitFile(filesPath); |
| 101 | + var dirName = pathInfo.name; |
| 102 | + |
| 103 | + async.eachSeries(matches, function(url, cb) { |
| 104 | + var fileId = url.substr(url.length - 24); |
| 105 | + Api.fileService.getImageLocalPath(fileId, function(err, imagePath) { |
| 106 | + // 将图片copy到filesPath下 |
| 107 | + if(imagePath) { |
| 108 | + var distFileName = fileId + '.png'; |
| 109 | + Api.commonService.copyFile(imagePath, filesPath + '/' + distFileName, function(ok) { |
| 110 | + content = me.replaceAll(content, url, dirName + '/' + distFileName); |
| 111 | + cb(); |
| 112 | + }); |
| 113 | + } |
| 114 | + else { |
| 115 | + cb(); |
| 116 | + } |
| 117 | + }); |
| 118 | + }, function() { |
| 119 | + callback(content); |
| 120 | + }); |
| 121 | + |
| 122 | + return; |
| 123 | + } |
| 124 | + callback(content); |
| 125 | + }, |
| 126 | + |
| 127 | + // 得到存放images, js, css的路径 |
| 128 | + getFilesPath: function(basePath, nameNotExt, n, cb) { |
| 129 | + var me = this; |
| 130 | + var absPath = basePath + '/' + nameNotExt + '_files'; |
| 131 | + if (n > 1) { |
| 132 | + absPath += '-' + n; |
| 133 | + } |
| 134 | + Api.nodeFs.exists(absPath, function(exists) { |
| 135 | + if(!exists) { |
| 136 | + cb(absPath); |
| 137 | + } |
| 138 | + else { |
| 139 | + me.getFilesPath(basePath, nameNotExt, n+1, cb); |
| 140 | + } |
| 141 | + }); |
| 142 | + }, |
| 143 | + |
| 144 | + // 得到可用的文件名, 避免冲突 |
| 145 | + getHtmlFilePath: function(pathInfo, n, cb) { |
| 146 | + var me = this; |
| 147 | + if(n > 1) { |
| 148 | + pathInfo.nameNotExt = pathInfo.nameNotExtRaw + '-' + n; |
| 149 | + } |
| 150 | + var absPath = pathInfo.getFullPath(); |
| 151 | + // 总是覆盖 |
| 152 | + return cb(absPath); |
| 153 | + |
| 154 | + // Api.nodeFs.existsSync(absPath) 总是返回false, 不知道什么原因 |
| 155 | + // 在控制台上是可以的 |
| 156 | + Api.nodeFs.exists(absPath, function(exists) { |
| 157 | + if(!exists) { |
| 158 | + cb(absPath); |
| 159 | + } |
| 160 | + else { |
| 161 | + me.getHtmlFilePath(pathInfo, n+1, cb); |
| 162 | + } |
| 163 | + }); |
| 164 | + }, |
| 165 | + |
| 166 | + exportHTML: function(note) { |
| 167 | + var me = this; |
| 168 | + if(!note) { |
| 169 | + return; |
| 170 | + } |
| 171 | + |
| 172 | + var name = note.Title ? note.Title + '.html' : getMsg('Untitled') + '.html'; |
| 173 | + name = me.fixFilename(name); |
| 174 | + |
| 175 | + Api.gui.dialog.showSaveDialog(Api.gui.getCurrentWindow(), {title: name, defaultPath: name}, function(targetPath) { |
| 176 | + if(targetPath) { |
| 177 | + // 将路径和名字区分开 |
| 178 | + var pathInfo = Api.commonService.splitFile(targetPath); |
| 179 | + pathInfo.nameNotExt = me.fixFilename(pathInfo.nameNotExt); // 重新修正一次 |
| 180 | + var nameNotExt = pathInfo.nameNotExt; |
| 181 | + pathInfo.nameNotExtRaw = pathInfo.nameNotExt; |
| 182 | + // 得到可用文件的绝对路径 |
| 183 | + me.getHtmlFilePath(pathInfo, 1, function(absHtmlFilePath) { |
| 184 | + me.getFilesPath(pathInfo.path, pathInfo.nameNotExt, 1, function(absFilesPath) { |
| 185 | + // alert(absHtmlFilePath + ' --- ' + absFilesPath); |
| 186 | + var html = me.render(note); |
| 187 | + // 写图片 |
| 188 | + me.writeFiles(absFilesPath, html, function(html) { |
| 189 | + // 把文件写到 |
| 190 | + Api.commonService.writeFile(absHtmlFilePath, html); |
| 191 | + Notify.show({title: 'Info', body: getMsg('plugin.export_html.exportSuccess')}); |
| 192 | + }); |
| 193 | + }); |
| 194 | + }); |
| 195 | + } |
| 196 | + }); |
| 197 | + }, |
| 198 | + |
| 199 | + // 打开前要执行的 |
| 200 | + onOpen: function() { |
| 201 | + var me = this; |
| 202 | + var gui = Api.gui; |
| 203 | + |
| 204 | + var menu = { |
| 205 | + label: Api.getMsg('plugin.export_html.export'), |
| 206 | + click: (function() { |
| 207 | + return function(note) { |
| 208 | + me.exportHTML(note); |
| 209 | + } |
| 210 | + })() |
| 211 | + }; |
| 212 | + Api.addExportMenu(menu); |
| 213 | + }, |
| 214 | + // 打开后 |
| 215 | + onOpenAfter: function() { |
| 216 | + }, |
| 217 | + // 关闭时需要运行的 |
| 218 | + onClose: function() { |
| 219 | + } |
| 220 | + }; |
| 221 | + |
| 222 | + return exportHTML; |
| 223 | + |
| 224 | +}); |
0 commit comments