From f61200f54e037b3b2e2f1bd135c74f57c87d2b65 Mon Sep 17 00:00:00 2001 From: liushuang Date: Mon, 5 Aug 2024 23:45:58 +0800 Subject: [PATCH] init --- .idea/.gitignore | 5 + .idea/Markdown2Html.iml | 12 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + LICENSE | 674 + README.md | 18 + config/env.js | 93 + config/jest/cssTransform.js | 14 + config/jest/fileTransform.js | 30 + config/paths.js | 84 + config/webpack.config.js | 608 + config/webpack.config.lib.js | 566 + config/webpackDevServer.config.js | 104 + main.js | 49 + package.json | 242 + public/favicon.svg | 16 + public/index.html | 54 + public/manifest.json | 20 + screenshot.jpg | Bin 0 -> 129850 bytes scripts/build.js | 192 + scripts/start.js | 117 + scripts/test.js | 60 + src/App.css | 210 + src/App.js | 410 + src/App.test.js | 9 + src/Lib.js | 155 + src/component/Dialog/AboutDialog.js | 100 + src/component/Dialog/FormDialog.js | 102 + src/component/Dialog/HistoryDialog.js | 146 + src/component/Dialog/ImageDialog.js | 180 + src/component/Dialog/LinkDialog.js | 61 + src/component/Dialog/SitDownDialog.js | 106 + src/component/Dialog/VersionDialog.css | 3 + src/component/Dialog/VersionDialog.js | 155 + src/component/ImageHosting/AliOSS.js | 96 + src/component/ImageHosting/GitHub.js | 95 + src/component/ImageHosting/Gitee.js | 82 + src/component/ImageHosting/QiniuOSS.js | 124 + src/component/LocalHistory/index.js | 113 + src/component/LocalHistory/indexdb.js | 63 + src/component/LocalHistory/localHistory.css | 66 + src/component/LocalHistory/util.js | 106 + src/component/MenuLeft/CodeTheme.css | 13 + src/component/MenuLeft/CodeTheme.js | 66 + src/component/MenuLeft/File.js | 27 + src/component/MenuLeft/File/ImportFile.js | 40 + src/component/MenuLeft/Function.js | 43 + src/component/MenuLeft/Function/History.js | 25 + src/component/MenuLeft/Function/Reset.js | 42 + src/component/MenuLeft/Function/Search.js | 28 + src/component/MenuLeft/Function/SitDown.js | 25 + src/component/MenuLeft/Help.js | 40 + src/component/MenuLeft/Help/About.js | 25 + src/component/MenuLeft/Help/Document.js | 23 + src/component/MenuLeft/Help/Question.js | 23 + src/component/MenuLeft/Help/Version.js | 25 + .../MenuLeft/Help/Version.js.default | 25 + src/component/MenuLeft/Help/Version.js.new | 23 + src/component/MenuLeft/LogIn.js | 60 + src/component/MenuLeft/Login.css | 10 + src/component/MenuLeft/Paragraph.js | 38 + src/component/MenuLeft/Pattern.js | 74 + src/component/MenuLeft/Pattern/Bold.js | 37 + src/component/MenuLeft/Pattern/Code.js | 36 + src/component/MenuLeft/Pattern/Del.js | 36 + src/component/MenuLeft/Pattern/Font.js | 43 + src/component/MenuLeft/Pattern/Form.js | 28 + src/component/MenuLeft/Pattern/Format.js | 30 + src/component/MenuLeft/Pattern/Image.js | 28 + src/component/MenuLeft/Pattern/InlineCode.js | 36 + src/component/MenuLeft/Pattern/Italic.js | 36 + src/component/MenuLeft/Pattern/Link.js | 28 + src/component/MenuLeft/Pattern/LinkToFoot.js | 30 + src/component/MenuLeft/Setting.js | 32 + .../MenuLeft/Setting/ContainImgName.js | 27 + src/component/MenuLeft/Setting/SyncScroll.js | 27 + src/component/MenuLeft/Theme.css | 54 + src/component/MenuLeft/Theme.js | 128 + src/component/MenuLeft/View.js | 43 + src/component/MenuLeft/View/EditArea.js | 27 + src/component/MenuLeft/View/FullScreen.js | 46 + src/component/MenuLeft/View/PreviewArea.js | 27 + src/component/MenuLeft/View/ThemeArea.js | 27 + src/component/MenuLeft/common.css | 65 + src/component/SearchBox/SearchBox.css | 109 + src/component/SearchBox/index.js | 219 + src/component/Sidebar/ExportPdf.js | 32 + src/component/Sidebar/Juejin.css | 10 + src/component/Sidebar/Juejin.js | 48 + src/component/Sidebar/Markdown.css | 10 + src/component/Sidebar/Markdown.js | 35 + src/component/Sidebar/PreviewType.css | 10 + src/component/Sidebar/PreviewType.js | 29 + src/component/Sidebar/Wechat.css | 10 + src/component/Sidebar/Wechat.js | 42 + src/component/Sidebar/Zhihu.css | 10 + src/component/Sidebar/Zhihu.js | 46 + src/component/Sidebar/pdf.css | 10 + src/component/Toolbar/Bold.js | 42 + src/component/Toolbar/Code.js | 42 + src/component/Toolbar/Del.js | 42 + src/component/Toolbar/Format.js | 36 + src/component/Toolbar/Image.js | 34 + src/component/Toolbar/InlineCode.js | 42 + src/component/Toolbar/Italic.js | 42 + src/component/Toolbar/Link.js | 34 + src/component/Toolbar/LinkToFoot.js | 36 + src/component/Toolbar/Table.js | 34 + src/component/Toolbar/common.css | 10 + src/icon/Bold.js | 18 + src/icon/Close.js | 19 + src/icon/Code.js | 22 + src/icon/Copy.js | 18 + src/icon/Del.js | 19 + src/icon/Down.js | 16 + src/icon/Environment.js | 15 + src/icon/Font.js | 18 + src/icon/FontCase.js | 18 + src/icon/Format.js | 46 + src/icon/GitHub.js | 15 + src/icon/Image.js | 20 + src/icon/Inbox.js | 15 + src/icon/InlineCode.js | 18 + src/icon/Italic.js | 15 + src/icon/Juejin.js | 19 + src/icon/Link.js | 18 + src/icon/Markdown.js | 19 + src/icon/Mobile.js | 15 + src/icon/More.js | 15 + src/icon/PC.js | 15 + src/icon/Pdf.js | 35 + src/icon/Quote.js | 18 + src/icon/Rabbit.js | 19 + src/icon/Replace.js | 18 + src/icon/ReplaceAll.js | 19 + src/icon/Smile.js | 23 + src/icon/Table.js | 18 + src/icon/User.js | 18 + src/icon/Wechat.js | 45 + src/icon/Zhihu.js | 19 + src/icon/index.css | 7 + src/icon/index.js | 102 + src/index.css | 15 + src/index.d.ts | 64 + src/index.js | 26 + src/layout/Dialog.js | 26 + src/layout/EditorMenu.css | 28 + src/layout/EditorMenu.js | 27 + src/layout/Footer.css | 64 + src/layout/Footer.js | 131 + src/layout/Navbar.css | 65 + src/layout/Navbar.js | 46 + src/layout/Sidebar.css | 12 + src/layout/Sidebar.js | 36 + src/layout/StyleEditor.js | 100 + src/layout/Toolbar.js | 51 + src/logo.svg | 7 + src/serviceWorker.js | 128 + src/store/content.js | 79 + src/store/dialog.js | 63 + src/store/footer.js | 31 + src/store/imageHosting.js | 92 + src/store/navbar.js | 128 + src/store/title.js | 16 + src/store/userInfo.js | 23 + src/store/view.js | 35 + src/template/basic.js | 473 + src/template/code/atomOneDark.js | 96 + src/template/code/atomOneLight.js | 96 + src/template/code/github.js | 99 + src/template/code/monokai.js | 70 + src/template/code/vs2015.js | 115 + src/template/code/xcode.js | 104 + src/template/content.md | 333 + src/template/index.js | 75 + src/template/macCode/macAtomOneDark.js | 121 + src/template/macCode/macAtomOneLight.js | 121 + src/template/macCode/macGithub.js | 124 + src/template/macCode/macMonokai.js | 95 + src/template/macCode/macVs2015.js | 140 + src/template/macCode/macXcode.js | 129 + src/template/markdown/custom.js | 203 + src/template/markdown/eight.js | 236 + src/template/markdown/eleven.js | 324 + src/template/markdown/fifteen.js | 252 + src/template/markdown/five.js | 327 + src/template/markdown/four.js | 227 + src/template/markdown/fourteen.js | 327 + src/template/markdown/nine.js | 272 + src/template/markdown/normal.js | 205 + src/template/markdown/one.js | 172 + src/template/markdown/seven.js | 243 + src/template/markdown/six.js | 198 + src/template/markdown/ten.js | 268 + src/template/markdown/thirteen.js | 414 + src/template/markdown/three.js | 223 + src/template/markdown/twelve.js | 240 + src/template/markdown/two.js | 228 + src/template/markdown/wgh.js | 271 + src/utils/appContext.js | 5 + src/utils/constant.js | 120 + src/utils/converter.js | 160 + src/utils/editorKeyEvents.js | 112 + src/utils/helper.js | 316 + src/utils/hotkey.js | 197 + src/utils/imageHosting.js | 533 + src/utils/langHighlight.js | 86 + src/utils/markdown-it-imageflow.js | 54 + src/utils/markdown-it-li.js | 14 + src/utils/markdown-it-linkfoot.js | 369 + src/utils/markdown-it-math.js | 233 + src/utils/markdown-it-removepre.js | 18 + src/utils/markdown-it-span.js | 44 + src/utils/markdown-it-table-container.js | 26 + src/utils/markdown-it-urlspan.js | 24 + src/utils/mdMirror.css | 108 + src/utils/pluginCenter.js | 4 + src/utils/sitdownConverter.js | 50 + src/utils/styleMirror.css | 122 + stories/allImageHosting.js | 29 + stories/defaultImageHosting.js | 19 + stories/index.js | 13 + stories/noneImageHosting.js | 27 + stories/online.js | 30 + watch.js | 65 + yarn.lock | 15044 ++++++++++++++++ 226 files changed, 34584 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/Markdown2Html.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 config/env.js create mode 100644 config/jest/cssTransform.js create mode 100644 config/jest/fileTransform.js create mode 100644 config/paths.js create mode 100644 config/webpack.config.js create mode 100644 config/webpack.config.lib.js create mode 100644 config/webpackDevServer.config.js create mode 100644 main.js create mode 100644 package.json create mode 100644 public/favicon.svg create mode 100644 public/index.html create mode 100644 public/manifest.json create mode 100644 screenshot.jpg create mode 100644 scripts/build.js create mode 100644 scripts/start.js create mode 100644 scripts/test.js create mode 100644 src/App.css create mode 100644 src/App.js create mode 100644 src/App.test.js create mode 100644 src/Lib.js create mode 100644 src/component/Dialog/AboutDialog.js create mode 100644 src/component/Dialog/FormDialog.js create mode 100644 src/component/Dialog/HistoryDialog.js create mode 100644 src/component/Dialog/ImageDialog.js create mode 100644 src/component/Dialog/LinkDialog.js create mode 100644 src/component/Dialog/SitDownDialog.js create mode 100644 src/component/Dialog/VersionDialog.css create mode 100644 src/component/Dialog/VersionDialog.js create mode 100644 src/component/ImageHosting/AliOSS.js create mode 100644 src/component/ImageHosting/GitHub.js create mode 100644 src/component/ImageHosting/Gitee.js create mode 100644 src/component/ImageHosting/QiniuOSS.js create mode 100644 src/component/LocalHistory/index.js create mode 100644 src/component/LocalHistory/indexdb.js create mode 100644 src/component/LocalHistory/localHistory.css create mode 100644 src/component/LocalHistory/util.js create mode 100644 src/component/MenuLeft/CodeTheme.css create mode 100644 src/component/MenuLeft/CodeTheme.js create mode 100644 src/component/MenuLeft/File.js create mode 100644 src/component/MenuLeft/File/ImportFile.js create mode 100644 src/component/MenuLeft/Function.js create mode 100644 src/component/MenuLeft/Function/History.js create mode 100644 src/component/MenuLeft/Function/Reset.js create mode 100644 src/component/MenuLeft/Function/Search.js create mode 100644 src/component/MenuLeft/Function/SitDown.js create mode 100644 src/component/MenuLeft/Help.js create mode 100644 src/component/MenuLeft/Help/About.js create mode 100644 src/component/MenuLeft/Help/Document.js create mode 100644 src/component/MenuLeft/Help/Question.js create mode 100644 src/component/MenuLeft/Help/Version.js create mode 100644 src/component/MenuLeft/Help/Version.js.default create mode 100644 src/component/MenuLeft/Help/Version.js.new create mode 100644 src/component/MenuLeft/LogIn.js create mode 100644 src/component/MenuLeft/Login.css create mode 100644 src/component/MenuLeft/Paragraph.js create mode 100644 src/component/MenuLeft/Pattern.js create mode 100644 src/component/MenuLeft/Pattern/Bold.js create mode 100644 src/component/MenuLeft/Pattern/Code.js create mode 100644 src/component/MenuLeft/Pattern/Del.js create mode 100644 src/component/MenuLeft/Pattern/Font.js create mode 100644 src/component/MenuLeft/Pattern/Form.js create mode 100644 src/component/MenuLeft/Pattern/Format.js create mode 100644 src/component/MenuLeft/Pattern/Image.js create mode 100644 src/component/MenuLeft/Pattern/InlineCode.js create mode 100644 src/component/MenuLeft/Pattern/Italic.js create mode 100644 src/component/MenuLeft/Pattern/Link.js create mode 100644 src/component/MenuLeft/Pattern/LinkToFoot.js create mode 100644 src/component/MenuLeft/Setting.js create mode 100644 src/component/MenuLeft/Setting/ContainImgName.js create mode 100644 src/component/MenuLeft/Setting/SyncScroll.js create mode 100644 src/component/MenuLeft/Theme.css create mode 100644 src/component/MenuLeft/Theme.js create mode 100644 src/component/MenuLeft/View.js create mode 100644 src/component/MenuLeft/View/EditArea.js create mode 100644 src/component/MenuLeft/View/FullScreen.js create mode 100644 src/component/MenuLeft/View/PreviewArea.js create mode 100644 src/component/MenuLeft/View/ThemeArea.js create mode 100644 src/component/MenuLeft/common.css create mode 100644 src/component/SearchBox/SearchBox.css create mode 100644 src/component/SearchBox/index.js create mode 100644 src/component/Sidebar/ExportPdf.js create mode 100644 src/component/Sidebar/Juejin.css create mode 100644 src/component/Sidebar/Juejin.js create mode 100644 src/component/Sidebar/Markdown.css create mode 100644 src/component/Sidebar/Markdown.js create mode 100644 src/component/Sidebar/PreviewType.css create mode 100644 src/component/Sidebar/PreviewType.js create mode 100644 src/component/Sidebar/Wechat.css create mode 100644 src/component/Sidebar/Wechat.js create mode 100644 src/component/Sidebar/Zhihu.css create mode 100644 src/component/Sidebar/Zhihu.js create mode 100644 src/component/Sidebar/pdf.css create mode 100644 src/component/Toolbar/Bold.js create mode 100644 src/component/Toolbar/Code.js create mode 100644 src/component/Toolbar/Del.js create mode 100644 src/component/Toolbar/Format.js create mode 100644 src/component/Toolbar/Image.js create mode 100644 src/component/Toolbar/InlineCode.js create mode 100644 src/component/Toolbar/Italic.js create mode 100644 src/component/Toolbar/Link.js create mode 100644 src/component/Toolbar/LinkToFoot.js create mode 100644 src/component/Toolbar/Table.js create mode 100644 src/component/Toolbar/common.css create mode 100644 src/icon/Bold.js create mode 100644 src/icon/Close.js create mode 100644 src/icon/Code.js create mode 100644 src/icon/Copy.js create mode 100644 src/icon/Del.js create mode 100644 src/icon/Down.js create mode 100644 src/icon/Environment.js create mode 100644 src/icon/Font.js create mode 100644 src/icon/FontCase.js create mode 100644 src/icon/Format.js create mode 100644 src/icon/GitHub.js create mode 100644 src/icon/Image.js create mode 100644 src/icon/Inbox.js create mode 100644 src/icon/InlineCode.js create mode 100644 src/icon/Italic.js create mode 100644 src/icon/Juejin.js create mode 100644 src/icon/Link.js create mode 100644 src/icon/Markdown.js create mode 100644 src/icon/Mobile.js create mode 100644 src/icon/More.js create mode 100644 src/icon/PC.js create mode 100644 src/icon/Pdf.js create mode 100644 src/icon/Quote.js create mode 100644 src/icon/Rabbit.js create mode 100644 src/icon/Replace.js create mode 100644 src/icon/ReplaceAll.js create mode 100644 src/icon/Smile.js create mode 100644 src/icon/Table.js create mode 100644 src/icon/User.js create mode 100644 src/icon/Wechat.js create mode 100644 src/icon/Zhihu.js create mode 100644 src/icon/index.css create mode 100644 src/icon/index.js create mode 100644 src/index.css create mode 100644 src/index.d.ts create mode 100644 src/index.js create mode 100644 src/layout/Dialog.js create mode 100644 src/layout/EditorMenu.css create mode 100644 src/layout/EditorMenu.js create mode 100644 src/layout/Footer.css create mode 100644 src/layout/Footer.js create mode 100644 src/layout/Navbar.css create mode 100644 src/layout/Navbar.js create mode 100644 src/layout/Sidebar.css create mode 100644 src/layout/Sidebar.js create mode 100644 src/layout/StyleEditor.js create mode 100644 src/layout/Toolbar.js create mode 100644 src/logo.svg create mode 100644 src/serviceWorker.js create mode 100644 src/store/content.js create mode 100644 src/store/dialog.js create mode 100644 src/store/footer.js create mode 100644 src/store/imageHosting.js create mode 100644 src/store/navbar.js create mode 100644 src/store/title.js create mode 100644 src/store/userInfo.js create mode 100644 src/store/view.js create mode 100644 src/template/basic.js create mode 100644 src/template/code/atomOneDark.js create mode 100644 src/template/code/atomOneLight.js create mode 100644 src/template/code/github.js create mode 100644 src/template/code/monokai.js create mode 100644 src/template/code/vs2015.js create mode 100644 src/template/code/xcode.js create mode 100644 src/template/content.md create mode 100644 src/template/index.js create mode 100644 src/template/macCode/macAtomOneDark.js create mode 100644 src/template/macCode/macAtomOneLight.js create mode 100644 src/template/macCode/macGithub.js create mode 100644 src/template/macCode/macMonokai.js create mode 100644 src/template/macCode/macVs2015.js create mode 100644 src/template/macCode/macXcode.js create mode 100644 src/template/markdown/custom.js create mode 100644 src/template/markdown/eight.js create mode 100644 src/template/markdown/eleven.js create mode 100644 src/template/markdown/fifteen.js create mode 100644 src/template/markdown/five.js create mode 100644 src/template/markdown/four.js create mode 100644 src/template/markdown/fourteen.js create mode 100644 src/template/markdown/nine.js create mode 100644 src/template/markdown/normal.js create mode 100644 src/template/markdown/one.js create mode 100644 src/template/markdown/seven.js create mode 100644 src/template/markdown/six.js create mode 100644 src/template/markdown/ten.js create mode 100644 src/template/markdown/thirteen.js create mode 100644 src/template/markdown/three.js create mode 100644 src/template/markdown/twelve.js create mode 100644 src/template/markdown/two.js create mode 100644 src/template/markdown/wgh.js create mode 100644 src/utils/appContext.js create mode 100644 src/utils/constant.js create mode 100644 src/utils/converter.js create mode 100644 src/utils/editorKeyEvents.js create mode 100644 src/utils/helper.js create mode 100644 src/utils/hotkey.js create mode 100644 src/utils/imageHosting.js create mode 100644 src/utils/langHighlight.js create mode 100644 src/utils/markdown-it-imageflow.js create mode 100644 src/utils/markdown-it-li.js create mode 100644 src/utils/markdown-it-linkfoot.js create mode 100644 src/utils/markdown-it-math.js create mode 100644 src/utils/markdown-it-removepre.js create mode 100644 src/utils/markdown-it-span.js create mode 100644 src/utils/markdown-it-table-container.js create mode 100644 src/utils/markdown-it-urlspan.js create mode 100644 src/utils/mdMirror.css create mode 100644 src/utils/pluginCenter.js create mode 100644 src/utils/sitdownConverter.js create mode 100644 src/utils/styleMirror.css create mode 100644 stories/allImageHosting.js create mode 100644 stories/defaultImageHosting.js create mode 100644 stories/index.js create mode 100644 stories/noneImageHosting.js create mode 100644 stories/online.js create mode 100644 watch.js create mode 100644 yarn.lock diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..10b731c --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/Markdown2Html.iml b/.idea/Markdown2Html.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/Markdown2Html.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e4e4ed1 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..20d40b6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2d26b93 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +
+ + + +
+

