opti: 1.adjust eventlistener;

This commit is contained in:
mitsuha
2022-08-23 20:07:35 +08:00
parent ab070daa7e
commit b96d6c37f7
6 changed files with 34 additions and 81 deletions

View File

@@ -23,7 +23,7 @@ import { useFlag } from '@toeverything/datasource/feature-flags';
import { CollapsiblePageTree } from './collapsible-page-tree'; import { CollapsiblePageTree } from './collapsible-page-tree';
import { Tabs } from './components/tabs'; import { Tabs } from './components/tabs';
import { TabMap, TAB_TITLE } from './components/tabs/Tabs'; import { TabMap, TAB_TITLE } from './components/tabs/Tabs';
import { TOC } from './components/toc'; import { Toc } from './components/toc';
import { WorkspaceName } from './workspace-name'; import { WorkspaceName } from './workspace-name';
type PageProps = { type PageProps = {
@@ -92,7 +92,7 @@ export function Page(props: PageProps) {
)} )}
{activeTab === TabMap.get(TAB_TITLE.TOC).value && ( {activeTab === TabMap.get(TAB_TITLE.TOC).value && (
<TOC editor={editorRef.current}>TOC</TOC> <Toc editor={editorRef.current}>TOC</Toc>
)} )}
</WorkspaceSidebarContent> </WorkspaceSidebarContent>
</WorkspaceSidebar> </WorkspaceSidebar>

View File

