fix: add ui for heading anchor
This commit is contained in:
parent
3040b849c5
commit
b467b65edb
|
@ -200,6 +200,7 @@ const Comment: React.FC<CommentProps> = forwardRef<CommentRef, CommentProps>(
|
|||
});
|
||||
});
|
||||
};
|
||||
if (typeof ResizeObserver === 'undefined') return;
|
||||
const resizeObserver = new ResizeObserver(update);
|
||||
resizeObserver.observe(editor.container[0]);
|
||||
return () => {
|
||||
|
|
|
@ -50,7 +50,6 @@ const EditorComponent: React.FC<EditorProps> = ({
|
|||
}) => {
|
||||
const engine = useRef<EngineInterface | null>(null);
|
||||
const otClient = useRef<OTClient | null>(null);
|
||||
const [value, setValue] = useState('');
|
||||
const comment = useRef<CommentRef | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [members, setMembers] = useState<Array<Member>>([]);
|
||||
|
@ -67,34 +66,57 @@ const EditorComponent: React.FC<EditorProps> = ({
|
|||
/**
|
||||
* 保存到服务器
|
||||
*/
|
||||
const save = useCallback(() => {
|
||||
if (!engine.current || !props.onSave) return;
|
||||
console.log('save', new Date().getTime());
|
||||
const filterValue: Content = props.comment
|
||||
? engine.current.command.executeMethod(
|
||||
'mark-range',
|
||||
'action',
|
||||
'comment',
|
||||
'filter',
|
||||
value,
|
||||
)
|
||||
: { value, paths: [] };
|
||||
props.onSave(filterValue);
|
||||
}, [props.onSave, value]);
|
||||
const save = useCallback(
|
||||
(value: string) => {
|
||||
if (!engine.current || !props.onSave) return;
|
||||
console.log('save', new Date().getTime());
|
||||
const filterValue: Content = props.comment
|
||||
? engine.current.command.executeMethod(
|
||||
'mark-range',
|
||||
'action',
|
||||
'comment',
|
||||
'filter',
|
||||
value,
|
||||
)
|
||||
: { value, paths: [] };
|
||||
props.onSave(filterValue);
|
||||
},
|
||||
[props.onSave],
|
||||
);
|
||||
/**
|
||||
* 60秒内无更改自动保存
|
||||
*/
|
||||
const autoSave = useCallback(() => {
|
||||
if (saveTimeout.current) clearTimeout(saveTimeout.current);
|
||||
saveTimeout.current = setTimeout(() => {
|
||||
save();
|
||||
const value = engine.current?.getValue() || '';
|
||||
save(value);
|
||||
}, 60000);
|
||||
}, [save]);
|
||||
|
||||
//用户主动保存
|
||||
const userSave = useCallback(() => {
|
||||
if (!engine.current) return;
|
||||
//获取异步的值,有些组件可能还在处理中,比如正在上传
|
||||
engine.current
|
||||
.getValueAsync(false, (pluginName, card) => {
|
||||
console.log(`${pluginName} 正在等待...`, card?.getValue());
|
||||
})
|
||||
.then((value) => {
|
||||
save(value);
|
||||
})
|
||||
.catch((data) => {
|
||||
console.log('终止保存:', data.name, data.card?.getValue());
|
||||
});
|
||||
}, [engine, save]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('beforeunload', save);
|
||||
const unloadSave = () => {
|
||||
save(engine.current?.getValue() || '');
|
||||
};
|
||||
window.addEventListener('beforeunload', unloadSave);
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', save);
|
||||
window.removeEventListener('beforeunload', unloadSave);
|
||||
};
|
||||
}, [save]);
|
||||
|
||||
|
@ -113,40 +135,23 @@ const EditorComponent: React.FC<EditorProps> = ({
|
|||
//自动保存,非远程更改,触发保存
|
||||
if (trigger !== 'remote') autoSave();
|
||||
if (props.onChange) props.onChange(trigger);
|
||||
const value = engine.current?.getValue();
|
||||
// const value = engine.current?.getValue();
|
||||
// 获取编辑器的值
|
||||
console.log(`value ${trigger} update:`, value);
|
||||
setValue(value || '');
|
||||
// console.log(`value ${trigger} update:`, value);
|
||||
// 获取当前所有at插件中的名单
|
||||
// console.log(
|
||||
// 'mention:',
|
||||
// engine.current?.command.executeMethod('mention', 'getList'),
|
||||
// );
|
||||
// 获取编辑器的html
|
||||
console.log('html:', engine.current?.getHtml());
|
||||
// console.log('html:', engine.current?.getHtml());
|
||||
// 获取编辑器的json
|
||||
// console.log('json:', engine.current?.getJsonValue());
|
||||
},
|
||||
[loading, autoSave, props.onChange],
|
||||
),
|
||||
};
|
||||
|
||||
//用户主动保存
|
||||
const userSave = useCallback(() => {
|
||||
if (!engine.current) return;
|
||||
//获取异步的值,有些组件可能还在处理中,比如正在上传
|
||||
engine.current
|
||||
.getValueAsync(false, (pluginName, card) => {
|
||||
console.log(`${pluginName} 正在等待...`, card?.getValue());
|
||||
})
|
||||
.then((value) => {
|
||||
setValue(value);
|
||||
save();
|
||||
})
|
||||
.catch((data) => {
|
||||
console.log('终止保存:', data.name, data.card?.getValue());
|
||||
});
|
||||
}, [engine, save]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!engine.current) return;
|
||||
//卡片最大化时设置编辑页面样式
|
||||
|
@ -215,12 +220,11 @@ const EditorComponent: React.FC<EditorProps> = ({
|
|||
} else {
|
||||
// 非协同编辑,设置编辑器值,异步渲染后回调
|
||||
engine.current.setValue(value, (count) => {
|
||||
console.log(count);
|
||||
console.log('setValue loaded:', count);
|
||||
if (onLoad) onLoad(engine.current!);
|
||||
return setLoading(false);
|
||||
});
|
||||
}
|
||||
setValue(value);
|
||||
}
|
||||
|
||||
return () => {
|
||||
|
|
|
@ -281,7 +281,9 @@ class NativeEvent {
|
|||
card.each((card) => {
|
||||
const center = card.getCenter();
|
||||
if (center && center.length > 0) {
|
||||
let isSelect = selection.containsNode(center[0]);
|
||||
let isSelect = selection.containsNode
|
||||
? selection.containsNode(center[0])
|
||||
: false;
|
||||
if (!isSelect && containsCard && selection.focusNode) {
|
||||
const focusCard = this.engine.card.find(
|
||||
selection.focusNode,
|
||||
|
|
|
@ -724,7 +724,8 @@ class NodeEntry implements NodeInterface {
|
|||
child = next;
|
||||
}
|
||||
children.forEach((child) => {
|
||||
(node as Element).append(child.cloneNode(true));
|
||||
if (node.nodeType === Node.ELEMENT_NODE)
|
||||
(node as Element).appendChild(child.cloneNode(true));
|
||||
});
|
||||
});
|
||||
return this;
|
||||
|
|
|
@ -652,7 +652,7 @@ class NodeModel implements NodeModelInterface {
|
|||
if (isUnwrap(nodeDom)) {
|
||||
const fragment = nodeDom.document!.createDocumentFragment();
|
||||
nodeDom.children().each((child) => {
|
||||
fragment.append(child);
|
||||
fragment.appendChild(child);
|
||||
});
|
||||
nodeDom.remove();
|
||||
node = fragment.childNodes[fragment.childNodes.length - 1];
|
||||
|
|
|
@ -43,18 +43,20 @@ class Position {
|
|||
this.#editor.scrollNode?.on('scroll', this.updateListener);
|
||||
}
|
||||
let size = { width: target.width(), height: target.height() };
|
||||
this.#observer = new ResizeObserver(() => {
|
||||
const width = target.width();
|
||||
const height = target.height();
|
||||
if (typeof ResizeObserver !== 'undefined') {
|
||||
this.#observer = new ResizeObserver(() => {
|
||||
const width = target.width();
|
||||
const height = target.height();
|
||||
|
||||
if (width === size.width && height === size.height) return;
|
||||
size = {
|
||||
width,
|
||||
height,
|
||||
};
|
||||
this.updateListener();
|
||||
});
|
||||
this.#observer.observe(target.get<HTMLElement>()!);
|
||||
if (width === size.width && height === size.height) return;
|
||||
size = {
|
||||
width,
|
||||
height,
|
||||
};
|
||||
this.updateListener();
|
||||
});
|
||||
this.#observer.observe(target.get<HTMLElement>()!);
|
||||
}
|
||||
this.update();
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ class Request implements RequestInterface {
|
|||
input['fireEvent'](event);
|
||||
} else throw '';
|
||||
|
||||
document.addEventListener('mousedown', remove);
|
||||
//document.addEventListener('mousedown', remove);
|
||||
} catch (error) {
|
||||
input.removeEventListener('change', change);
|
||||
remove();
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onUnmounted, ref, watch } from 'vue'
|
||||
import { $ } from '@aomao/engine'
|
||||
import { colorProps } from '../../types'
|
||||
import { useRight } from '../../hooks';
|
||||
import AmButton from '../button.vue'
|
||||
|
@ -94,7 +95,7 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
const hideDropdown = (event?: MouseEvent) => {
|
||||
if (event && (event.target as Element).closest('.toolbar-dropdown-list'))
|
||||
if (event?.target && $(event.target).closest('.toolbar-dropdown-list'))
|
||||
return;
|
||||
document.removeEventListener('click', hideDropdown);
|
||||
visible.value = false
|
||||
|
|
|
@ -20,7 +20,7 @@ export default class Popup {
|
|||
this.#options = options;
|
||||
this.#editor = editor;
|
||||
this.#root = $(`<div class="data-toolbar-popup-wrapper"></div>`);
|
||||
document.body.append(this.#root[0]);
|
||||
document.body.appendChild(this.#root[0]);
|
||||
if (isEngine(editor)) {
|
||||
this.#editor.on('select', this.onSelect);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import classNames from 'classnames-es-ts';
|
||||
import { $ } from '@aomao/engine';
|
||||
import type { EngineInterface, Placement } from '@aomao/engine';
|
||||
import { useRight } from '../hooks';
|
||||
import Button from '../button';
|
||||
|
@ -91,10 +92,7 @@ const ColorButton: React.FC<ColorButtonProps> = ({
|
|||
};
|
||||
|
||||
const hideDropdown = (event?: MouseEvent) => {
|
||||
if (
|
||||
event &&
|
||||
(event.target as Element).closest('.toolbar-dropdown-list')
|
||||
)
|
||||
if (event?.target && $(event.target).closest('.toolbar-dropdown-list'))
|
||||
return;
|
||||
document.removeEventListener('click', hideDropdown);
|
||||
setPickerVisible(false);
|
||||
|
|
|
@ -20,7 +20,7 @@ export default class Popup {
|
|||
this.#options = options;
|
||||
this.#editor = editor;
|
||||
this.#root = $(`<div class="data-toolbar-popup-wrapper"></div>`);
|
||||
document.body.append(this.#root[0]);
|
||||
document.body.appendChild(this.#root[0]);
|
||||
if (isEngine(editor)) {
|
||||
this.#editor.on('select', this.onSelect);
|
||||
} else {
|
||||
|
|
|
@ -8,6 +8,8 @@ import {
|
|||
PluginEntry,
|
||||
PluginOptions,
|
||||
DATA_ID,
|
||||
DATA_ELEMENT,
|
||||
UI,
|
||||
} from '@aomao/engine';
|
||||
import Outline from './outline';
|
||||
import type { OutlineData } from './outline';
|
||||
|
@ -64,7 +66,7 @@ export default class<T extends HeadingOptions> extends BlockPlugin<T> {
|
|||
node.find('.data-anchor-button').remove();
|
||||
Tooltip.hide();
|
||||
const button = $(
|
||||
`<a class="data-anchor-button"><span class="data-icon data-icon-${node.name}"></span></a>`,
|
||||
`<a class="data-anchor-button" ${DATA_ELEMENT}="${UI}"><span class="data-icon data-icon-${node.name}"></span></a>`,
|
||||
);
|
||||
if (node.height() !== 24) {
|
||||
button.css({
|
||||
|
@ -229,7 +231,7 @@ export default class<T extends HeadingOptions> extends BlockPlugin<T> {
|
|||
}
|
||||
|
||||
button = $(
|
||||
`<span class="data-anchor-button"><span class="data-icon data-icon-${block.name}"></span></span>`,
|
||||
`<span class="data-anchor-button" ${DATA_ELEMENT}="${UI}"><span class="data-icon data-icon-${block.name}"></span></span>`,
|
||||
);
|
||||
root.append(button);
|
||||
const parentRect = root.get<Element>()?.getBoundingClientRect() || {
|
||||
|
|
Loading…
Reference in New Issue