Skip to content

Commit

Permalink
feat: 代码块增加复制功能
Browse files Browse the repository at this point in the history
Fixed: #239
  • Loading branch information
sunsonliu committed Jul 8, 2022
1 parent f21810b commit ac48904
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 6 deletions.
3 changes: 3 additions & 0 deletions examples/scripts/index-demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ var basicConfig = {
},
},
syntax: {
codeBlock: {
theme: 'twilight',
},
table: {
enableChart: false,
// chartEngine: Engine Class
Expand Down
8 changes: 8 additions & 0 deletions src/Cherry.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ const callbacks = {
afterInit: (text, html) => {},
beforeImageMounted: (srcProp, src) => ({ srcProp, src }),
onClickPreview: (event) => {},
onCopyCode: (event, code) => {
// 阻止默认的粘贴事件
// return false;
// 对复制内容进行额外处理
return code;
},
};

/** @type {Partial<import('~types/cherry').CherryOptions>} */
Expand Down Expand Up @@ -218,6 +224,8 @@ const defaultConfig = {
beforeImageMounted: callbacks.beforeImageMounted,
// 预览区域点击事件,previewer.enablePreviewerBubble = true 时生效
onClickPreview: callbacks.onClickPreview,
// 复制代码块代码时的回调
onCopyCode: callbacks.onCopyCode,
},
previewer: {
dom: false,
Expand Down
1 change: 1 addition & 0 deletions src/core/hooks/CodeBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ export default class CodeBlock extends ParagraphBase {
cacheCode = this.renderLineNumber(cacheCode);
}
cacheCode = `<div data-sign="${sign}" data-type="codeBlock" data-lines="${lines}">
<div class="cherry-copy-code-block" style="display:none;"><i class="ch-icon ch-icon-copy" title="copy"></i></div>
<pre class="language-${lang}">${this.wrapCode(cacheCode, lang)}</pre>
</div>`;
return cacheCode;
Expand Down
31 changes: 31 additions & 0 deletions src/sass/cherry.scss
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,37 @@
.cherry-list__square {
list-style: square;
}

div[data-type="codeBlock"]:hover {
.cherry-copy-code-block {
display: block !important;
position: relative;
width: 25px;
text-align: center;
height: 25px;
border: 1px solid #DDD;
cursor: pointer;
float: right;
right: 10px;
top: 15px;
color: #FFF;
border-radius: 5px;
margin-left: -27px;
transition: all 0.3s;
z-index: 1;
}
// 浅色系
[data-code-block-theme='default'] & ,[data-code-block-theme='funky'] & ,[data-code-block-theme='solarized-light'] & ,[data-code-block-theme='coy'] & {
.cherry-copy-code-block {
background-color: #3582fb;
}
}
.cherry-copy-code-block:hover {
color: #3582fb;
background-color: #eee;
border-color: #3582fb;
}
}
}

.cherry-color-wrap {
Expand Down
32 changes: 29 additions & 3 deletions src/toolbars/PreviewerBubble.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,19 @@ export default class PreviewerBubble {
}

$onClick(e) {
// 只有双栏编辑模式才出现该功能
const { target } = e;
// 复制代码块操作不关心编辑器的状态
this.$dealCopyCodeBlock(e);
const cherryStatus = this.previewer.$cherry.getStatus();
// 纯预览模式下,支持点击放大图片功能(以回调的形式实现,需要业务侧实现图片放大功能)
if (cherryStatus.editor === 'hide') {
if (cherryStatus.previewer === 'show') {
// 纯预览模式下,支持点击放大图片功能(以回调的形式实现,需要业务侧实现图片放大功能)
this.previewer.$cherry.options.callback.onClickPreview &&
this.previewer.$cherry.options.callback.onClickPreview(e);
}
return;
}
const { target } = e;
// 只有双栏编辑模式才出现下面的功能
this.$removeAllPreviewerBubbles();
if (typeof target.tagName === 'undefined') {
return;
Expand All @@ -101,6 +103,30 @@ export default class PreviewerBubble {
}
}

/**
* 处理复制代码块的操作
*/
$dealCopyCodeBlock(e) {
const { target } = e;
if (target.className === 'cherry-copy-code-block' || target.parentNode.className === 'cherry-copy-code-block') {
const parentNode =
target.className === 'cherry-copy-code-block' ? target.parentNode : target.parentNode.parentNode;
const codeContent = parentNode.innerText;
const final = this.previewer.$cherry.options.callback.onCopyCode(e, codeContent);
if (final === false) {
return false;
}
const iconNode = parentNode.querySelector('i.ch-icon-copy');
if (iconNode) {
iconNode.className = iconNode.className.replace('copy', 'ok');
setTimeout(() => {
iconNode.className = iconNode.className.replace('ok', 'copy');
}, 1500);
}
return navigator.clipboard.writeText(final);
}
}

/**
* 隐藏预览区域已经激活的工具栏
*/
Expand Down
5 changes: 2 additions & 3 deletions src/toolbars/Toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default class Toolbar {

init() {
this.collectShortcutKey();
this.collectToolbarHandler();
// this.collectToolbarHandler();
}

previewOnly() {
Expand Down Expand Up @@ -99,12 +99,11 @@ export default class Toolbar {
}

collectToolbarHandler() {
this.toolbarHandlers = {};
this.options.extensions.forEach((ext) => {
if (typeof ext.onClick !== 'function') {
return;
}
this.toolbarHandlers[ext.name] = (shortKey, callback) => {
(shortKey, callback) => {
const selections = this.options.editor.editor.getSelections();
const ret = selections.map(
(selection, index, srcArray) => ext.onClick(selection, shortKey, callback) || srcArray[index],
Expand Down
1 change: 1 addition & 0 deletions types/cherry.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface CherryOptions {
/** img 标签挂载前触发,可用于懒加载等场景 */
beforeImageMounted: (srcProp: string, src: string) => { srcProp: string; src: string };
onClickPreview: (e: MouseEvent) => void;
onCopyCode: (e: ClipboardEvent, code: string) => string|false;
};
/** 预览区域配置 */
previewer: CherryPreviewerOptions;
Expand Down

0 comments on commit ac48904

Please sign in to comment.