@@ -1,6 +1,5 @@
import { BlockEditor } from '@toeverything/components/editor-core'; import { BlockEditor } from '@toeverything/components/editor-core';
import { styled } from '@toeverything/components/ui'; import { styled } from '@toeverything/components/ui';
import { services } from '@toeverything/datasource/db-service';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { import {
createContext, createContext,
@@ -12,12 +11,9 @@ import {
import { useParams } from 'react-router'; import { useParams } from 'react-router';
import { import {
BLOCK_TYPES, BLOCK_TYPES,
getPageContentById, getContentByAsyncBlocks,
} from '../../utils/getPageContentById'; getPageTOC,
} from '../../utils/toc';
const StyledTOC = styled('div')(() => {
return {};
});
const StyledTOCItem = styled('a')<{ type?: string; isActive?: boolean }>( const StyledTOCItem = styled('a')<{ type?: string; isActive?: boolean }>(
({ type, isActive }) => { ({ type, isActive }) => {
@@ -120,49 +116,42 @@ const renderTOCContent = tocDataSource => {
); );
}; };
export const TOC = (props: Props) => { export const Toc = (props: Props) => {
const { editor } = props; const { editor } = props;
const { workspace_id, page_id } = useParams(); const { page_id } = useParams();
const [tocDataSource, setTocDataSource] = useState([]); const [tocDataSource, setTocDataSource] = useState([]);
const [activeBlockId, setActiveBlockId] = useState('blockId'); const [activeBlockId, setActiveBlockId] = useState('blockId');
const updateTocDataSource = useCallback(async () => { const updateTocDataSource = useCallback(async () => {
const tocDataSource = await getPageContentById(editor, page_id); const { children = [] } =
(await editor.queryByPageId(page_id))?.[0] || {};
const asyncBlocks = (await editor.getBlockByIds(children)) || [];
const tocDataSource = getPageTOC(
asyncBlocks,
await getContentByAsyncBlocks(asyncBlocks, updateTocDataSource)
);
setTocDataSource(tocDataSource); setTocDataSource(tocDataSource);
}, [editor, page_id]); }, [editor, page_id]);
useEffect(() => { useEffect(() => {
(async () => await updateTocDataSource())(); (async () => {
await updateTocDataSource();
})();
}, [updateTocDataSource]); }, [updateTocDataSource]);
useEffect(() => {
let unobserve: () => void;
const observe = async () => {
unobserve = await services.api.tocService.observe(
{ workspace: workspace_id, pageId: page_id },
updateTocDataSource
);
};
void observe();
return () => {
unobserve?.();
};
}, [updateTocDataSource, workspace_id]);
const onClick = async (blockId?: string) => { const onClick = async (blockId?: string) => {
if (blockId === activeBlockId) { if (blockId === activeBlockId) {
return; return;
} }
console.log(blockId);
setActiveBlockId(blockId); setActiveBlockId(blockId);
await editor.scrollManager.scrollIntoViewByBlockId(blockId); await editor.scrollManager.scrollIntoViewByBlockId(blockId);
}; };
return ( return (
<TOCContext.Provider value={{ activeBlockId, onClick }}> <TOCContext.Provider value={{ activeBlockId, onClick }}>
<StyledTOC>{renderTOCContent(tocDataSource)}</StyledTOC> <div>{renderTOCContent(tocDataSource)}</div>
</TOCContext.Provider> </TOCContext.Provider>
); );
}; };

View File

@@ -1 +1 @@
export { TOC } from './TOC'; export { Toc } from './Toc';

View File

@@ -1,4 +1,4 @@
import type { BlockEditor } from '@toeverything/components/editor-core'; import { AsyncBlock } from '@toeverything/components/editor-core';
export const BLOCK_TYPES = { export const BLOCK_TYPES = {
GROUP: 'group', GROUP: 'group',
@@ -7,23 +7,29 @@ export const BLOCK_TYPES = {
HEADING3: 'heading3', HEADING3: 'heading3',
}; };
const getContentByAsyncBlocks = async (asyncBlocks = []) => { /* 😞😞sorry, I don't know how to define unlimited dimensions array */
const getContentByAsyncBlocks = async (
asyncBlocks: AsyncBlock[] = [],
callback: () => void
): Promise<any[]> => {
/* maybe should recast it to tail recursion */ /* maybe should recast it to tail recursion */
return await Promise.all( return await Promise.all(
asyncBlocks.map(async asyncBlock => { asyncBlocks.map(async (asyncBlock: AsyncBlock) => {
const asyncBlocks = await asyncBlock.children(); const asyncBlocks = await asyncBlock.children();
if (asyncBlocks?.length) { if (asyncBlocks?.length) {
return getContentByAsyncBlocks(asyncBlocks); return getContentByAsyncBlocks(asyncBlocks, callback);
} }
const { id, type } = asyncBlock; /* get update notice */
asyncBlock.onUpdate(callback);
const { id, type } = asyncBlock;
if (Object.values(BLOCK_TYPES).includes(type)) { if (Object.values(BLOCK_TYPES).includes(type)) {
const properties = await asyncBlock.getProperties(); const properties = await asyncBlock.getProperties();
return { return {
id: id, id,
type, type,
text: properties?.text?.value?.[0]?.text || '', text: properties?.text?.value?.[0]?.text || '',
}; };
@@ -34,12 +40,7 @@ const getContentByAsyncBlocks = async (asyncBlocks = []) => {
); );
}; };
const getPageContentById = async (editor: BlockEditor, pageId: string) => { const getPageTOC = (asyncBlocks: AsyncBlock[], tocContents) => {
const { children = [] } = (await editor.queryByPageId(pageId))?.[0] || {};
const asyncBlocks = (await editor.getBlockByIds(children)) || [];
const tocContents = await getContentByAsyncBlocks(asyncBlocks);
return tocContents return tocContents
.reduce((tocGroupContent, tocContent, index) => { .reduce((tocGroupContent, tocContent, index) => {
const { id, type } = asyncBlocks[index]; const { id, type } = asyncBlocks[index];
@@ -61,4 +62,4 @@ const getPageContentById = async (editor: BlockEditor, pageId: string) => {
.filter(Boolean); .filter(Boolean);
}; };
export { getPageContentById }; export { getPageTOC, getContentByAsyncBlocks };

View File

@@ -5,7 +5,6 @@ import { Database } from './database';
import { EditorBlock } from './editor-block'; import { EditorBlock } from './editor-block';
import { FileService } from './file'; import { FileService } from './file';
import { PageTree } from './workspace/page-tree'; import { PageTree } from './workspace/page-tree';
import { TOC } from './workspace/toc';
import { UserConfig } from './workspace/user-config'; import { UserConfig } from './workspace/user-config';
export { export {
@@ -49,7 +48,6 @@ export interface DbServicesMap {
userConfig: UserConfig; userConfig: UserConfig;
file: FileService; file: FileService;
commentService: CommentService; commentService: CommentService;
tocService: TOC;
} }
interface RegisterDependencyConfigWithName extends RegisterDependencyConfig { interface RegisterDependencyConfigWithName extends RegisterDependencyConfig {
@@ -78,13 +76,6 @@ const dbServiceConfig: RegisterDependencyConfigWithName[] = [
value: PageTree, value: PageTree,
dependencies: [{ token: Database }], dependencies: [{ token: Database }],
}, },
{
type: 'class',
callName: 'tocService',
token: TOC,
value: TOC,
dependencies: [{ token: Database }],
},
{ {
type: 'class', type: 'class',
callName: 'userConfig', callName: 'userConfig',

View File

@@ -1,28 +0,0 @@
import { ServiceBaseClass } from '../base';
import { ReturnUnobserve } from '../database/observer';
import { ObserveCallback } from './page-tree';
export class TOC extends ServiceBaseClass {
private onActivePageChange?: () => void;
async observe(
{ workspace, pageId }: { workspace: string; pageId: string },
callback: ObserveCallback
): Promise<ReturnUnobserve> {
// not only use observe, but also addChildrenListener is OK 🎉🎉🎉
// const pageBlock = await this.getBlock(workspace, pageId);
//
// this.onActivePageChange?.();
// pageBlock?.addChildrenListener('onPageChildrenChange', () => {
// callback();
// });
//
// this.onActivePageChange = () => pageBlock?.removeChildrenListener('onPageChildrenChange');
const unobserve = await this._observe(workspace, pageId, callback);
return () => {
unobserve();
};
}
}