fix: add ui for heading anchor

This commit is contained in:
yanmao 2022-01-10 14:47:50 +08:00
parent 3040b849c5
commit b467b65edb
12 changed files with 76 additions and 65 deletions

View File

@ -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 () => {

View File

@ -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 () => {

View File

@ -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,

View File

@ -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;

View File

@ -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];

View File

@ -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();
}

View File

@ -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();

View File

@ -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

View File

@ -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 {

View File

@ -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);

View File

@ -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 {

View File

@ -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() || {