Skip to content

Commit

Permalink
feat: 增加手风琴语法和对应的按钮;fix: 修复换行、列表语法占位符没有行号信息的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
sunsonliu committed Mar 2, 2023
1 parent 318740e commit e21cc35
Show file tree
Hide file tree
Showing 16 changed files with 330 additions and 10 deletions.
38 changes: 38 additions & 0 deletions examples/markdown/basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,44 @@
:::


---

## 手风琴

**说明**
使用连续三个加号`+++`和关键字(`[ + | - ]`)来声明,关键字`+`表示默认收起,关键字`-`表示默认展开
```
++++
点击展开更多
:
内容
+-
默认展开
:
内容
++
默认收起
:
内容
+++
```

**效果**
++++
点击展开更多
:
内容
+-
默认展开
:
内容
++
默认收起
:
内容
+++


---

## 语法高亮
Expand Down
1 change: 1 addition & 0 deletions examples/scripts/index-demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ var basicConfig = {
'ul',
'checklist',
'panel',
'detail',
'|',
'formula',
{
Expand Down
1 change: 1 addition & 0 deletions src/Cherry.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ const defaultConfig = {
'|',
'list',
'panel',
'detail',
{
insert: [
'image',
Expand Down
5 changes: 4 additions & 1 deletion src/Previewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,11 +496,14 @@ export default class Previewer {
continue;
}
}
if (/^(class|id|href|rel|target|src|title|controls|align|width|height|style)$/i.test(name)) {
if (/^(class|id|href|rel|target|src|title|controls|align|width|height|style|open)$/i.test(name)) {
name = name === 'class' ? 'className' : name;
if (name === 'style') {
ret.style = ret.style ? ret.style : [];
ret.style.push(value);
} else if (name === 'open') {
// 只要有open这个属性,就一定是true
ret[name] = true;
} else {
ret[name] = value;
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/HooksConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import HighLight from './hooks/HighLight';
import Suggester from './hooks/Suggester';
import Ruby from './hooks/Ruby';
import Panel from './hooks/Panel';
import Detail from './hooks/Detail';
/**
* 引擎各语法的配置
* 主要决定支持哪些语法,以及各语法的执行顺序
Expand All @@ -71,6 +72,7 @@ const hooksConfig = [
Header, // 处理标题, 传入strict属性严格要求ATX风格标题#后带空格
Hr,
List,
Detail,
Panel,
Paragraph, // 普通段落

Expand Down
4 changes: 2 additions & 2 deletions src/core/hooks/Br.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default class Br extends ParagraphBase {
if (index === 0) {
return match;
}
const lineCount = lines.match(/\n/g).length;
const lineCount = lines.match(/\n/g)?.length ?? 0;
const sign = `br${lineCount}`;
let html = '';
if (isBrowser()) {
Expand All @@ -49,7 +49,7 @@ export default class Br extends ParagraphBase {
// node环境下直接输出br
html = this.classicBr ? '' : '<br/>';
}
const placeHolder = this.pushCache(html, sign);
const placeHolder = this.pushCache(html, sign, lineCount);
// 结尾只补充一个\n是因为Br将下一个段落中间的所有换行都替换掉了,而两个换行符会导致下一个区块行数计算错误
return `\n\n${placeHolder}\n`;
});
Expand Down
110 changes: 110 additions & 0 deletions src/core/hooks/Detail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* Copyright (C) 2021 THL A29 Limited, a Tencent company.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ParagraphBase from '@/core/ParagraphBase';
import { prependLineFeedForParagraph } from '@/utils/lineFeed';
import { getDetailRule } from '@/utils/regexp';
import { blockNames } from '@/utils/sanitize';

/**
* +++(+|-)
* 点击查看详情
* :
* body
* body
* +-
* 标题(默认收起内容)
* :
* 内容
* ++
* 标题(默认展开内容)
* :
* 内容2
* +++
*/
export default class Detail extends ParagraphBase {
static HOOK_NAME = 'detail';

constructor() {
super({ needCache: true });
}

makeHtml(str, sentenceMakeFunc) {
return str.replace(this.RULE.reg, (match, preLines, isShow, content) => {
const lineCount = this.getLineCount(match, preLines);
const sign = this.$engine.md5(match);
const { type, html } = this.$getDetailInfo(isShow, content, sentenceMakeFunc);
const ret = this.pushCache(
`<div class="cherry-detail cherry-detail__${type}" data-sign="${sign}" data-lines="${lineCount}" >${html}</div>`,
sign,
lineCount,
);
return prependLineFeedForParagraph(match, ret);
});
}

$getDetailInfo(isShow, str, sentenceMakeFunc) {
const type = /\n\s*(\+\+|\+-)\s*\n/.test(str) ? 'multiple' : 'single';
const arr = str.split(/\n\s*(\+\+|\+-)\s*\n/);
let defaultShow = isShow !== '+';
let html = '';
if (type === 'multiple') {
arr.forEach((item) => {
if (/(\+\+|\+-)/.test(item)) {
defaultShow = item !== '++';
return true;
}
html += this.$getDetailHtml(defaultShow, item, sentenceMakeFunc);
});
} else {
html = this.$getDetailHtml(defaultShow, str, sentenceMakeFunc);
}
return { type, html };
}

$getDetailHtml(defaultShow, str, sentenceMakeFunc) {
let ret = `<details ${defaultShow ? 'open' : ''}>`;
const paragraphProcessor = (str) => {
if (str.trim() === '') {
return '';
}
// 调用行内语法,获得段落的签名和对应html内容
const { html } = sentenceMakeFunc(str);
let domName = 'p';
// 如果包含html块级标签(比如div、blockquote等),则当前段落外层用div包裹,反之用p包裹
const isContainBlockTest = new RegExp(`<(${blockNames})[^>]*>`, 'i');
if (isContainBlockTest.test(html)) {
domName = 'div';
}
return `<${domName}>${this.$cleanParagraph(html)}</${domName}>`;
};
str.replace(/(^[\w\W]+?)\n\s*:\s*\n([\w\W]+$)/, (match, title, body) => {
ret += `<summary>${sentenceMakeFunc(title).html}</summary>`;
let $body = '';
if (this.isContainsCache(body)) {
$body = this.makeExcludingCached(body, paragraphProcessor);
} else {
$body = paragraphProcessor(body);
}
ret += `<div class="cherry-detail-body">${$body}</div>`;
});
ret += `</details>`;
return ret;
}

rule() {
return getDetailRule();
}
}
13 changes: 11 additions & 2 deletions src/core/hooks/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,23 @@ export default class List extends ParagraphBase {
const text = wholeMatch.replace(/~0$/g, '').replace(/^\n+/, '');
this.buildTree(makeChecklist(text), sentenceMakeFunc);
const result = this.renderTree(0);
return this.pushCache(result, this.sign);
return this.pushCache(result, this.sign, this.$getLineNum(wholeMatch));
}

$getLineNum(str) {
const beginLine = str.match(/^\n\n/)?.length ?? 0;
const $str = str.replace(/^\n+/, '').replace(/\n+$/, '\n');
return $str.match(/\n/g)?.length ?? 0 + beginLine;
}

makeHtml(str, sentenceMakeFunc) {
let $str = `${str}~0`;
if (this.test($str)) {
$str = $str.replace(this.RULE.reg, (wholeMatch) => {
return this.getCacheWithSpace(this.checkCache(wholeMatch, sentenceMakeFunc), wholeMatch);
return this.getCacheWithSpace(
this.checkCache(wholeMatch, sentenceMakeFunc, this.$getLineNum(wholeMatch)),
wholeMatch,
);
});
}
$str = $str.replace(/~0$/g, '');
Expand Down
23 changes: 22 additions & 1 deletion src/core/hooks/Panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import ParagraphBase from '@/core/ParagraphBase';
import { prependLineFeedForParagraph } from '@/utils/lineFeed';
import { getPanelRule } from '@/utils/regexp';
import { blockNames } from '@/utils/sanitize';
/**
* 面板语法
* 例:
Expand Down Expand Up @@ -60,7 +61,27 @@ export default class Panel extends ParagraphBase {
ret.title = `<div class="cherry-panel--title ${ret.title ? 'cherry-panel--title__not-empty' : ''}">${
ret.title
}</div>`;
ret.body = `<div class="cherry-panel--body">${this.$cleanParagraph(sentenceMakeFunc(ret.body).html)}</div>`;
const paragraphProcessor = (str) => {
if (str.trim() === '') {
return '';
}
// 调用行内语法,获得段落的签名和对应html内容
const { html } = sentenceMakeFunc(str);
let domName = 'p';
// 如果包含html块级标签(比如div、blockquote等),则当前段落外层用div包裹,反之用p包裹
const isContainBlockTest = new RegExp(`<(${blockNames})[^>]*>`, 'i');
if (isContainBlockTest.test(html)) {
domName = 'div';
}
return `<${domName}>${this.$cleanParagraph(html)}</${domName}>`;
};
let $body = '';
if (this.isContainsCache(ret.body)) {
$body = this.makeExcludingCached(ret.body, paragraphProcessor);
} else {
$body = paragraphProcessor(ret.body);
}
ret.body = `<div class="cherry-panel--body">${$body}</div>`;
return ret;
}

Expand Down
5 changes: 3 additions & 2 deletions src/locales/zh_CN.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export default {
hide: '隐藏(ctrl+0)', // 隐藏(ctrl+0)
exportToPdf: '导出PDF', // 导出PDF
exportScreenshot: '导出长图', // 导出长图
theme: '主题', // 导出长图
panel: '面板', // 导出长图
theme: '主题', // 主题
panel: '面板', // 面板
detail: '手风琴', // 手风琴
};
32 changes: 32 additions & 0 deletions src/sass/markdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,38 @@ div[data-type='codeBlock'] {
}
}

.cherry-detail {
details {
background: #f8f9faaa;
border-radius: 8px;
overflow: hidden;
margin-bottom: 10px;
summary {
user-select: none;
padding: 5px 10px;
background-color: #6c757d;
color: #FFF;
border-radius: 8px;
}
.cherry-detail-body {
padding: 15px 25px 0 25px;
}
}
}

.cherry-detail__multiple {
border-radius: 8px;
overflow: hidden;
details {
margin-bottom: 1px;
border-radius: 0;
border: none;
summary {
border-radius: 0;
}
}
}

.cherry-panel {
margin: 10px 0;
overflow: hidden;
Expand Down
2 changes: 2 additions & 0 deletions src/toolbars/HookCenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import Theme from './hooks/Theme';
import MobilePreview from './hooks/MobilePreview';
import Copy from './hooks/Copy';
import Panel from './hooks/Panel';
import Detail from './hooks/Detail';

// 定义默认支持的工具栏
// 目前不支持按需动态加载
Expand Down Expand Up @@ -120,6 +121,7 @@ const HookList = {
theme: Theme,
file: File,
panel: Panel,
detail: Detail,
};

export default class HookCenter {
Expand Down
Loading

0 comments on commit e21cc35

Please sign in to comment.