├── docs
├── .gitkeep
├── CNAME
├── assets
│ ├── icon.png
│ ├── background.jpg
│ ├── site-shot.png
│ ├── export-shot.png
│ ├── f-multisource.png
│ ├── logo-github.png
│ ├── screen-shot.png
│ ├── gh-fork-ribbon.min.css
│ ├── index.js
│ └── site.css
├── images
│ └── mditor.png
├── fonts
│ ├── FontAwesome.otf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ └── fontawesome-webfont.woff2
├── slide
│ ├── css
│ │ └── bundle.css.map
│ ├── font
│ │ ├── 674f50d287a8c48dc19ba404d20fe713.eot
│ │ ├── a48ac41620cd818c5020d0f4302489ff.ttf
│ │ ├── af7ae505a9eed503f8b8e6982036873e.woff2
│ │ ├── b06871f281fee6b241d60582ae9369b9.ttf
│ │ └── fee66e712a8a08eef5805a46892932ad.woff
│ └── index.html
├── update.json
├── javascripts
│ └── scale.fix.js
├── doc
│ ├── slide.md
│ └── slide.html
└── stylesheets
│ └── github-light.css
├── packages
├── desktop
│ ├── docs
│ │ ├── .gitkeep
│ │ ├── CNAME
│ │ ├── assets
│ │ │ ├── icon.png
│ │ │ ├── background.jpg
│ │ │ ├── export-shot.png
│ │ │ ├── logo-github.png
│ │ │ ├── screen-shot.png
│ │ │ ├── site-shot.png
│ │ │ ├── f-multisource.png
│ │ │ ├── gh-fork-ribbon.min.css
│ │ │ ├── index.js
│ │ │ └── site.css
│ │ ├── images
│ │ │ └── mditor.png
│ │ ├── fonts
│ │ │ ├── FontAwesome.otf
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ ├── fontawesome-webfont.woff
│ │ │ └── fontawesome-webfont.woff2
│ │ ├── update.json
│ │ ├── slide
│ │ │ ├── font
│ │ │ │ ├── 674f50d287a8c48dc19ba404d20fe713.eot
│ │ │ │ ├── a48ac41620cd818c5020d0f4302489ff.ttf
│ │ │ │ ├── b06871f281fee6b241d60582ae9369b9.ttf
│ │ │ │ ├── af7ae505a9eed503f8b8e6982036873e.woff2
│ │ │ │ └── fee66e712a8a08eef5805a46892932ad.woff
│ │ │ └── index.html
│ │ ├── javascripts
│ │ │ └── scale.fix.js
│ │ ├── doc
│ │ │ ├── slide.md
│ │ │ └── slide.html
│ │ └── stylesheets
│ │ │ └── github-light.css
│ ├── test
│ │ ├── e2e
│ │ │ ├── .gitkeep
│ │ │ └── demo.test.js
│ │ ├── unit
│ │ │ ├── .gitkeep
│ │ │ └── demo.test.js
│ │ └── driver.js
│ ├── bin
│ │ ├── start.sh
│ │ ├── restart.sh
│ │ ├── prepublish.sh
│ │ ├── stop.sh
│ │ ├── clear.sh
│ │ ├── test.sh
│ │ ├── build.sh
│ │ ├── e2e.sh
│ │ ├── watch.sh
│ │ ├── unit.sh
│ │ ├── release.sh
│ │ ├── info.plist
│ │ └── release.js
│ ├── server.local.yml.rename
│ ├── src
│ │ ├── convert
│ │ │ ├── html.css
│ │ │ ├── border.css
│ │ │ ├── tmpl.html
│ │ │ ├── slide.html
│ │ │ └── index.js
│ │ ├── common
│ │ │ ├── sleep.js
│ │ │ ├── yaml.js
│ │ │ ├── mkdirp.js
│ │ │ ├── fs.js
│ │ │ ├── blob2base64.js
│ │ │ ├── blob2buffer.js
│ │ │ └── store.js
│ │ ├── menu
│ │ │ ├── index.js
│ │ │ ├── view.js
│ │ │ ├── help.js
│ │ │ ├── window.js
│ │ │ ├── contextmenu.js
│ │ │ ├── edit.js
│ │ │ ├── main.js
│ │ │ └── file.js
│ │ ├── window
│ │ │ ├── index.html
│ │ │ ├── drapable.js
│ │ │ ├── index.less
│ │ │ └── index.js
│ │ ├── preference
│ │ │ ├── tmpl.md
│ │ │ └── index.js
│ │ ├── recent
│ │ │ └── index.js
│ │ ├── i18n
│ │ │ ├── index.js
│ │ │ └── locales
│ │ │ │ ├── zh.yml
│ │ │ │ └── en.yml
│ │ ├── update
│ │ │ └── index.js
│ │ └── uml
│ │ │ └── index.js
│ ├── design
│ │ ├── icon.icns
│ │ ├── icon.png
│ │ ├── icon.psd
│ │ ├── install.png
│ │ ├── install.psd
│ │ └── install.dmgCanvas
│ │ │ ├── Disk Image
│ │ │ └── QuickLook
│ │ │ └── Preview.jpg
│ ├── .gitignore
│ ├── .babelrc
│ ├── jasmine.json
│ ├── electron-builder.yml
│ ├── server.yml
│ ├── .npmignore
│ ├── CHANGELOG.md
│ ├── karma.conf.js
│ ├── .eslintrc.yml
│ ├── README.md
│ ├── webpack.config.js
│ └── package.json
└── embed
│ ├── src
│ ├── plugins
│ │ └── csv.js
│ ├── server
│ │ └── index.js
│ ├── assets
│ │ ├── fonts
│ │ │ ├── Roboto-Black.ttf
│ │ │ ├── Roboto-Bold.ttf
│ │ │ ├── Roboto-Italic.ttf
│ │ │ ├── Roboto-Light.ttf
│ │ │ ├── Roboto-Medium.ttf
│ │ │ ├── Roboto-Thin.ttf
│ │ │ ├── robotomono.woff2
│ │ │ ├── Roboto-Regular.ttf
│ │ │ ├── RobotoMono-Bold.ttf
│ │ │ ├── RobotoMono-Thin.ttf
│ │ │ ├── Roboto-BlackItalic.ttf
│ │ │ ├── Roboto-BoldItalic.ttf
│ │ │ ├── Roboto-LightItalic.ttf
│ │ │ ├── Roboto-ThinItalic.ttf
│ │ │ ├── RobotoMono-Italic.ttf
│ │ │ ├── RobotoMono-Light.ttf
│ │ │ ├── RobotoMono-Medium.ttf
│ │ │ ├── RobotoMono-Regular.ttf
│ │ │ ├── Roboto-MediumItalic.ttf
│ │ │ ├── RobotoMono-BoldItalic.ttf
│ │ │ ├── RobotoMono-LightItalic.ttf
│ │ │ ├── RobotoMono-MediumItalic.ttf
│ │ │ └── RobotoMono-ThinItalic.ttf
│ │ └── index.ejs
│ ├── viewer
│ │ ├── index.html
│ │ ├── index.less
│ │ └── index.js
│ ├── toolbar
│ │ ├── index.html
│ │ ├── index.less
│ │ ├── index.js
│ │ └── items.js
│ ├── editor
│ │ ├── index.html
│ │ ├── commands.js
│ │ ├── stack.js
│ │ └── index.less
│ ├── finder
│ │ ├── index.html
│ │ ├── index.less
│ │ └── index.js
│ ├── client
│ │ ├── index.html
│ │ ├── shortcut.js
│ │ ├── index.less
│ │ └── index.js
│ └── common
│ │ └── parser.js
│ ├── test
│ ├── e2e
│ │ ├── .gitkeep
│ │ └── demo.test.js
│ ├── unit
│ │ ├── .gitkeep
│ │ └── demo.test.js
│ └── driver.js
│ ├── docs
│ ├── CNAME
│ ├── index.html
│ ├── images
│ │ └── mditor.png
│ └── demo
│ │ ├── css
│ │ ├── mditor.css.map
│ │ └── mditor.min.css.map
│ │ ├── font
│ │ ├── 674f50d287a8c48dc19ba404d20fe713.eot
│ │ ├── a48ac41620cd818c5020d0f4302489ff.ttf
│ │ ├── b06871f281fee6b241d60582ae9369b9.ttf
│ │ ├── af7ae505a9eed503f8b8e6982036873e.woff2
│ │ └── fee66e712a8a08eef5805a46892932ad.woff
│ │ └── index.html
│ ├── lib
│ ├── plugins
│ │ └── csv.js
│ ├── server
│ │ └── index.js
│ ├── editor
│ │ ├── commands.js
│ │ └── stack.js
│ ├── client
│ │ ├── shortcut.js
│ │ └── index.js
│ ├── viewer
│ │ └── index.js
│ ├── toolbar
│ │ ├── index.js
│ │ └── items.js
│ ├── finder
│ │ └── index.js
│ └── common
│ │ └── parser.js
│ ├── server.local.yml.rename
│ ├── bin
│ ├── restart.sh
│ ├── stop.sh
│ ├── prepublish.sh
│ ├── clear.sh
│ ├── test.sh
│ ├── e2e.sh
│ ├── start.sh
│ ├── watch.sh
│ ├── unit.sh
│ └── build.sh
│ ├── .gitignore
│ ├── dist
│ ├── css
│ │ ├── mditor.css.map
│ │ └── mditor.min.css.map
│ ├── font
│ │ ├── 674f50d287a8c48dc19ba404d20fe713.eot
│ │ ├── a48ac41620cd818c5020d0f4302489ff.ttf
│ │ ├── b06871f281fee6b241d60582ae9369b9.ttf
│ │ ├── af7ae505a9eed503f8b8e6982036873e.woff2
│ │ └── fee66e712a8a08eef5805a46892932ad.woff
│ └── index.html
│ ├── .babelrc
│ ├── jasmine.json
│ ├── .npmignore
│ ├── server.yml
│ ├── CHANGELOG.md
│ ├── karma.conf.js
│ ├── .eslintrc.yml
│ ├── webpack.config.js
│ ├── package.json
│ └── README.md
├── CNAME
├── .gitignore
└── README.md
/docs/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | mditor.ink
--------------------------------------------------------------------------------
/packages/desktop/docs/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/embed/src/plugins/csv.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/embed/test/e2e/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/embed/test/unit/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/desktop/docs/CNAME:
--------------------------------------------------------------------------------
1 | mditor.com
--------------------------------------------------------------------------------
/packages/desktop/test/e2e/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/desktop/test/unit/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | mditor.ink
2 | www.mditor.ink
3 |
--------------------------------------------------------------------------------
/packages/embed/docs/CNAME:
--------------------------------------------------------------------------------
1 | embed.mditor.com
--------------------------------------------------------------------------------
/packages/embed/lib/plugins/csv.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/"use strict";
--------------------------------------------------------------------------------
/packages/desktop/bin/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | electron .
--------------------------------------------------------------------------------
/packages/desktop/server.local.yml.rename:
--------------------------------------------------------------------------------
1 | proxy:
2 | rules:
3 | ^/api: '/'
--------------------------------------------------------------------------------
/packages/embed/server.local.yml.rename:
--------------------------------------------------------------------------------
1 | proxy:
2 | rules:
3 | ^/api: '/'
--------------------------------------------------------------------------------
/packages/desktop/src/convert/html.css:
--------------------------------------------------------------------------------
1 | .markdown-body table {
2 | display: table;
3 | }
--------------------------------------------------------------------------------
/packages/embed/bin/restart.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm stop && npm start
--------------------------------------------------------------------------------
/packages/embed/docs/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/assets/icon.png
--------------------------------------------------------------------------------
/packages/desktop/bin/restart.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm stop && npm start
--------------------------------------------------------------------------------
/packages/embed/bin/stop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | nokit delete $npm_package_name
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | *.log
3 | logs/
4 | node_modules/
5 | .vscode/
6 | server.local.yml
7 |
--------------------------------------------------------------------------------
/docs/images/mditor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/images/mditor.png
--------------------------------------------------------------------------------
/packages/desktop/bin/prepublish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm test
6 | npm run build
--------------------------------------------------------------------------------
/packages/desktop/bin/stop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | #nokit delete $npm_package_name
--------------------------------------------------------------------------------
/packages/embed/bin/prepublish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm test
6 | npm run build
--------------------------------------------------------------------------------
/docs/assets/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/assets/background.jpg
--------------------------------------------------------------------------------
/docs/assets/site-shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/assets/site-shot.png
--------------------------------------------------------------------------------
/docs/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/packages/embed/bin/clear.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | rm -rf ./dist/**
6 | mkdir -p ./dist
--------------------------------------------------------------------------------
/docs/assets/export-shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/assets/export-shot.png
--------------------------------------------------------------------------------
/docs/assets/f-multisource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/assets/f-multisource.png
--------------------------------------------------------------------------------
/docs/assets/logo-github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/assets/logo-github.png
--------------------------------------------------------------------------------
/docs/assets/screen-shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/assets/screen-shot.png
--------------------------------------------------------------------------------
/packages/embed/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | *.log
3 | logs/
4 | node_modules/
5 | .vscode/
6 | server.local.yml
7 |
--------------------------------------------------------------------------------
/docs/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/packages/desktop/bin/clear.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | rm -rf ./build/dist/**
6 | mkdir -p ./build/dist
--------------------------------------------------------------------------------
/packages/desktop/design/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/design/icon.icns
--------------------------------------------------------------------------------
/packages/desktop/design/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/design/icon.png
--------------------------------------------------------------------------------
/packages/desktop/design/icon.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/design/icon.psd
--------------------------------------------------------------------------------
/packages/embed/src/server/index.js:
--------------------------------------------------------------------------------
1 | exports.version = '{version}';
2 | exports.Parser = require('../common/parser');
--------------------------------------------------------------------------------
/docs/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/docs/slide/css/bundle.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/bundle.css","sourceRoot":""}
--------------------------------------------------------------------------------
/packages/desktop/design/install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/design/install.png
--------------------------------------------------------------------------------
/packages/desktop/design/install.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/design/install.psd
--------------------------------------------------------------------------------
/packages/embed/bin/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | export NODE_ENV=mock
6 |
7 | npm run unit
8 | npm run e2e
--------------------------------------------------------------------------------
/packages/desktop/bin/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | export NODE_ENV=mock
6 |
7 | npm run unit
8 | npm run e2e
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/assets/icon.png
--------------------------------------------------------------------------------
/packages/desktop/docs/images/mditor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/images/mditor.png
--------------------------------------------------------------------------------
/packages/embed/docs/images/mditor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/docs/images/mditor.png
--------------------------------------------------------------------------------
/packages/embed/dist/css/mditor.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/mditor.css","sourceRoot":""}
--------------------------------------------------------------------------------
/packages/desktop/bin/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm run clear
6 | npm run lint
7 |
8 | webpack --display-error-details
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/assets/background.jpg
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/export-shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/assets/export-shot.png
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/logo-github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/assets/logo-github.png
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/screen-shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/assets/screen-shot.png
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/site-shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/assets/site-shot.png
--------------------------------------------------------------------------------
/packages/desktop/docs/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/packages/embed/dist/css/mditor.min.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/mditor.min.css","sourceRoot":""}
--------------------------------------------------------------------------------
/packages/embed/docs/demo/css/mditor.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/mditor.css","sourceRoot":""}
--------------------------------------------------------------------------------
/docs/update.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0.0",
3 | "detail": [
4 | "1. 修正打开或保存对话框默认路径错误问题"
5 | ],
6 | "url": "http://mditor.com/"
7 | }
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/f-multisource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/assets/f-multisource.png
--------------------------------------------------------------------------------
/packages/embed/docs/demo/css/mditor.min.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/mditor.min.css","sourceRoot":""}
--------------------------------------------------------------------------------
/packages/embed/bin/e2e.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm run build
6 | npm restart
7 |
8 | JASMINE_CONFIG_PATH=$PWD/jasmine.json jasmine
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-Black.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-Italic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-Light.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-Thin.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/robotomono.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/robotomono.woff2
--------------------------------------------------------------------------------
/packages/desktop/bin/e2e.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm run build
6 | npm restart
7 |
8 | JASMINE_CONFIG_PATH=$PWD/jasmine.json jasmine
--------------------------------------------------------------------------------
/packages/desktop/docs/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/packages/desktop/docs/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/packages/embed/bin/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | nokit start --name $npm_package_name -p $npm_package_dev_port --config server -e local
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-Bold.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-Thin.ttf
--------------------------------------------------------------------------------
/docs/slide/font/674f50d287a8c48dc19ba404d20fe713.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/slide/font/674f50d287a8c48dc19ba404d20fe713.eot
--------------------------------------------------------------------------------
/docs/slide/font/a48ac41620cd818c5020d0f4302489ff.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/slide/font/a48ac41620cd818c5020d0f4302489ff.ttf
--------------------------------------------------------------------------------
/docs/slide/font/af7ae505a9eed503f8b8e6982036873e.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/slide/font/af7ae505a9eed503f8b8e6982036873e.woff2
--------------------------------------------------------------------------------
/docs/slide/font/b06871f281fee6b241d60582ae9369b9.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/slide/font/b06871f281fee6b241d60582ae9369b9.ttf
--------------------------------------------------------------------------------
/docs/slide/font/fee66e712a8a08eef5805a46892932ad.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/docs/slide/font/fee66e712a8a08eef5805a46892932ad.woff
--------------------------------------------------------------------------------
/packages/desktop/design/install.dmgCanvas/Disk Image:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/design/install.dmgCanvas/Disk Image
--------------------------------------------------------------------------------
/packages/desktop/docs/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/packages/desktop/docs/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-BlackItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-BlackItalic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-BoldItalic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-LightItalic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-ThinItalic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-Italic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-Light.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-Medium.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-Regular.ttf
--------------------------------------------------------------------------------
/packages/desktop/docs/update.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0.0",
3 | "detail": [
4 | "1. 修正打开或保存对话框默认路径错误问题"
5 | ],
6 | "url": "http://mditor.com/"
7 | }
--------------------------------------------------------------------------------
/packages/embed/lib/server/index.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | exports.version = '{version}';
4 | exports.Parser = require('../common/parser');
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/Roboto-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/Roboto-MediumItalic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-BoldItalic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-LightItalic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-MediumItalic.ttf
--------------------------------------------------------------------------------
/packages/embed/src/assets/fonts/RobotoMono-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/src/assets/fonts/RobotoMono-ThinItalic.ttf
--------------------------------------------------------------------------------
/packages/desktop/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | *.log
3 | *.js.map
4 | *.css.map
5 | logs/
6 | node_modules/
7 | build/
8 | .vscode/
9 | server.local.yml
10 | release/
--------------------------------------------------------------------------------
/packages/desktop/bin/watch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm run clear
6 | npm run lint
7 |
8 | export NODE_ENV=dev
9 | webpack --display-error-details --watch
--------------------------------------------------------------------------------
/packages/desktop/test/unit/demo.test.js:
--------------------------------------------------------------------------------
1 | describe('demo', function () {
2 |
3 | it('should do what...', function () {
4 | expect(0).not.toBe(1);
5 | });
6 |
7 | });
--------------------------------------------------------------------------------
/packages/embed/dist/font/674f50d287a8c48dc19ba404d20fe713.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/dist/font/674f50d287a8c48dc19ba404d20fe713.eot
--------------------------------------------------------------------------------
/packages/embed/dist/font/a48ac41620cd818c5020d0f4302489ff.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/dist/font/a48ac41620cd818c5020d0f4302489ff.ttf
--------------------------------------------------------------------------------
/packages/embed/dist/font/b06871f281fee6b241d60582ae9369b9.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/dist/font/b06871f281fee6b241d60582ae9369b9.ttf
--------------------------------------------------------------------------------
/packages/embed/test/unit/demo.test.js:
--------------------------------------------------------------------------------
1 | describe('demo', function () {
2 |
3 | it('should do what...', function () {
4 | expect(0).not.toBe(1);
5 | });
6 |
7 | });
--------------------------------------------------------------------------------
/packages/desktop/design/install.dmgCanvas/QuickLook/Preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/design/install.dmgCanvas/QuickLook/Preview.jpg
--------------------------------------------------------------------------------
/packages/embed/dist/font/af7ae505a9eed503f8b8e6982036873e.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/dist/font/af7ae505a9eed503f8b8e6982036873e.woff2
--------------------------------------------------------------------------------
/packages/embed/dist/font/fee66e712a8a08eef5805a46892932ad.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/dist/font/fee66e712a8a08eef5805a46892932ad.woff
--------------------------------------------------------------------------------
/packages/embed/docs/demo/font/674f50d287a8c48dc19ba404d20fe713.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/docs/demo/font/674f50d287a8c48dc19ba404d20fe713.eot
--------------------------------------------------------------------------------
/packages/embed/docs/demo/font/a48ac41620cd818c5020d0f4302489ff.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/docs/demo/font/a48ac41620cd818c5020d0f4302489ff.ttf
--------------------------------------------------------------------------------
/packages/embed/docs/demo/font/b06871f281fee6b241d60582ae9369b9.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/docs/demo/font/b06871f281fee6b241d60582ae9369b9.ttf
--------------------------------------------------------------------------------
/packages/desktop/docs/slide/font/674f50d287a8c48dc19ba404d20fe713.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/slide/font/674f50d287a8c48dc19ba404d20fe713.eot
--------------------------------------------------------------------------------
/packages/desktop/docs/slide/font/a48ac41620cd818c5020d0f4302489ff.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/slide/font/a48ac41620cd818c5020d0f4302489ff.ttf
--------------------------------------------------------------------------------
/packages/desktop/docs/slide/font/b06871f281fee6b241d60582ae9369b9.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/slide/font/b06871f281fee6b241d60582ae9369b9.ttf
--------------------------------------------------------------------------------
/packages/embed/docs/demo/font/af7ae505a9eed503f8b8e6982036873e.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/docs/demo/font/af7ae505a9eed503f8b8e6982036873e.woff2
--------------------------------------------------------------------------------
/packages/embed/docs/demo/font/fee66e712a8a08eef5805a46892932ad.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/embed/docs/demo/font/fee66e712a8a08eef5805a46892932ad.woff
--------------------------------------------------------------------------------
/packages/desktop/docs/slide/font/af7ae505a9eed503f8b8e6982036873e.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/slide/font/af7ae505a9eed503f8b8e6982036873e.woff2
--------------------------------------------------------------------------------
/packages/desktop/docs/slide/font/fee66e712a8a08eef5805a46892932ad.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Houfeng/mditor/HEAD/packages/desktop/docs/slide/font/fee66e712a8a08eef5805a46892932ad.woff
--------------------------------------------------------------------------------
/packages/desktop/src/common/sleep.js:
--------------------------------------------------------------------------------
1 | const Promise = require('bluebird');
2 |
3 | module.exports = function (delay) {
4 | return new Promise(resolve => {
5 | setTimeout(resolve, delay);
6 | });
7 | };
--------------------------------------------------------------------------------
/packages/embed/bin/watch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm run clear
6 | npm run lint
7 |
8 | npm run restart
9 |
10 | export NODE_ENV=dev
11 | webpack --display-error-details --watch
--------------------------------------------------------------------------------
/packages/embed/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015",
4 | "stage-3"
5 | ],
6 | "plugins": [
7 | "transform-runtime"
8 | ],
9 | "auxiliaryCommentBefore": "istanbul ignore next"
10 | }
--------------------------------------------------------------------------------
/packages/embed/src/viewer/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/desktop/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | //"es2015",
4 | //"stage-3"
5 | ],
6 | "plugins": [
7 | //"transform-runtime"
8 | ],
9 | "auxiliaryCommentBefore": "istanbul ignore next"
10 | }
--------------------------------------------------------------------------------
/packages/desktop/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "test",
3 | "spec_files": [
4 | "e2e/*.js"
5 | ],
6 | "helpers": [
7 | "driver.js"
8 | ],
9 | "stopSpecOnExpectationFailure": false,
10 | "random": false
11 | }
--------------------------------------------------------------------------------
/packages/embed/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "test",
3 | "spec_files": [
4 | "e2e/*.js"
5 | ],
6 | "helpers": [
7 | "driver.js"
8 | ],
9 | "stopSpecOnExpectationFailure": false,
10 | "random": false
11 | }
--------------------------------------------------------------------------------
/packages/desktop/electron-builder.yml:
--------------------------------------------------------------------------------
1 | appId: net.xhou.mditor
2 | electronVersion: "1.6.1"
3 | icon: ./design/icon.icns
4 | mac:
5 | category: net.xhou..mditor.editor
6 | target: dmg
7 | icon: ./design/icon.icns
8 | dmg:
9 | icon: ./design/icon.icns
--------------------------------------------------------------------------------
/packages/embed/.npmignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | *.log
3 | *.sh
4 | .babelrc
5 | .eslintrc.yml
6 | .travis.yml
7 | server.yml
8 | server.local.yml
9 | webpack.config.js
10 | logs/
11 | node_modules/
12 | scripts/
13 | docs/
14 | test/
15 | examples/
16 | .vscode/
--------------------------------------------------------------------------------
/packages/embed/server.yml:
--------------------------------------------------------------------------------
1 | filters:
2 | ^/: 'nokit-filter-proxy'
3 | public:
4 | ^/: './dist'
5 | cache:
6 | enabled: false
7 | log:
8 | enabled: false
9 | session:
10 | enabled: false
11 | proxy:
12 | rules:
13 | ^/api: '...'
--------------------------------------------------------------------------------
/packages/desktop/src/convert/border.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #eee;
3 | }
4 |
5 | .markdown-body {
6 | background-color: #fff;
7 | padding: 30px;
8 | max-width: 840px;
9 | margin: 20px auto;
10 | box-shadow: 0 0 5px 0px rgba(0, 0, 0, .1);
11 | }
--------------------------------------------------------------------------------
/packages/desktop/server.yml:
--------------------------------------------------------------------------------
1 | filters:
2 | ^/: 'nokit-filter-proxy'
3 | public:
4 | ^/: './build/dist'
5 | cache:
6 | enabled: false
7 | log:
8 | enabled: false
9 | session:
10 | enabled: false
11 | proxy:
12 | rules:
13 | ^/api: '...'
--------------------------------------------------------------------------------
/packages/desktop/bin/unit.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm run lint
6 |
7 | karma start karma.conf.js --single-run
8 | cat ./build/coverage/report-text/text-summary.txt
9 |
10 | echo ''
11 | echo 'Coverage Detail: ./build/coverage/report-html/index.html'
12 | echo ''
--------------------------------------------------------------------------------
/packages/desktop/src/common/yaml.js:
--------------------------------------------------------------------------------
1 | const yaml = require('js-yaml');
2 |
3 | function parseYaml(text) {
4 | try {
5 | return yaml.safeLoad(text, 'utf8');
6 | } catch (err) {
7 | console.error(err);
8 | return null;
9 | }
10 | }
11 |
12 | module.exports = parseYaml;
--------------------------------------------------------------------------------
/packages/embed/bin/unit.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm run lint
6 |
7 | karma start karma.conf.js --single-run
8 | cat ./build/coverage/report-text/text-summary.txt
9 |
10 | echo ''
11 | echo 'Coverage Detail: ./build/coverage/report-html/index.html'
12 | echo ''
--------------------------------------------------------------------------------
/packages/desktop/.npmignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | *.log
3 | *.sh
4 | *.js.map
5 | *.css.map
6 | .babelrc
7 | .eslintrc.yml
8 | .travis.yml
9 | server.yml
10 | server.local.yml
11 | webpack.config.js
12 | logs/
13 | node_modules/
14 | scripts/
15 | docs/
16 | test/
17 | examples/
18 | build/
19 | .vscode/
20 | release/
--------------------------------------------------------------------------------
/packages/embed/src/toolbar/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/desktop/src/common/mkdirp.js:
--------------------------------------------------------------------------------
1 | const mkdirp = require('mkdirp');
2 | const Promise = require('bluebird');
3 |
4 | module.exports = function (path) {
5 | return new Promise((resolve, reject) => {
6 | mkdirp(path, err => {
7 | if (err) return reject(err);
8 | resolve(path);
9 | });
10 | });
11 | };
--------------------------------------------------------------------------------
/packages/embed/bin/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm run clear
6 | npm run lint
7 |
8 | babel src --out-dir lib
9 |
10 | export NODE_ENV=dev
11 | webpack --display-error-details
12 |
13 | export NODE_ENV=prod
14 | webpack --display-error-details
15 |
16 | rm -rf ./docs/demo/*
17 | cp -R ./dist/* ./docs/demo/
--------------------------------------------------------------------------------
/packages/desktop/test/e2e/demo.test.js:
--------------------------------------------------------------------------------
1 | describe('demo test', function () {
2 |
3 | beforeEach(function () {
4 | driver.get('/');
5 | });
6 |
7 | it('check title', function (done) {
8 | driver.getTitle().then(function (title) {
9 | expect(title).toBe('Hello Mokit');
10 | done();
11 | });
12 | });
13 |
14 | });
--------------------------------------------------------------------------------
/packages/embed/test/e2e/demo.test.js:
--------------------------------------------------------------------------------
1 | describe('demo test', function () {
2 |
3 | beforeEach(function () {
4 | driver.get('/');
5 | });
6 |
7 | it('check title', function (done) {
8 | driver.getTitle().then(function (title) {
9 | expect(title).toBe('Hello Mokit');
10 | done();
11 | });
12 | });
13 |
14 | });
--------------------------------------------------------------------------------
/packages/desktop/src/common/fs.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const Promise = require('bluebird');
3 |
4 | exports.writeFile = Promise.promisify(fs.writeFile);
5 | exports.readFile = Promise.promisify(fs.readFile);
6 | exports.unlink = Promise.promisify(fs.unlink);
7 |
8 | exports.exists = async function exists(file) {
9 | return new Promise(resolve => {
10 | fs.exists(file, resolve);
11 | });
12 | };
--------------------------------------------------------------------------------
/packages/desktop/bin/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | npm run build
6 |
7 | #icns converter https://iconverticons.com/online/
8 |
9 | node ./bin/release.js
10 |
11 | PRJ_PATH=$PWD
12 |
13 | #install deps
14 | cd ./release/Mditor-darwin-x64/Mditor.app/Contents/Resources/app/
15 | cnpm prune --production
16 | cnpm i
17 | cnpm prune --production
18 |
19 | #dmg dmgCanvas http://www.araelium.com/dmgcanvas/
--------------------------------------------------------------------------------
/packages/desktop/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### 1.0.0
2 | 1. 修正打开或保存对话框默认路径错误问题
3 |
4 | ### 1.0.0Beta10
5 | 1. 新增支持「国际化」目前包括「中文」和「英文」
6 | 2. 新增支持「拖拽」插入图片
7 | 3. 新增加支持「复制」插入图片,并自动保存到当前目录
8 |
9 | ### 1.0.0Beta8
10 | 1. 新增支持导出「演示文稿」
11 | 2. 修复有时序号补全错误问题
12 |
13 | ### 1.0.0Beta7
14 | 1. 改进「偏好设置」功能
15 | 2. 修复有时右键打开文件空白的问题
16 |
17 | ### 1.0.0Beta6
18 | 1. 新增「偏好设置」功能
19 | 2. 新增支持用「相对路径引」入图片
20 | 3. 新增支持「双击标题栏」切换窗口状态
21 | 4. 修复「右键菜单」无法弹出问题
22 | 5. 改进 undo/redo 操作
--------------------------------------------------------------------------------
/packages/embed/src/editor/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/desktop/src/convert/tmpl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | ${title}
9 |
12 |
13 |
14 |
15 |
16 | ${content}
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/desktop/src/convert/slide.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | ${title}
9 |
10 | ${items.map(item=>item).join('\n')}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/packages/desktop/src/common/blob2base64.js:
--------------------------------------------------------------------------------
1 | const Promise = require('bluebird');
2 |
3 | module.exports = function blobToBase64(blob) {
4 | return new Promise((resolve, reject) => {
5 | var reader = new FileReader();
6 |
7 | function onLoadEnd(e) {
8 | reader.removeEventListener('loadend', onLoadEnd, false);
9 | if (e.error) return reject(e.error);
10 | resolve(reader.result);
11 | }
12 | reader.addEventListener('loadend', onLoadEnd, false);
13 | try {
14 | reader.readAsDataURL(blob);
15 | } catch (err) {
16 | console.warn(err);
17 | }
18 | });
19 | };
--------------------------------------------------------------------------------
/packages/desktop/src/menu/index.js:
--------------------------------------------------------------------------------
1 | const Menu = require('electron').Menu;
2 | const Promise = require('bluebird');
3 |
4 | exports.createMain = async function () {
5 | let template = await Promise.all([
6 | require('./file')(),
7 | require('./edit')(),
8 | require('./view')(),
9 | require('./window')(),
10 | require('./help')()
11 | ]);
12 | if (process.platform === 'darwin') {
13 | template.unshift(await require('./main')());
14 | }
15 | return Menu.buildFromTemplate(template);
16 | };
17 |
18 | exports.createContextMenu = async function () {
19 | return require('./contextmenu')();
20 | };
--------------------------------------------------------------------------------
/docs/javascripts/scale.fix.js:
--------------------------------------------------------------------------------
1 | var metas = document.getElementsByTagName('meta');
2 | var i;
3 | if (navigator.userAgent.match(/iPhone/i)) {
4 | for (i=0; i {
5 | var reader = new FileReader();
6 |
7 | function onLoadEnd(e) {
8 | reader.removeEventListener('loadend', onLoadEnd, false);
9 | if (e.error) return reject(e.error);
10 | resolve(Buffer.from(reader.result));
11 | }
12 | reader.addEventListener('loadend', onLoadEnd, false);
13 | try {
14 | reader.readAsArrayBuffer(blob);
15 | } catch (err) {
16 | console.warn(err);
17 | }
18 | });
19 | };
--------------------------------------------------------------------------------
/packages/desktop/src/menu/view.js:
--------------------------------------------------------------------------------
1 | const app = require('electron').app;
2 | const i18n = require('../i18n');
3 |
4 | module.exports = async() => {
5 | let locale = i18n.locale;
6 | return {
7 | label: locale.view,
8 | submenu: [{
9 | label: locale.toggleSplit,
10 | accelerator: 'Shift+Alt+S',
11 | click() {
12 | app.execCommand('toggleSplit');
13 | }
14 | },
15 | {
16 | label: locale.togglePreview,
17 | accelerator: 'Shift+Alt+V',
18 | click() {
19 | app.execCommand('togglePreview');
20 | }
21 | }
22 | ]
23 | };
24 | };
--------------------------------------------------------------------------------
/packages/embed/src/finder/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/desktop/docs/javascripts/scale.fix.js:
--------------------------------------------------------------------------------
1 | var metas = document.getElementsByTagName('meta');
2 | var i;
3 | if (navigator.userAgent.match(/iPhone/i)) {
4 | for (i=0; i
2 |
3 |
4 |
5 |
6 |
7 |
8 | Mditor
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/packages/embed/src/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/packages/desktop/src/preference/tmpl.md:
--------------------------------------------------------------------------------
1 | # Preferences
2 |
3 | Here is the Mditor "preference settings", each configuration is Yaml format, save after editing can be, [online document](http://mditor.com/doc/preference.html).
4 |
5 |
6 | ### 1. Editor Settings
7 |
8 | ```editor
9 | # tab: 2
10 | # backgroundColor: black
11 | # color: white
12 | ```
13 |
14 | > With these configurations, tab: The number of designated tab indent space, 0 do not use spaces instead of tab. backgroundColor: Edit area background color, the binary need to add "quotes", such as'#000', color: Edit area foreground.
15 |
16 |
17 | ### 2. Custom Shortcuts
18 |
19 | ```shortcut
20 | # bold: command+b
21 | ```
22 |
23 | > The format is "command: shortcut", please refer to the sample.
--------------------------------------------------------------------------------
/packages/embed/src/viewer/index.less:
--------------------------------------------------------------------------------
1 | .mditor {
2 | .viewer {
3 | overflow: auto;
4 | position: relative;
5 | display: inline-block;
6 | border: none;
7 | outline: none;
8 | width: 100%;
9 | height: 100%;
10 | resize: none;
11 | background-color: transparent;
12 | margin: 0px;
13 | padding: 10px 12px 40px 12px;
14 | color: #333;
15 | word-break: break-all;
16 | word-wrap: break-word;
17 | .markdown-body {
18 | max-width: 900px;
19 | margin: auto;
20 | }
21 | .alert {
22 | color: #ddd;
23 | text-align: center;
24 | position: absolute;
25 | left: 0;
26 | width: 100%;
27 | top: 50%;
28 | font-size: 20px;
29 | margin-top: -15px;
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/packages/embed/src/editor/commands.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | name: 'undo',
3 | key: '{cmd}+z',
4 | handler() {
5 | this.editor.undo();
6 | }
7 | }, {
8 | name: 'redo',
9 | key: '{cmd}+shift+z',
10 | handler() {
11 | this.editor.redo();
12 | }
13 | }, {
14 | name: 'h2',
15 | key: 'shift+alt+2',
16 | handler() {
17 | this.editor.wrapSelectText('## ');
18 | }
19 | }, {
20 | name: 'h3',
21 | key: 'shift+alt+3',
22 | handler() {
23 | this.editor.wrapSelectText('### ');
24 | }
25 | }, {
26 | name: 'h4',
27 | key: 'shift+alt+4',
28 | handler() {
29 | this.editor.wrapSelectText('#### ');
30 | }
31 | }, {
32 | name: 'h5',
33 | key: 'shift+alt+5',
34 | handler() {
35 | this.editor.wrapSelectText('##### ');
36 | }
37 | }];
--------------------------------------------------------------------------------
/packages/desktop/src/window/drapable.js:
--------------------------------------------------------------------------------
1 | const EventEmitter = require('mokit').EventEmitter;
2 |
3 | module.exports = function (element) {
4 | let eventer = new EventEmitter(element);
5 | eventer.on('dragover', function (event) {
6 | event.preventDefault();
7 | });
8 | eventer.on('drop', function (event) {
9 | event.preventDefault();
10 | let files = [].slice.call(event.dataTransfer.files);
11 | if (!files || files.length < 1) return;
12 | let firstFile = files[0];
13 | if (firstFile.type.startsWith('text/')) {
14 | ctx.openFile(firstFile.path);
15 | } else {
16 | let imageFiles = files.filter(file => file.type.startsWith('image/'));
17 | if (imageFiles.length < 1) return;
18 | ctx.insertImage(imageFiles.map(item => item.path));
19 | }
20 | });
21 | };
--------------------------------------------------------------------------------
/packages/desktop/test/driver.js:
--------------------------------------------------------------------------------
1 | const webdriver = require('selenium-webdriver');
2 | const phantomjsPath = require('phantomjs-prebuilt').path;
3 | const pkg = require('../package.json');
4 |
5 | const capabilities = webdriver.Capabilities.phantomjs();
6 | capabilities.set("phantomjs.binary.path", phantomjsPath);
7 | const driver = new webdriver.Builder().
8 | withCapabilities(capabilities).
9 | build();
10 |
11 | driver.manage().window().maximize();
12 |
13 | driver._get = driver.get;
14 | driver.get = function (path) {
15 | path = path || '/';
16 | return this._get(`http://${pkg.dev.host}:${pkg.dev.port}/#!${path}`);
17 | };
18 |
19 | global.driver = driver;
20 | global.by = webdriver.By;
21 | global.until = webdriver.until;
22 |
23 | by.text = function (text) {
24 | return by.xpath('//*[text()="' + text + '"]');
25 | };
--------------------------------------------------------------------------------
/packages/embed/test/driver.js:
--------------------------------------------------------------------------------
1 | const webdriver = require('selenium-webdriver');
2 | const phantomjsPath = require('phantomjs-prebuilt').path;
3 | const pkg = require('../package.json');
4 |
5 | const capabilities = webdriver.Capabilities.phantomjs();
6 | capabilities.set("phantomjs.binary.path", phantomjsPath);
7 | const driver = new webdriver.Builder().
8 | withCapabilities(capabilities).
9 | build();
10 |
11 | driver.manage().window().maximize();
12 |
13 | driver._get = driver.get;
14 | driver.get = function (path) {
15 | path = path || '/';
16 | return this._get(`http://${pkg.dev.host}:${pkg.dev.port}/#!${path}`);
17 | };
18 |
19 | global.driver = driver;
20 | global.by = webdriver.By;
21 | global.until = webdriver.until;
22 |
23 | by.text = function (text) {
24 | return by.xpath('//*[text()="' + text + '"]');
25 | };
--------------------------------------------------------------------------------
/packages/desktop/src/menu/help.js:
--------------------------------------------------------------------------------
1 | const shell = require('electron').shell;
2 | const pkg = require('../../package');
3 | const i18n = require('../i18n');
4 |
5 | module.exports = async() => {
6 | let locale = i18n.locale;
7 | return {
8 | label: locale.help,
9 | role: 'help',
10 | submenu: [{
11 | label: `${pkg.displayName} ${locale.homepage}`,
12 | click() {
13 | shell.openExternal(`${pkg.homepage}?locale=${i18n.localeName}`);
14 | }
15 | }, {
16 | label: locale.umlDoc,
17 | click() {
18 | shell.openExternal(`${pkg.homepage}/doc/uml.html?locale=${i18n.localeName}`);
19 | }
20 | }, {
21 | label: locale.slideDoc,
22 | click() {
23 | shell.openExternal(`${pkg.homepage}/doc/slide.html?locale=${i18n.localeName}`);
24 | }
25 | }]
26 | };
27 | };
--------------------------------------------------------------------------------
/packages/desktop/src/recent/index.js:
--------------------------------------------------------------------------------
1 | const app = require('electron').app;
2 | const store = require('../common/store');
3 |
4 | const STORE_KEY = 'recent';
5 | const MAX_NUM = 10;
6 |
7 | exports.add = async function (filename) {
8 | let list = (await store.getItem(STORE_KEY)) || [];
9 | let index = list.findIndex(item => item === filename);
10 | if (index > -1) list.splice(index, 1);
11 | list.unshift(filename);
12 | list = list.slice(0, MAX_NUM);
13 | await store.setItem(STORE_KEY, list);
14 | app.addRecentDocument(filename);
15 | await app.createMenu();
16 | };
17 |
18 | exports.getItems = async function () {
19 | return (await store.getItem(STORE_KEY)) || [];
20 | };
21 |
22 | exports.clear = async function () {
23 | await store.removeItem(STORE_KEY);
24 | app.clearRecentDocuments();
25 | await app.createMenu();
26 | };
--------------------------------------------------------------------------------
/docs/doc/slide.md:
--------------------------------------------------------------------------------
1 | `slide`
2 |
3 | # 如何编写演示文稿
4 |
5 | 通常 Mditor 仅适用于编写「技术分享」类的「演示文稿」,普通的 Markdown 可能需要简单修改才适合导出为「演示文稿」,按「回车」全屏,按「空格或右箭头」阅读下一页
6 |
7 | `slide`
8 |
9 | # 两种语法
10 |
11 | - 通过 **'slide'** 开始一页文稿
12 | - 通过 **'''slide \r\n'''** 开始一页文稿
13 |
14 | > 编写时请将 **'** 写为 **`**,第一种方式背景和转场动盏将随机产生,第二种方式可指定一些参数,请阅读后边的示例
15 |
16 | `slide`
17 |
18 | # 示例一
19 | 编写时请将 **'** 写为 **`**
20 | ```md
21 | 'slide'
22 |
23 | # 文稿一
24 | 1. 项目一
25 | 2. 项目二
26 |
27 | 'slide'
28 |
29 | # 文稿二
30 | 1. 项目一
31 | 2. 项目二
32 | ```
33 |
34 | `slide`
35 |
36 | # 示例二
37 | 编写时请将 **'** 写为 **`**
38 | ```md
39 | '''slide
40 | bgcolor: '#000' # 可指定背景色
41 | align: center # 可指定对齐方式
42 | effect: 17 # 可指定转场效果 (1~68)
43 | style: 'color: red' # 可指定样式
44 | '''
45 |
46 | # 文稿一
47 | 1. 项目一
48 | 2. 项目二
49 | ```
50 |
51 | ```slide
52 | align: center
53 | ```
54 | # 谢 谢
--------------------------------------------------------------------------------
/packages/desktop/docs/doc/slide.md:
--------------------------------------------------------------------------------
1 | `slide`
2 |
3 | # 如何编写演示文稿
4 |
5 | 通常 Mditor 仅适用于编写「技术分享」类的「演示文稿」,普通的 Markdown 可能需要简单修改才适合导出为「演示文稿」,按「回车」全屏,按「空格或右箭头」阅读下一页
6 |
7 | `slide`
8 |
9 | # 两种语法
10 |
11 | - 通过 **'slide'** 开始一页文稿
12 | - 通过 **'''slide \r\n'''** 开始一页文稿
13 |
14 | > 编写时请将 **'** 写为 **`**,第一种方式背景和转场动盏将随机产生,第二种方式可指定一些参数,请阅读后边的示例
15 |
16 | `slide`
17 |
18 | # 示例一
19 | 编写时请将 **'** 写为 **`**
20 | ```md
21 | 'slide'
22 |
23 | # 文稿一
24 | 1. 项目一
25 | 2. 项目二
26 |
27 | 'slide'
28 |
29 | # 文稿二
30 | 1. 项目一
31 | 2. 项目二
32 | ```
33 |
34 | `slide`
35 |
36 | # 示例二
37 | 编写时请将 **'** 写为 **`**
38 | ```md
39 | '''slide
40 | bgcolor: '#000' # 可指定背景色
41 | align: center # 可指定对齐方式
42 | effect: 17 # 可指定转场效果 (1~68)
43 | style: 'color: red' # 可指定样式
44 | '''
45 |
46 | # 文稿一
47 | 1. 项目一
48 | 2. 项目二
49 | ```
50 |
51 | ```slide
52 | align: center
53 | ```
54 | # 谢 谢
--------------------------------------------------------------------------------
/packages/desktop/src/i18n/index.js:
--------------------------------------------------------------------------------
1 | const app = require('electron').app;
2 | const yaml = require('../common/yaml');
3 | const fs = require('../common/fs');
4 |
5 | exports.getName = async function () {
6 | this.localeName = app.getLocale().toLowerCase();
7 | return this.localeName;
8 | };
9 |
10 | exports.load = async function () {
11 | let name = await this.getName();
12 | let localeFile;
13 | let localeFiles = [
14 | `${__dirname}/locales/${name}.yml`,
15 | `${__dirname}/locales/${name.split('-')[0]}.yml`,
16 | `${__dirname}/locales/en.yml`
17 | ];
18 | for (let i = 0; i < localeFiles.length; i++) {
19 | if (await fs.exists(localeFiles[i])) {
20 | localeFile = localeFiles[i];
21 | break;
22 | }
23 | }
24 | let buffer = await fs.readFile(localeFile);
25 | this.locale = yaml(buffer.toString());
26 | return this.locale;
27 | };
--------------------------------------------------------------------------------
/packages/desktop/src/update/index.js:
--------------------------------------------------------------------------------
1 | const pkg = require('../../package');
2 | const store = require('../common/store');
3 | const fetch = require('node-fetch');
4 | const utils = require('ntils');
5 | const os = require('os');
6 | const i18n = require('../i18n');
7 |
8 | const STORE_KEY = 'update';
9 | const ONE_DAY_MS = 10800000; //3 个小时内只提示一次
10 |
11 | exports.check = async function (force) {
12 | //如果不是强制检查,则对比上次更新时间
13 | if (!force) {
14 | let prevTime = await store.getItem(STORE_KEY);
15 | if (Date.now() - prevTime < ONE_DAY_MS) return;
16 | }
17 | //拉取服务器信息
18 | let response = await fetch(`${pkg.update.url}?locale=${i18n.localeName}`);
19 | let info = await response.json();
20 | if (info.version == pkg.version) return;
21 | if (utils.isArray(info.detail)) {
22 | info.detail = info.detail.join(os.EOL);
23 | }
24 | //记录本次更新时间
25 | store.setItem(STORE_KEY, Date.now());
26 | return info;
27 | };
--------------------------------------------------------------------------------
/packages/embed/src/toolbar/index.less:
--------------------------------------------------------------------------------
1 | .mditor {
2 | .toolbar {
3 | margin: 0px;
4 | padding: 4px;
5 | height: 100%;
6 | position: relative;
7 | .item {
8 | transition: .3s;
9 | height: 27px;
10 | width: 27px;
11 | text-align: center;
12 | line-height: 25px;
13 | font-size: 14px;
14 | border: 1px solid transparent;
15 | border-radius: 3px;
16 | margin: 1px;
17 | color: #888;
18 | transition: .2s;
19 | -webkit-transition: .2s;
20 | position: relative;
21 | vertical-align: middle;
22 | &:hover {
23 | color: #444;
24 | border: 1px solid #ddd;
25 | }
26 | &:active, &.active {
27 | border: 1px solid #ddd;
28 | background-color: #ebebeb;
29 | box-shadow: 0 0 3px rgba(0, 0, 0, .1) inset;
30 | }
31 | &.control {
32 | float: right;
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/packages/desktop/src/common/store.js:
--------------------------------------------------------------------------------
1 | const app = require('electron').app;
2 | const fs = require('../common/fs');
3 |
4 | const DATA_PATH = app.getPath('userData');
5 |
6 | exports.setItem = async function (key, value) {
7 | let storeFile = `${DATA_PATH}/${key}.json`;
8 | try {
9 | await fs.writeFile(storeFile, JSON.stringify(value));
10 | } catch (err) {
11 | console.error('setItem', err);
12 | }
13 | };
14 |
15 | exports.getItem = async function (key) {
16 | let storeFile = `${DATA_PATH}/${key}.json`;
17 | try {
18 | let buffer = await fs.readFile(storeFile);
19 | return JSON.parse(buffer.toString());
20 | } catch (err) {
21 | console.error('getItem', err);
22 | }
23 | };
24 |
25 | exports.removeItem = async function (key) {
26 | let storeFile = `${DATA_PATH}/${key}.json`;
27 | try {
28 | await fs.unlink(storeFile);
29 | } catch (err) {
30 | console.error('removeItem', err);
31 | }
32 | };
--------------------------------------------------------------------------------
/packages/embed/src/finder/index.less:
--------------------------------------------------------------------------------
1 | .mditor {
2 | .body {
3 | .finder {
4 | position: absolute;
5 | top: 0;
6 | right: 0;
7 | padding: 8px;
8 | background-color: rgba(240, 240, 240, .9);
9 | box-shadow: -1px 1px 2px 0 rgba(0, 0, 0, .18);
10 | z-index: 2;
11 | input {
12 | outline: 0;
13 | font-size: 13px;
14 | padding: 5px;
15 | height: 25px;
16 | vertical-align: middle;
17 | border: solid 1px #ddd;
18 | margin: 2px;
19 | min-width: 200px;
20 | -webkit-font-smoothing: antialiased;
21 | }
22 | i.fa {
23 | vertical-align: middle;
24 | font-size: 12px;
25 | padding: 5px;
26 | outline: 0;
27 | color: #888;
28 | &:hover {
29 | color: #555;
30 | }
31 | }
32 | display: none;
33 | &.active {
34 | display: block;
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/packages/desktop/bin/info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDocumentTypes
6 |
7 |
8 | CFBundleTypeName
9 | Mditor File
10 | CFBundleTypeRole
11 | Editor
12 | CFBundleTypeOSTypes
13 |
14 | TEXT
15 | utxt
16 | TUTX
17 | ****
18 |
19 | CFBundleTypeIconFile
20 | ../design/icon.icns
21 | CFBundleTypeExtensions
22 |
23 | md
24 | txt
25 | text
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/packages/embed/src/editor/stack.js:
--------------------------------------------------------------------------------
1 | const Class = require('cify').Class;
2 | const utils = require('ntils');
3 |
4 | const Stack = new Class({
5 | constructor(item) {
6 | this.init(item);
7 | },
8 | init(item) {
9 | this.undoList = [item || {
10 | value: null
11 | }];
12 | this.redoList = [];
13 | },
14 | push(item) {
15 | if (this.last() === item) return;
16 | this.undoList.push(item);
17 | },
18 | last() {
19 | return this.undoList[this.undoList.length - 1];
20 | },
21 | undo() {
22 | if (this.undoList.length > 1) {
23 | let item = this.undoList.pop();
24 | if (utils.isNull(item) || utils.isNull(item.value)) return;
25 | this.redoList.push(item);
26 | }
27 | return this.last();
28 | },
29 | redo() {
30 | let item = this.redoList.pop();
31 | if (utils.isNull(item) || utils.isNull(item.value)) return;
32 | this.undoList.push(item);
33 | return item;
34 | }
35 | });
36 |
37 | module.exports = Stack;
--------------------------------------------------------------------------------
/packages/desktop/src/menu/window.js:
--------------------------------------------------------------------------------
1 | const i18n = require('../i18n');
2 |
3 | module.exports = async() => {
4 | let locale = i18n.locale;
5 | const windowMenu = {
6 | label: locale.window,
7 | role: 'window',
8 | submenu: [{
9 | label: locale.minimize,
10 | role: 'minimize'
11 | },
12 | {
13 | label: locale.close,
14 | role: 'close'
15 | }
16 | ]
17 | };
18 |
19 | if (process.platform === 'darwin') {
20 | windowMenu.submenu = [{
21 | label: locale.close,
22 | accelerator: 'CmdOrCtrl+W',
23 | role: 'close'
24 | },
25 | {
26 | label: locale.minimize,
27 | accelerator: 'CmdOrCtrl+M',
28 | role: 'minimize'
29 | },
30 | {
31 | label: locale.zoom,
32 | role: 'zoom'
33 | },
34 | {
35 | type: 'separator'
36 | },
37 | {
38 | label: locale.front,
39 | role: 'front'
40 | }
41 | ];
42 | }
43 |
44 | return windowMenu;
45 | };
--------------------------------------------------------------------------------
/packages/embed/lib/editor/commands.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | module.exports = [{
4 | name: 'undo',
5 | key: '{cmd}+z',
6 | /*istanbul ignore next*/handler: function handler() {
7 | this.editor.undo();
8 | }
9 | }, {
10 | name: 'redo',
11 | key: '{cmd}+shift+z',
12 | /*istanbul ignore next*/handler: function handler() {
13 | this.editor.redo();
14 | }
15 | }, {
16 | name: 'h2',
17 | key: 'shift+alt+2',
18 | /*istanbul ignore next*/handler: function handler() {
19 | this.editor.wrapSelectText('## ');
20 | }
21 | }, {
22 | name: 'h3',
23 | key: 'shift+alt+3',
24 | /*istanbul ignore next*/handler: function handler() {
25 | this.editor.wrapSelectText('### ');
26 | }
27 | }, {
28 | name: 'h4',
29 | key: 'shift+alt+4',
30 | /*istanbul ignore next*/handler: function handler() {
31 | this.editor.wrapSelectText('#### ');
32 | }
33 | }, {
34 | name: 'h5',
35 | key: 'shift+alt+5',
36 | /*istanbul ignore next*/handler: function handler() {
37 | this.editor.wrapSelectText('##### ');
38 | }
39 | }];
--------------------------------------------------------------------------------
/packages/embed/src/viewer/index.js:
--------------------------------------------------------------------------------
1 | const mokit = require('mokit');
2 |
3 | require('./index.less');
4 |
5 | const Viewer = new mokit.Component({
6 | template: require('./index.html'),
7 |
8 | data() {
9 | return {
10 | html: '',
11 | alert: '预览区域'
12 | };
13 | },
14 |
15 | props: {
16 | mditor: null,
17 | value: {
18 | get() {
19 | return this._value;
20 | },
21 | set(value) {
22 | this._value = value;
23 | let beforeEvent = { value: this._value };
24 | this.$emit('beforeRender', beforeEvent);
25 | this.mditor.parser.parse(beforeEvent.value, (err, result) => {
26 | let afterEvent = { value: result || err };
27 | this.$emit('afterRender', afterEvent);
28 | this.html = afterEvent.value;
29 | });
30 | }
31 | }
32 | },
33 |
34 | onClick(event) {
35 | event.preventDefault();
36 | let tag = event.target;
37 | if (tag.tagName == 'A') {
38 | let href = tag.getAttribute('href');
39 | if (href) window.open(href, '_blank');
40 | }
41 | }
42 |
43 | });
44 |
45 | module.exports = Viewer;
--------------------------------------------------------------------------------
/packages/desktop/src/i18n/locales/zh.yml:
--------------------------------------------------------------------------------
1 | about: 关于
2 | checkUpdate: 检查更新
3 | preference: 偏好设置
4 | resetPreference: 重置偏好设置
5 | services: 服务
6 | hide: 隐藏
7 | hideOthers: 隐藏其它
8 | unHide: 取消隐藏
9 | quit: 退出
10 | clearRecent: 清除最近编辑
11 | file: 文件
12 | newFile: 新建
13 | open: 打开
14 | recentItems: 最近编辑
15 | save: 保存
16 | saveAs: 另存为
17 | export: 导出
18 | pdf: PDF
19 | html: HTML
20 | image: 图片
21 | slide: 演示
22 | edit: 编辑
23 | undo: 撤销
24 | redo: 重做
25 | cut: 剪切
26 | copy: 复制
27 | paste: 粘贴
28 | selectAll: 全选
29 | delete: 删除
30 | findAndReplace: 查找和替换
31 | view: 视图
32 | toggleSplit: 切换分屏
33 | togglePreview: 切换预览
34 | previewArea: 预览区域
35 | window: 窗口
36 | minimize: 最小化
37 | close: 关闭
38 | zoom: 缩放
39 | front: 置于最前
40 | help: 帮助
41 | homepage: 主页
42 | umlDoc: 如何生成 UML 图形
43 | slideDoc: 如何编写「演示」
44 | currentlyTheLatestVersion: 当前已是最新版本
45 | goDownload: 前往下载
46 | donNotUpdate: 暂不更新
47 | discoverNewVersion: 发现新版本
48 | recommendDownload: 建议现在就去下载新版本
49 | cancel: 取消
50 | donNotSave: 不保存
51 | confirmSave: 确认保存
52 | saveAlertDetail: 文件 "${filename}" 还未保存,是否现在保存?
53 | bold: 粗体
54 | italic: 斜体
55 | underline: 下划线
56 | strikethrough: 删除线
57 | header: 标题
58 | quote: 引用
59 | code: 代码
60 | listOl: 有序列表
61 | listUl: 无序列表
62 | link: 链接
63 | table: 表格
64 | line: 分隔线
--------------------------------------------------------------------------------
/packages/desktop/src/window/index.less:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | html, body, .app {
6 | height: 100%;
7 | margin: 0;
8 | padding: 0;
9 | }
10 |
11 | .mditor {
12 | margin: 0px !important;
13 | width: 100% !important;
14 | height: 100% !important;
15 | min-width: 100% !important;
16 | min-height: 100% !important;
17 | max-width: 100% !important;
18 | max-height: 100% !important;
19 | border-radius: 0px !important;
20 | border: none !important;
21 | .head {
22 | padding-top: 1px !important;
23 | padding-left: 72px !important;
24 | -webkit-app-region: drag;
25 | .toolbar {
26 | .item {
27 | -webkit-app-region: no-drag
28 | }
29 | .item.fa-arrows-alt {
30 | display: none !important;
31 | }
32 | }
33 | }
34 | .editor {
35 | font-size: 16px;
36 | line-height: normal;
37 | }
38 | .viewer {
39 | .highlight-alert {
40 | border-bottom: solid 1px #ddd;
41 | padding-bottom: 5px;
42 | margin-bottom: 10px;
43 | color: firebrick;
44 | font-size: 12px;
45 | }
46 | }
47 | }
48 |
49 | .fullscreen {
50 | .mditor {
51 | .head {
52 | padding-left: 0 !important;
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/packages/embed/lib/editor/stack.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | var Class = require('cify').Class;
4 | var utils = require('ntils');
5 |
6 | var Stack = new Class({
7 | /*istanbul ignore next*/constructor: function constructor(item) {
8 | this.init(item);
9 | },
10 | /*istanbul ignore next*/init: function init(item) {
11 | this.undoList = [item || {
12 | value: null
13 | }];
14 | this.redoList = [];
15 | },
16 | /*istanbul ignore next*/push: function push(item) {
17 | if (this.last() === item) return;
18 | this.undoList.push(item);
19 | },
20 | /*istanbul ignore next*/last: function last() {
21 | return this.undoList[this.undoList.length - 1];
22 | },
23 | /*istanbul ignore next*/undo: function undo() {
24 | if (this.undoList.length > 1) {
25 | var item = this.undoList.pop();
26 | if (utils.isNull(item) || utils.isNull(item.value)) return;
27 | this.redoList.push(item);
28 | }
29 | return this.last();
30 | },
31 | /*istanbul ignore next*/redo: function redo() {
32 | var item = this.redoList.pop();
33 | if (utils.isNull(item) || utils.isNull(item.value)) return;
34 | this.undoList.push(item);
35 | return item;
36 | }
37 | });
38 |
39 | module.exports = Stack;
--------------------------------------------------------------------------------
/packages/embed/karma.conf.js:
--------------------------------------------------------------------------------
1 | const webpackConfig = require('./webpack.config.js');
2 |
3 | module.exports = function (config) {
4 | config.set({
5 | browsers: ['PhantomJS'],
6 | frameworks: ['jasmine'],
7 | files: [
8 | 'test/unit/**/*.test.js'
9 | ],
10 | reporters: ['spec', 'coverage'],
11 | preprocessors: {
12 | 'test/unit/**/*.test.js': ['webpack'],
13 | },
14 | coverageReporter: {
15 | dir: './build/coverage/',
16 | reporters: [{
17 | type: 'html',
18 | subdir: 'report-html'
19 | }, {
20 | type: 'text-summary',
21 | subdir: 'report-text',
22 | file: 'text-summary.txt'
23 | }, {
24 | type: 'text',
25 | subdir: 'report-text',
26 | file: 'text.txt'
27 | }, ]
28 | },
29 | webpack: {
30 | devtool: 'inline-source-map',
31 | module: {
32 | preLoaders: [{
33 | test: /\.js$/,
34 | exclude: [/node_modules/, /\.test\.js$/, /mocks/],
35 | loader: 'isparta'
36 | }],
37 | loaders: webpackConfig.module.loaders
38 | },
39 | plugins: webpackConfig.plugins,
40 | resolve: webpackConfig.resolve
41 | },
42 | webpackServer: {
43 | noInfo: true
44 | }
45 | });
46 | };
--------------------------------------------------------------------------------
/packages/desktop/karma.conf.js:
--------------------------------------------------------------------------------
1 | const webpackConfig = require('./webpack.config.js');
2 |
3 | module.exports = function (config) {
4 | config.set({
5 | browsers: ['PhantomJS'],
6 | frameworks: ['jasmine'],
7 | files: [
8 | 'test/unit/**/*.test.js'
9 | ],
10 | reporters: ['spec', 'coverage'],
11 | preprocessors: {
12 | 'test/unit/**/*.test.js': ['webpack'],
13 | },
14 | coverageReporter: {
15 | dir: './build/coverage/',
16 | reporters: [{
17 | type: 'html',
18 | subdir: 'report-html'
19 | }, {
20 | type: 'text-summary',
21 | subdir: 'report-text',
22 | file: 'text-summary.txt'
23 | }, {
24 | type: 'text',
25 | subdir: 'report-text',
26 | file: 'text.txt'
27 | }, ]
28 | },
29 | webpack: {
30 | devtool: 'inline-source-map',
31 | module: {
32 | preLoaders: [{
33 | test: /\.js$/,
34 | exclude: [/node_modules/, /\.test\.js$/, /mocks/],
35 | loader: 'isparta'
36 | }],
37 | loaders: webpackConfig.module.loaders
38 | },
39 | plugins: webpackConfig.plugins,
40 | resolve: webpackConfig.resolve
41 | },
42 | webpackServer: {
43 | noInfo: true
44 | }
45 | });
46 | };
--------------------------------------------------------------------------------
/packages/desktop/src/menu/contextmenu.js:
--------------------------------------------------------------------------------
1 | const electron = require('electron');
2 | const Menu = electron.Menu;
3 | const MenuItem = electron.MenuItem;
4 | const i18n = require('../i18n');
5 |
6 | module.exports = async() => {
7 | let locale = i18n.locale;
8 | const items = [{
9 | label: locale.undo,
10 | role: 'undo',
11 | accelerator: 'CmdOrCtrl+Z'
12 | },
13 | {
14 | label: locale.redo,
15 | role: 'redo',
16 | accelerator: 'Shift+CmdOrCtrl+Z'
17 | },
18 | {
19 | type: 'separator'
20 | },
21 | {
22 | label: locale.cut,
23 | role: 'cut',
24 | accelerator: 'CmdOrCtrl+X'
25 | },
26 | {
27 | label: locale.copy,
28 | role: 'copy',
29 | accelerator: 'CmdOrCtrl+C'
30 | },
31 | {
32 | label: locale.paste,
33 | role: 'paste',
34 | accelerator: 'CmdOrCtrl+V'
35 | },
36 | {
37 | label: locale.delete,
38 | role: 'delete'
39 | },
40 | {
41 | type: 'separator'
42 | },
43 | {
44 | label: locale.selectAll,
45 | role: 'selectall',
46 | accelerator: 'CmdOrCtrl+A'
47 | }
48 | ];
49 |
50 | const menu = new Menu();
51 | items.forEach(item => {
52 | menu.append(new MenuItem(item));
53 | });
54 |
55 | return menu;
56 | };
--------------------------------------------------------------------------------
/packages/desktop/src/uml/index.js:
--------------------------------------------------------------------------------
1 | const encodeer = require('./encodeer');
2 | const fetch = global.fetch ? global.fetch : require('node-fetch');
3 | const Class = require('cify').Class;
4 |
5 | const UML_ERROR = /syntax error/i;
6 |
7 | function createAlert(message, detail) {
8 | return `${message}
${detail}`;
9 | }
10 |
11 | const UMLParser = new Class({
12 |
13 | //http://www.plantuml.com/plantuml/svg/
14 | //http://www.plantuml.com/plantuml/png/
15 | parse(code, lang, done) {
16 | if (!code) return done(null, '');
17 | let params = unescape(encodeURIComponent(code));
18 | let url = `http://www.plantuml.com/plantuml/svg/${encodeer.encode64(encodeer.zipDeflate(params, 9))}`;
19 | //发生错误时也不用 done 的第一个参数传递,
20 | //这样不让 mditor embed 认为是文档解析错误了
21 | //让 err 作为正确的结果返回,错误将显示在「图形」位置
22 | fetch(url).then((res, err) => {
23 | if (err) done(null, createAlert('发生了错误。', JSON.stringify(err)));
24 | res.text().then(result => {
25 | if (UML_ERROR.test(result)) {
26 | done(null, createAlert('语法错误,已显示原代码。', code));
27 | };
28 | done(null, result);
29 | });
30 | }).catch(err => {
31 | done(null, createAlert('暂时无法渲染 UML 图形,请检查网络设置。', code));
32 | });
33 | }
34 |
35 | });
36 |
37 | module.exports = UMLParser;
--------------------------------------------------------------------------------
/packages/embed/src/client/shortcut.js:
--------------------------------------------------------------------------------
1 | const shortcuts = require('shortcut-key');
2 | const utils = require('ntils');
3 |
4 | shortcuts.filter = event => {
5 | return !!event.target;
6 | };
7 |
8 | const Shortcut = module.exports = function (mditor) {
9 | utils.defineFreezeProp(this, 'mditor', mditor);
10 | };
11 |
12 | Shortcut.prototype._inRegion = function (target, owner) {
13 | if (!target) return false;
14 | owner = owner || this.mditor.editor.$element;
15 | if (utils.isFunction(owner)) owner = owner(this.mditor);
16 | return (target === owner) || this._inRegion(target.parentNode, owner);
17 | };
18 |
19 | Shortcut.prototype.bind = function (key, cmd, allowDefault, owner) {
20 | let mditor = this.mditor;
21 | //检查参数
22 | if (!key || !cmd) return;
23 | key = key.replace('{cmd}', mditor.CMD);
24 | shortcuts(key, event => {
25 | if (!this._inRegion(event.target, owner)) return;
26 | //禁用浏览器默认快捷键
27 | if (!allowDefault) {
28 | event.preventDefault();
29 | }
30 | if (cmd instanceof Function) {
31 | cmd.call(mditor, event);
32 | } else {
33 | mditor.execCommand(cmd, event);
34 | }
35 | setTimeout(() => {
36 | mditor.focus();
37 | }, 0);
38 | });
39 | };
40 |
41 | Shortcut.prototype.unbind = function (key) {
42 | shortcuts.unbind(key);
43 | };
--------------------------------------------------------------------------------
/packages/desktop/src/menu/edit.js:
--------------------------------------------------------------------------------
1 | const app = require('electron').app;
2 | const i18n = require('../i18n');
3 |
4 | module.exports = async() => {
5 | let locale = i18n.locale;
6 | return {
7 | label: locale.edit,
8 | submenu: [{
9 | label: locale.undo,
10 | accelerator: 'CmdOrCtrl+Z',
11 | click() {
12 | app.execCommand('undo');
13 | }
14 | },
15 | {
16 | label: locale.redo,
17 | accelerator: 'CmdOrCtrl+Shift+Z',
18 | click() {
19 | app.execCommand('redo');
20 | }
21 | },
22 | {
23 | type: 'separator'
24 | },
25 | {
26 | label: locale.cut,
27 | role: 'cut'
28 | },
29 | {
30 | label: locale.copy,
31 | role: 'copy'
32 | },
33 | {
34 | label: locale.paste,
35 | role: 'paste'
36 | },
37 | {
38 | label: locale.delete,
39 | role: 'delete'
40 | },
41 | {
42 | label: locale.selectAll,
43 | role: 'selectall'
44 | },
45 | {
46 | type: 'separator'
47 | },
48 | {
49 | label: locale.findAndReplace,
50 | accelerator: 'CmdOrCtrl+F',
51 | click() {
52 | app.execCommand('find');
53 | }
54 | }
55 | ]
56 | };
57 | };
--------------------------------------------------------------------------------
/packages/embed/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | mditor
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/packages/embed/src/editor/index.less:
--------------------------------------------------------------------------------
1 | .mditor {
2 | .editor {
3 | position: relative;
4 | display: inline-block;
5 | width: 100%;
6 | height: 100%;
7 | -webkit-text-size-adjust: none;
8 | transform: translateZ(0);
9 | .textarea, .backdrop {
10 | position: absolute;
11 | border: none;
12 | outline: none;
13 | display: block;
14 | left: 0;
15 | top: 0;
16 | width: 100%;
17 | height: 100%;
18 | resize: none;
19 | background-color: transparent;
20 | margin: 0px;
21 | overflow-x: hidden;
22 | overflow-y: auto;
23 | transition: transform 1s;
24 | letter-spacing: 1px;
25 | }
26 | .textarea, .backdrop .inner {
27 | padding: 8px 12px;
28 | white-space: pre-wrap;
29 | word-wrap: break-word;
30 | }
31 | .textarea {
32 | z-index: 1;
33 | color: #444;
34 | }
35 | .backdrop {
36 | z-index: 0;
37 | pointer-events: none;
38 | overflow: hidden;
39 | padding: 0px;
40 | .inner {
41 | color: transparent;
42 | mark {
43 | border-radius: 3px;
44 | color: transparent;
45 | background-color: rgba(255, 245, 75, .8);
46 | &.active {
47 | background-color: rgba(145, 225, 255, .8);
48 | }
49 | }
50 | }
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/packages/desktop/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | parser: babel-eslint
2 | rules:
3 | strict:
4 | - 0
5 | indent:
6 | - 2
7 | - 2
8 | quotes:
9 | - 2
10 | - single
11 | linebreak-style:
12 | - 2
13 | - unix
14 | semi:
15 | - 2
16 | - always
17 | no-multi-spaces:
18 | - 2
19 | no-self-compare:
20 | - 2
21 | max-depth:
22 | - 2
23 | - 4
24 | max-nested-callbacks:
25 | - 2
26 | - 4
27 | max-params:
28 | - 2
29 | - 4
30 | max-statements:
31 | - 2
32 | - 25
33 | max-statements-per-line:
34 | - 2
35 | max-len:
36 | - 2
37 | - 120
38 | multiline-ternary:
39 | - 0
40 | callback-return:
41 | - 2
42 | handle-callback-err:
43 | - 2
44 | array-bracket-spacing:
45 | - 2
46 | no-const-assign:
47 | - 2
48 | no-return-assign:
49 | - 0
50 | no-inner-declarations:
51 | - 2
52 | no-var:
53 | - 2
54 | no-console:
55 | - 1
56 | no-lonely-if:
57 | - 2
58 | require-jsdoc:
59 | - 2
60 | - require:
61 | FunctionDeclaration: true
62 | MethodDefinition: true
63 | ClassDeclaration: true
64 | valid-jsdoc:
65 | - 2
66 | comma-dangle:
67 | - 2
68 | - never
69 | no-undef:
70 | - 2
71 | env:
72 | es6: true
73 | browser: true
74 | commonjs: true
75 | extends: 'eslint:recommended'
76 | ecmaFeatures:
77 | jsx: true
--------------------------------------------------------------------------------
/packages/embed/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | parser: babel-eslint
2 | rules:
3 | strict:
4 | - 0
5 | indent:
6 | - 2
7 | - 2
8 | quotes:
9 | - 2
10 | - single
11 | linebreak-style:
12 | - 2
13 | - unix
14 | semi:
15 | - 2
16 | - always
17 | no-multi-spaces:
18 | - 2
19 | no-self-compare:
20 | - 2
21 | max-depth:
22 | - 2
23 | - 4
24 | max-nested-callbacks:
25 | - 2
26 | - 4
27 | max-params:
28 | - 2
29 | - 4
30 | max-statements:
31 | - 2
32 | - 25
33 | max-statements-per-line:
34 | - 2
35 | max-len:
36 | - 2
37 | - 120
38 | multiline-ternary:
39 | - 0
40 | callback-return:
41 | - 2
42 | handle-callback-err:
43 | - 2
44 | array-bracket-spacing:
45 | - 2
46 | no-const-assign:
47 | - 2
48 | no-return-assign:
49 | - 0
50 | no-inner-declarations:
51 | - 2
52 | no-var:
53 | - 2
54 | no-console:
55 | - 1
56 | no-lonely-if:
57 | - 2
58 | require-jsdoc:
59 | - 2
60 | - require:
61 | FunctionDeclaration: true
62 | MethodDefinition: true
63 | ClassDeclaration: true
64 | valid-jsdoc:
65 | - 2
66 | comma-dangle:
67 | - 2
68 | - never
69 | no-undef:
70 | - 2
71 | env:
72 | es6: true
73 | browser: true
74 | commonjs: true
75 | extends: 'eslint:recommended'
76 | ecmaFeatures:
77 | jsx: true
--------------------------------------------------------------------------------
/packages/embed/docs/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | mditor
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
4 | # 简单说明
5 | Mditor 最早只有「组件版」,随着「桌面版」的发布,Mditor 目前有两个版本:
6 | - 可嵌入到任意 Web 应用的 Embed 版本,这是一桌面版的基础,Repo: [https://github.com/houfeng/mditor](https://github.com/Houfeng/mditor)
7 | - 独立的桌面版本,目前仅有 Mac 版本,主页:[http://mditor.com](http://mditor.com),Repo: [https://github.com/houfeng/mditor-desktop](https://github.com/houfeng/mditor-desktop)
8 |
9 |
10 | # 相关特性
11 | 除常规的编辑功能,Mditor 桌面版还有如下特性
12 | - 多文件编辑,Mditor 桌面版是一个「多窗口」应用,可以通过「菜单、Dock、右键菜单」打开多个窗口实例进行多件编辑
13 | - 支持 GFM,如表格等(GFM 是 Github 拓展的基于 Markdown 的一种纯文本的书写格式)
14 | - 自动完成,Mditor 支持「无序列表、有序列表、引用」的自动完成,以辅助输入。
15 | - 多种编辑语言的的「代码高亮」支持(通过 ``` 语法)
16 | - 分屏实时预览,全屏预览
17 | - 导出 「HTML、PDF、Image」等功能。
18 |
19 | # 如何参与
20 | - 如果有任何问题或建议,可以直接发起 [Issue](https://github.com/Houfeng/mditor-desktop/issues)
21 | - 当然,你也可以直接向 Mditor 发起 [Pull Request](https://github.com/Houfeng/mditor-desktop/pulls)
22 | - 非常欢迎,直接给 Mditor [加个 Star](https://github.com/houfeng/mditor-desktop),这将是对 Midior 不错的鼓励,它会变成动力。
23 |
24 |
25 | ## 开发指南
26 |
27 | ##### Clone 源码
28 | ```sh
29 | $ git clone git@github.com:Houfeng/mditor-desktop.git your_path
30 | ```
31 |
32 | ##### 安装依赖
33 | 前提是需要安装好 Nodejs 和 npm(建议用 cnpm 可以通过国内镜象加速)
34 | ```sh
35 | $ npm install
36 | ```
37 |
38 | ##### 自动构建
39 | 将会自动进行基于 Webpack 的构建(部分资源需要 Webpack 打包),并将 Watch 文件的改动然后自动进行构建
40 | ```sh
41 | $ npm run dev
42 | ```
43 |
44 | ##### 启动程序
45 | 将会启动开发中的 Mditor
46 | ```sh
47 | $ npm start
48 | ```
--------------------------------------------------------------------------------
/packages/embed/lib/client/shortcut.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | var shortcuts = require('shortcut-key');
4 | var utils = require('ntils');
5 |
6 | shortcuts.filter = function (event) {
7 | return !!event.target;
8 | };
9 |
10 | var Shortcut = module.exports = function (mditor) {
11 | utils.defineFreezeProp(this, 'mditor', mditor);
12 | };
13 |
14 | Shortcut.prototype._inRegion = function (target, owner) {
15 | if (!target) return false;
16 | owner = owner || this.mditor.editor.$element;
17 | if (utils.isFunction(owner)) owner = owner(this.mditor);
18 | return target === owner || this._inRegion(target.parentNode, owner);
19 | };
20 |
21 | Shortcut.prototype.bind = function (key, cmd, allowDefault, owner) {
22 | /*istanbul ignore next*/var _this = this;
23 |
24 | var mditor = this.mditor;
25 | //检查参数
26 | if (!key || !cmd) return;
27 | key = key.replace('{cmd}', mditor.CMD);
28 | shortcuts(key, function (event) {
29 | if (! /*istanbul ignore next*/_this._inRegion(event.target, owner)) return;
30 | //禁用浏览器默认快捷键
31 | if (!allowDefault) {
32 | event.preventDefault();
33 | }
34 | if (cmd instanceof Function) {
35 | cmd.call(mditor, event);
36 | } else {
37 | mditor.execCommand(cmd, event);
38 | }
39 | setTimeout(function () {
40 | mditor.focus();
41 | }, 0);
42 | });
43 | };
44 |
45 | Shortcut.prototype.unbind = function (key) {
46 | shortcuts.unbind(key);
47 | };
--------------------------------------------------------------------------------
/packages/embed/lib/viewer/index.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | var mokit = require('mokit');
4 |
5 | require('./index.less');
6 |
7 | var Viewer = new mokit.Component({
8 | template: require('./index.html'),
9 |
10 | /*istanbul ignore next*/data: function data() {
11 | return {
12 | html: '',
13 | alert: '预览区域'
14 | };
15 | },
16 |
17 |
18 | props: {
19 | mditor: null,
20 | value: {
21 | /*istanbul ignore next*/get: function get() {
22 | return this._value;
23 | },
24 | /*istanbul ignore next*/set: function set(value) {
25 | /*istanbul ignore next*/var _this = this;
26 |
27 | this._value = value;
28 | var beforeEvent = { value: this._value };
29 | this.$emit('beforeRender', beforeEvent);
30 | this.mditor.parser.parse(beforeEvent.value, function (err, result) {
31 | var afterEvent = { value: result || err };
32 | /*istanbul ignore next*/_this.$emit('afterRender', afterEvent);
33 | /*istanbul ignore next*/_this.html = afterEvent.value;
34 | });
35 | }
36 | }
37 | },
38 |
39 | /*istanbul ignore next*/onClick: function onClick(event) {
40 | event.preventDefault();
41 | var tag = event.target;
42 | if (tag.tagName == 'A') {
43 | var href = tag.getAttribute('href');
44 | if (href) window.open(href, '_blank');
45 | }
46 | }
47 | });
48 |
49 | module.exports = Viewer;
--------------------------------------------------------------------------------
/packages/desktop/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
4 | # 简单说明
5 | Mditor 最早只有「组件版」,随着「桌面版」的发布,Mditor 目前有两个版本:
6 | - 可嵌入到任意 Web 应用的 Embed 版本,这是一桌面版的基础,Repo: [https://github.com/houfeng/mditor](https://github.com/Houfeng/mditor)
7 | - 独立的桌面版本,目前仅有 Mac 版本,主页:[http://mditor.com](http://mditor.com),Repo: [https://github.com/houfeng/mditor-desktop](https://github.com/houfeng/mditor-desktop)
8 |
9 |
10 | # 相关特性
11 | 除常规的编辑功能,Mditor 桌面版还有如下特性
12 | - 多文件编辑,Mditor 桌面版是一个「多窗口」应用,可以通过「菜单、Dock、右键菜单」打开多个窗口实例进行多件编辑
13 | - 支持 GFM,如表格等(GFM 是 Github 拓展的基于 Markdown 的一种纯文本的书写格式)
14 | - 自动完成,Mditor 支持「无序列表、有序列表、引用」的自动完成,以辅助输入。
15 | - 多种编辑语言的的「代码高亮」支持(通过 ``` 语法)
16 | - 分屏实时预览,全屏预览
17 | - 导出 「HTML、PDF、Image」等功能。
18 |
19 | # 如何参与
20 | - 如果有任何问题或建议,可以直接发起 [Issue](https://github.com/Houfeng/mditor-desktop/issues)
21 | - 当然,你也可以直接向 Mditor 发起 [Pull Request](https://github.com/Houfeng/mditor-desktop/pulls)
22 | - 非常欢迎,直接给 Mditor [加个 Star](https://github.com/houfeng/mditor-desktop),这将是对 Midior 不错的鼓励,它会变成动力。
23 |
24 |
25 | ## 开发指南
26 |
27 | ##### Clone 源码
28 | ```sh
29 | $ git clone git@github.com:Houfeng/mditor-desktop.git your_path
30 | ```
31 |
32 | ##### 安装依赖
33 | 前提是需要安装好 Nodejs 和 npm(建议用 cnpm 可以通过国内镜象加速)
34 | ```sh
35 | $ npm install
36 | ```
37 |
38 | ##### 自动构建
39 | 将会自动进行基于 Webpack 的构建(部分资源需要 Webpack 打包),并将 Watch 文件的改动然后自动进行构建
40 | ```sh
41 | $ npm run dev
42 | ```
43 |
44 | ##### 启动程序
45 | 将会启动开发中的 Mditor
46 | ```sh
47 | $ npm start
48 | ```
--------------------------------------------------------------------------------
/packages/desktop/src/menu/main.js:
--------------------------------------------------------------------------------
1 | const pkg = require('../../package.json');
2 | const app = require('electron').app;
3 | const i18n = require('../i18n');
4 |
5 | module.exports = async() => {
6 | let locale = i18n.locale;
7 | return {
8 | label: pkg.displayName,
9 | submenu: [{
10 | label: `${locale.about} ${pkg.displayName}`,
11 | role: 'about'
12 | },
13 | {
14 | label: `${locale.checkUpdate}...`,
15 | click() {
16 | app.checkUpdate(true);
17 | }
18 | },
19 | {
20 | type: 'separator'
21 | },
22 | {
23 | label: `${locale.preference}...`,
24 | click() {
25 | app.openPreference();
26 | }
27 | },
28 | {
29 | label: `${locale.resetPreference}...`,
30 | click() {
31 | app.resetPreference();
32 | }
33 | },
34 | {
35 | type: 'separator'
36 | },
37 | {
38 | label: locale.services,
39 | role: 'services',
40 | submenu: []
41 | },
42 | {
43 | type: 'separator'
44 | },
45 | {
46 | label: locale.hide,
47 | role: 'hide'
48 | },
49 | {
50 | label: locale.hideOthers,
51 | role: 'hideothers'
52 | },
53 | {
54 | label: locale.unHide,
55 | role: 'unhide'
56 | },
57 | {
58 | type: 'separator'
59 | },
60 | {
61 | label: locale.quit,
62 | role: 'quit'
63 | }
64 | ]
65 | };
66 | };
--------------------------------------------------------------------------------
/packages/embed/src/toolbar/index.js:
--------------------------------------------------------------------------------
1 | const mokit = require('mokit');
2 | const items = require('./items');
3 |
4 | require('./index.less');
5 |
6 | const Toolbar = new mokit.Component({
7 | template: require('./index.html'),
8 | props: {
9 | mditor: null
10 | },
11 |
12 | data() {
13 | return {
14 | items: items.slice(0)
15 | };
16 | },
17 |
18 | onReady() {
19 | this.bindCommands();
20 | },
21 |
22 | watch: {
23 | items() {
24 | this.bindCommands();
25 | }
26 | },
27 |
28 | bindCommands() {
29 | if (!this.mditor) return;
30 | this.items.forEach(item => {
31 | this.mditor.removeCommand(item.name);
32 | this.mditor.addCommand(item);
33 | });
34 | },
35 |
36 | isActive(item) {
37 | return this.mditor && item.state && this.mditor[item.state];
38 | },
39 |
40 | exec(name, event) {
41 | event.preventDefault();
42 | this.mditor.execCommand(name, event);
43 | },
44 |
45 | getItem(name) {
46 | return this.items.find(item => item.name === name);
47 | },
48 |
49 | removeItem(name) {
50 | let index = this.items.findIndex(item => item.name === name);
51 | return this.items.splice(index, 1);
52 | },
53 |
54 | addItem(item) {
55 | this.items.push(item);
56 | },
57 |
58 | replaceItem(name, newItem) {
59 | let index = this.items.findIndex(item => item.name === name);
60 | let oldItem = this.items.splice(index, 1);
61 | this.items.splice(index, 0, newItem);
62 | return oldItem;
63 | }
64 |
65 | });
66 |
67 | module.exports = Toolbar;
--------------------------------------------------------------------------------
/packages/embed/src/assets/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= htmlWebpackPlugin.options.title %>
8 | <% for (var css in htmlWebpackPlugin.files.css) { %>
9 |
10 | <% } %>
11 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
26 |
27 | <% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
28 |
29 | <% } %>
30 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/packages/desktop/bin/release.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs');
3 | const packager = require('electron-packager');
4 | const pkg = require('../package');
5 |
6 | const CWD = path.resolve(__dirname, '../');
7 |
8 | //electron-packager . Mditor --ignore='node_modules' --overwrite --out=release --icon=./design/icon.icns
9 | packager({
10 | name: 'Mditor',
11 | appBundleId: 'net.xhou.mditor',
12 | appCategoryType: 'public.app-category.utilities',
13 | dir: CWD,
14 | out: `${CWD}/release`,
15 | appVersion: pkg.version,
16 | arch: 'x64',
17 | icon: `${CWD}/design/icon.icns`,
18 | overwrite: true,
19 | electronVersion: '1.6.2',
20 | platform: "darwin",
21 | "osx-sign": {
22 | type: "distribution"
23 | },
24 | 'extend-info': `${__dirname}/info.plist`,
25 | ignore: [
26 | /node_modules/,
27 | /design/,
28 | /docs/,
29 | /release/,
30 | /test/,
31 | /bin/,
32 | /(\.DS_Store|\.babelrc|\.eslintrc\.yml|electron-builder\.yml|server\.yml|ignore|\.conf\.js|\.rename|\.config\.js|\.map|jasmine\.json)$/
33 | ]
34 | }, function (err, appPaths) {
35 | if (err) console.error(err);
36 | console.log('packaged', appPaths);
37 |
38 | //处理 deps
39 | let pkgFile = path.resolve(__dirname, '../release/Mditor-darwin-x64/Mditor.app/Contents/Resources/app/package.json');
40 | let buffer = fs.readFileSync(pkgFile);
41 | let pkgObj = JSON.parse(buffer.toString());
42 | delete pkgObj.devDependencies;
43 | delete pkgObj.scripts;
44 | delete pkgObj.dev;
45 | fs.writeFile(pkgFile, JSON.stringify(pkgObj, null, 2));
46 |
47 | });
--------------------------------------------------------------------------------
/packages/desktop/src/i18n/locales/en.yml:
--------------------------------------------------------------------------------
1 | about: About
2 | checkUpdate: Check For Updates
3 | preference: Preferences
4 | resetPreference: Reset Preferences
5 | services: Services
6 | hide: Hide
7 | hideOthers: Hide Others
8 | unHide: Un Hide
9 | quit: Quit
10 | clearRecent: Clear Recent Items
11 | file: File
12 | newFile: New File
13 | open: Open
14 | recentItems: Recent Items
15 | save: Save
16 | saveAs: Save As
17 | export: Export
18 | pdf: PDF
19 | html: HTML
20 | image: Image
21 | slide: Slide
22 | edit: Edit
23 | undo: Undo
24 | redo: Redo
25 | cut: Cut
26 | copy: Copy
27 | paste: Paste
28 | selectAll: Select All
29 | delete: Delete
30 | findAndReplace: Find And Replace
31 | view: View
32 | toggleSplit: Toggle Split
33 | togglePreview: Toggle Preview
34 | previewArea: Preview Area
35 | window: Window
36 | minimize: Minimize
37 | close: Close
38 | zoom: Zoom
39 | front: Bring To Front
40 | help: Help
41 | homepage: Homepage
42 | umlDoc: How to generate UML graphics
43 | slideDoc: How to write "Slide"
44 | currentlyTheLatestVersion: Currently the latest version
45 | goDownload: Go Download
46 | donNotUpdate: Don't Update
47 | discoverNewVersion: Discover new version
48 | recommendDownload: Recommend to download the new version now
49 | cancel: Cancel
50 | donNotSave: Don't Save
51 | confirmSave: Confirm Save
52 | saveAlertDetail: The file "${filename}" has not been saved, save now?
53 | bold: Bold
54 | italic: Italic
55 | underline: Underline
56 | strikethrough: Strikethrough
57 | header: Header
58 | quote: Quote
59 | code: Code
60 | listOl: Ordered list
61 | listUl: Unordered list
62 | link: Link
63 | table: Table
64 | line: Line
--------------------------------------------------------------------------------
/packages/desktop/src/preference/index.js:
--------------------------------------------------------------------------------
1 | const app = require('electron').app;
2 | const Promise = require('bluebird');
3 | const fs = require('../common/fs');
4 | const Parser = require('mditor').Parser;
5 | const yaml = require('../common/yaml');
6 |
7 | const DATA_PATH = app.getPath('userData');
8 | const PREFERENCE_FILE = `${DATA_PATH}/preference.md`;
9 |
10 | async function createFile() {
11 | let buffer = await fs.readFile(`${__dirname}/tmpl.md`)
12 | return fs.writeFile(PREFERENCE_FILE, buffer);
13 | }
14 |
15 | async function isExists() {
16 | return await fs.exists(PREFERENCE_FILE)
17 | }
18 |
19 | async function getFile() {
20 | if (!await isExists()) await createFile();
21 | return PREFERENCE_FILE;
22 | }
23 |
24 | async function load() {
25 | if (!await isExists()) return;
26 | let buffer = await fs.readFile(PREFERENCE_FILE);
27 | if (!buffer) return;
28 | let content = buffer.toString();
29 | let editorConfigs, shortcutConfigs;
30 | Parser.highlights['editor'] = {
31 | parse: function (code) {
32 | editorConfigs = code;
33 | }
34 | };
35 | Parser.highlights['shortcut'] = {
36 | parse: function (code) {
37 | shortcutConfigs = code;
38 | }
39 | };
40 | let parser = new Parser();
41 | parser.parse(content);
42 | Parser.highlights['editor'] = null;
43 | Parser.highlights['shortcut'] = null;
44 | return {
45 | editor: yaml(editorConfigs),
46 | shortcut: yaml(shortcutConfigs)
47 | }
48 | }
49 |
50 | async function reset() {
51 | if (!await isExists()) return;
52 | return fs.unlink(PREFERENCE_FILE);
53 | }
54 |
55 | exports.getFile = getFile;
56 | exports.load = load;
57 | exports.reset = reset;
--------------------------------------------------------------------------------
/packages/embed/lib/toolbar/index.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | var mokit = require('mokit');
4 | var items = require('./items');
5 |
6 | require('./index.less');
7 |
8 | var Toolbar = new mokit.Component({
9 | template: require('./index.html'),
10 | props: {
11 | mditor: null
12 | },
13 |
14 | /*istanbul ignore next*/data: function data() {
15 | return {
16 | items: items.slice(0)
17 | };
18 | },
19 | /*istanbul ignore next*/onReady: function onReady() {
20 | this.bindCommands();
21 | },
22 |
23 |
24 | watch: {
25 | /*istanbul ignore next*/items: function items() {
26 | this.bindCommands();
27 | }
28 | },
29 |
30 | /*istanbul ignore next*/bindCommands: function bindCommands() {
31 | /*istanbul ignore next*/var _this = this;
32 |
33 | if (!this.mditor) return;
34 | this.items.forEach(function (item) {
35 | /*istanbul ignore next*/_this.mditor.removeCommand(item.name);
36 | /*istanbul ignore next*/_this.mditor.addCommand(item);
37 | });
38 | },
39 | /*istanbul ignore next*/isActive: function isActive(item) {
40 | return this.mditor && item.state && this.mditor[item.state];
41 | },
42 | /*istanbul ignore next*/exec: function exec(name, event) {
43 | event.preventDefault();
44 | this.mditor.execCommand(name, event);
45 | },
46 | /*istanbul ignore next*/getItem: function getItem(name) {
47 | return this.items.find(function (item) /*istanbul ignore next*/{
48 | return item.name === name;
49 | });
50 | },
51 | /*istanbul ignore next*/removeItem: function removeItem(name) {
52 | var index = this.items.findIndex(function (item) /*istanbul ignore next*/{
53 | return item.name === name;
54 | });
55 | return this.items.splice(index, 1);
56 | },
57 | /*istanbul ignore next*/addItem: function addItem(item) {
58 | this.items.push(item);
59 | },
60 | /*istanbul ignore next*/replaceItem: function replaceItem(name, newItem) {
61 | var index = this.items.findIndex(function (item) /*istanbul ignore next*/{
62 | return item.name === name;
63 | });
64 | var oldItem = this.items.splice(index, 1);
65 | this.items.splice(index, 0, newItem);
66 | return oldItem;
67 | }
68 | });
69 |
70 | module.exports = Toolbar;
--------------------------------------------------------------------------------
/packages/embed/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const CleanWebpackPlugin = require('clean-webpack-plugin');
4 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
5 | const os = require('os');
6 | const pkg = require('./package.json');
7 |
8 | const ENV = process.env.NODE_ENV || 'prod';
9 | console.log(`${os.EOL}NODE_ENV:`, ENV);
10 |
11 | const cssBundlePlugin = new ExtractTextPlugin(`css/mditor${ENV == 'prod' ? '.min' : ''}.css`);
12 |
13 | const htmlPlugin = new HtmlWebpackPlugin({
14 | title: pkg.name,
15 | filename: 'index.html',
16 | template: './src/assets/index.ejs',
17 | inject: false
18 | });
19 |
20 | const cleanPlugin = new CleanWebpackPlugin(['dist'], {
21 | verbose: false
22 | });
23 |
24 | const compressPlugin = new webpack.optimize.UglifyJsPlugin({
25 | compress: {
26 | warnings: false
27 | }
28 | });
29 |
30 | const bannerPlugin = new webpack.BannerPlugin(`${pkg.displayName} version ${pkg.version}
31 | Homepage: ${pkg.homepage}`);
32 |
33 | // webpack plugins
34 | const plugins = [
35 | htmlPlugin,
36 | cssBundlePlugin,
37 | bannerPlugin,
38 | ];
39 | if (ENV === 'prod') plugins.push(compressPlugin);
40 |
41 | // webpack loaders
42 | const loaders = [{
43 | test: /\.js$/,
44 | loader: 'babel',
45 | exclude: [/node_modules/, /\.test\.js$/]
46 | }, {
47 | test: /.*mokit.*\.js$/,
48 | loader: 'babel'
49 | }, {
50 | test: /\.json$/,
51 | loader: 'json',
52 | }, {
53 | test: /\?raw$/,
54 | loader: 'raw'
55 | }, {
56 | test: /\.html$/,
57 | loader: 'raw'
58 | }, {
59 | test: /\.(png|jpg|gif)\?*.*$/,
60 | loader: 'url?limit=8192&name=img/[hash].[ext]'
61 | }, {
62 | test: /\.(eot|woff|woff2|webfont|ttf|svg)\?*.*$/,
63 | loader: 'url?limit=8192&name=font/[hash].[ext]'
64 | }, {
65 | test: /\.less$/,
66 | loader: cssBundlePlugin.extract('css!less', {
67 | publicPath: '../'
68 | })
69 | }, {
70 | test: /\.css$/,
71 | loader: cssBundlePlugin.extract('css', {
72 | publicPath: '../'
73 | })
74 | }];
75 |
76 | // webpack configs
77 | module.exports = {
78 | entry: {
79 | mditor: `./src/client`
80 | },
81 | output: {
82 | path: './dist/',
83 | filename: `js/[name]${ENV == 'prod' ? '.min' : ''}.js`
84 | },
85 | devtool: 'source-map',
86 | module: {
87 | loaders: loaders
88 | },
89 | plugins: plugins
90 | };
--------------------------------------------------------------------------------
/packages/desktop/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const CleanWebpackPlugin = require('clean-webpack-plugin');
4 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
5 | const os = require('os');
6 | const path = require('path');
7 |
8 | const ENV = process.env.NODE_ENV || 'prod';
9 | console.log(`${os.EOL}NODE_ENV:`, ENV);
10 |
11 | const cssBundlePlugin = new ExtractTextPlugin('css/bundle.css');
12 |
13 | const htmlPlugin = new HtmlWebpackPlugin({
14 | title: 'template',
15 | filename: 'index.html',
16 | template: './src/window/index.html'
17 | });
18 |
19 | const cleanPlugin = new CleanWebpackPlugin(['build/dist'], {
20 | verbose: false
21 | });
22 |
23 | const compressPlugin = new webpack.optimize.UglifyJsPlugin({
24 | compress: {
25 | warnings: false
26 | }
27 | });
28 |
29 | // webpack plugins
30 | const plugins = [
31 | htmlPlugin,
32 | cssBundlePlugin,
33 | cleanPlugin,
34 | ];
35 | //if (ENV === 'prod') plugins.push(compressPlugin);
36 |
37 | // webpack loaders
38 | const loaders = [{
39 | test: /\.js$/,
40 | loader: 'babel-loader',
41 | exclude: [/node_modules/, /\.test\.js$/]
42 | }, {
43 | test: /.*mokit.*\.js$/,
44 | loader: 'babel-loader'
45 | }, {
46 | test: /mditor/,
47 | loader: 'babel-loader'
48 | }, {
49 | test: /\.json$/,
50 | loader: 'json-loader'
51 | }, {
52 | test: /\?raw$/,
53 | loader: 'raw-loader'
54 | }, {
55 | test: /\.html$/,
56 | loader: 'raw-loader'
57 | }, {
58 | test: /\.(png|jpg|gif)\?*.*$/,
59 | loader: 'url-loader?limit=8192&name=img/[hash].[ext]'
60 | }, {
61 | test: /\.(eot|woff|woff2|webfont|ttf|svg)\?*.*$/,
62 | loader: 'url-loader?limit=8192&name=font/[hash].[ext]'
63 | }, {
64 | test: /\.less$/,
65 | loader: cssBundlePlugin.extract({
66 | use: ['css-loader', 'less-loader'],
67 | publicPath: '../'
68 | })
69 | }, {
70 | test: /\.css$/,
71 | loader: cssBundlePlugin.extract({
72 | use: 'css-loader',
73 | publicPath: '../'
74 | })
75 | }];
76 |
77 | // webpack configs
78 | module.exports = {
79 | context: __dirname,
80 | entry: {
81 | bundle: `./src/window/index.js`
82 | },
83 | output: {
84 | path: path.resolve(__dirname, './build'),
85 | filename: 'js/[name].js'
86 | },
87 | devtool: 'source-map',
88 | module: {
89 | loaders: loaders
90 | },
91 | plugins: plugins
92 | };
--------------------------------------------------------------------------------
/docs/assets/gh-fork-ribbon.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * "Fork me on GitHub" CSS ribbon v0.1.1 | MIT License
3 | * https://github.com/simonwhitaker/github-fork-ribbon-css
4 | */.github-fork-ribbon{position:absolute;padding:2px 0;background-color:#a00;background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(rgba(0,0,0,.15)));background-image:-webkit-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-moz-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-ms-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-o-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:linear-gradient(to bottom,rgba(0,0,0,0),rgba(0,0,0,.15));-webkit-box-shadow:0 2px 3px 0 rgba(0,0,0,.5);-moz-box-shadow:0 2px 3px 0 rgba(0,0,0,.5);box-shadow:0 2px 3px 0 rgba(0,0,0,.5);font:700 13px "Helvetica Neue",Helvetica,Arial,sans-serif;z-index:9999;pointer-events:auto}.github-fork-ribbon a,.github-fork-ribbon a:hover{color:#fff;text-decoration:none;text-shadow:0 -1px rgba(0,0,0,.5);text-align:center;width:200px;line-height:20px;display:inline-block;padding:2px 0;border-width:1px 0;border-style:dotted;border-color:#fff;border-color:rgba(255,255,255,.7)}.github-fork-ribbon-wrapper{width:150px;height:150px;position:absolute;overflow:hidden;top:0;z-index:9999;pointer-events:none}.github-fork-ribbon-wrapper.fixed{position:fixed}.github-fork-ribbon-wrapper.left{left:0}.github-fork-ribbon-wrapper.right{right:0}.github-fork-ribbon-wrapper.left-bottom{position:fixed;top:inherit;bottom:0;left:0}.github-fork-ribbon-wrapper.right-bottom{position:fixed;top:inherit;bottom:0;right:0}.github-fork-ribbon-wrapper.right .github-fork-ribbon{top:42px;right:-43px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.github-fork-ribbon-wrapper.left .github-fork-ribbon{top:42px;left:-43px;-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}.github-fork-ribbon-wrapper.left-bottom .github-fork-ribbon{top:80px;left:-43px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.github-fork-ribbon-wrapper.right-bottom .github-fork-ribbon{top:80px;right:-43px;-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/gh-fork-ribbon.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * "Fork me on GitHub" CSS ribbon v0.1.1 | MIT License
3 | * https://github.com/simonwhitaker/github-fork-ribbon-css
4 | */.github-fork-ribbon{position:absolute;padding:2px 0;background-color:#a00;background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(rgba(0,0,0,.15)));background-image:-webkit-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-moz-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-ms-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-o-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:linear-gradient(to bottom,rgba(0,0,0,0),rgba(0,0,0,.15));-webkit-box-shadow:0 2px 3px 0 rgba(0,0,0,.5);-moz-box-shadow:0 2px 3px 0 rgba(0,0,0,.5);box-shadow:0 2px 3px 0 rgba(0,0,0,.5);font:700 13px "Helvetica Neue",Helvetica,Arial,sans-serif;z-index:9999;pointer-events:auto}.github-fork-ribbon a,.github-fork-ribbon a:hover{color:#fff;text-decoration:none;text-shadow:0 -1px rgba(0,0,0,.5);text-align:center;width:200px;line-height:20px;display:inline-block;padding:2px 0;border-width:1px 0;border-style:dotted;border-color:#fff;border-color:rgba(255,255,255,.7)}.github-fork-ribbon-wrapper{width:150px;height:150px;position:absolute;overflow:hidden;top:0;z-index:9999;pointer-events:none}.github-fork-ribbon-wrapper.fixed{position:fixed}.github-fork-ribbon-wrapper.left{left:0}.github-fork-ribbon-wrapper.right{right:0}.github-fork-ribbon-wrapper.left-bottom{position:fixed;top:inherit;bottom:0;left:0}.github-fork-ribbon-wrapper.right-bottom{position:fixed;top:inherit;bottom:0;right:0}.github-fork-ribbon-wrapper.right .github-fork-ribbon{top:42px;right:-43px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.github-fork-ribbon-wrapper.left .github-fork-ribbon{top:42px;left:-43px;-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}.github-fork-ribbon-wrapper.left-bottom .github-fork-ribbon{top:80px;left:-43px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.github-fork-ribbon-wrapper.right-bottom .github-fork-ribbon{top:80px;right:-43px;-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}
--------------------------------------------------------------------------------
/packages/desktop/src/menu/file.js:
--------------------------------------------------------------------------------
1 | const app = require('electron').app;
2 | const recent = require('../recent');
3 | const i18n = require('../i18n');
4 |
5 | module.exports = async() => {
6 | let locale = i18n.locale;
7 | let recentItems = await recent.getItems();
8 | recentItems = recentItems.map(filename => {
9 | return {
10 | label: filename,
11 | click() {
12 | app.openFileInWindow(filename);
13 | }
14 | };
15 | });
16 | recentItems.push({
17 | type: 'separator'
18 | });
19 | recentItems.push({
20 | label: locale.clearRecent,
21 | click() {
22 | recent.clear();
23 | }
24 | });
25 |
26 | return {
27 | label: locale.file,
28 | role: 'file',
29 | submenu: [{
30 | label: locale.newFile,
31 | accelerator: 'CmdOrCtrl+N',
32 | click() {
33 | app.createWindow();
34 | }
35 | },
36 | {
37 | type: 'separator'
38 | },
39 | {
40 | label: `${locale.open}...`,
41 | accelerator: 'CmdOrCtrl+O',
42 | click() {
43 | app.open();
44 | }
45 | },
46 | {
47 | label: locale.recentItems,
48 | submenu: recentItems
49 | },
50 | {
51 | type: 'separator'
52 | },
53 | {
54 | accelerator: 'CmdOrCtrl+S',
55 | label: `${locale.save}...`,
56 | click() {
57 | app.save();
58 | }
59 | },
60 | {
61 | accelerator: 'Shift+CmdOrCtrl+S',
62 | label: `${locale.saveAs}...`,
63 | click() {
64 | app.saveAs();
65 | }
66 | },
67 | {
68 | type: 'separator'
69 | },
70 | {
71 | label: locale.export,
72 | submenu: [{
73 | label: `${locale.html}...`,
74 | click() {
75 | app.toHTML();
76 | }
77 | }, {
78 | label: `${locale.pdf}...`,
79 | click() {
80 | app.toPDF();
81 | }
82 | }, {
83 | label: `${locale.image}...`,
84 | click() {
85 | app.toImage();
86 | }
87 | }, {
88 | label: `${locale.slide}...`,
89 | click() {
90 | app.toSlide();
91 | }
92 | }]
93 | }, {
94 | type: 'separator'
95 | }, {
96 | label: locale.quit,
97 | click() {
98 | app.quit();
99 | }
100 | }
101 | ]
102 | };
103 | };
--------------------------------------------------------------------------------
/packages/embed/src/finder/index.js:
--------------------------------------------------------------------------------
1 | const mokit = require('mokit');
2 | const utils = require('ntils');
3 |
4 | require('./index.less');
5 |
6 | const CHECK_REGEXP = /^\/[\s\S]+\/(i|g|m)*$/;
7 |
8 | const Finder = new mokit.Component({
9 | template: require('./index.html'),
10 | props: {
11 | mditor: null,
12 | active: false,
13 | findWord: '',
14 | replaceWord: ''
15 | },
16 | onReady() {
17 | this.mditor.removeCommand('find');
18 | this.mditor.addCommand({
19 | name: 'find',
20 | key: '{cmd}+f',
21 | owner: this.mditor.$element,
22 | handler: this.show.bind(this, null)
23 | });
24 | this.mditor.removeCommand('cancel-find');
25 | this.mditor.addCommand({
26 | name: 'cancel-find',
27 | key: 'esc',
28 | owner: this.mditor.$element,
29 | handler: this.hide.bind(this)
30 | });
31 | },
32 | hide() {
33 | this.findWord = '';
34 | this.replaceWord = '';
35 | this.mditor.editor.markExp = null;
36 | this.active = false;
37 | },
38 | show(text) {
39 | this.active = true;
40 | this.findWord = text || this.mditor.editor.getSelectText();
41 | if (this.active) {
42 | setTimeout(() => {
43 | this.findBox.focus();
44 | }, 200);
45 | }
46 | this.mditor.editor.syncScroll();
47 | },
48 | watch: {
49 | findWord() {
50 | if (!this.mditor || !this.mditor.editor) return;
51 | if (!this.findWord) {
52 | this.mditor.editor.markExp = null;
53 | } else {
54 | this.mditor.editor.markExp = this.parseRegexp(this.findWord);
55 | }
56 | setTimeout(() => {
57 | this.mditor.editor.activeMark(0);
58 | }, 100);
59 | }
60 | },
61 | parseRegexp(text, forceStr) {
62 | if (!forceStr && CHECK_REGEXP.test(text)) {
63 | try {
64 | return (new Function(`return ${text}`))();
65 | } catch (err) {
66 | return this.parseRegexp(text, true);
67 | }
68 | } else {
69 | return new RegExp(utils.escapeRegExp(text), 'gm');
70 | }
71 | },
72 | find() {
73 | this.mditor.editor.activeMark();
74 | },
75 | replace() {
76 | this.mditor.value = this.mditor.value.replace(
77 | this.mditor.editor.markExp,
78 | this.replaceWord || ''
79 | );
80 | },
81 | onFindEnter(event) {
82 | if (event.keyCode != 13) return;
83 | event.preventDefault();
84 | this.find();
85 | },
86 | onReplaceEnter(event) {
87 | if (event.keyCode != 13) return;
88 | event.preventDefault();
89 | this.replace();
90 | },
91 | onCompositionEnd(event) {
92 | event.target.blur();
93 | event.target.focus();
94 | }
95 | });
96 |
97 | module.exports = Finder;
--------------------------------------------------------------------------------
/docs/doc/slide.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | slide
9 |
10 |
20 |
36 |
58 |
79 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/packages/desktop/docs/doc/slide.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | slide
9 |
10 |
20 |
36 |
58 |
79 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/packages/desktop/src/convert/index.js:
--------------------------------------------------------------------------------
1 | const pdf = require('html-pdf');
2 | const Promise = require('bluebird');
3 | const fs = require('../common/fs');
4 | const path = require('path');
5 | const stp = require('stp');
6 | const UMLParser = require('../uml');
7 | const yaml = require('../common/yaml');
8 |
9 | const Parser = require('mditor').Parser;
10 | Parser.highlights['uml'] = new UMLParser();
11 |
12 | const parser = Promise.promisifyAll(new Parser());
13 |
14 | exports.toHTML = async function (opts) {
15 | if (!opts) return;
16 | opts.title = opts.title || 'Untitled';
17 | opts.style = opts.style || '';
18 | opts.content = opts.content || '';
19 | let styleFile = require.resolve('mditor/dist/css/mditor.min.css');
20 | opts.style += (await fs.readFile(styleFile)).toString();
21 | opts.style += (await fs.readFile(`${__dirname}/html.css`)).toString();
22 | if (opts.border) {
23 | opts.style += (await fs.readFile(`${__dirname}/border.css`)).toString();
24 | }
25 | opts.content = await parser.parseAsync(opts.content);
26 | let tmpl = (await fs.readFile(`${__dirname}/tmpl.html`)).toString();
27 | let fn = stp(tmpl);
28 | return fn(opts);
29 | };
30 |
31 | exports.toPDF = async function (opts) {
32 | let html = await this.toHTML(opts);
33 | return new Promise((resolve, reject) => {
34 | pdf.create(html, {
35 | format: 'A4',
36 | border: '1cm',
37 | type: 'pdf'
38 | }).toBuffer(function (err, buffer) {
39 | if (err) return reject(err);
40 | resolve(buffer);
41 | });
42 | });
43 | };
44 |
45 | exports.toImage = async function (opts) {
46 | opts.style = 'body{padding:15px;background-color: #fff;}';
47 | let html = await this.toHTML(opts);
48 | return new Promise((resolve, reject) => {
49 | pdf.create(html, {
50 | border: '1cm',
51 | width: '900px',
52 | type: opts.type || 'png'
53 | }).toBuffer(function (err, buffer) {
54 | if (err) return reject(err);
55 | resolve(buffer);
56 | });
57 | });
58 | };
59 |
60 | exports.toSlide = async function (opts) {
61 | if (!opts) return;
62 | opts.title = opts.title || 'Untitled';
63 | opts.content = opts.content || '';
64 | let parts = opts.content.split(/`{1,3}slide([\s\S]*?)`{1,3}/).slice(1);
65 | opts.items = [];
66 | for (let i = 0; i < parts.length; i += 2) {
67 | let meta = yaml(parts[i]) || {};
68 | let body = await parser.parseAsync(parts[i + 1]);
69 | opts.items.push(``);
77 | }
78 | let tmpl = (await fs.readFile(`${__dirname}/slide.html`)).toString();
79 | let fn = stp(tmpl);
80 | return fn(opts);
81 | };
--------------------------------------------------------------------------------
/packages/desktop/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mditor-desktop",
3 | "displayName": "Mditor",
4 | "version": "1.0.0",
5 | "description": "Mditor,最好用的 markdown 编辑器!",
6 | "main": "./src/app.js",
7 | "scripts": {
8 | "start": "./bin/start.sh",
9 | "stop": "./bin/stop.sh",
10 | "restart": "./bin/restart.sh",
11 | "clear": "./bin/clear.sh",
12 | "lint": "eslint ./lib",
13 | "build": "./bin/build.sh",
14 | "watch": "./bin/watch.sh",
15 | "dev": "./bin/watch.sh",
16 | "unit": "./bin/unit.sh",
17 | "e2e": "./bin/e2e.sh",
18 | "test": "./bin/test.sh",
19 | "release": "./bin/release.sh",
20 | "desk": "electron ."
21 | },
22 | "author": "",
23 | "license": "MIT",
24 | "dev": {
25 | "host": "localhost",
26 | "port": 8006
27 | },
28 | "homepage": "http://mditor.com",
29 | "update": {
30 | "url": "http://mditor.com/update.json"
31 | },
32 | "devDependencies": {
33 | "babel-core": "^6.21.0",
34 | "babel-eslint": "^7.1.1",
35 | "babel-loader": "^6.4.0",
36 | "babel-plugin-transform-runtime": "^6.15.0",
37 | "babel-polyfill": "^6.20.0",
38 | "babel-preset-es2015": "^6.18.0",
39 | "babel-preset-stage-3": "^6.17.0",
40 | "babel-runtime": "^6.20.0",
41 | "bootstrap": "^3.3.7",
42 | "cify": "^2.1.11",
43 | "clean-webpack-plugin": "^0.1.14",
44 | "css-loader": "^0.26.1",
45 | "electron": "^1.6.5",
46 | "electron-builder": "^15.2.0",
47 | "electron-installer-dmg": "^0.2.0",
48 | "electron-packager": "^8.5.2",
49 | "eslint": "^3.13.0",
50 | "exorcist": "^0.4.0",
51 | "extract-text-webpack-plugin": "^2.1.0",
52 | "file-loader": "^0.10.1",
53 | "html-webpack-plugin": "^2.26.0",
54 | "isparta": "4.0.0",
55 | "isparta-loader": "^2.0.0",
56 | "istanbul": "0.4.5",
57 | "jasmine": "2.5.2",
58 | "jasmine-core": "2.5.0",
59 | "json-loader": "^0.5.4",
60 | "karma": "1.2.0",
61 | "karma-chrome-launcher": "2.0.0",
62 | "karma-coverage": "1.1.1",
63 | "karma-jasmine": "1.0.2",
64 | "karma-phantomjs-launcher": "1.0.2",
65 | "karma-sourcemap-loader": "0.3.7",
66 | "karma-spec-reporter": "0.0.26",
67 | "karma-webpack": "1.8.0",
68 | "less": "^2.7.2",
69 | "less-loader": "^3.0.0",
70 | "nokit-filter-proxy": "0.0.8",
71 | "nokitjs": "^1.26.3",
72 | "phantomjs-prebuilt": "^2.1.13",
73 | "raw-loader": "^0.5.1",
74 | "selenium-webdriver": "^3.0.1",
75 | "style-loader": "^0.13.2",
76 | "url-loader": "^0.5.8",
77 | "webpack": "^2.2.1"
78 | },
79 | "dependencies": {
80 | "bluebird": "^3.5.0",
81 | "electron-renderer-value": "^1.1.0",
82 | "html-pdf": "^2.1.0",
83 | "js-yaml": "^3.8.2",
84 | "md5": "^2.2.1",
85 | "mditor": "^1.2.9",
86 | "mkdirp": "^0.5.1",
87 | "mokit": "^3.1.2",
88 | "node-fetch": "^1.6.3",
89 | "ntils": "^2.1.0",
90 | "stp": "^0.0.2"
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/packages/embed/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mditor",
3 | "displayName": "Mditor embed",
4 | "version": "1.3.3",
5 | "description": "一个简洁、易于集成、方便扩展、期望舒服的编写 markdown 的编辑器",
6 | "main": "./lib/server/index.js",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/houfeng/mditor.git"
10 | },
11 | "keywords": [
12 | "mditor",
13 | "markdown",
14 | "embedded",
15 | "editor"
16 | ],
17 | "scripts": {
18 | "start": "./bin/start.sh",
19 | "stop": "./bin/stop.sh",
20 | "restart": "./bin/restart.sh",
21 | "clear": "./bin/clear.sh",
22 | "lint": "eslint ./src",
23 | "build": "./bin/build.sh",
24 | "watch": "./bin/watch.sh",
25 | "dev": "./bin/watch.sh",
26 | "unit": "./bin/unit.sh",
27 | "e2e": "./bin/e2e.sh",
28 | "test": "./bin/test.sh"
29 | },
30 | "author": {
31 | "name": "Houfeng",
32 | "email": "admin@xhou.net",
33 | "url": "http://houfeng.net"
34 | },
35 | "license": "MIT",
36 | "bugs": {
37 | "url": "https://github.com/houfeng/mditor/issues"
38 | },
39 | "homepage": "http://mditor.com",
40 | "dependencies": {
41 | "font-awesome": "^4.7.0",
42 | "github-markdown-css": "^2.4.1",
43 | "marked": "^0.3.6",
44 | "mokit": "^3.1.2",
45 | "ntils": "^2.1.0",
46 | "prismjs": "^1.8.3",
47 | "shortcut-key": "^1.0.0"
48 | },
49 | "dev": {
50 | "host": "localhost",
51 | "port": 8008
52 | },
53 | "devDependencies": {
54 | "babel-cli": "^6.24.1",
55 | "babel-core": "^6.21.0",
56 | "babel-eslint": "^7.1.1",
57 | "babel-loader": "^6.2.10",
58 | "babel-plugin-transform-runtime": "^6.15.0",
59 | "babel-polyfill": "^6.20.0",
60 | "babel-preset-es2015": "^6.18.0",
61 | "babel-preset-stage-3": "^6.17.0",
62 | "babel-runtime": "^6.20.0",
63 | "bootstrap": "^3.3.7",
64 | "cify": "^2.1.11",
65 | "clean-webpack-plugin": "^0.1.14",
66 | "css-loader": "^0.26.1",
67 | "eslint": "^3.13.0",
68 | "exorcist": "^0.4.0",
69 | "extract-text-webpack-plugin": "^1.0.1",
70 | "file-loader": "^0.10.0",
71 | "html-webpack-plugin": "^2.26.0",
72 | "isparta": "4.0.0",
73 | "isparta-loader": "^2.0.0",
74 | "istanbul": "0.4.5",
75 | "jasmine": "2.5.2",
76 | "jasmine-core": "2.5.0",
77 | "json-loader": "^0.5.4",
78 | "karma": "1.2.0",
79 | "karma-chrome-launcher": "2.0.0",
80 | "karma-coverage": "1.1.1",
81 | "karma-jasmine": "1.0.2",
82 | "karma-phantomjs-launcher": "1.0.2",
83 | "karma-sourcemap-loader": "0.3.7",
84 | "karma-spec-reporter": "0.0.26",
85 | "karma-webpack": "1.8.0",
86 | "less": "^2.7.2",
87 | "less-loader": "^2.2.3",
88 | "nokit-filter-proxy": "0.0.8",
89 | "nokitjs": "^1.26.3",
90 | "phantomjs-prebuilt": "^2.1.13",
91 | "raw-loader": "^0.5.1",
92 | "selenium-webdriver": "^3.0.1",
93 | "url-loader": "^0.5.7",
94 | "webpack": "^1.14.0"
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/docs/slide/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | PPT
9 |
20 |
24 |
30 |
69 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/packages/desktop/docs/slide/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | PPT
9 |
20 |
24 |
30 |
69 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/docs/stylesheets/github-light.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 GitHub Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | */
17 |
18 | .pl-c /* comment */ {
19 | color: #969896;
20 | }
21 |
22 | .pl-c1 /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */,
23 | .pl-s .pl-v /* string variable */ {
24 | color: #0086b3;
25 | }
26 |
27 | .pl-e /* entity */,
28 | .pl-en /* entity.name */ {
29 | color: #795da3;
30 | }
31 |
32 | .pl-s .pl-s1 /* string source */,
33 | .pl-smi /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ {
34 | color: #333;
35 | }
36 |
37 | .pl-ent /* entity.name.tag */ {
38 | color: #63a35c;
39 | }
40 |
41 | .pl-k /* keyword, storage, storage.type */ {
42 | color: #a71d5d;
43 | }
44 |
45 | .pl-pds /* punctuation.definition.string, string.regexp.character-class */,
46 | .pl-s /* string */,
47 | .pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */,
48 | .pl-sr /* string.regexp */,
49 | .pl-sr .pl-cce /* string.regexp constant.character.escape */,
50 | .pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */,
51 | .pl-sr .pl-sre /* string.regexp source.ruby.embedded */ {
52 | color: #183691;
53 | }
54 |
55 | .pl-v /* variable */ {
56 | color: #ed6a43;
57 | }
58 |
59 | .pl-id /* invalid.deprecated */ {
60 | color: #b52a1d;
61 | }
62 |
63 | .pl-ii /* invalid.illegal */ {
64 | background-color: #b52a1d;
65 | color: #f8f8f8;
66 | }
67 |
68 | .pl-sr .pl-cce /* string.regexp constant.character.escape */ {
69 | color: #63a35c;
70 | font-weight: bold;
71 | }
72 |
73 | .pl-ml /* markup.list */ {
74 | color: #693a17;
75 | }
76 |
77 | .pl-mh /* markup.heading */,
78 | .pl-mh .pl-en /* markup.heading entity.name */,
79 | .pl-ms /* meta.separator */ {
80 | color: #1d3e81;
81 | font-weight: bold;
82 | }
83 |
84 | .pl-mq /* markup.quote */ {
85 | color: #008080;
86 | }
87 |
88 | .pl-mi /* markup.italic */ {
89 | color: #333;
90 | font-style: italic;
91 | }
92 |
93 | .pl-mb /* markup.bold */ {
94 | color: #333;
95 | font-weight: bold;
96 | }
97 |
98 | .pl-md /* markup.deleted, meta.diff.header.from-file */ {
99 | background-color: #ffecec;
100 | color: #bd2c00;
101 | }
102 |
103 | .pl-mi1 /* markup.inserted, meta.diff.header.to-file */ {
104 | background-color: #eaffea;
105 | color: #55a532;
106 | }
107 |
108 | .pl-mdr /* meta.diff.range */ {
109 | color: #795da3;
110 | font-weight: bold;
111 | }
112 |
113 | .pl-mo /* meta.output */ {
114 | color: #1d3e81;
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/packages/desktop/docs/stylesheets/github-light.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 GitHub Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | */
17 |
18 | .pl-c /* comment */ {
19 | color: #969896;
20 | }
21 |
22 | .pl-c1 /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */,
23 | .pl-s .pl-v /* string variable */ {
24 | color: #0086b3;
25 | }
26 |
27 | .pl-e /* entity */,
28 | .pl-en /* entity.name */ {
29 | color: #795da3;
30 | }
31 |
32 | .pl-s .pl-s1 /* string source */,
33 | .pl-smi /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ {
34 | color: #333;
35 | }
36 |
37 | .pl-ent /* entity.name.tag */ {
38 | color: #63a35c;
39 | }
40 |
41 | .pl-k /* keyword, storage, storage.type */ {
42 | color: #a71d5d;
43 | }
44 |
45 | .pl-pds /* punctuation.definition.string, string.regexp.character-class */,
46 | .pl-s /* string */,
47 | .pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */,
48 | .pl-sr /* string.regexp */,
49 | .pl-sr .pl-cce /* string.regexp constant.character.escape */,
50 | .pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */,
51 | .pl-sr .pl-sre /* string.regexp source.ruby.embedded */ {
52 | color: #183691;
53 | }
54 |
55 | .pl-v /* variable */ {
56 | color: #ed6a43;
57 | }
58 |
59 | .pl-id /* invalid.deprecated */ {
60 | color: #b52a1d;
61 | }
62 |
63 | .pl-ii /* invalid.illegal */ {
64 | background-color: #b52a1d;
65 | color: #f8f8f8;
66 | }
67 |
68 | .pl-sr .pl-cce /* string.regexp constant.character.escape */ {
69 | color: #63a35c;
70 | font-weight: bold;
71 | }
72 |
73 | .pl-ml /* markup.list */ {
74 | color: #693a17;
75 | }
76 |
77 | .pl-mh /* markup.heading */,
78 | .pl-mh .pl-en /* markup.heading entity.name */,
79 | .pl-ms /* meta.separator */ {
80 | color: #1d3e81;
81 | font-weight: bold;
82 | }
83 |
84 | .pl-mq /* markup.quote */ {
85 | color: #008080;
86 | }
87 |
88 | .pl-mi /* markup.italic */ {
89 | color: #333;
90 | font-style: italic;
91 | }
92 |
93 | .pl-mb /* markup.bold */ {
94 | color: #333;
95 | font-weight: bold;
96 | }
97 |
98 | .pl-md /* markup.deleted, meta.diff.header.from-file */ {
99 | background-color: #ffecec;
100 | color: #bd2c00;
101 | }
102 |
103 | .pl-mi1 /* markup.inserted, meta.diff.header.to-file */ {
104 | background-color: #eaffea;
105 | color: #55a532;
106 | }
107 |
108 | .pl-mdr /* meta.diff.range */ {
109 | color: #795da3;
110 | font-weight: bold;
111 | }
112 |
113 | .pl-mo /* meta.output */ {
114 | color: #1d3e81;
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/packages/embed/README.md:
--------------------------------------------------------------------------------
1 | ## 只求极致
2 |
3 | [ **M** ] arkdown + E [ **ditor** ] = **Mditor**
4 |
5 | [](http://badge.fury.io/js/mditor)
6 |
7 | Mditor 是一个简洁、易于集成、方便扩展、期望舒服的编写 markdown 的编辑器,仅此而已...
8 |
9 | 支持浏览器: chrome/safari/firefox/ie9+
10 |
11 | 
12 |
13 | ## 在线体验
14 | [在线 demo](http://embed.mditor.com/demo/index.html)
15 |
16 | ## 使用桌面版
17 | 下载桌面版本 [http://mditor.com/](http://mditor.com/)
18 |
19 | ## 在浏览器集成 Mditor
20 |
21 | ##### 第一步:
22 |
23 | 引入 Mditor 样式文件
24 | ```html
25 |
26 | ```
27 |
28 | 引用 Mditor 脚本文件
29 | ```html
30 |
31 | ```
32 |
33 | 当然,也可以使用 CDN 资源
34 | ```html
35 | ...
36 |
37 | ...
38 |
39 | ...
40 | ```
41 |
42 | ##### 第二步:
43 |
44 | 添加 textarea 元素
45 | ```html
46 |
47 | ```
48 |
49 | 创建 Mditor 实例
50 | ```js
51 | var mditor = Mditor.fromTextarea(document.getElementById('editor'));
52 |
53 | //获取或设置编辑器的值
54 | mditor.on('ready',function(){
55 | console.log(mditor.value);
56 | mditor.value = '** hello **';
57 | });
58 | ```
59 |
60 | 所有 API 都应在 ready 事件中进行调用
61 |
62 | ##### 模式控制 API:
63 |
64 | ```js
65 | //是否打开分屏
66 | mditor.split = true; //打开
67 | mditor.split = false; //关闭
68 |
69 | //是否打开预览
70 | mditor.preivew = true; //打开
71 | mditor.preivew = false; //关闭
72 |
73 | //是否全屏
74 | mditor.fullscreen = true; //打开
75 | mditor.fullscreen = false; //关闭
76 | ```
77 |
78 | ##### 工具条配置 API
79 |
80 | ```js
81 | //mditor.toolbar.items 是一个数组,包括所有按钮的信息
82 | //可以直接操作 items 以控制工具条
83 |
84 | //只保留第一个按钮
85 | mditor.toolbar.items = mditor.toolbar.items.slice(0,1);
86 | //添加一个按钮
87 | mditor.toolbar.addItem({...});
88 | //移除一个按钮
89 | mditor.toolbar.removeItem(name);
90 | //替换一个按钮
91 | mditor.toolbar.replaceItem(name, {...});
92 | //获取一个按钮
93 | mditor.toolbar.getItem(name);
94 |
95 | //更改按钮行为
96 | //示例,更改「图片」按钮配置,其它按钮是同样的方法
97 | let btn = mditor.toolbar.getItem('image');
98 | //替换按钮动作
99 | btn.handler = function(){
100 | //自定义处理逻辑
101 | //this 指向当前 mditor 实例
102 | };
103 |
104 | //还可以替换其它信息
105 | btn.icon = '...'; //设置按钮图标
106 | btn.title = '...'; //投置按钮标题
107 | btn.control = true; //作为控制按钮显示在右侧
108 | btn.key = 'ctrl+d'; //设置按钮快捷建
109 | ```
110 |
111 | ##### 文本编辑 API
112 |
113 | ```js
114 | //编辑器相关 API 在 mditor.editor 对象上
115 |
116 | //在光标前插入文本
117 | mditor.editor.insertBeforeText('文本');
118 | //在光标后插入文本
119 | mditor.editor.insertAfterText('文本');
120 | //其它,说明待补充
121 | ...
122 | ```
123 |
124 | ## 在服务器渲染 Markdown
125 |
126 | 通过 npm 安装
127 | ```sh
128 | npm install mditor -save
129 | ```
130 |
131 | 在服务端解析
132 | ```javascript
133 | var mditor = require("mditor");
134 | var parser = new mditor.Parser();
135 | var html = parser.parse("** Hello mditor! **");
136 | ```
137 |
138 | 在页面中展示解析后的内容
139 | ```html
140 | ...
141 |
142 |
143 | ...
144 |
145 |
146 |
147 | ```
148 |
149 | -end-
150 |
--------------------------------------------------------------------------------
/packages/embed/lib/finder/index.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | var mokit = require('mokit');
4 | var utils = require('ntils');
5 |
6 | require('./index.less');
7 |
8 | var CHECK_REGEXP = /^\/[\s\S]+\/(i|g|m)*$/;
9 |
10 | var Finder = new mokit.Component({
11 | template: require('./index.html'),
12 | props: {
13 | mditor: null,
14 | active: false,
15 | findWord: '',
16 | replaceWord: ''
17 | },
18 | /*istanbul ignore next*/onReady: function onReady() {
19 | this.mditor.removeCommand('find');
20 | this.mditor.addCommand({
21 | name: 'find',
22 | key: '{cmd}+f',
23 | owner: this.mditor.$element,
24 | handler: this.show.bind(this, null)
25 | });
26 | this.mditor.removeCommand('cancel-find');
27 | this.mditor.addCommand({
28 | name: 'cancel-find',
29 | key: 'esc',
30 | owner: this.mditor.$element,
31 | handler: this.hide.bind(this)
32 | });
33 | },
34 | /*istanbul ignore next*/hide: function hide() {
35 | this.findWord = '';
36 | this.replaceWord = '';
37 | this.mditor.editor.markExp = null;
38 | this.active = false;
39 | },
40 | /*istanbul ignore next*/show: function show(text) {
41 | /*istanbul ignore next*/var _this = this;
42 |
43 | this.active = true;
44 | this.findWord = text || this.mditor.editor.getSelectText();
45 | if (this.active) {
46 | setTimeout(function () {
47 | /*istanbul ignore next*/_this.findBox.focus();
48 | }, 200);
49 | }
50 | this.mditor.editor.syncScroll();
51 | },
52 |
53 | watch: {
54 | /*istanbul ignore next*/findWord: function findWord() {
55 | /*istanbul ignore next*/var _this2 = this;
56 |
57 | if (!this.mditor || !this.mditor.editor) return;
58 | if (!this.findWord) {
59 | this.mditor.editor.markExp = null;
60 | } else {
61 | this.mditor.editor.markExp = this.parseRegexp(this.findWord);
62 | }
63 | setTimeout(function () {
64 | /*istanbul ignore next*/_this2.mditor.editor.activeMark(0);
65 | }, 100);
66 | }
67 | },
68 | /*istanbul ignore next*/parseRegexp: function parseRegexp(text, forceStr) {
69 | if (!forceStr && CHECK_REGEXP.test(text)) {
70 | try {
71 | return new Function( /*istanbul ignore next*/'return ' + text)();
72 | } catch (err) {
73 | return this.parseRegexp(text, true);
74 | }
75 | } else {
76 | return new RegExp(utils.escapeRegExp(text), 'gm');
77 | }
78 | },
79 | /*istanbul ignore next*/find: function find() {
80 | this.mditor.editor.activeMark();
81 | },
82 | /*istanbul ignore next*/replace: function replace() {
83 | this.mditor.value = this.mditor.value.replace(this.mditor.editor.markExp, this.replaceWord || '');
84 | },
85 | /*istanbul ignore next*/onFindEnter: function onFindEnter(event) {
86 | if (event.keyCode != 13) return;
87 | event.preventDefault();
88 | this.find();
89 | },
90 | /*istanbul ignore next*/onReplaceEnter: function onReplaceEnter(event) {
91 | if (event.keyCode != 13) return;
92 | event.preventDefault();
93 | this.replace();
94 | },
95 | /*istanbul ignore next*/onCompositionEnd: function onCompositionEnd(event) {
96 | event.target.blur();
97 | event.target.focus();
98 | }
99 | });
100 |
101 | module.exports = Finder;
--------------------------------------------------------------------------------
/docs/assets/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var screenshots = ['scr1', 'scr2', 'scr3', 'scr4'];
4 |
5 | document.addEventListener('DOMContentLoaded', function() {
6 | initDownload();
7 | setImages();
8 | });
9 |
10 | function setImages() {
11 | var odd = false;
12 | each('.feature>img', function(el) {
13 | if (odd) {
14 | el.parentNode.insertBefore(el, el.parentNode.firstChild);
15 | }
16 | odd = !odd;
17 | });
18 | }
19 |
20 | function initDownload() {
21 | var os = detectOs();
22 | if (os) {
23 | setDownloadButton(os);
24 | }
25 | }
26 |
27 | function detectOs() {
28 | var platform = navigator.platform.toLowerCase();
29 | if (platform.indexOf('mac') >= 0) {
30 | return 'mac';
31 | }
32 | if (platform.indexOf('linux') >= 0) {
33 | return 'linux';
34 | }
35 | if (platform.indexOf('win') >= 0) {
36 | return 'win32';
37 | }
38 | return undefined;
39 | }
40 |
41 | function setDownloadButton(os) {
42 | setDownloadButtonTitle(os);
43 | setLatestReleaseUrl(os);
44 | }
45 |
46 | function setDownloadButtonTitle(os) {
47 | each('.btn-download>.btn-desc', function(el) {
48 | switch (os) {
49 | case 'mac':
50 | el.innerHTML = ' for Mac OS X';
51 | break;
52 | case 'win32':
53 | el.innerHTML = ' for Windows';
54 | break;
55 | case 'linux':
56 | el.innerHTML = ' for Linux';
57 | break;
58 | }
59 | });
60 | each('.btn-sub-link', function(el) {
61 | el.style.display = 'block';
62 | });
63 | }
64 |
65 | function setLatestReleaseUrl(os) {
66 | var xhr = new XMLHttpRequest();
67 | xhr.responseType = 'json';
68 | xhr.addEventListener('load', function() {
69 | releasesLoaded(xhr.response, os)
70 | });
71 | xhr.open('GET', 'https://api.github.com/repos/antelle/keeweb/releases/latest');
72 | xhr.send();
73 | }
74 |
75 | function releasesLoaded(releaseInfo, os) {
76 | var knownAssets = [
77 | 'KeeWeb.linux.x64.deb',
78 | 'KeeWeb.mac.dmg',
79 | 'KeeWeb.win32.exe'
80 | ];
81 | var url;
82 | releaseInfo.assets.forEach(function(asset) {
83 | if (asset.name.indexOf(os) > 0 && knownAssets.indexOf(asset.name) >= 0) {
84 | url = asset.browser_download_url;
85 | }
86 | });
87 | if (url) {
88 | each('.btn-download', function(el) {
89 | el.setAttribute('href', url);
90 | });
91 | }
92 | }
93 |
94 | function rotateScreenshot(next) {
95 | var el = document.getElementById('scr-large');
96 | var src = el.getAttribute('src');
97 | var pic = src.match(/scr\d/)[0];
98 | var ix = screenshots.indexOf(pic);
99 | ix = (ix + screenshots.length + (next ? 1 : -1)) % screenshots.length;
100 | src = src.replace(pic, screenshots[ix]);
101 | el.setAttribute('src', src);
102 | each('.screenshot-loader', function(el) {
103 | el.style.display = 'inline-block';
104 | });
105 | }
106 |
107 | function screenshotLoaded() {
108 | each('.screenshot-loader', function(el) {
109 | el.style.display = 'none';
110 | });
111 | }
112 |
113 | function each(sel, fn) {
114 | Array.prototype.forEach.call(document.querySelectorAll(sel), fn);
115 | }
116 |
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var screenshots = ['scr1', 'scr2', 'scr3', 'scr4'];
4 |
5 | document.addEventListener('DOMContentLoaded', function() {
6 | initDownload();
7 | setImages();
8 | });
9 |
10 | function setImages() {
11 | var odd = false;
12 | each('.feature>img', function(el) {
13 | if (odd) {
14 | el.parentNode.insertBefore(el, el.parentNode.firstChild);
15 | }
16 | odd = !odd;
17 | });
18 | }
19 |
20 | function initDownload() {
21 | var os = detectOs();
22 | if (os) {
23 | setDownloadButton(os);
24 | }
25 | }
26 |
27 | function detectOs() {
28 | var platform = navigator.platform.toLowerCase();
29 | if (platform.indexOf('mac') >= 0) {
30 | return 'mac';
31 | }
32 | if (platform.indexOf('linux') >= 0) {
33 | return 'linux';
34 | }
35 | if (platform.indexOf('win') >= 0) {
36 | return 'win32';
37 | }
38 | return undefined;
39 | }
40 |
41 | function setDownloadButton(os) {
42 | setDownloadButtonTitle(os);
43 | setLatestReleaseUrl(os);
44 | }
45 |
46 | function setDownloadButtonTitle(os) {
47 | each('.btn-download>.btn-desc', function(el) {
48 | switch (os) {
49 | case 'mac':
50 | el.innerHTML = ' for Mac OS X';
51 | break;
52 | case 'win32':
53 | el.innerHTML = ' for Windows';
54 | break;
55 | case 'linux':
56 | el.innerHTML = ' for Linux';
57 | break;
58 | }
59 | });
60 | each('.btn-sub-link', function(el) {
61 | el.style.display = 'block';
62 | });
63 | }
64 |
65 | function setLatestReleaseUrl(os) {
66 | var xhr = new XMLHttpRequest();
67 | xhr.responseType = 'json';
68 | xhr.addEventListener('load', function() {
69 | releasesLoaded(xhr.response, os)
70 | });
71 | xhr.open('GET', 'https://api.github.com/repos/antelle/keeweb/releases/latest');
72 | xhr.send();
73 | }
74 |
75 | function releasesLoaded(releaseInfo, os) {
76 | var knownAssets = [
77 | 'KeeWeb.linux.x64.deb',
78 | 'KeeWeb.mac.dmg',
79 | 'KeeWeb.win32.exe'
80 | ];
81 | var url;
82 | releaseInfo.assets.forEach(function(asset) {
83 | if (asset.name.indexOf(os) > 0 && knownAssets.indexOf(asset.name) >= 0) {
84 | url = asset.browser_download_url;
85 | }
86 | });
87 | if (url) {
88 | each('.btn-download', function(el) {
89 | el.setAttribute('href', url);
90 | });
91 | }
92 | }
93 |
94 | function rotateScreenshot(next) {
95 | var el = document.getElementById('scr-large');
96 | var src = el.getAttribute('src');
97 | var pic = src.match(/scr\d/)[0];
98 | var ix = screenshots.indexOf(pic);
99 | ix = (ix + screenshots.length + (next ? 1 : -1)) % screenshots.length;
100 | src = src.replace(pic, screenshots[ix]);
101 | el.setAttribute('src', src);
102 | each('.screenshot-loader', function(el) {
103 | el.style.display = 'inline-block';
104 | });
105 | }
106 |
107 | function screenshotLoaded() {
108 | each('.screenshot-loader', function(el) {
109 | el.style.display = 'none';
110 | });
111 | }
112 |
113 | function each(sel, fn) {
114 | Array.prototype.forEach.call(document.querySelectorAll(sel), fn);
115 | }
116 |
--------------------------------------------------------------------------------
/packages/embed/src/client/index.less:
--------------------------------------------------------------------------------
1 | /**
2 | Mditor 公共样式
3 | **/
4 |
5 | @font-face {
6 | font-family: 'RobotoMono';
7 | font-style: normal;
8 | font-weight: 400;
9 | src: url('../assets/fonts/RobotoMono-Regular.ttf') format('truetype');
10 | }
11 |
12 | .mditor {
13 | transition: .05s;
14 | border-radius: 3px;
15 | padding: 38px 0 0 0;
16 | overflow: hidden;
17 | background-color: #fff;
18 | border: 1px solid #ccc;
19 | position: relative;
20 | outline: 0;
21 | &, * {
22 | box-sizing: border-box;
23 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
24 | }
25 | .head {
26 | -webkit-touch-callout: none;
27 | user-select: none;
28 | cursor: default;
29 | outline: 0;
30 | position: absolute;
31 | height: 38px;
32 | left: 0;
33 | top: 0;
34 | width: 100%;
35 | zoom: 1;
36 | margin: 0;
37 | padding: 0px;
38 | border-bottom: 1px solid #CCC;
39 | border-radius: 3px 3px 0 0;
40 | background: #f1f1f1;
41 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4);
42 | background-color: #f3f3f3;
43 | background-image: -moz-linear-gradient(top, #f5f5f5, #efefef);
44 | background-image: -ms-linear-gradient(top, #f5f5f5, #efefef);
45 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#efefef));
46 | background-image: -webkit-linear-gradient(top, #f5f5f5, #efefef);
47 | background-image: -o-linear-gradient(top, #f5f5f5, #efefef);
48 | background-image: linear-gradient(top, #f5f5f5, #efefef);
49 | background-repeat: repeat-x;
50 | }
51 | .body {
52 | margin: 0px;
53 | padding: 0px;
54 | position: relative;
55 | line-height: 0;
56 | font-size: 0;
57 | border-radius: 0 0 3px 3px;
58 | box-shadow: 0 0 4px 0 rgba(0, 0, 0, .1) inset;
59 | height: 100%;
60 | &.active {
61 | border: 1px solid #aaa;
62 | }
63 | }
64 | &.split {
65 | .editor, .viewer {
66 | width: 50%;
67 | float: left;
68 | }
69 | .editor {
70 | border-right: 1px solid #ddd;
71 | }
72 | }
73 | &.preview {
74 | .viewer, {
75 | width: 100%;
76 | }
77 | .editor, .toolbar .item {
78 | display: none;
79 | }
80 | .toolbar .item.control {
81 | display: inline-block;
82 | }
83 | }
84 | &.fullscreen {
85 | position: fixed;
86 | margin: 0px !important;
87 | left: 0px !important;
88 | top: 0px !important;
89 | width: 100% !important;
90 | height: 100% !important;
91 | min-width: 100% !important;
92 | min-height: 100% !important;
93 | max-width: 100% !important;
94 | max-height: 100% !important;
95 | z-index: 999999;
96 | border-radius: 0px;
97 | border: none;
98 | }
99 | &.toolbar-hidden {
100 | .head {
101 | display: none;
102 | }
103 | .body {
104 | border-radius: 3px;
105 | }
106 | }
107 | .textarea, .backdrop, .viewer {
108 | -webkit-font-smoothing: antialiased;
109 | font: 16px/1.6 'RobotoMono', 'PingFang SC', 'Lantinghei SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', '\\5FAE\8F6F\96C5\9ED1', 'STHeitiSC-Light', 'simsun', '\\5B8B\4F53', 'WenQuanYi Zen Hei', 'WenQuanYi Micro Hei', sans-serif;
110 | }
111 | }
112 |
113 | .mditor-hidden {
114 | display: none;
115 | }
116 |
117 | .markdown-body {
118 | &>ul {
119 | list-style-type: initial;
120 | }
121 | &>ol {
122 | list-style-type: decimal;
123 | }
124 | table {
125 | display: table;
126 | }
127 | hr {
128 | height: 2px;
129 | padding: 0;
130 | margin: 24px 0;
131 | background-color: #eaecef;
132 | border: 0;
133 | }
134 | img {
135 | background-color: rgba(255, 255, 255, .1);
136 | }
137 | }
--------------------------------------------------------------------------------
/packages/embed/src/common/parser.js:
--------------------------------------------------------------------------------
1 | const marked = require('marked');
2 | const Prism = require('prismjs');
3 |
4 | //language
5 | require('prismjs/components/prism-java');
6 | require('prismjs/components/prism-csharp');
7 | require('prismjs/components/prism-php');
8 | require('prismjs/components/prism-python');
9 | require('prismjs/components/prism-json');
10 | require('prismjs/components/prism-yaml.min');
11 | require('prismjs/components/prism-perl');
12 | require('prismjs/components/prism-go');
13 | require('prismjs/components/prism-bash');
14 | require('prismjs/components/prism-fsharp');
15 | require('prismjs/components/prism-typescript');
16 | require('prismjs/components/prism-stylus');
17 | require('prismjs/components/prism-less');
18 | require('prismjs/components/prism-sass');
19 | require('prismjs/components/prism-handlebars');
20 | require('prismjs/components/prism-applescript');
21 | require('prismjs/components/prism-actionscript');
22 | require('prismjs/components/prism-aspnet');
23 | require('prismjs/components/prism-basic');
24 | require('prismjs/components/prism-c');
25 | require('prismjs/components/prism-pascal');
26 | require('prismjs/components/prism-vim');
27 | require('prismjs/components/prism-swift');
28 | require('prismjs/components/prism-objectivec');
29 | require('prismjs/components/prism-sql');
30 | require('prismjs/components/prism-scheme');
31 | require('prismjs/components/prism-ruby');
32 | require('prismjs/components/prism-smarty');
33 | require('prismjs/components/prism-smalltalk');
34 | require('prismjs/components/prism-rust');
35 | require('prismjs/components/prism-r');
36 | require('prismjs/components/prism-d');
37 | require('prismjs/components/prism-dart');
38 | require('prismjs/components/prism-coffeescript');
39 | require('prismjs/components/prism-batch');
40 | require('prismjs/components/prism-cpp');
41 | require('prismjs/components/prism-lua');
42 | require('prismjs/components/prism-livescript');
43 | require('prismjs/components/prism-latex');
44 | require('prismjs/components/prism-groovy');
45 | require('prismjs/components/prism-graphql');
46 | require('prismjs/components/prism-nginx');
47 | require('prismjs/components/prism-erlang');
48 | require('prismjs/components/prism-powershell');
49 | require('prismjs/components/prism-makefile');
50 | require('prismjs/components/prism-markdown');
51 |
52 | //alias
53 | Prism.languages.js = Prism.languages.javascript;
54 | Prism.languages['c#'] = Prism.languages.csharp;
55 | Prism.languages['f#'] = Prism.languages.fsharp;
56 | Prism.languages.sh = Prism.languages.bash;
57 | Prism.languages.md = Prism.languages.markdown;
58 | Prism.languages.py = Prism.languages.python;
59 | Prism.languages.yml = Prism.languages.yaml;
60 | Prism.languages.rb = Prism.languages.ruby;
61 |
62 | const Parser = function (options) {
63 | options = options || {};
64 | this.options = options;
65 | };
66 |
67 | Parser.highlights = {};
68 | Parser.marked = marked;
69 | Parser.Prism = Prism;
70 |
71 | //使标题解析 # 号可以无空格
72 | marked.Lexer.rules.gfm.heading = marked.Lexer.rules.heading;
73 | marked.Lexer.rules.tables.heading = marked.Lexer.rules.heading;
74 |
75 | let renderer = new marked.Renderer();
76 | Parser.renderer = renderer;
77 | marked.setOptions({
78 | renderer: renderer, gfm: true, tables: true, breaks: true, //可行尾不加两空格直接换行
79 | pedantic: false,
80 | sanitize: false,
81 | smartLists: true,
82 | smartypants: false,
83 | mangle: false,
84 | highlight: function (code, lang, callback) {
85 | if (Parser.highlights[lang]) {
86 | let result = Parser.highlights[lang].parse(code, lang, callback);
87 | if (!callback)
88 | return result;
89 | } else if (Prism.languages[lang]) {
90 | let result = Prism.highlight(code, Prism.languages[lang]);
91 | if (callback)
92 | return callback(null, result);
93 | else
94 | return result;
95 | } else {
96 | if (callback) //eslint-disable-line
97 | return callback(null, code);
98 | else
99 | return code;
100 | }
101 | }
102 | });
103 |
104 | Parser.prototype.parse = function (mdText, callback) {
105 | return marked(mdText, callback);
106 | };
107 |
108 | module.exports = Parser;
--------------------------------------------------------------------------------
/packages/embed/lib/common/parser.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | var marked = require('marked');
4 | var Prism = require('prismjs');
5 |
6 | //language
7 | require('prismjs/components/prism-java');
8 | require('prismjs/components/prism-csharp');
9 | require('prismjs/components/prism-php');
10 | require('prismjs/components/prism-python');
11 | require('prismjs/components/prism-json');
12 | require('prismjs/components/prism-yaml.min');
13 | require('prismjs/components/prism-perl');
14 | require('prismjs/components/prism-go');
15 | require('prismjs/components/prism-bash');
16 | require('prismjs/components/prism-fsharp');
17 | require('prismjs/components/prism-typescript');
18 | require('prismjs/components/prism-stylus');
19 | require('prismjs/components/prism-less');
20 | require('prismjs/components/prism-sass');
21 | require('prismjs/components/prism-handlebars');
22 | require('prismjs/components/prism-applescript');
23 | require('prismjs/components/prism-actionscript');
24 | require('prismjs/components/prism-aspnet');
25 | require('prismjs/components/prism-basic');
26 | require('prismjs/components/prism-c');
27 | require('prismjs/components/prism-pascal');
28 | require('prismjs/components/prism-vim');
29 | require('prismjs/components/prism-swift');
30 | require('prismjs/components/prism-objectivec');
31 | require('prismjs/components/prism-sql');
32 | require('prismjs/components/prism-scheme');
33 | require('prismjs/components/prism-ruby');
34 | require('prismjs/components/prism-smarty');
35 | require('prismjs/components/prism-smalltalk');
36 | require('prismjs/components/prism-rust');
37 | require('prismjs/components/prism-r');
38 | require('prismjs/components/prism-d');
39 | require('prismjs/components/prism-dart');
40 | require('prismjs/components/prism-coffeescript');
41 | require('prismjs/components/prism-batch');
42 | require('prismjs/components/prism-cpp');
43 | require('prismjs/components/prism-lua');
44 | require('prismjs/components/prism-livescript');
45 | require('prismjs/components/prism-latex');
46 | require('prismjs/components/prism-groovy');
47 | require('prismjs/components/prism-graphql');
48 | require('prismjs/components/prism-nginx');
49 | require('prismjs/components/prism-erlang');
50 | require('prismjs/components/prism-powershell');
51 | require('prismjs/components/prism-makefile');
52 | require('prismjs/components/prism-markdown');
53 |
54 | //alias
55 | Prism.languages.js = Prism.languages.javascript;
56 | Prism.languages['c#'] = Prism.languages.csharp;
57 | Prism.languages['f#'] = Prism.languages.fsharp;
58 | Prism.languages.sh = Prism.languages.bash;
59 | Prism.languages.md = Prism.languages.markdown;
60 | Prism.languages.py = Prism.languages.python;
61 | Prism.languages.yml = Prism.languages.yaml;
62 | Prism.languages.rb = Prism.languages.ruby;
63 |
64 | var Parser = function Parser(options) {
65 | options = options || {};
66 | this.options = options;
67 | };
68 |
69 | Parser.highlights = {};
70 | Parser.marked = marked;
71 | Parser.Prism = Prism;
72 |
73 | //使标题解析 # 号可以无空格
74 | marked.Lexer.rules.gfm.heading = marked.Lexer.rules.heading;
75 | marked.Lexer.rules.tables.heading = marked.Lexer.rules.heading;
76 |
77 | var renderer = new marked.Renderer();
78 | Parser.renderer = renderer;
79 | marked.setOptions({
80 | renderer: renderer, gfm: true, tables: true, breaks: true, //可行尾不加两空格直接换行
81 | pedantic: false,
82 | sanitize: false,
83 | smartLists: true,
84 | smartypants: false,
85 | mangle: false,
86 | highlight: function /*istanbul ignore next*/highlight(code, lang, callback) {
87 | if (Parser.highlights[lang]) {
88 | var result = Parser.highlights[lang].parse(code, lang, callback);
89 | if (!callback) return result;
90 | } else if (Prism.languages[lang]) {
91 | var _result = Prism.highlight(code, Prism.languages[lang]);
92 | if (callback) return callback(null, _result);else return _result;
93 | } else {
94 | if (callback) //eslint-disable-line
95 | return callback(null, code);else return code;
96 | }
97 | }
98 | });
99 |
100 | Parser.prototype.parse = function (mdText, callback) {
101 | return marked(mdText, callback);
102 | };
103 |
104 | module.exports = Parser;
--------------------------------------------------------------------------------
/packages/embed/src/toolbar/items.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | name: 'bold',
3 | title: '粗体',
4 | key: 'shift+alt+b',
5 | handler() {
6 | this.editor.wrapSelectText('**', '**');
7 | }
8 | }, {
9 | name: 'italic',
10 | title: '斜体',
11 | key: 'shift+alt+i',
12 | handler() {
13 | this.editor.wrapSelectText('*', '*');
14 | }
15 | }, {
16 | name: 'underline',
17 | title: '下划线',
18 | key: 'shift+alt+e',
19 | handler() {
20 | this.editor.wrapSelectText('', '');
21 | }
22 | }, {
23 | name: 'strikethrough',
24 | title: '删除线',
25 | key: 'shift+alt+d',
26 | handler() {
27 | this.editor.wrapSelectText('~~', '~~');
28 | }
29 | }, {
30 | name: 'header',
31 | title: '标题',
32 | key: 'shift+alt+1',
33 | handler() {
34 | this.editor.wrapSelectText('# ');
35 | }
36 | }, {
37 | name: 'quote',
38 | icon: 'quote-left',
39 | title: '引用',
40 | key: 'shift+alt+q',
41 | handler() {
42 | let selectText = this.editor.getSelectText();
43 | if (selectText.length < 1) {
44 | this.editor.wrapSelectText('> ');
45 | return;
46 | }
47 | let textArray = selectText.split(this.EOL);
48 | let buffer = [];
49 | textArray.forEach(function (line) {
50 | buffer.push('> ' + line + ' ');
51 | });
52 | this.editor.setSelectText(buffer.join(this.EOL) + this.EOL);
53 | }
54 | }, {
55 | name: 'code',
56 | title: '代码',
57 | key: 'shift+alt+c',
58 | handler() {
59 | let lang = 'js' + this.EOL;
60 | let before = '```' + lang;
61 | let after = '``` ' + this.EOL;
62 | let text = this.editor.getSelectText().trim();
63 | if (text.length > 0) {
64 | text += this.EOL;
65 | }
66 | this.editor.setSelectText(text);
67 | this.editor.wrapSelectText(before, after);
68 | let range = this.editor.getSelectRange();
69 | let start = range.start - lang.length;
70 | let end = range.start - this.EOL.length;
71 | this.editor.setSelectRange(start, end);
72 | }
73 | }, {
74 | name: 'list-ol',
75 | title: '有序列表',
76 | key: 'shift+alt+o',
77 | handler() {
78 | let selectText = this.editor.getSelectText();
79 | if (selectText.length < 1) {
80 | this.editor.wrapSelectText('1. ');
81 | return;
82 | }
83 | let textArray = selectText.split(this.EOL);
84 | let buffer = [];
85 | for (let i = 0; i < textArray.length; i++) {
86 | let line = textArray[i];
87 | buffer.push((i + 1) + '. ' + line);
88 | }
89 | this.editor.setSelectText(buffer.join(this.EOL) + this.EOL);
90 | }
91 | }, {
92 | name: 'list-ul',
93 | title: '无序列表',
94 | key: 'shift+alt+u',
95 | handler() {
96 | let selectText = this.editor.getSelectText();
97 | if (selectText.length < 1) {
98 | this.editor.wrapSelectText('- ');
99 | return;
100 | }
101 | let textArray = selectText.split(this.EOL);
102 | let buffer = [];
103 | textArray.forEach(function (line) {
104 | buffer.push('- ' + line);
105 | });
106 | this.editor.setSelectText(buffer.join(this.EOL) + this.EOL);
107 | }
108 | }, {
109 | name: 'link',
110 | title: '链接',
111 | key: 'shift+alt+l',
112 | handler() {
113 | let text = this.editor.getSelectText();
114 | if (!text || /^(https:|http:|ftp:|file:|mailto:|\/|\.)/i.test(text)) {
115 | this.editor.wrapSelectText('[link](', ')');
116 | if (!text) return;
117 | let range = this.editor.getSelectRange();
118 | let start = range.start - 6;
119 | this.editor.setSelectRange(start, start + 4);
120 | } else {
121 | this.editor.wrapSelectText('[', ']()');
122 | let range = this.editor.getSelectRange();
123 | let index = range.end + 2;
124 | this.editor.setSelectRange(index, index);
125 | }
126 | }
127 | }, {
128 | name: 'table',
129 | title: '表格',
130 | key: 'shift+alt+t',
131 | handler() {
132 | let buffer = [
133 | 'column1 | column2 | column3 ',
134 | '------- | ------- | ------- ',
135 | 'column1 | column2 | column3 ',
136 | 'column1 | column2 | column3 ',
137 | 'column1 | column2 | column3 '
138 | ];
139 | this.editor.wrapSelectText(buffer.join(this.EOL) + this.EOL);
140 | }
141 | }, {
142 | name: 'line',
143 | title: '分隔线',
144 | icon: 'minus',
145 | key: 'shift+alt+h',
146 | handler() {
147 | this.editor.wrapSelectText('----' + this.EOL);
148 | }
149 | }, {
150 | name: 'image',
151 | title: '图片',
152 | key: 'shift+alt+p',
153 | handler() {
154 | this.editor.wrapSelectText('');
155 | }
156 | }, {
157 | name: 'help',
158 | title: '帮助',
159 | icon: 'question',
160 | key: 'shift+alt+/',
161 | handler() {
162 | window.open('http://mditor.com', '_blank');
163 | }
164 | }, {
165 | name: 'toggleFullScreen',
166 | title: '全屏',
167 | icon: 'arrows-alt',
168 | key: 'shift+alt+f',
169 | control: true,
170 | state: 'fullscreen',
171 | owner: function (mditor) {
172 | return mditor.$element;
173 | },
174 | handler() {
175 | this.fullscreen = !this.fullscreen;
176 | }
177 | }, {
178 | name: 'togglePreview',
179 | title: '预览',
180 | icon: 'desktop',
181 | key: 'shift+alt+v',
182 | control: true,
183 | state: 'preview',
184 | owner: function (mditor) {
185 | return mditor.$element;
186 | },
187 | handler() {
188 | this.preview = !this.preview;
189 | if (this.preview) {
190 | this._split = this.split;
191 | this.split = false;
192 | } else {
193 | this.split = this._split;
194 | }
195 | }
196 | }, {
197 | name: 'toggleSplit',
198 | title: '分屏',
199 | icon: 'columns',
200 | key: 'shift+alt+s',
201 | control: true,
202 | state: 'split',
203 | owner: function (mditor) {
204 | return mditor.$element;
205 | },
206 | handler() {
207 | this.split = !this.split;
208 | if (this.split) {
209 | this.preview = false;
210 | }
211 | }
212 | }];
--------------------------------------------------------------------------------
/docs/assets/site.css:
--------------------------------------------------------------------------------
1 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre,
2 | a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp,
3 | small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend,
4 | table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed,
5 | figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary,
6 | time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }
7 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; }
8 | body { line-height: 1; }
9 | ol, ul { list-style: none; }
10 | blockquote, q { quotes: none; }
11 | blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
12 | table { border-collapse: collapse; border-spacing: 0; }
13 | .right { float: right; }
14 | .left { float: left; }
15 | .clear { clear: both; }
16 |
17 | body {
18 | font-family: -apple-system, "BlinkMacSystemFont", "Open Sans", "Raleway", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
19 | font-feature-settings: "liga" 0;
20 | text-align: center;
21 | background: #F5F5F5;
22 | font-weight: 300;
23 | background-image: url("../assets/background.jpg");
24 | background-size: cover;
25 | background-repeat: no-repeat;
26 | }
27 |
28 | #intro {
29 | color: #263C69;
30 | }
31 |
32 | h1 {
33 | font-size: 3em;
34 | padding-top: 10vh;
35 | }
36 | h1>span {
37 | line-height: 65px;
38 | vertical-align: top;
39 | }
40 | h2 {
41 | font-size: 2em;
42 | font-weight: 100;
43 | margin: 1em;
44 | }
45 | h3 {
46 | font-size: 1.5em;
47 | font-weight: 100;
48 | margin-bottom: 1em;
49 | }
50 | hr {
51 | margin: 1.5em 0;
52 | height: 1px;
53 | background: #e3e3e3;
54 | border: none;
55 | }
56 | .logo {
57 | width: 64px;
58 | height: 64px;
59 | }
60 | .buttons-col {
61 | display: inline-block;
62 | vertical-align: top;
63 | }
64 | .btn {
65 | appearance: none;
66 | cursor: pointer;
67 | display: inline-block;
68 | font-size: 1.2em;
69 | line-height: 1;
70 | padding: .6em 1.4em;
71 | margin: 1em 1em .4em;
72 | text-decoration: none;
73 | vertical-align: middle;
74 | white-space: nowrap;
75 | outline: none;
76 | min-width: 80px;
77 | border-radius: 2px;
78 | -webkit-user-select: none;
79 | -moz-user-select: none;
80 | background: #528BFF;
81 | border: 1px solid #4A86FF;
82 | color: #fafafa;
83 | }
84 | .btn.btn-large {
85 | width: 180px;
86 | }
87 | .btn:hover {
88 | background: #4B85FA;
89 | border-color: #417EFA;
90 | color: #fefefe;
91 | box-shadow: 0 0 20px rgba(0, 0, 0, .05);
92 | }
93 | .btn:active {
94 | background: #467EF0;
95 | border-color: #437FF7;
96 | color: #fff;
97 | }
98 | .btn-desc {
99 | font-size: .8rem;
100 | margin-top: .5em;
101 | font-weight: 100;
102 | }
103 | .btn-sub-link {
104 | text-decoration: none;
105 | color: rgb(86, 86, 86);
106 | font-size: .8rem;
107 | display: block;
108 | transition: color 100ms ease-out;
109 | }
110 | .btn-sub-link-platforms {
111 | display: none;
112 | }
113 | .btn-sub-link:hover {
114 | color: #528BFF;
115 | transition: color 100ms ease-in;
116 | }
117 | .screenshots {
118 | max-width: 100vw;
119 | white-space: nowrap;
120 | -webkit-user-select: none;
121 | -moz-user-select: none;
122 | position: relative;
123 | }
124 | .screenshot {
125 | width: 850px;
126 | max-width: 80vw;
127 | position: relative;
128 | vertical-align: middle;
129 | }
130 | .screenshot-loader.fa {
131 | width: 200px;
132 | position:absolute;
133 | left: 0;
134 | right: 0;
135 | top: 50%;
136 | margin: -70px auto 0 auto;
137 | font-size: 120px;
138 | color: rgba(128, 128, 128, .05);
139 | }
140 | .scr-arrow {
141 | vertical-align: middle;
142 | cursor: pointer;
143 | display: inline-block;
144 | }
145 | .scr-arrow:before {
146 | font-size: 4em;
147 | color: #ccc;
148 | }
149 | .scr-arrow:hover:before {
150 | color: #528BFF;
151 | }
152 | .feature {
153 | border-bottom: 1px solid #e3e3e3;
154 | padding: 2em 0;
155 | }
156 | .feature-item {
157 | display: inline-block;
158 | width: 400px;
159 | text-align: left;
160 | vertical-align: top;
161 | margin: .5em 3em;
162 | }
163 | .feature-item>h2 {
164 | margin: 0 0 .8em;
165 | }
166 | .feature-item>p {
167 | line-height: 1.4em;
168 | padding-bottom: 1em;
169 | }
170 | .feature>img {
171 | width: 350px;
172 | border-radius: 3px;
173 | /**box-shadow: 0 0 20px rgba(0, 0, 0, .2);**/
174 | margin: .5em 3em;
175 | }
176 |
177 | @media only screen and (max-width: 510px) {
178 |
179 | .feature-item {
180 | width: 80vw;
181 | margin: .5em 2.5em;
182 | }
183 | .feature>img {
184 | width: 90vw;
185 | margin: .5em 1em;
186 | }
187 | }
188 |
189 | @media screen and (max-width: 945px) {
190 | .feature-item {
191 | text-align: center;
192 | }
193 | }
194 |
195 | @media screen and (min-width: 945px) {
196 | .padding35 {
197 | padding-top: 50px;
198 | }
199 |
200 | .padding50 {
201 | padding-top: 50px;
202 | }
203 |
204 | .padding100 {
205 | padding-top: 100px;
206 | }
207 | }
208 |
209 |
210 | .img-ext {
211 | width: 250px;
212 | opacity: .9;
213 | }
214 | .footer {
215 | color: #999;
216 | font-size: .8em;
217 | margin: 2em;
218 | }
219 | .footer a {
220 | color: #999;
221 | text-decoration: none;
222 | }
223 | .footer a ~ a {
224 | margin-left: 1.5em;
225 | }
226 | .footer a:hover {
227 | color: #528BFF;
228 | }
229 |
230 | .hide {
231 | display: none;
232 | }
233 |
234 | .twitter-follow-button {
235 | position: fixed !important;
236 | top: 10px;
237 | left: 20px;
238 | z-index: 10;
239 | }
--------------------------------------------------------------------------------
/packages/desktop/docs/assets/site.css:
--------------------------------------------------------------------------------
1 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre,
2 | a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp,
3 | small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend,
4 | table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed,
5 | figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary,
6 | time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }
7 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; }
8 | body { line-height: 1; }
9 | ol, ul { list-style: none; }
10 | blockquote, q { quotes: none; }
11 | blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
12 | table { border-collapse: collapse; border-spacing: 0; }
13 | .right { float: right; }
14 | .left { float: left; }
15 | .clear { clear: both; }
16 |
17 | body {
18 | font-family: -apple-system, "BlinkMacSystemFont", "Open Sans", "Raleway", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
19 | font-feature-settings: "liga" 0;
20 | text-align: center;
21 | background: #F5F5F5;
22 | font-weight: 300;
23 | background-image: url("../assets/background.jpg");
24 | background-size: cover;
25 | background-repeat: no-repeat;
26 | }
27 |
28 | #intro {
29 | color: #263C69;
30 | }
31 |
32 | h1 {
33 | font-size: 3em;
34 | padding-top: 10vh;
35 | }
36 | h1>span {
37 | line-height: 65px;
38 | vertical-align: top;
39 | }
40 | h2 {
41 | font-size: 2em;
42 | font-weight: 100;
43 | margin: 1em;
44 | }
45 | h3 {
46 | font-size: 1.5em;
47 | font-weight: 100;
48 | margin-bottom: 1em;
49 | }
50 | hr {
51 | margin: 1.5em 0;
52 | height: 1px;
53 | background: #e3e3e3;
54 | border: none;
55 | }
56 | .logo {
57 | width: 64px;
58 | height: 64px;
59 | }
60 | .buttons-col {
61 | display: inline-block;
62 | vertical-align: top;
63 | }
64 | .btn {
65 | appearance: none;
66 | cursor: pointer;
67 | display: inline-block;
68 | font-size: 1.2em;
69 | line-height: 1;
70 | padding: .6em 1.4em;
71 | margin: 1em 1em .4em;
72 | text-decoration: none;
73 | vertical-align: middle;
74 | white-space: nowrap;
75 | outline: none;
76 | min-width: 80px;
77 | border-radius: 2px;
78 | -webkit-user-select: none;
79 | -moz-user-select: none;
80 | background: #528BFF;
81 | border: 1px solid #4A86FF;
82 | color: #fafafa;
83 | }
84 | .btn.btn-large {
85 | width: 180px;
86 | }
87 | .btn:hover {
88 | background: #4B85FA;
89 | border-color: #417EFA;
90 | color: #fefefe;
91 | box-shadow: 0 0 20px rgba(0, 0, 0, .05);
92 | }
93 | .btn:active {
94 | background: #467EF0;
95 | border-color: #437FF7;
96 | color: #fff;
97 | }
98 | .btn-desc {
99 | font-size: .8rem;
100 | margin-top: .5em;
101 | font-weight: 100;
102 | }
103 | .btn-sub-link {
104 | text-decoration: none;
105 | color: rgb(86, 86, 86);
106 | font-size: .8rem;
107 | display: block;
108 | transition: color 100ms ease-out;
109 | }
110 | .btn-sub-link-platforms {
111 | display: none;
112 | }
113 | .btn-sub-link:hover {
114 | color: #528BFF;
115 | transition: color 100ms ease-in;
116 | }
117 | .screenshots {
118 | max-width: 100vw;
119 | white-space: nowrap;
120 | -webkit-user-select: none;
121 | -moz-user-select: none;
122 | position: relative;
123 | }
124 | .screenshot {
125 | width: 850px;
126 | max-width: 80vw;
127 | position: relative;
128 | vertical-align: middle;
129 | }
130 | .screenshot-loader.fa {
131 | width: 200px;
132 | position:absolute;
133 | left: 0;
134 | right: 0;
135 | top: 50%;
136 | margin: -70px auto 0 auto;
137 | font-size: 120px;
138 | color: rgba(128, 128, 128, .05);
139 | }
140 | .scr-arrow {
141 | vertical-align: middle;
142 | cursor: pointer;
143 | display: inline-block;
144 | }
145 | .scr-arrow:before {
146 | font-size: 4em;
147 | color: #ccc;
148 | }
149 | .scr-arrow:hover:before {
150 | color: #528BFF;
151 | }
152 | .feature {
153 | border-bottom: 1px solid #e3e3e3;
154 | padding: 2em 0;
155 | }
156 | .feature-item {
157 | display: inline-block;
158 | width: 400px;
159 | text-align: left;
160 | vertical-align: top;
161 | margin: .5em 3em;
162 | }
163 | .feature-item>h2 {
164 | margin: 0 0 .8em;
165 | }
166 | .feature-item>p {
167 | line-height: 1.4em;
168 | padding-bottom: 1em;
169 | }
170 | .feature>img {
171 | width: 350px;
172 | border-radius: 3px;
173 | /**box-shadow: 0 0 20px rgba(0, 0, 0, .2);**/
174 | margin: .5em 3em;
175 | }
176 |
177 | @media only screen and (max-width: 510px) {
178 |
179 | .feature-item {
180 | width: 80vw;
181 | margin: .5em 2.5em;
182 | }
183 | .feature>img {
184 | width: 90vw;
185 | margin: .5em 1em;
186 | }
187 | }
188 |
189 | @media screen and (max-width: 945px) {
190 | .feature-item {
191 | text-align: center;
192 | }
193 | }
194 |
195 | @media screen and (min-width: 945px) {
196 | .padding35 {
197 | padding-top: 50px;
198 | }
199 |
200 | .padding50 {
201 | padding-top: 50px;
202 | }
203 |
204 | .padding100 {
205 | padding-top: 100px;
206 | }
207 | }
208 |
209 |
210 | .img-ext {
211 | width: 250px;
212 | opacity: .9;
213 | }
214 | .footer {
215 | color: #999;
216 | font-size: .8em;
217 | margin: 2em;
218 | }
219 | .footer a {
220 | color: #999;
221 | text-decoration: none;
222 | }
223 | .footer a ~ a {
224 | margin-left: 1.5em;
225 | }
226 | .footer a:hover {
227 | color: #528BFF;
228 | }
229 |
230 | .hide {
231 | display: none;
232 | }
233 |
234 | .twitter-follow-button {
235 | position: fixed !important;
236 | top: 10px;
237 | left: 20px;
238 | z-index: 10;
239 | }
--------------------------------------------------------------------------------
/packages/desktop/src/window/index.js:
--------------------------------------------------------------------------------
1 | require('./index.less');
2 |
3 | const mokit = require('mokit');
4 | const Mditor = require('mditor/src/client');
5 | const drapable = require('./drapable');
6 | const ipcRenderer = nodeRequire('electron').ipcRenderer;
7 | const pkg = require('../../package');
8 | const UMLParser = require('../uml');
9 | const utils = require('ntils');
10 | const blobToBase64 = require('../common/blob2buffer');
11 |
12 | //初始处理
13 | drapable(document.body);
14 | window.open = function (url) {
15 | remote.shell.openExternal(url);
16 | };
17 |
18 | const baseElement = document.querySelector('base');
19 |
20 | //插件或语法扩展
21 | let languages = Mditor.Parser.Prism.languages;
22 | let highlights = Mditor.Parser.highlights;
23 | highlights['uml'] = new UMLParser();
24 | languages['editor'] = languages['yaml'];
25 | languages['shortcut'] = languages['yaml'];
26 | languages['slide'] = languages['yaml'];
27 |
28 | //context
29 | const ctx = window.ctx = mokit({
30 | element: document.body,
31 | components: {
32 | Mditor
33 | },
34 |
35 | /**
36 | * 组件就续时
37 | * @returns {void} 无返回
38 | */
39 | onReady() {
40 | this.currentWindow = remote.getCurrentWindow();
41 | this.mditor.removeCommand('toggleFullScreen');
42 | this.overrideToolbar();
43 | this.applyPreference(remote.getGlobal('preference'));
44 | this.applyLocale(remote.getGlobal('locale'));
45 | },
46 |
47 | /**
48 | * 在右击时弹出内容菜单
49 | * @param {object} event 事件对象
50 | * @returns {void} 无返回
51 | */
52 | onContextMenu(event) {
53 | if (event.target != this.mditor.editor.textarea) return;
54 | ipcRenderer.send('contextmenu');
55 | },
56 |
57 | /**
58 | * 重写帮助按钮
59 | * @returns {void} 无返回
60 | */
61 | overrideToolbar() {
62 | //帮助按钮
63 | let helpBtn = this.mditor.toolbar.getItem('help');
64 | helpBtn.handler = () => {
65 | remote.shell.openExternal(pkg.homepage);
66 | };
67 | //图片按钮
68 | let imgBtn = this.mditor.toolbar.getItem('image');
69 | imgBtn.handler = () => {
70 | remote.dialog.showOpenDialog(this.currentWindow, {
71 | filters: [{
72 | name: 'Images',
73 | extensions: ['png', 'jpg', 'jpeg', 'gif']
74 | }],
75 | properties: ['openFile', 'multiSelections']
76 | }, this.insertImage.bind(this));
77 | };
78 | },
79 |
80 | insertImage(filenames) {
81 | if (!filenames) return;
82 | if (!utils.isArray(filenames)) {
83 | filenames = [filenames];
84 | }
85 | filenames = filenames.filter(item => !!item);
86 | if (!filenames || filenames.length < 1) return;
87 | let text = filenames.map(filename => {
88 | return ``;
89 | }).join(this.mditor.EOL);
90 | this.mditor.editor.insertBeforeText(text);
91 | },
92 |
93 | openFile(filename) {
94 | ipcRenderer.send('open-file', {
95 | filename: filename,
96 | windowId: this.currentWindow.id
97 | });
98 | },
99 |
100 | onChanged() {
101 | ipcRenderer.send('content-changed', {
102 | filename: ctx.filename,
103 | windowId: this.currentWindow.id
104 | });
105 | },
106 |
107 | async onPaste(event) {
108 | let items = [].slice.call(event.clipboardData.items);
109 | let imageItems = items.filter(item => {
110 | return item.type.startsWith('image/');
111 | }).map(item => ({
112 | type: item.type,
113 | file: item.getAsFile()
114 | }));
115 | if (imageItems.length < 1) return;
116 | event.preventDefault();
117 | await Promise.all(imageItems.map(item => {
118 | return blobToBase64(item.file).then(content => {
119 | item.content = content;
120 | });
121 | }));
122 | imageItems.forEach(image => {
123 | ipcRenderer.send('save-image', {
124 | type: image.type,
125 | content: image.content
126 | });
127 | });
128 | },
129 |
130 | toggleMaximize() {
131 | if (this.currentWindow.isMaximized()) {
132 | this.currentWindow.unmaximize();
133 | } else {
134 | this.currentWindow.maximize();
135 | }
136 | },
137 |
138 | applyPreference(preference) {
139 | if (!preference) return;
140 | this.applyEditorPreference(preference.editor);
141 | this.applyShortcutPreference(preference.shortcut);
142 | },
143 |
144 | applyEditorPreference(configs) {
145 | configs = configs || {};
146 | if (!utils.isNumber(configs.tab)) configs.tab = 2;
147 | if (configs.tab < 1) {
148 | this.mditor.INDENT = '\t';
149 | } else {
150 | this.mditor.INDENT = new Array(configs.tab).fill(' ').join('');
151 | }
152 | this.mditor.editor.textarea.style.color = configs.color || '';
153 | this.mditor.editor.$element.style.backgroundColor = configs.backgroundColor || '';
154 | },
155 |
156 | applyShortcutPreference(configs) {
157 | if (!configs) return;
158 | utils.each(configs, (cmd, key) => {
159 | if (!key || !cmd) return;
160 | this.mditor.shortcut.unbind(key);
161 | this.mditor.shortcut.bind(key, cmd);
162 | });
163 | },
164 |
165 | applyLocale(locale) {
166 | this.mditor.viewer.alert = locale.previewArea;
167 | this.mditor.toolbar.items.forEach(item => {
168 | let name = item.name.replace(/\-([a-z]{1})/ig, $1 => $1.slice(1).toUpperCase());
169 | item.title = locale[name];
170 | });
171 | }
172 |
173 | }).start();
174 |
175 | //在收到文件内容时
176 | ipcRenderer.on('file', function (event, info) {
177 | document.title = info.filename;
178 | baseElement.href = info.filename;
179 | ctx.filename = info.filename;
180 | ctx.mditor.value = info.content;
181 | ctx.mditor.editor.stack.init({
182 | value: info.content
183 | });
184 | });
185 |
186 | //在收到执行命令时
187 | ipcRenderer.on('command', function (event, info) {
188 | ctx.mditor.execCommand(info.name);
189 | });
190 |
191 | //在收到偏好设置时
192 | ipcRenderer.on('preference', function (event, preference) {
193 | ctx.applyPreference(preference);
194 | });
195 |
196 | //在收到国际化设置时
197 | ipcRenderer.on('locale', function (event, locale) {
198 | ctx.applyLocale(locale);
199 | });
200 |
201 | //在收到插入图片时
202 | ipcRenderer.on('image', function (event, info) {
203 | ctx.insertImage(info.filename);
204 | });
--------------------------------------------------------------------------------
/packages/embed/src/client/index.js:
--------------------------------------------------------------------------------
1 | const mokit = require('mokit');
2 | const Toolbar = require('../toolbar');
3 | const Editor = require('../editor');
4 | const Viewer = require('../viewer');
5 | const Finder = require('../finder');
6 | const Shortcut = require('./shortcut');
7 | const Parser = require('../common/parser');
8 |
9 | require('font-awesome/css/font-awesome.css');
10 | require('github-markdown-css/github-markdown.css');
11 | require('prismjs/themes/prism.css');
12 | require('./index.less');
13 |
14 | const HIDDEN_CLASS_NAME = 'mditor-hidden';
15 |
16 | const Mditor = new mokit.Component({
17 | template: require('./index.html'),
18 |
19 | onInit() {
20 | this.PLATFORM = navigator.platform.toLowerCase();
21 | this.EOL = this.PLATFORM == 'win32' ? '\r\n' : '\n';
22 | this.CMD = this.PLATFORM.indexOf('mac') > -1 ? 'command' : 'ctrl';
23 | this.INDENT = ' ';
24 | this.shortcut = new Shortcut(this);
25 | this.Parser = Parser;
26 | this.parser = new Parser(this);
27 | },
28 |
29 | onReady() {
30 | this.shortcut.bind('tab', this.editor.addIndent.bind(this.editor));
31 | this.shortcut.bind('shift+tab', this.editor.removeIndent.bind(this.editor));
32 | this.shortcut.bind('enter', (event) => {
33 | this._ulAndQuoteAutoComplete(event);
34 | this._olAutoComplete(event);
35 | this._keepIndent(event);
36 | }, true);
37 | setTimeout(() => {
38 | this.$emit('ready');
39 | }, 0);
40 | },
41 |
42 | components: {
43 | Toolbar,
44 | Editor,
45 | Viewer,
46 | Finder
47 | },
48 |
49 | props: {
50 | height: '400px',
51 | width: 'auto',
52 | preview: false,
53 | split: true,
54 | fullscreen: false
55 | },
56 |
57 | data() {
58 | return {
59 | self: this,
60 | value: ''
61 | };
62 | },
63 |
64 | find(text) {
65 | this.finder.show(text);
66 | },
67 |
68 | syncScroll() {
69 | if (!this.split || this.preview) return;
70 | let offsetHeight = this.editor.textarea.offsetHeight;
71 | let editorScrollHeight = this.editor.textarea.scrollHeight;
72 | let viewerScrollHeight = this.viewer.$element.scrollHeight;
73 | let editorScrollTop = this.editor.textarea.scrollTop;
74 | let viewerScrollTop = editorScrollTop * (viewerScrollHeight - offsetHeight) / (editorScrollHeight - offsetHeight);
75 | this.viewer.$element.scrollTop = viewerScrollTop;
76 | },
77 |
78 | onChanged(event) {
79 | this.$emit('changed', event);
80 | this.syncScroll();
81 | },
82 |
83 | onInput(event) {
84 | this.$emit('input', event);
85 | },
86 |
87 | onPaste(event) {
88 | this.$emit('paste', event);
89 | this.syncScroll();
90 | },
91 |
92 | onHeadDblClick(event) {
93 | if (event.target.tagName == 'I') return;
94 | this.$emit('head-dblclick', event);
95 | },
96 |
97 | _keepIndent(event) {
98 | let text = this.editor.getBeforeTextInLine();
99 | let parts = text.split(this.INDENT);
100 | if (parts.length < 2) return;
101 | let count = 0;
102 | let buffer = [this.EOL];
103 | while (parts[count] === '' &&
104 | count < (parts.length - 1)) {
105 | count++;
106 | buffer.push(this.INDENT);
107 | }
108 | this.editor.insertBeforeText(buffer.join(''));
109 | event.preventDefault();
110 | },
111 |
112 | _ulAndQuoteAutoComplete(event) {
113 | let text = this.editor.getBeforeTextInLine();
114 | let prefix = text.substr(0, 2);
115 | if (prefix != '- ' && prefix != '* ' && prefix != '> ') return;
116 | if (text.length > prefix.length) {
117 | this.editor.insertBeforeText(this.EOL + prefix);
118 | } else {
119 | this.editor.selectBeforeText(prefix.length);
120 | this.editor.setSelectText('');
121 | }
122 | event.preventDefault();
123 | },
124 |
125 | _olAutoComplete(event) {
126 | let exp = /^\d+\./;
127 | let text = this.editor.getBeforeTextInLine();
128 | let trimedText = text.trim();
129 | if (!exp.test(trimedText)) return;
130 | let num = trimedText.split('.')[0];
131 | if (trimedText.length > num.length + 1) {
132 | this.editor.insertBeforeText(this.EOL + (parseInt(num) + 1) + '. ');
133 | } else {
134 | this.editor.selectBeforeText(text.length);
135 | this.editor.setSelectText('');
136 | }
137 | event.preventDefault();
138 | },
139 |
140 | focus() {
141 | if (this.preview) {
142 | this.$element.focus();
143 | } else {
144 | this.editor.focus();
145 | }
146 | },
147 |
148 | blur() {
149 | this.editor.blur();
150 | },
151 |
152 | addCommand(item) {
153 | if (!item.name || !item.handler) return;
154 | this.commands = this.commands || {};
155 | this.commands[item.name] = item;
156 | if (item.key) {
157 | this.shortcut.bind(item.key, item.name, item.allowDefault, item.owner);
158 | }
159 | },
160 |
161 | removeCommand(name) {
162 | this.commands = this.commands || {};
163 | let item = this.commands[name];
164 | if (!item) return;
165 | this.shortcut.unbind(item.key);
166 | this.commands[name] = null;
167 | delete this.commands[name];
168 | },
169 |
170 | execCommand(name, event) {
171 | event = event || {};
172 | event.mditor = this;
173 | event.toolbar = this.toolbar;
174 | event.editor = this.editor;
175 | this.commands[name].handler.call(this, event);
176 | }
177 |
178 | });
179 |
180 | Mditor.fromTextarea = function (textarea) {
181 | textarea.classList.add(HIDDEN_CLASS_NAME);
182 | let mditor = new Mditor();
183 | mditor.value = textarea.value;
184 | mditor.$watch('value', () => {
185 | textarea.value = mditor.value;
186 | });
187 | mditor.$mount(textarea);
188 | mditor.switchTextarea = function () {
189 | if (textarea.classList.contains(HIDDEN_CLASS_NAME)) {
190 | textarea.value = mditor.value;
191 | mditor.$element.classList.add(HIDDEN_CLASS_NAME);
192 | textarea.classList.remove(HIDDEN_CLASS_NAME);
193 | } else {
194 | mditor.value = textarea.value;
195 | textarea.classList.add(HIDDEN_CLASS_NAME);
196 | mditor.$element.classList.remove(HIDDEN_CLASS_NAME);
197 | }
198 | };
199 | return mditor;
200 | };
201 |
202 | Mditor.Parser = Parser;
203 |
204 | module.exports = window.Mditor = Mditor;
--------------------------------------------------------------------------------
/packages/embed/lib/toolbar/items.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | module.exports = [{
4 | name: 'bold',
5 | title: '粗体',
6 | key: 'shift+alt+b',
7 | /*istanbul ignore next*/handler: function handler() {
8 | this.editor.wrapSelectText('**', '**');
9 | }
10 | }, {
11 | name: 'italic',
12 | title: '斜体',
13 | key: 'shift+alt+i',
14 | /*istanbul ignore next*/handler: function handler() {
15 | this.editor.wrapSelectText('*', '*');
16 | }
17 | }, {
18 | name: 'underline',
19 | title: '下划线',
20 | key: 'shift+alt+e',
21 | /*istanbul ignore next*/handler: function handler() {
22 | this.editor.wrapSelectText('', '');
23 | }
24 | }, {
25 | name: 'strikethrough',
26 | title: '删除线',
27 | key: 'shift+alt+d',
28 | /*istanbul ignore next*/handler: function handler() {
29 | this.editor.wrapSelectText('~~', '~~');
30 | }
31 | }, {
32 | name: 'header',
33 | title: '标题',
34 | key: 'shift+alt+1',
35 | /*istanbul ignore next*/handler: function handler() {
36 | this.editor.wrapSelectText('# ');
37 | }
38 | }, {
39 | name: 'quote',
40 | icon: 'quote-left',
41 | title: '引用',
42 | key: 'shift+alt+q',
43 | /*istanbul ignore next*/handler: function handler() {
44 | var selectText = this.editor.getSelectText();
45 | if (selectText.length < 1) {
46 | this.editor.wrapSelectText('> ');
47 | return;
48 | }
49 | var textArray = selectText.split(this.EOL);
50 | var buffer = [];
51 | textArray.forEach(function (line) {
52 | buffer.push('> ' + line + ' ');
53 | });
54 | this.editor.setSelectText(buffer.join(this.EOL) + this.EOL);
55 | }
56 | }, {
57 | name: 'code',
58 | title: '代码',
59 | key: 'shift+alt+c',
60 | /*istanbul ignore next*/handler: function handler() {
61 | var lang = 'js' + this.EOL;
62 | var before = '```' + lang;
63 | var after = '``` ' + this.EOL;
64 | var text = this.editor.getSelectText().trim();
65 | if (text.length > 0) {
66 | text += this.EOL;
67 | }
68 | this.editor.setSelectText(text);
69 | this.editor.wrapSelectText(before, after);
70 | var range = this.editor.getSelectRange();
71 | var start = range.start - lang.length;
72 | var end = range.start - this.EOL.length;
73 | this.editor.setSelectRange(start, end);
74 | }
75 | }, {
76 | name: 'list-ol',
77 | title: '有序列表',
78 | key: 'shift+alt+o',
79 | /*istanbul ignore next*/handler: function handler() {
80 | var selectText = this.editor.getSelectText();
81 | if (selectText.length < 1) {
82 | this.editor.wrapSelectText('1. ');
83 | return;
84 | }
85 | var textArray = selectText.split(this.EOL);
86 | var buffer = [];
87 | for (var i = 0; i < textArray.length; i++) {
88 | var line = textArray[i];
89 | buffer.push(i + 1 + '. ' + line);
90 | }
91 | this.editor.setSelectText(buffer.join(this.EOL) + this.EOL);
92 | }
93 | }, {
94 | name: 'list-ul',
95 | title: '无序列表',
96 | key: 'shift+alt+u',
97 | /*istanbul ignore next*/handler: function handler() {
98 | var selectText = this.editor.getSelectText();
99 | if (selectText.length < 1) {
100 | this.editor.wrapSelectText('- ');
101 | return;
102 | }
103 | var textArray = selectText.split(this.EOL);
104 | var buffer = [];
105 | textArray.forEach(function (line) {
106 | buffer.push('- ' + line);
107 | });
108 | this.editor.setSelectText(buffer.join(this.EOL) + this.EOL);
109 | }
110 | }, {
111 | name: 'link',
112 | title: '链接',
113 | key: 'shift+alt+l',
114 | /*istanbul ignore next*/handler: function handler() {
115 | var text = this.editor.getSelectText();
116 | if (!text || /^(https:|http:|ftp:|file:|mailto:|\/|\.)/i.test(text)) {
117 | this.editor.wrapSelectText('[link](', ')');
118 | if (!text) return;
119 | var range = this.editor.getSelectRange();
120 | var start = range.start - 6;
121 | this.editor.setSelectRange(start, start + 4);
122 | } else {
123 | this.editor.wrapSelectText('[', ']()');
124 | var _range = this.editor.getSelectRange();
125 | var index = _range.end + 2;
126 | this.editor.setSelectRange(index, index);
127 | }
128 | }
129 | }, {
130 | name: 'table',
131 | title: '表格',
132 | key: 'shift+alt+t',
133 | /*istanbul ignore next*/handler: function handler() {
134 | var buffer = ['column1 | column2 | column3 ', '------- | ------- | ------- ', 'column1 | column2 | column3 ', 'column1 | column2 | column3 ', 'column1 | column2 | column3 '];
135 | this.editor.wrapSelectText(buffer.join(this.EOL) + this.EOL);
136 | }
137 | }, {
138 | name: 'line',
139 | title: '分隔线',
140 | icon: 'minus',
141 | key: 'shift+alt+h',
142 | /*istanbul ignore next*/handler: function handler() {
143 | this.editor.wrapSelectText('----' + this.EOL);
144 | }
145 | }, {
146 | name: 'image',
147 | title: '图片',
148 | key: 'shift+alt+p',
149 | /*istanbul ignore next*/handler: function handler() {
150 | this.editor.wrapSelectText('');
151 | }
152 | }, {
153 | name: 'help',
154 | title: '帮助',
155 | icon: 'question',
156 | key: 'shift+alt+/',
157 | /*istanbul ignore next*/handler: function handler() {
158 | window.open('http://mditor.com', '_blank');
159 | }
160 | }, {
161 | name: 'toggleFullScreen',
162 | title: '全屏',
163 | icon: 'arrows-alt',
164 | key: 'shift+alt+f',
165 | control: true,
166 | state: 'fullscreen',
167 | owner: function /*istanbul ignore next*/owner(mditor) {
168 | return mditor.$element;
169 | },
170 | /*istanbul ignore next*/handler: function handler() {
171 | this.fullscreen = !this.fullscreen;
172 | }
173 | }, {
174 | name: 'togglePreview',
175 | title: '预览',
176 | icon: 'desktop',
177 | key: 'shift+alt+v',
178 | control: true,
179 | state: 'preview',
180 | owner: function /*istanbul ignore next*/owner(mditor) {
181 | return mditor.$element;
182 | },
183 | /*istanbul ignore next*/handler: function handler() {
184 | this.preview = !this.preview;
185 | if (this.preview) {
186 | this._split = this.split;
187 | this.split = false;
188 | } else {
189 | this.split = this._split;
190 | }
191 | }
192 | }, {
193 | name: 'toggleSplit',
194 | title: '分屏',
195 | icon: 'columns',
196 | key: 'shift+alt+s',
197 | control: true,
198 | state: 'split',
199 | owner: function /*istanbul ignore next*/owner(mditor) {
200 | return mditor.$element;
201 | },
202 | /*istanbul ignore next*/handler: function handler() {
203 | this.split = !this.split;
204 | if (this.split) {
205 | this.preview = false;
206 | }
207 | }
208 | }];
--------------------------------------------------------------------------------
/packages/embed/lib/client/index.js:
--------------------------------------------------------------------------------
1 | /*istanbul ignore next*/'use strict';
2 |
3 | var mokit = require('mokit');
4 | var Toolbar = require('../toolbar');
5 | var Editor = require('../editor');
6 | var Viewer = require('../viewer');
7 | var Finder = require('../finder');
8 | var Shortcut = require('./shortcut');
9 | var Parser = require('../common/parser');
10 |
11 | require('font-awesome/css/font-awesome.css');
12 | require('github-markdown-css/github-markdown.css');
13 | require('prismjs/themes/prism.css');
14 | require('./index.less');
15 |
16 | var HIDDEN_CLASS_NAME = 'mditor-hidden';
17 |
18 | var Mditor = new mokit.Component({
19 | template: require('./index.html'),
20 |
21 | /*istanbul ignore next*/onInit: function onInit() {
22 | this.PLATFORM = navigator.platform.toLowerCase();
23 | this.EOL = this.PLATFORM == 'win32' ? '\r\n' : '\n';
24 | this.CMD = this.PLATFORM.indexOf('mac') > -1 ? 'command' : 'ctrl';
25 | this.INDENT = ' ';
26 | this.shortcut = new Shortcut(this);
27 | this.Parser = Parser;
28 | this.parser = new Parser(this);
29 | },
30 | /*istanbul ignore next*/onReady: function onReady() {
31 | /*istanbul ignore next*/var _this = this;
32 |
33 | this.shortcut.bind('tab', this.editor.addIndent.bind(this.editor));
34 | this.shortcut.bind('shift+tab', this.editor.removeIndent.bind(this.editor));
35 | this.shortcut.bind('enter', function (event) {
36 | /*istanbul ignore next*/_this._ulAndQuoteAutoComplete(event);
37 | /*istanbul ignore next*/_this._olAutoComplete(event);
38 | /*istanbul ignore next*/_this._keepIndent(event);
39 | }, true);
40 | setTimeout(function () {
41 | /*istanbul ignore next*/_this.$emit('ready');
42 | }, 0);
43 | },
44 |
45 |
46 | components: {
47 | Toolbar: Toolbar,
48 | Editor: Editor,
49 | Viewer: Viewer,
50 | Finder: Finder
51 | },
52 |
53 | props: {
54 | height: '400px',
55 | width: 'auto',
56 | preview: false,
57 | split: true,
58 | fullscreen: false
59 | },
60 |
61 | /*istanbul ignore next*/data: function data() {
62 | return {
63 | self: this,
64 | value: ''
65 | };
66 | },
67 | /*istanbul ignore next*/find: function find(text) {
68 | this.finder.show(text);
69 | },
70 | /*istanbul ignore next*/syncScroll: function syncScroll() {
71 | if (!this.split || this.preview) return;
72 | var offsetHeight = this.editor.textarea.offsetHeight;
73 | var editorScrollHeight = this.editor.textarea.scrollHeight;
74 | var viewerScrollHeight = this.viewer.$element.scrollHeight;
75 | var editorScrollTop = this.editor.textarea.scrollTop;
76 | var viewerScrollTop = editorScrollTop * (viewerScrollHeight - offsetHeight) / (editorScrollHeight - offsetHeight);
77 | this.viewer.$element.scrollTop = viewerScrollTop;
78 | },
79 | /*istanbul ignore next*/onChanged: function onChanged(event) {
80 | this.$emit('changed', event);
81 | this.syncScroll();
82 | },
83 | /*istanbul ignore next*/onInput: function onInput(event) {
84 | this.$emit('input', event);
85 | },
86 | /*istanbul ignore next*/onPaste: function onPaste(event) {
87 | this.$emit('paste', event);
88 | this.syncScroll();
89 | },
90 | /*istanbul ignore next*/onHeadDblClick: function onHeadDblClick(event) {
91 | if (event.target.tagName == 'I') return;
92 | this.$emit('head-dblclick', event);
93 | },
94 | /*istanbul ignore next*/_keepIndent: function _keepIndent(event) {
95 | var text = this.editor.getBeforeTextInLine();
96 | var parts = text.split(this.INDENT);
97 | if (parts.length < 2) return;
98 | var count = 0;
99 | var buffer = [this.EOL];
100 | while (parts[count] === '' && count < parts.length - 1) {
101 | count++;
102 | buffer.push(this.INDENT);
103 | }
104 | this.editor.insertBeforeText(buffer.join(''));
105 | event.preventDefault();
106 | },
107 | /*istanbul ignore next*/_ulAndQuoteAutoComplete: function _ulAndQuoteAutoComplete(event) {
108 | var text = this.editor.getBeforeTextInLine();
109 | var prefix = text.substr(0, 2);
110 | if (prefix != '- ' && prefix != '* ' && prefix != '> ') return;
111 | if (text.length > prefix.length) {
112 | this.editor.insertBeforeText(this.EOL + prefix);
113 | } else {
114 | this.editor.selectBeforeText(prefix.length);
115 | this.editor.setSelectText('');
116 | }
117 | event.preventDefault();
118 | },
119 | /*istanbul ignore next*/_olAutoComplete: function _olAutoComplete(event) {
120 | var exp = /^\d+\./;
121 | var text = this.editor.getBeforeTextInLine();
122 | var trimedText = text.trim();
123 | if (!exp.test(trimedText)) return;
124 | var num = trimedText.split('.')[0];
125 | if (trimedText.length > num.length + 1) {
126 | this.editor.insertBeforeText(this.EOL + (parseInt(num) + 1) + '. ');
127 | } else {
128 | this.editor.selectBeforeText(text.length);
129 | this.editor.setSelectText('');
130 | }
131 | event.preventDefault();
132 | },
133 | /*istanbul ignore next*/focus: function focus() {
134 | if (this.preview) {
135 | this.$element.focus();
136 | } else {
137 | this.editor.focus();
138 | }
139 | },
140 | /*istanbul ignore next*/blur: function blur() {
141 | this.editor.blur();
142 | },
143 | /*istanbul ignore next*/addCommand: function addCommand(item) {
144 | if (!item.name || !item.handler) return;
145 | this.commands = this.commands || {};
146 | this.commands[item.name] = item;
147 | if (item.key) {
148 | this.shortcut.bind(item.key, item.name, item.allowDefault, item.owner);
149 | }
150 | },
151 | /*istanbul ignore next*/removeCommand: function removeCommand(name) {
152 | this.commands = this.commands || {};
153 | var item = this.commands[name];
154 | if (!item) return;
155 | this.shortcut.unbind(item.key);
156 | this.commands[name] = null;
157 | delete this.commands[name];
158 | },
159 | /*istanbul ignore next*/execCommand: function execCommand(name, event) {
160 | event = event || {};
161 | event.mditor = this;
162 | event.toolbar = this.toolbar;
163 | event.editor = this.editor;
164 | this.commands[name].handler.call(this, event);
165 | }
166 | });
167 |
168 | Mditor.fromTextarea = function (textarea) {
169 | textarea.classList.add(HIDDEN_CLASS_NAME);
170 | var mditor = new Mditor();
171 | mditor.value = textarea.value;
172 | mditor.$watch('value', function () {
173 | textarea.value = mditor.value;
174 | });
175 | mditor.$mount(textarea);
176 | mditor.switchTextarea = function () {
177 | if (textarea.classList.contains(HIDDEN_CLASS_NAME)) {
178 | textarea.value = mditor.value;
179 | mditor.$element.classList.add(HIDDEN_CLASS_NAME);
180 | textarea.classList.remove(HIDDEN_CLASS_NAME);
181 | } else {
182 | mditor.value = textarea.value;
183 | textarea.classList.add(HIDDEN_CLASS_NAME);
184 | mditor.$element.classList.remove(HIDDEN_CLASS_NAME);
185 | }
186 | };
187 | return mditor;
188 | };
189 |
190 | Mditor.Parser = Parser;
191 |
192 | module.exports = window.Mditor = Mditor;
--------------------------------------------------------------------------------