Skip to content

Commit

Permalink
feat: Tencent#876 窗口浮动
Browse files Browse the repository at this point in the history
  • Loading branch information
Saraph1nes committed Aug 29, 2024
1 parent 7f398cd commit e05091e
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 1 deletion.
1 change: 1 addition & 0 deletions examples/scripts/index-demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ var basicConfig = {
previewer: {
// 自定义markdown预览区域class
// className: 'markdown'
floatWhenClosePreviewer: true,
},
keydown: [],
//extensions: [],
Expand Down
1 change: 1 addition & 0 deletions src/Cherry.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ const defaultConfig = {
className: 'cherry-markdown',
// 是否启用预览区域编辑能力(目前支持编辑图片尺寸、编辑表格内容)
enablePreviewerBubble: true,
floatWhenClosePreviewer: false,
/**
* 配置图片懒加载的逻辑
* - 如果不希望图片懒加载,可配置成 lazyLoadImg = {noLoadImgNum: -1}
Expand Down
85 changes: 84 additions & 1 deletion src/Cherry.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ export default class Cherry extends CherryStatic {
*/
this.options = mergeWith({}, defaultConfigCopy, options, customizer);

this.storageFloatPreviewerWrapData = {
x: 50,
y: 58,
width: 800,
height: 500,
};

this.locales = locales;
if (this.options.locales) {
this.locales = {
Expand Down Expand Up @@ -737,7 +744,7 @@ export default class Cherry extends CherryStatic {
const anchorStyle =
(this.options.engine.syntax.header && this.options.engine.syntax.header.anchorStyle) || 'default';
const autonumberClass = anchorStyle === 'autonumber' ? ' head-num' : '';
const { className, dom, enablePreviewerBubble } = this.options.previewer;
const { className, dom, enablePreviewerBubble, floatWhenClosePreviewer } = this.options.previewer;
const previewerClassName = [
'cherry-previewer cherry-markdown',
className || '',
Expand All @@ -763,12 +770,88 @@ export default class Cherry extends CherryStatic {
value: this.options.value,
isPreviewOnly: this.options.isPreviewOnly,
enablePreviewerBubble,
floatWhenClosePreviewer,
lazyLoadImg: this.options.previewer.lazyLoadImg,
});

return this.previewer;
}

clearFloatPreviewer() {
this.wrapperDom.appendChild(this.previewer.getDom());
this.storageFloatPreviewerWrapData = {
x: this.floatPreviewerWrapDom.offsetLeft,
y: this.floatPreviewerWrapDom.offsetTop,
height: this.floatPreviewerWrapDom.offsetHeight,
width: this.floatPreviewerWrapDom.offsetWidth,
};
this.floatPreviewerWrapDom.remove();
}

/**
* @private
* @returns {import('@/Previewer').default}
*/
createFloatPreviewer() {
const floatPreviewerWrap = createElement('div', 'float-previewer-wrap');
const floatPreviewerHeader = createElement('div', 'float-previewer-header');
const floatPreviewerClose = createElement('div', 'float-previewer-close');
const floatPreviewerTitle = createElement('div', 'float-previewer-title');
floatPreviewerTitle.innerHTML = '预览';
floatPreviewerWrap.style.left = `${this.storageFloatPreviewerWrapData.x}px`;
floatPreviewerWrap.style.top = `${this.storageFloatPreviewerWrapData.y}px`;
floatPreviewerWrap.style.height = `${this.storageFloatPreviewerWrapData.height}px`;
floatPreviewerWrap.style.width = `${this.storageFloatPreviewerWrapData.width}px`;
floatPreviewerHeader.appendChild(floatPreviewerTitle);
floatPreviewerHeader.appendChild(floatPreviewerClose);
floatPreviewerWrap.appendChild(floatPreviewerHeader);
floatPreviewerWrap.appendChild(this.previewer.getDom());
this.floatPreviewerWrapDom = floatPreviewerWrap;
this.wrapperDom.appendChild(floatPreviewerWrap);

const pageWidth = document.body.clientWidth;
const pageHeight = document.body.clientHeight;

let initOffsetX = 0;
let initOffsetY = 0;

document.addEventListener('mousedown', (evt) => {
if (evt.target !== floatPreviewerHeader) return;
evt.preventDefault();
initOffsetX = evt.offsetX;
initOffsetY = evt.offsetY;
floatPreviewerWrap.classList.add('float-previewer-dragging');
});

document.addEventListener('mouseup', (evt) => {
floatPreviewerWrap.classList.remove('float-previewer-dragging');
});

document.addEventListener('mousemove', (evt) => {
if (!floatPreviewerWrap.classList.contains('float-previewer-dragging')) return;
evt.preventDefault();
const { clientX, clientY } = evt;
let newRight = clientX - initOffsetX;
let newTop = clientY - initOffsetY;
if (newRight < 0) {
newRight = 0;
}
if (newTop < 0) {
newTop = 0;
}
if (newRight + floatPreviewerWrap.offsetWidth > pageWidth) {
newRight = pageWidth - floatPreviewerWrap.offsetWidth;
}
if (newTop + floatPreviewerWrap.offsetHeight > pageHeight) {
newTop = pageHeight - floatPreviewerWrap.offsetHeight;
}
requestAnimationFrame(() => {
floatPreviewerWrap.style.left = `${newRight}px`;
floatPreviewerWrap.style.top = `${newTop}px`;
});
});
}

/**
* @private
* @param {import('codemirror').Editor} codemirror
Expand Down
28 changes: 28 additions & 0 deletions src/Previewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export default class Previewer {
minBlockPercentage: 0.2, // editor或previewer所占宽度比例的最小值
value: '',
enablePreviewerBubble: true,
floatWhenClosePreviewer: false, // 是否在关闭预览区时,将预览区浮动
afterUpdateCallBack: [],
isPreviewOnly: false,
previewerCache: {
Expand Down Expand Up @@ -190,6 +191,15 @@ export default class Previewer {
return this.options.previewerDom.classList.contains('cherry-previewer--hidden');
}

isPreviewerFloat() {
const floatDom = this.$cherry.cherryDom.querySelector('.float-previewer-wrap');
return this.$cherry.cherryDom.contains(floatDom);
}

isPreviewerNeedFloat() {
return this.options.floatWhenClosePreviewer;
}

calculateRealLayout(editorWidth) {
// 根据editor的绝对宽度计算editor和previewer的百分比宽度
const editorDomWidth = this.editor.options.editorDom.getBoundingClientRect().width;
Expand Down Expand Up @@ -775,6 +785,24 @@ export default class Previewer {
this.$cherry.$event.emit('editorOpen');
}

floatPreviewer() {
const fullEditorLayout = {
editorPercentage: '100%',
previewerPercentage: '100%',
};
const editorWidth = this.editor.options.editorDom.getBoundingClientRect().width;
const layout = this.calculateRealLayout(editorWidth);
this.options.previewerCache.layout = layout;
this.setRealLayout(fullEditorLayout.editorPercentage, fullEditorLayout.previewerPercentage);
this.options.virtualDragLineDom.classList.add('cherry-drag--hidden');
this.$cherry.createFloatPreviewer();
}

recoverFloatPreviewer() {
this.recoverPreviewer(true);
this.$cherry.clearFloatPreviewer();
}

recoverPreviewer(dealToolbar = false) {
this.options.previewerDom.classList.remove('cherry-previewer--hidden');
this.options.virtualDragLineDom.classList.remove('cherry-drag--hidden');
Expand Down
45 changes: 45 additions & 0 deletions src/sass/cherry.scss
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,51 @@
}
}

.float-previewer-wrap {
position: fixed;
right: 0;
top: 0;
z-index: 100;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 0 60px rgba(0, 0, 0, 0.1);
resize: both;
min-width: 430px;
min-height: 300px;

&.float-previewer-dragging{
box-shadow: 0 0 60px rgba(0, 0, 0, 0.3);

.float-previewer-header{
cursor: grabbing;
background: #ace4ff;
}
}

.float-previewer-header{
z-index: 999999;
height: 40px;
border-bottom: 1px solid #ebedee;
background: #caecfd;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
cursor: grab;

.float-previewer-title{
user-select: none;
font-size: 16px;
color: #333;
font-weight: bold;
}
}

.cherry-previewer{
border-left: none;
}
}

.cherry-previewer {
padding: 20px 45px 20px 20px;
border-left: 2px solid #ebedee;
Expand Down
12 changes: 12 additions & 0 deletions src/toolbars/hooks/TogglePreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ export default class TogglePreview extends MenuBase {
* 响应点击事件
*/
onClick() {
// 需要浮动预览
if (this.editor.previewer.isPreviewerNeedFloat()) {
// 正在浮动预览
if (this.editor.previewer.isPreviewerFloat()) {
this.editor.previewer.recoverFloatPreviewer(true);
this.isHidden = false;
} else {
this.editor.previewer.floatPreviewer();
this.isHidden = true;
}
return;
}
if (this.editor.previewer.isPreviewerHidden()) {
this.editor.previewer.recoverPreviewer(true);
this.isHidden = false;
Expand Down
1 change: 1 addition & 0 deletions types/cherry.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export interface CherryPreviewerOptions {
/** 预览区域的DOM className */
className: string;
enablePreviewerBubble: boolean;
floatWhenClosePreviewer: boolean;
// 配置图片懒加载的逻辑
lazyLoadImg: {
// 加载图片时如果需要展示loaing图,则配置loading图的地址
Expand Down
2 changes: 2 additions & 0 deletions types/previewer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export interface PreviewerOptions {
previewerMaskDom: HTMLDivElement;
/** 是否开启预览区域菜单 */
enablePreviewerBubble?: boolean;
// 是否在关闭预览区时,将预览区浮动
floatWhenClosePreviewer?: boolean;
$cherry?: Cherry;
// 配置图片懒加载的逻辑
lazyLoadImg: {
Expand Down

0 comments on commit e05091e

Please sign in to comment.