# heather
**Repository Path**: majingzhen/heather
## Basic Information
- **Project Name**: heather
- **Description**: markdown在线编辑器
- **Primary Language**: JavaScript
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: https://md.qyh.me
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 2
- **Created**: 2019-07-27
- **Last Updated**: 2020-12-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# heather
## 说明
markdown编辑器,特性如下:
1. 支持mermaid图表、katex
2. 自定义工具条|辅助工具条
3. 支持拖曳html|md文件,自动将html转化为markdown
4. 本地存储(localStorage)支持
5. 编辑预览同步滚动
6. 主题设置
7. 支持手机端
8. 离线访问
9. mermaid、katex懒加载
10. 全屏编辑
### 在线demo
https://md.qyh.me
### 源码
https://github.com/mhlx/heather
## 使用
从 https://github.com/mhlx/heather 下载最新的文件
### 引入css
```html
```
### 引入js
```html
```
### 创建编辑器
```javascript
var config = {};
var wrapper = EditorWrapper.create(config);
```
### 完整代码
```html
```
### 其他
1. `codemirror.js` codemirror核心文件 **本地处理过,请勿使用cdn**
2. `md.js` markdown-it **本地处理过,请勿使用cdn**
3. 一个页面只能存在一个`EditorWrapper`实例,创建另一个`EditorWrapper`实例时会自动销毁已经存在的实例
4. 编辑器不会替代任何你页面的html元素,它只会额外创建一些html元素,它始终是全屏的,并且**无法改变**
5. `EditorWrapper`依赖以下html元素(初始化实例时自动创建),请保证ID的唯一性
```html
```
## 配置
| 配置项 | 说明 | 默认值 |
| - | - | - |
| `toolbar_icons` | 配置顶部工具条图标 | [ 'toc','innerBar','backup','new','search','config' ] |
| `backupEnable` | 是否开启备份 | |
| `backup_autoSaveMs` | **当配置backupEnable为true时生效**,当编辑器内容发生变更时,多少毫秒后自动保存编辑器内容 | 500 |
| `innerBar_icons` | 配置辅助工具条的图标 |['heading','bold','italic','quote','strikethrough','link','code','code-block','uncheck','check','table','undo','redo','close'] |
| `render_allowHtml` | 是否允许html标签 | false |
| `render_plugins` | 配置markdown渲染支持的插件 | ['footnote','katex','mermaid','anchor','task-lists','sup','sub','abbr'] |
| `render_beforeRender` | 配置在渲染前元素处理器 | |
| `render_ms` | 当编辑器内容发生变更时,多少毫秒后开始渲染 | 500 |
| `stat_enable` | 是否启用状态条 | true |
| `stat_formatter` | 当启用状态条时,用于获取状态条渲染内容的方法 | |
| `sync_animateMs` | 配置同步滚动时滚动动画时间 | 0 |
| `sync_enable` | 是否启用同步滚动 | |
| `swipe_animateMs` | 预览、编辑、toc切换时动画时间 | 500 |
| `res_mermaid_js` | 指定mermaid文件的加载路径 | js/mermaid.min.js ||
| `res_katex_css` | 指定katex css文件的加载路径 | katex/katex.min.css |
| `res_katex_js` | 指定katex js文件的加载路径 | katex/katex.min.js |
| `res_hljsTheme` | 获取highlightjs主题的路径 | function(theme){return themeCssUrl} |
| `res_editorTheme` | 获取CodeMirror主题的路径 | function(theme){return themeCssUrl} |
| `res_colorpickerCss` | 指定colorpicker css文件路径 | colorpicker/dist/css/bootstrap-colorpicker.min.css |
| `res_colorpickerJs` | 指定colorpicker js文件路径 | colorpicker/dist/js/bootstrap-colorpicker.min.js |
| `renderAllDocEnable` | 代码高亮的同步预览中,由于codemirror只渲染当前视窗,因此会出现不同步的现象,开启这个选项在载入文档时可以消除这个现象,但是在文本量比较大的时候,加载非常缓慢,可以选择关闭 | true |
## 方法
### 编辑器
#### 获取codemirror对象
`wrapper.editor`
#### 获取编辑器内容
`wrapper.getValue()`
#### 设置编辑器内容
`wrapper.setValue(newValue)`
### 获取html内容
`wrapper.getHtml()`
### 渲染内容
`wrapper.doRender(patch)` patch:是否patch更新
### 同步滚动条
`wrapper.doSync()`
### 启用编辑和预览的同步
`wrapper.enableSync()`
### 停用编辑和预览的同步
`wrapper.disableSync()`
### 切换到编辑器页面
`wrapper.toEditor()`
### 切换到TOC页面
`wrapper.toToc()`
### 切换到预览页面
`wrapper.toPreview()`**只在手机端或者全屏模式下有效**
### 顶部工具栏
`wrapper.toolbar`
#### 添加一个图标
`wrapper.toolbar.addIcon(clazz,hander,callback)`
clazz为fontawesome图标的样式,例如`fa fa-file icon`,handler为图标被点击时触发的方法,callback则为图标元素的回调,例如为添加的图标加上id属性:
```javascript
wrapper.toolbar.addIcon(clazz,hander,function(icon){
icon.setAttribute(id,'icon-id');
})
```
##### 额外的图标样式
1. `mobile-hide`在手机端隐藏
2. `pc-hide`在pc端隐藏
3. `nofullscreen`在全屏模式下隐藏
4. `onfullscreen` 只在全屏模式下出现
#### 删除图标
`wrapper.toolbar.removeIcon(function(icon){return bool})`
#### 隐藏
`wrapper.toolbar.hide()`
#### 显示
`wrapper.toolbar.show()`
#### 保持隐藏状态
```javascript
wrapper.toolbar.keepHidden = true;
wrapper.toolbar.hide();
```
### 辅助工具栏
`wrapper.innerBar`
方法同顶部工具条
### 主题
`wrapper.theme`
#### 配置编辑器主题
```javascript
var theme = wrapper.theme;
theme.editor.theme = 'abcdef'
theme.render();
wrapper.saveTheme();
```
#### 配置代码高亮主题
```javascript
var theme = wrapper.theme;
theme.hljs.theme = 'a11y-light'
theme.render();
wrapper.saveTheme();
```
#### 配置顶部工具条颜色
```javascript
var theme = wrapper.theme;
theme.toolbar.color = '#fff'
theme.render();
wrapper.saveTheme();
```
#### 配置辅助工具条颜色
```javascript
var theme = wrapper.theme;
theme.bar.color = '#fff'
theme.render();
wrapper.saveTheme();
```
#### 配置状态条字体颜色
```javascript
var theme = wrapper.theme;
theme.stat.color = '#fff'
theme.render();
wrapper.saveTheme();
```
#### 自定义css
```javascript
var css = '';
wrapper.theme.customCss = css;
wrapper.theme.render();
wrapper.saveTheme();
```
### 执行指令
`wrapper.execCommand(commandName)`
系统内置指令
| 名称 | 说明 | 快捷键_mac| 快捷键_pc|
| - | - | - | - |
| search | 开启\|关闭一个搜索框 | Ctrl S |Alt S|
| emoji | 打开emoji选择框 |
| heading | 打开heading选择框 |Ctrl H |Ctrl H |
| bold | 加粗文本 | Ctrl B |Ctrl B |
| italic | 倾斜文本 |Ctrl I |Ctrl I|
| quote | 引用文本 | Ctrl Q |Ctrl Q |
| strikethrough | 为文本添加删除线 |
| link | 插入超链接 | Ctrl L |Ctrl L |
| codeBlock | 插入代码块 |Shift Cmd B |Alt B|
| code | 插入行内代码 |
| uncheck | 插入待办事项 |Shift Cmd U |Alt U|
| check | 插入已完成待办事项 |Shift Cmd I|Alt I|
| undo | 撤回 |Cmd Z | Ctrl Z|
| redo | 取消撤回 |Cmd Y|Ctrl Y|
| table | 插入表格 | Shift Cmd T |Alt T|
### 新增指令
`EditorWrapper.commands[commandName] = commandHandler`
commandHandler接受一个参数`wrapper`,例如:
新增一个插入图片的指令,并且为该指令绑定`Ctrl+G`的快捷键:
```javascript
EditorWrapper.commands['image'] = function(wrapper){
var editor = wrapper.editor;
var text = editor.getSelection();
if (text == '') {
editor.replaceRange("![]()", editor.getCursor());
editor.focus();
var start_cursor = editor.getCursor();
var cursorLine = start_cursor.line;
var cursorCh = start_cursor.ch;
editor.setCursor({
line: cursorLine,
ch: cursorCh - 1
});
} else {
editor.replaceSelection("![" + text + "]()");
}
}
wrapper.bindKey({'Ctrl-G':'image'});
```
### 快捷键绑定
`wrapper.bindKey(keyMap)`
keyMap对象属性为快捷键名称,例如`Ctrl-A`,属性值可以为string或者一个方法,如果为string类型,那么则会绑定对应名称的命令,如果为方法,则会直接绑定该方法
### 解除快捷键绑定
`wrapper.unbindKey(keyArray)` keyArray为快捷键数组,例如`['Ctrl-A']`
### 全屏编辑
`wrapper.requestFullScreen()` **只在PC端有效**
### 退出全屏
`wrapper.exitFullScreen()` **只在PC端有效**
### 销毁实例
`wrapper.remove()`
### 监听实例销毁
`wrapper.onRemove(fun)`
### 取消监听实例销毁
`wrapper.offRemove(fun)`
## 导出PDF
没有直接导出PDF的方法,但是可以通过以下步骤,让chrome浏览器的打印功能来实现
### 设置打印样式
```html
```
上述html中,`media="print"`的只会在打印时使用,`media="screen"`的则只会在页面渲染时使用,而`media="all"` 则在所有情况下都会使用,请参考 https://www.w3schools.com/tags/att_link_media.asp
### 打印前渲染
mermaid渲染出来的元素大小会根据视窗大小自动调整,由于左右预览的原因,打印出来的大小会跟预期的大小不一致,此时可以通过监听打印事件使得在打印前再次渲染。
```javascript
var wrapper = EditorWrapper.create({});
var beforePrintHandler = function(mql) {
if (mql.matches) {
wrapper.doRender(false);
}
}
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(beforePrintHandler);
}
wrapper.onRemove(function(){
mediaQueryList.removeListener(beforePrintHandler);
});
```
### 强制分页
通过添加以下代码可以让pdf文件强制分页
```html
```
## 支持的浏览器
**只在chrome上做了测试,但应该支持一些其他的现代化浏览器**
## 感谢
1. 采用[codemirror](https://codemirror.net/)作为编辑器
2. 采用[markdown-it](https://github.com/markdown-it/markdown-it)渲染markdown
3. 采用[jquery](https://jquery.com/)简化dom操作
4. 采用[fontawesome](https://fontawesome.com/)美化图标
5. 采用[highlight.js](https://highlightjs.org/)高亮代码
6. 采用[katex](https://katex.org/)渲染数学公式
7. 采用[sweet2alert](https://sweetalert2.github.io/)美化弹出框
8. 采用[mermaid](https://mermaidjs.github.io/)绘制流程图、甘特图和时序图
9. 采用[turndown](https://github.com/domchristie/turndown)将html转化为markdown
10. 采用[morphdom](https://github.com/patrick-steele-idem/morphdom)来patch更新dom