Markdown2Html

+ +## 简介 + +Fork 自 [markdown2html](https://github.com/TaleAi/markdown2html),略有调整。 + +- 支持自定义样式的 Markdown 编辑器 +- 支持微信公众号、知乎和稀土掘金 +- 支持公式 +- 支持 html 转 markdwon +- 支持导出 pdf 和 markdown +- 在线使用: + - https://md.luckday.cn/ \ No newline at end of file diff --git a/config/env.js b/config/env.js new file mode 100644 index 0000000..b0344c5 --- /dev/null +++ b/config/env.js @@ -0,0 +1,93 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const paths = require('./paths'); + +// Make sure that including paths.js after env.js will read .env variables. +delete require.cache[require.resolve('./paths')]; + +const NODE_ENV = process.env.NODE_ENV; +if (!NODE_ENV) { + throw new Error( + 'The NODE_ENV environment variable is required but was not specified.' + ); +} + +// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use +var dotenvFiles = [ + `${paths.dotenv}.${NODE_ENV}.local`, + `${paths.dotenv}.${NODE_ENV}`, + // Don't include `.env.local` for `test` environment + // since normally you expect tests to produce the same + // results for everyone + NODE_ENV !== 'test' && `${paths.dotenv}.local`, + paths.dotenv, +].filter(Boolean); + +// Load environment variables from .env* files. Suppress warnings using silent +// if this file is missing. dotenv will never modify any environment variables +// that have already been set. Variable expansion is supported in .env files. +// https://github.com/motdotla/dotenv +// https://github.com/motdotla/dotenv-expand +dotenvFiles.forEach(dotenvFile => { + if (fs.existsSync(dotenvFile)) { + require('dotenv-expand')( + require('dotenv').config({ + path: dotenvFile, + }) + ); + } +}); + +// We support resolving modules according to `NODE_PATH`. +// This lets you use absolute paths in imports inside large monorepos: +// https://github.com/facebook/create-react-app/issues/253. +// It works similar to `NODE_PATH` in Node itself: +// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders +// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. +// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims. +// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421 +// We also resolve them to make sure all tools using them work consistently. +const appDirectory = fs.realpathSync(process.cwd()); +process.env.NODE_PATH = (process.env.NODE_PATH || '') + .split(path.delimiter) + .filter(folder => folder && !path.isAbsolute(folder)) + .map(folder => path.resolve(appDirectory, folder)) + .join(path.delimiter); + +// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be +// injected into the application via DefinePlugin in Webpack configuration. +const REACT_APP = /^REACT_APP_/i; + +function getClientEnvironment(publicUrl) { + const raw = Object.keys(process.env) + .filter(key => REACT_APP.test(key)) + .reduce( + (env, key) => { + env[key] = process.env[key]; + return env; + }, + { + // Useful for determining whether we’re running in production mode. + // Most importantly, it switches React into the correct mode. + NODE_ENV: process.env.NODE_ENV || 'development', + // Useful for resolving the correct path to static assets in `public`. + // For example, . + // This should only be used as an escape hatch. Normally you would put + // images into the `src` and `import` them in code to get their paths. + PUBLIC_URL: publicUrl, + } + ); + // Stringify all values so we can feed into Webpack DefinePlugin + const stringified = { + 'process.env': Object.keys(raw).reduce((env, key) => { + env[key] = JSON.stringify(raw[key]); + return env; + }, {}), + }; + + return { raw, stringified }; +} + +module.exports = getClientEnvironment; diff --git a/config/jest/cssTransform.js b/config/jest/cssTransform.js new file mode 100644 index 0000000..8f65114 --- /dev/null +++ b/config/jest/cssTransform.js @@ -0,0 +1,14 @@ +'use strict'; + +// This is a custom Jest transformer turning style imports into empty objects. +// http://facebook.github.io/jest/docs/en/webpack.html + +module.exports = { + process() { + return 'module.exports = {};'; + }, + getCacheKey() { + // The output is always the same. + return 'cssTransform'; + }, +}; diff --git a/config/jest/fileTransform.js b/config/jest/fileTransform.js new file mode 100644 index 0000000..07010e3 --- /dev/null +++ b/config/jest/fileTransform.js @@ -0,0 +1,30 @@ +'use strict'; + +const path = require('path'); + +// This is a custom Jest transformer turning file imports into filenames. +// http://facebook.github.io/jest/docs/en/webpack.html + +module.exports = { + process(src, filename) { + const assetFilename = JSON.stringify(path.basename(filename)); + + if (filename.match(/\.svg$/)) { + return `module.exports = { + __esModule: true, + default: ${assetFilename}, + ReactComponent: (props) => ({ + $$typeof: Symbol.for('react.element'), + type: 'svg', + ref: null, + key: null, + props: Object.assign({}, props, { + children: ${assetFilename} + }) + }), + };`; + } + + return `module.exports = ${assetFilename};`; + }, +}; diff --git a/config/paths.js b/config/paths.js new file mode 100644 index 0000000..3003b9c --- /dev/null +++ b/config/paths.js @@ -0,0 +1,84 @@ +"use strict"; + +const path = require("path"); +const fs = require("fs"); +const url = require("url"); + +// Make sure any symlinks in the project folder are resolved: +// https://github.com/facebook/create-react-app/issues/637 +const appDirectory = fs.realpathSync(process.cwd()); +const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath); + +const envPublicUrl = process.env.PUBLIC_URL; + +function ensureSlash(inputPath, needsSlash) { + const hasSlash = inputPath.endsWith("/"); + if (hasSlash && !needsSlash) { + return inputPath.substr(0, inputPath.length - 1); + } else if (!hasSlash && needsSlash) { + return `${inputPath}/`; + } else { + return inputPath; + } +} + +const getPublicUrl = (appPackageJson) => envPublicUrl || require(appPackageJson).homepage; + +// We use `PUBLIC_URL` environment variable or "homepage" field to infer +// "public path" at which the app is served. +// Webpack needs to know it to put the right + + + diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..8021471 --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,20 @@ +{ + "short_name": "Markdown Nice", + "name": "Markdown Nice", + "icons": [ + { + "src": "https://my-wechat.mdnice.com/mdnice/mdnice%20logo_20191007150129.png", + "sizes": "128x128", + "type": "image/png" + }, + { + "src": "https://my-wechat.mdnice.com/mdnice/mdnice%20logo_20191007150129.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "start_url": "./index.html", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/screenshot.jpg b/screenshot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..06af1ec63fb09fada589c804d35739f186ddaf55 GIT binary patch literal 129850 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 LvbTKq@k{>$itPIm literal 0 HcmV?d00001 diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..e01b7a5 --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,192 @@ +'use strict'; + +// Do this as the first thing so that any code reading it knows the right env. +process.env.BABEL_ENV = 'production'; +process.env.NODE_ENV = 'production'; + +// Makes the script crash on unhandled rejections instead of silently +// ignoring them. In the future, promise rejections that are not handled will +// terminate the Node.js process with a non-zero exit code. +process.on('unhandledRejection', err => { + throw err; +}); + +// Ensure environment variables are read. +require('../config/env'); + + +const path = require('path'); +const chalk = require('react-dev-utils/chalk'); +const fs = require('fs-extra'); +const webpack = require('webpack'); +const bfj = require('bfj'); +const configFactory = require('../config/webpack.config'); +const paths = require('../config/paths'); +const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); +const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); +const printHostingInstructions = require('react-dev-utils/printHostingInstructions'); +const FileSizeReporter = require('react-dev-utils/FileSizeReporter'); +const printBuildError = require('react-dev-utils/printBuildError'); + +const measureFileSizesBeforeBuild = + FileSizeReporter.measureFileSizesBeforeBuild; +const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild; +const useYarn = fs.existsSync(paths.yarnLockFile); + +// These sizes are pretty large. We'll warn for bundles exceeding them. +const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; +const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; + +const isInteractive = process.stdout.isTTY; + +// Warn and crash if required files are missing +if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { + process.exit(1); +} + +// Process CLI arguments +const argv = process.argv.slice(2); +const writeStatsJson = argv.indexOf('--stats') !== -1; + +// Generate configuration +const config = configFactory('production'); + +// We require that you explicitly set browsers and do not fall back to +// browserslist defaults. +const { checkBrowsers } = require('react-dev-utils/browsersHelper'); +checkBrowsers(paths.appPath, isInteractive) + .then(() => { + // First, read the current file sizes in build directory. + // This lets us display how much they changed later. + return measureFileSizesBeforeBuild(paths.appBuild); + }) + .then(previousFileSizes => { + // Remove all content but keep the directory so that + // if you're in it, you don't end up in Trash + fs.emptyDirSync(paths.appBuild); + // Merge with the public folder + copyPublicFolder(); + // Start the webpack build + return build(previousFileSizes); + }) + .then( + ({ stats, previousFileSizes, warnings }) => { + if (warnings.length) { + console.log(chalk.yellow('Compiled with warnings.\n')); + console.log(warnings.join('\n\n')); + console.log( + '\nSearch for the ' + + chalk.underline(chalk.yellow('keywords')) + + ' to learn more about each warning.' + ); + console.log( + 'To ignore, add ' + + chalk.cyan('// eslint-disable-next-line') + + ' to the line before.\n' + ); + } else { + console.log(chalk.green('Compiled successfully.\n')); + } + + console.log('File sizes after gzip:\n'); + printFileSizesAfterBuild( + stats, + previousFileSizes, + paths.appBuild, + WARN_AFTER_BUNDLE_GZIP_SIZE, + WARN_AFTER_CHUNK_GZIP_SIZE + ); + console.log(); + + const appPackage = require(paths.appPackageJson); + const publicUrl = paths.publicUrl; + const publicPath = config.output.publicPath; + const buildFolder = path.relative(process.cwd(), paths.appBuild); + printHostingInstructions( + appPackage, + publicUrl, + publicPath, + buildFolder, + useYarn + ); + }, + err => { + console.log(chalk.red('Failed to compile.\n')); + printBuildError(err); + process.exit(1); + } + ) + .catch(err => { + if (err && err.message) { + console.log(err.message); + } + process.exit(1); + }); + +// Create the production build and print the deployment instructions. +function build(previousFileSizes) { + console.log('Creating an optimized production build...'); + + let compiler = webpack(config); + return new Promise((resolve, reject) => { + compiler.run((err, stats) => { + let messages; + if (err) { + if (!err.message) { + return reject(err); + } + messages = formatWebpackMessages({ + errors: [err.message], + warnings: [], + }); + } else { + messages = formatWebpackMessages( + stats.toJson({ all: false, warnings: true, errors: true }) + ); + } + if (messages.errors.length) { + // Only keep the first error. Others are often indicative + // of the same problem, but confuse the reader with noise. + if (messages.errors.length > 1) { + messages.errors.length = 1; + } + return reject(new Error(messages.errors.join('\n\n'))); + } + if ( + process.env.CI && + (typeof process.env.CI !== 'string' || + process.env.CI.toLowerCase() !== 'false') && + messages.warnings.length + ) { + console.log( + chalk.yellow( + '\nTreating warnings as errors because process.env.CI = true.\n' + + 'Most CI servers set it automatically.\n' + ) + ); + return reject(new Error(messages.warnings.join('\n\n'))); + } + + const resolveArgs = { + stats, + previousFileSizes, + warnings: messages.warnings, + }; + if (writeStatsJson) { + return bfj + .write(paths.appBuild + '/bundle-stats.json', stats.toJson()) + .then(() => resolve(resolveArgs)) + .catch(error => reject(new Error(error))); + } + + return resolve(resolveArgs); + }); + }); +} + +function copyPublicFolder() { + fs.copySync(paths.appPublic, paths.appBuild, { + dereference: true, + filter: file => file !== paths.appHtml, + }); +} diff --git a/scripts/start.js b/scripts/start.js new file mode 100644 index 0000000..1dc9805 --- /dev/null +++ b/scripts/start.js @@ -0,0 +1,117 @@ +'use strict'; + +// Do this as the first thing so that any code reading it knows the right env. +process.env.BABEL_ENV = 'development'; +process.env.NODE_ENV = 'development'; + +// Makes the script crash on unhandled rejections instead of silently +// ignoring them. In the future, promise rejections that are not handled will +// terminate the Node.js process with a non-zero exit code. +process.on('unhandledRejection', err => { + throw err; +}); + +// Ensure environment variables are read. +require('../config/env'); + + +const fs = require('fs'); +const chalk = require('react-dev-utils/chalk'); +const webpack = require('webpack'); +const WebpackDevServer = require('webpack-dev-server'); +const clearConsole = require('react-dev-utils/clearConsole'); +const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); +const { + choosePort, + createCompiler, + prepareProxy, + prepareUrls, +} = require('react-dev-utils/WebpackDevServerUtils'); +const openBrowser = require('react-dev-utils/openBrowser'); +const paths = require('../config/paths'); +const configFactory = require('../config/webpack.config'); +const createDevServerConfig = require('../config/webpackDevServer.config'); + +const useYarn = fs.existsSync(paths.yarnLockFile); +const isInteractive = process.stdout.isTTY; + +// Warn and crash if required files are missing +if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { + process.exit(1); +} + +// Tools like Cloud9 rely on this. +const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; +const HOST = process.env.HOST || '0.0.0.0'; + +if (process.env.HOST) { + console.log( + chalk.cyan( + `Attempting to bind to HOST environment variable: ${chalk.yellow( + chalk.bold(process.env.HOST) + )}` + ) + ); + console.log( + `If this was unintentional, check that you haven't mistakenly set it in your shell.` + ); + console.log( + `Learn more here: ${chalk.yellow('http://bit.ly/CRA-advanced-config')}` + ); + console.log(); +} + +// We require that you explictly set browsers and do not fall back to +// browserslist defaults. +const { checkBrowsers } = require('react-dev-utils/browsersHelper'); +checkBrowsers(paths.appPath, isInteractive) + .then(() => { + // We attempt to use the default port but if it is busy, we offer the user to + // run on a different port. `choosePort()` Promise resolves to the next free port. + return choosePort(HOST, DEFAULT_PORT); + }) + .then(port => { + if (port == null) { + // We have not found a port. + return; + } + const config = configFactory('development'); + const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; + const appName = require(paths.appPackageJson).name; + const urls = prepareUrls(protocol, HOST, port); + // Create a webpack compiler that is configured with custom messages. + const compiler = createCompiler(webpack, config, appName, urls, useYarn); + // Load proxy config + const proxySetting = require(paths.appPackageJson).proxy; + const proxyConfig = prepareProxy(proxySetting, paths.appPublic); + // Serve webpack assets generated by the compiler over a web server. + const serverConfig = createDevServerConfig( + proxyConfig, + urls.lanUrlForConfig + ); + const devServer = new WebpackDevServer(compiler, serverConfig); + // Launch WebpackDevServer. + devServer.listen(port, HOST, err => { + if (err) { + return console.log(err); + } + if (isInteractive) { + clearConsole(); + } + console.log(chalk.cyan('Starting the development server...\n')); + openBrowser(urls.localUrlForBrowser); + }); + + ['SIGINT', 'SIGTERM'].forEach(function(sig) { + process.on(sig, function() { + devServer.close(); + process.exit(); + }); + }); + }) + .catch(err => { + if (err && err.message) { + console.log(err.message); + } + process.exit(1); + }); diff --git a/scripts/test.js b/scripts/test.js new file mode 100644 index 0000000..4172e42 --- /dev/null +++ b/scripts/test.js @@ -0,0 +1,60 @@ +'use strict'; + +// Do this as the first thing so that any code reading it knows the right env. +process.env.BABEL_ENV = 'test'; +process.env.NODE_ENV = 'test'; +process.env.PUBLIC_URL = ''; + +// Makes the script crash on unhandled rejections instead of silently +// ignoring them. In the future, promise rejections that are not handled will +// terminate the Node.js process with a non-zero exit code. +process.on('unhandledRejection', err => { + throw err; +}); + +// Ensure environment variables are read. +require('../config/env'); + + +const jest = require('jest'); +const execSync = require('child_process').execSync; +let argv = process.argv.slice(2); + +function isInGitRepository() { + try { + execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); + return true; + } catch (e) { + return false; + } +} + +function isInMercurialRepository() { + try { + execSync('hg --cwd . root', { stdio: 'ignore' }); + return true; + } catch (e) { + return false; + } +} + +// Watch unless on CI, in coverage mode, explicitly adding `--no-watch`, +// or explicitly running all tests +if ( + !process.env.CI && + argv.indexOf('--coverage') === -1 && + argv.indexOf('--no-watch') === -1 && + argv.indexOf('--watchAll') === -1 +) { + // https://github.com/facebook/create-react-app/issues/5210 + const hasSourceControl = isInGitRepository() || isInMercurialRepository(); + argv.push(hasSourceControl ? '--watch' : '--watchAll'); +} + +// Jest doesn't have this option so we'll remove it +if (argv.indexOf('--no-watch') !== -1) { + argv = argv.filter(arg => arg !== '--no-watch'); +} + + +jest.run(argv); diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..588245a --- /dev/null +++ b/src/App.css @@ -0,0 +1,210 @@ +.ant-btn-primary { + color: #fff; + background-color: #000; + border-color: #000; +} + +.ant-btn-primary:hover, +.ant-btn-primary:focus { + color: #fff; + background-color: #000; + border-color: #000; +} + +.ant-btn:hover, .ant-btn:focus { + color: #000; + background-color: #fff; + border-color: #000; +} + +.ant-input:hover, .ant-input:focus { + border-color: #000; + border-right-width: 1px !important; + -webkit-box-shadow: 0 0 0 2px rgb(82 82 83 / 20%); + box-shadow: 0 0 0 2px rgb(82 82 83 / 20%); +} + +.ant-select-selection:hover { + border-color: #000; + border-right-width: 1px !important; +} + +.ant-select-focused .ant-select-selection, .ant-select-selection:focus, .ant-select-selection:active, +.ant-input-number:focus, .ant-input-number:active , .ant-input-number:hover { + border-color: #000; + -webkit-box-shadow: 0 0 0 2px rgb(82 82 83 / 20%); + box-shadow: 0 0 0 2px rgb(82 82 83 / 20%); +} + +.ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled) { + background-color: #f1f1f1; +} + +.ant-select-dropdown-menu { + margin: 4px; + padding: 0; +} + +.ant-select-dropdown-menu-item { + border-radius: 4px; + margin: 2px 0; +} + +.ant-menu-item-selected { + color: #000; + /*font-weight: bolder;*/ +} + +.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected { + background-color: #f6f6f6; +} + +.ant-menu-item { + text-align: center; + margin-right: 20px; +} + +.ant-menu-inline, .ant-menu-vertical, .ant-menu-vertical-left { + margin-right: 20px; +} + +.ant-menu-item:hover, .ant-menu-item-active, .ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open, .ant-menu-submenu-active, .ant-menu-submenu-title:hover { + color: #000; + font-weight: bolder; +} + +.nice-app { + height: 100vh; + width: 100%; + display: flex; + overflow: hidden; + flex-direction: column; + font-family: "PingFang SC", BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serifhtml, body; + font-size: 16px; +} + +.nice-text-container { + display: flex; + height: calc(100vh - 50px); + width: 100%; +} + +.nice-text-container-immersive { + display: flex; + height: 100vh; + width: 100%; +} + +.nice-md-editing-immersive { + padding: 0px; + width: 100%; +} + +.nice-md-editing-immersive .CodeMirror-lines { + padding: 20px; +} + +@media screen and (min-width: 768px) { + .nice-md-editing-immersive .CodeMirror-lines { + padding: 20px 10%; + } +} + +@media screen and (min-width: 1024px) { + .nice-md-editing-immersive .CodeMirror-lines { + padding: 20px 15%; + } +} + +/* 编辑器最多会被分成三份width:33.3%,当两份时根据flex-grow:1伸展 */ +.nice-md-editing, +.nice-style-editing { + position: relative; + width: 33.3%; + height: 88%; + flex-grow: 1; + word-wrap: break-word; + z-index: 1; +} + +.nice-marked-text { + display: flex; + justify-content: center; + width: 33.3%; + flex-grow: 1; + padding: 20px; + margin-bottom: 70px; + word-wrap: break-word; + position: relative; +} + +.nice-marked-text-pc { + padding: 0; +} + +.nice-wx-box { + overflow-y: auto; + padding: 25px 20px; + height: 98%; + width: 375px; + box-shadow: 0 0 60px rgba(0, 0, 0, 0.1); +} + +.nice-wx-box-pc { + width: 100%; + padding: 20px 35px 20px 20px; + box-shadow: none; +} + +.nice-style-editing-hide { + display: none; +} + +.nice-md-editing-hide { + display: none; +} + +.nice-marked-text-hide { + display: none; +} + +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-track { + border-radius: 3px; + background: rgba(0, 0, 0, 0.06); + box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08); +} +::-webkit-scrollbar-thumb { + border-radius: 3px; + background: rgba(0, 0, 0, 0.12); + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.2); +} + +@media print { + .nice-md-editing { + display: none; + } + .nice-navbar { + display: none; + } + .nice-sidebar { + display: none; + } + .nice-wx-box { + overflow: visible; + box-shadow: none; + width: 100%; + } + .nice-style-editing { + display: none; + } + #nice-rich-text { + padding: 0 !important; + } + .nice-footer-container { + display: none; + } +} diff --git a/src/App.js b/src/App.js new file mode 100644 index 0000000..4aa76a6 --- /dev/null +++ b/src/App.js @@ -0,0 +1,410 @@ +import React, {Component} from "react"; +import CodeMirror from "@uiw/react-codemirror"; +import "codemirror/addon/search/searchcursor"; +import "codemirror/keymap/sublime"; +import "antd/dist/antd.css"; +import {observer, inject} from "mobx-react"; +import classnames from "classnames"; +import throttle from "lodash.throttle"; + +import Dialog from "./layout/Dialog"; +import Navbar from "./layout/Navbar"; +import Toobar from "./layout/Toolbar"; +import Footer from "./layout/Footer"; +import Sidebar from "./layout/Sidebar"; +import StyleEditor from "./layout/StyleEditor"; +import EditorMenu from "./layout/EditorMenu"; +import SearchBox from "./component/SearchBox"; + +import "./App.css"; +import "./utils/mdMirror.css"; + +import { + LAYOUT_ID, + BOX_ID, + IMAGE_HOSTING_NAMES, + IMAGE_HOSTING_TYPE, + MJX_DATA_FORMULA, + MJX_DATA_FORMULA_TYPE, +} from "./utils/constant"; +import {markdownParser, markdownParserWechat, updateMathjax} from "./utils/helper"; +import pluginCenter from "./utils/pluginCenter"; +import appContext from "./utils/appContext"; +import {uploadAdaptor} from "./utils/imageHosting"; +import bindHotkeys, {betterTab, rightClick} from "./utils/hotkey"; + +@inject("content") +@inject("navbar") +@inject("footer") +@inject("view") +@inject("dialog") +@inject("imageHosting") +@observer +class App extends Component { + constructor(props) { + super(props); + this.scale = 1; + this.handleUpdateMathjax = throttle(updateMathjax, 1500); + this.state = { + focus: false, + }; + } + + componentDidMount() { + document.addEventListener("fullscreenchange", this.solveScreenChange); + document.addEventListener("webkitfullscreenchange", this.solveScreenChange); + document.addEventListener("mozfullscreenchange", this.solveScreenChange); + document.addEventListener("MSFullscreenChange", this.solveScreenChange); + try { + window.MathJax = { + tex: { + inlineMath: [["$", "$"]], + displayMath: [["$$", "$$"]], + tags: "ams", + }, + svg: { + fontCache: "none", + }, + options: { + renderActions: { + addMenu: [0, "", ""], + addContainer: [ + 190, + (doc) => { + for (const math of doc.math) { + this.addContainer(math, doc); + } + }, + this.addContainer, + ], + }, + }, + }; + // eslint-disable-next-line + require("mathjax/es5/tex-svg-full"); + pluginCenter.mathjax = true; + } catch (e) { + console.log(e); + } + this.setEditorContent(); + this.setCustomImageHosting(); + } + + componentDidUpdate() { + if (pluginCenter.mathjax) { + this.handleUpdateMathjax(); + } + } + + componentWillUnmount() { + document.removeEventListener("fullscreenchange", this.solveScreenChange); + document.removeEventListener("webkitfullscreenchange", this.solveScreenChange); + document.removeEventListener("mozfullscreenchange", this.solveScreenChange); + document.removeEventListener("MSFullscreenChange", this.solveScreenChange); + } + + setCustomImageHosting = () => { + if (this.props.useImageHosting === undefined) { + return; + } + const {url, name, isSmmsOpen, isQiniuyunOpen, isAliyunOpen, isGiteeOpen, isGitHubOpen} = this.props.useImageHosting; + if (name) { + this.props.imageHosting.setHostingUrl(url); + this.props.imageHosting.setHostingName(name); + this.props.imageHosting.addImageHosting(name); + } + if (isSmmsOpen) { + this.props.imageHosting.addImageHosting(IMAGE_HOSTING_NAMES.smms); + } + if (isAliyunOpen) { + this.props.imageHosting.addImageHosting(IMAGE_HOSTING_NAMES.aliyun); + } + if (isQiniuyunOpen) { + this.props.imageHosting.addImageHosting(IMAGE_HOSTING_NAMES.qiniuyun); + } + if (isGiteeOpen) { + this.props.imageHosting.addImageHosting(IMAGE_HOSTING_NAMES.gitee); + } + if (isGitHubOpen) { + this.props.imageHosting.addImageHosting(IMAGE_HOSTING_NAMES.github); + } + + // 第一次进入没有默认图床时 + if (window.localStorage.getItem(IMAGE_HOSTING_TYPE) === null) { + let type; + if (name) { + type = name; + } else if (isSmmsOpen) { + type = IMAGE_HOSTING_NAMES.smms; + } else if (isAliyunOpen) { + type = IMAGE_HOSTING_NAMES.aliyun; + } else if (isQiniuyunOpen) { + type = IMAGE_HOSTING_NAMES.qiniuyun; + } else if (isGiteeOpen) { + type = IMAGE_HOSTING_NAMES.isGitee; + } + this.props.imageHosting.setType(type); + window.localStorage.setItem(IMAGE_HOSTING_TYPE, type); + } + }; + + setEditorContent = () => { + const {defaultText} = this.props; + if (defaultText) { + this.props.content.setContent(defaultText); + } + }; + + setCurrentIndex(index) { + this.index = index; + } + + solveScreenChange = () => { + const {isImmersiveEditing} = this.props.view; + this.props.view.setImmersiveEditing(!isImmersiveEditing); + }; + + getInstance = (instance) => { + instance.editor.on("inputRead", function(cm, event) { + if (event.origin === "paste") { + var text = event.text[0]; // pasted string + var new_text = ""; // any operations here + cm.refresh(); + const {length} = cm.getSelections(); + // my first idea was + // note: for multiline strings may need more complex calculations + cm.replaceRange(new_text, event.from, {line: event.from.line, ch: event.from.ch + text.length}); + // first solution did'nt work (before i guess to call refresh) so i tried that way, works too + if (length === 1) { + cm.execCommand("undo"); + } + // cm.setCursor(event.from); + cm.replaceSelection(new_text); + } + }); + if (instance) { + this.props.content.setMarkdownEditor(instance.editor); + } + }; + + handleScroll = () => { + if (this.props.navbar.isSyncScroll) { + const {markdownEditor} = this.props.content; + const cmData = markdownEditor.getScrollInfo(); + const editorToTop = cmData.top; + const editorScrollHeight = cmData.height - cmData.clientHeight; + this.scale = (this.previewWrap.offsetHeight - this.previewContainer.offsetHeight + 55) / editorScrollHeight; + if (this.index === 1) { + this.previewContainer.scrollTop = editorToTop * this.scale; + } else { + this.editorTop = this.previewContainer.scrollTop / this.scale; + markdownEditor.scrollTo(null, this.editorTop); + } + } + }; + + handleChange = (editor) => { + if (this.state.focus) { + const content = editor.getValue(); + this.props.content.setContent(content); + this.props.onTextChange && this.props.onTextChange(content); + } + }; + + handleFocus = (editor) => { + this.setState({ + focus: true, + }); + this.props.onTextFocus && this.props.onTextFocus(editor.getValue()); + }; + + handleBlur = (editor) => { + this.setState({ + focus: false, + }); + this.props.onTextBlur && this.props.onTextBlur(editor.getValue()); + }; + + getStyleInstance = (instance) => { + if (instance) { + this.styleEditor = instance.editor; + this.styleEditor.on("keyup", (cm, e) => { + if ((e.keyCode >= 65 && e.keyCode <= 90) || e.keyCode === 189) { + cm.showHint(e); + } + }); + } + }; + + handleDrop = (instance, e) => { + // e.preventDefault(); + // console.log(e.dataTransfer.files[0]); + if (!(e.dataTransfer && e.dataTransfer.files)) { + return; + } + for (let i = 0; i < e.dataTransfer.files.length; i++) { + // console.log(e.dataTransfer.files[i]); + uploadAdaptor({file: e.dataTransfer.files[i], content: this.props.content}); + } + }; + + handlePaste = (instance, e) => { + const cbData = e.clipboardData; + + const insertPasteContent = (cm, content) => { + const {length} = cm.getSelections(); + cm.replaceSelections(Array(length).fill(content)); + this.setState( + { + focus: true, + }, + () => { + this.handleChange(cm); + }, + ); + }; + + if (e.clipboardData && e.clipboardData.files) { + for (let i = 0; i < e.clipboardData.files.length; i++) { + uploadAdaptor({file: e.clipboardData.files[i], content: this.props.content}); + } + } + + if (cbData) { + const html = cbData.getData("text/html"); + const text = cbData.getData("TEXT"); + insertPasteContent(instance, text); + console.log(html); + + if (html) { + console.log("htmsdkskdkskdk"); + this.props.footer.setPasteHtmlChecked(true); + this.props.footer.setPasteHtml(html); + this.props.footer.setPasteText(text); + } else { + this.props.footer.setPasteHtmlChecked(false); + } + } + }; + + addContainer(math, doc) { + const tag = "span"; + const spanClass = math.display ? "span-block-equation" : "span-inline-equation"; + const cls = math.display ? "block-equation" : "inline-equation"; + math.typesetRoot.className = cls; + math.typesetRoot.setAttribute(MJX_DATA_FORMULA, math.math); + math.typesetRoot.setAttribute(MJX_DATA_FORMULA_TYPE, cls); + math.typesetRoot = doc.adaptor.node(tag, {class: spanClass, style: "cursor:pointer"}, [math.typesetRoot]); + } + + render() { + const {codeNum, previewType} = this.props.navbar; + const {isEditAreaOpen, isPreviewAreaOpen, isStyleEditorOpen, isImmersiveEditing} = this.props.view; + const {isSearchOpen} = this.props.dialog; + + const parseHtml = + codeNum === 0 + ? markdownParserWechat.render(this.props.content.content) + : markdownParser.render(this.props.content.content); + + const mdEditingClass = classnames({ + "nice-md-editing": !isImmersiveEditing, + "nice-md-editing-immersive": isImmersiveEditing, + "nice-md-editing-hide": !isEditAreaOpen, + }); + + const styleEditingClass = classnames({ + "nice-style-editing": true, + "nice-style-editing-hide": isImmersiveEditing, + }); + + const richTextClass = classnames({ + "nice-marked-text": true, + "nice-marked-text-pc": previewType === "pc", + "nice-marked-text-hide": isImmersiveEditing || !isPreviewAreaOpen, + }); + + const richTextBoxClass = classnames({ + "nice-wx-box": true, + "nice-wx-box-pc": previewType === "pc", + }); + + const textContainerClass = classnames({ + "nice-text-container": !isImmersiveEditing, + "nice-text-container-immersive": isImmersiveEditing, + }); + + return ( + + {({defaultTitle, onStyleChange, onStyleBlur, onStyleFocus, token}) => ( +
+ + +
+
this.setCurrentIndex(1, e)}> + {isSearchOpen && } + +
+
this.setCurrentIndex(2, e)}> + +
{ + this.previewContainer = node; + }} + > +
{ + this.previewWrap = node; + }} + /> +
+
+ + {isStyleEditorOpen && ( +
+ +
+ )} + + + +
+
+
+ )} +
+ ); + } +} + +export default App; diff --git a/src/App.test.js b/src/App.test.js new file mode 100644 index 0000000..a754b20 --- /dev/null +++ b/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/src/Lib.js b/src/Lib.js new file mode 100644 index 0000000..ea65612 --- /dev/null +++ b/src/Lib.js @@ -0,0 +1,155 @@ +import React, {Component} from "react"; +import PropTypes from "prop-types"; +import {Result} from "antd"; +import {Provider} from "mobx-react"; + +import "./index.css"; + +import App from "./App"; + +import content from "./store/content"; +import userInfo from "./store/userInfo"; +import navbar from "./store/navbar"; +import footer from "./store/footer"; +import dialog from "./store/dialog"; +import imageHosting from "./store/imageHosting"; +import view from "./store/view"; + +import {isPC} from "./utils/helper"; +import appContext from "./utils/appContext"; +import SvgIcon from "./icon"; +import {solveWeChatMath, solveZhihuMath, solveHtml} from "./utils/converter"; +import {LAYOUT_ID} from "./utils/constant"; + +class Lib extends Component { + getWeChatHtml() { + const layout = document.getElementById(LAYOUT_ID); // 保护现场 + const html = layout.innerHTML; + solveWeChatMath(); + const res = solveHtml(); + layout.innerHTML = html; // 恢复现场 + return res; + } + + getZhihuHtml() { + const layout = document.getElementById(LAYOUT_ID); // 保护现场 + const html = layout.innerHTML; + solveZhihuMath(); + const res = solveHtml(); + layout.innerHTML = html; // 恢复现场 + return res; + } + + render() { + const { + defaultTitle, + defaultText, + onTextChange, + onTextBlur, + onTextFocus, + onStyleChange, + onStyleBlur, + onStyleFocus, + token, + useImageHosting, + } = this.props; + const appCtx = { + defaultTitle, + defaultText, + onTextChange, + onTextBlur, + onTextFocus, + onStyleChange, + onStyleBlur, + onStyleFocus, + token, + useImageHosting, + }; + return ( + + {isPC() ? ( + + + + ) : ( + } + title="请使用 PC 端打开排版工具" + subTitle="更多 Markdown Nice 信息,请扫码关注公众号「编程如画」" + extra={} + /> + )} + + ); + } +} + +const style = { + svgIcon: { + width: "72px", + height: "72px", + }, +}; + +Lib.defaultProps = { + defaultTitle: "", + defaultText: "", + onTextChange: () => {}, + onTextBlur: () => {}, + onTextFocus: () => {}, + onStyleChange: () => {}, + onStyleBlur: () => {}, + onStyleFocus: () => {}, + token: "", + // eslint-disable-next-line react/default-props-match-prop-types + useImageHosting: { + url: "", + name: "", + isSmmsOpen: true, + isQiniuyunOpen: true, + isAliyunOpen: true, + isGiteeOpen: true, + isGitHubOpen: true, + }, +}; +Lib.propTypes = { + defaultTitle: PropTypes.string, + defaultText: PropTypes.string, + onTextChange: PropTypes.func, + onTextBlur: PropTypes.func, + onTextFocus: PropTypes.func, + onStyleChange: PropTypes.func, + onStyleBlur: PropTypes.func, + onStyleFocus: PropTypes.func, + token: PropTypes.string, + // eslint-disable-next-line react/require-default-props + useImageHosting: PropTypes.shape({ + url: PropTypes.string, + name: PropTypes.string, + isSmmsOpen: PropTypes.bool, + isQiniuyunOpen: PropTypes.bool, + isAliyunOpen: PropTypes.bool, + isGiteeOpen: PropTypes.bool, + isGitHubOpen: PropTypes.bool, + }), +}; + +export default Lib; diff --git a/src/component/Dialog/AboutDialog.js b/src/component/Dialog/AboutDialog.js new file mode 100644 index 0000000..b6c6beb --- /dev/null +++ b/src/component/Dialog/AboutDialog.js @@ -0,0 +1,100 @@ +import React, {Component} from "react"; +import {observer, inject} from "mobx-react"; +import {Modal, Button} from "antd"; + +@inject("dialog") +@observer +class AboutDialog extends Component { + handleOk = () => { + this.props.dialog.setAboutOpen(false); + }; + + handleCancel = () => { + this.props.dialog.setAboutOpen(false); + }; + + handleVersion = () => { + this.props.dialog.setAboutOpen(false); + this.props.dialog.setVersionOpen(true); + }; + + render() { + return ( + + 确认 + , + ]} + bodyStyle={{ + paddingTop: "5px", + }} + > +

+ Markdown2Html + + + +

+ +

支持自定义样式的 Markdown 编辑器;

+

支持微信公众号、知乎和稀土掘金;

+

+ 如果你喜欢我们的工具,欢迎关注 + +  GitHub  + +

+
+ ); + } +} + +const style = { + leftImgWidth: { + width: "40%", + height: "100%", + }, + rightImgWidth: { + width: "60%", + height: "100%", + }, + headerMargin: { + marginTop: "5px", + marginBottom: "5px", + color: "black", + }, + lineHeight: { + lineHeight: "26px", + color: "black", + padding: 0, + margin: 0, + }, + img: { + width: "70px", + marginLeft: "10px", + display: "inline-block", + }, + noBorder: { + border: "none", + }, +}; + +export default AboutDialog; diff --git a/src/component/Dialog/FormDialog.js b/src/component/Dialog/FormDialog.js new file mode 100644 index 0000000..095130d --- /dev/null +++ b/src/component/Dialog/FormDialog.js @@ -0,0 +1,102 @@ +import React from "react"; +import {observer, inject} from "mobx-react"; +import {Modal, InputNumber, Form} from "antd"; + +@inject("dialog") +@inject("content") +@observer +class FormDialog extends React.Component { + constructor(props) { + super(props); + this.state = { + ...initialState, + }; + } + + buildRow = (rowNum, columnNum) => { + let appendText = "|"; + if (rowNum === 1) { + appendText += " --- |"; + for (let i = 0; i < columnNum - 1; i++) { + appendText += " --- |"; + } + } else { + appendText += " |"; + for (let i = 0; i < columnNum - 1; i++) { + appendText += " |"; + } + } + return appendText + (/windows|win32/i.test(navigator.userAgent) ? "\r\n" : "\n"); + }; + + buildFormFormat = (rowNum, columnNum) => { + let formFormat = ""; + for (let i = 0; i < 3; i++) { + formFormat += this.buildRow(i, columnNum); + } + for (let i = 3; i <= rowNum; i++) { + formFormat += this.buildRow(i, columnNum); + } + return formFormat; + }; + + handleOk = () => { + const {markdownEditor} = this.props.content; + const cursor = markdownEditor.getCursor(); + + const text = this.buildFormFormat(this.state.rowNum, this.state.columnNum); + markdownEditor.replaceSelection(text, cursor); + + const content = markdownEditor.getValue(); + this.props.content.setContent(content); + + this.handleCancel(); + cursor.ch += 2; + markdownEditor.setCursor(cursor); + markdownEditor.focus(); + }; + + handleCancel = () => { + this.setState(initialState); + this.props.dialog.setFormOpen(false); + }; + + render() { + return ( + + + this.setState({rowNum: value})} + /> + + + this.setState({columnNum: value})} + /> + + + ); + } +} + +const initialState = { + columnNum: 1, + rowNum: 2, +}; + +export default FormDialog; diff --git a/src/component/Dialog/HistoryDialog.js b/src/component/Dialog/HistoryDialog.js new file mode 100644 index 0000000..fd6c527 --- /dev/null +++ b/src/component/Dialog/HistoryDialog.js @@ -0,0 +1,146 @@ +import React, {Component} from "react"; +import {observer, inject} from "mobx-react"; +import {Modal, Empty, message} from "antd"; +import LocalHistory from "../LocalHistory"; +import {AutoSaveInterval, getLocalDocuments, setLocalDocuments, setLocalDraft} from "../LocalHistory/util"; +import IndexDB from "../LocalHistory/indexdb"; +import debouce from "lodash.debounce"; + +const DocumentID = 1; + +@inject("dialog") +@inject("content") +@observer +class HistoryDialog extends Component { + timer = null; + + db = null; + + constructor(props) { + super(props); + this.state = { + documents: [], + }; + } + + async componentDidMount() { + await this.initIndexDB(); + } + + componentWillUnmount() { + clearInterval(this.timer); + } + + get editor() { + return this.props.content.markdownEditor; + } + + // + // async UNSAFE_componentWillReceiveProps(nextProps) { + // // 文档 id 变更 + // if (this.props.documentID !== nextProps.documentID && nextProps.documentID != null) { + // if (this.db) { + // await this.overrideLocalDocuments(nextProps.documentID); + // } + // } + // } + // + + closeDialog = () => { + this.props.dialog.setHistoryOpen(false); + }; + + editLocalDocument = (content) => { + this.props.content.setContent(content); + message.success("恢复成功!"); + this.closeDialog(); + }; + + autoSave = async (isRecent = false) => { + const Content = this.props.content.markdownEditor.getValue(); + if (Content.trim() !== "") { + const document = { + Content, + DocumentID: this.props.documentID, + SaveTime: new Date(), + }; + const setLocalDocumentMethod = isRecent && this.state.documents.length > 0 ? setLocalDraft : setLocalDocuments; + await setLocalDocumentMethod(this.db, this.state.documents, document); + await this.overrideLocalDocuments(this.props.documentID); + } + }; + + async initIndexDB() { + try { + const indexDB = new IndexDB({ + name: "mdnice-local-history", + storeName: "customers", + storeOptions: {keyPath: "id", autoIncrement: true}, + storeInit: (objectStore) => { + objectStore.createIndex("DocumentID", "DocumentID", {unique: false}); + objectStore.createIndex("SaveTime", "SaveTime", {unique: false}); + }, + }); + this.db = await indexDB.init(); + + if (this.db && this.props.documentID) { + await this.overrideLocalDocuments(this.props.documentID); + } + // 每隔一段时间自动保存 + this.timer = setInterval(async () => { + await this.autoSave(); + }, AutoSaveInterval); + // 每改变内容自动保存最近的一条 + this.editor.on && + this.editor.on( + "change", + debouce(async () => { + await this.autoSave(true); + }, 1000), + ); + } catch (e) { + console.error(e); + } + } + + // 刷新本地历史文档 + async overrideLocalDocuments(documentID) { + const localDocuments = await getLocalDocuments(this.db, +documentID); + // console.log('refresh local',localDocuments); + this.setState({ + documents: localDocuments, + }); + } + + render() { + return ( + + {this.state.documents && this.state.documents.length > 0 ? ( + + ) : ( + + )} + + ); + } +} + +HistoryDialog.defaultProps = { + documentID: DocumentID, +}; + +export default HistoryDialog; diff --git a/src/component/Dialog/ImageDialog.js b/src/component/Dialog/ImageDialog.js new file mode 100644 index 0000000..0ada692 --- /dev/null +++ b/src/component/Dialog/ImageDialog.js @@ -0,0 +1,180 @@ +import React, {Component} from "react"; +import {observer, inject} from "mobx-react"; +import {Modal, Upload, Tabs, Select} from "antd"; + +import SvgIcon from "../../icon"; + +import AliOSS from "../ImageHosting/AliOSS"; +import QiniuOSS from "../ImageHosting/QiniuOSS"; +import Gitee from "../ImageHosting/Gitee"; +import GitHub from "../ImageHosting/GitHub"; + +import {uploadAdaptor} from "../../utils/imageHosting"; +import {SM_MS_PROXY, IMAGE_HOSTING_TYPE, IMAGE_HOSTING_NAMES} from "../../utils/constant"; +import appContext from "../../utils/appContext"; + +const {Dragger} = Upload; +const {TabPane} = Tabs; +const {Option} = Select; + +@inject("dialog") +@inject("content") +@inject("imageHosting") +@inject("navbar") +@observer +class ImageDialog extends Component { + constructor(props) { + super(props); + this.images = []; + } + + // 确认后将内容更新到编辑器上 + handleOk = () => { + let text = ""; + // 成功后添加url + if (this.props.navbar.isContainImgName) { + this.images.forEach((value) => { + text += `![${value.filename}](${value.url})\n`; + }); + } else { + this.images.forEach((value) => { + text += `![](${value.url})\n`; + }); + } + // 重新初始化 + this.images = []; + const {markdownEditor} = this.props.content; + const cursor = markdownEditor.getCursor(); + markdownEditor.replaceSelection(text, cursor); + // 上传后实时更新内容 + const content = markdownEditor.getValue(); + this.props.content.setContent(content); + + this.props.dialog.setImageOpen(false); + cursor.ch += 2; + markdownEditor.setCursor(cursor); + markdownEditor.focus(); + }; + + handleCancel = () => { + this.props.dialog.setImageOpen(false); + }; + + customRequest = ({action, data, file, headers, onError, onProgress, onSuccess, withCredentials}) => { + const formData = new FormData(); + const {images} = this; + if (data) { + Object.keys(data).forEach((key) => { + formData.append(key, data[key]); + }); + } + // 使用阿里云图床 + if (this.props.imageHosting.type === "阿里云") { + uploadAdaptor({file, onSuccess, onError, images}); + } + // 使用七牛云图床 + else if (this.props.imageHosting.type === "七牛云") { + uploadAdaptor({file, onSuccess, onError, onProgress, images}); + } + // 使用SM.MS图床 + else if (this.props.imageHosting.type === "SM.MS") { + uploadAdaptor({formData, file, action, onProgress, onSuccess, onError, headers, withCredentials}); + } + // 使用Gitee图床 + else if (this.props.imageHosting.type === "Gitee") { + uploadAdaptor({formData, file, action, onProgress, onSuccess, onError, headers, withCredentials, images}); + } + // 使用GitHub图床 + else if (this.props.imageHosting.type === "GitHub") { + uploadAdaptor({formData, file, action, onProgress, onSuccess, onError, headers, withCredentials, images}); + } + // 使用用户提供的图床或是默认mdnice图床 + else { + uploadAdaptor({formData, file, onSuccess, onError, images}); + } + + return { + abort() { + console.log("upload progress is aborted."); + }, + }; + }; + + typeChange = (type) => { + this.props.imageHosting.setType(type); + window.localStorage.setItem(IMAGE_HOSTING_TYPE, type); + }; + + render() { + const {hostingList, type} = this.props.imageHosting; + + const columns = hostingList.map((option, index) => ( + + )); + + const imageHostingSwitch = ( + + ); + + return ( + + + {({useImageHosting}) => ( + + + +

+ +

+

点击或拖拽一张或多张照片上传

+

{"正在使用" + type + "图床"}

+
+
+ {useImageHosting.isAliyunOpen ? ( + + + + ) : null} + {useImageHosting.isQiniuyunOpen ? ( + + + + ) : null} + {useImageHosting.isGiteeOpen ? ( + + + + ) : null} + {useImageHosting.isGitHubOpen ? ( + + + + ) : null} +
+ )} +
+
+ ); + } +} + +const style = { + svgIcon: { + width: "48px", + height: "48px", + }, +}; + +export default ImageDialog; diff --git a/src/component/Dialog/LinkDialog.js b/src/component/Dialog/LinkDialog.js new file mode 100644 index 0000000..afca47b --- /dev/null +++ b/src/component/Dialog/LinkDialog.js @@ -0,0 +1,61 @@ +import React, {Component} from "react"; +import {observer, inject} from "mobx-react"; +import {Modal, Input, Form} from "antd"; + +@inject("dialog") +@inject("content") +@observer +class LinkDialog extends Component { + constructor(props) { + super(props); + this.state = { + link: "", + }; + } + + handleOk = () => { + const {markdownEditor} = this.props.content; + const cursor = markdownEditor.getCursor(); + const selection = markdownEditor.getSelection(); + const text = `[${selection}](${this.state.link})`; + markdownEditor.replaceSelection(text, cursor); + + // 上传后实时更新内容 + const content = markdownEditor.getValue(); + this.props.content.setContent(content); + + this.setState({link: ""}); + this.props.dialog.setLinkOpen(false); + cursor.ch += 1; + markdownEditor.setCursor(cursor); + markdownEditor.focus(); + }; + + handleCancel = () => { + this.setState({link: ""}); + this.props.dialog.setLinkOpen(false); + }; + + handleChange = (e) => { + this.setState({link: e.target.value}); + }; + + render() { + return ( + + + + + + ); + } +} + +export default LinkDialog; diff --git a/src/component/Dialog/SitDownDialog.js b/src/component/Dialog/SitDownDialog.js new file mode 100644 index 0000000..a08985c --- /dev/null +++ b/src/component/Dialog/SitDownDialog.js @@ -0,0 +1,106 @@ +import React, {Component} from "react"; +import {observer, inject} from "mobx-react"; +import {Modal, Input, Select, message} from "antd"; + +import SitDownConverter from "../../utils/sitdownConverter"; +import {SITDOWN_OPTIONS} from "../../utils/constant"; + +const {Option} = Select; +const {TextArea} = Input; + +@inject("dialog") +@inject("content") +@observer +class SitDownDialog extends Component { + constructor(props) { + super(props); + this.state = { + platform: "default", + sourceCode: "", + }; + } + + handleOk = () => { + try { + const {platform, sourceCode} = this.state; + + const domParser = new DOMParser(); + const sourceCodeDom = domParser.parseFromString(sourceCode, "text/html"); + + let content = ""; + + if (platform === "csdn") { + const articleDom = sourceCodeDom.getElementById("content_views"); + content = SitDownConverter.CSDN(articleDom); + } else if (platform === "juejin") { + const articleDom = sourceCodeDom.getElementsByClassName("article-content"); + content = SitDownConverter.Juejin(articleDom[0]); + } else if (platform === "zhihu") { + const articleDom = sourceCodeDom.getElementsByClassName("Post-RichText"); + content = SitDownConverter.Zhihu(articleDom[0]); + } else if (platform === "wechat") { + const articleDom = sourceCodeDom.getElementById("js_content"); + content = SitDownConverter.Wechat(articleDom); + } else { + content = SitDownConverter.GFM(sourceCodeDom); + } + + this.props.content.setContent(content); + + this.props.dialog.setSitDownOpen(false); + + const {markdownEditor} = this.props.content; + // const cursor = markdownEditor.getCursor(); + // cursor.ch += 1; + // markdownEditor.setCursor(cursor); + markdownEditor.focus(); + } catch (e) { + message.error("源代码与已选平台的文章域名不符"); + } + }; + + handleCancel = () => { + this.props.dialog.setSitDownOpen(false); + }; + + handlePlatform = (value) => { + this.setState({platform: value}); + }; + + handleSourceCode = (e) => { + this.setState({sourceCode: e.target.value}); + }; + + render() { + const {sourceCode, platform} = this.state; + return ( + + + +