1 Star 0 Fork 113

feng0428 / thinker-md

forked from 邓海二 / thinker-md 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

logo

Thinker-md是什么

Thinker-md是一个支持markdown的在线文档编辑器,在线演示:http://thinkermd.oschina.mopaas.com/produce.html

Thinker-md的特性

  • 支持Markdown标准和Github风格;
  • 编辑内容实时保存,刷新页面不会丢失;
  • 支持实时预览、图片(跨域)上传;
  • 支持MarkdownToHtml,HtmlToMarkdown双向解析;
  • 支持emoji表情;
  • 支持流程图与序列图;
  • 多语言语法高亮;
  • 可全屏可缩小,全屏编辑体验佳;
  • 国际化支持;
  • 极致的在线代码编写体验

Thinker-md的由来

在开发Team@OSC的过程中,一直在寻找一款好用的Markdown编辑器,纵观所有开源的Markdown编辑器,要么就是外观简陋,要么就是集成繁琐,最终找了一款比较符合要求的产品https://github.com/toopay/bootstrap-markdown ,但由于在使用过程中仍然遇到一些不够完善的地方,于是我们决定自己开发完善一个,并且开源出来,方便大家。

License

The MIT License.

Copyright (c) 2016 OSChina.net

我们正在用

Team@OSC , Git@OSC

1. 开发者指南

1.1 安装Grunt插件

参考: Nodejs 文档 Grunt 中文社区

进入thinker-md根目录,执行如下命令(2016.03.30更新加入了新依赖,请更新后再执行一次):

npm install

1.2 编译

grunt watch

编译后会生成如下目录

dist

----javascript

----|----user

----|----|----thinker-md-user.js

----|----|----thinker-md-user.min.js

----|----|----thinker-md-user.min.map

----|----vendor

----|----|----jquery-2.1.3.js

----|----|----thinker-md.js

----|----|----thinker-md.min.js

----|----|----thinker-md.min.map

----stylesheets

----|----fonts

----|----|----fontawesome-webfont.eot

----|----|----glyphicons-halflings-regular.eot

----|----|----...

----|----img

----|----user

----|----|----thinker-md.user.min.css

----|----vendor

----|----|----thinker-md.min.css

2. 用户指南

thinker-md 依赖jquery库。推荐使用最新版jquery 1.x或者2.x

页面引入

参照/view/index.html和/view/develop.html

  • index.html默认引用编译之后的js和css资源。
  • 如果需要定制thinker-md,你需要按照 开发者指南 步骤执行命令,切换到develop.html。所有资源的修改会自动生成到dist目录下。
  • 推广ES6(ES2015):我们强烈建议您修改bootstrap-markdown-es6.js而非bootstrap-markdown.js,您可以在里面使用ES6标准的JavaScript来进行编码。代码将被编译为ES5标准代码的bootstrap-markdown.js,因此您无需担心兼容性问题。(了解ES6)

3. 使用

3.1 使用案例

<!DOCTYPE html>
<html>
<head lang="zh">
    <meta charset="UTF-8">
    <title>Thinker-md</title>
</head>
<body>
    <textarea id="md" data-provide="markdown"></textarea>
<link href="../dist/stylesheets/user/thinker-md.user.min.css" rel="stylesheet">
<link href="../dist/stylesheets/vendor/thinker-md.min.css" rel="stylesheet">
<script src="../dist/javascripts/vendor/jquery-2.1.3.js" type="text/javascript"></script>
<script src="../dist/javascripts/vendor/thinker-md.js" type="text/javascript"></script>
<script>
    $("#md").markdown({
    language: 'zh',
    fullscreen: {
        enable: true
    },
    resize:'vertical',
    localStorage:'md',
    imgurl: 'http://192.168.1.142:8080/upload',
    base64url: 'http://192.168.1.142:8080/base64'
});
</script>
</body>
</html>

3.2 配置参数说明

参数名称 类型 说明
autofocus boolean 编辑器初始后是否默认获取焦点。 默认 false
savable boolean 编辑器是否显示并激活保存按钮。 默认 false
hideable boolean 如果设置 true ,编辑器在 blur 事件后自动隐藏。 默认 false
width mixed 编辑器宽度。 默认 inherit 支持数字类型 (在css充许范围), 或bootstrap样式 (如 span2)
height mixed 编辑器高度。 默认 inherit
resize string 禁用或改变 resize 属性, 可能的值 none,both,horizontal,vertical。 默认 none 如果此属性未被禁止, 用户可以预览时改变编辑器高度。
language string 本地语言设置。 默认 zh
footer mixed 编辑器底部栏. 可能的值 string,callback。 默认为空
fullscreen object enable (boolean):是否启用全屏;debounce (number):全屏状态下由按键触发的解析函数两次执行最小间隔,用来防止快速输入时的卡顿,单位毫秒,默认为0,不限制。
hiddenButtons mixed 按钮名字数组或字符串。 默认为空字符串
disabledButtons mixed 按钮名字数组或字符串。 默认为空字符串
localStorage string HTML5本地存储,全局唯一
imgurl url 图像上传地址
base64url url base64编码格式图像上传地址
flowChart boolean 是否启用流程图、时序图

3.2.1 java版上传代码实现

普通/base64图像上传案例(代码要求jdk8, 可自行修改以适应低版本jdk)

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by 艺 on 16/03/31.
 */
@WebServlet(name = "upload", urlPatterns = "/c/imgUpload", initParams = {@WebInitParam(name = "upload_path", value = "/ImageDir/")})
public class UploadServlet extends javax.servlet.http.HttpServlet {

    @Override
    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.addHeader("Access-Control-Allow-Origin", "*");
        resp.addHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
        resp.addHeader("Access-Control-Allow-Headers", "Cache-Control,X-Requested-With,Content-Type");
        super.doOptions(req,resp);
    }


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.addHeader("Access-Control-Allow-Origin", "*");
        String imageDir = getServletConfig().getInitParameter("upload_path");
        String directory = req.getSession().getServletContext().getRealPath(imageDir);
        StringBuilder path = new StringBuilder(directory);
        path.append(File.separator);

        StringBuffer url = req.getRequestURL();
        String urlBase = url.substring(0, url.indexOf(req.getRequestURI())) + imageDir;

        boolean isMultipart = ServletFileUpload.isMultipartContent(req);
        if (isMultipart) {
            FileItemFactory fileItemFactory = new DiskFileItemFactory();
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
            List<String> imgFileNames = new ArrayList<>();

            try {
                for (FileItem item : servletFileUpload.parseRequest(req)) {
                    if (!item.isFormField()) { // file upload
                        //文件名称
                        String name = item.getName();
                        String fileName = new Date().getTime() + name.substring(name.lastIndexOf('\\') + 1, name.length());

                        //上传文件
                        File file = new File(path + fileName);
                        File dir = file.getParentFile();
                        if (!dir.exists() && !dir.isDirectory()) {
                            dir.mkdir();
                        }
                        item.write(file);

                        imgFileNames.add(fileName);
                    } else if (item.getFieldName().equals("base64Date")) { // base64 upload
                        String fileName = new Date().getTime() + ".png";
                        StringBuilder base64Data = new StringBuilder();
                        Reader reader = new InputStreamReader(item.getInputStream(), "UTF-8");
                        char[] buffer = new char[1024];
                        int read;
                        while ((read = reader.read(buffer)) != -1) {
                            base64Data.append(buffer, 0, read);
                        }
                        reader.close();
                        String base64 = base64Data.toString();
                        if (!"".equals(base64.trim())) {
                            base64 = base64.substring(base64.lastIndexOf(',') + 1);
                            byte[] b = Base64.getDecoder().decode(base64.getBytes());
                            BufferedOutputStream bos;
                            FileOutputStream fos;
                            File file = new File(path + fileName);
                            fos = new FileOutputStream(file);
                            bos = new BufferedOutputStream(fos);
                            bos.write(b);
                            fos.flush();
                            fos.close();
                            bos.flush();
                            bos.close();

                            imgFileNames.add(fileName);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            resp.addHeader("Access-Control-Allow-Origin", "*");
            resp.setContentType("text/json; charset=UTF-8");
            OutputStream outputStream = resp.getOutputStream();
            outputStream.write(imgFileNames.stream()
                    .map(fileName -> (urlBase + fileName))
                    .collect(Collectors.joining("\n"))
                    .getBytes("UTF-8"));

            outputStream.flush();
            outputStream.close();
            return ;
        }
    }
}
The MIT License (MIT) Copyright (c) 2015 成熟的毛毛虫 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

md编辑器,支持Markdown标准,极致的编辑体验,支持草稿保存,全屏编辑 展开 收起
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/fapanda/thinker-md.git
git@gitee.com:fapanda/thinker-md.git
fapanda
thinker-md
thinker-md
master

搜索帮助

14c37bed 8189591 565d56ea 8189591